Script Name: EfficientPlayersLoop
Script Description: Dynamic array storing active players for maximum loop efficiency.
Original Author(s): Savage
Compilation: PassedCore Version: 2.8.0 (SC3)
For 2 years I made tons of scripts and I was using 1 to 32 loop to check if player is active(in game). That's not really efficient especially if you are using loop inside AppOnIdle in addition with AppOnIdleTimer set to 1 then the loop is executed 1920 times per second!
So there was few solutions:
* Use MaxPlayers property - If server slots are set to 32 we won't achieve anything. If it's set to 16 and there will be player with id 16 and we will change Max_Players amount to 10 (using command /maxplayers or Game.MaxPlayers from SC3) then the loop will be from 1 to 10 and we will miss player with id 16
* Better from above is HighID by ExHunter:
http://forums.soldat.pl/index.php?topic=40264.msg494124#msg494124But if there are 5 players, 4 of them will leave and last guy has id 5 then the loop still is executed 4 useless times. I've noticed few bugs in this topic but the idea isn't bad.
That's all what I knew until i had to write WeaponLimiter(mainly for miniguns) for overloaded VPS.
With that code(written in SC3) the loop is gonna execute that much times how many players are in game:
var
psids: array of Byte;
ppos: array[1..32] of Byte;
procedure OnJoin(Player: TActivePlayer; Team: TTeam);
begin
SetLength(psids,high(psids)+2);
psids[high(psids)] := Player.ID;
ppos[Player.ID] := high(psids);
end;
procedure OnLeave(Player: TActivePlayer; Kicked: Boolean);
begin
if psids[high(psids)]=Player.ID then
SetLength(psids,high(psids))
else begin
psids[ppos[Player.ID]] := psids[high(psids)];
ppos[psids[high(psids)]] := ppos[Player.ID];
SetLength(psids,high(psids));
end;
end;
procedure Init;
var
i: Byte;
begin
Game.OnJoin := @OnJoin;
Game.OnLeave := @OnLeave;
for i := 1 to 32 do
if Players[i].Active then begin
SetLength(psids,high(psids)+2);
psids[high(psids)] := i;
ppos[i] := high(psids);
end;
end;
begin
Init;
end.
How it works:
* OnJoin: Players IDs are stored in dynamic array - psids. If the Player joins then psids length is expanded and Player's ID is added to new highest psids's index then Player's position inside psids is saved to ppos array.
* OnLeave: If highest psids index stores Player's ID then psids length is simply shortened by 1 otherwise highest psids's index's Player's ID goes to Player's position who left. Next highest psids's index's Player's ID's ppos takes Player's ppos who left and array is shortened by 1.
* Loop between begin end. : psids array is filled with active players after recompile (works the same as code in OnJoin).
Usage:
* psids index is zero based, example:
for i := 0 to high(psids) do
Players[psids[i]].WriteConsole('Hello world!',$FFFFFF);
* If there are no players on the server then psids highest index is -1. Remember to check it in events in which no players can occur (OnLeave, AppOnIdle, OnMapChange, TCP events, OnRequest), example:
if high(psids)<>-1 then
for i := 0 to high(psids) do
Players[psids[i]].WriteConsole('Hello world!',$FFFFFF);
Here's my script that's using it:
http://forums.soldat.pl/index.php?topic=44076.0