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)