Jump to content

Foxyy

Member
  • Content Count

    30
  • Joined

  • Last visited

  • Medals

Everything posted by Foxyy

  1. Foxyy

    Building extensions on mingw

    Of course it can, like any other C++ compiler. You said before that the library built with MSVC worked. Did you also use BE then, and did that not get blocked, while the library built with MinGW did? It seems very odd to me that BE would act differently depending on the compiler used to build the library.
  2. Foxyy

    Building extensions on mingw

    If you're sure your library is not getting loaded by the game, next i would breakpoint LoadLibraryExA and GetProcAddress in kernelbase.dll and check the last error after each call to figure out why one of them is failing.
  3. Foxyy

    Building extensions on mingw

    I believe OP mentioned that when building with MSVC, everything worked as expected so i assume this is not the problem. Also last time i tried it BattlEye did not block loading extensions in singleplayer in Arma 3, like it does in Arma 2, though this could since have changed.
  4. Foxyy

    Building extensions on mingw

    Clearly your library works. Does Arma load it? To find out you should first call it using callExtension. Next there are a variety of ways to find out which modules are loaded by a process. You could do it programmatically, for example using the .NET Process class and its Modules property. You could also attach a debugger such as the one integrated in Visual Studio. Personally i tend to use the more lightweight Cheat Engine for such simple tasks. Or you could use the Windows Resource Monitor (Vista and later), which lists the modules loaded by a process in the CPU tab under associated modules. Of course in all cases you should disable BattlEye, as the rootkit it installs makes peering this information a bit trickier. If your module is indeed loaded, but still you get the wrong results in game, i suggest you attach a debugger to the game process and breakpoint your code to step through it and see what is going on.
  5. Foxyy

    Building extensions on mingw

    Alright, if the function is exported correctly now, next you might try rigging up a little test case to call the function yourself. #include <iostream> #include <Windows.h> int main() { HMODULE module = LoadLibrary("myextension.dll"); if (!module) { std::cout << "!module" << std::endl; return; } FARPROC farproc = GetProcAddress(module, "_RVExtension@12"); if (!farproc) { std::cout << "!farproc" << std::endl; return; } auto* function = reinterpret_cast<void (__stdcall*)(char*, size_t, const char*)>(farproc); char buffer[10240]; buffer[0] = 0; function(buffer, sizeof(buffer), "my extension arguments"); std::cout << "result:" << buffer << std::endl; return 0; } Something like this ought to do. Then you can fire up your favourite debugger and get debugging.
  6. Foxyy

    Building extensions on mingw

    You've exported the function incorrectly. The name should be _RVExtension@12 . Note the underscore at the beginning.
  7. Foxyy

    Building extensions on mingw

    First i would find out if your DLL exports the interface function. One way to do this is using DUMPBIN. To do this you must open the Visual Studio developer command prompt, and execute DUMPBIN like so. dumpbin /EXPORTS "my/path/myextension.dll" If all goes well you should see output similar to this. Dump of file myextension.dll File Type: DLL Section contains the following exports for myextension.dll 00000000 characteristics 578F8D42 time date stamp Wed Jul 20 17:40:02 2016 0.00 version 1 ordinal base 1 number of functions 1 number of names ordinal hint RVA name 1 0 00014F5F _RVExtension@12 = @ILT+3930(_RVExtension@12) Summary 1000 .00cfg 1000 .data 1000 .gfids 2000 .idata 7000 .rdata 2000 .reloc 1000 .rsrc 2B000 .text 13000 .textbss 1000 .tls Note the export _RVExtension@12. This is what Arma looks for when you use callExtension.
  8. sync <code> SQF makes it very easy to achieve asynchrony, while at the same time offering no means of synchronization. Some people seem to think that race conditions aren't a thing in SQF. This is of course wrong, as the scheduler is free to pause execution almost anywhere. A simple example: if (player hasWeapon _someWeapon) then { player removeWeapon _someWeapon; player addWeapon _someOtherWeapon; }; Here it is entirely possible (though admittedly unlikely) for the scheduler to pause between the condition and the effect, and consequently for the player to drop the weapon, keeping it, while also receiving the new one. I have personally witnessed a similar situation occurring in a real game under very heavy lag. Using certain hacky solutions it is possible to get around these issues. Relating to the previous example, it is for example possible to create an atomic function which at the same time attempts to remove the weapon, and returns a boolean indicating whether it was. It is also of course possible to create simple mutexes and consequently spinlocks. Neither solution is very pretty however. As such i suggest the following, very simple, script command: sync { /* some critical section */ } This command should execute the right hand argument synchronously, without the possibility of interruption by the scheduler. Use of any scheduler-only commands such as sleep and waitUntil should generate errors, just as they do in the unscheduled environment. If used in the unscheduled environment the command would have no special effect of course, behaving instead similarly to call. [<string>,...] preprocessFileLineNumbers <string> Many mod developers make clever use of macros for conditional compilation, for instance in order to enable or disable debugging features such as logging, argument validation, call stack tracing, et cetera. This is often done using macro constants defined either in each code file, or in a central header file. Unfortunately it doesn't seem to be possible to include files from the mission in an addon, as it is vice versa. This means in order to enable or disable the aforementioned features, one has to rebuild the mod, or a part of it while defining different macro constants. To ease this, and undoubtedly many other tasks, i suggest the extension of the preprocessFileLineNumbers command with a variant accepting, as the left hand argument, an array of strings representing macro constants to be defined during preprocessing. For example: ["MY_MACRO", "DO_THE_DEBUG"] preprocessFileLineNumbers "myScript.sqf" Would be equivalent to defining these macros at the top of the myScript.sqf file, like so: #define MY_MACRO #define DO_THE_DEBUG // ... compileFinal <code> We can all agree that the compileFinal command, as well as the underlying concept, are great additions to SQF. However they seem to necessitate placing each function, no matter how small, into its own code file. I would often prefer to place related functions, such as class member functions, next to each other in the same code file. For instance: //map.sqf my_fnc_map_add = { // add key value pair to the map }; my_fnc_map_get = { // retrieve value from the map using the specified key }; my_fnc_map_remove = { // remove the specified key from the map }; my_fnc_map_hasKey = { // determine whether the map contains the specified key }; Now all of these functions end up being non-final, and editable. For a dirty workaround something like this might be used: my_fnc = compileFinal str {...} However extending the compileFinal command with a variant accepting code as the right hand argument seems like it would be very simple to implement. serializeObject <object> / deserializeObject [...] Persistence across sessions is nothing new. Implementing it however ranges from arduous to downright impossible (at least without hacking memory via extensions), depending on the desired fidelity. Correctly saving and loading the attachments on a weapon inside a backpack inside a vehicle for instance isn't exactly simple. What i'm suggesting is two new simple commands to streamline this process. The proposed serializeObject command, given a right hand argument of type object, might return an array containing enough information to recreate the object with high precision. Properties such as type, position, orientation, velocity, damage to each part, and the entire inventory tree should be included. The counterpart, deserializeObject, could then be used to bring this array representation back to life. This would simplify immensely the task of persistence seen in many missions and mods, as well as offer a performance boost by moving a significant portion of SQF code over to a native implementation. Please share your thoughts, or any other suggestions you might have. If any (or all) of these have been suggested before, i apologize.
  9. Foxyy

    SQF feature requests

    It was meant to be sarcastic showing that both isNil and call, one of the most frequently used commands, can crash the game when used in the exact same way. But once again sarcasm doesn't convey very well in written form. It is noteworthy that you're using call for recursion here. A call stack frame is implemented as a heap object, and as such recursion depth is limited only by available system memory. In the case of isNil however, a native stack frame is created, meaning the program will end in stack overflow at a much lower recursion depth.
  10. Foxyy

    SQF feature requests

    @commy2 I don't think that's necessarily the case. I just tried and this code does crash the game: dbg_fnc = { isNil dbg_fnc }; isNil dbg_fnc; But then again so does this: dbg_fnc = { call dbg_fnc }; call dbg_fnc; @kylania @Freghar There is no reason to keep something like this from public knowledge. It can't be exploited. If you want to crash your own game you can just kill the process. And even if it could, i say make it public and if it does get exploited that's just more pressure on the developer to fix it.
  11. Foxyy

    SQF feature requests

    I agree with cyruz. Might as well just report it on bug tracker and hold your tongue if you're not going to add anything constructive to the discussion. If you do bring up something like this, at least back it up with some evidence.
  12. Foxyy

    SQF feature requests

    @killzone_kid Could you provide us with sample code that reliably crashes the game? Until you do i don't think there's any reason to believe that this use of the command is at fault. Unfortunately the forum rules prevent me from going into detail on why i think it's perfectly safe.
  13. Foxyy

    SQF feature requests

    I know you're being sarcastic, but seriously though this is by far the best solution i've seen so far.
  14. Foxyy

    SQF feature requests

    Well apparently isNil <code> is atomic. Case closed. We can all go home now. fxy_fnc_sync = { private "_result"; _result = []; isNil { _result set [0, _this select 1 call (_this select 0)] }; _result select 0 }; Test case: #define DELAY (selectBestPlaces [position player, 200, "meadow + 2*hills", 1, 5]) 0 spawn { _func = { private "_frame"; _frame = diag_frameNo; DELAY; DELAY; DELAY; DELAY; diag_frameNo - _frame }; _control = { _this select 1 call (_this select 0) }; systemChat format ["control: %1 frames", [_func, 0] call _control]; systemChat format ["sync: %1 frames", [_func, 0] call fxy_fnc_sync]; }; Output: control: 4 frames sync: 0 frames
  15. Foxyy

    SQF feature requests

    You're right, this is not atomic. However an array initializer containing only atomic statements is atomic. For example: //long running command pretty much guaranteed to go over 3ms #define COMMAND (selectBestPlaces [position player, 500, "meadow + 2*hills", 1, 5]) [] spawn { systemChat "async"; systemChat str diag_frameNo; COMMAND; COMMAND; COMMAND; COMMAND; systemChat str diag_frameNo; systemChat "sync"; [ systemChat str diag_frameNo, COMMAND, COMMAND, COMMAND, COMMAND, systemChat str diag_frameNo ] };
  16. Foxyy

    SQF feature requests

    Heh, i just forgot for a minute how setVariable works. Obviously i meant to use the mission namespace. I edited the code, which by the way i haven't tested at all and am obviously not recommending anyone use.
  17. Foxyy

    SQF feature requests

    Since we're all posting totally awesome not at all dirty solutions... //config class CfgVehicles { class Logic; class MyShittyObject : Logic { scope = protected; class EventHandlers { init = "my_shitty_result = my_shitty_args call my_shitty_function"; }; }; }; //SQF my_shitty_synccall = { [ missionNamespace setVariable ["my_shitty_args", _this select 0], missionNamespace setVariable ["my_shitty_function", _this select 1], missionNamespace setVariable ["my_shitty_object", "MyShittyObject" createVehicleLocal [0,0,0]], deleteVehicle (missionNamespace getVariable "my_shitty_object"), my_shitty_result ] select 4 };
  18. Foxyy

    SQF feature requests

    It is possible to implement a proper mutex in SQF. dayz_code\util\mutex.hpp /* Provides a simple mutex implementation for synchronization between the scheduled and unscheduled environments. See https://en.wikipedia.org/wiki/Mutual_exclusion Author: Foxy */ #ifndef _INCLUDE_GUARD_MUTEX #define _INCLUDE_GUARD_MUTEX //Initializes a new unlocked mutex. #define Mutex_New() [true] //Attempts to lock the specified mutex. Returns true if the mutex was locked. #define Mutex_TryLock(mtx) ((mtx) call dz_fn_mutex_tryLock) #define Mutex_TryLock_Fast(mtx) ([(mtx) select 0, (mtx) set [0, false]] select 0) //Waits until the mutex becomes available and locks it. #define Mutex_WaitLock(mtx) ((mtx) call dz_fn_mutex_waitLock) #define Mutex_WaitLock_Fast(mtx) waitUntil {Mutex_TryLock_Fast(mtx)} //Unlocks the mutex. Use only when you have previously obtained lock yourself. #define Mutex_Unlock(mtx) ((mtx) set [0, true]) #endif Also array references are very useful, they allow you to share and pass objects by reference. This might be used for dependency injection or inter-thread communication for example.
  19. Foxyy

    SQF feature requests

    I'm aware of these hacky solutions pedeathrian and they're exactly what i would like to avoid. Just as well you could dispatch to a PFH which is clearly not ideal as it requires polling and waiting. You could even dispatch using object initializers or in MP self-publicVariable if you wanted to go the real dirty route. Any FSM condition based solutions will obviously require suspension and as such most likely require further inter-thread synchronization. Also even if the scheduler were to execute two threads intermittently without explicit waiting, you could construct mutexes using array initializers, which if containing only atomic expressions, are themselves atomic. Unfortunately however, this trick cannot be used for branching. I'm not saying any of this is impossible, everything is perfectly safe from race conditions in the unscheduled environment. What i'm saying is all of these hacks could be made obsolete by a single, arguably very simple command.
  20. Foxyy

    SQF feature requests

    You are correct imperialalex, it's absolutely not a huge issue and might very well cause, among less experienced programmers, the issues you describe. I personally strive for correctness in all aspects of my code, and the lack of tools to do so in this particular regard irritates me. It's something that, if easily implemented, i would very much appreciate having. That said i probably shouldn't have placed it at the top of my list in the original post, the ordering of which is in no way indicative of the importance of each item. In fact, if i could choose only one of these features to be implemented it would definitely be the object serialization.
  21. Foxyy

    SQF feature requests

    A function when called in the scheduled environment executes synchronously only in the context of the scheduler, and then only if the function does not wait. Calling does not make a function uninterruptable by the scheduler. For example: [] spawn { call { systemChat str diag_frameNo; // n //A long running command to force the scheduler to go over the 3ms limit for the frame selectBestPlaces [position player, 1000, "forest + trees - meadow - houses - (10 * sea)", 5, 1]; systemChat str diag_frameNo; // n + m, m > 0 }; };
  22. Foxyy

    BIS_fnc_arrayShuffle - broken

    I don't have a whole lot of faith in the BIS functions and it seems at least in this case i'm right not to. This way i also get the option of modifying the original array, an option which in my opinion should not be omitted. In addition i like to know exactly what each piece of code does, without having to wade through someone else's potentially undocumented code.
  23. Foxyy

    SQF feature requests

    You're correct in that the scheduler will only start executing another thread if the first cedes control (sleep, waitUntil). However both unscheduled and native code can obviously execute while the scheduler is paused. In the case of unscheduled code one might use global variables to indicate ownership of an object or a context by a scheduled thread. In the case of native functionality (such as dropping an item in my previous example), one has to resort to some very ugly tricks to achieve correctness, if it is at all possible. Being able to have uninterruptable segments of code in the scheduled environment would simplify both tasks, and i doubt it would be very difficult to implement either.
  24. Foxyy

    BIS_fnc_arrayShuffle - broken

    I didn't even know there were BIS functions for shuffling and sorting. I just use a simple in-place Fisher-Yates. private ["_j", "_t"]; for "_i" from count _this - 1 to 1 step -1 do { //Select random index _j = floor random (_i + 1); //Swap if (_i != _j) then { _t = _this select _i; _this set [_i, _this select _j]; _this set [_j, _t]; }; }; _this To preserve the original just pass a copy. +_myArray call my_fnc_shuffle
  25. Also having the source client id passed to public variable event handlers would be great.
×