Lampen-Prop entfernt. Seit der Umstellung auf die spieleigene Scuba-Lampe war es funktionslos: standardmaessig aus, nie verifiziert, und eine Polizei-Taschenlampe am Kopf haette neben dem nativen Licht nur Deko gespielt. Damit fallen auch die Debug-Befehle /divelamp und /divelampcheck weg, samt config.debug und vier Config-Werten. Zwoelf Upstream-Locales geloescht. Sie hatten 8 von 26 Keys - im Spiel waeren dort rohe Key-Namen erschienen. Gepflegt werden DE und EN. PLAN.md war ein Vorab-Plan mit Phasen und Aufwandsschaetzungen und damit erledigt. Ersetzt durch ENTSCHEIDUNGEN.md: warum die Dinge so gebaut sind und welche Fallstricke dahinterstecken - onCache-Timing, consume, decay, SetMetadata, die Atemgas-Grenze, das transform-origin am Zeiger. Also das, was beim naechsten Anfassen wirklich hilft. README von den Abschnitten befreit, die es nicht mehr gibt. Bilder und Icons neu erzeugt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.5 KiB
Entscheidungen und Fallstricke
Warum die Dinge so gebaut sind, wie sie gebaut sind. Wer hier etwas ändern will, sollte den jeweiligen Absatz vorher gelesen haben — das meiste davon hat genau einmal wehgetan.
Fork von qbx_divegear v1.0.1. Die
Upstream-Historie liegt vollständig auf dem Remote upstream.
Was am Original nicht funktionierte
- Der Sauerstoff war eine lokale Client-Variable, die an keinem Item hing. Nicht persistent, nicht übertragbar, weg bei Relog. Damit war weder eine Flaschengröße noch eine ehrliche Restluft-Anzeige möglich.
- Die Laufzeit war verrechnet:
startingOxygenLevel = 100beidecayRate = 1pro Sekunde ergab 100 Sekunden, nicht Minuten. - Die Props waren soft-pinned angehängt. Mit
useSoftPinning = truedarf die Physik-Engine die Verbindung bei Ragdoll und harten Anim-Übergängen lösen — genau deshalb verschwand die Ausrüstung ständig.
Ausrüstung
Attachment hart, nicht soft. useSoftPinning = false; laut Native-Doku heißt
das "attached entity will not detach when fixed". Zusätzlich prüft ein Watchdog
jede Sekunde, ob beide Props noch am aktuellen Ped hängen, und hängt sie sonst
neu an. Er setzt auch SetEnableScuba und SetPedMaxTimeUnderwater neu, weil das
Spiel beides bei Respawn und Fahrzeugausstieg zurücksetzt.
lib.onCache('ped') gibt den neuen Ped als Parameter — cache.ped nicht.
ox_lib ruft die Callbacks über Citizen.CreateThreadNow auf, bevor der neue Wert
in den Cache geschrieben wird. Wer im Handler cache.ped benutzt, hängt die Props
an den gerade verschwundenen Ped. Das ist der Kleiderladen-Fall, für den der
Handler überhaupt existiert.
SetPedMaxTimeUnderwater hat zwei Werte, das ist Absicht. maxTimeUnderwater
(50 s) beim Ablegen = normal weiterschwimmen. maxTimeUnderwaterOutOfAir (1 s)
bei leerer Flasche = absaufen. Sieht nach Inkonsistenz aus, ist keine.
Besitz wird laufend geprüft. Ausrüstung und Flasche können das Inventar mitten
im Tauchgang verlassen — weggegeben, abgelegt, vom Admin entfernt. Der Client hält
nur eine Slot-Nummer; ohne Gegenprüfung taucht man unbegrenzt weiter.
ox_inventory:updateInventory feuert bei jeder Änderung, dort wird beim Server
nachgefragt. Wurde nur umsortiert, bindet der Client auf den neuen Slot um.
Items
Kein consume bei Items mit CreateUseableItem. ox_inventory verzweigt so:
elseif consume then -- interner Pfad
elseif not item.weapon and server.UseItem then -- hier erst CreateUseableItem
In Lua ist 0 wahr. consume = 0 landet im ersten Zweig, der qbx-Callback feuert
nie, und beim Benutzen passiert gar nichts — ohne Fehlermeldung. Steht so nicht
in der ox-Doku, nur im Quellcode.
Kein decay auf den Flaschen. metadata.durability trägt hier den Füllstand.
ox_inventory löscht Items mit decay, sobald durability 0 erreicht — die leere
Flasche würde also verschwinden statt auffüllbar zu bleiben.
SetMetadata ersetzt die Metadata-Tabelle komplett, es merged nicht. Deshalb
wird der bestehende Inhalt kopiert, bevor oxygen und durability gesetzt werden.
Flaschen ohne Metadata gelten als voll (newTanksFull). Eine frisch gekaufte
Flasche hat kein oxygen — ohne diese Regel wäre sie leer und man müsste erst eine
Kartusche verbrauchen, um überhaupt tauchen zu können.
Sauerstoff
Restsekunden statt Punkte, und der Verbrauch läuft über GetGameTimer()-Deltas
statt gezählter Wait(1000). Ein Tick dauert unter Last länger als eine Sekunde;
über einen 20-Minuten-Tauchgang summiert sich das sichtbar.
Der Server clampt. Der Client meldet die Restluft, der Server akzeptiert nur
Abnahme und höchstens maxDrainPerSecond pro echter Sekunde. Wer den Tiefenfaktor
oder den Narkose-drainFactor hochdreht, muss diesen Wert mitziehen — sonst
bekommen ehrliche Spieler in großer Tiefe Luft zurückgeschrieben.
Tiefe
Die Grenze hängt am Atemgas, nicht an einer unsichtbaren Wand. Real begrenzt
nicht der Druck, sondern der Stickstoff in der Pressluft: tiefer wirkt er
narkotisch, ab etwa 56 m wird auch der Sauerstoff giftig. Wer tiefer will, atmet
Trimix. Genau so umgesetzt — maxDepth pro Flasche, darunter Tiefenrausch in
Stufen.
Bei 160 m ist Schluss, das macht die Engine. Dagegen hilft kein Atemgas, deshalb dort nur eine Warnung und kein eigener Effekt. Trimix hört mit 100 m bewusst darüber auf.
Lampe
Die spieleigene Scuba-Lampe, kein Eigenbau. GTA hat seit v1493
SetEnableScubaGearLight (0xEE2476B9EE4A094F). Die sitzt richtig, leuchtet in
Blickrichtung und macht Prop, Offsets, Kegelwerte und einen Draw-Thread
überflüssig. Gefunden über esx_scuba.
Der dortige Hinweis, das Licht hänge am Kleidungs-Component 8, trifft nicht zu — ingame geprüft, sie funktioniert auch ohne Scuba-Kleidung. Das Outfit wird nicht angefasst.
Der Flag ist lokal und repliziert sich nicht von selbst. Deshalb der Umweg über einen Statebag: jeder Client setzt den Flag für die Taucher in seiner Nähe. Der Abgleich-Thread ist nötig, weil Peds beim Streaming, Respawn und Model-Wechsel neu erzeugt werden und den Flag dabei verlieren.
HUD
Zeigerinstrumente ohne Skalenzahlen. Bei 96 px kollidieren Zahlen mit Strichen, Zeiger und rotem Bereich, und gelesen werden sie ohnehin nicht. Der Zeiger zeigt die Tendenz, die Zahl darunter den Wert.
Kein transform-origin am Zeiger. Das rotate(winkel 50 50) im
transform-Attribut bringt den Drehpunkt schon mit; CSS rechnet eine zusätzliche
Origin obendrauf und der Zeiger landet außerhalb der Uhr.
Das HUD skaliert mit der Bildschirmhöhe. Entworfen auf 1080p; FiveM rendert das NUI in der echten Auflösung, ohne Nachskalieren wäre es auf 4K halb so groß.
Kein backdrop-filter — bekannter FiveM-Bug, wird nach Updates zu einem
schwarzen Kasten.
Offen
- Nach einem Relog muss die Ausrüstung neu angelegt werden. Die Restluft überlebt, die liegt auf der Flasche.
- Die HUD-Position ist nur in
nui/style.csseinstellbar, nicht in der Config. IsHudHidden()— ob die Native aufDisplayHud(false)anspringt, ist ungeprüft. Falls nicht, greifen Taste und Export weiterhin.- Die
timecycle-Namen des Tiefenrauschs sind nicht verifiziert. Kommt kein Effekt, inconfig/client.luaunternarcosis.stageseinen anderen eintragen. - Balancing: Laufzeiten und Narkose-Stufen sind gesetzt, aber nicht über längere Zeit am Spielgefühl geprüft.