diff --git a/README.md b/README.md index 7467a1d..efcf495 100644 --- a/README.md +++ b/README.md @@ -172,12 +172,14 @@ FiveM* umlegbar. | Option | Default | Bedeutung | |---|---|---| | `lampKey` | `'l'` | Vorbelegung | -| `lampProp` | `'prop_cs_police_torch'` | Optik. Ungültiges Model → Warnung im Log, Licht funktioniert trotzdem | -| `lampOffset` | `vec3(0, 0.15, 0)` | Position relativ zum Kopf-Bone | +| `lampBone` | `12844` | Bone für Prop **und** Licht — derselbe, damit der Strahl aus der Lampe kommt. `28422` = Hand statt Kopf | +| `lampProp` | `'prop_cs_police_torch'` | Optik. Ungültiges Model → Warnung im Log, Licht funktioniert trotzdem. `''` = kein Prop | +| `lampPropOffset` / `lampPropRotation` | `vec3(0,0,0)` | Sitz des Props am Bone — mit `/divelamp` einstellen | +| `lampOffset` | `vec3(0,0,0)` | Ursprung des Lichtkegels, bone-relativ | | `lampDirection` | `vec3(0, 1, 0)` | Richtung des Kegels, bone-relativ | -| `lampColour` | `{225, 245, 255}` | RGB | -| `lampDistance` / `lampBrightness` / `lampRoundness` / `lampRadius` / `lampFalloff` | `30/6/1/14/1.5` | Form des Lichtkegels | -| `lampShadows` | `true` | `false` nutzt `DrawSpotLight` statt der Schattenvariante — flacher, aber spürbar schneller | +| `lampColour` | `{255, 250, 235}` | RGB | +| `lampDistance` / `lampBrightness` / `lampRoundness` / `lampRadius` / `lampFalloff` | `28/3/0/16/2` | Form des Lichtkegels, Werte aus `d4rk_phone` übernommen | +| `lampShadows` | `false` | `true` nutzt `DrawSpotLightWithShadow` — sieht besser aus, kostet aber deutlich Performance | | `lampDrawDistance` | `45.0` | Ab hier werden fremde Lampen nicht mehr gezeichnet | | `lampMaxLights` | `4` | Gleichzeitige Lampen, die nächstgelegenen gewinnen | @@ -185,6 +187,30 @@ FiveM* umlegbar. > `maxDecayFactor` (client) liegen. Sonst hält der Server den ehrlichen Verbrauch > in großer Tiefe für Cheat und schreibt Luft zurück. +## Lampe einstellen + +Wo Prop und Lichtkegel am Kopf sitzen, hängt daran, wie das Prop-Model selbst +ausgerichtet ist — das lässt sich nicht am Schreibtisch erraten. Mit +`debug = true` in `config/client.lua` gibt es zwei Befehle, die die Werte im +laufenden Spiel ändern und die fertige Config-Zeile ins Log schreiben: + +``` +/divelamp Sitz des Lampen-Props +/divelight Ursprung und Richtung des Lichtkegels +``` + +Das Prop wird sofort neu angehängt, das Licht zieht ohne Verzögerung mit — kein +Resource-Restart pro Versuch. Sind die Werte gut, die ausgegebenen Zeilen in die +Config übernehmen und `debug` wieder ausschalten. + +Alternativ mit einem Prop-Attach-Editor wie +[noted_propattacher](https://github.com/NotedDevelopment/noted_propattacher) +ausmessen: Prop spawnen, mit der Maus an die Stelle ziehen, Werte übernehmen. + +> Im Basegame gibt es **keine** Tauchlampe. `prop_cs_police_torch` ist eine +> Polizei-Taschenlampe; Varianten davon sind `prop_police_torch` und +> `prop_scn_police_torch`. Wer eine echte Tauchlampe will, braucht ein Custom-Model. + ## Exports ```lua diff --git a/client/light.lua b/client/light.lua index ea98fc2..bc500bc 100644 --- a/client/light.lua +++ b/client/light.lua @@ -10,7 +10,6 @@ local config = require 'config.client' -- anderen Tauchers selbst zeichnet. local STATE_KEY = 'divelight' -local HEAD_BONE = 31086 -- SKEL_Head --- Kandidaten des aktuellen Frames. Wird wiederverwendet statt jedes Frame neu --- angelegt, damit der GC bei Dauerbetrieb nichts zu tun bekommt. @@ -26,8 +25,8 @@ local function getLampVectors(ped) local offset = config.lampOffset local direction = config.lampDirection - local from = GetPedBoneCoords(ped, HEAD_BONE, offset.x, offset.y, offset.z) - local ahead = GetPedBoneCoords(ped, HEAD_BONE, + local from = GetPedBoneCoords(ped, config.lampBone, offset.x, offset.y, offset.z) + local ahead = GetPedBoneCoords(ped, config.lampBone, offset.x + direction.x, offset.y + direction.y, offset.z + direction.z) diff --git a/client/main.lua b/client/main.lua index 0ab6b98..d7912cd 100644 --- a/client/main.lua +++ b/client/main.lua @@ -125,10 +125,10 @@ end --- Lampen-Model einmalig prüfen. lib.requestModel wirft bei ungültigen Models einen --- Error - ohne diese Prüfung würde ein falsch geschriebener Prop-Name die komplette --- Ausrüstung unbenutzbar machen, statt nur die Optik der Lampe zu kosten. -local lampModel = joaat(config.lampProp) -local hasLampProp = IsModelValid(lampModel) or IsModelInCdimage(lampModel) +local lampModel = config.lampProp ~= '' and joaat(config.lampProp) or nil +local hasLampProp = lampModel ~= nil and (IsModelValid(lampModel) or IsModelInCdimage(lampModel)) -if not hasLampProp then +if lampModel and not hasLampProp then lib.print.warn(('lampProp "%s" ist kein gültiges Model - die Lampe leuchtet, das Prop fehlt.'):format(config.lampProp)) end @@ -139,7 +139,7 @@ local function attachGear(ped) currentGear.mask = attachProp(ped, MASK_MODEL, MASK_BONE, vec3(0.0, 0.0, 0.0), vec3(180.0, 90.0, 0.0)) if hasLampProp then - currentGear.lamp = attachProp(ped, lampModel, MASK_BONE, vec3(0.1, 0.05, 0.0), vec3(180.0, 90.0, 0.0)) + currentGear.lamp = attachProp(ped, lampModel, config.lampBone, config.lampPropOffset, config.lampPropRotation) end end @@ -536,6 +536,59 @@ lib.addKeybind({ end }) +--- Wo Prop und Lichtkegel am Bone sitzen, lässt sich nicht am Schreibtisch +--- erraten - das hängt daran, wie das Model selbst ausgerichtet ist. Diese Befehle +--- ändern die Werte im laufenden Spiel und geben die Zeile zum Übernehmen aus, +--- damit nicht pro Versuch die Resource neu gestartet werden muss. +--- +--- lib.require cached Module, main.lua und light.lua teilen sich also dieselbe +--- config-Tabelle - das Licht zieht sofort mit. +if config.debug then + --- @return vector3? + local function readVec(args, from) + local x, y, z = tonumber(args[from]), tonumber(args[from + 1]), tonumber(args[from + 2]) + + if not x or not y or not z then return end + + return vec3(x, y, z) + end + + local function fmtVec(v) + return ('vec3(%.2f, %.2f, %.2f)'):format(v.x, v.y, v.z) + end + + RegisterCommand('divelamp', function(_, args) + local offset, rotation = readVec(args, 1), readVec(args, 4) + + if not offset or not rotation then + lib.print.info('/divelamp - Sitz des Lampen-Props') + return + end + + config.lampPropOffset, config.lampPropRotation = offset, rotation + + if currentGear.enabled then + deleteGear() + attachGear() + end + + lib.print.info(('lampPropOffset = %s,\nlampPropRotation = %s,'):format(fmtVec(offset), fmtVec(rotation))) + end, false) + + RegisterCommand('divelight', function(_, args) + local offset, direction = readVec(args, 1), readVec(args, 4) + + if not offset or not direction then + lib.print.info('/divelight - Ursprung und Richtung des Lichtkegels') + return + end + + config.lampOffset, config.lampDirection = offset, direction + + lib.print.info(('lampOffset = %s,\nlampDirection = %s,'):format(fmtVec(offset), fmtVec(direction))) + end, false) +end + --- Beim Model-Wechsel (Kleiderladen, Skin-Change) ist der Ped ein anderer - --- alle attached Props sind weg und die Scuba-Flags gelten für den alten Ped. --- diff --git a/config/client.lua b/config/client.lua index b456bae..e2f73cf 100644 --- a/config/client.lua +++ b/config/client.lua @@ -1,4 +1,9 @@ return { + --- Schaltet /divelamp und /divelight frei, mit denen sich Sitz und + --- Leuchtrichtung der Lampe im laufenden Spiel einstellen lassen - ohne + --- Resource-Restart pro Versuch. Auf dem Live-Server ausschalten. + debug = false, + putOnSuitTimeMs = 5000, takeOffSuitTimeMs = 5000, refillTankTimeMs = 5000, @@ -61,31 +66,53 @@ return { --- Tastenbelegungen unter "FiveM" umlegen. lampKey = 'l', - --- Prop am Kopf. Rein optisch - das Licht selbst hängt nicht daran. - --- Ist das Model ungültig, wird nur das Licht gezeichnet und eine Warnung - --- ins Log geschrieben. Alternativen: siehe forge.plebmasters.de/objects + --- Bone, an dem Lampe und Licht hängen. Beides derselbe Bone, damit der + --- Strahl auch sichtbar aus der Lampe kommt. + --- 12844 = Kopf (wie die Maske) - Strahl folgt der Blickrichtung + --- 28422 = Hand (wie das Prop in d4rk_phone) - Handlampe, aber beim + --- Schwimmen sind die Arme seitlich ausgestreckt, der Kegel + --- wandert also mit den Schwimmzügen + lampBone = 12844, + + --- Prop am Kopf. Rein optisch - das Licht hängt nicht daran, es wird nur + --- vom selben Bone aus gezeichnet. Ist das Model ungültig, leuchtet es + --- trotzdem und es gibt eine Warnung im Log. + --- Im Basegame gibt es keine Tauchlampe. Alternativen sind Varianten + --- derselben Polizei-Lampe: 'prop_police_torch', 'prop_scn_police_torch'. + --- Auf '' setzen = gar kein Prop, nur Licht. lampProp = 'prop_cs_police_torch', - --- Position des Lichts relativ zum Kopf-Bone (bone-relativ, nicht Weltkoordinaten). - lampOffset = vec3(0.0, 0.15, 0.0), + --- Sitz des Props am Bone. Wie in d4rk_phone bewusst auf null: das Prop sitzt + --- dann genau im Bone statt auf geratenen Offsets. Beim Kopf-Bone darf ein + --- kleiner Versatz nach vorne/seitlich nötig sein, damit die Lampe nicht im + --- Schädel steckt - mit /divelamp im Spiel einstellen statt hier zu raten. + lampPropOffset = vec3(0.0, 0.0, 0.0), + lampPropRotation = vec3(0.0, 0.0, 0.0), + + --- Ursprung des Lichtkegels relativ zum Bone (bone-relativ, nicht Welt). + --- Sollte ungefähr dort liegen, wo das Prop sitzt. + lampOffset = vec3(0.0, 0.0, 0.0), --- Richtung des Lichtkegels, ebenfalls bone-relativ. Leuchtet der Kegel in die --- falsche Richtung, hier die Achse tauschen oder das Vorzeichen drehen - --- welche lokale Achse des Kopf-Bones nach vorne zeigt, hängt am Skelett. lampDirection = vec3(0.0, 1.0, 0.0), - --- Lichtfarbe als { r, g, b }, 0-255. Leicht kühl für Unterwasser. - lampColour = { 225, 245, 255 }, + --- Lichtwerte aus d4rk_phone übernommen - dort im Betrieb erprobt, statt hier + --- neu geraten. Leicht warmweiß wie eine echte Taschenlampe. + lampColour = { 255, 250, 235 }, - lampDistance = 30.0, -- Reichweite in Metern - lampBrightness = 6.0, -- Helligkeit - lampRoundness = 1.0, -- Weichzeichnung des Kegelrands - lampRadius = 14.0, -- Öffnungswinkel - lampFalloff = 1.5, -- Abfall zum Rand hin + lampDistance = 28.0, -- Reichweite in Metern + lampBrightness = 3.0, -- Helligkeit + lampRoundness = 0.0, -- Weichzeichnung des Kegelrands + lampRadius = 16.0, -- Öffnungswinkel + lampFalloff = 2.0, -- Abfall zum Rand hin - --- Schatten kosten deutlich Performance. Auf false wird DrawSpotLight statt - --- DrawSpotLightWithShadow benutzt - sieht flacher aus, läuft aber spürbar besser. - lampShadows = true, + --- Schatten kosten deutlich Performance. d4rk_phone nutzt bewusst das + --- schattenlose DrawSpotLight, deshalb hier auch der Default - unter Wasser + --- fällt der Unterschied kaum auf, in einer Höhle mit mehreren Tauchern + --- dagegen sehr wohl. + lampShadows = false, --- Ab dieser Entfernung werden fremde Lampen nicht mehr gezeichnet (Meter). lampDrawDistance = 45.0,