Visa ämne
Anrop » ArmA 3 » Editing
 Skriv ut ämne
Multiplayer scripting - Tutorial 1
Hej hej alle zusammen.

jag har pratat mycket om det här förr men jag tycker det kan vara dags för en ny guide med ett litet konkret scenario som gör det lättare för just dig att förstå konceptet kring lokalitet och så.
I den här guiden så kommer jag främst att beröra saker som körs lokalt hos en spelare som en action meny eller vissa triggers och hur man kan lösa så att något sker för alla spelare när en spelare t.ex. trycker på actionmenyn, dvs en lokal handling triggar en global handling.

Ponera följande scenario, Vi har en trigger med 50 meter radius och i Condition fältet så skriver vi följande:
Kod Källa  

player in thisList


Normalt sett så är Condition satt till "this" vilket innebär att den använder värdena man sätter i triggerns dialogruta som condition för om den skall aktivera men om du byter ut this mot något annat så kan du sätta precis vad du vill oberoende av vad som står i trigger rutan, vill du kombinera så kan man göra "player in thisList && this"

Vad koden ovan gör är att kolla om spelaren befinner sig i thisList vilket är en specialvariabel som Arma fyller i med alla objekt som befinner sig inom triggers radie, Alltså så kollar vi helt enkelt om spelaren befinner sig innuti triggern. Easy right?

På onAct så kan vi sätta något roligt som t.ex. hint "Du har gått in i ett minfält" och om du startar uppdraget och går in i triggern så kommer ett litet fint meddelande att dyka upp på din skärm! Än så länge så är det inga konstigheter.

Nu börjar det roliga, Fundera en stund på vad player innebär. Läs bikin på player så märker du att det står: Person controlled by player. In MP this value is different on each computer and on dedicated server this value is null.

Alltså är det en ytterligare specialvariabel som Arma använder och den är annorlunda för varje spelare som kör uppdraget och refererar alltid till den lokala spelarens enhet. Vad har detta för betydelse i våran trigger som vi har satt upp om vi kör ett multiplayer uppdrag?

i.imgur.com/qr5kzrE.png
På bilden så ser vi våran trigger och två spelare varav den gröna är du och den blåa är någon annan på servern.
Nu är ingen av er inom triggerns radie och således händer inget alls.

Men..
i.imgur.com/xEs65rj.png
Du har gått in i triggern, Triggerns Condition fält kommer att urvärderas Av er båda två (och alla andra på servern) men eftersom vi använder en specialvariable player som är unik för varje dator så kommer vi att få olika resultat.
För dig så kommer den att evaluera till true eftersom Ja, du (din enhet) befinner sig faktiskt inom triggerns radie.
För din medspelare som står utanför så kommer den att evaluera till false därför att nej, Från hans perspektiv så är player (hans enhet) inte inom triggerns radie.

Detta innebär att triggerns OnAct kommando endast kommer att köras för dig och nu har vi alltså skapat en situation där någon form av logik kommer att köras lokalt på din dator och inte för någon annan, Det här är helt okej och normalt. Du kommer nu att se en varning att du har gått in i ett minfält och det kommer ingen annan på servern att göra! Annars hade det blivit lite konstigt om någon annan på servern sitter i en hkp och ser att han är på väg in i ett minfält..

Nu vill vi att det finns en viss chans att spelaren faktiskt dör av en mina.
I OnAct fältet så skriver vi nu istället:
Kod Källa  

Nul = execVM "minefield.sqf"; 


Vad den här gör är att den läser in filen minefield.sqf och kör den filen.
Nu ska vi skapa minefield.sqf! Gör det i din uppdragskatalog och skriv följande:

Kod Källa  


/*
   Minefield.sqf
   Varna för minfält
   20% chans att det exploderar
*/

hint "Du är på väg in i ett minfält!"

_rand = floor(random 100);
if (_rand < 20) then {
   _bomb = "R_60mm_HE" createVehicle getPos player;
};


Två viktiga saker måste observeras i den här koden!
Kom ihåg att eftersom triggerns design gör att den bara körs för spelaren som går in i triggern så vet vi att minefield.sqf endast kommer att köras för varje spelare som faktiskt befinner sig inne i triggern, Första raden så ser vi hinten som vi tidigare hade i OnAct och om vi kollar bikin för hint så ser du en ikon som ser ut så här: community.bistudio.com/wikidata/images/5/52/effects_local.gif och om du trycker på den så står det vad den betyder:
Effects of these scripting commands are not broadcasted over the network and remain local to the client the command is executed on.

Eftersom vi vet att minefield.sqf endast körs för de som befinner sig i minfältet så betyder det ovanstående att hint meddelandet därför endast kommer att visas för de spelarna inom triggern! Inga konstigheter.
Men om du kollar bikin för createVehicle så är det en annorlunda ikon med ett rött G community.bistudio.com/wikidata/images/f/f7/effects_global.gif och den betyder:
Effects of these scripting commands are broadcasted over the network and happen on every computer in the network.

Vad betydet det här i vårat kontext?
Om vi utgår från att det endast finns en spelare i triggern så kommer minefield.sqf endast att köras en gång och det är på hans dator och ingen annan, Han kommer att se hinten men när han väl kör createVehicle så kommer resultatet av det att ske för alla dvs ett "fordon" som i det här fallet är en 60mm granat kommer att spawna i arma världen och den kommer att hamna på getPos player vilket kommer vara positionen för spelaren inne i triggern då det är han som kör skriptet.

Alltså kommer alla på hela servern att se/höra explosionen av 60mm granaten som spelaren inne i triggern skapar!
Hade man löst det här på ett annat sätt där man t.ex. namnger en enhet "plutChef" och sedan sätter condition "plutChef in thisList" i triggern så hade vi haft ett helt annat scenario om vi har samma minefield.sqf skript.

Varför? Jo därför att som jag skrev tidigare så evalueras condition fältet hos triggern för alla spelare när någon går in i triggern och eftersom plutChef i så fall är en variabel som är samma för alla spelare eftersom den refererar till samma enhet hos alla så kommer condition att evalueras till true och därmed körs triggern onAct för alla vilket hade resulterat i att alla på servern hade utfört minefield.sqf vilket potentiellt kan orsaka att 30 explosioner skapas på en 30 manna server.

Därför är det viktigt att förstå när kod körs och av vem, Vi har lite roliga exempel på exakt detta problem på anrop (regnande ubåtar från himlen, bomb som exploderar 30 gånger trots att den defusats mfl.)

----

Om vi lämnar triggern nu och vill göra ett nytt scenario där vi har en bomblåda och vi vill ha en action för att kunna defusa den, Det går att lösa på två sätt.
Antingen så skapar vi en trigger runt lådan och sätter att en action ska skapas när spelaren går in i triggern på OnAct och likaså att på OnDeact så tas actionet bort och det skulle fungera super fint men då måste vi skriva två kommandon vilket är lite redundant

Eller så kikar vi lite noggrannare på bikin för addAction och ser att det finns ett fält för condition, Intressant! Vi kan alltså sätta addAction kommandot på lådans init fält direkt och skriva i Condition fältet för addAction att player måste befinna sig inom 5 meter av lådan och i så fall skulle actionet bara visas om spelaren faktiskt befinner sig nära lådan och automatiskt försvinna om spelaren är out of range. Precis vad vi vill ha!

Så på lådans init skriver vi:
Kod Källa  


this addAction ["Defuse", "defuse.sqf", [], 10, true, true, "", "player distance _target < 5"];


Om du kollar på bikin för addAction så ser du vilka argument vi skickar med i addAction och i vilken ordning. Man kan inte blanda ordningen utan det måste ske i den som står på bikin.
Det viktiga är är att vårat sista argument vi skickar med är condition vilket kollar om spelaren är inom 5 meter av lådan. (obs att _target är en specialvariabel som refererar till objektet som actionet sätts på, i vårat fall är det lådan.)
Alla andra argument efter condition kan vi skippa eftersom bikin listar dem som optional och de har default värden som används men vi är tvugna att specifiera allt fram tills condition.

Nu måste vi skapa en defuse.sqf eftersom något bör rimligtvis hända när spelaren trycker på actionet!
Kod Källa  


/*
   Defuse.sqf
   Notifiera alla spelare på servern att bomben har defusats
*/

xea_eh_bombDefused = true;
publicVariable "xea_eh_bombDefused";
[] execVM "bombDefused.sqf"


Ojsan, Nu har jag introducerat ännu ett nytt kommando!
Kika på bikin för publicVariable så ser du nog snabbt vad den är till för,
Med hjälp av publicVariable (som härefter kommer att kallas för PV) så kan vi alltså synkronisera en variabel med alla på servern.

Vad det innebär är att om jag har en variabel som heter xea_eh_bombDefused och den är satt till false hos alla och när jag då sätter den till true i defuse.sqf så kommer ju den variabeln endast att vara true för spelaren som faktiskt tryckte på Defuse actionet! Med hjälp av publicVariable så kommer xea_eh_bombDefused att bli true för alla alltså synkroniserar vi alla klienternas variabel med våran. Du ser att publicVariable har en effect global ikon uppe till vänster! :).

Just nu så skulle den har koden vara helt verkanslös trots att xea_eh_bombDefused faktiskt uppdateras för alla på servern för det är bara en variabel som inte gör något så vi vill att något händer när den är true.
Återigen som det nästan alltid är så går det att lösa på flera sätt t.ex. så kan du ha en trigger med Condition satt till xea_eh_bombDefused == true och då hade den triggern körts igång så fort variabeln blir true.

Jag brukar föredra att använda en event handler för publicVariable vilket är en bit kod man kan sätta in som säger åt arma att automatiskt köra en fil eller funktion så fort en viss variabel har synkats med hjälp av PV.

Skapa nu en init.sqf i din uppdragskatalog och skriv följande:
Kod Källa  


if (isNil "xea_eh_bombDefused") then {
   xea_eh_bombDefused = false;
};

"xea_eh_bombDefused" addPublicVariableEventHandler { [] execVM "bombDefused.sqf" };


Init.sqf är en speciell fil som alltid körs av alla (inkl servern) som är på servern när uppdraget har laddats in, Den körs normalt när man befinner sig i kartskärmen innan man kommer in i 3D.
Vi gör 2 saker här: Först så kollar vi ifall xea_eh_bombDefused redan är definerad på något sätt så vi inte skriver över den av misstag och om den inte är det så skapar vi den och sätter den till false, På så vis så borde den alltså vara false på för alla per automatik om det inte är så att man JIPar och den redan är ändrad till true p.g.a att någon redan defusat bomben.

Det andra är att vi nu sätter en PV event handler på våran xea_eh_bombDefused variabel som gör att så fort någon har kört publicVariable "xea_eh_bombDefused"; så kommer [] execVM "bombDefused.sqf" att köras - vilket helt enkelt bara laddar in och kör bombDefused.sqf

Nu skapar vi bombDefused.sqf:
Kod Källa  


/*
   bombDefused.sqf
   bomben har defusats
   notifiera spelaren
*/

hint "Bomben har defusats! Nu kan vi gå hem";


Om vi tar ett steg tillbaka och tittar på helheten så bör du reflektera över vad som faktiskt har gjorts här.
Vi har alltså en lokal händelse där en action visas för en spelare och när han trycker på den så körs endast skriptet den startar för den spelaren och för att göra det till en global händelse så triggar vi en publicVariable event handler som i sin tur kör ett annat skript vilket kommer att köras av alla på servern.

Så om du tar Defuse actionet så kommer alla på servern att se "Bomben har defusats! Nu kan vi gå hem".
Man kan göra den här processen mycket enklare / mer läsbart med hjälp av CBA och det kan jag visa i en snabb follow up tutorial till den här när jag orkar och om det finns intresse.
The enemy cannot predict your actions if you have no idea what you're doing.
Bra, hoppas ni/vi som gör mp uppdrag tar oss tid läsa igenom. Även om jag gjort MP missions i tio år så är det nyttigt läsa hur andra löser det och hur de tänker.
Exakt, kanon info ! Så superbra att ha såna här guider liggande att kunna återkomma till, stor eloge Smile
Stay frosty !
Kul att ni tycker det är intressant.
Kom gärna med frågor, förslag, synpunkter, kritik eller motbevisa mig om jag har fel någonstans.

Det må vara ganska mycket wall of text då jag fick lov att förklara ganska utförligt men det är väldigt enkla koncept att förstå när man väl lärt sig det.
The enemy cannot predict your actions if you have no idea what you're doing.
Mycket bra text! Smile
Bra med bilder också.
YouTube:
https://www.youtube.com/user/MasterMindEcho/videos
Gå gärna igenom när olika enheter är lokala osv. Tex när är ett tomt fordon lokalt för spelaren gentemot servern gentemot HC. Eller ett AI kontrollerat fordon eller fordon som en annan spelare kontrollerar.

Citera

nibbles skrev:

Gå gärna igenom när olika enheter är lokala osv. Tex när är ett tomt fordon lokalt för spelaren gentemot servern gentemot HC. Eller ett AI kontrollerat fordon eller fordon som en annan spelare kontrollerar.


jag har inte full koll på det själv så det måste testas isf och jag har tyvärr inte tid för att sitta och gamea hemma Sad
AI soldater är alltid lokala till den som leder gruppen iaf, Gör ingen det så är det servern som tar över om man inte skapar gruppen via skript hos en maskin typ hos en HC.

För någon som har tid och vill bidra,
Skapa ett fordon med createVehicle hos en klient, kolla om den är local förslagsvis med:
nyaFordonet = "något klassnamn" createVehicle getPos player;
player sideChat format["%1", local nyaFordonet];

Hoppa sedan in i fordnet och exekvera samma sideChat och kolla, hoppa ut, kolla om lokaliteten nu har ändrats.
Om den har gjort det så hoppa in och kör den igen för att kolla om lokaliteten ändrar till servern när den blivit övergiven och om den isf går över tillbaka till commandern när den är bemannad.
The enemy cannot predict your actions if you have no idea what you're doing.
Hur man försäkrar sig om att ens uppdrag är JIP-säkert (Join In Progress) skulle vara intressant Smile
YouTube:
https://www.youtube.com/user/MasterMindEcho/videos
Följ https://community.bistudio.com/wiki/E...nt_Scripts och https://community.bistudio.com/wiki/I...tion_Order eller https://community.bistudio.com/wiki/F...tion_Order korrekt med lite publicVariable
Moget ZiP.........

Här får du en fråga så ger du den tråkiga forumslänkalänken svaret.

Buuuuu

Sad
Stay frosty !
Får väl skriva ihop något fint i nästa vecka Facepalm
Jätte bra Xealot mer sånt här åt folket!
Jag ser gärna en uppföljning hur man gör i CBA
Playing Diablo 3 is for losers! Boting Diablo 3 is for winners!