Refactor: Database and Client Updates

This commit introduces several changes related to database interactions and client-side functionality:

*   **Database Response Handling:** Implements a mechanism to handle responses from server requests, specifically for database operations. This includes setting up a callback system to process results based on request IDs.
*   **Store Functionality:** Corrects a typo in the `fnc_buyItem.sqf` script, changing `EFUNC(armory,addArmoryItem)` to `EFUNC(arsenal,addArmoryItem)`.
*   **Inventory Management:** Improves the `fnc_moveInventory.sqf` script by correcting a conditional statement to ensure proper handling of inventory items.
*   **Configuration Updates:** Updates the mod configuration (`CfgMods.hpp`) to use the correct path for the mod picture.
*   **Client Initialization:** Adds a client registration call to the server during client post-initialization (`XEH_postInit_client.sqf`).
*   **Workflow Update:** Updates the build workflow to use the latest Ubuntu runner.
*   **Database Preparation:** Removes unnecessary preparations from `XEH_postInit.sqf` and `XEH_PREP.hpp`.
This commit is contained in:
Jacob Schmidt 2025-03-28 09:46:24 -05:00
parent 39c8648bd6
commit 613f05d52a
37 changed files with 841 additions and 242 deletions

View File

@ -16,7 +16,7 @@ on:
jobs:
build:
name: Build
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Checkout Source Code
uses: actions/checkout@v4

BIN
addons/db.7z Normal file

Binary file not shown.

View File

@ -1,3 +1 @@
PREP(saveToMission);
PREP(saveToProfile);
PREP(saveToTempDB);
PREP(requestServerDB);

View File

@ -1,3 +1 @@
#include "script_component.hpp"
GVAR(tempDB) = [];
#include "script_component.hpp"

View File

@ -1 +1,3 @@
#include "script_component.hpp"
#include "script_component.hpp"
["forge_db_registerClient", [getPlayerUID player, clientOwner]] call CBA_fnc_serverEvent;

View File

@ -5,4 +5,18 @@ PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
// Handle responses from server requests
["forge_db_response", {
params ["_targetUID", "_requestType", "_result", "_requestID"];
if (_targetUID isEqualTo getPlayerUID player) then {
if (!isNil QGVAR(pendingCallbacks)) then {
private _callback = GVAR(pendingCallbacks) getOrDefault [_requestID, {}];
GVAR(pendingCallbacks) deleteAt _requestID;
[_result, _requestType] call _callback;
};
};
}] call CBA_fnc_addEventHandler;
ADDON = true;

Binary file not shown.

View File

@ -0,0 +1,35 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_db_fnc_requestServerDB
* Author: J. Schmidt
*
* Description:
* Sends database requests to the server using CBA events
*
* Arguments:
* 0: _type - Type of database operation <STRING>
* 1: _data - Data for the operation <ANY>
* 2: _callback - Function to call when data is returned <CODE>
*
* Return Value:
* Request ID <STRING>
*/
params [
["_type", "", [""]],
["_data", nil, [createHashMap, [], "", 0, true, objNull]],
["_callback", {}, [{}]]
];
private _requestID = format ["%1_%2", diag_tickTime, random 1000];
if (isNil QGVAR(pendingCallbacks)) then {
GVAR(pendingCallbacks) = createHashMap;
};
GVAR(pendingCallbacks) set [_requestID, _callback];
["forge_db_request", [getPlayerUID player, _type, _data, _requestID]] call CBA_fnc_serverEvent;
_requestID

View File

@ -1,111 +0,0 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_db_fnc_saveToMission
* Author: J.Schmidt
* Edit: 07.23.2024
* Copyright © 2024 J.Schmidt, All rights reserved
*
* Do not edit without permission!
*
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivative 4.0 International License.
* To view a copy of this license, vist https://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to Creative Commons,
* PO Box 1866, Mountain View, CA 94042
*
* [Description]
* Store mission and player data in Mission Namespace.
*
* Arguments:
* N/A
*
* Return Value:
* N/A
*
* Examples:
* [] call forge_client_db_fnc_saveToMission;
*
* Public: Yes
*/
if (isNil "companyFunds") then { companyFunds = 0 };
if (isNil "companyRating") then { companyRating = 0 };
if (isNil "companyGenerals") then { companyGenerals = [] };
if (isNil "companyGarageUnlocks") then { companyGarageUnlocks = [] };
if (isNil EGVAR(arsenal,armory_unlocks)) then { EGVAR(arsenal,armory_unlocks) = [[],[],[],[]] };
if (isNil EGVAR(arsenal,garage_unlocks)) then { EGVAR(arsenal,garage_unlocks) = [[],[],[],[],[],[]] };
private _vdata = [];
private _pdata = [];
private _cdata = [
["key", "CompanyState"],
["funds", [companyFunds]],
["rating", [companyRating]],
["operations", [companyGenerals]],
["garage_unlocks", [companyGarageUnlocks]]
];
private _vehicles = nearestObjects [player, ["LandVehicle"], 50] apply {
createHashMapFromArray [
["vehicle", _x],
["class", [typeOf _x]],
["position", [getPosATL _x]],
["direction", [getDir _x]],
["health", [damage _x]]
];
};
{
if (alive _x) then {
_vdata pushBackUnique _x;
};
} forEach _vehicles;
{
private _data = [
["key", getPlayerUID player],
// ["armory_unlocks", [forge_client_armory_arsenalUnlocks]],
// ["garage_unlocks", [forge_client_armory_garageUnlocks]],
["armory_unlocks", [EGVAR(arsenal,armory_unlocks)]],
["garage_unlocks", [EGVAR(arsenal,garage_unlocks)]],
// ["locker", [player getVariable ["Locker", []]]],
// ["garage", [player getVariable ["Garage", []]]],
["locker", [GETVAR(player,FORGE_Locker,[])]],
["garage", [GETVAR(player,FORGE_Garage,[])]],
// ["cash", [player getVariable ["FORGE_Cash", 0]]],
// ["bank", [player getVariable ["FORGE_Bank", 0]]],
["cash", [GETVAR(player,FORGE_Cash,0)]],
["bank", [GETVAR(player,FORGE_Bank,0)]],
// ["number", [player getVariable ["FORGE_Phone_Number", "unknown"]]],
// ["email", [player getVariable ["FORGE_Email", "unknown@spearnet.mil"]]],
["number", [GETVAR(player,FORGE_Phone_Number,"unknown")]],
["email", [GETVAR(player,FORGE_Email,"unknown@spearnet.mil")]],
// ["paygrade", [player getVariable ["Paygrade", "E1"]]],
["paygrade", [GETVAR(player,FORGE_Paygrade,"E1")]],
["reputation", [rating player]],
["loadout", [getUnitLoadout player]],
// ["holster", [player getVariable ["FORGE_Holster_Weapon", true]]],
["holster", [GETVAR(player,FORGE_Holster_Weapon,true)]],
["position", [getPosASLVisual player]],
["direction", [getDirVisual player]]
];
if (isNull objectParent player) then {
_data pushBack "currentWeapon";
_data pushBack [currentMuzzle player];
_data pushBack "stance";
_data pushBack [stance player];
};
_pdata pushBackUnique _data;
} forEach playableUnits;
private _cHashMap = createHashMapFromArray _cdata;
private _pHashMap = createHashMapFromArray _pdata;
private _vHashMap = createHashMapFromArray _vdata;
// missionProfileNamespace setVariable ["FORGE_MissionData", _cHashMap];
// missionProfileNamespace setVariable ["FORGE_PlayerData", _pHashMap];
// missionProfileNamespace setVariable ["FORGE_VehicleData", _vHashMap];
SETPVAR(missionNamespace,FORGE_MissionData,_cHashMap);
SETPVAR(missionNamespace,FORGE_PlayerData,_pHashMap);
SETPVAR(missionNamespace,FORGE_VehicleData,_vHashMap);

View File

@ -1,69 +0,0 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_db_fnc_saveToProfile
* Author: J.Schmidt
* Edit: 07.23.2024
* Copyright © 2024 J.Schmidt, All rights reserved
*
* Do not edit without permission!
*
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivative 4.0 International License.
* To view a copy of this license, vist https://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to Creative Commons,
* PO Box 1866, Mountain View, CA 94042
*
* [Description]
* Store player data in Profile Namespace.
*
* Arguments:
* N/A
*
* Return Value:
* N/A
*
* Examples:
* [] call forge_client_db_fnc_saveToProfile;
*
* Public: Yes
*/
// if (isNil "forge_client_armory_arsenalUnlocks") then { forge_client_armory_arsenalUnlocks = [] };
// if (isNil "forge_client_armory_garageUnlocks") then { forge_client_armory_garageUnlocks = [] };
if (isNil EGVAR(arsenal,armory_unlocks)) then { EGVAR(arsenal,armory_unlocks) = [[],[],[],[]] };
if (isNil EGVAR(arsenal,garage_unlocks)) then { EGVAR(arsenal,garage_unlocks) = [[],[],[],[],[],[]] };
private _data = [
["key", getPlayerUID player],
["armory_unlocks", [EGVAR(arsenal,armory_unlocks)]],
["garage_unlocks", [EGVAR(arsenal,garage_unlocks)]],
// ["locker", [player getVariable ["Locker", []]]],
// ["garage", [player getVariable ["Garage", []]]],
["locker", [GETVAR(player,FORGE_Locker,[])]],
["garage", [GETVAR(player,FORGE_Garage,[])]],
// ["cash", [player getVariable ["FORGE_Cash", 0]]],
// ["bank", [player getVariable ["FORGE_Bank", 0]]],
["cash", [GETVAR(player,FORGE_Cash,0)]],
["bank", [GETVAR(player,FORGE_Bank,0)]],
// ["number", [player getVariable ["FORGE_Phone_Number", "unknown"]]],
// ["email", [player getVariable ["FORGE_Email", "unknown@spearnet.mil"]]],
["number", [GETVAR(player,FORGE_PhoneNumber,"unknown")]],
["email", [GETVAR(player,FORGE_Email,"unknown@spearnet.mil")]],
// ["paygrade", [player getVariable ["Paygrade", "E1"]]],
["paygrade", [GETVAR(player,FORGE_Paygrade,"E1")]],
["reputation", [rating player]],
["loadout", [getUnitLoadout player]],
// ["holster", [player getVariable ["FORGE_Holster_Weapon", true]]],
["holster", [GETVAR(player,FORGE_Holster_Weapon,true)]],
["position", [getPosASLVisual player]],
["direction", [getDirVisual player]]
];
if (isNull objectParent player) then {
_data pushBack ["currentWeapon", [currentMuzzle player]];
_data pushBack ["stance", [stance player]];
};
private _hashMap = createHashMapFromArray _data;
// profileNamespace setVariable ["FORGE_PlayerData", _hashMap];
SETVAR(profileNamespace,FORGE_PlayerData,_hashMap);

View File

@ -1,51 +0,0 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_db_fnc_saveToTempDB
* Author: J.Schmidt
* Edit: 07.23.2024
* Copyright © 2024 J.Schmidt, All rights reserved
*
* Do not edit without permission!
*
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivative 4.0 International License.
* To view a copy of this license, vist https://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to Creative Commons,
* PO Box 1866, Mountain View, CA 94042
*
* [Description]
* Store data in Temp DB.
*
* Arguments:
* 0: Name of Event <STRING>
* 1: Name of DB <STRING>
* 2: UID of Player <STRING>
* 3: Name of Key <STRING>
* 4: Value to store in key <ARRAY|STRING|NUMBER|BOOL>
*
* Return Value:
* N/A
*
* Examples:
* ["playerStatus", "players", "76561198027566824", "status", "available"] call forge_client_db_fnc_saveToTempDB;
*
* Public: Yes
*/
params [["_event", "", [""]], ["_db", "", [""]], ["_uid", "", [""]], ["_key", "", [""]], ["_value", "", [[], 0, "", false]]];
if (isNil "_event") exitWith { ["No Event provided"] call BFUNC(log); };
if (isNil "_db") exitWith { ["No DB provided"] call BFUNC(log); };
if (isNil "_uid") exitWith { ["No UID provided"] call BFUNC(log); };
if (isNil "_key") exitWith { ["No key provided"] call BFUNC(log); };
if (isNil "_value") exitWith { ["No Value provided"] call BFUNC(log); };
["Received event: %1", _this] call BFUNC(logFormat);
private _response = [GVAR(tempDB), [_db, _uid, _key], _value] call BFUNC(dbValueSet);
if !(_response) then {
["Failed to set Key '%1' for UID '%2' with '%3' to DB", _key, _uid, _value] call BFUNC(logFormat);
} else {
SETPVAR(missionNamespace,FORGE_TempDb,GVAR(tempDB));
["Successfully set key '%1' for UID '%2' with '%3'", _key, _uid, _value] call BFUNC(logFormat);
};

View File

@ -3,7 +3,7 @@ class CfgMods {
dir = "@forge_client";
name = "FORGE Client";
author = "IDSolutions";
picture = "A3\Ui_f\data\Logos\arma3_expansion_alpha_ca";
picture = "A3\Ui_f\data\Logos\arma3_expansion_alpha_ca.paa";
hideName = "false";
hidePicture = "false";
action = "https://innovativedevsolutions.org";

View File

@ -59,7 +59,7 @@ if (_backpack != "") then {
{
private _holderWeapons = ((getWeaponCargo _x) select 0) select { _x in _weapons };
if !(_holderWeapons isEqualTo []) then {
if (_holderWeapons isNotEqualTo []) then {
deleteVehicle _x;
};
} forEach _nearHolders;

1
addons/org/$PBOPREFIX$ Normal file
View File

@ -0,0 +1 @@
z\forge_client\addons\org

View File

@ -0,0 +1,19 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
};
};
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
serverInit = QUOTE(call COMPILE_FILE(XEH_preInit_server));
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_postInit));
clientInit = QUOTE(call COMPILE_FILE(XEH_postInit_client));
};
};

13
addons/org/XEH_PREP.hpp Normal file
View File

@ -0,0 +1,13 @@
PREP(acceptInvite);
PREP(addAsset);
PREP(addFunds);
PREP(addReputation);
PREP(create);
PREP(disband);
PREP(initOrgStore);
PREP(invite);
PREP(join);
PREP(leave);
PREP(listInvites);
PREP(removeAsset);
PREP(verifyOrgStore);

View File

@ -0,0 +1 @@
#include "script_component.hpp"

View File

@ -0,0 +1,6 @@
#include "script_component.hpp"
// Initialize organization store
[{!isNil "FORGE_STORE_REG"}, {
[] call FUNC(initOrgStore);
}] call CFUNC(waitUntilAndExecute);

View File

@ -0,0 +1,8 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;

View File

@ -0,0 +1 @@
#include "script_component.hpp"

View File

@ -0,0 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

16
addons/org/config.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "script_component.hpp"
class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"forge_client_main"};
authors[] = {"J. Schmidt", "Creedcoder"};
author = "IDSolutions";
VERSION_CONFIG;
};
};
#include "CfgEventHandlers.hpp"

View File

@ -0,0 +1,31 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_acceptInvite
* Author: J. Schmidt
*
* Description:
* Allows a player to accept an organization invite from their stored invites
*
* Arguments:
* 0: _playerUID - Player UID <STRING>
* 1: _playerName - Player Name <STRING>
* 2: _inviteKey - Invite key from the player's invites <STRING>
*
* Return Value:
* Success <BOOL>
*/
params [["_playerUID", "", [""]], ["_playerName", "", [""]], ["_inviteKey", "", [""]]];
if (_playerUID == "" || _playerName == "" || _inviteKey == "") exitWith { TRACE_3("Invalid parameters for accepting invitation",_playerUID,_playerName,_inviteKey); false };
private _playerInvites = GETVAR(profileNamespace,FORGE_ORG_INVITES,createHashMap);
private _invite = _playerInvites get _inviteKey;
if (isNil "_invite") exitWith { TRACE_1("Invite not found",_inviteKey); false };
private _orgName = _invite get "orgName";
private _ownerUID = _invite get "ownerUID";
[_ownerUID, _orgName, _playerUID, _playerName, "member"] call FUNC(join);

View File

@ -0,0 +1,49 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_addAsset
* Author: J. Schmidt
*
* Description:
* Adds an asset to an organization's inventory
*
* Arguments:
* 0: _uid - Player UID <STRING>
* 1: _name - Organization name <STRING>
* 2: _assetType - Type of asset (vehicle, building, etc.) <STRING>
* 3: _assetData - Asset data <HASHMAP>
*
* Return Value:
* Updated assets collection <HASHMAP>
*/
params [["_uid", "", [""]], ["_name", "", [""]], ["_assetType", "", [""]], ["_assetData", createHashMap, [createHashMap]]];
if (_uid == "" || _name == "" || _assetType == "") exitWith { TRACE_3("Invalid parameters for adding asset",_uid,_name,_assetType); nil };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _uid, _name];
private _org = _store call ["getByKey", [_key]];
private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }};
private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6];
if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); nil };
private _assets = _org get "assets";
private _logs = _org get "logs";
private _owner = _org get "owner";
if (isNil { _assets get _assetType }) then { _assets set [_assetType, []]; };
private _typeAssets = _assets get _assetType;
_typeAssets pushBack _assetData;
_org set ["assets", _assets];
_logs pushBack [_dateTime, "ASSET_ADDED", _assetType, _assetData];
_org set ["logs", _logs];
_store call ["post", [_owner, _name]];
_assets

View File

@ -0,0 +1,44 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_addFunds
* Author: J. Schmidt
*
* Description:
* Adds funds to an organization's account
*
* Arguments:
* 0: _uid - Player UID <STRING>
* 1: _name - Organization name <STRING>
* 2: _amount - Amount to add (can be negative for withdrawals) <NUMBER>
*
* Return Value:
* New funds amount <NUMBER>
*/
params [["_uid", "", [""]], ["_name", "", [""]], ["_amount", 0, [0]]];
if (_uid == "" || _name == "") exitWith { TRACE_2("Invalid parameters for adding funds",_uid,_name); nil };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _uid, _name];
private _org = _store call ["getByKey", [_key]];
private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }};
private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6];
if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); nil };
private _funds = _org get "funds";
private _logs = _org get "logs";
private _owner = _org get "owner";
private _newFunds = _funds + _amount;
_org set ["funds", _newFunds];
_logs pushBack [_dateTime, "FUNDS_ADDED", _amount, _newFunds];
_org set ["logs", _logs];
_store call ["post", [_owner, _name]];
_newFunds

View File

@ -0,0 +1,44 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_addReputation
* Author: J. Schmidt
*
* Description:
* Adds reputation to an organization
*
* Arguments:
* 0: _uid - Player UID <STRING>
* 1: _name - Organization name <STRING>
* 2: _amount - Amount of reputation to add (can be negative) <NUMBER>
*
* Return Value:
* New reputation amount <NUMBER>
*/
params [["_uid", "", [""]], ["_name", "", [""]], ["_amount", 0, [0]]];
if (_uid == "" || _name == "") exitWith { TRACE_2("Invalid parameters for adding reputation",_uid,_name); nil };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _uid, _name];
private _org = _store call ["getByKey", [_key]];
private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }};
private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6];
if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); nil };
private _reputation = _org get "reputation";
private _logs = _org get "logs";
private _owner = _org get "owner";
private _newReputation = _reputation + _amount;
_org set ["reputation", _newReputation];
_logs pushBack [_dateTime, "REPUTATION", _amount, _newReputation];
_org set ["logs", _logs];
_store call ["post", [_owner, _name]];
_newReputation

View File

@ -0,0 +1,43 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_create
* Author: J. Schmidt
*
* Description:
* Creates a new organization for a player
*
* Arguments:
* 0: _ownerUID - Player UID <STRING>
* 1: _ownerName - Player name <STRING>
* 2: _name - Organization name <STRING>
*
* Return Value:
* Success <BOOL>
*/
params [["_ownerUID", "", [""]], ["_ownerName", "", [""]], ["_name", "", [""]]];
if (_ownerUID == "" || _ownerName == "" || _name == "") exitWith { TRACE_3("Invalid parameters for organization creation",_ownerUID,_ownerName,_name); false };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _ownerUID, _name];
private _existingOrg = _store call ["getByKey", [_key]];
private _playerAlreadyInOrg = false;
{
private _org = _x;
private _members = _org get "members";
if (!isNil { _members get _ownerUID }) exitWith {
_playerAlreadyInOrg = true;
};
} forEach (_store call ["get", []]);
if (_playerAlreadyInOrg) exitWith { TRACE_1("Player already in an organization",_ownerUID); false };
_store call ["post", [_ownerUID, _name, 0, 0]];
[_name, _ownerUID, _ownerName, "owner"] call FUNC(join);
TRACE_2("Organization created successfully",_name,_ownerUID);
true

View File

@ -0,0 +1,33 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_disband
* Author: J. Schmidt
*
* Description:
* Disbands an organization if requested by the owner
*
* Arguments:
* 0: _uid - UID of the player attempting to disband <STRING>
* 1: _name - Organization name <STRING>
*
* Return Value:
* Success <BOOL>
*/
params [["_uid", "", [""]], ["_name", "", [""]]];
if (_uid == "" || _name == "") exitWith { TRACE_2("Invalid parameters for disbanding organization",_uid,_name); false };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _uid, _name];
private _org = _store call ["getByKey", [_key]];
if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); false };
if ((_org get "owner") != _uid) exitWith { TRACE_2("Player is not the owner of this organization",_uid,_name); false };
_store call ["delete", [_key]];
TRACE_1("Organization disbanded successfully",_name);
true

View File

@ -0,0 +1,134 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_initOrgStore
* Author: J. Schmidt
*
* Description:
* Initializes player organization data using the database interface
*
* Arguments:
* None
*
* Return Value:
* Organization interface <OBJECT>
*/
private _orgStoreInterface = createHashMapObject [[
["#type", "IOrganizationStore"],
["#create", {
private _store = GETMVAR(FORGE_STORE_REG,nil);
if (isNil "_store") exitWith { ERROR_MSG("Store not initialized"); false };
private _orgStore = _store call ["getStore", ["organizations"]];
private _orgNameIndex = _store call ["getStore", ["organizationNameIndex"]];
private _orgRegistry = GETVAR(profileNamespace,FORGE_ORG_REG,createHashMap);
if (isNil "_orgStore" || isNil "_orgNameIndex") then { _orgStore = _store call ["createStore", ["organizations"]]; };
if (isNil "_orgNameIndex") then { _orgNameIndex = _store call ["createStore", ["organizationNameIndex"]]; };
private _name = _orgRegistry get "name";
private _uid = _orgRegistry get "owner";
if (!isNil "_name" && !isNil "_uid") then {
private _key = format ["%1_%2", _uid, _name];
_orgStore set [_key, _orgRegistry];
_orgNameIndex set [_key, _name];
};
true
}],
["post", {
params [["_uid", "", [""]], ["_name", "", [""]], ["_initialFunds", 0, [0]], ["_initialReputation", 0, [0]]];
if (_uid == "" || _name == "") exitWith { ERROR_MSG("Owner UID and, or name cannot be empty"); nil };
private _store = GETMVAR(FORGE_STORE_REG,nil);
private _key = format ["%1_%2", _uid, _name];
private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }};
private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6];
private _orgRegistry = GETVAR(profileNamespace,FORGE_ORG_REG,createHashMap);
private _existingOrgKey = _store call ["get", ["organizationNameIndex", _key]];
private _existingOrg = nil;
private _orgData = nil;
if !(isNil "_existingOrgKey") then {
_existingOrg = _store call ["get", ["organizations", _existingOrgKey]];
};
if !(isNil "_existingOrg") then {
_orgData = _existingOrg;
} else {
_orgData = createHashMapFromArray [
["name", _name],
["owner", _uid],
["funds", _initialFunds],
["reputation", _initialReputation],
["assets", createHashMap],
["members", createHashMap],
["invites", createHashMap],
["logs", []],
["created", _dateTime]
];
_orgRegistry set [_key, _orgData];
SETVAR(profileNamespace,FORGE_ORG_REG,_orgRegistry);
saveProfileNamespace;
};
_store call ["set", ["organizationNameIndex", _key, _name]];
_store call ["set", ["organizations", _key, _orgData]];
_orgData
}],
["get", {
private _store = GETMVAR(FORGE_STORE_REG,nil);
private _orgStore = _store call ["getStore", ["organizations"]];
if (isNil "_orgStore") exitWith { createHashMap };
_orgStore
}],
["getByKey", {
params [["_key", "", [""]]];
if (_key == "") exitWith { ERROR_MSG("Key cannot be empty"); nil };
private _store = GETMVAR(FORGE_STORE_REG,nil);
private _org = _store call ["get", ["organizations", _key]]
if (isNil "_org") exitWith { ERROR_MSG_1("Organization with composite key %1 not found", _key); nil };
_org
}],
["delete", {
params [["_key", "", [""]]];
if (_key == "") exitWith { ERROR_MSG("Key cannot be empty"); false };
private _store = GETMVAR(FORGE_STORE_REG,nil);
private _key = _store call ["get", ["organizationNameIndex", _key, nil]];
_store call ["delete", ["organizationNameIndex", _key]];
if (isNil "_key") exitWith { ERROR_MSG_1("Key for organization not found", _key); false };
_store call ["delete", ["organizations", _key]];
private _orgRegistry = GETVAR(profileNamespace,FORGE_ORG_REG,createHashMap);
_orgRegistry deleteAt _key;
SETVAR(profileNamespace,FORGE_ORG_REG,_orgRegistry);
saveProfileNamespace;
true
}]
]];
SETMVAR(FORGE_ORG_STORE_REG,_orgStoreInterface);
GETMVAR(FORGE_ORG_STORE_REG,nil)

View File

@ -0,0 +1,76 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_invite
* Author: J. Schmidt
*
* Description:
* Sends an invitation to a player to join an organization
*
* Arguments:
* 0: _uid - Player UID <STRING>
* 1: _name - Organization name <STRING>
* 2: _targetUID - Target player's UID <STRING>
* 3: _targetName - Target player's name <STRING>
*
* Return Value:
* Success <BOOL>
*/
params [["_uid", "", [""]], ["_name", "", [""]], ["_targetUID", "", [""]], ["_targetName", "", [""]]];
if (_uid == "" || _name == "" || _targetUID == "" || _targetName == "") exitWith { TRACE_3("Invalid parameters for organization invitation",_uid,_name,_targetUID); false };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _uid, _name];
private _org = _store call ["getByKey", [_key]];
private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }};
private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6];
if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); false };
private _invites = _org get "invites";
private _logs = _org get "logs";
private _invite = createHashMapFromArray [
["uid", _targetUID],
["name", _targetName],
["timestamp", _dateTime],
["status", "pending"]
];
_invites set [_targetUID, _invite];
_org set ["invites", _invites];
_logs pushBack [_dateTime, "INVITE", _targetName, _targetUID];
_org set ["logs", _logs];
_store call ["post", [_uid, _name]];
[_targetUID, _uid, _name, _dateTime] spawn {
params ["_targetUID", "_ownerUID", "_orgName", "_timestamp"];
if (isRemoteExecuted && remoteExecutedOwner != 2) exitWith {};
private _target = [_targetUID] call BIS_fnc_getUnitByUID;
if !(isNull _target) then {
private _orgInvites = GETVAR(profileNamespace,FORGE_ORG_INVITES,createHashMap);
private _inviteKey = format ["%1_%2", _ownerUID, _orgName];
_orgInvites set [_inviteKey, createHashMapFromArray [
["orgName", _orgName],
["ownerUID", _ownerUID],
["timestamp", _timestamp],
["status", "pending"]
]];
SETVAR(profileNamespace,FORGE_ORG_INVITES,_orgInvites);
saveProfileNamespace;
[format ["You have been invited to join %1", _orgName]] remoteExec ["hint", _target];
};
};
true

View File

@ -0,0 +1,86 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_join
* Author: J. Schmidt
*
* Description:
* Adds a player to an organization, either as a new member or the owner
*
* Arguments:
* 0: _uid - Player UID <STRING>
* 1: _name - Organization name <STRING>
* 2: _targetUID - Target player's UID <STRING>
* 3: _targetName - Target player's name <STRING>
* 4: _targetRank - Player's rank in organization (default: "member") <STRING>
*
* Return Value:
* Success <BOOL>
*/
params [["_uid", "", [""]], ["_name", "", [""]], ["_targetUID", "", [""]], ["_targetName", "", [""]], ["_targetRank", "member", [""]]];
if (_uid == "" || _name == "" || _targetUID == "" || _targetName == "") exitWith { TRACE_3("Invalid parameters for joining organization",_name,_targetUID,_targetName); false };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _uid, _name];
private _org = _store call ["getByKey", [_key]];
private _playerAlreadyInOrg = false;
private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }};
private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6];
if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); false };
private _invites = _org get "invites";
private _logs = _org get "logs";
private _members = _org get "members";
{
private _checkOrg = _x;
private _checkMembers = _checkOrg get "members";
if (!isNil { _checkMembers get _targetUID }) exitWith {
_playerAlreadyInOrg = true;
};
} forEach (_store call ["get", []]);
if (_playerAlreadyInOrg) exitWith { TRACE_2("Player already in an organization",_targetUID,_targetName); false };
private _member = createHashMapFromArray [
["uid", _targetUID],
["name", _targetName],
["rank", _targetRank],
["joinDate", _dateTime]
];
if (_targetRank == "owner") then {
_members set [_targetUID, _member];
_org set ["members", _members];
_store call ["post", [_uid, _name]];
true
} else {
if !(isNil { _invites get _targetUID }) then {
_invites deleteAt _targetUID;
_members set [_targetUID, _member];
_org set ["members", _members];
_org set ["invites", _invites];
_logs pushBack [_dateTime, "JOIN", _targetName, _targetUID];
_org set ["logs", _logs];
private _inviteKey = format ["%1_%2", _uid, _name];
private _orgInvites = GETVAR(profileNamespace,FORGE_ORG_INVITES,createHashMap);
_orgInvites deleteAt _inviteKey;
SETVAR(profileNamespace,FORGE_ORG_INVITES,_orgInvites);
saveProfileNamespace;
_store call ["post", [_uid, _name]];
true
} else {
TRACE_2("Player not invited to this organization",_targetUID,_name);
false
};
};

View File

@ -0,0 +1,50 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_leave
* Author: J. Schmidt
*
* Description:
* Removes a player from an organization
*
* Arguments:
* 0: _ownerUID - Organization owner's UID <STRING>
* 1: _orgName - Organization name <STRING>
* 2: _playerUID - Player's UID who is leaving <STRING>
* 3: _playerName - Player's name who is leaving <STRING>
*
* Return Value:
* Success <BOOL>
*/
params [["_ownerUID", "", [""]], ["_orgName", "", [""]], ["_playerUID", "", [""]], ["_playerName", "", [""]]];
if (_ownerUID == "" || _orgName == "" || _playerUID == "" || _playerName == "") exitWith { TRACE_4("Invalid parameters for leaving organization",_ownerUID,_orgName,_playerUID,_playerName); false };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _ownerUID, _orgName];
private _org = _store call ["getByKey", [_key]];
private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }};
private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6];
if (isNil "_org") exitWith { TRACE_1("Organization not found", _key); false };
private _members = _org get "members";
private _logs = _org get "logs";
if (isNil { _members get _playerUID }) exitWith { TRACE_2("Player not in this organization",_playerUID,_orgName); false };
private _memberData = _members get _playerUID;
if (_memberData get "rank" == "owner") exitWith { TRACE_2("Owner cannot leave organization, must transfer ownership first",_playerUID,_orgName); false };
_logs pushBack [_dateTime, "LEAVE", _playerName, _playerUID];
_org set ["logs", _logs];
_members deleteAt _playerUID;
_org set ["members", _members];
_store call ["post", [_ownerUID, _orgName]];
true

View File

@ -0,0 +1,36 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_listPlayerInvites
* Author: J. Schmidt
*
* Description:
* Lists all organization invites for the current player
*
* Arguments:
* 0: _playerUID - Player UID <STRING>
*
* Return Value:
* Array of organization invites <ARRAY>
*/
params [["_playerUID", "", [""]]];
if (_playerUID == "") exitWith { TRACE_1("Invalid player UID",_playerUID); [] };
private _playerInvites = GETVAR(profileNamespace,FORGE_ORG_INVITES,createHashMap);
private _invitesList = [];
{
private _inviteKey = _x;
private _invite = _playerInvites get _inviteKey;
_invitesList pushBack [
_inviteKey,
_invite get "orgName",
_invite get "ownerUID",
_invite get "timestamp"
];
} forEach (keys _playerInvites);
_invitesList

View File

@ -0,0 +1,52 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_removeAsset
* Author: J. Schmidt
*
* Description:
* Removes an asset from an organization's inventory
*
* Arguments:
* 0: _uid - Player UID <STRING>
* 1: _name - Organization name <STRING>
* 2: _assetType - Type of asset (vehicle, building, etc.) <STRING>
* 3: _assetId - Unique identifier of the asset <STRING>
*
* Return Value:
* Updated assets collection <HASHMAP>
*/
params [["_uid", "", [""]], ["_name", "", [""]], ["_assetType", "", [""]], ["_assetId", "", [""]]];
if (_uid isEqualTo "" || _name isEqualTo "" || _assetType isEqualTo "" || _assetId isEqualTo "") exitWith { TRACE_4("Invalid parameters for removing asset",_uid,_name,_assetType,_assetId); createHashMap };
private _store = call FUNC(verifyOrgStore);
private _key = format ["%1_%2", _uid, _name];
private _org = _store call ["getByKey", [_key]];
private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }};
private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6];
if (isNil "_org") exitWith { TRACE_1("Organization not found",_name); createHashMap };
private _assets = _org get "assets";
private _logs = _org get "logs";
private _typeAssets = _assets getOrDefault [_assetType, []];
private _index = _typeAssets findIf { (_x getOrDefault ["id", ""]) == _assetId };
if (_index != -1) then {
private _assetToRemove = _typeAssets select _index;
private _assetName = _assetToRemove getOrDefault ["name", "Unknown Asset"];
_typeAssets deleteAt _index;
_logs pushBack [_dateTime, "ASSET_REMOVED", _assetType, _assetName];
_org set ["logs", _logs];
};
_org set ["assets", _assets];
_store call ["post", [_uid, _name]];
_assets

View File

@ -0,0 +1,22 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_verifyOrgStore
* Author: J. Schmidt
*
* Description:
* Ensures the store is initialized and returns the store object
*
* Arguments:
* None
*
* Return Value:
* Store object <OBJECT>
*/
private _store = GETMVAR(FORGE_ORG_STORE_REG,nil);
if (isNil "_store") then {
_store = [] call FUNC(initOrgStore);
};
_store

View File

@ -0,0 +1,16 @@
#define COMPONENT org
#define COMPONENT_BEAUTIFIED Org
#include "\z\forge_client\addons\main\script_mod.hpp"
// #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE
#ifdef DEBUG_ENABLED_ORG
#define DEBUG_MODE_FULL
#endif
#ifdef DEBUG_SETTINGS_ORG
#define DEBUG_SETTINGS DEBUG_SETTINGS_ORG
#endif
#include "\z\forge_client\addons\main\script_macros.hpp"

View File

@ -30,6 +30,6 @@ switch (_configType) do {
// player setVariable ["FORGE_Locker", _locker, true];
SETPVAR(player,FORGE_Locker,_locker);
[_className, _itemType] call EFUNC(armory,addArmoryItem);
[_className, _itemType] call EFUNC(arsenal,addArmoryItem);
[format ["You have purchased %1 for $%2.", _displayName, _price], "info", 3, "right"] call EFUNC(misc,notify);