feat: Add metro transit, gadgets, shop, social apps, and traffic models checkpoint
This commit is contained in:
1 parent
caa42b84ed
commit
74e2963a12
79 files changed
+527962
-496
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -2,6 +2,15 @@ using Ananta.SDK.Network;
|
||||
|
||||
namespace Ananta.Server.Gameplay.Traffic;
|
||||
|
||||
/// <summary>One lane-progress sample for the batched Aether lane sync.</summary>
|
||||
public readonly record struct AetherLaneSample(ulong EntityId, int LaneHandle, float Distance, byte Status);
|
||||
|
||||
/// <summary>One Aether vehicle spawn sample for the batch form.</summary>
|
||||
public readonly record struct AetherVehicleInit(
|
||||
ulong EntityId, uint ConfigId, uint ColorPartId, int LaneHandle, float Distance,
|
||||
float Speed, double Timestamp, float X, float Y, float Z, float Yaw,
|
||||
List<(float X, float Y, float Z)>? CruisePoints = null);
|
||||
|
||||
public interface ITrafficVehicleDriver
|
||||
{
|
||||
Task<(bool Ok, ulong EntityId)> SpawnTrafficVehicleAsync(
|
||||
@@ -13,6 +22,44 @@ public interface ITrafficVehicleDriver
|
||||
Task SendVehicleMoveAsync(
|
||||
TcpSession session, ulong entityId, float x, float y, float z, float yaw, float vx, float vz);
|
||||
|
||||
/// <summary>
|
||||
/// Native client-driven spawn: registers an Aether vehicle on the client's own zone graph.
|
||||
/// The client simulates/renders it from lane handle + distance; no scene entity is created.
|
||||
/// </summary>
|
||||
Task SpawnAetherVehicleAsync(
|
||||
TcpSession session, ulong entityId, uint configId, uint colorPartId, int laneHandle,
|
||||
float distanceAlongLane, float speed, double timestamp, float x, float y, float z, float yaw);
|
||||
|
||||
/// <summary>
|
||||
/// Spawns Aether vehicles on the client's zone graph. The 4229938 client has NO batch
|
||||
/// AddDatas method — the implementer must send one SyncAetherAIVehicleAddData (68916691)
|
||||
/// notify per vehicle.
|
||||
/// </summary>
|
||||
Task SpawnAetherVehiclesAsync(
|
||||
TcpSession session, IReadOnlyList<AetherVehicleInit> vehicles);
|
||||
|
||||
/// <summary>Binds a driver/passenger NPC into an Aether vehicle seat (SyncAetherAIVehicleNpcAdd).</summary>
|
||||
Task SpawnAetherVehicleNpcAsync(
|
||||
TcpSession session, ulong npcId, uint npcFormworkId, ulong vehicleId, byte seatIndex);
|
||||
|
||||
/// <summary>Removes an Aether vehicle NPC (SyncAetherAINpcRemove 68332284 — the only Aether NPC remove the client has).</summary>
|
||||
Task RemoveAetherVehicleNpcAsync(TcpSession session, ulong npcId);
|
||||
|
||||
/// <summary>Pushes one intersection period change (SyncAetherAIIntersectionUpdateData); the id is the InstanceId previously sent in the init.</summary>
|
||||
Task SendAetherIntersectionUpdateAsync(
|
||||
TcpSession session, ulong intersectionInstanceId, int currentPeriod, int nextPeriod, byte state);
|
||||
|
||||
/// <summary>
|
||||
/// Batched lane-progress sync (one packet per session per tick); the client interpolates
|
||||
/// between samples using its 0.35s delay buffer.
|
||||
/// </summary>
|
||||
Task SendAetherLaneDatasAsync(
|
||||
TcpSession session, List<AetherLaneSample> samples, double timestamp);
|
||||
|
||||
/// <summary>Removes an Aether vehicle from the client's traffic simulation.</summary>
|
||||
Task RemoveAetherVehicleAsync(
|
||||
TcpSession session, ulong entityId);
|
||||
|
||||
bool IsVehiclePlayerControlled(ulong entityId);
|
||||
|
||||
(bool HasPlayer, float X, float Y, float Z, float Yaw, uint RaidId) GetPlayerPosition(TcpSession session);
|
||||
|
||||
@@ -8,6 +8,100 @@ public sealed class TrafficSignalFile
|
||||
{
|
||||
[JsonPropertyName("lights")]
|
||||
public List<TrafficLightEntry> Lights { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("intersections")]
|
||||
public List<TrafficIntersectionEntry> Intersections { get; set; } = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// City zone-graph intersection mapping (InterZones.json): for every signalized city
|
||||
/// intersection (id from the world TrafficLights dump) the indexes of its zones in the
|
||||
/// city ZoneGraphStorage zones array. The client's AetherIntersectionManager resolves each
|
||||
/// SyncAetherAIInitDatas entry by ZoneIndex against its baked StaticIntersectionData blob,
|
||||
/// so these are the values ClientTrafficIntersectionInitInfo.ZoneIndex must carry.
|
||||
/// Generated from readable_world_dump 03_ZONEGRAPHS vfc_1286_e108 + 04_WORLD_JSON vfc_1286_e104.
|
||||
/// </summary>
|
||||
public sealed class IntersectionZoneFile
|
||||
{
|
||||
[JsonPropertyName("source")]
|
||||
public string Source { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("intersections")]
|
||||
public List<IntersectionZoneEntry> Intersections { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class IntersectionZoneEntry
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public uint Id { get; set; }
|
||||
|
||||
[JsonPropertyName("zones")]
|
||||
public List<int> Zones { get; set; } = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The client's baked StaticIntersectionData.json (recovered from the L50 VFS, artifact 111):
|
||||
/// the authoritative intersection zones for the city raid — one entry per signalized
|
||||
/// intersection, with its real zone-graph ZoneIndex, position, traffic-light bindings and
|
||||
/// per-period control tables. This is exactly what the client's AetherIntersectionManager
|
||||
/// resolves against, so the ambient init must use these ZoneIndexes.
|
||||
/// </summary>
|
||||
public sealed class StaticIntersectionFile
|
||||
{
|
||||
[JsonPropertyName("ZoneInfos")]
|
||||
public List<StaticZoneInfoEntry> ZoneInfos { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class StaticZoneInfoEntry
|
||||
{
|
||||
[JsonPropertyName("ZoneIndex")]
|
||||
public int ZoneIndex { get; set; }
|
||||
|
||||
[JsonPropertyName("Position")]
|
||||
public List<float> Position { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("TrafficLights")]
|
||||
public List<StaticTrafficLightEntry> TrafficLights { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("TrafficLightPeriodControls")]
|
||||
public List<StaticPeriodRowEntry> TrafficLightPeriodControls { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class StaticTrafficLightEntry
|
||||
{
|
||||
[JsonPropertyName("Index")]
|
||||
public int Index { get; set; }
|
||||
|
||||
[JsonPropertyName("CrosswalkControlIndex")]
|
||||
public int CrosswalkControlIndex { get; set; }
|
||||
|
||||
[JsonPropertyName("VehicleControlIndex")]
|
||||
public int VehicleControlIndex { get; set; }
|
||||
}
|
||||
|
||||
public sealed class StaticPeriodRowEntry
|
||||
{
|
||||
[JsonPropertyName("TrafficLightControls")]
|
||||
public List<StaticLightControlEntry> TrafficLightControls { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("VehicleLanesOpen")]
|
||||
public List<int> VehicleLanesOpen { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class StaticLightControlEntry
|
||||
{
|
||||
[JsonPropertyName("TrafficLightStateFlags")]
|
||||
public int TrafficLightStateFlags { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>One signalized intersection: its id and the zebra (stop-line group) indexes it controls.</summary>
|
||||
public sealed class TrafficIntersectionEntry
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public uint Id { get; set; }
|
||||
|
||||
[JsonPropertyName("zebras")]
|
||||
public List<uint> Zebras { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class TrafficLightEntry
|
||||
|
||||
Reference in new issue
Block a user