kleinToHCs.sqf 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * kleinToHCs.sqf
  3. *
  4. * In the mission editor, name the Headless Clients "HC1", "HC2", "HC3" without the quotes
  5. *
  6. * In the mission init.sqf, call kleinToHCs.sqf with:
  7. * execVM "kleinToHCs.sqf";
  8. *
  9. * It seems that the dedicated server and headless client processes never use more than 20-22% CPU each.
  10. * With a dedicated server and 3 headless clients, that's about 88% CPU with 10-12% left over. Far more efficient use of your processing power.
  11. *
  12. */
  13. if (!isServer) exitWith {};
  14. diag_log "kleinToHCs: Started";
  15. waitUntil {!isNil "HC1_1"};
  16. waitUntil {!isNull HC1_1};
  17. _HC_ID = -1; // Will become the Client ID of HC
  18. _HC2_ID = -1; // Will become the Client ID of HC2
  19. _HC3_ID = -1; // Will become the Client ID of HC3
  20. rebalanceTimer = 60; // Rebalance sleep timer in seconds
  21. cleanUpThreshold = 50; // Threshold of number of dead bodies + destroyed vehicles before forcing a clean up
  22. diag_log format["kleinToHCs: First pass will begin in %1 seconds", rebalanceTimer];
  23. [] spawn {
  24. while {true} do {
  25. // Rebalance every rebalanceTimer seconds to avoid hammering the server
  26. sleep rebalanceTimer;
  27. // Do not enable load balancing unless more than one HC is present
  28. // Leave this variable false, we'll enable it automatically under the right conditions
  29. _loadBalance = false;
  30. // Get HC Client ID else set variables to null
  31. try {
  32. _HC_ID = owner HC1_1;
  33. if (_HC_ID > 2) then {
  34. diag_log format ["kleinToHCs: Found HC with Client ID %1", _HC_ID];
  35. } else {
  36. diag_log "kleinToHCs: [WARN] HC disconnected";
  37. HC1_1 = objNull;
  38. _HC_ID = -1;
  39. };
  40. } catch { diag_log format ["kleinToHCs: [ERROR] [HC1_1] %1", _exception]; HC1_1 = objNull; _HC_ID = -1; };
  41. // Get HC2 Client ID else set variables to null
  42. if (!isNil "HC2_1") then {
  43. try {
  44. _HC2_ID = owner HC2_1;
  45. if (_HC2_ID > 2) then {
  46. diag_log format ["kleinToHCs: Found HC2 with Client ID %1", _HC2_ID];
  47. } else {
  48. diag_log "kleinToHCs: [WARN] HC2 disconnected";
  49. HC2_1 = objNull;
  50. _HC2_ID = -1;
  51. };
  52. } catch { diag_log format ["kleinToHCs: [ERROR] [HC2_1] %1", _exception]; HC2_1 = objNull; _HC2_ID = -1; };
  53. };
  54. // Get HC3 Client ID else set variables to null
  55. if (!isNil "HC3_1") then {
  56. try {
  57. _HC3_ID = owner HC3_1;
  58. if (_HC3_ID > 2) then {
  59. diag_log format ["kleinToHCs: Found HC2 with Client ID %1", _HC3_ID];
  60. } else {
  61. diag_log "kleinToHCs: [WARN] HC3 disconnected";
  62. HC3_1 = objNull;
  63. _HC3_ID = -1;
  64. };
  65. } catch { diag_log format ["kleinToHCs: [ERROR] [HC3_1] %1", _exception]; HC3_1 = objNull; _HC3_ID = -1; };
  66. };
  67. // If no HCs present, wait for HC to rejoin
  68. if ( (isNull HC1_1) && (isNull HC2_1) && (isNull HC3_1) ) then { waitUntil {!isNull HC1_1}; };
  69. // Check to auto enable Round-Robin load balancing strategy
  70. if ( (!isNull HC1_1 && !isNull HC2_1) || (!isNull HC1_1 && !isNull HC3_1) || (!isNull HC2_1 && !isNull HC3_1) ) then { _loadBalance = true; };
  71. if ( _loadBalance ) then {
  72. diag_log "kleinToHCs: Starting load-balanced transfer of AI groups to HCs";
  73. } else {
  74. // No load balancing
  75. diag_log "kleinToHCs: Starting transfer of AI groups to HC";
  76. };
  77. // Determine first HC to start with
  78. _currentHC = 0;
  79. if (!isNull HC1_1) then { _currentHC = 1; } else {
  80. if (!isNull HC2_1) then { _currentHC = 2; } else { _currentHC = 3; };
  81. };
  82. // Pass the AI
  83. _numTransfered = 0;
  84. {
  85. _swap = true;
  86. // If a player is in this group, don't swap to an HC
  87. { if (isPlayer _x) then { _swap = false; }; } forEach (units _x);
  88. // If load balance enabled, round robin between the HCs - else pass all to HC
  89. if ( _swap ) then {
  90. _rc = false;
  91. if ( _loadBalance ) then {
  92. switch (_currentHC) do {
  93. case 1: { _rc = _x setGroupOwner _HC_ID; if (!isNull HC2_1) then { _currentHC = 2; } else { _currentHC = 3; }; };
  94. case 2: { _rc = _x setGroupOwner _HC2_ID; if (!isNull HC3_1) then { _currentHC = 3; } else { _currentHC = 1; }; };
  95. case 3: { _rc = _x setGroupOwner _HC3_ID; if (!isNull HC1_1) then { _currentHC = 1; } else { _currentHC = 2; }; };
  96. default { diag_log format["kleinToHCs: [ERROR] No Valid HC to pass to. _currentHC = %1", _currentHC]; };
  97. };
  98. } else {
  99. switch (_currentHC) do {
  100. case 1: { _rc = _x setGroupOwner _HC_ID; };
  101. case 2: { _rc = _x setGroupOwner _HC2_ID; };
  102. case 3: { _rc = _x setGroupOwner _HC3_ID; };
  103. default { diag_log format["kleinToHCs: [ERROR] No Valid HC to pass to. _currentHC = %1", _currentHC]; };
  104. };
  105. };
  106. // If the transfer was successful, count it for accounting and diagnostic information
  107. if ( _rc ) then { _numTransfered = _numTransfered + 1; };
  108. };
  109. } forEach (allGroups);
  110. if (_numTransfered > 0) then {
  111. // More accounting and diagnostic information
  112. diag_log format ["kleinToHCs: Transfered %1 AI groups to HC(s)", _numTransfered];
  113. _numHC = 0;
  114. _numHC2 = 0;
  115. _numHC3 = 0;
  116. {
  117. switch (owner ((units _x) select 0)) do {
  118. case _HC_ID: { _numHC = _numHC + 1; };
  119. case _HC2_ID: { _numHC2 = _numHC2 + 1; };
  120. case _HC3_ID: { _numHC3 = _numHC3+ 1; };
  121. };
  122. } forEach (allGroups);
  123. if (_numHC > 0) then { diag_log format ["kleinToHCs: %1 AI groups currently on HC1_1", _numHC]; };
  124. if (_numHC2 > 0) then { diag_log format ["kleinToHCs: %1 AI groups currently on HC2_1", _numHC2]; };
  125. if (_numHC3 > 0) then { diag_log format ["kleinToHCs: %1 AI groups currently on HC3_1", _numHC3]; };
  126. diag_log format ["kleinToHCs: %1 AI groups total across all HC(s)", (_numHC + _numHC2 + _numHC3)];
  127. } else {
  128. diag_log "kleinToHCs: No rebalance or transfers required this round";
  129. };
  130. // Force clean up dead bodies and destroyed vehicles
  131. if (count allDead > cleanUpThreshold) then {
  132. _numDeleted = 0;
  133. {
  134. deleteVehicle _x;
  135. _numDeleted = _numDeleted + 1;
  136. } forEach allDead;
  137. diag_log format ["kleinToHCs: Cleaned up %1 dead bodies/destroyed vehicles", _numDeleted];
  138. };
  139. };
  140. };