using Ananta.SDK.Network; using Ananta.SDK.Serialization; using Ananta.Server.Protocol.Client4229938; namespace Ananta.Server.Handlers.Game; internal sealed partial class GameRouter { // Diagnostic only. Do not change seat attachments, transforms, authority or // animation state here. Short, bounded samples identify visual/root mismatch. private static async Task TracePoliceVehicleAnimation4229938(TcpSession session, uint child, ulong agent, ulong vehicle, int seat, bool boarding) { try { if (!session.Items.TryGetValue(PoliceGateSessionKey4229938, out var value) || value is not TcpSession gate) { session.Log.Warn("[LIXI-ANIM] diagnostic skipped: gate session unavailable"); return; } static string U64(ulong id) => FormattableString.Invariant($"ulong.new({(uint)id}, {id >> 32})"); for (int sample = 0; sample < 7; sample++) { if (sample > 0) await Task.Delay(1000, session.ClosedToken); if (gate.ClosedToken.IsCancellationRequested || !PoliceRuntimes.TryGetValue(session, out var runtime)) return; await runtime.Gate.WaitAsync(session.ClosedToken); bool active; try { active = runtime.Child == child && runtime.Agent == agent; } finally { runtime.Gate.Release(); } if (!active) return; var owner = GetStateIfExists(session)?.ActiveSpiritUnitId ?? 0; var script = $$""" local ok, err = pcall(function() local prefix = '[LIXI-ANIM] {{(boarding ? "board" : "alight")}} sample={{sample}} agent={{agent}} vehicle={{vehicle}} seat={{seat}} ' local npc = gCS.SceneDataMgr.GetUnit({{U64(agent)}}) local car = LX6.Drive.DriveManager.Instance:GetBaseVehicle({{U64(vehicle)}}) -- Normal print can be filtered out of Player.log. The -- exported logger used by existing Lua diagnostics is -- intentionally used here; this is not a gameplay error. if not npc or not car then print_error(prefix .. 'unit/vehicle unavailable'); return end print_error(prefix .. 'npcWorld=' .. tostring(npc.Position) .. ' npcLocal=' .. tostring(npc.LocalPosition) .. ' npcYaw=' .. tostring(npc.WorldEulerY) .. ' vehicleWorld=' .. tostring(car.Position) .. ' vehicleYaw=' .. tostring(car.EulerY)) if {{(boarding ? "true" : "false")}} and ReflectionGetProperty and ReflectionCallMethod then local traced, detail = pcall(function() local player = gCS.SceneDataMgr.GetUnit({{U64(owner)}}) if not player or not player.MeshRoot then return end local m = ReflectionGetProperty('LX6.Drive.BaseVehicle','interactModule',car) if not m then return end local idx = ReflectionCallMethod('LX6.Drive.VehicleInteractModule','GetInteractPointIndexByTag',m,41+{{seat}}) if not idx or idx < 0 then return end local target = ReflectionCallMethod('LX6.Drive.VehicleInteractModule','GetInteractWorldPos',m,idx) local angles = ReflectionCallMethod('LX6.Drive.VehicleInteractModule','GetInteractEularOffset',m,idx) local p = player.Position local mesh = player.MeshRoot print_error(prefix .. 'officer-v3 player=' .. tostring(p) .. ' rootYaw=' .. tostring(player.WorldEulerY) .. ' meshWorld=' .. tostring(mesh.position) .. ' meshYaw=' .. tostring(mesh.eulerAngles.y) .. ' meshLocal=' .. tostring(mesh.localPosition) .. ' target=' .. tostring(target) .. ' targetYaw=' .. tostring(car.EulerY+angles.y) .. ' deltaXYZ=' .. tostring(target.x-p.X) .. ',' .. tostring(target.y-p.Y) .. ',' .. tostring(target.z-p.Z)) end) if not traced then print_error(prefix .. 'officer-v3 unavailable: ' .. tostring(detail)) end end if {{sample}} == 0 then local count = 0 local function walk(t, path, depth) if depth > 6 or count >= 256 then return end count = count + 1 local name = string.lower(t.name) if string.find(name, 'seat', 1, true) or string.find(name, 'escort', 1, true) or string.find(name, 'door', 1, true) or string.find(name, 'gangster', 1, true) then print_error(prefix .. 'anchor=' .. path .. ' world=' .. tostring(t.position) .. ' local=' .. tostring(t.localPosition) .. ' angles=' .. tostring(t.eulerAngles)) end for i = 0, t.childCount - 1 do local c = t:GetChild(i) walk(c, path .. '/' .. c.name, depth + 1) end end walk(car.gameObject.transform, car.gameObject.name, 0) end end) if not ok then print_error('[LIXI-ANIM] diagnostic unavailable: ' .. tostring(err)) end """; await gate.NotifyAsync(MethodId.SyncDoToLuaMaster, new UxWriter().UxString(script).ToArray(), session.ClosedToken); if (sample == 0) session.Log.Info($"[LIXI-ANIM] trace-v2 sent agent={agent} vehicle={vehicle} seat={seat} boarding={boarding}; read Player.log for samples (diagnostic severity only)"); } } catch (OperationCanceledException) { } catch (Exception ex) { session.Log.Warn($"[LIXI-ANIM] diagnostic stopped: {ex.GetType().Name}"); } } }