openclonk/src/control/C4Record.h

319 lines
7.9 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
// scenario record functionality
#ifndef INC_C4Record
#define INC_C4Record
class C4Record;
#include "c4group/C4Group.h"
#include "control/C4Control.h"
extern int DoNoDebugRec; // debugrec disable counter in C4Record.cpp
#define DEBUGREC_OFF ++DoNoDebugRec;
#define DEBUGREC_ON --DoNoDebugRec;
// turn off debugrecs in current block
class C4DebugRecOff
{
bool fDoOff;
public:
C4DebugRecOff();
C4DebugRecOff(bool fDoOff);
~C4DebugRecOff();
void Clear();
};
enum C4RecordChunkType // record file chunk type
{
RCT_Ctrl = 0x00, // control
RCT_CtrlPkt= 0x01, // control packet
RCT_Frame = 0x02, // beginning frame
RCT_End = 0x10, // --- the end ---
RCT_Log = 0x20, // log message
// Streaming
RCT_File = 0x30, // file data
// DEBUGREC
RCT_DbgFrame= 0x81, // frame start in Game::Execute
RCT_Block = 0x82, // point in Game::Execute
RCT_SetPix = 0x83, // set landscape pixel
RCT_ExecObj = 0x84, // exec object
RCT_Random = 0x85, // Random()-call
RCT_Rn3 = 0x86, // Rn3()-call
RCT_MMC = 0x87, // create MassMover
RCT_MMD = 0x88, // destroy MassMover
RCT_CrObj = 0x89, // create object
RCT_DsObj = 0x8A, // remove object
RCT_GetPix = 0x8B, // get landscape pixel; let the Gigas flow!
RCT_RotVtx1 = 0x8C, // before shape is rotated
RCT_RotVtx2 = 0x8D, // after shape is rotated
RCT_ExecPXS = 0x8E, // execute pxs system
RCT_Sin = 0x8F, // sin by Shape-Rotation
RCT_Cos = 0x90, // cos by Shape-Rotation
RCT_Map = 0x91, // map dump
RCT_Ls = 0x92, // complete landscape dump!
RCT_MCT1 = 0x93, // MapCreatorS2: before transformation
RCT_MCT2 = 0x94, // MapCreatorS2: after transformation
RCT_AulFunc = 0x9A, // script function call
RCT_ObjCom = 0x9B, // object com
RCT_PlrCom = 0x9C, // player com
RCT_PlrInCom= 0x9D, // player InCom
RCT_MatScan = 0x9E, // landscape scan execute
RCT_MatScanDo= 0x9F, // landscape scan mat change
RCT_Area = 0xA0, // object area change
RCT_MenuAdd = 0xA1, // add menu item
RCT_MenuAddC = 0xA2, // add menu item: Following commands
RCT_OCF = 0xA3, // OCF setting of updating
RCT_DirectExec = 0xA4, // a DirectExec-script
RCT_Definition = 0xA5, // Definition callback
RCT_SetProperty= 0xA6, // set a property in a proplist
RCT_Custom = 0xc0, // varies
RCT_Undefined = 0xff
};
void AddDbgRec(C4RecordChunkType eType, const void *pData=NULL, int iSize=0); // record debug stuff
#pragma pack(1)
struct C4RecordChunkHead // record file chunk head
{
uint8_t iFrm; // frame
uint8_t Type; // chunk type
};
struct C4RecordChunk
{
int32_t Frame;
uint8_t Type;
union
{
C4Control *pCtrl;
C4IDPacket *pPkt;
class C4PktDebugRec *pDbg;
StdBuf *pFileData;
};
StdCopyStrBuf Filename; // RCT_File only
public:
C4RecordChunk();
void Delete();
virtual void CompileFunc(StdCompiler *pComp);
virtual ~C4RecordChunk() {}
};
struct C4RCSetPix
{
int x,y; // pos
BYTE clr; // new fg color
BYTE bgClr; // new bg color
};
struct C4RCExecObj
{
int Number; // object number
C4Real fx,fy,fr;
};
struct C4RCMassMover
{
int x,y; // pos
};
struct C4RCRandom
{
int Cnt; // index in seed
uint32_t Range; // random range query
uint32_t Val; // random value
};
struct C4RCCreateObj
{
int oei;
char id[32+1];
int x,y,ownr;
};
struct C4RCSin
{
// value+return value
double v,r;
};
struct C4RCRotVtx
{
// shape size
int x,y,wdt,hgt,r;
// vertices
int VtxX[4], VtxY[4];
};
struct C4RCExecPXS
{
// pos
C4Real x,y;
// mat
int32_t iMat;
// execution pos
int32_t pos;
};
struct C4RCTrf
{
int x,y,Turbulence,Rotate;
};
struct C4RCPos
{
int x,y;
};
struct C4RCObjectCom
{
BYTE com;
int32_t data;
int32_t o;
};
struct C4RCMatScan
{
int32_t cx, cy, mat, conv_to, dir, mconvs;
};
struct C4RCArea
{
char op;
int32_t obj;
int32_t x1,y1, xL, yL, dpitch;
bool out;
};
struct C4RCMenuAdd
{
int32_t iObjNum;
int32_t iCount;
C4ID idID;
bool fOwnValue;
int32_t iValue;
bool fIsSelectable;
};
struct C4RCOCF
{
uint32_t dwOCFOld;
uint32_t dwOCFNew;
bool fUpdate;
};
#pragma pack()
// debug record packet
class C4PktDebugRec : public C4PktBuf
{
protected:
C4RecordChunkType eType;
public:
C4PktDebugRec() : C4PktBuf(), eType(RCT_Undefined) {}
C4PktDebugRec(const C4PktDebugRec &rCopy) : C4PktBuf(rCopy), eType(rCopy.eType) {}
C4PktDebugRec(C4RecordChunkType eType, const StdBuf &rCpyData)
: C4PktBuf(rCpyData), eType(eType) {}
C4RecordChunkType getType() const { return eType; }
virtual void CompileFunc(StdCompiler *pComp);
};
class C4Record // demo recording
{
private:
CStdFile CtrlRec; // control file handle
CStdFile LogRec; // handle for additional log file in record
StdStrBuf sFilename; // recorded scenario file name
C4Group RecordGrp; // record scenario group
bool fRecording; // set if recording is active
uint32_t iLastFrame; // frame of last chunk written
bool fStreaming; // perdiodically sent new control to server
unsigned int iStreamingPos; // Position of current buffer in stream
StdBuf StreamingData; // accumulated control data since last stream sync
public:
C4Record(); // constructor; creates control file etc
C4Record(const char *szPlaybackFile, const char *szRecordFile, const char *szTempRecFile); // start recording from replay into record
~C4Record(); // destructor; close file; create demo scen
int Index;
bool IsRecording() const { return fRecording; } // return whether Start() has been called
unsigned int GetStreamingPos() const { return iStreamingPos; }
const StdBuf &GetStreamingBuf() const { return StreamingData; }
bool Start(bool fInitial);
bool Stop(StdStrBuf *pRecordName = NULL, BYTE *pRecordSHA1 = NULL);
bool Rec(const C4Control &Ctrl, int iFrame); // record control
bool Rec(C4PacketType eCtrlType, C4ControlPacket *pCtrl, int iFrame); // record control packet
bool Rec(int iFrame, const StdBuf &sBuf, C4RecordChunkType eType);
bool AddFile(const char *szLocalFilename, const char *szAddAs, bool fDelete = false);
bool StartStreaming(bool fInitial);
void ClearStreamingBuf(unsigned int iAmount);
void StopStreaming();
CStdFile * GetLogFile() { return &LogRec; }
private:
void Stream(const C4RecordChunkHead &Head, const StdBuf &sBuf);
bool StreamFile(const char *szFilename, const char *szAddAs);
};
class C4Playback // demo playback
{
private:
typedef std::list<C4RecordChunk> chunks_t;
chunks_t chunks;
chunks_t::iterator currChunk;
bool Finished; // if set, free playback in next frame
CStdFile playbackFile; // if open, try reading additional chunks from this file
bool fLoadSequential; // used for debugrecs: Sequential reading of files
StdBuf sequentialBuffer; // buffer to manage sequential reads
uint32_t iLastSequentialFrame; // frame number of last chunk read
void Finish(); // end playback
C4PacketList DebugRec;
public:
C4Playback(); // constructor; init playback
~C4Playback(); // destructor; deinit playback
bool Open(C4Group &rGrp);
bool ReadBinary(const StdBuf &Buf);
bool ReadText(const StdStrBuf &Buf);
void NextChunk(); // point to next prepared chunk in mem or read it
bool NextSequentialChunk(); // read from seq file until a new chunk has been filled
StdStrBuf ReWriteText();
StdBuf ReWriteBinary();
void Strip();
bool ExecuteControl(C4Control *pCtrl, int iFrame); // assign control
bool IsFinished() { return Finished; }
void Clear();
void Check(C4RecordChunkType eType, const uint8_t *pData, int iSize); // compare with debugrec
void DebugRecError(const char *szError);
static bool StreamToRecord(const char *szStream, StdStrBuf *pRecord);
};
#endif