Skriptování v ArmA 2 – 3. část – Multiplayer

Úvod

Samotné skriptování pro multiplayer se nijak neliší od skriptování pro singleplayer, jen je třeba dát si pozor na to, kdo bude skripty vykonávat. U multiplayeru je vždy jeden server a klienti. Je dobré si předem rozmyslet, jak skripty napsat, aby při hře přes síť nevznikaly problémy.

Musíme se dívat na věci z obou stran. Jak se strany serveru, tak ze strany klientů. Zde se již asi moc nevyplatí používat proměnnou player. Dále budeme muset rozpoznávat, zda je nějaká role skutečně obsazena hráčem, pokud nechceme mít v týmu AI.

Server a klient

Na následujícím příkladu si můžeme ukázat hned několik věcí. Pokud budeme mít například misi, kde se nám bude odpočítávat čas, bude také zapotřebí, aby všichni hráči viděly ten stejný. Pokud si bude každý klient odpočítávat sám, tak se brzy bude každému ukazovat něco jiného. Nejvhodnější je, když se bude odpočítávat všem, a server bude čas klientům synchronizovat. Nejdříve ale musíme od sebe oddělit klienty a server:

if (isServer) then {[] exec "timerserver.sqs"} else {[] exec "timer.sqs"}

Nyní můžeme porovnat oba kódy:

timer.sqs

; CLIENT
timeSec = 0
timeMin = 0
timeHour = 0
strSec = ""
strMin = ""
strHour = ""

if (isMultiplayer) then {timeSec = param1} else {timeSec = 18000}

#clock
if (timeSec >= 60) then {timeMin = timeMin + 1; timeSec = timeSec - 60}
if (timeMin >= 60) then {timeHour = timeHour + 1; timeMin = timeMin - 60}
if (timeSec >= 60) then {goto "clock"}

#loop
timeSec = timeSec - 1

if (timeSec <= -1) then {timeSec = 59; timeMin = timeMin - 1}
if (timeMin <= -1) then {timeMin = 59; timeHour = timeHour - 1}

if (timeSec < 10) then {strSec = format["0%1", timeSec]} else {strSec = format["%1",timeSec]}
if (timeMin < 10) then {strMin = format["0%1", timeMin]} else {strMin = format["%1",timeMin]}
if (timeHour < 10) then {strHour = format["0%1", timeHour]} else {strHour = format["%1",timeHour]}

hintSilent format["Time left: %1:%2:%3",strHour,strMin,strSec]

~1
goto "loop"

timerserver.sqs

; SERVER
timeSec = 0
timeMin = 0
timeHour = 0
strSec = ""
strMin = ""
strHour = ""

if (isMultiplayer) then {timeSec = param1} else {timeSec = 18000}

#clock
if (timeSec >= 60) then {timeMin = timeMin + 1; timeSec = timeSec - 60}
if (timeMin >= 60) then {timeHour = timeHour + 1; timeMin = timeMin - 60}
if (timeSec >= 60) then {goto "clock"}

#loop
timeSec = timeSec - 1
if ((timeSec <= -1) and (timeMin == 0) and (timeHour == 0)) then {endMission "END2"; exit}

if (timeSec <= -1) then {timeSec = 59; timeMin = timeMin - 1; publicVariable "timeSec"; publicVariable "timeMin";
publicVariable "timeHour"}
if (timeMin <= -1) then {timeMin = 59; timeHour = timeHour - 1}

if (timeSec < 10) then {strSec = format["0%1",timeSec]} else {strSec = format["%1", timeSec]}
if (timeMin < 10) then {strMin = format["0%1",timeMin]} else {strMin = format["%1", timeMin]}
if (timeHour < 10) then {strHour = format["0%1",timeHour]} else {strHour = format["%1", timeHour]}

hintSilent format["Time left: %1:%2:%3",strHour,strMin,strSec]

~1
goto "loop"

Kódy jsou téměř stejné, jenomže server necháváme misi po uplynutí času ukončit a synchonizovat čas. Misi je dobré neukončovat u klientů, protože by se mohlo stát, že někteří hrají a některým se mise ukončila. A nyní jak se synchnizujé proměnné. Kód serveru obsahuje:

... publicVariable "timeSec"; publicVariable "timeMin"; publicVariable "timeHour" ...

Takto pošleme proměnnou do včech počítačů. Je však důležité, abychom nepoužívali publicVariable moc frekventovaně, protože to nemá síťové spojení rádo.

Servery bychom ale měli ještě rozdělit dva druhy. Jeden z nich je dedicated server. To je počítač, u kterého nemusí sedět žádný hráč. Naproti tomu můžeme být server i hráč, když hru zapne a hostuje přímo z ní. Příkaz isServer by nám vyhodil true v obou případech, takže se ještě můžeme zeptat příkazem isDedicated, abychom odhalili dedicated server.

Fajnšmekři mohou nyní namítat, že na kódu pro server volám příkaz hintSilent, který se vlastně nemá komu ukázat. To mi zde však nevadí, protože si to volá každý klient a server čas jen synchronizuje a ukončuje hru.

Dále se nám může hodit příkaz isPlayer, který vrátí true, pokud roli řídí hráč:

if !(isPlayer hrac1) then {hrac1 setPos(getMarkerPos "out")}

Takto můžeme například odsunout nepotřebné vojáky pryč na okraj mapy, nebo se jich zbavit v moři. To se však hodí jen pokud nejsou součástí týmu. Pokud je jednotka nastavena jako Hratelná a hostitel zakáže AI, pak se jednotka ve hře nezobrazí.

Multiplayer mise

Mise pro multiplayer nemusí mít soubor overview.html. Dále je třeba dávat pozor na používání objektů, které nebyly součástí původní hry. Tyto doplňky pak musí mít všichni, kteří si misi chtějí zahrát. Je zbytečné využívat v jedné misi mraky doplňků, protože najdete málokoho, kdo by je měl také.

Dále můžeme zakázat rádiové zprávy:

enableRadio = false

Při tvorbě multiplayer misí je třeba mít navědomí to, že pokud budeme skriptovat cokoli, je třeba zařídit, aby to mělo globální efekt. Každý klient může mít jinou hodnotu proměnných. Pokud budeme používat spínače na volání skriptů, budou se provádět u toho, kdo je spustil a jejich důsledky se nemusí projevit ostatním hráčům.