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>
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user