Add Headless

This commit is contained in:
jonpas 2016-01-02 14:23:14 +01:00
parent 32b4416c29
commit a1866a561b
18 changed files with 493 additions and 0 deletions

View File

@ -0,0 +1 @@
z\ace\addons\headless

View File

@ -0,0 +1,20 @@
class ACE_Settings {
class GVAR(Enabled) {
value = 0;
typeName = "BOOL";
displayName = ECSTRING(common,Enabled);
description = CSTRING(EnabledDesc);
};
class GVAR(Delay) {
value = DELAY_DEFAULT;
typeName = "SCALAR";
displayName = CSTRING(Delay);
description = CSTRING(DelayDesc);
};
class GVAR(Log) {
value = 0;
typeName = "BOOL";
displayName = CSTRING(Log);
description = CSTRING(LogDesc);
};
};

View File

@ -0,0 +1,19 @@
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_postInit));
};
};
class Extended_InitPost_EventHandlers {
class AllVehicles {
class ADDON {
serverInit = QUOTE(_this call FUNC(handleInitPost));
};
};
};

View File

@ -0,0 +1,37 @@
class CfgVehicles {
class ACE_Module;
class GVAR(module): ACE_Module {
author = ECSTRING(common,ACETeam);
category = "ACE_missionModules";
displayName = CSTRING(Module);
function = QFUNC(moduleInit);
scope = 2;
isGlobal = 1; // Global
isTriggerActivated = 0;
isDisposable = 0;
icon = QUOTE(PATHTOF(UI\Icon_Module_Headless_ca.paa));
class Arguments {
class Enabled {
displayName = ECSTRING(common,Enabled);
description = CSTRING(EnabledDesc);
typeName = "BOOL";
defaultValue = 0;
};
class Delay {
displayName = CSTRING(Delay);
description = CSTRING(DelayDesc);
typeName = "NUMBER";
defaultValue = DELAY_DEFAULT;
};
class Log {
displayName = CSTRING(Log);
description = CSTRING(LogDesc);
typeName = "BOOL";
defaultValue = 0;
};
};
class ModuleDescription {
description = CSTRING(ModuleDesc);
};
};
};

16
addons/headless/README.md Normal file
View File

@ -0,0 +1,16 @@
ace_headless
============
Adds automatic passing of AI groups to (up to 3) Headless Clients.
- Automatic Headless Client recognition
- Event-based transferring (on unit spawn, Headless Client connect and disconnect)
- Round-robin transferring when more than 1 Headless Client is present
- Mission makers can use the following to prevent a group from transferring to a Headless Client:
`this setVariable ["ace_headless_blacklist", true, true];`
## Maintainers
The people responsible for merging changes to this component or answering potential questions.
- [Jonpas](http://github.com/jonpas)

Binary file not shown.

View File

@ -0,0 +1,16 @@
#include "script_component.hpp"
// Exit on player clients that are not hosts
if (hasInterface && !isServer) exitWith {};
["SettingsInitialized", {
// Exit if HC transferring disabled
if (!GVAR(Enabled)) exitWith {};
if (isServer) then {
addMissionEventHandler ["HandleDisconnect", {_this call FUNC(handleDisconnect)}];
} else {
// Register HC on server (this part happens on HC only)
["ACE_HeadlessClientJoined", [player]] call EFUNC(common,serverEvent);
};
}] call EFUNC(common,addEventHandler);

View File

@ -0,0 +1,18 @@
#include "script_component.hpp"
ADDON = false;
PREP(handleConnectHC);
PREP(handleDisconnect);
PREP(handleInitPost);
PREP(moduleInit);
PREP(rebalance);
PREP(transferGroups);
if (isServer) then {
GVAR(headlessClients) = [];
GVAR(inRebalance) = false;
["ACE_HeadlessClientJoined", FUNC(handleConnectHC)] call EFUNC(common,addEventHandler);
};
ADDON = true;

View File

@ -0,0 +1,17 @@
#include "script_component.hpp"
class CfgPatches {
class ADDON {
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_common"};
author[]= {"Jonpas"};
authorUrl = "https://github.com/jonpas";
VERSION_CONFIG;
};
};
#include "ACE_Settings.hpp"
#include "CfgEventHandlers.hpp"
#include "CfgVehicles.hpp"

View File

@ -0,0 +1,31 @@
/*
* Author: Jonpas
* Registers connected Headless Client for use.
*
* Arguments:
* 0: Headless Client <OBJECT>
*
* Return Value:
* None
*
* Example:
* [headlessClient] call ace_headless_handleConnectHC;
*
* Public: No
*/
#include "script_component.hpp"
params ["_headlessClient"];
// Exit if already registered
if (_headlessClient in GVAR(headlessClients)) exitWith {};
// Register for use
GVAR(headlessClients) pushBack _headlessClient;
if (GVAR(Log)) then {
ACE_LOGINFO_1("Registered HC: %1",_headlessClient);
};
// Rebalance
[true] call FUNC(rebalance);

View File

@ -0,0 +1,34 @@
/*
* Author: Jonpas
* Removes Headless Client from use.
*
* Arguments:
* 0: Object <OBJECT>
*
* Return Value:
* Transfer To Server <BOOL>
*
* Example:
* [unit] call ace_headless_handleDisconnect;
*
* Public: No
*/
#include "script_component.hpp"
params ["_object"];
// Exit if not HC
if !(_object in GVAR(headlessClients)) exitWith {};
// Remove HC
GVAR(headlessClients) deleteAt (GVAR(headlessClients) find _object);
if (GVAR(Log)) then {
ACE_LOGINFO_1("Removed HC: %1",_object);
};
// Rebalance
[true] call FUNC(rebalance);
// Prevent transferring of HC to server
false

View File

@ -0,0 +1,31 @@
/*
* Author: Jonpas
* Request a rebalance.
*
* Arguments:
* 0: Object <OBJECT>
*
* Return Value:
* None
*
* Example:
* [object] call ace_headless_handleInitPost;
*
* Public: No
*/
#include "script_component.hpp"
params ["_object"];
TRACE_1("InitPost",_object);
// Delay until settings are initialized (for checking if HC trasnferring is enabled)
if (!EGVAR(common,settingsInitFinished)) exitWith {
EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(handleInitPost), _this];
};
// Exit if HC transferring disabled or object not a unit (including unit inside vehicle) or is player
if (!GVAR(Enabled) || {!(_object in allUnits)} || {isPlayer _object}) exitWith {};
// Rebalance
[false] call FUNC(rebalance);

View File

@ -0,0 +1,27 @@
/*
* Author: Jonpas
* Initializes the Headless module.
*
* Arguments:
* 0: The module logic <LOGIC>
* 1: Units <ARRAY> (Unused)
* 2: Activated <BOOL>
*
* Return Value:
* None
*
* Public: No
*/
#include "script_component.hpp"
if (!isServer) exitWith {};
params ["_logic", "", "_activated"];
if (!_activated) exitWith {};
[_logic, QGVAR(Enabled), "Enabled"] call EFUNC(common,readSettingFromModule);
[_logic, QGVAR(Delay), "Delay"] call EFUNC(common,readSettingFromModule);
[_logic, QGVAR(Log), "Log"] call EFUNC(common,readSettingFromModule);
ACE_LOGINFO("Headless Module Initialized.");

View File

@ -0,0 +1,29 @@
/*
* Author: Jonpas
* Rebalance AI groups accross HCs.
*
* Arguments:
* 0: Force <BOOL>
*
* Return Value:
* None
*
* Example:
* [false] call ace_headless_rebalance;
*
* Public: No
*/
#include "script_component.hpp"
params ["_force"];
TRACE_3("Rebalance",GVAR(inRebalance),GVAR(headlessClients),_force);
// Exit if waiting for rebalance or no HCs present
if (GVAR(inRebalance) || {GVAR(headlessClients) isEqualTo []}) exitWith {};
// Transfer after rebalance delay
[FUNC(transferGroups), [_force], GVAR(Delay)] call EFUNC(common,waitAndExecute);
// Currently in rebalance flag
GVAR(inRebalance) = true;

View File

@ -0,0 +1,148 @@
/*
* Author: Jonpas
* Transfers AI groups to Headess Client(s).
*
* Arguments:
* 0: Force <BOOL>
*
* Return Value:
* None
*
* Example:
* [false] call ace_headless_fnc_transferGroups;
*
* Public: No
*/
#include "script_component.hpp"
params ["_force"];
GVAR(headlessClients) params [
["_HC1", objNull, [objNull] ],
["_HC2", objNull, [objNull] ],
["_HC3", objNull, [objNull] ]
];
if (GVAR(Log)) then {
ACE_LOGINFO_2("Present HCs: %1 - Full Rebalance: %2",GVAR(headlessClients),_force);
};
// Enable round-robin load balancing if more than one HC is present
private _loadBalance = [false, true] select (count GVAR(headlessClients) > 1);
// Get IDs and determine first HC to start with
private _idHC1 = -1;
private _idHC2 = -1;
private _idHC3 = -1;
private _currentHC = 0;
if (!local _HC1) then {
_idHC1 = owner _HC1;
_currentHC = 1;
};
if (!local _HC2) then {
_idHC2 = owner _HC2;
if (_currentHC == 0) then {
_currentHC = 2;
};
};
if (!local _HC3) then {
_idHC3 = owner _HC3;
if (_currentHC == 0) then {
_currentHC = 3;
};
};
// Prepare statistics
private _numTransferredHC1 = 0;
private _numTransferredHC2 = 0;
private _numTransferredHC3 = 0;
// Transfer AI groups
{
private _transfer = true;
// No transfer if empty group
if (_x isEqualTo []) then {
_transfer = false;
};
if (_transfer) then {
{
// No transfer if already transferred
if (!_force && {(owner _x) in [_idHC1, _idHC2, _idHC3]}) exitWith {
_transfer = false;
};
// No transfer if player in this group
if (isPlayer _x) exitWith {
_transfer = false;
};
// No transfer if any unit in group is blacklisted
if (_x getVariable [QGVAR(blacklist), false]) exitWith {
_transfer = false;
};
// No transfer if vehicle unit is in or crew in that vehicle is blacklisted
if (vehicle _x != _x && {(vehicle _x) getVariable [QGVAR(blacklist), false]}) exitWith {
_transfer = false;
};
} forEach (units _x);
};
// Round robin between HCs if load balance enabled, else pass all to one HC
if (_transfer) then {
switch (_currentHC) do {
case 1: {
private _transferred = _x setGroupOwner _idHC1;
if (_loadBalance) then {
_currentHC = [3, 2] select (!local _HC2);
};
if (_transferred) then {
_numTransferredHC1 = _numTransferredHC1 + 1;
};
};
case 2: {
private _transferred = _x setGroupOwner _idHC2;
if (_loadBalance) then {
_currentHC = [1, 3] select (!local _HC3);
};
if (_transferred) then {
_numTransferredHC2 = _numTransferredHC2 + 1;
};
};
case 3: {
private _transferred = _x setGroupOwner _idHC3;
if (_loadBalance) then {
_currentHC = [2, 1] select (!local _HC1);
};
if (_transferred) then {
_numTransferredHC3 = _numTransferredHC3 + 1;
};
};
default {
TRACE_1("No Valid HC to transfer to",_currentHC);
};
};
};
} forEach allGroups;
if (GVAR(Log)) then {
private _numTransferredTotal = _numTransferredHC1 + _numTransferredHC2 + _numTransferredHC3;
ACE_LOGINFO_4("Groups Transferred: Total: %1 - HC1: %2 - HC2: %3 - HC3: %4",_numTransferredTotal,_numTransferredHC1,_numTransferredHC2,_numTransferredHC3);
};
// Allow rebalance flag
GVAR(inRebalance) = false;

View File

@ -0,0 +1 @@
#include "\z\ace\addons\headless\script_component.hpp"

View File

@ -0,0 +1,15 @@
#define COMPONENT headless
#include "\z\ace\addons\main\script_mod.hpp"
#ifdef DEBUG_ENABLED_HEADLESS
#define DEBUG_MODE_FULL
#endif
#ifdef DEBUG_SETTINGS_HEADLESS
#define DEBUG_SETTINGS DEBUG_SETTINGS_HEADLESS
#endif
#include "\z\ace\addons\main\script_macros.hpp"
#define DELAY_DEFAULT 15

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="Headless">
<Key ID="STR_ACE_Headless_Module">
<English>Headless</English>
<German>Headless</German>
</Key>
<Key ID="STR_ACE_Headless_ModuleDesc">
<English>This module allows you to setup automatic transferring of AI to Headless Clients. (Default: No)</English>
<German>Dieses Modul erlaubt es dir, die KI automatisch auf einen Headless Client zu transferieren. (Standard: Nein) </German>
</Key>
<Key ID="STR_ACE_Headless_EnabledDesc">
<English>Enables transferring of AI to Headless Clients.</English>
<German>Aktiviert denTransfer der KI auf Headless Clients.</German>
</Key>
<Key ID="STR_ACE_Headless_Delay">
<English>Delay</English>
<German>Verzögerung</German>
</Key>
<Key ID="STR_ACE_Headless_DelayDesc">
<English>Minimal delay between transfers, in seconds. (Default: 15)</English>
<German>Minimale Verzögerung zwischen Transfers in Sekunden. (Standard: 15)</German>
</Key>
<Key ID="STR_ACE_Headless_Log">
<English>Log</English>
<German>Protokolldatei anlegen</German>
</Key>
<Key ID="STR_ACE_Headless_LogDesc">
<English>Log transfer statistics and Headless Client (dis)connections to RPT. (Default: No)</English>
<German>Zeichnet Transferstatistiken, Verbindungen und Verbindungsabbrüche in einer RPT-Datei auf. (Standard: Nein)</German>
</Key>
</Package>
</Project>