egametang/ET · critical · Exception

frame out: , maxframe

Error message

frame out: {frame}, maxframe: {this.MaxFrame}

What it means

Thrown by FrameBuffer.EnsureFrame when a frame index is negative or exceeds MaxFrame. FrameBuffer is a ring buffer for lockstep simulation; MaxFrame starts at (initialFrame + 30s of frames) and advances via MoveForward one frame at a time. Accessing a frame beyond this ceiling means the buffer has not been extended to cover that simulation step yet.

Solutions

  1. Ensure MoveForward is called the correct number of times before accessing frames at the simulation frontier — the server must deliver frame data that triggers MaxFrame advancement.
  2. Verify the caller is not requesting a frame the simulation hasn't reached yet (add a CheckFrame guard before access).
  3. For replays, ensure MaxFrame is set high enough or the replay logic calls MoveForward incrementally.

Example fix

// before
public OneFrameInputs FrameInputs(int frame)
{
    EnsureFrame(frame);
    return this.frameInputs[frame % this.frameInputs.Capacity];
}
// after: caller checks first
if (!buffer.CheckFrame(frame))
{
    Log.Error($"frame {frame} out of range, max {buffer.MaxFrame}");
    return null;
}
Defensive patterns

Strategy: validation

Validate before calling

// Guard before accessing a frame in the buffer
if (!buffer.CheckFrame(frame))
{
    Log.Error($"Frame {frame} out of range, max {buffer.MaxFrame}");
    return; // or handle appropriately
}
var inputs = buffer.FrameInputs(frame);

Prevention

When it happens

Trigger: Calling FrameInputs, GetHash, SetHash, or Snapshot with a frame number greater than MaxFrame or less than 0. This happens when the lockstep simulation tries to read/write a future frame before MoveForward has been called enough times to extend the buffer, or when a desync/replay seeks to a frame the buffer doesn't cover.

Common situations: Lockstep simulation advances faster than MoveForward is called (server hasn't sent enough frame data). A replay system seeks to a frame beyond the buffer's MaxFrame. The buffer capacity (60s * frameRate) is too small for long matches and MaxFrame advancement logic has a bug. Negative frame from an underflow in frame arithmetic.

Related errors


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

Appendix: source

Thrown at Packages/cn.etetet.lockstep/Scripts/Model/Share/FrameBuffer.cs:63

        {
            if (frame < 0)
            {
                return false;
            }

            if (frame > this.MaxFrame)
            {
                return false;
            }

            return true;
        }

        private void EnsureFrame(int frame)
        {
            if (!CheckFrame(frame))
            {
                throw new Exception($"frame out: {frame}, maxframe: {this.MaxFrame}");
            }
        }
        
        public OneFrameInputs FrameInputs(int frame)
        {
            EnsureFrame(frame);
            OneFrameInputs oneFrameInputs = this.frameInputs[frame % this.frameInputs.Capacity];
            return oneFrameInputs;
        }

        public void MoveForward(int frame)
        {
            if (this.MaxFrame - frame > LSConstValue.FrameCountPerSecond) // 至少留出1秒的空间
            {
                return;
            }
            
            ++this.MaxFrame;

View on GitHub (pinned to 5cab01f7a8)