7.6 KiB
7.6 KiB
TH1 Network Contract
This reference summarizes the multiplayer contract after the May 2026 pre-release network audit.
SimpleP2P
- All normal game messages use per-peer outgoing queues.
- Per-peer FIFO is required.
- Ordered envelopes are used for game payloads; do not bypass them for gameplay sync.
- Outgoing sequence is committed only after enqueue succeeds.
- Large payloads are chunked after ordered wrapping.
- Outgoing queue processing may send multiple messages per update within a per-frame message/byte budget, but must preserve FIFO per peer.
- Incoming large chunks must validate magic, version, message id, chunk index, chunk count, total length, and payload length.
- Large incoming messages and outgoing queues have per-peer and global byte budgets.
- Ordered gaps and large-message receives must timeout and disconnect/clean state rather than wait forever.
- Steam message pointers must be released in
finally.
SteamLobbyManager
SendMessageToPeerreturnsbool; precheck failures must call the same failure path used by P2P send failures.BroadcastMessagereturnsbool.- Critical broadcast must gather current lobby members, skip self, preflight all targets through
SimpleP2P.CanQueueMessages, and only then enqueue. - Missing connection, non-lobby target, invalid data, or queue budget failure must surface through
OnLobbyErrorEvent/ send-failure logging.
GameNetSender
- Sender methods that gate local state must return
bool. GameStartmust validateMapDataand return broadcast success.ChangeCivcarries fullMemberCivroom state such as civ, force, and ready state. Client optimistic local application is allowed only after send success and must still be reconciled by hostUpdateLobbyData.RequestLobbyDatashould be retried by clients until host config matches current lobby members. Avoid treating a request as synced before the host P2P connection is active and accepted.ActionConfirmmust return send success.ActionExecutemust return broadcast success.ForceUpdateand fullMapDatasends must validate multiplayer map data before sending.MapDataDebugMessagesends currentMapDatafor diagnostics only. Member-to-host and host-broadcast sends should useGameNetSenderand the normal lobby queue path, but callers must not treat it as authoritative sync.- Heartbeat send timestamps should only update after send acceptance.
GameNetReceiver
- Wrap deserialization and dispatch in try/catch.
- Ignore
P2PMsgType.NetworkStress; the editor stress tool consumes diagnostics packets throughSimpleP2P.OnMessageReceivedEventbefore gameplay dispatch. - Validate incoming
GameStartandForceUpdatemaps before applying. - Host handles
ChangeCivas a full member room-config mutation, including civ, force, and ready state, then broadcasts changed lobby config. - Client
UpdateLobbyDatais authoritative for room config. Mark lobby data synced only when the receivedMapConfig.MultiCivsmatches the current lobby member set. NetStartGameandNetResumeMatchreturnbool; UI should only close/hide after success.ForceUpdateshould restore previous game state if resume fails.MapConfirmmust guard null maps, missing actions, and null action payloads.MapDataDebugMessageshould compare incomingMapDatawith localMain.MapDataand log[MapDataDebug]hash/action/diff details only. It must not callNetResumeMatch, changeGameState, requestForceUpdate, or replace local map data.
Network Stress Tool
- Tool path:
Unity/Assets/Scripts/TH1_Logic/Editor/NetworkStressEditorWindow.cs. - Diagnostics message:
NetworkStressMessage/P2PMsgType.NetworkStress. - The tool must send probes through
Lobby.BroadcastMessageandLobby.SendMessageToPeer, not through a raw side channel. - The host starts one-click tests; clients auto-start on
ControlStart. - Reports are keyed by
RunId; stale packets, ACKs, and reports from previous runs must be ignored. - Host export should contain one report per lobby member when clients are reachable. If a report is late, host may update the same export file after receipt.
- Current default test is a one-minute flow: 50 seconds of traffic and up to 10 seconds of report collection.
MapData Debug Tool
- Tool path:
Unity/Assets/Scripts/TH1_Logic/Editor/NetworkStressEditorWindow.cs. - Menu:
Tools/Steam MapData一致性诊断. - Diagnostics message:
MapDataDebugMessage/P2PMsgType.MapDataDebug. - Use when
MapConfirm/ForceUpdatelogs are too late to reveal the original divergence. The tool captures the sender's currentMapDataat button click time. - Buttons:
- Members send current
MapDatato host. - Host broadcasts current
MapDatato all members.
- Members send current
- Receiver logs whether local and remote maps match, map hashes, action counts, first action mismatch, and diff details.
- The tool is read-only from a gameplay perspective. It must not mutate
Main.MapData, request reconnect, enterForceUpdating, or hide/show gameplay UI. - It should continue to use
GameNetSender/ lobby P2P queues so full-map diagnostics exercise ordered delivery and large-message chunking.
Lobby MapConfig / Ready State
- Pre-game room settings and member state live in
Main.Instance.MapConfig. MemberCivcontainsMemberId,PlayerId,CivId,ForceId, andIsReady.- Host is the authority. Clients can optimistically apply their own
MemberCivonly afterChangeCivsend success, but must keep requesting host data untilHasSameLobbyMembersis true. - Host
UpdateLobbyMemberremoves stale members, adds new members, and keeps the owner ready. New guests default to not ready. - UI should call
SetSelfReadyorToggleSelfReady; read readiness throughIsMemberReadyorMemberCiv.IsReady. - Changing civ resets that member's
IsReady; host room setting changes reset guest readiness throughResetGuestReadyStates. StartGameand resume must requireAreAllLobbyMembersReady; owner is treated ready and guests must be ready.
MapData And NetData
MapData.DeserializedMissingCriticalDatameans the save/network map must not be used.OnAfterMemoryPackDeserializemay coalesce non-critical containers to avoid callback NREs but must not silently accept missing core data.NetData.RefreshPlayerNet(MapData)returnsbool.- In multiplayer mode, every current lobby member must have a valid, non-duplicate
PlayerId. - Host resume/start must fail before assigning global
MapDataif player network mapping is invalid.
Main And UI
- Host start/resume snapshots
MapData,InputLogic,MapInteractionLogic, andMapGeneratorLogic. - Host
GameStartfailure must roll back and must not save, refresh turn, or report success. - Custom map load must check
mapRecord == nullbeforeRegenerateMap. UIOutsideMultiplayView.ShowLoadingAndStartGamemust only invokeOnStartGameafter the host start/resume method returnstrue.UIOutsideMultiplayView.StartGamemust gate host start/resume on lobby readiness.- Lobby UI should mutate member config through
MapConfigAPIs rather than directly editing sharedMemberCivinstances. - Timer callbacks for start announcements should be cancelled during abort paths.
ActionLogic
- Client
ActionConfirmfailure aborts local action execution. - Owner
ActionExecutebroadcast failure aborts owner local action execution. TurnEndcan send confirmation and stop local execution as designed.
Timer/Event Notes
- Timer callbacks should guard destroyed Unity targets.
- Timer mutation during callback must not remove the wrong task.
- Event publish should isolate listener exceptions so one bad listener does not block others.