feat(traffic): implement autonomous City Traffic Engine and Living Urban Crowd Engine from CBT dump

This commit is contained in:
CAtlas0784 committed 2026-09-18 14:19:52 +07:00
1 parent f2a36fe188
commit 67bdbae24b
17 files changed
+18759

No files matched your search

@@ -0,0 +1,73 @@
using Ananta.SDK.Network;
using Ananta.SDK.Serialization;
using Ananta.Server.Gameplay.Crowd;
using Ananta.Server.Gameplay.Traffic;
using Ananta.Server.Protocol.Client4229938;
using Ananta.Server.RpcTypes.Client4229938;
using SceneMethods = Ananta.Server.RpcTypes.Client4229938.Methods.GameScene;
namespace Ananta.Server.Handlers.Game;
internal sealed class TrafficAndCrowdDriver : ITrafficVehicleDriver, IUrbanCrowdDriver
{
public static TrafficAndCrowdDriver Instance { get; } = new();
public async Task<(bool Ok, ulong EntityId)> SpawnTrafficVehicleAsync(
TcpSession session, uint configId, float x, float y, float z, float yaw)
{
var result = await GameRouter.SpawnDirectAsync(
session, configId, new Vec3(x, y, z), yaw, rightOffset: 0f, sourceType: 2, reason: "city-traffic");
return (result.Ok, result.EntityId);
}
public async Task DestroyTrafficVehicleAsync(TcpSession session, ulong entityId)
{
await GameRouter.DestroyDirectAsync(session, entityId, "traffic-despawn");
}
public async Task SendVehicleMoveAsync(
TcpSession session, ulong entityId, float x, float y, float z, float yaw, float vx, float vz)
{
var moveData = new SceneMethods.RaidVehicleSyncData
{
Id = entityId,
Position = new SceneMethods.UxVector3(x, y, z),
FacingDirection = yaw,
EulerAngles = new SceneMethods.UxVector3(0f, yaw, 0f),
Velocity = new SceneMethods.UxVector3(vx, 0f, vz),
Bits = [],
MoveToken = 0,
};
await session.NotifyAsync(MethodId.SyncVehicleMove, UxSerializer.Serialize(moveData), CancellationToken.None);
GameRouter.TrackVehicleMove(entityId, x, y, z, yaw);
}
public bool IsVehiclePlayerControlled(ulong entityId)
{
return GameRouter.TryGetSummoned(entityId, out var summoned) && summoned?.ControllerPid != 0;
}
public (bool HasPlayer, float X, float Y, float Z, float Yaw, uint RaidId) GetPlayerPosition(TcpSession session)
{
var state = GameRouter.GetStateIfExists(session);
if (state is null)
return (false, 0, 0, 0, 0, 0);
lock (state.SyncRoot)
{
if (!state.Ready || !state.HasLastReportedPlayerTransform)
return (false, 0, 0, 0, 0, 0);
var pos = state.LastReportedPlayerPosition;
var rot = state.LastReportedPlayerRotation;
return (true, pos.X, pos.Y, pos.Z, rot.Y, state.ActiveRaidId);
}
}
public async Task<(bool Ok, ulong[] EntityIds)> SpawnCrowdPedestriansAsync(
TcpSession session, uint npcFormworkId, uint poiActionId, float x, float y, float z, float facing)
{
var result = await GameRouter.SpawnStaticNpcAtAsync(session, npcFormworkId, poiActionId, x, y, z, facing);
return (result.Ok, result.Ids);
}
}