callExtension: Difference between revisions
Jump to navigation
Jump to search
Lou Montana (talk | contribs) |
Killzone Kid (talk | contribs) (x64 linux was out for a while) |
||
Line 36: | Line 36: | ||
<br><br> | <br><br> | ||
<u>Linux specific</u><br> | <u>Linux specific</u><br> | ||
While on Windows the extension name is case-insensitive, on Linux the extension name is case-sensitive and should match the name of the .so file exactly (minus ".so" part) | While on Windows the extension name is case-insensitive, on Linux the extension name is case-sensitive and should match the name of the .so file exactly (minus ".so" part).<br><br> | ||
{{Feature | important | If a user has anti-virus software running, this could cause brand new extension to stutter the game and return with <tt>EXECUTION_WARNING_TAKES_TOO_LONG</tt> when executed for the first time, because of the AV software scanning. After the extension is whitelisted by AV this should go away until a new version of the extension is installed. Perhaps a dummy call to the extension on init should be considered as a feature of implementation to account for that}} | {{Feature | important | If a user has anti-virus software running, this could cause brand new extension to stutter the game and return with <tt>EXECUTION_WARNING_TAKES_TOO_LONG</tt> when executed for the first time, because of the AV software scanning. After the extension is whitelisted by AV this should go away until a new version of the extension is installed. Perhaps a dummy call to the extension on init should be considered as a feature of implementation to account for that}} |
Revision as of 08:33, 19 March 2021
Description
- Description:
- Description needed
- Groups:
- System
Syntax
- Syntax:
- Syntax needed
- Parameters:
- extension: String - extension name
- function: String - data sent to the extension
- Return Value:
- Return value needed
Alternative Syntax
- Syntax:
- extension callExtension [function, arguments] Template:Since
- Parameters:
- extension: String - extension name
- function: String - extension function identifier
- arguments: Array - function arguments. Could be array of Anything, each element will be converted to String automatically. Current allowed max length of this array is 2048 (since Arma 3 v1.92; previous limit: 1024)
- Return Value:
- Array - in format [result, returnCode, errorCode], where:
Examples
- Example 1:
_return = "myExtension" callExtension "stringToBeParsed";
- Example 2:
_result = "test_extension" callExtension str weapons player; _result = "test_extension" callExtension ["fnc1", getUnitLoadout player]; _result = "test_extension" callExtension ["fnc2", magazinesAmmoFull player]; _result = "test_extension" callExtension ["fnc1", [weapons player, magazines player]];
- Example 3:
_result = "test_extension" callExtension ["fnc1", [1,"two",true,[4,"five",false]]]; parseSimpleArray (_result select 0) params ["_number","_string","_boolean","_array"]; systemChat str [_number,_string,_boolean,_array];
Source Code (Download .dll)
This is an example of an extension compatible with both syntaxes. When using 1st syntax, the data is just copied from input to output. When using alt syntax, the arguments are parsed and then assembled back into string array in 2 ways: fnc1 and fnc2. fnc1 is a fraction faster.#include <string> #include <vector> #include <iterator> #include <sstream> #define CURRENT_VERSION "1.0.0.1" extern "C" { //--- Engine called on extension load __declspec (dllexport) void __stdcall RVExtensionVersion(char *output, int outputSize); //--- STRING callExtension STRING __declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function); //--- STRING callExtension ARRAY __declspec (dllexport) int __stdcall RVExtensionArgs(char *output, int outputSize, const char *function, const char **args, int argsCnt); } //--- Extension version information shown in .rpt file void __stdcall RVExtensionVersion(char *output, int outputSize) { //--- max outputSize is 32 bytes strncpy_s(output, outputSize, CURRENT_VERSION, _TRUNCATE); } //--- name callExtension function void __stdcall RVExtension(char *output, int outputSize, const char *function) { std::string str = function; strncpy_s(output, outputSize, ("Input Was: " + str).c_str(), _TRUNCATE); } //--- name callExtension [function, args] int __stdcall RVExtensionArgs(char *output, int outputSize, const char *function, const char **args, int argsCnt) { if (strcmp(function, "fnc1") == 0) { //--- Manually assemble output array int i = 0; std::string str = "["; //--- Each argument can be accessed via args[n] if (argsCnt > 0) str += args[i++]; while (i < argsCnt) { str += ","; str += args[i++]; } str += "]"; //--- Extension result strncpy_s(output, outputSize, str.c_str(), _TRUNCATE); //--- Extension return code return 100; } else if (strcmp(function, "fnc2") == 0) { //--- Parse args into vector std::vector<std::string> vec(args, std::next(args, argsCnt)); std::ostringstream oss; if (!vec.empty()) { //--- Assemble output array std::copy(vec.begin(), vec.end() - 1, std::ostream_iterator<std::string>(oss, ",")); oss << vec.back(); } //--- Extension result strncpy_s(output, outputSize, ("[" + oss.str() + "]").c_str(), _TRUNCATE); //--- Extension return code return 200; } else { strncpy_s(output, outputSize, "Avaliable Functions: fnc1, fnc2", outputSize - 1); return -1; } }
- Example 4:
fncToExecute_1 = { hint format ["Extension Result 1: %1", _this] };
fncToExecute_2 = { hint format ["Extension Result 2: %1", _this] }; fncToExecute_3 = { hint format ["Extension Result 3: %1", _this] };
addMissionEventHandler ["ExtensionCallback", { params ["_name", "_function", "_data"]; if (_name isEqualTo "test_callback") then { parseSimpleArray _data call (missionNamespace getVariable [_function, { hint "Function does not exist!" }]); }; }];
"test_callback" callExtension str "test data";
Here is a minimal example of an extension utilising extension callback (don't actually do it like this). fncToExecute_X function is called from "ExtensionCallback" event handler when it is triggered after 2 seconds of the extension call.#include <thread> #include <string> #include <chrono> extern "C" { __declspec (dllexport) void __stdcall RVExtensionRegisterCallback(int(*callbackProc)(char const *name, char const *function, char const *data)); __declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function); } int(*callbackPtr)(char const *name, char const *function, char const *data) = nullptr; void __stdcall RVExtensionRegisterCallback(int(*callbackProc)(char const *name, char const *function, char const *data)) { callbackPtr = callbackProc; } void __stdcall RVExtension(char *output, int outputSize, const char *function) { if (!callbackPtr) return; std::thread ([](std::string fnc) { using namespace std::chrono_literals; fnc = "[1,2,3," + fnc + "]"; for (int i = 1; i < 4; ++i) // run 3 times { std::this_thread::sleep_for(2s); // sleep for 2 seconds callbackPtr("test_callback", ("fncToExecute_" + std::to_string(i)).c_str(), fnc.c_str()); } }, function).detach(); }
Additional Information
- See also:
- callcompileparseSimpleArrayExtensions
Notes
-
Report bugs on the Feedback Tracker and/or discuss them on the Arma Discord or on the Forums.
Only post proven facts here! Add Note