Object Oriented SQF Scripting v1.3.1 - v1 Commercial Distribution b1 By Naught GitHub: https://github.com/dylanplecki/RBS/blob/master/addons/rbs_main/h/oop.h Issues: https://github.com/dylanplecki/RBS/issues Download: https://raw.github.com/dylanplecki/RBS/master/addons/rbs_main/h/oop.h Description What is object oriented programming? From Wikipedia, the page being a recommended read for anyone interested in the possibilities of object-oriented programming (OOP), So, as you can see, Arma is already largely object-oriented with its extensive use of vehicles, units, players, shapes, groups, locations, and so on. So wouldn't it be logical to fully carry this syntax over to the SQF scripting language? So what can I do with it? Instead of having long, drawn-out lists of functions all centered around the same goal, we can instead have one object with many functions (behaviors) and variables (states) integrated within it. This practice can simplify complex tasks by utilizing our minds natural thinking pattern of internal and external interaction - or what "I" do, and what "they" see. For example, in Arma we can have an object such as a "platoon", and that platoon is made up of Arma groups. Instead of making an array holding a list of all of these groups, and then having functions for adding/removing groups from the platoon, we can just have a platoon object, with an array of groups as one of its states and have the adding/removing of groups as some of the platoon's behaviors. A pseudo-sketch of this object would look like this: class Platoon { array Groups; function AddGroup(group); function RemoveGroup(group); }; So now all the programmer has to do is create a new Platoon and add/remove groups directly to the object - easy, right? Features Human-readable syntax that closely resembles PHP's OOP integration.
Extensively documented source-code for ease-of-use.
Only one header file, and it's fully macro-based, and only executed by the preprocessor.
Implements full class-based object inheritance.
Compiles to full-speed SQF code, so no need for run-time interpretation!
Allows for public, protected, and private class members, for instituting complex objects and inheritance.
Full support for polymorphism (to the limits of the SQF syntax).
Small memory footprint - all functions are static, and no code is unnecessarily duplicated.
Support for constructors and deconstructors.
Completely recursive via the MEMBER macro.
Allows for static variables, which are persistent to all classes of the same type.
Note: Objects cannot be copied to other machines just by sending the object variable - all data members (object variables) need to be serialized (preferably to an array), transferred, and then added to a new object on the remote machine.
Examples Sorry for the weird indentation, that's what I get for working in Linux. Basic Example (probably doesn't work): #include "oop.h" CLASS("StatSheet") // Player Statistics Sheet Object PRIVATE STATIC_VARIABLE("scalar","playerCount"); // Static variables are shared amongst all instances of this class PRIVATE VARIABLE("object","player"); PRIVATE VARIABLE("scalar","kills"); // Scalar == Number PRIVATE VARIABLE("scalar","deaths"); PRIVATE VARIABLE("scalar","score"); PUBLIC FUNCTION("object","constructor") { // Accepts an object as a parameter private ["_player"]; _player = _this; INC_VAR("playerCount"); // Increases the member by 1 MEMBER("player",_player); // Sets the member to the given value MEMBER("kills",0); // Important to initialize all necessary members MEMBER("deaths",0); MEMBER("score",0); }; PUBLIC FUNCTION("nil","deconstructor") { // Accepts no parameters (nil) DEC_VAR("playerCount"); // Decreases the member by 1 DELETE_VARIABLE("player"); // Must delete all members on deconstruction to avoid memory leaks DELETE_VARIABLE("kills"); DELETE_VARIABLE("deaths"); DELETE_VARIABLE("score"); }; PUBLIC FUNCTION("","addKill") { INC_VAR("kills"); MEMBER("kills",nil); // Return total kills }; PUBLIC FUNCTION("","addDeath") { // Also accepts no parameters (same as "nil", or "" == "nil") INC_VAR("deaths"); MEMBER("deaths",nil); // Return total deaths }; PUBLIC FUNCTION ("scalar","addScore") { // Accepts scalar (number) as parameter MOD_VAR("score",_this); // Adds the param to the member, ie. (0 + 1) }; PUBLIC FUNCTION("","getKills") FUNC_GETVAR("kills"); // Shorthand for getting variables PUBLIC FUNCTION("","getDeaths") FUNC_GETVAR("deaths"); PUBLIC FUNCTION("","getScore") FUNC_GETVAR("score"); ENDCLASS; EXAMPLE_fnc_addStatTracker = { private ["_unit", "_stats"]; _unit = _this select 0; _stats = ["new", _unit] call StatSheet; ["addScore", (score _unit)] call _stats; _unit setVariable ["stats", _stats]; }; EXAMPLE_fnc_remStatTracker = { private ["_unit", "_stats"]; _unit = _this select 0; _stats = _unit getVariable ["stats", {}]; // All objects are actually a "code" type _unit setVariable ["stats", nil]; ["delete", _stats] call StatSheet; }; Advanced Example: /* Title: Hashmap Library Author: Dylan Plecki (Naught) Version: 1.0.3.1 - v1.0 CD b1 API Example: _hm = ["new"] call UCD_obj_hashMap; ["insert", ["key", value]] call _hm; _val = ["get", ["key", defaultValue]] call _hm; ["erase", "key"] call _hm; ["delete", _hm] call UCD_obj_hashMap; License: Copyright © 2013 Dylan Plecki. All rights reserved. Except where otherwise noted, this work is licensed under CC BY 4.0, available for reference at <http://creativecommons.org/licenses/by/4.0/>. */ #include "oop.h" // Required /* Group: Hashmap Object */ CLASS("UCD_obj_hashMap") // Unique unordered map PRIVATE VARIABLE("array", "map"); PUBLIC FUNCTION("","constructor") { #define DFT_MAP [[],[]] // Since param macros can't correctly parse comma-delimited arrays MEMBER("map",DFT_MAP); }; PUBLIC FUNCTION("","deconstructor") { DELETE_VARIABLE("map"); }; PUBLIC FUNCTION("array","get") { // ["key", default], returns value (any) private ["_map", "_index"]; _map = MEMBER("map",nil); _index = (_map select 0) find (_this select 0); if (_index >= 0) then { (_map select 1) select _index; } else {_this select 1}; }; PUBLIC FUNCTION("string","get") { // "key", returns value (any) private ["_args"]; _args = [_this, nil]; MEMBER("get",_args); }; PUBLIC FUNCTION("array","insert") { // ["key", value], returns overwritten (bool) private ["_map", "_index"]; _map = MEMBER("map",nil); _index = (_map select 0) find (_this select 0); if (_index >= 0) then { (_map select 1) set [_index, (_this select 1)]; true; } else { _index = count (_map select 0); (_map select 0) set [_index, (_this select 0)]; (_map select 1) set [_index, (_this select 1)]; false; }; }; PUBLIC FUNCTION("string","erase") { // "key", returns success (bool) private ["_map", "_index"]; _map = MEMBER("map",nil); _index = (_map select 0) find (_this select 0); if (_index >= 0) then { private ["_last"]; _last = (count (_map select 0)) - 1; (_map select 0) set [_index, ((_map select 0) select _last)]; (_map select 1) set [_index, ((_map select 1) select _last)]; (_map select 0) resize _last; (_map select 1) resize _last; true; } else { false; }; }; PUBLIC FUNCTION("","copy") { // nil, returns hashmap (array) MEMBER("map",nil); }; PUBLIC FUNCTION("array","copy") { // [hashMap], returns nothing (nil) MEMBER("map",_this); }; ENDCLASS; Success Stories AI Caching and Distribution Script
Object-Oriented Hashmaps
Object-Oriented Marker