Lint / Lint Resource (push) Has been cancelled
Offset und Rotation des Lampen-Props waren hart im Code, und die Rotation (180, 90, 0) war stumpf von der Maske uebernommen - daher stand die Lampe quer im Gesicht. d4rk_phone haengt sein Prop mit komplett null Offset und Rotation an, das ist der bessere Ausgangspunkt. - lampBone, lampPropOffset, lampPropRotation in die Config; Prop und Licht haengen jetzt am selben Bone, damit der Strahl aus der Lampe kommt - lampProp = '' erlaubt, dann nur Licht ohne Prop - Lichtwerte (Farbe, Reichweite, Helligkeit, Kegel) aus d4rk_phone uebernommen statt neu geraten; lampShadows wie dort auf false - /divelamp und /divelight stellen beides im laufenden Spiel ein und geben die Config-Zeile zum Uebernehmen aus (config.debug) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
112 lines
4.0 KiB
Lua
112 lines
4.0 KiB
Lua
local config = require 'config.client'
|
|
|
|
-- Reiner Renderer: zeichnet die Lampen aller Taucher in der Nähe, gesteuert
|
|
-- ausschließlich über den replizierten Statebag. Kein gemeinsamer Zustand mit
|
|
-- client/main.lua - das hier läuft auch für Spieler, deren Ausrüstung wir gar
|
|
-- nicht kennen.
|
|
--
|
|
-- Licht ist in GTA nie synchronisiert: DrawSpotLight zeichnet nur lokal, für den
|
|
-- aktuellen Frame. "Gesynct" heißt deshalb, dass jeder Client das Licht jedes
|
|
-- anderen Tauchers selbst zeichnet.
|
|
|
|
local STATE_KEY = 'divelight'
|
|
|
|
--- Kandidaten des aktuellen Frames. Wird wiederverwendet statt jedes Frame neu
|
|
--- angelegt, damit der GC bei Dauerbetrieb nichts zu tun bekommt.
|
|
local candidates = {}
|
|
|
|
--- Position und Richtung der Lampe eines Peds.
|
|
---
|
|
--- Die Offsets von GetPedBoneCoords sind laut Native-Doku "relative to the bone's
|
|
--- rotation" - zwei bone-relative Punkte ergeben also die echte Blickrichtung
|
|
--- inklusive Pitch. Genau das wird beim Tauchen gebraucht: der Ped liegt waagerecht
|
|
--- im Wasser, GetEntityForwardVector würde die Lampe stur horizontal leuchten lassen.
|
|
local function getLampVectors(ped)
|
|
local offset = config.lampOffset
|
|
local direction = config.lampDirection
|
|
|
|
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)
|
|
|
|
local delta = ahead - from
|
|
local length = #delta
|
|
|
|
if length <= 0 then return end
|
|
|
|
return from, delta / length
|
|
end
|
|
|
|
local function drawLamp(ped)
|
|
local from, direction = getLampVectors(ped)
|
|
|
|
if not from then return end
|
|
|
|
local colour = config.lampColour
|
|
|
|
if config.lampShadows then
|
|
DrawSpotLightWithShadow(from.x, from.y, from.z, direction.x, direction.y, direction.z,
|
|
colour[1], colour[2], colour[3],
|
|
config.lampDistance, config.lampBrightness, config.lampRoundness,
|
|
config.lampRadius, config.lampFalloff, 0)
|
|
else
|
|
DrawSpotLight(from.x, from.y, from.z, direction.x, direction.y, direction.z,
|
|
colour[1], colour[2], colour[3],
|
|
config.lampDistance, config.lampBrightness, config.lampRoundness,
|
|
config.lampRadius, config.lampFalloff)
|
|
end
|
|
end
|
|
|
|
CreateThread(function()
|
|
while true do
|
|
local players = GetActivePlayers()
|
|
local myCoords = GetEntityCoords(cache.ped)
|
|
local count = 0
|
|
|
|
for i = 1, #players do
|
|
local player = players[i]
|
|
local state = Player(GetPlayerServerId(player)).state
|
|
|
|
if state and state[STATE_KEY] then
|
|
local ped = GetPlayerPed(player)
|
|
|
|
if ped ~= 0 and DoesEntityExist(ped) then
|
|
local distance = #(myCoords - GetEntityCoords(ped))
|
|
|
|
if distance < config.lampDrawDistance then
|
|
count += 1
|
|
local entry = candidates[count]
|
|
|
|
if entry then
|
|
entry.ped, entry.distance = ped, distance
|
|
else
|
|
candidates[count] = { ped = ped, distance = distance }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Reste des letzten Frames abschneiden, sonst sortiert table.sort veraltete
|
|
-- Einträge mit und ein alter, näherer Eintrag verdrängt einen echten.
|
|
for i = #candidates, count + 1, -1 do
|
|
candidates[i] = nil
|
|
end
|
|
|
|
-- Nur sortieren wenn tatsächlich mehr Lampen da sind als gezeichnet werden
|
|
-- dürfen. DrawSpotLightWithShadow ist teuer, in einer vollen Höhle sonst
|
|
-- der erstbeste Frame-Killer.
|
|
if count > config.lampMaxLights then
|
|
table.sort(candidates, function(a, b) return a.distance < b.distance end)
|
|
end
|
|
|
|
for i = 1, math.min(count, config.lampMaxLights) do
|
|
drawLamp(candidates[i].ped)
|
|
end
|
|
|
|
Wait(count > 0 and 0 or 300)
|
|
end
|
|
end)
|