Agent Skills: Server Game Loop

Server-side game loop implementation with fixed timestep, physics simulation, and tick rate optimization

UncategorizedID: pluginagentmarketplace/custom-plugin-server-side-game-dev/game-loop

Skill Files

Browse the full folder contents for game-loop.

Download Skill

Loading file tree…

skills/game-loop/SKILL.md

Skill Metadata

Name
game-loop
Description
Server-side game loop implementation with fixed timestep, physics simulation, and tick rate optimization

Server Game Loop

Implement deterministic game loops with fixed timestep for consistent gameplay.

Fixed Timestep Loop

class GameLoop {
  constructor(tickRate = 60) {
    this.tickRate = tickRate;
    this.tickMs = 1000 / tickRate;
    this.tick = 0;
    this.running = false;
  }

  start() {
    this.running = true;
    this.lastTime = process.hrtime.bigint();
    this.accumulator = 0n;
    this.loop();
  }

  loop() {
    if (!this.running) return;

    const now = process.hrtime.bigint();
    const deltaNs = now - this.lastTime;
    this.lastTime = now;
    this.accumulator += deltaNs;

    const tickNs = BigInt(Math.round(this.tickMs * 1_000_000));
    let ticksProcessed = 0;

    while (this.accumulator >= tickNs && ticksProcessed < 5) {
      this.update(this.tickMs);
      this.tick++;
      this.accumulator -= tickNs;
      ticksProcessed++;
    }

    // Prevent spiral of death
    if (ticksProcessed === 5) {
      this.accumulator = 0n;
      console.warn('Tick catchup limit reached');
    }

    const sleepMs = Math.max(1, this.tickMs - Number(this.accumulator) / 1_000_000);
    setTimeout(() => this.loop(), sleepMs);
  }

  update(dt) {
    this.processInputs();
    this.updatePhysics(dt);
    this.updateEntities(dt);
    this.checkGameState();
    this.broadcastState();
  }
}

Tick Rate Guide

| Game Type | Rate | Budget | Rationale | |-----------|------|--------|-----------| | FPS | 60-128 Hz | 8-16ms | Hit precision | | MOBA | 30-60 Hz | 16-33ms | Balance | | BR | 20-30 Hz | 33-50ms | Scale | | MMO | 10-20 Hz | 50-100ms | Massive |

Performance Monitoring

class TickMetrics {
  constructor(size = 100) {
    this.samples = [];
    this.size = size;
  }

  record(ms) {
    this.samples.push(ms);
    if (this.samples.length > this.size) this.samples.shift();
  }

  stats() {
    const sorted = [...this.samples].sort((a, b) => a - b);
    return {
      avg: this.samples.reduce((a, b) => a + b, 0) / this.samples.length,
      p50: sorted[Math.floor(sorted.length * 0.5)],
      p99: sorted[Math.floor(sorted.length * 0.99)]
    };
  }
}

Troubleshooting

Common Failure Modes

| Error | Root Cause | Solution | |-------|------------|----------| | Tick spikes | GC pauses | Object pooling | | Drift | Float precision | Fixed-point math | | Explosion | Large dt | Cap dt value | | Stuttering | Variable tick | Fixed timestep |

Debug Checklist

const stats = metrics.stats();
console.log(`Avg: ${stats.avg.toFixed(2)}ms`);
console.log(`P99: ${stats.p99.toFixed(2)}ms`);
console.log(`Budget: ${(stats.avg / tickBudget * 100).toFixed(1)}%`);

Unit Test Template

describe('GameLoop', () => {
  test('maintains tick rate', async () => {
    const loop = new GameLoop(60);
    const ticks = [];

    loop.update = () => ticks.push(Date.now());
    loop.start();

    await new Promise(r => setTimeout(r, 100));
    loop.running = false;

    expect(ticks.length).toBeGreaterThan(4);
  });
});

Resources

  • assets/ - Loop templates
  • references/ - Optimization guides