PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Lokalitäten, MP, Dedicated, Server und der Versuch es zu verstehen


wolkenstuermer
20.10.2016, 21:02
Hallo!

Nachdem ich feststelle, dass ich immer wieder mit dem Irrsinn stolpere: Kann mir einer von den durchsteigenden Skriptern mal auf Deutsch erklären, was es mit diesem Wirrwar zu tun hat und wie man als normalsynapsierter Mensch da durchsteigen kann, so dass es auch hängen bleibt?

Ich habe zum Beispiel einen Lautsprecher, der soll einen hässlichen Alarm ausspucken und zwar so, dass
- alle ihn EINMAL hören
- alle ihn jeweils ein- oder ausschalten können

Im Singleplayer ist das halbwegs einfach:
1) Skript schreiben, da steht drin

private ["_soundpath", "_sound", "_repeat", "_duration", "_volume", "_pitch", "_distance"];

_soundpath = [(str missionConfigFile), 0, -15] call BIS_fnc_trimString; // define relative path to description.ext
_sound = _soundpath + "sounds\luftalarm.ogg"; // sound with relative path to description.ext
_repeat = 1000; // times the sound will play in loop
_duration = 4.733; // time in seconds between loops (normally the duration of the soundsample
_volume = 10; // volume in db, effects distance (i.e. 1 km needs volume to be around 10+)
_pitch = 1; // pitch of the sound
_distance = 1500; // maximum distance the sound could be heared

speakerAirport = createVehicle ["Land_HelipadEmpty_F", getPosATL loudspeaker_airport, [], 0, "NONE"];

for [{_i=0},{_i<_repeat},{_i=_i+1}] do
{
playSound3D [_sound, speakerAirport, false, getPosASL speakerAirport, _volume, _pitch, _distance];
sleep _duration;
};

deleteVehicle speakerAirport;

Wobei "speakerAirport" und "loudspeaker_airport" ein global in Skripten erreichbares Objekt sind, damit ich das erzeugte Objekt a) ansprechen und b) später killen kann (damit der hässliche Sound auch wieder aufhört).

Soweit klappt das ganz gut. Aber nur im Singleplayer.
Das mit den "privates" habe ich auf deutsch so verstanden, dass ich die brauche, um sie vorher definieren zu können, ohne dass sie dann im Scope drunter kollidieren (so richtig habe ich es also nicht verstanden).

Im MP klappt das Ganze aber nicht, bzw. nur unvollständig.
Jeder kann den Sound auslösen, ich denke, ich könnte das abfangen, indem ich das erzeugte addAction mittels ID lösche, sobald einer es ausgewählt hat und es erst wieder anfüge, wenn jemand ausschaltet (anderes Skript).

Aber das mit den Servern, MP, remoteExec, isDedicated, etc. begreife ich nur halb. Und daher klappt immer nur die Hälfte von dem ganzen Skriptzeuchs auf dem Dedicated.

Ich denke als Normalsterblicher immer so, dass ein Skript auf einem Rechner aufgerufen wird, oder auf allen oder nur auf dem Server oder ein MischMasch daraus (auf einem Client aufgerufen, dann an alle Clients verteilt oder nur auf dem Server ausgeführt), aber wie kann ich mir das so mit der realen Welt verknüpfen, dass ich mir das merken kann?

Im Beispiel: Ich will ja, dass JEDER Spieler das aufrufen kann, also sollte der addAction ja auf dem Server aufgerufen werden (oder denke ich hier schon falsch?) und dann sollte das Skript aber jedem Client sagen "hallo ich spiele jetzt einen grässlichen Ton, der euch allen die Ohren GLEICHZEITIG und EINMAL ruiniert, nicht bei jedem lokal anders und mehrmals.".

Also naiv geschrieben: rufe mittels addAction z.B. in einem Laptop auf dem Server ein Skript auf, dieses verzählt aber jedem Spieler, was passiert. Und der Ton wird dann wieder nur vom Server wiedergegeben oder würfele ich da alles durcheinander?

Wenn ich das nun in eine

if (isDedicated) then {Skript}; packe, heisst das nun, dass nur der Server es ausführt und was bedeutet es im Endeffekt für meinen Sound und für die auf dem Dedicated spielenden Spieler?

Muss ich mittels public meine Variablen durch die Gegend verteilen?

Wann mache ich was und warum? :confused:

Und ja. Ich habe schon recht viel darüber gelesen, vom Wiki bis zu KillzoneKids völlig durchgedrehten Ausführungen. Aber es ist mir zu hoch. Bzw. bringe ich glaube ich ständig Dinge durcheinander, die mich dann daran hindern, es einmal richtig gedanklich zu verankern, damit ich in Zukunft genau sagen kann: Klar, ich brauche das auf dem Dedicated, als remoteExec mit publics, weil sonst schreit er nur lautlos für alle auf dem Server rum.

Vielleicht kann mir das einer mal eindeutschen? Bzw. einnaivisieren?
Das frustriert ein bisschen, weil Skripten an sich recht viel Spaß macht, aber es selten klappt, wenn man nicht richtig schnallt, was man da eigentlich macht :zahn:

Wäre dankbar und meine Synapsen könnten sich mal wieder entknoten.

Cheers!

Pfandgiraffe
20.10.2016, 22:37
Ja, du haust alles durcheinander.

Der Action Eintrag muss bei den Clients vorhanden sein. Das Auslösen der Action kann ja auch nur ein Spieler machen. (zumindest ohne Script) Der Code der per addAction ausgeführt wird, wird dann auch bei dem Client lokal ausgeführt welcher die Action ausgelöst hat.

Dein Script hingegen sollte wirklich nur der Server ausführen damit der Sound nicht doppelt und dreifach abgespielt wird. Außerdem läuft es dann auch (halbwegs) synchron ab.


Sieht dann etwa so aus:

Zuerst das Script welches durch deine addAction beim Client ausgeführt wird. Dieses Script beinhaltet jetzt eine Verriegelung damit es nur einmal ausgeführt werden kann. Dazu sendet es an den Server den Befehl den eigentliches Script auszuführen.

params ["_obj", "_caller", "_id"];

if (isNil "action_locked" then {
action_locked = true; // action verriegeln
publicVariable "action_locked";

[] remoteExecCall ["ABC_fnc_Luftalarm", 2, false]; // befehl an server deine funktion zu rufen
[_obj, {player removeAction _id}] remoteExec ["call", 0, true]; // action für jeden client entfernen, inkl. JIP's
};

Ich setze jetzt mal voraus das du schon weist wie man eine Funktion initialisiert. Jetzt dein Script welches du als Funktion kompilieren wirst. (fn_luftalarm.sqf) Das Script wird jetzt nur noch vorm Server ausgeführt. Außerdem habe ich es in einen spawn {} gesetzt, da der gecallte Loop sonst nich funzen würde.


if (!isServer) exitWith {}; // server only

true spawn {
private _soundpath = [(str missionConfigFile), 0, -15] call BIS_fnc_trimString; // define relative path to description.ext
private _sound = _soundpath + "sounds\luftalarm.ogg"; // sound with relative path to description.ext
private _repeat = 1000; // times the sound will play in loop
private _duration = 4.733; // time in seconds between loops (normally the duration of the soundsample
private _volume = 10; // volume in db, effects distance (i.e. 1 km needs volume to be around 10+)
private _pitch = 1; // pitch of the sound
private _distance = 1500; // maximum distance the sound could be heared

speakerAirport = createVehicle ["Land_HelipadEmpty_F", getPosATL loudspeaker_airport, [], 0, "NONE"];

for [{_i=0},{_i<_repeat},{_i=_i+1}] do
{
playSound3D [_sound, speakerAirport, false, getPosASL speakerAirport, _volume, _pitch, _distance];
sleep _duration;
};

deleteVehicle speakerAirport;
};


ungetestet. Sollte funzen.

Grüße



p.s.: Und bevor der erste Klugscheißer um die Ecke kommt - das ist natürlich keine optimierte Lösung! Das ist eine sehr einfache Lösung mit so wenig wie möglich Veränderungen von der Ausgangsbasis, da es hier um das Verstehen geht und nicht um eine Performance Optimierung für 100+ Coop Missionen.
Und ja, die Nil Frage + das entfernen des Action Entrys macht eine der beiden Aktionen überflüssig - aber Arma ist eine Hure!

wolkenstuermer
21.10.2016, 20:28
Hi Pfandgiraffe,

vielen Dank für das Geschriebene. Ich werde das jetzt mal durchhirnen und versuchen zu begreifen.

Und: Es kann gerne auch geklugscheissert werden, denn eine Optimierung zeigt ja auch andere Hirnwindungen auf, die einen weiterbringen. Ich würde auch gerne wissen, wie man es optimieren kann, man kann nie genug lernen.

Ziel: Es gibt 2 Objekte irgendwo, einer ist ein Laptop, einer ist ein Lautsprecher. Am Laptop soll man per Aktion "Alarm auslösen" und "Alarm abstellen" auswählen können, dann soll global auf dem Server das Getröte hörbar sein, so dass es alle gleichzeitig und nur einmal hören, auch JIP.

Ich habe mich z.B. auch gefragt, ob man es nicht eleganter lösen kann, so dass man sich die globalen Variablen sparen kann, indem man einer Gamelogic vielleicht einfach zwei Objekte "mitteilen" kann, die man dann mittels select übermittelt oder ähnlich. Oder, da man den Auslöser ja eh immer braucht, einen select 0 für den Schlepptopf und eine Variable für den Lautsprecher mit übermitteln (select 2, da select 1 ja der caller ist?)

Danke auf jeden Fall. Es hilft einfach unheimlich weiter, wenn einem jemand gewisse Dinge auf "dummy" erklären kann.