• Content count

  • Joined

  • Last visited

  • Medals

Community Reputation

13 Good


About Muzzleflash

  • Rank
    First Sergeant


  • Interests
    Little of everything
  1. I'm wondering if others have noticed this issue. When people control Ravens, there are bright (especially at night in NVG) spheres on the ground at the locations circled by the Ravens. Everyone, except the operator of a given Raven, can see the spheres. This is a bright telltale that someone is operating a Raven in the air above. I found this old post where it seems the spheres were introduced as invisible object for optimisation. But it seems they are only invisible to the operators.
  2. I've created a JSON parser for reading JSON files into sqf. Example of loading json file and into script: mydata.json { "name": "John Doe", "age": 34, "active": true, "qualifications": ["rifleman","grenadier"], "position": { "rank": "Private", "squad": "Bravo" } } your script, e.g. (init.sqf) //Load library [] call compile preProcessFile "json.sqf"; //Be sure to run in non-scheduled mode, otherwise the engine will halt parsing before completion. [] spawn { //Load data from json file _rawJson = loadFile "mydata.json"; _json = _rawJson call MF_Json_Parse; //Extract data from JSON structure _qualifications = [_json, "qualifications"] call MF_Json_Get; _rank = [_json, "position.rank"]; waitUntil {!isNull player}; //Update player attributes player setVariable ["MY_TAG_Qualifications", _qualifications, true]; player setRank (toUpper _rank); }; Performance is about 250 lines per second. It can handle files up to 10,000 lines, however, they will take extremely long to parse, and it is not intended for such huge amount of data. (It is still SQF). More information is available in the top of the script listed below. The script itself: /*** JSON Parser by Muzzleflash v0.987 --- To parse json _json = "JSON_STRING" call MF_Json_Parse _json now contains the JSON structure in SQF as described below. If some error occurs during parsing _json would be set to a string instead, so you to check for errors you should check whether the return is of type string. --- To ease use, MF_Json_Get can be used to read keys separated by period (.) It currently does not handle indexing into arrays --- Example Usage: FILE: mydata.json: { "name": "John Doe", "age": 34, "active": true, "qualifications": ["rifleman","grenadier"], "position": { "rank": "Private", "squad": "Bravo" } } Script: //Load library [] call compile preProcessFile "json.sqf"; _json = (loadFile "mydata.json") call MF_Json_Parse; //Find rank _rank = [_json, "position.rank"] call MF_Json_Get; --- How JSON data is mapped to SQF JSON objects map to: ["object", [[key_1, val_1], [key_2, val_2] ...]] JSON arrays map to: ["array", [val_1, val_2, val_3, ...]] JSON null maps to objNull The other JSON types maps to what you would expect, eg.: false, true, 123.456, "and strings" The above example would map to: ["object", [ ["name", "John Doe"], ["age", 34], ["active", true], ["qualifications", ["array", ["rifleman", "grenadier"]]], ["position", ["object", [ ["rank", "Private"], ["squad", "Bravo"] ]] ] ]] --- The only unsupported feature is \uXXXX inside strings. --- Performance notes Scheduled environment. (Do not parse in non-scheduled environment since the parsing is aborted halway by the engine) The second number in parantheses is the amount of time spent on lexing out of the total time taken. 254 lines (8577 chars) takes 0.81 (0.78) seconds 1010 lines (34693 chars) takes 3.29 (3.06) seconds 10082 lines (349246 chars) takes 34.19 (31.94) seconds On my budget non-server machine with 500 AI all engaged in battle simultaneous, the time to parse doubled. So expected performance is around 5000-10000 characters or 150-300 lines per second. ***/ //------ Getters MF_Json_Get = { private ["_node","_pathParts","_path","_node","_index"]; _node = _this select 0; _pathParts = (_this select 1) call MF_Json_PathParts; //For each part of the path { _part = _x; //Only objects have keys if (_node select 0 != "object") exitWith { _node = objNull; }; //Find index of key _index = -1; { if (_x select 0 == _part) exitWith { _index = _forEachIndex; }; } forEach (_node select 1); if (_index == -1) exitWith { _node = objNull; }; //Select child with the key matching the part _node = ((_node select 1) select _index) select 1; } forEach _pathParts; //Did client mean to extract array? if (typeName _node == typeName [] and {_node select 0 == "array"}) then { _node = _node select 1; }; _node }; MF_Json_PathParts = { private ["_path","_parts","_dot","_start"]; _path = toArray _this; _parts = []; _dot = toArray "." select 0; _start = 0; for "_i" from 0 to (count _path - 1) do { if (_path select _i == _dot) then { _parts set [count _parts, [_path, _start, _i - 1] call MF_Json_Lex_Extract]; _start = _i + 1; }; }; //Extract last part _parts set [count _parts, [_path, _start, count _path - 1] call MF_Json_Lex_Extract]; _parts }; //------ Parser MF_Json_Parse = { private ["_tokens","_parseState","_result"]; _tokens = _this call MF_Json_Lex; //Error? if (typeName _tokens == typeName "string") exitWith {_tokens}; _parseState = [_tokens, 0, ""]; _result = _parseState call MF_Json_Parse_Top; if (_parseState select 2 != "") exitWith {_parseState select 2}; _result }; MF_Json_SetError = { private ["_parseState", "_formatArgs"]; _parseState = _this select 0; _formatArgs = []; for "_i" from 1 to (count _this - 1) do { _formatArgs set [_i - 1, _this select _i]; }; _parseState set [2, format _formatArgs]; }; #define PARSE_TOKEN_TYPE (((_parseState select 0) select (_parseState select 1)) select 0) #define PARSE_TOKEN_VALUE (((_parseState select 0) select (_parseState select 1)) select 1) #define PARSE_HAS_ERROR (_parseState select 2 != "") #define PARSE_EXIT_IF_ERROR if PARSE_HAS_ERROR exitWith {_result}; #define PARSE_SET_ERROR(ERROR) [_parseState, "%1 at %2", ERROR, PARSE_TOKEN_VALUE] call MF_Json_SetError #define PARSE_SKIP if ((_parseState select 1) >= (count (_parseState select 0))) exitWith {[_parseState, "Expected more input after %1", ((_parseState select 0) select ((_parseState select 1) - 1))] call MF_Json_SetError;}; _parseState set [1, (_parseState select 1) + 1] #define PARSE_IGNORE(TOKEN) if (PARSE_TOKEN_TYPE != TOKEN) exitWith {[_parseState, "Expected token %1 near %2", TOKEN, PARSE_TOKEN_VALUE] call MF_Json_SetError;}; PARSE_SKIP #define PARSE_READ_VAL_INTO(VAR) VAR = PARSE_TOKEN_VALUE; PARSE_SKIP #define PARSE_COMPARE_CURRENT(VAL) (typeName PARSE_TOKEN_TYPE == typeName VAL and {PARSE_TOKEN_TYPE == VAL}) //JSON top level can only be object or array MF_Json_Parse_Top = { private ["_parseState"]; _parseState = _this; if (PARSE_TOKEN_TYPE == "lbrace") exitWith { _parseState call MF_Json_Parse_Object; }; if (PARSE_TOKEN_TYPE == "lbracket") exitWith { _parseState call MF_Json_Parse_Array; }; PARSE_SET_ERROR("Expected { or ["); }; MF_Json_Parse_Object = { private ["_parseState","_result","_kvArray","_key","_val"]; _parseState = _this; _kvArray = []; _result = ["object", _kvArray]; PARSE_IGNORE("lbrace"); if (PARSE_TOKEN_TYPE == "rbrace") exitWith { PARSE_SKIP; _result }; while {true} do { if (PARSE_TOKEN_TYPE != "string") exitWith { PARSE_SET_ERROR("String expected"); }; PARSE_READ_VAL_INTO(_key); PARSE_IGNORE("colon"); _val = _parseState call MF_Json_Parse_Value; PARSE_EXIT_IF_ERROR; _kvArray set [count _kvArray, [_key, _val]]; if (PARSE_TOKEN_TYPE == "rbrace") exitWith { PARSE_SKIP; _result }; if (PARSE_TOKEN_TYPE != "comma") exitWith { //Thanks for a buggy preprocessor , => comma PARSE_SET_ERROR("Expected comma or }"); }; PARSE_SKIP; }; _result }; MF_JSON_Parse_Array = { private ["_parseState","_array","_result","_val"]; _parseState = _this; _array = []; _result = ["array", _array]; PARSE_IGNORE("lbracket"); if (PARSE_TOKEN_TYPE == "rbracket") exitWith { PARSE_SKIP; _result }; while {true} do { _val = _parseState call MF_Json_Parse_Value; PARSE_EXIT_IF_ERROR; _array set [count _array, _val]; if (PARSE_TOKEN_TYPE == "rbracket") exitWith { PARSE_SKIP; _result }; if (PARSE_TOKEN_TYPE != "comma") exitWith { PARSE_SET_ERROR("Expected comma or ]"); }; PARSE_SKIP }; _result }; MF_Json_Parse_Value = { private ["_parseState","_result"]; _parseState = _this; if (PARSE_TOKEN_TYPE == "lbrace") exitWith { _parseState call MF_Json_Parse_Object }; if (PARSE_TOKEN_TYPE == "lbracket") exitWith { _parseState call MF_Json_Parse_Array }; if (PARSE_TOKEN_TYPE in ["string","number","bool","null"]) exitWith { PARSE_READ_VAL_INTO(_result); _result }; PARSE_SET_ERROR("Did not expect the value"); }; //----------------- Lexer MF_Json_Lex = { private ["_codePoints","_state","_startI","_currentI","_codePoint","_tokens","_error","_nextState","_action","_token"]; _codePoints = toArray _this; //EOF -- set does not work when the index is very large, even though still perfectly representable integer _codePoints set [count _codePoints, -1]; _state = 0; _startI = 0; _currentI = 0; _codePoint = _codePoints select _currentI; _tokens = []; _error = ""; scopeName "main"; while {true} do { //Skip blanks if (_state == 0 and (_codePoint in MF_Json_Blanks)) then { _currentI = _currentI + 1; _startI = _currentI; _codePoint = _codePoints select _currentI; } else { //Find next state _nextState = MF_Json_Lex_AcceptUnicodeTable select _state; //In table range? if (_codePoint >= 0 and _codePoint < 128) then { _nextState = (MF_Json_Lex_Table select _state) select _codePoint; }; //Token complete or bad input? if (_nextState == -1) then { //EOF? (Moved inside here for performance; yes it matters!) if (_state == 0 and _codePoint == -1) then { breakTo "main"; }; _action = MF_Json_Lex_AcceptingStates select _state; if (typeName _action == typeName -1) then { _error = format ["Lexer: Did not expect '%1' at this time", toString [_codePoint]]; breakTo "main"; }; //Extract token _token = [_codePoints, _startI, _currentI - 1] call _action; _tokens set [count _tokens, _token]; _nextState = 0; _startI = _currentI; } else { _currentI = _currentI + 1; _codePoint = _codePoints select _currentI; }; _state = _nextState; }; }; if (_error != "") exitWith {_error}; _tokens }; MF_Json_Lex_Extract = { private ["_codePoints","_fromI","_toI","_result"]; _codePoints = _this select 0; _fromI = _this select 1; _toI = _this select 2; _result = []; _result resize (_toI - _fromI + 1); for "_i" from _fromI to (_toI) do { _result set [_i - _fromI, _codePoints select _i]; }; toString _result }; MF_Json_Blanks = [32, 9, 10, 13]; //Lexer functions MF_Json_Lex_Func_Number = { ["number", parseNumber (_this call MF_Json_Lex_Extract)] }; MF_Json_Lex_Func_String = { //TODO: Handle unicode hexadecimal code points //Strip quotes ["string", [_this select 0, (_this select 1) + 1, (_this select 2) - 1] call MF_Json_Lex_Extract] }; MF_Json_Lex_Func_True = { ["bool", true] }; MF_Json_Lex_Func_False = { ["bool", false] }; MF_Json_Lex_Func_Null = { ["null", objNull] }; MF_Json_Lex_Func_Colon = { ["colon", ":"] }; MF_Json_Lex_Func_Comma = { ["comma", ","] }; MF_Json_Lex_Func_L_Brace = { ["lbrace", "{"] }; MF_Json_Lex_Func_L_Bracket = { ["lbracket", "["] }; MF_Json_Lex_Func_R_Brace = { ["rbrace", "}"] }; MF_Json_Lex_Func_R_Bracket = { ["rbracket", "]"] }; //-------- TABLES MF_Json_Lex_Table = [ //START, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,29,9,-1,-1,7,8,8,8,8,8,8,8,8,8,30,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,25,-1,26,-1,-1,-1,-1,-1,-1,-1,-1,18,-1,-1,-1,-1,-1,-1,-1,15,-1,-1,-1,-1,-1,22,-1,-1,-1,-1,-1,-1,27,-1,28,-1,-1], //STRING_1, [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], //STRING_2, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,1,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //STRING_3, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,4,4,4,4,4,4,4,4,4,-1,-1,-1,-1,-1,-1,-1,4,4,4,4,4,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,4,4,4,4,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //STRING_4, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,5,5,5,5,5,5,5,5,5,5,-1,-1,-1,-1,-1,-1,-1,5,5,5,5,5,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,5,5,5,5,5,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //STRING_5, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,6,6,6,6,6,6,6,6,6,6,-1,-1,-1,-1,-1,-1,-1,6,6,6,6,6,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,6,6,6,6,6,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //STRING_6, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NUMBER_1, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NUMBER_2, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,-1,8,8,8,8,8,8,8,8,8,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NUMBER_3, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,8,8,8,8,8,8,8,8,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NUMBER_4, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,11,11,11,11,11,11,11,11,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NUMBER_5, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,11,11,11,11,11,11,11,11,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NUMBER_6, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,13,-1,13,-1,-1,14,14,14,14,14,14,14,14,14,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NUMBER_7, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,14,14,14,14,14,14,14,14,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NUMBER_8, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,14,14,14,14,14,14,14,14,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NULL_1, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,16,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NULL_2, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,17,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NULL_3, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //FALSE_1, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,19,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //FALSE_2, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,20,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //FALSE_3, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //FALSE_4, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,33,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //TRUE_1, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,23,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //TRUE_2, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //TRUE_3, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,34,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //ACCEPT_LBRACKET, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //ACCEPT_RBRACKET, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //ACCEPT_LBRACE, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //ACCEPT_RBRACE, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //ACCEPT_COMMA, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //ACCEPT_COLON, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //STRING_ACCEPT, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //NULL_ACCEPT, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //FALSE_ACCEPT, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], //TRUE_ACCEPT, [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1] ]; MF_Json_Lex_AcceptUnicodeTable = [ -1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ]; MF_Json_Lex_AcceptingStates = [ -1,-1,-1,-1,-1,-1,-1,MF_Json_Lex_Func_Number,MF_Json_Lex_Func_Number,-1,-1,MF_Json_Lex_Func_Number,-1,-1,MF_Json_Lex_Func_Number,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,MF_Json_Lex_Func_L_Bracket,MF_Json_Lex_Func_R_Bracket,MF_Json_Lex_Func_L_Brace,MF_Json_Lex_Func_R_Brace,MF_Json_Lex_Func_Comma,MF_Json_Lex_Func_Colon,MF_Json_Lex_Func_String,MF_Json_Lex_Func_Null,MF_Json_Lex_Func_False,MF_Json_Lex_Func_True ];
  3. No it does not imply that. You can store the number (2 ^ 128)-1 in an unsigned integer of 128 bit. However, floating point numbers have a different internal representation that works differently. You can represent (2 ^ 128)-1 (and no more!) using only single-precision float (4 bytes), however, you are not guaranteed the less significant numbers are accurate. Likewise you can store 0.000000000053143453132231 in a floating point number, again no guarantee that it is exactly the number you guaranteed. Basically a 'normal' int and float each only take 4 bytes, giving 32 bits, giving 2^32 different possibilities. Integers can represent, well integers, accurately as long as they are withing the range +(2^31 - 1) to -(2^31) for signed integers. Floats can represent much larger or smaller numbers, but can only accurately represent least significant numbers. A 4 byte float should give you between 6 to 9 significant (decimal) digits. My guess is that the engine either: - Stores all numbers as C floats. This causes no issue normally since most numbers are are less than 9 digits long. - Converts between C floats and C integers automatically.
  4. Groups don't contain vehicles. Groups contain people. Vehicles are in the group of whichever units are in it. (Guessing driver or commander decides). I'm guessing this is the reasons you get the null: - There aren't any units in the heli belonging to the group and an empty vehicle does not belong to any group.
  5. Yes this is possible if you add gear from a script. You can use this to decide what to add: if (isClass(configFile >> "CfgPatches" >> "ace_main")) then { //ACE is running //Add ace gear. } else { //ACE is not running! //Add vanilla gear }; However, since there is no addon dependency people without ACE can join the server, but they will probably get classname errors and ACE weapons will be invisible from their perspective.
  6. No, you should change it to something else. HORDE would be fine. Remember to change it everywhere (also the 2 defines at the top). Only think it is unsafe if the "actual" code to be run is not thread safe: From the globalEvent call: any publicVariabled data are guaranteed to arrive separate, so if you do 2 global events at the same time, then they will still arrive in some order. From the localEvent: when the handler for addPublicVariableHandler runs it runs to completion before any other publicVariabled events are processed. Since localEvent also calls each handler there is no issue with the event "framework". If you own code is affected by race conditions then it will still be affected by if you used two variables. The only place I can see where you might have this problem is if you addEventHandler while a events are already being processed. However that can be fixed by copying the handler array when processing: TAG_LocalEvent = { private ["_event","_args","_eventHandlers"]; _event = _this select 0; _args = if (count _this > 1) then {_this select 1} else {[]}; _eventHandlers = [color="#009000"]+[/color]TAG_EventHandlers getVariable [_event, []]; { //Handler may have been removed. if (!isNil "_x") then { _args call _x; }; } forEach _eventHandlers; };
  7. You should run the file on mission init (preferable: call compile preProcessFile "events.sqf"; ) You call it like this: ["MyEvent", ["My", "Arguments", "Here"]] call Tag_GlobalEvent; //Global event means it will run everywhere (machines) there you have added an event handler with that name. See below. Listeners are added like this: ["MyEvent", { //You get there parameters here: private ["_me", "_arguments", "_here"]; _me = _this select 0; _arguments = _this select 1; _here = _this select 2; //Do weird greeting hint format ["%1 are %2 %3", _here, _me, _arguments]; }] call TAG_AddEventHandler; Can't remember which environment addPublicVariableEventHandler runs in, so if you plan to do sleeping or long running loops in your event 'handler code' you may want to spawn it, to prevent it from blocking other event handlers for the same event, eg.: ["MyEvent", { //Don't block (sleep) other events _this spawn { //Code here that might sleep or take long. Still have all parameters since they are passed in. }; }] call TAG_AddEventHandler; I modified the code above. No reason to change this. It still get all the parameters here from the AddEventHandler shown first. I consider it good style to keep, the "real code" separate from the "message passing" code, be it CBA-style events, publicVariable, RE framework or whatever. During your init or similar you add the event handler for all machines (or those that need): ["Horde_SpaRemPar", { //You sleep in the called code, so it gets spawned. //All the parameters are in _this.. Eg. _this = [_pl, _pos, _type] (horde_fnc_spawn_particle_effect) _this spawn horde_fnc_spawn_remote_particles; }] call TAG_AddEventHandler; So you avoid sending all the code each time. With some minor modifications horde_fnc_spawn_particle_effect and horde_fnc_spawn_remote_particles could be exactly the same you could call GlobalEvent from the fired event handler directly.
  8. If you for some reason can't/won't use CBA then this mimics the event functionality:
  9. Avast is definitely being weird. It suddenly gave me warnings a week ago when attempting to start it and moved it to virus chest. Then when scanned it said nothing was found.
  10. It was not meant to comphrensive and be able to process all caes, just the most common cases for where you might want to remove duplicates. However, yes good idea to add the incompatible types check, especially if someone is going to use the function elsewhere. I've never had any trouble comparing BOOLs. Another interesting case is null.. Should [objNull] == [objNull]? Might make sense from a certain viewpoint, however, may cause confusion since objNull != objNull is the 'vanilla' case.
  11. Got around to attempting it myself. Good catch with _arrayA, just found that myself and also the 'not' in RemoveDuplicates should not be there.. With these codes I got it working: FancyIsEqual = { private ["_objectA","_objectB","_result","_elemB","_elemB"]; _objectA = _this select 0; _objectB = _this select 1; //Nils? if (isNil "_objectA") exitWith {isNil "_objectB"}; //Do they have the same type? if (typeName _objectA != typeName _objectB) exitWith {false}; //Are they values? if (typeName _objectA != typeName []) exitWith {_objectA == _objectB}; //It must be arrays. Do they have same length? if (count _objectA != count _objectB) exitWith {false}; //Process each element; assume true _result = true; for "_i" from 0 to (count _objectA - 1) do { _elemA = _objectA select _i; _elemB = _objectB select _i; //Process recursively if (not ([_elemA, _elemB] call FancyIsEqual)) exitWith {_result = false;}; }; _result }; RemoveDuplicates = { private ["_array", "_unduplicated", "_original","_exists"]; _array = _this; _unduplicated = []; { _original = _x; _exists = false; { if ([_original, _x] call FancyIsEqual) exitWith { _exists = true; }; } forEach _unduplicated; if (not _exists) then { _unduplicated set [count _unduplicated, _original]; }; } forEach _array; _unduplicated }; The hint'ed result are to the right: hint str ( [ [1, [2,3]], [1, [2,3]] ] call FancyIsEqual); true hint str ( [ [1, [2,3]], [1, [2,4]] ] call FancyIsEqual); false hint str ( [ [1,2,3], [2,3,4], [1,2,3] ] call RemoveDuplicates); [[1,2,3],[2,3,4]] hint str ( [ [1, [2, 3]], [[1, 2],3], [1, [2, 3]] ] call RemoveDuplicates ); [[1,[2,3]],[[1,2],3]] Yes order matters. [1,2] is not the same as [2, 1] using FancyEqual.
  12. The "problem" with arrays are that they don't compare equal. [1,2,3] == [1,2,3] (false) So I define equality by the content of the arrays, eg. I want it to be the case that the above is true. I also want this to be true (it is equally simple to implement): [ [1, 2], 3] == [ [1, 2], 3] This is what FancyIsEqual checks for. The plan to remove duplicates is then, given: Original: [ [1,2,3], [2,3,4], [1,2,3] ] New: [] Then we take the first item [1,2,3] and check if it already is in the new array using FancyIsEqual since == doesn't work. If it isn't so New: [ [1,2,3] ] Then we take the next item [2,3,4] and check. None of the current elements in New array matches so we add it: New: [ [1,2,3], [2,3,4] ] Then we check the last item [1,2,3]. Using == it would give false since it is in fact two different arrays. Just happens to have the same content. But FancyIsEqual idenfies the as equal so it is not added. Resulting in: New: [ [1,2,3], [2,3,4] ] Good catch. Hadn't noticed that. I've attempted to fix it: RemoveDuplicates = { private ["_array", "_unduplicated", "_original","_exists"]; _array = _this; _unduplicated = []; { _original = _x; _exists = false; { if (not ([_original, _x] call FancyIsEqual)) exitWith { _exists = true; }; } forEach _unduplicated; if (not _exists) then { _unduplicated set [count _unduplicated, _original]; }; } forEach _array; _unduplicated }; I don't know if you are going to be using nil in your code. But to make FancyIsEqual more robust maybe add these lines as the first check: if (isNil "_objectA") exitWith {isNil "_objectB"}; Which properly checks that if one value is 'nil' then the other has to be too for them to be equal.
  13. It is not part of the functions module. Looking at the function,, you want to call it doesn't look like it will handle nested arrays, since you have to check if every element is the same. We can solve this by creating a function that checks if two (nested)arrays are equal and then another to check the entire array for duplicates: Checks if two objects are equal. They are if they are of the same type and value. For array they are if they have the same length and same content: FancyIsEqual = { private ["_objectA","_objectB","_result","_elemB","_elemB"]; _objectA = _this select 0; _objectB = _this select 1; //Do they have the same type? if (typeName _objectA != typeName _objectB) exitWith {false}; //Are they values? if (typeName _objectA != typeName []) exitWith {_objectA == _objectB}; //It must be arrays. Do they have same length? if (count _objectA != count _objectB) exitWith {false}; //Process each element; assume true _result = true; for "_i" from 0 to (count _arrayA - 1) do { _elemA = _objectA select _i; _elemB = _objectB select _i; //Process recursively if (not ([_elemA, _elemB] call FancyIsEqual)) exitWith {_result = false;}; }; _result }; Now we can remove duplicates. Keep adding to a new array and check if we already added it to the new array. If we did then it is a duplicate and should not be added again. RemoveDuplicates = { private ["_array", "_unduplicated", "_original"]; _array = _this; _unduplicated = []; { _original = _x; { if (not ([_original, _x] call FancyIsEqual)) exitWith { _unduplicated set [count _unduplicated, _original]; }; } forEach _unduplicated; } forEach _array; }; I have not checked this for syntax or logic errors.
  14. Most likely because player object has not been set yet when you do the local check. Anything objNull is never local.
  15. Yes. You could do something like this: if (isServer) then { setViewDistance 1337; }; Or if you allow players to change their viewdistance, this might be more suitable: if (isDedicated) then { setViewDistance 1337; }; Beware, some scripts change viewdistance on their own, like certain AI scripts serverside.