1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Lockstep.mli *)typestats={stalls:int;dropped:int;inputs_sent:int}typet={inputs:Inputs.t;delay:int;(* the next tick to simulate *)mutabletick:int;mutablestalls:int;}letcreate~(me:int)~(players:int)~(delay:int):t={inputs=Inputs.create~me~players~delay;delay;tick=0;stalls=0}lettick(t:t):int=t.tick(* wait for every player's input of the tick: lockstep's one rule *)letstep(t:t)(input:string):stringarrayoption=letplayers=Inputs.playerst.inputsin(* no delay (1997's way): my input of this very tick is sent first,
* then the tick waits for everybody else's; kept as first read, since
* it may be sent already when the tick stalls *)ift.delay=0&&Inputs.findt.inputs~tick:t.tick(Inputs.met.inputs)=NonethenInputs.add_minet.inputs~tick:t.tickinput;ifList.for_all(funp->Inputs.known_uptot.inputsp>=t.tick)(List.initplayersFun.id)thenbeginletinputs=Array.initplayers(funp->Option.get(Inputs.findt.inputs~tick:t.tickp))inift.delay>0thenInputs.add_minet.inputs~tick:(t.tick+t.delay)input;t.tick<-t.tick+1;Someinputsendelsebegint.stalls<-t.stalls+1;Noneendletpacket(t:t):string=Inputs.packett.inputsletreceive(t:t)(bytes:string):unit=Inputs.receivet.inputsbytesletchecksum(t:t)~(tick:int)(sum:int32):unit=Inputs.checksumt.inputs~ticksumletdesync(t:t):(int*int)option=Inputs.desynct.inputsletstats(t:t):stats={stalls=t.stalls;dropped=Inputs.droppedt.inputs;inputs_sent=Inputs.inputs_sentt.inputs}