feat: Add metro transit, gadgets, shop, social apps, and traffic models checkpoint

This commit is contained in:
CAtlas0784 committed 2026-10-29 01:55:01 +07:00
1 parent caa42b84ed
commit 74e2963a12
79 files changed
+527962 -496

No files matched your search

@@ -6,19 +6,21 @@ namespace Ananta.Server.RpcTypes.Client4229938.Methods.Game;
/// <summary>
/// Metro/Train runtime data structures for CBT 4229938.
/// Matching ReadMetroClientInfo and ReadMetroCarriageGadgetInfos from GameAssembly.
/// NOTE: UxSerializer walks public FIELDS in declaration order — keep these as fields, not
/// properties, or the wire payload becomes empty objects.
/// </summary>
[UxContract]
public sealed class MetroClientInfo
{
public int Id { get; set; }
public uint LineId { get; set; }
public float ElapsedTime { get; set; }
public bool IsFinalTrain { get; set; }
public int Id;
public uint LineId;
public float ElapsedTime;
public bool IsFinalTrain;
}
[UxContract]
public sealed class MetroCarriageGadgetInfos
{
public List<ulong> InnerGadgetIds { get; set; } = [];
public List<ulong> OuterGadgetIds { get; set; } = [];
public List<ulong> InnerGadgetIds = [];
public List<ulong> OuterGadgetIds = [];
}
@@ -0,0 +1,83 @@
using Ananta.SDK.Serialization;
using Auto = Ananta.Server.RpcTypes.Client4229938.Auto;
namespace Ananta.Server.RpcTypes.Client4229938.Methods.Game;
/// <summary>
/// Phone / contacts-app wire contracts for build 4229938. The "NETWORK OF CONTACTS" list is
/// push-only: the login SyncPlayerInfo snapshot carries PlayerPhoneInfo, and
/// AddSpiritPhoneInfos (64199774) is the incremental per-character refresh — the client has
/// no C2S "fetch contacts". Writers mirrored from RPCSerializeAuto.lua.
/// </summary>
/// <summary>Notify AddSpiritPhoneInfos(uint spiritId, PhoneInfos phoneInfos) — inline wrapper + complex payload.</summary>
[UxContract(Inline = true)]
internal class AddSpiritPhoneInfos4229938
{
public uint spiritId;
public Auto.PhoneInfos phoneInfos = new();
}
/// <summary>Ask AskPhoneAddContact(uint spiritid, string phonenumber, string contactname).</summary>
[UxContract(Inline = true)]
internal class AskPhoneAddContact4229938
{
public uint spiritid;
public string phonenumber = string.Empty;
public string contactname = string.Empty;
}
/// <summary>Ask AskPhoneEditContact(uint spiritid, string oldphonenumber, string newphonenumber, string contactname).</summary>
[UxContract(Inline = true)]
internal class AskPhoneEditContact4229938
{
public uint spiritid;
public string oldphonenumber = string.Empty;
public string newphonenumber = string.Empty;
public string contactname = string.Empty;
}
/// <summary>Ask AskPhoneDeleteContact(uint spiritid, string phonenumber).</summary>
[UxContract(Inline = true)]
internal class AskPhoneDeleteContact4229938
{
public uint spiritid;
public string phonenumber = string.Empty;
}
/// <summary>Ask AskPhoneAddContactGroup(uint spiritid, string groupname).</summary>
[UxContract(Inline = true)]
internal class AskPhoneAddContactGroup4229938
{
public uint spiritid;
public string groupname = string.Empty;
}
/// <summary>Ask AskPhoneEditContactGroup(uint spiritid, uint groupindex, string groupname).</summary>
[UxContract(Inline = true)]
internal class AskPhoneEditContactGroup4229938
{
public uint spiritid;
public uint groupindex;
public string groupname = string.Empty;
}
/// <summary>Ask AskPhoneDeleteContactGroup(uint spiritid, uint groupindex).</summary>
[UxContract(Inline = true)]
internal class AskPhoneDeleteContactGroup4229938
{
public uint spiritid;
public uint groupindex;
}
/// <summary>Ask AskPhoneAddContactToGroup(uint spiritid, uint groupindex, List&lt;string&gt; phonenumberlist).</summary>
[UxContract(Inline = true)]
internal class AskPhoneAddContactToGroup4229938
{
public uint spiritid;
public uint groupindex;
[UxCollection(Count = UxCountEncoding.Int7)]
public List<string> phonenumberlist = [];
}
@@ -0,0 +1,127 @@
using Ananta.SDK.Serialization;
namespace Ananta.Server.RpcTypes.Client4229938.Methods.Game;
/// <summary>
/// NPC shop wire contracts for build 4229938, ported from the PrivateServer1 (Drmk) pack.
/// The tuning/4S shop menus render exactly what the server pushes via
/// SyncFullCommodityInfos; purchases are client-validated against that inventory.
/// </summary>
/// <summary>Args of AskNpcShop (63563263, Invoke): {shopid:u32}.</summary>
[UxContract(Inline = true)]
internal sealed class AskNpcShop
{
public uint shopid;
}
/// <summary>S2C SyncFullCommodityInfos (64769566): full shop inventory refresh.</summary>
[UxContract(Inline = true)]
internal sealed class SyncFullCommodityInfos
{
public uint shopId;
public List<ShopCommodityItem> infos = [];
}
/// <summary>Args of AskNpcShopCommodityInfo (63699253, Invoke): {shopid:u32}.</summary>
[UxContract(Inline = true)]
internal sealed class AskNpcShopCommodityInfo
{
public uint shopid;
}
/// <summary>Args of AskVehicleShopSpawnVehicle (63497070, Invoke): {shopid, vehicleid, isbind}.</summary>
[UxContract(Inline = true)]
internal sealed class AskVehicleShopSpawnVehicle
{
public uint shopid;
public uint vehicleid;
public bool isbind;
}
/// <summary>Args of AskBuyModifyParts (63701165, Invoke → void): dict is WriteDict7Bit.</summary>
[UxContract(Inline = true)]
internal sealed class AskBuyModifyParts
{
public uint shopid;
public uint vehicleid;
[UxCollection(Count = UxCountEncoding.Int7)]
public Dictionary<uint, uint> commodityiddict = [];
public List<uint> removedparttypes = [];
}
/// <summary>Args of AskBuyCommodities (63614427, Invoke → void): the 4S purchase path.</summary>
[UxContract(Inline = true)]
internal sealed class AskBuyCommodities
{
public uint shopid;
[UxCollection(Count = UxCountEncoding.Int7)]
public Dictionary<uint, uint> commodityiddict = [];
}
/// <summary>Args of AskBuyCommodity (63970007, Invoke → void): tuning-menu purchase.</summary>
[UxContract(Inline = true)]
internal sealed class AskBuyCommodity
{
public uint shopid;
public uint commodityid;
public uint count;
}
/// <summary>Args of AskVehicleShopDestroyParking (63613647, Invoke → void).</summary>
[UxContract(Inline = true)]
internal sealed class AskVehicleShopDestroyParking
{
public uint shopid;
}
/// <summary>Return of AskVehicleShopSpawnVehicle: {vehicleUid:u64}.</summary>
[UxContract(Inline = true)]
internal sealed class AskVehicleShopSpawnVehicleResult
{
public ulong vehicleUid;
}
/// <summary>One shop commodity (RPCDeserializeAuto.lua Reader[366]) — field order is wire order.</summary>
[UxContract]
internal sealed class ShopCommodityItem
{
public uint TemplateId;
public int Count;
public uint RefreshTime;
public byte Status;
public uint Discount;
public uint DiscountPrice;
public uint MaxBuyCount;
public uint DailyDiscount;
// Lua WriteDict7Bit (biased 7-bit count), NOT Int32 — an Int32 zero-count here
// desyncs the whole item list client-side (ShopManager.lua crash).
[UxCollection(Count = UxCountEncoding.Int7)]
public Dictionary<uint, uint> CommodityBadgeDiscountDict = [];
public int BlackMarketPriceModifier;
}
/// <summary>Shop refresh state (RPCDeserializeAuto.lua Reader[328]).</summary>
[UxContract(Inline = true)]
internal sealed class ShopRefreshState
{
public uint SellRefreshTime;
public uint BuybackRefreshTime;
public uint ManualRefreshCountResetTime;
public uint SellManualRefreshCount;
public uint BuybackManualRefreshCount;
public uint SellRotationIndex;
public uint BuybackRotationIndex;
public uint SellRefreshPlusCount;
public uint BuybackRefreshPlusCount;
}
/// <summary>Return of AskNpcShopCommodityInfo (Reader[638]): the full NPC shop inventory.</summary>
[UxContract]
internal sealed class NpcShopCommodityInfo
{
public uint CurrentDiscount;
public List<ShopCommodityItem> CommodityInfoList = [];
public List<ShopCommodityItem> BuybackCommodityInfoList = [];
public ShopRefreshState RefreshState = new();
}
@@ -0,0 +1,175 @@
using Ananta.SDK.Serialization;
using Auto = Ananta.Server.RpcTypes.Client4229938.Auto;
namespace Ananta.Server.RpcTypes.Client4229938.Methods.Game;
[UxContract]
internal sealed class PostPlayerCommentClientInfo4229938
{
public string Comment = string.Empty;
public uint CommentId;
public bool IsFinish;
}
[UxContract]
internal sealed class PostSimpleClientInfo4229938
{
public uint Id;
public byte PostType;
public uint PostConfigId;
public uint Date;
public string ImageUrl = string.Empty;
public bool Approved;
public string Title = string.Empty;
public uint Likes;
public bool Liked;
public List<uint> LikeNpcs = [];
public List<uint> Comments = [];
public List<PostPlayerCommentClientInfo4229938> PlayerComments = [];
public bool IsRead;
public bool HasNewLike;
public uint AcquireCfgId;
public uint ActivityCfgId;
public bool IsStory;
public bool IsPinStory;
}
[UxContract]
internal sealed class SimpleUnreadMessage4229938
{
public uint PostId;
public uint CommentId;
public int MessageType;
}
[UxContract]
internal sealed class EmojiData4229938
{
public string Id = string.Empty;
public uint Count;
}
[UxContract]
internal sealed class AskMomentsPostSimpleInfos4229938
{
public uint lastId;
public byte postType;
}
[UxContract]
internal sealed class AskMomentsPostInfos4229938
{
[UxCollection(Count = UxCountEncoding.Int7)]
public List<uint> postIds = [];
}
[UxContract]
internal sealed class AskMomentsPostInfosInt324229938
{
[UxCollection(Count = UxCountEncoding.Int32)]
public List<uint> postIds = [];
}
[UxContract]
internal sealed class AskMomentsMarkRead4229938
{
[UxCollection(Count = UxCountEncoding.Int7)]
public List<uint> postIds = [];
}
[UxContract]
internal sealed class AskMomentsMarkReadInt324229938
{
[UxCollection(Count = UxCountEncoding.Int32)]
public List<uint> postIds = [];
}
[UxContract]
internal sealed class AskMomentsLikePost4229938
{
public uint postId;
public bool like;
}
[UxContract]
internal sealed class AskMomentsSendCommentWithId4229938
{
public uint postId;
public uint commentId;
}
[UxContract]
internal sealed class AskMomentsTapPostWithCount4229938
{
public uint postId;
[UxCollection(Count = UxCountEncoding.Int7)]
public List<EmojiData4229938> emojiList = [];
}
[UxContract]
internal sealed class AskMomentsTapPostWithCountInt324229938
{
public uint postId;
[UxCollection(Count = UxCountEncoding.Int32)]
public List<EmojiData4229938> emojiList = [];
}
[UxContract]
internal sealed class NpcTimeTableScheduleInfo4229938
{
public uint ActivityId;
public int StartDaySecond;
[UxObject(Encoding = UxObjectEncoding.Struct)]
public Auto.UXVector3 Position = new();
public int SpoonAgentId;
public int EndDaySecond;
public uint RaidId;
}
[UxContract]
internal sealed class NpcTimeTableInfo4229938
{
public NpcTimeTableScheduleInfo4229938? Schedule0;
public NpcTimeTableScheduleInfo4229938? Schedule1;
public NpcTimeTableScheduleInfo4229938? Schedule2;
public NpcTimeTableScheduleInfo4229938? Schedule3;
public NpcTimeTableScheduleInfo4229938? Schedule4;
public int CurrentSpoonAgentId;
[UxObject(Encoding = UxObjectEncoding.Struct)]
public Auto.UXVector3 SpoonPosition = new();
public NpcTimeTableScheduleInfo4229938? TempSchedule;
public bool IsTempScheduleOnly;
public long RefreshDay;
}
[UxContract]
internal sealed class SyncFavorNpcTimeTableInfos4229938
{
[UxCollection(Count = UxCountEncoding.Int7)]
public Dictionary<uint, NpcTimeTableInfo4229938> timeTableInfos = new();
}
@@ -0,0 +1,205 @@
using Ananta.SDK.Serialization;
namespace Ananta.Server.RpcTypes.Client4229938.Methods.GameScene;
/// <summary>
/// Aether (client-driven) traffic wire contracts for build 4229938, mirrored from the
/// client's UX.Game IL2CPP dump: ClientVehicleInitData, ClientVehicleLaneData,
/// ClientVehicleLaneChangeData and their notify wrappers. The client simulates and renders
/// these vehicles along its own ZoneGraphStorage; the server only supplies lane handles,
/// distances and speeds, and the client interpolates with its 0.35s delay buffer.
/// </summary>
/// <summary>ClientVehicleLaneData (struct): one vehicle's progress on a zone-graph lane.</summary>
[UxContract(Inline = true)]
internal struct ClientVehicleLaneData4229938
{
public ulong Id;
public int LaneHandle;
public float DistanceAlongLane;
/// <summary>VehicleLaneDataStatus flags: Normal=0, LaneChangeToLeft=1, LaneChangeToRight=2, Teleport=4, StandBy=8.</summary>
public byte Status;
}
/// <summary>ClientVehicleLaneChangeData (struct): optional lane-change interpolation info.</summary>
[UxContract(Inline = true)]
internal struct ClientVehicleLaneChangeData4229938
{
public ClientVehicleLaneData4229938 VehicleLaneData;
public int LaneHandleInitial;
public int LaneHandleFinal;
public float BeginDistanceAloneLaneInitial;
public float BeginDistanceAloneLaneFinal;
public float EndDistanceAlongLaneFinal;
public float DistanceBetweenLanes;
}
/// <summary>
/// ClientVehicleInitData spawn payload for SyncAetherAIVehicleAddData.
/// WIRE ORDER VERIFIED against the client's own RPCSerializeAuto.lua WriteClientVehicleInitData:
/// the DERIVED fields come FIRST and the base-class fields (Id/Position/Facing/EulerAngles)
/// come LAST — do not reorder to C# inheritance order.
/// </summary>
[UxContract]
internal class ClientVehicleInitData4229938
{
// ClientVehicleInitData
public uint VehicleConfigId;
public uint VehicleColorPartId;
public byte VehicleLightState;
public int LaneHandle;
public float DistanceAlongLane;
public ulong NextVehicleId;
public double Timestamp;
/// <summary>VehicleControlType: Invalid=0, AetherVehicle=1, RaidVehicle=2 (serialized as byte).</summary>
public byte ControlType;
public float Speed;
public float DustRatio;
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<VehicleClientPart> Parts = [];
public uint SuitId;
public float RandomFraction;
// ClientBaseEntityData — wire order puts base fields LAST
public ulong Id;
public UxVector3 Position;
public float Facing;
public UxVector3 EulerAngles;
}
/// <summary>Notify SyncAetherAIVehicleLaneDatas(List&lt;ClientVehicleLaneData&gt;, List&lt;ClientVehicleLaneChangeData&gt;, double timeStamp).</summary>
[UxContract(Inline = true)]
internal class SyncAetherAIVehicleLaneDatas4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<ClientVehicleLaneData4229938> Data = [];
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<ClientVehicleLaneChangeData4229938> LaneChangeData = [];
public double TimeStamp;
}
/// <summary>Notify SyncAetherAIVehicleNpcAdd(ClientVehicleNpcInitData) — inline wrapper + complex initData.</summary>
[UxContract(Inline = true)]
internal class SyncAetherAIVehicleNpcAdd4229938
{
public ClientVehicleNpcInitData4229938 initData = new();
}
/// <summary>Notify SyncAetherAIVehicleAddData(ulong pid).</summary>
[UxContract(Inline = true)]
internal class SyncAetherAIVehicleRemove4229938
{
public ulong Pid;
}
/// <summary>Notify SyncAetherAIVehicleForceGo(ulong instanceId, bool forceGo) — force the aether car to start driving.</summary>
[UxContract(Inline = true)]
internal class SyncAetherAIVehicleForceGo4229938
{
public ulong instanceId;
public bool forceGo;
}
/// <summary>Ask AskAetherAIBorrowVehicle(ulong vehicleInstanceId) — player takes over a traffic car.</summary>
[UxContract(Inline = true)]
internal class AskAetherAIBorrowVehicle4229938
{
public ulong VehicleInstanceId;
}
/// <summary>Notify SyncAetherAIBorrowVehicle(ulong vehicleInstanceId) — borrow granted.</summary>
[UxContract(Inline = true)]
internal class SyncAetherAIBorrowVehicle4229938
{
public ulong VehicleInstanceId;
}
/// <summary>Ask AskAetherAIRaidVehicleRegressAether(ulong vehicleInstanceId) — borrowed car returns to traffic.</summary>
[UxContract(Inline = true)]
internal class AskAetherAIRaidVehicleRegressAether4229938
{
public ulong VehicleInstanceId;
}
/// <summary>Notify SyncAetherAIChangeVehicleControlType(ulong vehicleId, VehicleControlType) — AetherVehicle=1, RaidVehicle=2.</summary>
[UxContract(Inline = true)]
internal class SyncAetherAIChangeVehicleControlType4229938
{
public ulong VehicleId;
/// <summary>VehicleControlType: Invalid=0, AetherVehicle=1, RaidVehicle=2 (byte).</summary>
public byte ControlType;
}
// NOTE: there is NO batch SyncAetherAIVehicleAddDatas in the 4229938 client. The full IL2CPP
// dump + RPCMethodIdToName.lua only expose the single-vehicle SyncAetherAIVehicleAddData
// (68916691). A previous session invented id 68571034 for a batch form — those packets were
// silently dropped by the client (cars never rendered). Always spawn via single notifies.
/// <summary>
/// ClientVehicleNpcInitData: binds a driver/passenger NPC into an Aether vehicle seat.
/// Real traffic spawn table (VehicleSpawnConfig): driver 45200091, passenger 45200093.
/// </summary>
[UxContract]
internal class ClientVehicleNpcInitData4229938
{
public ulong Id;
public uint NpcFormworkId;
public ulong BindVehicleId;
public byte SeatIndex;
}
/// <summary>Notify SyncAetherAINpcRemove(ulong pid) — the only Aether NPC remove the client has.</summary>
[UxContract(Inline = true)]
internal class SyncAetherAINpcRemove4229938
{
public ulong Pid;
}
/// <summary>
/// ClientTrafficIntersectionInitInfo : TrafficIntersectionPeriodInfo.
/// WIRE ORDER VERIFIED against RPCSerializeAuto.lua WriteClientTrafficIntersectionInitInfo:
/// derived fields (InstanceId/ZoneIndex/CurrentState) come FIRST, base period bytes LAST —
/// do not reorder to C# inheritance order.
/// </summary>
[UxContract]
internal class ClientTrafficIntersectionInitInfo4229938
{
// ClientTrafficIntersectionInitInfo — wire order puts derived fields FIRST
public ulong InstanceId;
public int ZoneIndex;
/// <summary>MassTrafficIntersectionState: Start=0, Transition=1, Finishing=2.</summary>
public byte CurrentState;
// TrafficIntersectionPeriodInfo (base) — written LAST on the wire
public byte CurrentPeriodIndex;
public byte NextPeriodIndex;
public byte RailPeriodIndex;
}
/// <summary>
/// ClientTrafficIntersectionPeriodUpdateInfo : TrafficIntersectionPeriodInfo.
/// WIRE ORDER VERIFIED against RPCSerializeAuto.lua WriteClientTrafficIntersectionPeriodUpdateInfo:
/// derived fields (IntersectionIndex/CurrentState) come FIRST, base period bytes LAST.
/// Payload of SyncAetherAIIntersectionUpdateData.
/// </summary>
[UxContract]
internal class ClientTrafficIntersectionPeriodUpdateInfo4229938
{
// ClientTrafficIntersectionPeriodUpdateInfo — derived fields FIRST
public ulong IntersectionIndex;
/// <summary>MassTrafficIntersectionState: Start=0, Transition=1, Finishing=2.</summary>
public byte CurrentState;
// TrafficIntersectionPeriodInfo (base) — written LAST on the wire
public byte CurrentPeriodIndex;
public byte NextPeriodIndex;
public byte RailPeriodIndex;
}
@@ -0,0 +1,88 @@
using Ananta.SDK.Serialization;
namespace Ananta.Server.RpcTypes.Client4229938.Methods.GameScene;
// Agent property + NPC interact/date wire contracts for build 4229938.
//
// The F-prompt on an NPC is gated by the server-pushed agent property
// AgentPropertyType.EnableInteract (0). The dating system ("เดต") is the
// InviteRide family: SyncInviteRideNpcInfo activates an NPC as the invite-ride
// (date) companion and AgentPropertyType.InviteRideNpcInteract (21) carries the
// interaction menu. Wire formats verified against RPCSerializeAuto.lua
// (WriteSyncAgentProperty 10046, WriteAgentPropertyDataBool 394,
// WriteAgentPropertyDataInteractIcon 413, WriteAgentPropertyDataInviteRideNpcInteract 417).
//
// Polymorphic framing of SyncAgentProperty: V = complex (0xFF marker + concrete
// subclass fields) followed by the Type byte — the client uses Type to pick the
// subclass shape, so each property kind gets its own DTO pair here.
/// <summary>AgentPropertyDataBool (complex): one boolean agent property value.</summary>
[UxContract]
internal class AgentPropertyDataBool4229938
{
public bool V;
}
/// <summary>SyncAgentPropertyChange(agentId, {bool V, Type}) — push for EnableInteract etc.</summary>
[UxContract(Inline = true)]
internal class SyncAgentPropertyBoolChange4229938
{
public ulong AgentId;
/// <summary>AgentPropertyType: EnableInteract=0, EnableMinded=5, ... (byte).</summary>
public byte Type;
public AgentPropertyDataBool4229938 V = new();
}
/// <summary>InviteRideNpcInteractItem (complex): one dating-menu entry.</summary>
[UxContract]
internal class InviteRideNpcInteractItem4229938
{
public int Index;
public uint Sprite;
public uint LabelId;
}
/// <summary>AgentPropertyDataInviteRideNpcInteract (complex): the dating interaction menu.</summary>
[UxContract]
internal class AgentPropertyDataInviteRide4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<InviteRideNpcInteractItem4229938> InviteRideNpcInteractList = [];
}
/// <summary>SyncAgentPropertyChange(agentId, {InviteRideNpcInteractList, Type=21}).</summary>
[UxContract(Inline = true)]
internal class SyncAgentPropertyInviteRideChange4229938
{
public ulong AgentId;
public AgentPropertyDataInviteRide4229938 V = new();
/// <summary>AgentPropertyType.InviteRideNpcInteract = 21.</summary>
public byte Type = 21;
}
/// <summary>Notify SyncInviteRideNpcInfo(ulong instanceId, bool active) — activate a date companion.</summary>
[UxContract(Inline = true)]
internal class SyncInviteRideNpcInfo4229938
{
public ulong InviteRideNpcInstanceId;
public bool IsInviteRideNpcActive;
}
/// <summary>Ask GmStartInviteRideNpc(uint npcId) — start a date with an NPC (client GM command).</summary>
[UxContract(Inline = true)]
internal class GmStartInviteRideNpc4229938
{
public uint NpcId;
}
/// <summary>Ask AskInteractNpcWithGift(uint activityCfgId, ulong itemId, uint count) — give a gift.</summary>
[UxContract(Inline = true)]
internal class AskInteractNpcWithGift4229938
{
public uint ActivityCfgId;
public ulong ItemId;
public uint Count;
}
@@ -0,0 +1,344 @@
using Ananta.SDK.Serialization;
namespace Ananta.Server.RpcTypes.Client4229938.Methods.GameScene;
// Gadget grid-AOI streaming wire contracts for build 4229938.
//
// The client instantiates interactive gadgets (vending machines, claw machines, doors,
// benches, arcades, stalls...) from its own baked per-grid-cell data the moment the
// server tells it which 40m grid cells to load — exactly what LX6.Item.GadgetMgr.
// SyncGadgetGridAOIAddByIndex(indexX, indexZ, exceptIds, sectorIdList, playerStandardIndex)
// does internally (verified by the community's Frida-based AnantaGadgetLoader). The real
// server does the same over the wire with SyncGadgetGridAOIDecrease (68956797, CSharpOnly
// payload — read by the client's C# stack, no Lua reader).
//
// WIRE ORDER VERIFIED against RPCSerializeAuto.lua: WriteGadgetGridAOIIncrease (line 4503),
// WriteGridAOIDecrease (line 4808), WriteGadgetExtraSyncInfo (line 4499), WriteGridIndex.
// All four payload params are structs in the IL2CPP dump → serialized inline (no complex
// marker at the method-arg level).
/// <summary>GridIndex (struct): one 40m world grid cell.</summary>
[UxContract(Inline = true)]
internal struct GadgetGridIndex4229938
{
public int X;
public int Z;
public GadgetGridIndex4229938(int x, int z)
{
X = x;
Z = z;
}
}
/// <summary>
/// GadgetGridAOIIncrease (struct): the AOI-increase side of one gadget grid sync.
/// indexList carries the cells to load; addInfos stays EMPTY (server-authoritative gadget
/// entities would go here — ambient gadgets come from the client's baked grid data).
/// </summary>
[UxContract(Inline = true)]
internal struct GadgetGridAOIIncrease4229938
{
public GadgetGridIndex4229938 PlayerStandardIndex;
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<GadgetEntityInfo4229938> AddInfos = [];
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<GadgetGridIndex4229938> IndexList = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<ulong> AddUniqueIds = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<ulong> RemoveIds = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<ulong> ActiveIds = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<ulong> InactiveIds = [];
/// <summary>AoiAddAndRemoveReason: Init=0, Loaded=1, AOIMove=2, SpecialCondition=3, TargetCondition=4, SectorChange=5, BuildingChange=6.</summary>
public byte Reason;
public GadgetGridAOIIncrease4229938()
{
}
}
/// <summary>
/// GridAOIDecrease (struct): one sector/building batch of grid cells. SectorIdList selects
/// which baked sector data the client instantiates for the cells — sector 0 is the outdoor
/// city sector; indoor gadgets live under per-building sector ids.
/// </summary>
[UxContract(Inline = true)]
internal struct GridAOIDecrease4229938
{
[UxCollection(Count = UxCountEncoding.Int7)]
public List<int> SectorIdList = [];
public int BuildingId;
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<GadgetGridIndex4229938> StandardIndexList = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<ulong> ExceptIds = [];
public GridAOIDecrease4229938()
{
}
}
/// <summary>GadgetExtraSyncInfo (struct): drop-limit sync; empty for ambient streaming.</summary>
[UxContract(Inline = true)]
internal struct GadgetExtraSyncInfo4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<GadgetClientDropLimitInfo4229938> DropLimit = [];
public GadgetExtraSyncInfo4229938()
{
}
}
/// <summary>GadgetClientDropLimitInfo — payload shape per IL2CPP dump; never sent (empty list).</summary>
[UxContract]
internal class GadgetClientDropLimitInfo4229938
{
public ulong GadgetUid;
[UxCollection(Count = UxCountEncoding.Int7)]
public Dictionary<uint, uint> DropLimitId2FinishTime = new();
}
/// <summary>
/// GadgetEntityInfo — payload shape stub. Our stream keeps addInfos EMPTY (ambient gadgets
/// come from the client's baked grid data); if server-authoritative gadget entities are ever
/// needed, mirror every field of RPCSerializeAuto.lua WriteGadgetEntityInfo (line 4474)
/// BEFORE adding items to the list — field order there is the only source of truth.
/// </summary>
[UxContract]
internal class GadgetEntityInfo4229938
{
}
/// <summary>DestructibleInfo — payload shape stub. addInfos stays EMPTY for grid streaming;
/// see RPCSerializeAuto.lua WriteDestructibleInfo (line 3306) before sending entities.</summary>
[UxContract]
internal class DestructibleInfo4229938
{
}
/// <summary>
/// DestructibleGridAOIIncrease (struct): the scene-item / destructible grid window. Pushing
/// this makes the client instantiate lampposts, street props and breakables for the cells
/// from its baked SceneItemBlob — the server-side equivalent of the community's
/// AnantaWorldMod (SceneItemMgr.SyncSceneItemGridAOIAddByIndex) without injection.
/// WIRE ORDER VERIFIED against RPCSerializeAuto.lua WriteDestructibleGridAOIIncrease (3293).
/// </summary>
[UxContract(Inline = true)]
internal struct DestructibleGridAOIIncrease4229938
{
public GadgetGridIndex4229938 PlayerStandardIndex;
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<DestructibleInfo4229938> AddInfos = [];
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<GadgetGridIndex4229938> IndexList = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<ulong> AddUniqueIds = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<ulong> RemoveIds = [];
/// <summary>AoiAddAndRemoveReason byte (Init=0, Loaded=1, AOIMove=2, ...).</summary>
public byte Reason;
public DestructibleGridAOIIncrease4229938()
{
}
}
/// <summary>Notify SyncDestructibleGridAOIIncrease(DestructibleGridAOIIncrease) — scene-item grid load (68934309).</summary>
[UxContract(Inline = true)]
internal class SyncDestructibleGridAOIIncrease4229938
{
public DestructibleGridAOIIncrease4229938 AoiInfo = new();
}
/// <summary>
/// Notify SyncGadgetGridAOIDecrease(GadgetGridAOIIncrease, GridAOIDecrease, GridAOIDecrease,
/// GadgetExtraSyncInfo) — the gadget grid AOI stream.
/// </summary>
[UxContract(Inline = true)]
internal class SyncGadgetGridAOIDecrease4229938
{
public GadgetGridAOIIncrease4229938 AoiInfo = new();
/// <summary>Entering cells grouped by sector/building (indoor flow); carries sector 0 for our outdoor batch.</summary>
public GridAOIDecrease4229938 AddGridInfo = new();
/// <summary>Leaving cells. Intentionally left empty: re-adding a removed cell often yields
/// nothing (the injection tool calls this "poisoning"), so we never unload explicitly — the
/// client's own AOI cleanup handles far cells.</summary>
public GridAOIDecrease4229938 RemoveGridInfo = new();
public GadgetExtraSyncInfo4229938 ExtraInfo = new();
}
// ---------------------------------------------------------------------------
// Gadget interaction (SceneDevice) wire contracts — what makes spawned gadgets
// pressable. Pressing F runs the gadget's local graph which then asks the
// server: AskInteractCmd / AskSceneDeviceChangeState / AskSceneDeviceRecordValue
// / AskSceneDeviceSendSignal. The server answers with the check-index callback
// and echoes the change back via the Sync* notifies — without those the graph
// stalls and the gadget never reacts ("spawns but can't be pressed").
// Wire formats verified against ClientToGameSceneDelegate.lua (client-side arg
// writers, lines 552/2230/892/1366/4068) + RPCSerializeAuto.lua (5192/9059/9083/9091).
// ---------------------------------------------------------------------------
/// <summary>InteractCmdData (struct): one generic interact command aimed at a gadget uid.</summary>
[UxContract(Inline = true)]
internal struct InteractCmdData4229938
{
public uint CmdType;
public ulong Sender;
public ulong Receiver;
public int BroadCastType;
[UxCollection(Count = UxCountEncoding.Int7)]
public List<byte> CommandData = [];
public string StringParam1 = string.Empty;
public string StringParam2 = string.Empty;
public InteractCmdData4229938()
{
}
}
/// <summary>SceneDeviceStateChangeInfo (struct): one state transition request for a device.</summary>
[UxContract(Inline = true)]
internal struct SceneDeviceStateChangeInfo4229938
{
public ulong Id;
public int StateType;
public int State;
public int StateCheckIndex;
public bool ToTask;
}
/// <summary>SceneDeviceValueChangeInfo (struct): one value write request for a device.</summary>
[UxContract(Inline = true)]
internal struct SceneDeviceValueChangeInfo4229938
{
public ulong Id;
public int ValueName;
public string Value = string.Empty;
public int ValueCheckIndex;
public bool ToTask;
public bool SetOnceOnly;
public SceneDeviceValueChangeInfo4229938()
{
}
}
/// <summary>SceneDeviceCheckIndexCallback (struct): the invoke return for scene-device asks.</summary>
[UxContract(Inline = true)]
internal struct SceneDeviceCheckIndexCallback4229938
{
public int CheckIndex;
public uint Error;
}
/// <summary>Ask AskInteractCmd(InteractCmdData) — notify, no return.</summary>
[UxContract(Inline = true)]
internal class AskInteractCmd4229938
{
public InteractCmdData4229938 Data;
}
/// <summary>Ask AskInteractCmds(List&lt;InteractCmdData&gt;) — notify, no return.</summary>
[UxContract(Inline = true)]
internal class AskInteractCmds4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<InteractCmdData4229938> Data = [];
}
/// <summary>Ask AskSceneDeviceChangeState(SceneDeviceEntityType, SceneDeviceStateChangeInfo) — invoke.</summary>
[UxContract(Inline = true)]
internal class AskSceneDeviceChangeState4229938
{
/// <summary>SceneDeviceEntityType: Gadget=0, Destructible=1 (byte on the wire).</summary>
public byte Type;
public SceneDeviceStateChangeInfo4229938 Info;
}
/// <summary>Ask AskSceneDeviceRecordValue(SceneDeviceEntityType, SceneDeviceValueChangeInfo) — invoke.</summary>
[UxContract(Inline = true)]
internal class AskSceneDeviceRecordValue4229938
{
public byte Type;
public SceneDeviceValueChangeInfo4229938 Info;
}
/// <summary>Ask AskSceneDeviceSendSignal(SceneDeviceEntityType, ulong, string) — invoke.</summary>
[UxContract(Inline = true)]
internal class AskSceneDeviceSendSignal4229938
{
public byte Type;
public ulong Id;
public string SignalName = string.Empty;
}
/// <summary>Notify SyncInteractCmd(InteractCmdData) — echoes an interact command to the gadget graph.</summary>
[UxContract(Inline = true)]
internal class SyncInteractCmd4229938
{
public InteractCmdData4229938 Data;
}
/// <summary>Notify SyncInteractCmds(List&lt;InteractCmdData&gt;).</summary>
[UxContract(Inline = true)]
internal class SyncInteractCmds4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<InteractCmdData4229938> Data = [];
}
/// <summary>Notify SyncSceneDeviceStateChange(type, id, stateType, state, stateCheckIndex).</summary>
[UxContract(Inline = true)]
internal class SyncSceneDeviceStateChange4229938
{
public byte Type;
public ulong Id;
public int StateType;
public int State;
public int StateCheckIndex;
}
/// <summary>Notify SyncSceneDeviceValueChange(type, id, valueName, value, valueCheckIndex).</summary>
[UxContract(Inline = true)]
internal class SyncSceneDeviceValueChange4229938
{
public byte Type;
public ulong Id;
public int ValueName;
public string Value = string.Empty;
public int ValueCheckIndex;
}
/// <summary>Notify SyncSceneDeviceSignalSend(type, id, signalName).</summary>
[UxContract(Inline = true)]
internal class SyncSceneDeviceSignalSend4229938
{
public byte Type;
public ulong Id;
public string SignalName = string.Empty;
}
@@ -0,0 +1,313 @@
using Ananta.SDK.Serialization;
namespace Ananta.Server.RpcTypes.Client4229938.Methods.GameScene;
// NPC dialog + task (quest) wire contracts for build 4229938.
//
// Dialog flow: pressing F on an NPC makes the client fire AskAgentStartNpcDialog with the
// dialog id it resolved locally; the server opens the dialog by pushing
// SyncAgentPrepareStartNpcDialog back (dialog TEXT is client-baked — the server only
// arbitrates). AskAgentFinishNpcDialog closes it via SyncAgentFinishNpcDialog.
//
// Task flow: AskAcceptTask / AskSubmitTask / AskAcceptAndSetCurrentTask (invokes) are
// answered by pushing SyncPlayerSingleTask with the new TaskState — without that push the
// quest never shows up in the tracker.
// Wire formats verified against ClientToGameSceneDelegate.lua (2480/5414/3172/2656/7136)
// and RPCSerializeAuto.lua (WriteTaskViewCounter 10220 / WriteTaskViewData 10228 /
// WriteTaskSpoonViewInfo 10198 / WriteTaskStateData 10208 / WriteIntList 5184).
[UxContract(Inline = true)]
internal class AskAgentStartNpcDialog4229938
{
public ulong AgentEntityId;
public uint NpcDialogId;
public float DialogDuration;
}
[UxContract(Inline = true)]
internal class SyncAgentPrepareStartNpcDialog4229938
{
public ulong AgentId;
public uint NpcDialogId;
public uint NpcSoundId;
public bool VirtualNpc;
public uint EntireDialogId;
}
[UxContract(Inline = true)]
internal class AskAgentFinishNpcDialog4229938
{
public ulong AgentEntityId;
public uint NpcDialogId;
}
[UxContract(Inline = true)]
internal class SyncAgentFinishNpcDialog4229938
{
public ulong AgentId;
}
/// <summary>Ask AskGadgetSceneRoomTrigger(int, ulong, bool) — interior room enter/leave via a door gadget.</summary>
[UxContract(Inline = true)]
internal class AskGadgetSceneRoomTrigger4229938
{
public int SceneRoomId;
public ulong GadgetUniqueId;
public bool IsEnter;
}
/// <summary>Ask AskGadgetDoorTransfer(ulong id, ulong from, ulong to, UXVector3 position) — door teleport report.</summary>
[UxContract(Inline = true)]
internal class AskGadgetDoorTransfer4229938
{
public ulong Id;
public ulong From;
public ulong To;
public UxVector3 Position;
}
[UxContract(Inline = true)]
internal class AskAcceptTask4229938
{
public uint TaskId;
}
[UxContract(Inline = true)]
internal class AskSubmitTask4229938
{
public uint TaskId;
}
[UxContract(Inline = true)]
internal class AskAcceptAndSetCurrentTask4229938
{
public uint TaskId;
public uint Spirit;
public bool IgnoreSwitchSpirit;
}
/// <summary>TaskViewCounter (class): one quest counter node (recursive children).</summary>
[UxContract]
internal class TaskViewCounter4229938
{
public int Index;
public int Value;
public int ConfigValue;
public int Parent;
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<TaskViewCounter4229938> Child = [];
}
/// <summary>IntList (class): wrapper list used inside task function dictionaries.</summary>
[UxContract]
internal class IntList4229938
{
[UxCollection(Count = UxCountEncoding.Int32)]
public List<int> Value = [];
}
/// <summary>TaskSpoonViewInfo (class): spoon/scene binding of a task.</summary>
[UxContract]
internal class TaskSpoonViewInfo4229938
{
public string SpoonMd5 = string.Empty;
public uint SpRaidId;
public uint StartTaskId;
public uint EndTaskId;
public string Alias = string.Empty;
public uint EventId;
public uint EventStartTaskId;
}
/// <summary>TaskViewData (class): the client-visible state of one task.</summary>
[UxContract]
internal class TaskViewData4229938
{
public uint TaskId;
[UxCollection(Count = UxCountEncoding.Int7)]
public List<int> CounterValues = [];
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<TaskViewCounter4229938> Counters = [];
/// <summary>TaskState: NotAccept=0, Accepted=1, Submited=3, Aborted=4 (byte).</summary>
public byte State;
[UxCollection(Count = UxCountEncoding.Int7)]
public Dictionary<byte, int> ActiveFunctionValue = [];
[UxCollection(Count = UxCountEncoding.Int7, ValueObjectEncoding = UxObjectEncoding.Complex)]
public Dictionary<byte, IntList4229938> ActiveFunctionIds = [];
public bool RecoverResource;
public TaskSpoonViewInfo4229938? SpoonViewInfo;
}
/// <summary>TaskStateData (struct): state transition descriptor.</summary>
[UxContract(Inline = true)]
internal struct TaskStateData4229938
{
public byte State;
public byte Reason;
public uint FailTextId;
public bool CanSkip;
}
/// <summary>
/// Notify SyncPlayerSingleTask(uint taskId, TaskViewData, TaskSpoonViewInfo, TaskStateData) —
/// the authoritative push for one task's state.
/// </summary>
[UxContract(Inline = true)]
internal class SyncPlayerSingleTask4229938
{
public uint TaskId;
public TaskViewData4229938 View = new();
public TaskSpoonViewInfo4229938 Spoon = new();
public TaskStateData4229938 State;
}
/// <summary>EventPanelInfo (class): event panel state carried inside SyncPlayerAllTask (all empty for us).</summary>
[UxContract]
internal class EventPanelInfo4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<TaskEventInfo4229938> EventsInfo = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<uint> SubmitEventList = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<uint> SubmitReplayEventList = [];
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<EventSpoonViewInfo4229938> EventViewInfoList = [];
}
/// <summary>TaskEventInfo (class) — stub: our EventsInfo list stays EMPTY.</summary>
[UxContract]
internal class TaskEventInfo4229938
{
}
/// <summary>EventSpoonViewInfo (class) — stub: our list stays EMPTY.</summary>
[UxContract]
internal class EventSpoonViewInfo4229938
{
}
/// <summary>
/// Notify SyncPlayerAllTask(List&lt;TaskViewData&gt;, List&lt;uint&gt; submitTaskList, uint currentTask,
/// EventPanelInfo, bool loginGameServer) — the login/entry task-state snapshot.
/// </summary>
[UxContract(Inline = true)]
internal class SyncPlayerAllTask4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<TaskViewData4229938> TaskInfos = [];
[UxCollection(Count = UxCountEncoding.Int7)]
public List<uint> SubmitTaskList = [];
public uint CurrentTask;
public EventPanelInfo4229938 EventsInfo = new();
public bool LoginGameServer;
}
/// <summary>Ask AskFinishTaskCounter(uint taskId, int counterIndex) — sandbox shortcut to complete one counter.</summary>
[UxContract(Inline = true)]
internal class AskFinishTaskCounter4229938
{
public uint TaskId;
public int CounterIndex;
}
// ---------------------------------------------------------------------------
// Scene rooms (interiors): the client asks on door enter/leave and the server
// answers with SyncSpoonRoomState — the room's geometry only loads when the
// server enables it. Missing this is what made house/interior entries fall
// through the world.
// ---------------------------------------------------------------------------
/// <summary>Ask AskEnterSceneRoom(int sceneRoomId, bool isVehicle, byte moveId).</summary>
[UxContract(Inline = true)]
internal class AskEnterSceneRoom4229938
{
public int SceneRoomId;
public bool IsVehicle;
public byte MoveId;
}
/// <summary>Ask AskExistSceneRoom(int sceneRoomId, bool isVehicle, byte moveId).</summary>
[UxContract(Inline = true)]
internal class AskExistSceneRoom4229938
{
public int SceneRoomId;
public bool IsVehicle;
public byte MoveId;
}
/// <summary>Ask AskAgentSceneRoomTrigger(int sceneRoomId, int spoonAgentId, bool isEnter).</summary>
[UxContract(Inline = true)]
internal class AskAgentSceneRoomTrigger4229938
{
public int SceneRoomId;
public int SpoonAgentId;
public bool IsEnter;
}
/// <summary>Notify SyncSpoonRoomState(int sceneRoomId, bool enabled, uint taskId) — room on/off.</summary>
[UxContract(Inline = true)]
internal class SyncSpoonRoomState4229938
{
public int SceneRoomId;
public bool Enabled;
public uint TaskId;
}
/// <summary>FurnitureInfo (class): owned/placed counts for one furniture id.</summary>
[UxContract]
internal class FurnitureInfo4229938
{
public uint FurnitureId;
public uint Count;
public uint PlacedCount;
}
/// <summary>Notify SyncHouseFurnitureInfo(Dictionary&lt;uint, FurnitureInfo&gt;) — the player's furniture inventory.</summary>
[UxContract(Inline = true)]
internal class SyncHouseFurnitureInfo4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ValueObjectEncoding = UxObjectEncoding.Complex)]
public Dictionary<uint, FurnitureInfo4229938> FurnitureInfoDict = [];
}
/// <summary>Notify SyncDoAetherAgentBehaviorTaskDef(ulong agentEntityId, ulong taskId, uint behaviorTaskId) —
/// assigns a behavior task (drive/idle/...) to an aether agent (driver NPCs).</summary>
[UxContract(Inline = true)]
internal class SyncDoAetherAgentBehaviorTaskDefine4229938
{
public ulong agentEntityId;
public ulong taskId;
public uint behaviorTaskId;
}
/// <summary>
/// TeamTrackGPS (class): the tracked-quest map pin (หมุด). Notify SyncTrackGPS(63861463)
/// carries exactly this complex — writer RPCSerializeAuto.lua WriteTeamTrackGPS:
/// TrackPosition (UXVector3) → TrackGPSId (string) → TrackGPSType (uint).
/// The client's task view binds it via TaskViewActiveFunction.GPS.
/// </summary>
[UxContract]
internal class TeamTrackGPS4229938
{
public UxVector3 TrackPosition = new();
public string TrackGPSId = string.Empty;
/// <summary>TaskViewActiveFunction-flavoured source tag; 0 = plain tracked position.</summary>
public uint TrackGPSType;
}
@@ -0,0 +1,190 @@
using Ananta.SDK.Serialization;
namespace Ananta.Server.RpcTypes.Client4229938.Methods.GameScene;
[UxContract(Inline = true)]
internal sealed class SyncAssignVehicleAITask4229938
{
public ulong vehicleUId;
public CruiseAITaskParameters4229938 parameters = new();
}
[UxContract(Inline = true)]
internal sealed class SyncChangeVehicleAITaskState4229938
{
public ulong vehicleUID;
public ulong taskToken;
public byte status;
}
internal enum VehicleAIStatus4229938 : byte
{
Pending = 0,
Running = 1,
Success = 2,
Pause = 3,
Abort = 4,
Override = 5,
}
internal enum E_TaskVehicleCruiseType4229938
{
GoToOneTarget = 0,
GoToTargetInOrderOnce = 1,
GoToTargetInOrderLoop = 2,
GoToTargetInOrderLoopInCount = 3,
GoToTargetInRandomOnce = 4,
GoToTargetInRandomOneByOne = 5,
GoToTargetInRandomOneByOneInCount = 6,
GoToTargetInRandomAlways = 7,
}
[Flags]
internal enum TaskVehicleCruiseConfigFlags4229938
{
None = 0,
BreakByPlayerWhenAtFront = 1,
PauseByPlayerWhenAtFront = 2,
SlowDownWhenArriveTarget = 4,
DynamicSpeed = 8,
}
[Flags]
internal enum TaskVehiclePathFindFlags4229938
{
None = 0,
IgnoreAlley = 1,
IgnoreDirection = 2,
}
internal enum E_AITargetType4229938
{
None = 0,
Vehicle = 1,
Unit = 2,
}
[Flags]
internal enum VehicleTaskDrivingFlags4229938
{
None = 0,
DFStopForCars = 1,
DFStopForPeds = 2,
DFSwerveAroundAllCars = 4,
DFSteerAroundStationaryCars = 8,
DFSteerAroundPeds = 16,
DFSteerAroundObjects = 32,
DFStopAtLights = 128,
DFGoOffRoadWhenAvoiding = 256,
}
[Flags]
internal enum VehicleStuckLevel4229938
{
None = 0,
Relaxed = 1,
Moderate = 2,
Strict = 4,
}
internal enum VirtualGroundMoveType4229938
{
None = 0,
ColliderNotLoaded = 1,
Always = 2,
ForceDummy = 3,
ForcePhysics = 4,
}
[UxContract]
internal sealed class VehicleStuckCheckConfig4229938
{
public byte StuckLevel = (byte)VehicleStuckLevel4229938.None;
public float RelaxedStuckCheckTime = 2f;
public int RelaxedStuckCheckCount = 2;
public int ModerateStuckCheckCount = 2;
public float StrictStuckCheckDistance = 6f;
public float CheckGoToNextPointStuckTime;
public bool ResetWhenStuck;
}
[UxContract(Inline = true)]
internal struct TaskVehicleBuffInitInfo4229938
{
public uint configId;
public float duration;
}
[UxContract(Inline = true)]
internal struct VehicleAICommonParameters4229938
{
public float FollowPathCheckArrivePointDistance;
public int TurnSlowSpeedTemplateId;
public float TurnMinAheadSpeed;
public float TurnMinAheadDistance;
public float TurnMaxAheadSpeed;
public float TurnMaxAheadDistance;
public float AheadDistanceNormalRatio;
public float DummySpeedRatio;
public VehicleStuckCheckConfig4229938? StuckCheckConfig;
public byte VirtualGroundMoveType;
}
[UxContract(TypeMark = 6)]
internal sealed class CruiseAITaskParameters4229938
{
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<Auto.UXVector3> TargetPointList = [];
public byte CruiseType = (byte)E_TaskVehicleCruiseType4229938.GoToTargetInOrderLoop;
public int Count;
public byte configFlags = (byte)TaskVehicleCruiseConfigFlags4229938.SlowDownWhenArriveTarget;
public byte pathFindFlags = (byte)TaskVehiclePathFindFlags4229938.None;
public byte TargetType = (byte)E_AITargetType4229938.None;
public ulong TargetUid;
public bool checkClose;
public bool checkFar;
public float closeRange;
public float farawayRange;
public float accelerateScale = 1f;
public float decelerateScale = 1f;
public float minSpeed;
public float maxSpeed;
public float ArrivalDistance = 4f;
public bool AdaptSpeedToTargetDistance = true;
public ulong Token;
public uint taskAIConfigId;
public float defaultSpeed;
public int drivingFlags = (int)(VehicleTaskDrivingFlags4229938.DFStopForCars
| VehicleTaskDrivingFlags4229938.DFStopForPeds
| VehicleTaskDrivingFlags4229938.DFStopAtLights);
public float initSpeed;
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Struct)]
public List<TaskVehicleBuffInitInfo4229938> initTaskAIBuffList = [];
public VehicleAICommonParameters4229938 commonParameters;
}
@@ -182,8 +182,9 @@ internal sealed class RaidVehicleSyncData
}
/// <summary>
/// Server -&gt; client SyncAetherAIInitDatas: vehicle-AI subsystem init (mirrors V2).
/// Lists stay empty on a private server; the header alone unblocks DriveManager.
/// Server -&gt; client SyncAetherAIInitDatas: vehicle-AI subsystem init. Field set verified against
/// the real client type (IL2CPP UX.Game.AetherAIInitData): header + intersection list only — the
/// client's MassTraffic populates ambient traffic itself from these + incremental Aether updates.
/// </summary>
[UxContract]
internal sealed class AetherAIInitData
@@ -192,11 +193,7 @@ internal sealed class AetherAIInitData
public bool HasZoneGraph;
public int ZoneStorageDataHandle;
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<AetherInitStub> Intersections = [];
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<AetherInitStub> Vehicles = [];
[UxCollection(Count = UxCountEncoding.Int7, ItemObjectEncoding = UxObjectEncoding.Complex)]
public List<AetherInitStub> StaticVehicles = [];
public List<ClientTrafficIntersectionInitInfo4229938> Intersections = [];
}
/// <summary>Never serialized (all Aether init lists are empty); satisfies the serializer.</summary>
@@ -204,7 +201,6 @@ internal sealed class AetherAIInitData
internal sealed class AetherInitStub
{
}
/// <summary>
/// Server -> client SyncChangeVehicleInteractable(ulong vehicleInstanceId, bool interactable).
/// Inline struct (no complex marker). From RPCDeserializeAuto reader for 68943521.