Files
d4rk_divegear/ENTSCHEIDUNGEN.md
T
D4rkst3randClaude Opus 5 1ed6a924f8 chore: aufgeraeumt nach der Abnahme
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>
2026-08-11 10:16:04 +02:00

141 lines
6.5 KiB
Markdown

# 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](https://github.com/Qbox-project/qbx_divegear) v1.0.1. Die
Upstream-Historie liegt vollständig auf dem Remote `upstream`.
---
## Was am Original nicht funktionierte
1. **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.
2. **Die Laufzeit war verrechnet:** `startingOxygenLevel = 100` bei `decayRate = 1`
pro Sekunde ergab 100 Sekunden, nicht Minuten.
3. **Die Props waren soft-pinned angehängt.** Mit `useSoftPinning = true` darf 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:
```lua
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](https://github.com/wobozkyng/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.css` einstellbar, nicht in der Config.
- `IsHudHidden()` — ob die Native auf `DisplayHud(false)` anspringt, ist ungeprüft.
Falls nicht, greifen Taste und Export weiterhin.
- Die `timecycle`-Namen des Tiefenrauschs sind nicht verifiziert. Kommt kein Effekt,
in `config/client.lua` unter `narcosis.stages` einen anderen eintragen.
- Balancing: Laufzeiten und Narkose-Stufen sind gesetzt, aber nicht über längere
Zeit am Spielgefühl geprüft.