How to use SteamAPICall_t with a SteamLeaderboard_t handle with LuaJIT FFI?
I use LÖVE2D framework & Steamworks Lua Integration (SLI)
Links: FindLeaderboard
/ UploadLeaderboardScore
/ Typedef
function UploadLeaderboards(score)
local char = ffi.new('const char*', 'Leaderboard name')
local leaderboardFound = steamworks.userstats.FindLeaderboard(char) -- Returns SteamAPICall_t
local leaderboardCurrent = ?? -- Use SteamAPICall_t with typedef SteamLeaderboard_t somehow.
local c = ffi.new("enum SteamWorks_ELeaderboardUploadScoreMethod", "k_ELeaderboardUploadScoreMethodKeepBest")
score = ffi.cast('int',math.round(score))
return steamworks.userstats.UploadLeaderboardScore(leaderboardCurrent, c, score, ffi.cast('int *', 0), 0ULL)
end
leaderboardCurrent = ffi.cast("SteamLeaderboard_t", leaderboardFound) -- No declaration error
SteamAPICall_t is simply a number that corresponds to your request.
This is meant to be used alongside CCallback in the steam API.
The lua integration misses out CCallback and STEAM_CALLBACK.
The SteamLeaderboard_t response is generated by calling FindLeaderboard.
In this case you are making a request to steam and steam needs to respond in an asynchronous way.
So what you have to do is define a Listener object ( in C++ ) that will listen for the response ( which will be in form of SteamLeaderboard_t) and write C-like functions for it so ffi can understand them.
This means that your program must be able to do this:
Register a listener for the leaderboard.
Submit a request for a leaderboard. ( FindLeaderboard )
Wait for message ( SteamLeaderboard_t )
Use SteamLeaderboard_t
In short you will need to write code in C++ for the events and add C-like interface for them and compile it all into a DLL then link that DLL to lua using FFI. This can be tricky so exercise caution.
in C (ffi.cdef and dll):
//YOU have to write a DLL that defines these
typedef struct LeaderboardEvents{
void(*onLeaderboardFound)(SteamLeaderboard_t id);
} LeaderboardEvents;
void MySteamLib_attachListener(LeaderboardEvents* events);
Then in lua.
local lib = --load your DLL library here
local Handler = ffi.new("LeaderboardEvents")
Handler.onLeaderboardFound = function(id)
-- do your stuff here.
end
lib.MySteamLib_attachListener(Handler)
While writing your DLL, I STRONGLY recommend that you read through the SpaceWar example provided by steam api so you can see how callbacks are registered.
Related
Trying to follow this example:
DirectX11 ReportLiveObjects Instantiation
I'm trying to get a debug interface setup using C99 with directx11. I've already defined COBJMACROS and CINTERFACE in order to use directx c api and currently have a triangle rendering on my screen. In order to get dxgi debug stuff setup I've tried:
IDXGIDebug1* debug = { 0 };
DXGIGetDebugInterface(0, IID_PPV_ARGS(&debug));
IDXGIDebug1_ReportLiveObjects(debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
but get errors that 'IID_PPV_ARGS' is not defined and I'm sure this is because I'm using the C interface and this is specific to c++. I've also tried:
IDXGIDebug1* debug = { 0 };
ID3D11Device_QueryInterface(device, &IID_IDXGIDebug1, (void**)(&debug));
IDXGIDebug1_ReportLiveObjects(debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
But 'debug' variable isn't getting filled. Not sure what the equivalent C calls are for DXGI debug interface.
After some diggin I found what I was looking for. The c function equilavent 'DXGIGetDebugInterface1' is located in the dxgi1_3.h header file and I was only including the dxgidebug.h header. Also, need to link to dxgi.lib. Final code is:
IDXGIDebug1* debug = { 0 };
DXGIGetDebugInterface1(0, &IID_IDXGIDebug1, (void**)(&debug));
IDXGIDebug1_ReportLiveObjects(debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
I am working on a desktop application using nim's webgui package, which sort of works like electron in that it renders a gui using HTML + CSS + JS. However, instead of bundling its own browser and having a backend in node, it uses the browser supplied by the OS (Epiphany under Linux/GNOME, Edge under Windows, Safari under iOS) and allows writing the backend in nim.
In that context I am basically writing an SPA in Angular and need to load in the HTML, JS and CSS files at compile-time into my binary.
Reading from a known absolute filepath is not an issue, you can use nim's staticRead method for that.
However, I would like to avoid having to adjust the filenames in my application code all the time, e.g. when a new build of the SPA changes a file name from main.a72efbfe86fbcbc6.js to main.b72efbfe86fbcbc6.js.
There is an iterator in std/os that you can use at runtime called walkFiles and walkPattern, but these fail when used at compileTime!
import std/[os, sequtils, strformat, strutils]
const resourceFolder = "/home/philipp/dev/imagestable/html" # Put into config file
const applicationFiles = toSeq(walkFiles(fmt"{resourceFolder}/*"))
/home/philipp/.choosenim/toolchains/nim-#devel/lib/pure/os.nim(2121, 11) Error: cannot 'importc' variable at compile time; glob
How do I get around this?
Thanks to enthus1ast from nim's discord server I arrived at an answer: using the collect macro with the walkDir iterator.
The walkDir iterator does not make use of things that are only available at runtime and thus can be safely used at compiletime. With the collect macro you can iterate over all your files in a specific directory and collect their paths into a compile-time seq!
Basically you start writing collect-block, which is a simple for-loop that at its end evaluates to some form of value. The collect macro will put them all into a seq at the end.
The end result looks pretty much like this:
import std/[sequtils, sugar, strutils, strformat, os]
import webgui
const resourceFolder = "/home/philipp/dev/imagestable/html"
proc getFilesWithEnding(folder: string, fileEnding: string): seq[string] {.compileTime.} =
result = collect:
for path in walkDir(folder):
if path.path.endswith(fmt".{fileEnding}"): path.path
proc readFilesWithEnding(folder: string, fileEnding: string): seq[string] {.compileTime.} =
result = getFilesWithEnding(folder, fileEnding).mapIt(staticRead(it))
Suppose that I have an app written in C that must parse some blob data. The parsing process is done by an entire dedicated library (I have access to this library code).
Since this blob is versioned I need to support let's say 2 versions of it at a time. Workflow would be something like:
'v1' is out -> library supports 'v1'
'v2' is out -> library now supports 'v2' and 'v1'
'v3' is out -> library now supports 'v3' and 'v2'
and so on.
The main problem is that the majority of symbols in the library for 'v2', for example, are also present in 'v1' library, with the same function prototype.
First thought was use something like namespaces in C++, in order to have something like:
/app/src/lib_v1/parser.c
void _parse_blob(char* blob){ //data parsing code for v1}
/////////////////////////////
/app/src/lib_v2/parser.c
void _parse_blob(char* blob){ //data parsing code for v2}
////////////////////////////
/app/src/main.c
//Pseudo-code
char* data;
if(_check_version(data) == 'v1')
parser.v1._parse_blob(data);
else
parser.v2._parse_blob(data);
But I don't know if any similar can be achieved in C without changing anything in the code of the 'outgoing' library (v1 in this case) since all that code has already been tested and modifying it would invalidate all the release tests.
Other idea would be separate both libraries code into two dynamic linked libraries and load/unload them when necessary, but don't know if could work or if it is efficient.
What would be the best approach to this problem ?
I have an Angular 1 app that I am trying to increase the performance of a particular service that makes a lot of calculations (and probably is not optimized but that's besides the point for now, running it in another thread is the goal right now to increase animation performance)
The App
The app runs calculations on your GPA, Terms, Courses Assignments etc. The service name is calc. Inside Calc there are user, term, course and assign namespaces. Each namespace is an object in the following form
{
//Times for the calculations (for development only)
times:{
//an array of calculation times for logging and average calculation
array: []
//Print out the min, max average and total calculation times
report: function(){...}
},
//Hashes the object (with service.hash()) and checks to see if we have cached calculations for the item, if not calls runAllCalculations()
refresh: function(item){...},
//Runs calculations, saves it in the cache (service.calculations array) and returns the calculation object
runAllCalculations: function(item){...}
}
Here is a screenshot from the very nice structure tab of IntelliJ to help visualization
What Needs To Be Done?
Detect Web Worker Compatibility (MDN)
Build the service depending on Web Worker compatibility
a. Structure it the exact same as it is now
b. Replace with a Web Worker "proxy" (Correct terminology?) service
The Problem
The problem is how to create the Web Worker "Proxy" to maintain the same service behavior from the rest of the code.
Requirements/Wants
A few things that I would like:
Most importantly, as stated above, keep the service behavior unchanged
To keep one code base for the service, keep it DRY, not having to modify two spots. I have looked at WebWorkify for this, but I am unsure how to implement it best.
Use Promises while waiting for the worker to finish
Use Angular and possibly other services inside the worker (if its possible) again WebWorkify seems to address this
The Question
...I guess there hasn't really been a question thus far, it's just been an explanation of the problem...So without further ado...
What is the best way to use an Angular service factory to detect Web Worker compatibility, conditionally implement the service as a Web Worker, while keeping the same service behavior, keeping DRY code and maintaining support for non Web Worker compatible browsers?
Other Notes
I have also looked at VKThread, which may be able to help with my situation, but I am unsure how to implement it the best.
Some more resources:
How to use a Web Worker in AngularJS?
http://www.html5rocks.com/en/tutorials/workers/basics/
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Worker_feature_detection
In general, good way to make a manageable code that works in worker - and especially one that also can run in the same window (eg. when worker is not supported) is to make the code event-driven and then use simple proxy to drive the events through the communication channel - in this case worker.
I first created abstract "class" that didn't really define a way of sending events to the other side.
function EventProxy() {
// Object that will receive events that come from the other side
this.eventSink = null;
// This is just a trick I learned to simulate real OOP for methods that
// are used as callbacks
// It also gives you refference to remove callback
this.eventFromObject = this.eventFromObject.bind(this);
}
// Object get this as all events callback
// typically, you will extract event parameters from "arguments" variable
EventProxy.prototype.eventFromObject = (name)=>{
// This is not implemented. We should have WorkerProxy inherited class.
throw new Error("This is abstract method. Object dispatched an event "+
"but this class doesn't do anything with events.";
}
EventProxy.prototype.setObject = (object)=> {
// If object is already set, remove event listener from old object
if(this.eventSink!=null)
//do it depending on your framework
... something ...
this.eventSink = object;
// Listen on all events. Obviously, your event framework must support this
object.addListener("*", this.eventFromObject);
}
// Child classes will call this when they receive
// events from other side (eg. worker)
EventProxy.prototype.eventReceived = (name, args)=> {
// put event name as first parameter
args.unshift(name);
// Run the event on the object
this.eventSink.dispatchEvent.apply(this.eventSink, args);
}
Then you implement this for worker for example:
function WorkerProxy(worker) {
// call superconstructor
EventProxy.call(this);
// worker
this.worker = worker;
worker.addEventListener("message", this.eventFromWorker = this.eventFromWorker.bind(this));
}
WorkerProxy.prototype = Object.create(EventProxy.prototype);
// Object get this as all events callback
// typically, you will extract event parameters from "arguments" variable
EventProxy.prototype.eventFromObject = (name)=>{
// include event args but skip the first one, the name
var args = [];
args.push.apply(args, arguments);
args.splice(0, 1);
// Send the event to the script in worker
// You could use additional parameter to use different proxies for different objects
this.worker.postMessage({type: "proxyEvent", name:name, arguments:args});
}
EventProxy.prototype.eventFromWorker = (event)=>{
if(event.data.type=="proxyEvent") {
// Use superclass method to handle the event
this.eventReceived(event.data.name, event.data.arguments);
}
}
The usage then would be that you have some service and some interface and in the page code you do:
// Or other proxy type, eg socket.IO, same window, shared worker...
var proxy = new WorkerProxy(new Worker("runServiceInWorker.js"));
//eg user clicks something to start calculation
var interface = new ProgramInterface();
// join them
proxy.setObject(interface);
And in the runServiceInWorker.js you do almost the same:
importScripts("myservice.js", "eventproxy.js");
// Here we're of course really lucky that web worker API is symethric
var proxy = new WorkerProxy(self);
// 1. make a service
// 2. assign to proxy
proxy.setObject(new MyService());
// 3. profit ...
In my experience, eventually sometimes I had to detect on which side am I but that was with web sockets, which are not symmetric (there's server and many clients). You could run into similar problems with shared worker.
You mentioned Promises - I think the approach with promises would be similar, though maybe more complicated as you would need to store the callbacks somewhere and index them by ID of the request. But surely doable, and if you're invoking worker functions from different sources, maybe better.
I am the author of the vkThread plugin which was mentioned in the question. And yes, I developed Angular version of vkThread plugin which allows you to execute a function in a separate thread.
Function can be defined directly in the main thread or called from an external javascript file.
Function can be:
Regular functions
Object's methods
Functions with dependencies
Functions with context
Anonymous functions
Basic usage:
/* function to execute in a thread */
function foo(n, m){
return n + m;
}
// to execute this function in a thread: //
/* create an object, which you pass to vkThread as an argument*/
var param = {
fn: foo // <-- function to execute
args: [1, 2] // <-- arguments for this function
};
/* run thread */
vkThread.exec(param).then(
function (data) {
console.log(data); // <-- thread returns 3
}
);
Examples and API doc: http://www.eslinstructor.net/ng-vkthread/demo/
Hope this helps,
--Vadim
Currently I'm working on an application which embeds the mongoose webserver. In some cases, I have to call additional functions inside the begin_request_handler to create the desired HTTP header. During this, I realized that theses functions are called after the request handler is done. For example:
void test() {
printf("HELLO");
}
static int begin_request_handler(struct mg_connection *conn) {
test();
const struct mg_request_info *request_info = mg_get_request_info(conn);
...
return 1;
}
Here the HELLO is getting printed right after the browser closes the tcp connection. Is there even a way to call functions from inside the callbacks? Or am I just missing something?
If you want to create the desired HTTP header. Then the function you mentioned above (begin_request_handler) may not be the correct approach. Look into the structure mg_request_info which is field in structure mg_connection. Here the name and value of headers is set.
I think these structures are populated at the very start after connection establishment. Also look at pull() and read(). These are ground-level function where all data is set.
And yes there is a way to call functions from callbacks.You can write your own callback and make callback function to point in struct of mg_context to make it point to your callback.
and then in handle_request() you can call it appropriately. You can add it to struct mg_callbacks in mongoose.h
Example:
memset(&callbacks, 0, sizeof(callbacks));
callbacks.begin_request => begin_request_handler;
//place your function in place of begin_request_handler
// Start the web server.
ctx = mg_start(&callbacks, NULL, options);
Please specify any more details you maybe interested in.
Well, got it. I got confused by the printf() buffers in stdout. The methods ARE called at the right time, yet the results aren't shown. Thank anyways.