forked from Mirrors/openclonk
450 lines
14 KiB
C++
450 lines
14 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.
|
|
*/
|
|
#ifndef INC_C4Network2
|
|
#define INC_C4Network2
|
|
|
|
#include "network/C4NetIO.h"
|
|
#include "network/C4Network2Players.h"
|
|
#include "network/C4Network2IO.h"
|
|
#include "network/C4Network2Res.h"
|
|
#include "network/C4Network2Client.h"
|
|
#include "control/C4Control.h"
|
|
#include "gui/C4Gui.h"
|
|
#include "control/C4GameParameters.h"
|
|
|
|
// standard ports
|
|
const int16_t C4NetStdPortTCP = 11112,
|
|
C4NetStdPortUDP = 11113,
|
|
C4NetStdPortDiscovery = 11114,
|
|
C4NetStdPortRefServer = 11111,
|
|
C4NetStdPortPuncher = 11115,
|
|
C4NetStdPortHTTP = 80;
|
|
|
|
// resource retrieve wait timeout
|
|
const int C4NetResRetrieveTimeout = 100000; // (ms)
|
|
|
|
// client (de)activation
|
|
const int C4NetActivationReqInterval = 5000, // (ms)
|
|
C4NetMaxBehind4Activation = 20, // (ticks)
|
|
C4NetDeactivationDelay = 500; // (ticks)
|
|
|
|
// client chase
|
|
const unsigned int C4NetChaseTargetUpdateInterval = 5; // (s)
|
|
|
|
// reference
|
|
const unsigned int C4NetReferenceUpdateInterval = 120; // (s)
|
|
const unsigned int C4NetMinLeagueUpdateInterval = 1; // (s)
|
|
|
|
// voting
|
|
const unsigned int C4NetVotingTimeout = 10; // (s)
|
|
const unsigned int C4NetMinVotingInterval = 120; // (s)
|
|
|
|
// streaming
|
|
const size_t C4NetStreamingMinBlockSize = 10 * 1024;
|
|
const size_t C4NetStreamingMaxBlockSize = 20 * 1024;
|
|
const int C4NetStreamingInterval = 30; // (s)
|
|
|
|
enum C4NetGameState
|
|
{
|
|
GS_None, // network not active
|
|
GS_Init, // connecting to host, waiting for join data
|
|
GS_Lobby, // lobby mode
|
|
GS_Pause, // game paused
|
|
GS_Go // game running
|
|
};
|
|
|
|
class C4Network2Status : public C4PacketBase
|
|
{
|
|
public:
|
|
C4Network2Status();
|
|
|
|
protected:
|
|
C4NetGameState eState;
|
|
int32_t iCtrlMode;
|
|
int32_t iTargetCtrlTick;
|
|
|
|
public:
|
|
C4NetGameState getState() const { return eState; }
|
|
int32_t getCtrlMode() const { return iCtrlMode; }
|
|
int32_t getTargetCtrlTick() const { return iTargetCtrlTick; }
|
|
const char *getStateName() const;
|
|
const char *getDescription() const;
|
|
|
|
bool isEnabled() const { return eState != GS_None; }
|
|
bool isLobbyActive() const { return eState == GS_Lobby; }
|
|
bool isPastLobby() const { return eState > GS_Lobby; }
|
|
bool isPaused() const { return eState == GS_Pause; }
|
|
bool isRunning() const { return eState == GS_Go; }
|
|
|
|
void Set(C4NetGameState eState, int32_t iTargetCtrlTick);
|
|
void SetCtrlMode(int32_t iCtrlMode);
|
|
void SetTargetTick(int32_t iTargetCtrlTick);
|
|
void Clear();
|
|
|
|
void CompileFunc(StdCompiler *pComp, bool fReference);
|
|
virtual void CompileFunc(StdCompiler *pComp);
|
|
};
|
|
|
|
class C4Network2 : private C4ApplicationSec1Timer
|
|
{
|
|
friend class C4Network2IO;
|
|
public:
|
|
C4Network2();
|
|
virtual ~C4Network2();
|
|
|
|
public:
|
|
// network i/o class
|
|
C4Network2IO NetIO;
|
|
|
|
// resource list
|
|
C4Network2ResList ResList;
|
|
|
|
// client list
|
|
C4Network2ClientList Clients;
|
|
|
|
// player list
|
|
C4Network2Players Players;
|
|
|
|
// game status
|
|
C4Network2Status Status;
|
|
|
|
protected:
|
|
|
|
// role
|
|
bool fHost;
|
|
|
|
// options
|
|
bool fAllowJoin, fAllowObserve;
|
|
|
|
// join resource
|
|
C4Network2ResCore ResDynamic;
|
|
|
|
// resources
|
|
int32_t iDynamicTick;
|
|
bool fDynamicNeeded;
|
|
|
|
// game status flags
|
|
bool fStatusAck, fStatusReached;
|
|
bool fChasing;
|
|
|
|
// control
|
|
class C4GameControlNetwork *pControl;
|
|
|
|
// lobby
|
|
C4GameLobby::MainDlg *pLobby;
|
|
bool fLobbyRunning;
|
|
C4GameLobby::Countdown *pLobbyCountdown;
|
|
|
|
// master server used
|
|
StdCopyStrBuf MasterServerAddress;
|
|
|
|
// clients
|
|
int32_t iNextClientID;
|
|
|
|
// chase
|
|
uint32_t iLastChaseTargetUpdate;
|
|
|
|
// time of last activation request.
|
|
C4TimeMilliseconds tLastActivateRequest;
|
|
|
|
// reference
|
|
uint32_t iLastReferenceUpdate;
|
|
uint32_t iLastLeagueUpdate, iLeagueUpdateDelay;
|
|
bool fLeagueEndSent;
|
|
|
|
// league
|
|
class C4LeagueClient *pLeagueClient;
|
|
|
|
// game password
|
|
StdStrBuf sPassword;
|
|
|
|
// connection failed because password needed?
|
|
bool fWrongPassword;
|
|
|
|
// delayed activation request?
|
|
bool fDelayedActivateReq;
|
|
|
|
// voting
|
|
C4Control Votes;
|
|
class C4VoteDialog *pVoteDialog;
|
|
bool fPausedForVote;
|
|
time_t iVoteStartTime, iLastOwnVoting;
|
|
|
|
// streaming
|
|
bool fStreaming;
|
|
time_t iLastStreamAttempt;
|
|
C4Record *pStreamedRecord;
|
|
StdBuf StreamingBuf;
|
|
z_stream StreamCompressor;
|
|
|
|
class C4Network2HTTPClient *pStreamer;
|
|
unsigned int iCurrentStreamAmount, iCurrentStreamPosition;
|
|
|
|
// puncher
|
|
C4NetpuncherID NetpuncherGameID;
|
|
StdCopyStrBuf NetpuncherAddr;
|
|
|
|
public:
|
|
|
|
// data access
|
|
bool isEnabled() const { return Status.isEnabled(); }
|
|
bool isLobbyActive()const { return Status.isLobbyActive(); }
|
|
bool isPastLobby() const { return Status.isPastLobby(); }
|
|
bool isRunning() const { return Status.isRunning() && isStatusAck(); }
|
|
bool isPaused() const { return Status.isPaused() && isStatusAck(); }
|
|
bool isPausing() const { return Status.isPaused() && !fStatusAck; }
|
|
bool isHost() const { return fHost; }
|
|
bool isStatusAck() const { return fStatusAck; }
|
|
bool isFrozen() const;
|
|
|
|
bool isJoinAllowed() const { return fAllowJoin; }
|
|
bool isObservingAllowed() const { return fAllowObserve; }
|
|
|
|
class C4GameLobby::MainDlg *GetLobby() const { return pLobby; } // lobby publication
|
|
const char *GetPassword() const { return sPassword.getData(); } // Oh noez, now the password is public!
|
|
bool isPassworded() const { return !sPassword.isNull(); }
|
|
|
|
// initialization result type
|
|
enum InitResult
|
|
{
|
|
IR_Success, IR_Error, IR_Fatal
|
|
};
|
|
|
|
// initialization
|
|
bool InitHost(bool fLobby);
|
|
InitResult InitClient(const class C4Network2Reference &Ref, bool fObserver);
|
|
InitResult InitClient(const class C4Network2Address *pAddrs, int iAddrCount, const class C4ClientCore &HostCore, const char *szPassword = nullptr);
|
|
bool DoLobby();
|
|
bool Start();
|
|
bool Pause();
|
|
bool Sync();
|
|
bool FinalInit();
|
|
|
|
bool RetrieveScenario(char *szScenario);
|
|
C4Network2Res::Ref RetrieveRes(const C4Network2ResCore &Core, int32_t iTimeout, const char *szResName, bool fWaitForCore = false);
|
|
|
|
// idle processes
|
|
void OnSec1Timer();
|
|
void Execute();
|
|
|
|
// termination
|
|
void Clear();
|
|
|
|
// some options
|
|
bool ToggleAllowJoin();
|
|
bool ToggleClientListDlg();
|
|
void AllowJoin(bool fAllow);
|
|
void SetAllowObserve(bool fAllow);
|
|
void SetCtrlMode(int32_t iCtrlMode);
|
|
void SetPassword(const char *szToPassword);
|
|
StdStrBuf QueryClientPassword(); // ask client for a password; empty if user canceled
|
|
|
|
// interface for C4Network2IO
|
|
void OnConn(C4Network2IOConnection *pConn);
|
|
void OnDisconn(C4Network2IOConnection *pConn);
|
|
void HandlePacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn);
|
|
void HandleLobbyPacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn);
|
|
bool HandlePuncherPacket(C4NetpuncherPacket::uptr, C4NetIO::HostAddress::AddressFamily family);
|
|
|
|
// runtime join stuff
|
|
void OnGameSynchronized();
|
|
|
|
// status
|
|
void DrawStatus(C4TargetFacet &cgo);
|
|
|
|
// client activation
|
|
void RequestActivate();
|
|
void DeactivateInactiveClients(); // host
|
|
|
|
// league
|
|
void LeagueGameEvaluate(const char *szRecordName = nullptr, const BYTE *pRecordSHA = nullptr);
|
|
void LeagueSignupDisable(); // if "internet game" button is switched off in lobby: Remove from league server
|
|
bool LeagueSignupEnable(); // if "internet game" button is switched on in lobby: (re)Add to league server
|
|
void InvalidateReference(); // forces a recreation and re-send of the game reference in the next execution cycle
|
|
bool LeaguePlrAuth(C4PlayerInfo *pInfo); // client: get authentication for a player from the league server
|
|
bool LeaguePlrAuthCheck(C4PlayerInfo *pInfo); // host: check AUID of player info with league server
|
|
void LeagueNotifyDisconnect(int32_t iClientID, enum C4LeagueDisconnectReason eReason); //
|
|
void LeagueWaitNotBusy(); // block until league serveris no longer busy. Process update reply if last message was an update
|
|
void LeagueSurrender(); // forfeit in league - just fake a disconnect
|
|
void LeagueShowError(const char *szMsg); // show league error msg box in fullscreen; just log in console
|
|
|
|
// voting
|
|
void Vote(C4ControlVoteType eType, bool fApprove = true, int32_t iData = 0);
|
|
void AddVote(const C4ControlVote &Vote);
|
|
C4IDPacket *GetVote(int32_t iClientID, C4ControlVoteType eType, int32_t iData);
|
|
void EndVote(C4ControlVoteType eType, bool fApprove, int32_t iData);
|
|
void OpenVoteDialog();
|
|
void OpenSurrenderDialog(C4ControlVoteType eType, int32_t iData);
|
|
void OnVoteDialogClosed();
|
|
|
|
// lobby countdown
|
|
void StartLobbyCountdown(int32_t iCountdownTime);
|
|
void AbortLobbyCountdown();
|
|
bool isLobbyCountDown() { return pLobbyCountdown != 0; }
|
|
|
|
// streaming
|
|
size_t getPendingStreamData() const { return StreamingBuf.getSize() - StreamCompressor.avail_out; }
|
|
bool isStreaming() const;
|
|
bool StartStreaming(C4Record *pRecord);
|
|
bool FinishStreaming();
|
|
bool StopStreaming();
|
|
|
|
// netpuncher
|
|
C4NetpuncherID::value& getNetpuncherGameID(C4NetIO::HostAddress::AddressFamily family);
|
|
C4NetpuncherID getNetpuncherGameID() const { return NetpuncherGameID; };
|
|
StdStrBuf getNetpuncherAddr() const { return NetpuncherAddr; }
|
|
|
|
protected:
|
|
|
|
using C4ApplicationSec1Timer::Execute; // to avoid "virtual ... is hidden" warning
|
|
|
|
// net i/o initialization
|
|
bool InitNetIO(bool fNoClientID, bool fHost);
|
|
|
|
// handling of own packets
|
|
void HandleConn(const class C4PacketConn &Pkt, C4Network2IOConnection *pConn, C4Network2Client *pClient);
|
|
bool CheckConn(const C4ClientCore &CCore, C4Network2IOConnection *pConn, C4Network2Client *pClient, StdStrBuf * szReply);
|
|
bool HostConnect(const C4ClientCore &CCore, C4Network2IOConnection *pConn, StdStrBuf *szReply);
|
|
bool Join(C4ClientCore &CCore, C4Network2IOConnection *pConn, StdStrBuf *szReply);
|
|
void HandleConnRe(const class C4PacketConnRe &Pkt, C4Network2IOConnection *pConn, C4Network2Client *pClient);
|
|
void HandleStatus(const C4Network2Status &nStatus);
|
|
void HandleStatusAck(const C4Network2Status &nStatus, C4Network2Client *pClient);
|
|
void HandleActivateReq(int32_t iTick, C4Network2Client *pClient);
|
|
void HandleJoinData(const class C4PacketJoinData &rPkt);
|
|
|
|
// events
|
|
void OnConnect(C4Network2Client *pClient, C4Network2IOConnection *pConn, const char *szMsg, bool fFirstConnection);
|
|
void OnConnectFail(C4Network2IOConnection *pConn);
|
|
void OnDisconnect(C4Network2Client *pClient, C4Network2IOConnection *pConn);
|
|
void OnClientConnect(C4Network2Client *pClient, C4Network2IOConnection *pConn);
|
|
void OnClientDisconnect(C4Network2Client *pClient);
|
|
|
|
void SendJoinData(C4Network2Client *pClient);
|
|
|
|
// resource list
|
|
bool CreateDynamic(bool fInit);
|
|
void RemoveDynamic();
|
|
|
|
// status changes
|
|
bool PauseGame(bool fAutoContinue);
|
|
bool ChangeGameStatus(C4NetGameState enState, int32_t iTargetCtrlTick, int32_t iCtrlMode = -1);
|
|
void CheckStatusReached(bool fFromFinalInit = false);
|
|
void CheckStatusAck();
|
|
void OnStatusReached();
|
|
void OnStatusAck();
|
|
|
|
// chase
|
|
void UpdateChaseTarget();
|
|
|
|
// league
|
|
bool InitLeague(bool *pCancel);
|
|
void DeinitLeague();
|
|
bool LeagueStart(bool *pCancel);
|
|
bool LeagueUpdate();
|
|
bool LeagueUpdateProcessReply();
|
|
bool LeagueEnd(const char *szRecordName = nullptr, const BYTE *pRecordSHA = nullptr);
|
|
|
|
// streaming
|
|
bool StreamIn(bool fFinish);
|
|
bool StreamOut();
|
|
|
|
// puncher
|
|
void InitPuncher();
|
|
};
|
|
|
|
extern C4Network2 Network;
|
|
|
|
class C4VoteDialog : public C4GUI::MessageDialog
|
|
{
|
|
public:
|
|
C4VoteDialog(const char *szText, C4ControlVoteType eVoteType, int32_t iVoteData, bool fSurrender);
|
|
|
|
private:
|
|
C4ControlVoteType eVoteType;
|
|
int32_t iVoteData;
|
|
bool fSurrender;
|
|
|
|
public:
|
|
C4ControlVoteType getVoteType() const { return eVoteType; }
|
|
int32_t getVoteData() const { return iVoteData; }
|
|
|
|
private:
|
|
virtual bool OnEnter() { UserClose(false); return true; } // the vote dialog defaults to "No" [MarkFra]
|
|
virtual void OnClosed(bool fOK);
|
|
|
|
// true for dialogs that receive full keyboard and mouse input even in shared mode
|
|
virtual bool IsExclusiveDialog() { return true; }
|
|
};
|
|
|
|
// * Packets *
|
|
|
|
class C4PacketJoinData : public C4PacketBase
|
|
{
|
|
public:
|
|
C4PacketJoinData() { }
|
|
|
|
protected:
|
|
|
|
// the client ID
|
|
int32_t iClientID;
|
|
|
|
// Dynamic data to boot
|
|
C4Network2ResCore Dynamic;
|
|
|
|
// network status
|
|
C4Network2Status GameStatus;
|
|
|
|
// control tick
|
|
int32_t iStartCtrlTick;
|
|
|
|
public:
|
|
|
|
// scenario parameter definitions (so the client can see them in the lobby)
|
|
C4ScenarioParameterDefs ScenarioParameterDefs;
|
|
|
|
// the game parameters
|
|
C4GameParameters Parameters;
|
|
|
|
public:
|
|
const int32_t &getClientID() const { return iClientID; }
|
|
const C4Network2ResCore&getDynamicCore() const { return Dynamic; }
|
|
const C4Network2Status &getStatus() const { return GameStatus; }
|
|
int32_t getStartCtrlTick() const { return iStartCtrlTick; }
|
|
|
|
void SetClientID(int32_t inClientID) { iClientID = inClientID; }
|
|
void SetGameStatus(const C4Network2Status &Status) { GameStatus = Status; }
|
|
void SetDynamicCore(const C4Network2ResCore &Core) { Dynamic = Core; }
|
|
void SetStartCtrlTick(int32_t iTick) { iStartCtrlTick = iTick; }
|
|
|
|
virtual void CompileFunc(StdCompiler *pComp);
|
|
};
|
|
|
|
class C4PacketActivateReq : public C4PacketBase
|
|
{
|
|
public:
|
|
C4PacketActivateReq(int32_t iTick = -1) : iTick(iTick) { }
|
|
|
|
protected:
|
|
int32_t iTick;
|
|
|
|
public:
|
|
int32_t getTick() const { return iTick; }
|
|
|
|
virtual void CompileFunc(StdCompiler *pComp);
|
|
};
|
|
|
|
#endif
|