97 lines
5.9 KiB
C#
97 lines
5.9 KiB
C#
using Ananta.SDK.Network;
|
|
using Ananta.SDK.Serialization;
|
|
using Ananta.Server.Protocol.Client4229938;
|
|
|
|
namespace Ananta.Server.Handlers.Game;
|
|
|
|
internal sealed partial class GameRouter
|
|
{
|
|
// Read-only boarding target audit. Reapplying the same native target had no
|
|
// effect in the user's recording; do not keep resetting EntrySystem.Setup.
|
|
private static async Task PreparePoliceOfficerBoarding4229938(
|
|
TcpSession session, PoliceRuntime4229938 runtime, ulong owner)
|
|
{
|
|
if (owner == 0 || runtime.PendingBoarding is not { } passenger
|
|
|| passenger.Seat is not (2 or 3)
|
|
|| !runtime.Npcs.TryGetValue(passenger.Agent, out var npc) || npc.Template != 4065053)
|
|
return;
|
|
var vehicles = GetVehicleRuntimeState(session);
|
|
lock (vehicles.SyncRoot)
|
|
if (!vehicles.Vehicles.TryGetValue(passenger.Vehicle, out var car) || car.ConfigId != 81004027)
|
|
return;
|
|
if (!session.Items.TryGetValue(PoliceGateSessionKey4229938, out var gateValue)
|
|
|| gateValue is not TcpSession gate || gate.ClosedToken.IsCancellationRequested) return;
|
|
|
|
var script = $$"""
|
|
local ok, err = pcall(function()
|
|
local prefix = '[LIXI-BOARD] officer-audit-v3 '
|
|
-- These are registered by ReflectionUtils.RegisterToLua in the
|
|
-- client (0x148BB780). C# public does NOT imply direct Lua export.
|
|
local get = ReflectionGetProperty
|
|
local call = ReflectionCallMethod
|
|
if type(get) ~= 'function' or type(call) ~= 'function' then
|
|
print_error(prefix .. 'skipped: reflection bridge unavailable'); return
|
|
end
|
|
local vehicleType = 'LX6.Drive.BaseVehicle'
|
|
local moduleType = 'LX6.Drive.VehicleInteractModule'
|
|
local actionType = 'LX6.Drive.Interact.VehicleInteractAction'
|
|
local officerType = 'LX6.Drive.Interact.PlayerEscortToVehicleAction'
|
|
local owner = ulong.new({{(uint)owner}}, {{owner >> 32}})
|
|
local player = gCS.SceneDataMgr.GetUnit(owner)
|
|
local vehicle = LX6.Drive.DriveManager.Instance:GetBaseVehicle(ulong.new({{(uint)passenger.Vehicle}}, {{passenger.Vehicle >> 32}}))
|
|
if not player or not vehicle then print_error(prefix .. 'skipped: unit unavailable'); return end
|
|
local module = get(vehicleType,'interactModule',vehicle)
|
|
if not module then print_error(prefix .. 'skipped: no interact module'); return end
|
|
local action = call(moduleType,'GetUnitCurrentAction',module,owner)
|
|
if not action then print_error(prefix .. 'skipped: no officer vehicle action'); return end
|
|
-- VehicleInteractType.PoliceEscortToVehicle=10. A late gate
|
|
-- message must never repoint driving, alighting or other actions.
|
|
local kind = get(actionType,'interactType',action)
|
|
if kind ~= 10 and tostring(kind) ~= 'PoliceEscortToVehicle' then
|
|
print_error(prefix .. 'skipped: action=' .. tostring(kind)); return
|
|
end
|
|
if call(officerType,'GetInteractSeat',action) ~= {{passenger.Seat}} then
|
|
print_error(prefix .. 'skipped: seat changed'); return
|
|
end
|
|
local phase = call(actionType,'GetActionState',action)
|
|
if phase ~= 1 and phase ~= 2 and tostring(phase) ~= 'Pending' and tostring(phase) ~= 'Running' then
|
|
print_error(prefix .. 'skipped: action already ending'); return
|
|
end
|
|
-- VehicleInteractPointTagConfig: 41..44=EscortNpc_Police_0..3.
|
|
-- 51..54 belong to the NPC and must not be used for the officer.
|
|
local tag = 41 + {{passenger.Seat}}
|
|
local point = call(moduleType,'GetInteractPointIndexByTag',module,tag)
|
|
if point == nil or point < 0 then print_error(prefix .. 'skipped: no police point'); return end
|
|
local target = call(moduleType,'GetInteractWorldPos',module,point)
|
|
local p = player.Position -- UXVector3 uses uppercase fields.
|
|
local dx, dz = target.x-p.X, target.z-p.Z
|
|
local distance = math.sqrt(dx*dx + dz*dz)
|
|
-- This refresh is for the nearby door, not a new path through
|
|
-- the vehicle from the opposite side or a stale scene request.
|
|
if distance ~= distance or distance > 1.5 or math.abs(target.y-p.Y) > 1 then
|
|
print_error(prefix .. 'skipped: target too far distance=' .. tostring(distance)); return
|
|
end
|
|
local trigger = get('LX6.Drive.Interact.VehicleTriggerInteractAction','interactTrigger',action)
|
|
local oldTag = call(moduleType,'GetTriggerMapToInteractPointTag',module,trigger)
|
|
-- Log confirmed oldTag==policeTag==43: resetting this same
|
|
-- destination did not fix the visual door mismatch. Observe only.
|
|
print_error(prefix .. 'observed seat={{passenger.Seat}} oldTag=' .. tostring(oldTag)
|
|
.. ' policeTag=' .. tostring(tag) .. ' distance=' .. tostring(distance))
|
|
end)
|
|
if not ok then print_error('[LIXI-BOARD] officer-audit-v3 failed: ' .. tostring(err)) end
|
|
""";
|
|
try
|
|
{
|
|
await gate.NotifyAsync(MethodId.SyncDoToLuaMaster,
|
|
new UxWriter().UxString(script).ToArray(), session.ClosedToken);
|
|
}
|
|
catch (OperationCanceledException) when (session.ClosedToken.IsCancellationRequested) { throw; }
|
|
catch (Exception ex)
|
|
{
|
|
// Keep the original native boarding response available if the gate
|
|
// is absent; this helper must never strand a reserved passenger.
|
|
session.Log.Warn($"[LIXI-BOARD] officer entry refresh unavailable: {ex.GetType().Name}");
|
|
}
|
|
}
|
|
}
|