Nachhilfeantrag
#1
Archiv-Beitrag: Ursprünglich von MadJosch vom 2018-04-23 15:42:17.
Hallo ihr fleißigen Arma-Scripter, Zeuse und Mod-Bauer.
Ich würde gerne tiefer in die Welt der Arma-Programmierung einsteigen, d.h. "richtig" Scripten (MP-fähig!) und Zeusen lernen.
Programmiererfahrung habe ich bereits, allerdings lediglich Single-Player fähig. Nun würde ich gerne so programmieren lernen, dass die Scripte auch unfallfrei im Multiplayer funktionieren.
Weiterhin würde ich gerne verstehen, wie man Mods für Arma schreibt. Also eher so kleine Sachen, wie z.B. Funktionen zum Spiel hinzufügen die es in Vanilla nicht gibt. Beispielsweise sowas wie Belbo mit den ACE-Medic Erweiterungen (CPR und Splint) gemacht hat.
Sollte hier jemad sein wertvolles Wissen mit mir teilen wollen, wäre ich äußerst dankbar, in die Lehre gehen zu dürfen.
#2
Archiv-Beitrag: Ursprünglich von Belbo vom 2018-04-23 16:58:41.
Erste Adresse wäre für dich mein kleines Arma 3 Missionsbau-Tutorial. Darin ist besonders der Abschnitt über das BI-Wiki mit Informationen ausgestattet, die dir für spezifische Multiplayer-Themen weiterhelfen. Das BI-Wiki enthält normalerweise zu allen Befehlen die notwendigen Informationen, die du für die Berücksichtigung von Multiplayer-Problemen benötigst.
Das Hauptproblem an MP-Scripting ist das Stichwort "Lokalität". Damit ist gemeint, wo bestimmter Code ausgeführt wird.
Dabei gibt es die beiden Grundlokalitäten: Server und Client. Ein Befehl mit lokalem Effekt, der auf dem Server ausgeführt wird, hat keinen Effekt auf den Clients. Ein Befehl mit globalem Effekt, der auf einem Client ausgeführt wird, hat diesen Effekt auf jedem Client, inklusive dem ausführenden Client, und dem Server.
Ein Beispiel: addWeaponCargoGlobal hat einen globalen Effekt (siehe die kleinen Symbole auf der BIKI-Seite). Das heißt, wenn wir den Befehl auf einem einzigen Client ausführen, dann ist der Effekt dennoch global - und sowohl der Server, als auch alle anderen Clients sehen den Effekt, mit anderen Worten: Für alle Clients liegt eine Waffe in der Kiste. Wenn wir den Befehl nur auf dem Server ausführen, ist der Effekt immer noch global, es liegt eine Waffe in der Kiste. Wenn wir jetzt den Befehl überall außer dem Server ausführen, wird der Befehl auf jedem Client ausgeführt, mit dem Ergebnis, das plötzlich (Anzahl an Clients) Waffen in der Kiste sind.
Das wollen wir natürlich verhindern, also fragen wir uns vor jedem Befehl: Ist der Effekt global? Wenn ja, haben wir Sorge dafür getragen, dass der Befehl nur einmal ausgeführt wurde? Wenn nein, wo muss der Befehl ausgeführt werden und haben wir dafür Sorge getragen, dass der Befehl überall dort ausgeführt wird, wo wir den Effekt haben wollen.
Ein weiteres Beispiel wäre setRank. Der Befehl hat nur lokalen Effekt. Das bedeutet, dass wenn ich den Befehl auf dem Client eines Spielers ausführe, sehen die anderen die Auswirkung davon nicht. Wenn jetzt beispielsweise der Server abfragt, welchen Rank der Spieler hat, wird der immer den sehen, der gesetzt war, bevor setRank ausgeführt wurde. Um einen Befehl mit lokalem Effekt überall ausführen zu lassen, muss man zu Netzwerkbefehlen wie remoteExec greifen. Da kann man beispielsweise über die Parameter festlegen, ob der Befehl auf nur dem Server (bspw. bei Befehlen mit globalem Effekt, die wir aber auf einem Client ausführen müssen), nur auf den Clients, oder auf Server und Clients (bspw. mit setRank) ausgeführt werden soll.
Ein weiteres Problem mit Lokalität, ist die Definition von Variablen. Diese geschieht immer lokal zu dem Client/Server, auf dem die Variable definiert wurde. Wenn jetzt auf dem Server die Variable var_1 definiert wurde, weiß kein Client, dass es die Variable var_1 gibt, und damit auch nicht, welchen Wert sie hat. Dafür gibt es den Befehl publicVariable, oder man arbeitet direkt mit den Zusatzparametern von setVariable. var_1 könnte als missionNamespace-Variable gesetzt werden.
Damit ist eigentlich schon alles gesagt, was man über Lokalität wissen muss, wenn man für MP scripten möchte. Eine Mission, die MP-fähig ist, ist immer auch SP-fähig, vorausgesetzt, man arbeitet nicht mit isDedicated-Checks. Der Begrifflichkeit halber muss man allerdings noch sagen, dass die Begriffe "globale Variable" und "lokale Variable" nichts mit der Lokalität zu tun haben. Eine lokale Variable ist nur innerhalb eines Scripts definiert - deswegen nennt man sie "lokal". Es hat nichts mit dem Verhältnis von Clients und Server zu tun.
#3
Archiv-Beitrag: Ursprünglich von Belbo vom 2018-04-23 17:11:27.
Dann gibt es natürlich noch den Unterschied zwischen MP- und SP-Scripting in Hinsicht auf die Event-Scripts, deren Lokalität sowie deren Ausführungsreihenfolge. Bei der Initialization Order sieht man ja schon unter "Applies To", wo diese Scripts jeweils ausgeführt wird. Wenn da "All" steht, bedeutet dass, dass alles, was da drin steht, auch bei allen, Clients und Server, ausgeführt wird.
Will man da Code unterbringen, muss man sich wieder fragen: Haben die Befehle globalen Effekt? Habe ich dafür Sorge getragen, dass die Lokalität der Befehle berücksichtigt wurde? Dafür gibt es dann Befehle wie isServer und hasInterface. Mit diesen beiden kann man schon alles machen, was man braucht. isDedicated ist nicht wirklich sinnvoll, außer für ganz spezifische Probleme - und auf die muss ich tatsächlich erst noch stoßen, auch wenn wir einen dedizierten Server verwenden. Wer nur für dedizierten Server scriptet, hat, glaube ich, noch ganz andere Probleme.
Ein kleineres Problem der Lokalität betrifft die Lokalität der Argumente von Scriptbefehlen. Wenn irgendwo steht "Arguments local" bedeutet das, dass die Daten, die man an den Befehl weitergibt, dort bekannt sein müssen, wo der Befehl ausgeführt wird. Das ist ja auch klar: Wenn ich einen Befehl auf eine Einheit ausführen möchte, die auf einem bestimmten Client nicht definiert ist, dann hat der Befehl keinen Effekt oder wirft im schlimmsten Fall einen Fehler aus. addWeapon ist beispielsweise so ein Kandidat. Die Einheit, die die Waffe bekommen will, muss dort lokal sein, wo der Befehl ausgeführt wird. Bei player_1 eine Waffe für player_2 hinzuzufügen ist damit unmöglich, ebenso wie auf dem Server. Aber auch da hilft wieder remoteExec, indem man damit die Ausführung des Befehls auf den Client verschiebt, der die Einheit hat.
Da kommt aber ein spezifisches Problem dedizierter Server auf: Auf dediziertem Server ist player immer == null. Es gibt dort, prinzipbedingt, keinen player. Im gehosteten Spiel gibt es durchaus player, das ist nämlich die Spieleinheit des Hosts. Das sollte allerdings schon alles sein, was dafür spezifisch ist.
Wichtig ist also immer:
  1. Welche Effekt-Lokalität hat ein Befehl?
  2. Welche Argument-Lokalität hat ein Befehl?
  3. Muss der Befehl auf einem Client oder dem Server, oder auf allen ausgeführt werden?
  4. Darf der Effekt des Befehls nur einmal auftreten?
  5. Muss der Effekt des Befehls bei allen auftreten?
MP-Scripting ist tatsächlich weniger Zauberei, als immer gedacht wird, weil es sich damit tatsächlich bereits erschöpft.
Was Mod-Scripting angeht, ist das noch ein bisschen anders, aber auch bei weitem nicht so wahnsinnig kompliziert - einzig das System hinter Config-Vererbung benötigt manchmal ein bisschen Hirnschmalz. Da schreibe ich gerne später noch etwas zu.
#4
Archiv-Beitrag: Ursprünglich von Belbo vom 2018-04-23 17:25:41.
Alles, was man zum Erstellen einer Mod benötigt, findet man ersteinmal hier: https://community.bistud..._And_Gear_Encoding_Guide
Dort wird insbesondere die Datei-Struktur einer Mod-PBO erklärt. Das mindeste, was man dafür braucht, ist ein Ordner, der den Namen trägt, den später auch die pbo tragen soll, und eine Datei namens config.cpp. Damit hat man schon alles für den Anfang. Damit kann man beispielsweise anhand des Encoding Guides schon Items, Fahrzeuge oder Einheiten umbauen, also Eigenschaften, die diese Einheiten bereits haben, umdefinieren, oder ihnen neue Variablen zuweisen.
Ein Beispiel dafür wäre meine adv_tfar_backpacks-Mod. Alles was diese macht, ist vorhandene Classes von Backpacks (die in der CfgVehicles definiert sind) zu nehmen, und neue classes mit zwei veränderten Variablen zu erzeugen.
Will man etwas komplexere Sachen machen, empfiehlt es sich, die Functions Library anzuschauen. Denn wie in einer description.ext einer Mission kann man in der config.cpp eine cfgFunctions eintragen und damit Funktionen definieren, die beispielsweise über die preInit- oder postInit-Attribute entsprechend automatisch ausgeführt wird. So kann man Funktionen erzeugen, die unbhängig von der geladenen Mission, bei jeder Mission ausgeführt werden.
Ein ganz einfaches Beispiel dafür wäre meine adv_nvg-Mod. Diese hat ausschließlich die Aufgabe, eine Funktion am Start jeder Mission auszuführen, die die Optik der NVG-Ansicht ein bisschen aufhübscht. In der config.cpp findet sich nur die CfgPatches, so etwas wie der Header der Mod, und die CfgFunctions, in der diese eine Funktion mit dem postInit-Attribut definiert wird. Die Funktion findet sich dann entsprechend bei mir im functions-Ordner.
Und das ist im Grunde genommen schon alles, was ich zumindest über Modding sagen kann. Sicherlich gibt es noch mehr, was man machen kann, aber von solchen Dingen wie Modelling, also tatsächlich neue Objekte ins Spiel zu bringen, habe ich keine Ahnung.
#5
Archiv-Beitrag: Ursprünglich von MadJosch vom 2018-04-24 13:42:29.
Herzlichen Dank für deine Erklärungen. Das hilft mir schonmal viel weiter. Jetzt muss ich mich Stück für Stück herantasten. Mit deinem Tutorial hatte ich mich ja schon einmal auseinandergesetzt. Ich muss das jetzt alles mal in der Praxis ausprobieren.
Dabei stellt sich mir eine ganz pragmatische Frage: Wie teste ich, ob ein Script im Multiplayer auch funktioniert? Ich hab ja nicht mehrere Clients, mit denen ich das testen kann.
#6
Archiv-Beitrag: Ursprünglich von Belbo vom 2018-04-24 16:07:13.
Mach' dir eine Start-Bat für einen dedizierten Server und teste deine Mission da. Dann hast du immer einen Multiplayer. Wink Damit kann man zugegebenermaßen nicht alle Fälle abdecken, die auftauchen können, aber die ersten schon.
Zusätzlich besteht immer die Möglichkeit, Code in der Konsole zu testen, solange man Admin ist. Damit lassen sich auch Dinge auf unserem Server mit anderen testen, selbst wenn man keine Mission hochgeladen hat.
Das geht folgendermaßen:
  1. Der Code, den man testen möchte, darf keine Kommentare, also // oder /* */, enthalten.
  2. Der Code muss, da die Konsole nur unscheduled ausführt, möglicherweise per spawn ausgeführt wird.
  3. Argumente, die an den Code weitergegeben werden müssen, müssen auch in der Konsole vorkommen.
Das könnte beispielsweise so aussehen:

Klickt man nun auf "Global Exec", wird der Code auf jedem Client und dem Server ausgeführt, aber der Code hinter der if-Bedingung nur bei demjenigen Client, dessen Spieler die Spielereinheit player_1 führt. var_1 wird (durch das true in den Argumenten von setVariable) durch den Code auf allen Clients und dem Server als _player, in diesem Fall also player_1, definiert.
#7
Archiv-Beitrag: Ursprünglich von MadJosch vom 2018-04-24 17:59:47.
Bild vom Archiv entfernt Belbo, ein Quell des Wissens
Bild vom Archiv entfernt Danke!


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste