Back to Supersonic RC Revive
SOURCE / PINNED RELEASE

Made of little things.

Supersonic RC Revive

Release
1ba42f1ca1d6…
Author-recorded commit
baecad10b1cd…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.napplet.soy%2F/n-143146b0d6f

Archive hash verified: 90d22b206672eba4…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

tests/local-multiplayer.test.mjs
import assert from 'node:assert/strict';
import { before, after, test } from 'node:test';
import { createServer } from 'vite';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
let server, LocalMultiplayer, splitViewports, Input, App, DrivingManager;
before(async () => {
  server = await createServer({ logLevel: 'error', server: { middlewareMode: true }, appType: 'custom', optimizeDeps: { noDiscovery: true, entries: [] } });
  ({ LocalMultiplayer, splitViewports } = await server.ssrLoadModule('/src/game/localMultiplayer.ts'));
  ({ Input } = await server.ssrLoadModule('/src/game/input.ts'));
  ({ App } = await server.ssrLoadModule('/src/game/app.ts'));
  ({ DrivingManager } = await server.ssrLoadModule('/src/game/lingo/drivingManager.ts'));
  const { initPhysics } = await server.ssrLoadModule('/src/game/physics/havok.ts');
  // Exercise the optimized browser WASM too: source-only tests previously
  // missed removal helpers stripped by the production build.
  const { rapierKeepList, slimRapierWasm } = await server.ssrLoadModule('/tools/build/rapier-slim.ts');
  const raw = readFileSync('node_modules/@dimforge/rapier3d-compat/dist/rapier.mjs', 'utf8');
  const encoded = /[\w$]+\.toByteArray\("(AGFzbQ[A-Za-z0-9+/=]+)"\)/.exec(raw)?.[1];
  assert.ok(encoded, 'Rapier still embeds WASM in the expected format');
  const slim = slimRapierWasm(Buffer.from(encoded, 'base64'), rapierKeepList(resolve('.')));
  const instantiate = WebAssembly.instantiate;
  let optimized = false;
  WebAssembly.instantiate = (input, imports) => {
    optimized = true;
    return instantiate(slim, imports);
  };
  try { await initPhysics(); } finally { WebAssembly.instantiate = instantiate; }
  assert.ok(optimized, 'tests initialized the optimized WASM');
});
after(() => server?.close());
const identity = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
function level() {
  return {
    markers: { raymesh_models: ['floor'], car_hull: { node_matrix: identity, positions: [[-10,-20,-5],[10,-20,-5],[-10,20,-5],[10,20,-5],[-10,-20,5],[10,-20,5],[-10,20,5],[10,20,5]] }, level: [{name:'ssrc_start',matrix:[...identity.slice(0,12),0,0,40,1]}], car: [] },
    collision: { gravity: [0,0,-386], scale: 1, bodies: [] },
    rayMesh: { positions: new Float32Array([-1000,-1000,0,1000,-1000,0,1000,1000,0,-1000,1000,0]), indices: new Uint32Array([0,1,2,0,2,3]), owner: new Uint16Array([0,0]) },
  };
}
const action = (value = 0, pressed = false) => ({value, down: Math.abs(value) >= .5, pressed, released:false});
const controller = (index, throttle = 0, steering = 0) => ({index,id:`pad${index}`,mapped:true,mapping:'standard',actions:{accelerate:action(throttle),stickX:action(steering),menu:action()},buttons:[],axes:[]});
const frame = (players, more = {}) => ({status:'ready',players,connected:[],disconnected:[],...more});

test('hot-plug adds/removes independent cars, preserves slots and caps at four', () => {
  const local = new LocalMultiplayer(level(), null);
  try {
    local.updateControllers(frame([controller(2,1,-.7),controller(6,0,.8)]));
    assert.deepEqual(local.players.map(p=>[p.slot,p.controllerIndex]),[[0,2],[1,6]]);
    assert.equal(local.players[0].input.keyPressed(126),true);
    assert.equal(local.players[1].input.keyPressed(126),false);
    assert.equal(local.players[0].input.steerAxis(),-.7);
    assert.equal(local.players[1].input.steerAxis(),.8);
    const survivor = local.players[1], position = survivor.driver.car.rb.position;
    local.step(25);
    assert.equal(local.dm.milliseconds,25); // shared clock advances once, not per car
    local.updateControllers(frame([controller(6)]));
    assert.equal(local.players[0],survivor);
    assert.equal(survivor.slot,1);
    assert.ok(survivor.driver.car.rb.position.distanceTo(position) < 5);
    assert.equal(local.dm.players.length,1);
    assert.equal(local.dm.havokManager.havok.rigidBody('car-p1'),undefined);
    local.updateControllers(frame([controller(6),controller(7),controller(8),controller(9),controller(10)]));
    assert.equal(local.players.length,4);
    assert.equal(local.dm.players.length,4);
    assert.equal(new Set(local.players.map(p=>p.driver.car.rb.name)).size,4);
    for (let i=0;i<4;i++) for(let j=i+1;j<4;j++) assert.ok(local.players[i].driver.car.rb.position.distanceTo(local.players[j].driver.car.rb.position)>85);
    local.updateControllers(frame([controller(10)]));
    assert.equal(local.players.length,1); // waiting extra pad joins when a place opens
    assert.equal(local.players[0].controllerIndex,10);
    local.updateControllers(frame([]));
    assert.equal(local.players.length,0);
    assert.equal(local.dm.players.length,0);
  } finally { local.destroy(); }
});

test('focus loss clears input and pauses; replacement removes the old car; unavailable API preserves roster', () => {
  const local = new LocalMultiplayer(level(), null);
  try {
    local.updateControllers(frame([controller(0,1)]));
    const old = local.players[0];
    local.updateControllers(frame([controller(0)], {status:'inactive'}));
    assert.equal(local.paused,true);
    assert.equal(old.input.keyPressed(126),false);
    local.step(25);
    assert.equal(local.dm.milliseconds,0);
    local.updateControllers(frame([], {status:'blocked'}));
    assert.equal(local.players[0],old);
    local.updateControllers(frame([controller(0)], {disconnected:[0],connected:[0]}));
    assert.notEqual(local.players[0],old);
    const pad=controller(0); pad.actions.menu=action(1,true);
    local.updateControllers(frame([pad]));
    assert.equal(local.paused,false);
  } finally {local.destroy();}
});

test('all viewport layouts fit odd-sized frames without overlap', () => {
  for (const [w,h] of [[200,160],[320,560],[900,600],[1921,1081]]) for(let count=1;count<=4;count++) {
    const rects=splitViewports(count,w,h);
    assert.equal(rects.length,count);
    for (const a of rects) {assert.ok(a.width>0 && a.height>0);assert.ok(a.x+a.width<=w && a.y+a.height<=h);}
    for(let i=0;i<count;i++) for(let j=i+1;j<count;j++) {
      const a=rects[i],b=rects[j];
      assert.ok(a.x+a.width<=b.x || b.x+b.width<=a.x || a.y+a.height<=b.y || b.y+b.height<=a.y);
    }
  }
  assert.deepEqual(splitViewports(0,900,600),[]);
  assert.deepEqual(splitViewports(2,900,600),[
    {x:0,y:0,width:900,height:300},{x:0,y:300,width:900,height:300},
  ]);
  assert.deepEqual(splitViewports(3,900,600),[
    {x:0,y:0,width:450,height:300},{x:450,y:0,width:450,height:300},
    {x:0,y:300,width:450,height:300},
  ]);
  assert.deepEqual(splitViewports(4,900,600),[
    {x:0,y:0,width:450,height:300},{x:450,y:0,width:450,height:300},
    {x:0,y:300,width:450,height:300},{x:450,y:300,width:450,height:300},
  ]);
});

test('native polling hot-plugs 1 → 2 → 3 → 4 controllers with separate cars and cameras', () => {
  const saved = ['navigator','window'].map(key => [key,Object.getOwnPropertyDescriptor(globalThis,key)]);
  let samples = [];
  Object.defineProperty(globalThis,'navigator',{configurable:true,value:{getGamepads:()=>samples}});
  Object.defineProperty(globalThis,'window',{configurable:true,value:{addEventListener(){},removeEventListener(){},document:{hidden:false,hasFocus:()=>true,addEventListener(){},removeEventListener(){}}}});
  const input = new Input(), local = new LocalMultiplayer(level(),null);
  const pad = index => ({index,id:'Xbox controller',connected:true,mapping:'standard',axes:[index ? .8 : -.8,0,0,0],buttons:Array.from({length:17},(_,i)=>({value:i===0 && index===0 ? 1 : 0}))});
  try {
    for (let count=1;count<=4;count++) {
      // Browsers return sparse slots; multiple identical IDs must stay distinct.
      samples = Array.from({length:7},(_,i)=>i%2===0 && i/2<count ? pad(i) : null);
      const {frame}=input.pollGamepad(false,0,true);
      assert.equal(frame.status,'ready');
      local.updateControllers(frame);
      assert.equal(local.players.length,count);
      assert.equal(new Set(local.players.map(p=>p.driver.car)).size,count);
      assert.equal(new Set(local.players.map(p=>p.driver.camera)).size,count);
      assert.equal(local.players[0].input.keyPressed(126),true);
      for (const p of local.players.slice(1)) assert.equal(p.input.keyPressed(126),false);
      assert.equal(input.keyPressed(126),false,'session input must not merge player controls');
    }
    samples=[pad(0)];
    local.updateControllers(input.pollGamepad(false,0,true).frame);
    assert.equal(local.players.length,1);
  } finally {
    local.destroy();
    for (const [key,descriptor] of saved) {
      if (descriptor) Object.defineProperty(globalThis,key,descriptor);
      else delete globalThis[key];
    }
  }
});

test('player input ignores session Menu and clears held driving controls',()=>{
  const input=new Input(); const pad=controller(4,1,.6); pad.actions.menu=action(1,true);
  input.applyController(pad);
  assert.equal(input.keyPressed(53),false);
  input.clear();
  assert.equal(input.keyPressed(126),false);
  assert.equal(input.steerAxis(),0);
});

test('Free Driving automatically switches from merged input to separate cars on the second pad',()=>{
  const app=Object.create(App.prototype);
  const dm=new DrivingManager(level(),new Input());
  const position=dm.car.rb.position;
  app.race={name:'free_driving',dm,driving:true,sound:null};
  app.local=null;
  let current=frame([controller(0,1)]);
  app.input={pollGamepad:()=>({intents:[],waiting:false,frame:current})};
  app.screens={hideRace(){},navigate(){}};
  app.onStatus=()=>{};
  app.localStart=()=>{app.local=new LocalMultiplayer(level(),null);};
  try {
    app.pollGamepad(0);
    assert.equal(app.race.dm,dm,'one controller retains keyboard/touch Free Driving');
    current=frame([controller(0,1),controller(3,0,.8)]);
    app.pollGamepad(1);
    assert.equal(app.race,null);
    assert.equal(app.local.players.length,2);
    assert.ok(app.local.players[0].driver.car.rb.position.distanceTo(position)<.001);
    assert.notEqual(app.local.players[0].driver.camera,app.local.players[1].driver.camera);
    assert.equal(app.local.players[0].input.keyPressed(126),true);
    assert.equal(app.local.players[1].input.keyPressed(126),false);
    app.input.keyPressed=()=>false;
    for (let count=3;count<=4;count++) {
      current=frame(Array.from({length:count},(_,i)=>controller(i===0?0:i+2)));
      app.pollGamepad(count);
      assert.equal(app.local.players.length,count);
    }
  } finally {if(app.local) app.local.destroy();else dm.destroy();}
});

test('unmapped controllers are reported even when none can join',()=>{
  const local=new LocalMultiplayer(level(),null);
  try {
    const pad=controller(2);pad.mapped=false;pad.mapping='';
    local.updateControllers(frame([pad]));
    assert.equal(local.players.length,0);
    assert.match(local.status,/Controller 3 detected without a supported mapping/);
  } finally {local.destroy();}
});