egametang/ET · error · Exception

player not in wait list: {playerId}

Error message

player not in wait list: {playerId}

What it means

Thrown by MapCopy.AddPlayer when the playerId is not found in the WaitEnterPlayer dictionary (Remove returns false). The contract is: a player must first be added via AddWaitPlayer before AddPlayer is called. If AddPlayer is called for a player not in the wait list, or one that was already moved/removed, the exception fires.

Source

Thrown at Packages/cn.etetet.mapmanager/Scripts/Hotfix/Server/MapManagerComponentSystem.cs:25

    [EntitySystemOf(typeof(MapCopy))]
    public static partial class MapCopySystem
    {
        [EntitySystem]
        private static void Destroy(this MapCopy self)
        {
            self.Fiber().RemoveFiber(self.FiberId).Coroutine();
        }
        [EntitySystem]
        private static void Awake(this MapCopy self, long fiberId)
        {
            self.FiberId = fiberId;
        }

        public static void AddPlayer(this MapCopy self, long playerId)
        {
            if (!self.WaitEnterPlayer.Remove(playerId))
            {
                throw new Exception($"player not in wait list: {playerId}");
            }
            self.Players.Add(playerId);
        }

        public static void AddWaitPlayer(this MapCopy self, long playerId)
        {
            self.WaitEnterPlayer.Add(playerId, self.GetSingleton<TimeInfo>().ServerNow());
        }
    }

    [EntitySystemOf(typeof(MapInfo))]
    public static partial class MapInfoSystem
    {
        [EntitySystem]
        private static void Awake(this MapInfo self, string mapName)
        {
            self.MapName = mapName;
        }

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Ensure AddWaitPlayer(playerId) is always called before AddPlayer(playerId) in the map copy lifecycle.
  2. Guard with ContainsKey before AddPlayer, or make AddPlayer idempotent by checking if the player is already in Players.
  3. Investigate race conditions if multiple fibers can process enter-requests for the same player simultaneously.

Example fix

// before
public static void AddPlayer(this MapCopy self, long playerId)
{
    if (!self.WaitEnterPlayer.Remove(playerId))
        throw new Exception($"player not in wait list: {playerId}");
    self.Players.Add(playerId);
}
// after: idempotent guard
public static void AddPlayer(this MapCopy self, long playerId)
{
    if (self.Players.Contains(playerId))
        return; // already added
    if (!self.WaitEnterPlayer.Remove(playerId))
    {
        Log.Error($"player not in wait list: {playerId}");
        return;
    }
    self.Players.Add(playerId);
}
Defensive patterns

Strategy: validation

Validate before calling

// Before calling AddPlayer, verify the player is in the wait list
if (!self.WaitEnterPlayer.ContainsKey(playerId))
{
    if (self.Players.Contains(playerId))
    {
        Log.Warning($"Player {playerId} already in map copy, skipping");
        return;
    }
    Log.Error($"Player {playerId} not in wait list and not already added");
    return;
}

Prevention

When it happens

Trigger: AddPlayer(playerId) is called without a prior AddWaitPlayer(playerId). Or AddPlayer is called twice for the same player (the first removes them from WaitEnterPlayer, the second fails). Or the player was removed from the wait list by another path before AddPlayer was called.

Common situations: A player enters a map copy without going through the wait-list registration flow. Race condition: two enter-requests for the same player processed concurrently. Player was kicked/timed-out from the wait list before the enter message arrived. Stale duplicate enter request after the player already entered.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/e045698f6ef8d25f. Report an issue: GitHub.