forked from Mirrors/openclonk
288 lines
8.3 KiB
C++
288 lines
8.3 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.
|
|
*/
|
|
#include "control/C4GameControl.h"
|
|
|
|
#ifndef INC_C4GameControlNetwork
|
|
#define INC_C4GameControlNetwork
|
|
|
|
#include "control/C4Control.h"
|
|
#include "network/C4Network2.h"
|
|
#include "network/C4PacketBase.h"
|
|
|
|
// constants
|
|
const int32_t C4ControlBacklog = 100, // (ctrl ticks)
|
|
C4ClientIDAll = C4ClientIDUnknown,
|
|
C4ControlOverflowLimit = 3, // (ctrl ticks)
|
|
C4MaxPreSend = 15; // (frames) - must be smaller than C4ControlBacklog!
|
|
|
|
const uint32_t C4ControlRequestInterval = 2000; // (ms)
|
|
|
|
enum C4GameControlNetworkMode
|
|
{
|
|
CNM_Decentral = 0, // 0 is the standard mode set in config
|
|
CNM_Central = 1,
|
|
CNM_Async = 2
|
|
};
|
|
|
|
// declarations
|
|
class C4GameControlPacket; class C4GameControlClient;
|
|
class C4PacketControlReq; class C4ClientList;
|
|
|
|
// main class
|
|
class C4GameControlNetwork // run by network thread
|
|
{
|
|
public:
|
|
C4GameControlNetwork(class C4GameControl *pParent);
|
|
~C4GameControlNetwork();
|
|
|
|
protected:
|
|
volatile bool fEnabled, fRunning;
|
|
|
|
// local status
|
|
int32_t iClientID;
|
|
bool fHost, fActivated;
|
|
C4GameControlNetworkMode eMode;
|
|
int32_t iTargetTick;
|
|
|
|
// options
|
|
volatile int32_t iControlPreSend;
|
|
|
|
// statistics
|
|
|
|
|
|
// time started to wait.
|
|
C4TimeMilliseconds tWaitStart;
|
|
|
|
int32_t iAvgControlSendTime;
|
|
int32_t iTargetFPS; // used for PreSend-colculation
|
|
|
|
// control send / recv status
|
|
volatile int32_t iControlSent, iControlReady;
|
|
|
|
// control list
|
|
C4GameControlPacket *pCtrlStack;
|
|
CStdCSec CtrlCSec;
|
|
|
|
// list of clients (activated only!)
|
|
C4GameControlClient *pClients;
|
|
CStdCSec ClientsCSec;
|
|
|
|
// holds control that needs to be executed synchronized (main thread only)
|
|
C4Control SyncControl;
|
|
C4GameControlPacket *pSyncCtrlQueue;
|
|
|
|
// control request timing
|
|
C4TimeMilliseconds tNextControlRequest;
|
|
|
|
// links
|
|
C4GameControl *const pParent;
|
|
C4Network2 *pNetwork;
|
|
|
|
public:
|
|
bool IsEnabled() const { return fEnabled; }
|
|
bool IsRunning() const { return fRunning; }
|
|
bool IsActivated() const { return fActivated; }
|
|
|
|
int32_t getControlPreSend() const { return iControlPreSend; }
|
|
void setControlPreSend(int32_t iToVal) { iControlPreSend = std::min(iToVal, C4MaxPreSend); }
|
|
int32_t getAvgControlSendTime() const { return iAvgControlSendTime; }
|
|
void setTargetFPS(int32_t iToVal) { iTargetFPS = iToVal; }
|
|
|
|
// main thread communication
|
|
bool Init(int32_t iClientID, bool fHost, int32_t iStartTick, bool fActivated, C4Network2 *pNetwork); // by main thread
|
|
void Clear(); // by main thread
|
|
|
|
void Execute(); // by main thread
|
|
bool CtrlReady(int32_t iTick); // by main thread
|
|
bool CtrlOverflow(int32_t iTick) const { return fRunning && iControlReady >= iTick + C4ControlOverflowLimit; } // by main thread
|
|
int32_t GetBehind(int32_t iTick) const { return iControlReady - iTick + 1; } // by main thread
|
|
bool GetControl(C4Control *pCtrl, int32_t iTick); // by main thread
|
|
bool ClientReady(int32_t iClientID, int32_t iTick); // by main thread
|
|
int32_t ClientPerfStat(int32_t iClientID); // by main thread
|
|
int32_t ClientNextControl(int32_t iClientID); // by main thread
|
|
|
|
bool CtrlNeeded(int32_t iTick) const; // by main thread
|
|
void DoInput(const C4Control &Input); // by main thread
|
|
void DoInput(C4PacketType eCtrlType, C4ControlPacket *pPkt, enum C4ControlDeliveryType eType); // by main thread
|
|
|
|
// sync control
|
|
C4ControlDeliveryType DecideControlDelivery() const; // by main thread
|
|
void ExecSyncControl(); // by main thread
|
|
void ExecSyncControl(int32_t iControlTick); // by main thread
|
|
|
|
// clients
|
|
void CopyClientList(const C4ClientList &rClients);
|
|
|
|
// pausing
|
|
void SetRunning(bool fnRunning, int32_t inTargetTick = -1); // by main thread
|
|
void SetActivated(bool fnActivated); // by main thread
|
|
void SetCtrlMode(C4GameControlNetworkMode enMode); // by main thread
|
|
C4GameControlNetworkMode GetCtrlMode() const { return eMode; } // by main thread
|
|
|
|
// performance
|
|
void CalcPerformance(int32_t iCtrlTick); // by main thread
|
|
|
|
// interfaces
|
|
void HandlePacket(char cStatus, const C4PacketBase *pPacket, C4Network2IOConnection *pConn);
|
|
void OnResComplete(C4Network2Res *pRes);
|
|
|
|
protected:
|
|
|
|
// clients
|
|
void AddClient(int32_t iClientID, const char *szName); // by main thread
|
|
void RemoveClient(int32_t iClientID); // by main thread
|
|
void ClearClients(); // by main thread
|
|
|
|
// packet handling
|
|
void HandleControl(int32_t iByClientID, const C4GameControlPacket &rPkt);
|
|
void HandleControlReq(const C4PacketControlReq &rPkt, C4Network2IOConnection *pConn);
|
|
void HandleControlPkt(C4PacketType eCtrlType, C4ControlPacket *pPkt, enum C4ControlDeliveryType eType);
|
|
|
|
// client list
|
|
C4GameControlClient *getClient(int32_t iID);
|
|
void AddClient(C4GameControlClient *pClient);
|
|
void RemoveClient(C4GameControlClient *pClient);
|
|
|
|
// control stack
|
|
C4GameControlPacket *getCtrl(int32_t iClientID, int32_t iCtrlTick); // by both
|
|
void AddCtrl(C4GameControlPacket *pCtrl);
|
|
void ClearCtrl(int32_t iBeforeTick = -1);
|
|
void CheckCompleteCtrl(bool fSetEvent); // by both
|
|
C4GameControlPacket *PackCompleteCtrl(int32_t iTick); // by main thread
|
|
|
|
// sync control
|
|
void AddSyncCtrlToQueue(const C4Control &Ctrl, int32_t iTick); // by main thread
|
|
void ExecQueuedSyncCtrl(); // by main thread
|
|
|
|
};
|
|
|
|
class C4GameControlPacket : public C4PacketBase
|
|
{
|
|
friend class C4GameControlNetwork;
|
|
public:
|
|
C4GameControlPacket();
|
|
|
|
// needed as C4Control doesn't seem to implement correct copying behavior
|
|
C4GameControlPacket(const C4GameControlPacket &Pkt2);
|
|
C4GameControlPacket &operator = (const C4GameControlPacket &Pkt2);
|
|
|
|
protected:
|
|
// header
|
|
int32_t iClientID, iCtrlTick{-1};
|
|
C4TimeMilliseconds tTime;
|
|
|
|
// data
|
|
C4Control Ctrl;
|
|
|
|
// list (C4GameControlNetwork)
|
|
C4GameControlPacket *pNext{nullptr};
|
|
|
|
public:
|
|
int32_t getClientID() const { return iClientID; }
|
|
int32_t getCtrlTick() const { return iCtrlTick; }
|
|
C4TimeMilliseconds getTime() const { return tTime; }
|
|
const C4Control &getControl() const { return Ctrl; }
|
|
|
|
void Set(int32_t iClientID, int32_t iCtrlTick);
|
|
void Set(int32_t iClientID, int32_t iCtrlTick, const C4Control &Ctrl);
|
|
void Add(const C4GameControlPacket &Ctrl);
|
|
|
|
void CompileFunc(StdCompiler *pComp) override;
|
|
};
|
|
|
|
class C4GameControlClient
|
|
{
|
|
friend class C4GameControlNetwork;
|
|
public:
|
|
C4GameControlClient();
|
|
|
|
protected:
|
|
// core data
|
|
int32_t iClientID;
|
|
char szName[C4MaxName + 1];
|
|
|
|
// next expected control for this client
|
|
int32_t iNextControl{0};
|
|
|
|
// performance data
|
|
int32_t iPerformance{0};
|
|
|
|
// list (C4GameControl)
|
|
C4GameControlClient *pNext;
|
|
|
|
public:
|
|
int32_t getClientID() const { return iClientID; }
|
|
const char *getName() const { return szName; }
|
|
int32_t getNextControl() const { return iNextControl; }
|
|
int32_t getPerfStat() const;
|
|
|
|
void Set(int32_t iClientID, const char *szName);
|
|
void SetNextControl(int32_t inNextControl) { iNextControl = inNextControl; }
|
|
void AddPerf(int32_t iTime);
|
|
};
|
|
|
|
// * Packet classes *
|
|
|
|
class C4PacketControlReq : public C4PacketBase
|
|
{
|
|
public:
|
|
C4PacketControlReq(int32_t iCtrlTick = -1);
|
|
|
|
protected:
|
|
int32_t iCtrlTick;
|
|
|
|
public:
|
|
int32_t getCtrlTick() const { return iCtrlTick; }
|
|
|
|
void CompileFunc(StdCompiler *pComp) override;
|
|
};
|
|
|
|
class C4PacketControlPkt : public C4PacketBase
|
|
{
|
|
public:
|
|
C4PacketControlPkt() = default;
|
|
C4PacketControlPkt(enum C4ControlDeliveryType eDelivery, const C4IDPacket &Ctrl)
|
|
: eDelivery(eDelivery), Ctrl(Ctrl)
|
|
{ }
|
|
|
|
protected:
|
|
enum C4ControlDeliveryType eDelivery{CDT_Queue};
|
|
C4IDPacket Ctrl;
|
|
|
|
public:
|
|
C4ControlDeliveryType getDelivery() const { return eDelivery; }
|
|
const C4IDPacket &getCtrl() const { return Ctrl; }
|
|
|
|
void CompileFunc(StdCompiler *pComp) override;
|
|
};
|
|
|
|
class C4PacketExecSyncCtrl : public C4PacketBase
|
|
{
|
|
public:
|
|
C4PacketExecSyncCtrl(int32_t iControlTick = ~0) : iControlTick(iControlTick) { }
|
|
|
|
protected:
|
|
int32_t iControlTick;
|
|
|
|
public:
|
|
int32_t getControlTick() const { return iControlTick; }
|
|
|
|
void CompileFunc(StdCompiler *pComp) override { pComp->Value(mkNamingAdapt(iControlTick, "ControlTick", -1)); }
|
|
};
|
|
|
|
|
|
#endif // INC_C4GameControlNetwork
|