#pragma once #include "state.h" #include "receiver.h" #include "time.h" #include "resource.h" #include "hostid.h" //########################################################################## //########################### Net clock ############################## //########################################################################## // // Aligning a peer's clock with ours, so a replicant is dead-reckoned from // when its update was SENT rather than when it happened to arrive. // // Every update record carries the sender's own timestamp. The receiver // used to throw it away and stamp lastUpdate with its own Now() - the // original code says so: "HACK - should be based upon message->timeStamp". // The dead reckoner then extrapolates over (lastPerformance - lastUpdate), // so starting that clock at ARRIVAL rather than at SEND leaves every // remote vehicle exactly one network latency behind where it should be. // On the 1 ms arcade LAN that was invisible. Over Steam Datagram Relay it // is a constant 50-150 ms of positional lag - a bias, not jitter. // // The timestamp cannot be used raw: two machines' clocks share no epoch, // both being QueryPerformanceCounter since their own boot. So we estimate // the offset per peer. Each arriving record gives // // sample = ourNow - theirStamp = trueOffset + oneWayLatency // // and since latency is never negative, the SMALLEST sample seen is the // closest to the true offset. Taking a minimum over a short rolling // window tracks crystal drift and re-adapts when the route changes, // instead of being pinned forever by one lucky packet. // // RP412NETCLOCK=0 turns the whole thing off and restores the arrival-time // behaviour, so a test machine can A/B it without a rebuild. // void NetClock_BeginUpdate(HostID sender); // around one message's records void NetClock_EndUpdate(); void NetClock_Reset(); // forget every peer (new mission) class Simulation__SharedData; class Simulation__IndexData; struct Simulation__IndexEntry; class Simulation__AttributeIndexSet; class MemoryStream; //########################################################################## //################# Simulation::UpdateRecord ######################### //########################################################################## struct Simulation__UpdateRecord { public: size_t recordLength; Word subsystemID; Word recordID; Time timeStamp; Enumeration simulationState; }; //########################################################################## //####################### Simulation ################################# //########################################################################## class Simulation: public Receiver { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Shared Data Support // public: typedef Simulation__SharedData SharedData; SharedData* GetSharedData(); static Derivation *GetClassDerivations(); static SharedData DefaultData; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Construction and Destruction Support // protected: Simulation( ClassID class_ID, SharedData &shared_data ); public: ~Simulation(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Attribute Support // public: typedef Enumeration AttributeID; typedef Simulation__IndexData IndexData; typedef Simulation__IndexEntry IndexEntry; typedef Simulation__AttributeIndexSet AttributeIndexSet; typedef int Simulation::*AttributePointer; enum { AnyAttributeID = 0, SimulationStateAttributeID, NextAttributeID }; static const AttributePointer NullAttribute; void* GetAttributePointer(AttributeID attribute); void* GetAttributePointer(const char* attribute_name); private: static const IndexEntry AttributePointers[]; protected: //static AttributeIndexSet AttributeIndex static AttributeIndexSet& GetAttributeIndex(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Simulation Support // public: typedef void (Simulation::*Performance)(Scalar time_slice); typedef void (Simulation::*Encore)(); typedef Simulation__UpdateRecord UpdateRecord; void SetPerformance(Performance performance) {Check(this); activePerformance = performance;} void Perform(Scalar time_slice) { Check(this); (this->*activePerformance)(time_slice); } virtual void PerformAndWatch( const Time& till, MemoryStream *update_stream ); void DoNothingOnce(Scalar time_slice); void DoNothing(Scalar time_slice); void SetLastPerformance(const Time& when) {Check(this); Check(&when); lastPerformance = when;} void RequestEncore(Encore encore); virtual void ReadUpdateRecord(UpdateRecord *message); virtual void WriteUpdateRecord( UpdateRecord *message, int update_model ); void WriteSimulationUpdate(MemoryStream *update_stream); enum { DefaultUpdateModelBit=0, NextUpdateModelBit }; enum { DefaultUpdateModelFlag = 1<= lastPerformance; } Logical IsNonReplicantExecutable() {Check(this); return (simulationFlags&DontExecuteFlag) == 0;} //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // State support // public: enum { DefaultState = 0, StateCount }; unsigned GetSimulationState() {Check(this); return simulationState.GetState();} unsigned GetOldSimulationState() {Check(this); return simulationState.GetOldState();} void SetSimulationState(unsigned new_state) {Check(this); simulationState.SetState(new_state);} StateIndicator simulationState; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Watcher Support // public: void AddAudioWatcher(Component *watcher) {Check(&audioWatcherSocket);audioWatcherSocket.Add(watcher);} void AddVideoWatcher(Component *watcher) {Check(&videoWatcherSocket);videoWatcherSocket.Add(watcher);} void AddGaugeWatcher(Component *watcher) {Check(&gaugeWatcherSocket);gaugeWatcherSocket.Add(watcher);} void AddEffectWatcher(Component *watcher) {Check(&effectWatcherSocket); effectWatcherSocket.Add(watcher);} void ExecuteWatchers(); private: SChainOf audioWatcherSocket; SChainOf videoWatcherSocket; SChainOf gaugeWatcherSocket; SChainOf effectWatcherSocket; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Test Support // public: Logical TestInstance() const; static Logical TestClass(); }; //########################################################################## //################### Simulation::IndexEntry ######################### //########################################################################## struct Simulation__IndexEntry { Enumeration entryID; const char * entryName; Simulation::AttributePointer entryAddress; }; #define ATTRIBUTE_ENTRY(class,name,attribute)\ {\ class::name##AttributeID,\ #name,\ (Simulation::AttributePointer) &class::attribute\ } //########################################################################## //################# Simulation::AttributeIndexSet #################### //########################################################################## class Simulation__AttributeIndexSet: public Receiver::InheritanceSet { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Construction and Destruction // public: Simulation__AttributeIndexSet( Simulation::AttributeID count, const Simulation::IndexEntry index_table[], const Simulation::AttributeIndexSet &inheritance ) {Build(count, index_table, &inheritance);} Simulation__AttributeIndexSet( Simulation::AttributeID count, const Simulation::IndexEntry index_table[] ) {Build(count, index_table, NULL);} Simulation__AttributeIndexSet() {attributeIndex = NULL; entryCount = 0;} ~Simulation__AttributeIndexSet(); protected: void Build( Simulation::AttributeID count, const Simulation::IndexEntry index_table[], const Simulation::AttributeIndexSet *inheritance ); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AttributeIndexSet Functionality // protected: Simulation::IndexEntry *attributeIndex; public: Simulation::AttributePointer Find(Simulation::AttributeID attribute) const { Check(this); Verify(attribute > 0); if (attribute<=entryCount) return attributeIndex[attribute-1].entryAddress; else return Simulation::NullAttribute; } Simulation::AttributePointer Find(const char* attribute_name) const; const Simulation::IndexEntry* FindEntry(const char* attribute_name) const; static const Simulation::AttributeIndexSet NullSet; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Test Support // public: static Logical TestClass(); }; //########################################################################## //################### Simulation::SharedData ######################### //########################################################################## class Simulation__SharedData: public Receiver::SharedData { public: Simulation__SharedData( Derivation* derivation, Receiver::MessageHandlerSet &message_handlers, Simulation::AttributeIndexSet &attribute_index, int state_count ): Receiver::SharedData(derivation, message_handlers), activeAttributeIndex(&attribute_index), stateCount(state_count) {} Simulation::AttributeIndexSet* activeAttributeIndex; int stateCount; }; inline Simulation::SharedData* Simulation::GetSharedData() {return Cast_Object(SharedData*,sharedData);}