#include "..\script_component.hpp" /* * Function: forge_client_org_fnc_initOrgStore * Author: IDSolutions * * Description: * Initializes a client-side organization store interface for managing player organization data * Provides CRUD operations for organizations, including database persistence through ArmaDragonflyClient * * Creates a hashMap object with methods for: * - Creating, loading, and saving organizations * - Managing organization funds and reputation * - Adding, removing, and querying organization members and assets * * Returns: * Organization store interface * * Example: * private _orgStore = call forge_client_org_fnc_initOrgStore; * _orgStore call ["createOrg", [getPlayerUID player, "My Organization"]]; */ private _orgStoreInterface = createHashMapObject [[ ["#type", "IOrganizationStore"], ["#create", { /** * Initializes the organization store interface * * Sets up the initial state of the organization store: * - Clears any existing organization data * - Sets the current user's UID as the playerUID * - Marks the store as not loaded * - Triggers database loading of organization data * * @return {Boolean} True if initialization was successful */ _self set ["currentOrganization", nil]; _self set ["playerUID", getPlayerUID player]; _self set ["isLoaded", false]; _self call ["loadFromDatabase", []]; true }], ["loadFromDatabase", { /** * Loads organization data from the database * * Retrieves organization data associated with the current player's UID * from the database using the ArmaDragonflyClient database system. * Sets isLoaded to false until the data is retrieved and processed by * the handleOrgLoad callback function. * * @return {Void} No return value */ private _playerUID = _self get "playerUID"; private _orgID = format ["%1_org", _playerUID]; ["hgetallid", _orgID, "", -1, [], QFUNC(handleOrgLoad), false, netId player] remoteExecCall ["dragonfly_db_fnc_addTask", 2, false]; _self set ["isLoaded", false]; }], ["saveToDatabase", { /** * Saves the current organization data to the database * * Processes the organization data structure for database storage: * - Serializes string values for name and owner * - Converts the members hashMap to a flattened array format * - Converts the assets hashMap to a flattened array format * - Sends the processed data to the database using ArmaDragonflyClient * * @return {Boolean} True if save was successful, false if no organization data exists */ private _orgData = _self get "currentOrganization"; if (isNil "_orgData") exitWith { ["No organization data to save", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _processedData = createHashMapFromArray []; { private _key = _x; private _value = _orgData get _key; if (_key in ["name", "owner"] && _value isEqualType "") then { _value = [_value] call EFUNC(misc,serializeString); }; // Convert members hashMap back to array format for storage if (_key == "members" && _value isEqualType createHashMap) then { private _flattenedMembers = []; { private _uid = _x; private _memberMap = _value get _uid; if (!isNil "_memberMap") then { private _name = _memberMap get "name"; // Replace spaces with underscores for storage if (_name isEqualType "") then { _name = [_name] call EFUNC(misc,serializeString); }; private _role = _memberMap get "role"; private _joinDate = _memberMap get "joinDate"; private _memberArray = [_uid, _name, _role, _joinDate]; // Add any additional properties { if !(_x in ["uid", "name", "role", "joinDate"]) then { _memberArray pushBack _x; _memberArray pushBack (_memberMap get _x); }; } forEach (keys _memberMap); _flattenedMembers pushBack _memberArray; }; } forEach (keys _value); _value = _flattenedMembers; }; // Convert assets hashMap back to flat array for storage if (_key == "assets" && _value isEqualType createHashMap) then { private _flattenedAssets = []; { private _type = _x; private _typeAssets = _value get _type; { private _assetMap = _x; private _id = _assetMap get "id"; private _className = _assetMap get "className"; private _flatAsset = [_type, _className, "id", _id]; // Add all other properties as key-value pairs { if (_x != "className" && _x != "id") then { _flatAsset pushBack _x; _flatAsset pushBack (_assetMap get _x); }; } forEach (keys _assetMap); _flattenedAssets pushBack _flatAsset; } forEach _typeAssets; } forEach (keys _value); _value = _flattenedAssets; }; _processedData set [_key, _value]; } forEach (keys _orgData); private _data = [ _processedData get "id", "id", [_processedData get "id"], "name", [_processedData get "name"], "owner", [_processedData get "owner"], "funds", [_processedData get "funds"], "reputation", [_processedData get "reputation"], "assets", [_processedData get "assets"], "members", [_processedData get "members"], "logs", [_processedData get "logs"], "created", [_processedData get "created"], "lastModified", [_processedData get "lastModified"] ]; ["hsetidbulk", "", "", -1, _data, "", false, netId player] remoteExecCall ["dragonfly_db_fnc_addTask", 2, false]; true }], ["generateOrgID", { /** * Generates a unique organization ID based on the owner's UID * * Creates a standardized organization ID format by appending "_org" * to the player's UID, ensuring consistent ID generation for database storage. * * @param {String} _uid The player UID to use as the base for the organization ID * @return {String} The generated organization ID, or empty string if UID is invalid */ params [["_uid", "", [""]]]; if (_uid == "") exitWith { ["Owner UID cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify; "" }; private _orgID = format ["%1_org", _uid]; _orgID }], ["createOrg", { /** * Creates a new organization with the specified parameters * * Initializes a new organization with the given name and owner, * setting up the initial structure with default values for funds, * reputation, assets, members, and logs. Adds the current player * as the owner in the members list and saves to the database. * * @param {String} _uid The player UID who will be the organization owner * @param {String} _name The name of the organization * @param {Number} _initialFunds Starting funds for the organization (default: 0) * @param {Number} _initialReputation Starting reputation for the organization (default: 0) * @return {HashMap} The newly created organization data, or nil if creation failed */ params [["_uid", "", [""]], ["_name", "", [""]], ["_initialFunds", 0, [0]], ["_initialReputation", 0, [0]]]; if (_uid == "" || _name == "") exitWith { ["Owner UID and name cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify; nil }; if (!isNil {_self get "currentOrganization"}) exitWith { ["You are already part of an organization", "warning", 5, "right"] call forge_client_misc_fnc_notify; nil }; private _dateTime = call EFUNC(misc,getSystemTime); private _orgID = _self call ["generateOrgID", [_uid]]; private _orgData = createHashMapFromArray [ ["id", _orgID], ["name", _name], ["owner", _uid], ["funds", _initialFunds], ["reputation", _initialReputation], ["assets", createHashMap], ["members", createHashMap], ["logs", []], ["created", _dateTime], ["lastModified", _dateTime] ]; // Create owner member entry private _memberMap = createHashMap; _memberMap set ["uid", _uid]; _memberMap set ["name", name player]; _memberMap set ["role", "owner"]; _memberMap set ["joinDate", _dateTime]; // Add to members hashMap private _members = _orgData get "members"; _members set [_uid, _memberMap]; _orgData set ["members", _members]; _self set ["currentOrganization", _orgData]; _self call ["saveToDatabase", []]; SETPVAR(player,FORGE_Organization,_orgID); _orgData }], ["getOrg", { /** * Retrieves the current organization data * * Gets the organization data for the current player. If the data * hasn't been loaded yet, waits until the loading process completes * before returning the data. * * @return {HashMap} The current organization data, or nil if not in an organization */ if (!(_self get "isLoaded")) then { waitUntil { _self get "isLoaded" }; }; _self get "currentOrganization" }], ["syncWithDatabase", { /** * Synchronizes the current organization data with the database * * Updates the lastModified timestamp and saves the current * organization data to the database. Used to ensure database * consistency after making changes to the organization. * * @return {Boolean} True if sync was successful, false if no organization data exists */ private _orgData = _self get "currentOrganization"; if (isNil "_orgData") exitWith { ["No organization data to sync", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; _orgData set ["lastModified", call EFUNC(misc,getSystemTime)]; _self set ["currentOrganization", _orgData]; _self call ["saveToDatabase", []]; true }], ["updateFunds", { /** * Updates the organization's funds balance * * Adds or subtracts the specified amount from the organization's funds. * Records the transaction in the organization logs with timestamp, * amount changed, and new balance. * * @param {Number} _amount The amount to add (positive) or subtract (negative) * @return {Boolean} True if update was successful, false if no organization exists */ params [["_amount", 0, [0]]]; private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _funds = _orgData get "funds"; private _dateTime = call EFUNC(misc,getSystemTime); private _newFunds = _funds + _amount; _orgData set ["funds", _newFunds]; _orgData set ["lastModified", _dateTime]; // Add to logs private _logs = _orgData get "logs"; _logs pushBack [_dateTime, "FUNDS_UPDATED", _amount, _newFunds]; _orgData set ["logs", _logs]; _self set ["currentOrganization", _orgData]; _self call ["saveToDatabase", []]; true }], ["getFunds", { /** * Retrieves the current funds balance of the organization * * Gets the current financial balance of the organization. * Used for displaying funds or checking if sufficient funds * are available for transactions. * * @return {Number} The current funds amount, or nil if no organization exists */ private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; nil }; _orgData getOrDefault ["funds", 0] }], ["updateReputation", { /** * Updates the organization's reputation value * * Adds or subtracts the specified amount from the organization's reputation. * Records the change in the organization logs with timestamp, * amount changed, and new reputation value. * * @param {Number} _amount The amount to add (positive) or subtract (negative) * @return {Boolean} True if update was successful, false if no organization exists */ params [["_amount", 0, [0]]]; private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _reputation = _orgData get "reputation"; private _newReputation = _reputation + _amount; _orgData set ["reputation", _newReputation]; _orgData set ["lastModified", call EFUNC(misc,getSystemTime)]; // Add to logs private _dateTime = call EFUNC(misc,getSystemTime); private _logs = _orgData get "logs"; _logs pushBack [_dateTime, "REPUTATION_UPDATED", _amount, _newReputation]; _orgData set ["logs", _logs]; _self set ["currentOrganization", _orgData]; _self call ["saveToDatabase", []]; true }], ["getReputation", { /** * Retrieves the current reputation value of the organization * * Gets the current reputation score of the organization. * Used for displaying reputation or checking if sufficient reputation * is available for certain actions or unlocks. * * @return {Number} The current reputation value, or nil if no organization exists */ private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; nil }; _orgData getOrDefault ["reputation", 0] }], ["addAsset", { /** * Adds a new asset to the organization's inventory * * Creates and stores a new asset entry in the organization's assets collection. * Assets are organized by type (vehicles, buildings, etc.) and include * a unique ID, class name, and any additional custom properties. * Records the addition in the organization logs. * * @param {String} _assetType The category/type of the asset (e.g., "vehicle", "building") * @param {String} _className The class name of the asset in the game * @param {HashMap} _properties Additional properties to store with the asset * @return {String} The generated unique ID for the asset, or false if failed */ params [["_assetType", "", [""]], ["_className", "", [""]], ["_properties", createHashMap, [createHashMap]]]; if (_assetType == "" || _className == "") exitWith { ["Asset type and className cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _assets = _orgData get "assets"; if !(_assets isEqualType createHashMap) then { _assets = createHashMap; }; // Get or create the asset type array private _typeAssets = _assets getOrDefault [_assetType, []]; // Generate a unique ID for this asset private _assetId = format ["%1_%2", _className, call EFUNC(misc,getSystemTime)]; // Create the asset hashMap private _assetMap = createHashMap; _assetMap set ["id", _assetId]; _assetMap set ["className", _className]; // Add all provided properties { if (_x != "className" && _x != "id") then { _assetMap set [_x, _properties get _x]; }; } forEach (keys _properties); // Add as a new asset _typeAssets pushBack _assetMap; _assets set [_assetType, _typeAssets]; _orgData set ["assets", _assets]; _orgData set ["lastModified", call EFUNC(misc,getSystemTime)]; // Add to logs private _dateTime = call EFUNC(misc,getSystemTime); private _logs = _orgData get "logs"; _logs pushBack [_dateTime, "ASSET_ADDED", _assetType, _className, _assetId]; _orgData set ["logs", _logs]; _self set ["currentOrganization", _orgData]; _self call ["saveToDatabase", []]; _assetId // Return the generated ID }], ["getAssets", { /** * Retrieves assets from the organization's inventory * * Flexible method to get assets from the organization with multiple retrieval options: * - Get all assets across all types * - Get all assets of a specific type * - Get a specific asset by ID or className * * @param {String} _assetType Optional type/category to filter assets (empty for all types) * @param {String} _idOrClassName Optional ID or className to find a specific asset * @param {Boolean} _findById If true, search by ID; if false, search by className * @return {Array|HashMap|Nil} Asset data based on search parameters, or nil if not found */ params [["_assetType", "", [""]], ["_idOrClassName", "", [""]], ["_findById", false, [false]]]; private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; nil }; private _assets = _orgData get "assets"; if !(_assets isEqualType createHashMap) then { _assets = createHashMap; }; // Get specific asset by ID or className if (_assetType != "" && _idOrClassName != "") then { private _typeAssets = _assets getOrDefault [_assetType, []]; private _index = -1; if (_findById) then { _index = _typeAssets findIf {(_x get "id") == _idOrClassName}; } else { // Get first matching className (for backward compatibility) _index = _typeAssets findIf {(_x get "className") == _idOrClassName}; }; if (_index != -1) then { _typeAssets select _index } else { nil } } else { if (_assetType != "") then { _assets getOrDefault [_assetType, []] } else { private _allAssets = []; { private _type = _x; private _typeAssets = _assets get _type; { private _assetMap = _x; private _id = _assetMap get "id"; private _className = _assetMap get "className"; private _flatAsset = [_type, _className, "id", _id]; // Add all other properties as key-value pairs { if (_x != "className" && _x != "id") then { _flatAsset pushBack _x; _flatAsset pushBack (_assetMap get _x); }; } forEach (keys _assetMap); _allAssets pushBack _flatAsset; } forEach _typeAssets; } forEach (keys _assets); _allAssets } } }], ["removeAsset", { /** * Removes an asset from the organization's inventory * * Deletes a specific asset from the organization's assets collection * based on its type and unique ID. Records the removal in the * organization logs with details about the removed asset. * * @param {String} _assetType The category/type of the asset to remove * @param {String} _assetId The unique ID of the asset to remove * @return {Boolean} True if asset was successfully removed, false if not found or error */ params [["_assetType", "", [""]], ["_assetId", "", [""]]]; if (_assetType == "" || _assetId == "") exitWith { ["Asset type and asset ID cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _assets = _orgData get "assets"; if !(_assets isEqualType createHashMap) then { _assets = createHashMap; }; private _typeAssets = _assets getOrDefault [_assetType, []]; private _index = _typeAssets findIf {(_x get "id") == _assetId}; if (_index != -1) then { private _asset = _typeAssets select _index; private _className = _asset get "className"; _typeAssets deleteAt _index; _assets set [_assetType, _typeAssets]; _orgData set ["assets", _assets]; // Add to logs private _dateTime = call EFUNC(misc,getSystemTime); private _logs = _orgData get "logs"; _logs pushBack [_dateTime, "ASSET_REMOVED", _assetType, _className, _assetId]; _orgData set ["logs", _logs]; _orgData set ["lastModified", call EFUNC(misc,getSystemTime)]; _self set ["currentOrganization", _orgData]; _self call ["saveToDatabase", []]; true } else { false }; }], ["addMember", { /** * Adds a new member to the organization * * Creates and stores a new member entry in the organization's members collection. * Only the organization owner can add new members. Each member has a UID, name, * role, and join date. Records the addition in the organization logs. * * @param {String} _uid The unique player ID of the member to add * @param {String} _name The display name of the member * @param {String} _role The role/rank of the member in the organization (default: "member") * @return {Boolean} True if member was successfully added, false if error or not authorized */ params [["_uid", "", [""]], ["_name", "", [""]], ["_role", "member", [""]]]; if (_uid == "" || _name == "") exitWith { ["Member UID and name cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _playerUID = _self get "playerUID"; if ((_orgData get "owner") != _playerUID) exitWith { ["Only the owner can add members", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _members = _orgData get "members"; if !(_members isEqualType createHashMap) then { _members = createHashMap; }; // Check if member already exists if (!isNil {_members get _uid}) exitWith { private _errorMsg = format ["Member already in this organization: %1", _uid]; [_errorMsg, "warning", 5, "right"] call forge_client_misc_fnc_notify; true }; // Create member hashMap private _memberMap = createHashMap; private _joinDate = call EFUNC(misc,getSystemTime); // Add member data to hashMap _memberMap set ["uid", _uid]; _memberMap set ["name", _name]; _memberMap set ["role", _role]; _memberMap set ["joinDate", _joinDate]; // Add to members hashMap _members set [_uid, _memberMap]; _orgData set ["members", _members]; _orgData set ["lastModified", call EFUNC(misc,getSystemTime)]; // Add to logs private _dateTime = call EFUNC(misc,getSystemTime); private _logs = _orgData get "logs"; _logs pushBack [_dateTime, "MEMBER_ADDED", _uid, _name, _role]; _orgData set ["logs", _logs]; _self set ["currentOrganization", _orgData]; _self call ["saveToDatabase", []]; true }], ["removeMember", { /** * Removes a member from the organization * * Deletes a member from the organization's members collection based on their UID. * Only the organization owner can remove members, and the owner cannot remove themselves. * Records the removal in the organization logs. * * @param {String} _uid The unique player ID of the member to remove * @return {Boolean} True if member was successfully removed, false if not found or not authorized */ params [["_uid", "", [""]]]; if (_uid == "") exitWith { ["Member UID cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _playerUID = _self get "playerUID"; if ((_orgData get "owner") != _playerUID) exitWith { ["Only the owner can remove members", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _members = _orgData get "members"; if !(_members isEqualType createHashMap) then { _members = createHashMap; }; // Get member and check if they exist private _memberMap = _members get _uid; if (isNil "_memberMap") exitWith { private _errorMsg = format ["Member not in organization: %1", _uid]; [_errorMsg, "error", 5, "right"] call forge_client_misc_fnc_notify; false }; // Check if trying to remove the owner if ((_memberMap get "role") == "owner") exitWith { ["Cannot remove the organization owner", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; // Get name for logging private _name = _memberMap get "name"; // Remove from hashMap _members deleteAt _uid; _orgData set ["members", _members]; _orgData set ["lastModified", call EFUNC(misc,getSystemTime)]; // Add to logs private _dateTime = call EFUNC(misc,getSystemTime); private _logs = _orgData get "logs"; _logs pushBack [_dateTime, "MEMBER_REMOVED", _uid, _name]; _orgData set ["logs", _logs]; _self set ["currentOrganization", _orgData]; _self call ["saveToDatabase", []]; [format ["Member %1 removed from organization", _name], "info", 5, "right"] call forge_client_misc_fnc_notify; true }], ["getMembers", { /** * Retrieves members from the organization * * Gets either a specific member by UID or all members of the organization. * Returns member data including UID, name, role, and join date. * * @param {String} _uid Optional UID to get a specific member (empty for all members) * @return {HashMap|Array|Nil} Member data for specific member, array of all members, or nil if error */ params [["_uid", "", [""]]]; private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; nil }; private _members = _orgData get "members"; if !(_members isEqualType createHashMap) then { _members = createHashMap; }; // Get specific member by UID if (_uid != "") then { _members get _uid } else { // Get all members private _allMembers = []; { _allMembers pushBack (_members get _x); } forEach (keys _members); _allMembers } }], ["deleteOrg", { /** * Deletes the entire organization * * Permanently removes the organization from the database. * Only the organization owner can delete the organization. * Clears the current organization data from the store after deletion. * * @return {Boolean} True if organization was successfully deleted, false if not authorized */ private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _playerUID = _self get "playerUID"; if ((_orgData get "owner") != _playerUID) exitWith { ["Only the owner can delete the organization", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _orgID = _orgData get "id"; ["del", _orgID, "", -1, [], "", false, netId player] remoteExecCall ["dragonfly_db_fnc_addTask", 2, false]; _self set ["currentOrganization", nil]; _self set ["isLoaded", true]; true }], ["leaveOrg", { /** * Removes the current player from the organization * * Allows a member to leave the organization they're currently in. * The organization owner cannot use this method (must use deleteOrg instead). * Records the departure in the organization logs before removing player access. * * @return {Boolean} True if player successfully left the organization, false if error or owner */ private _orgData = _self call ["getOrg", []]; if (isNil "_orgData") exitWith { ["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify; false }; private _playerUID = _self get "playerUID"; if ((_orgData get "owner") == _playerUID) exitWith { ["Organization owner cannot leave, must delete instead", "warning", 5, "right"] call forge_client_misc_fnc_notify; false }; private _members = _orgData get "members"; if !(_members isEqualType createHashMap) then { _members = createHashMap; }; // Get member data private _memberMap = _members get _playerUID; if (!isNil "_memberMap") then { private _dateTime = call EFUNC(misc,getSystemTime); private _memberName = _memberMap get "name"; // Add to logs private _logs = _orgData get "logs"; _logs pushBack [_dateTime, "MEMBER_LEFT", _playerUID, _memberName]; _orgData set ["logs", _logs]; _self call ["saveToDatabase", []]; }; _self set ["currentOrganization", nil]; _self set ["isLoaded", true]; ["You have left the organization", "info", 5, "right"] call forge_client_misc_fnc_notify; true }] ]]; SETMVAR(FORGE_ORG_STORE_REG,_orgStoreInterface); GETMVAR(FORGE_ORG_STORE_REG,_orgStoreInterface)