OpenClonk
C4Client.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 #include "C4Include.h"
17 #include "network/C4Client.h"
18 
19 #include "control/C4GameControl.h"
20 #include "game/C4Application.h"
22 #include "player/C4PlayerList.h"
23 
24 #ifndef HAVE_WINSOCK
25 #include <netdb.h>
26 #include <sys/socket.h> /* for AF_INET */
27 #endif
28 
29 // *** C4ClientCore
30 
32 {
33  Name.Ref(""); CUID.Ref(""); Nick.Ref("");
34 }
35 
36 C4ClientCore::~C4ClientCore() = default;
37 
38 void C4ClientCore::SetLocal(int32_t inID, bool fnActivated, bool fnObserver)
39 {
40  // status
41  iID = inID;
42  fActivated = fnActivated;
43  fObserver = fnObserver;
44  // misc
48  {
50  Nick.Copy(Name);
51  }
52  else
53  {
54  const char* position = std::strchr(Config.General.Participants, ';');
55  if (!position)
56  position = Config.General.Participants + std::strlen(Config.General.Participants);
57  if (Config.General.Participants + 4 <= position && std::strncmp(position - 4, ".ocp", 4) == 0)
58  Name.CopyValidated(std::string(Config.General.Participants, position - Config.General.Participants - 4).c_str());
59  else
60  Name.Copy("empty");
61  Nick.Copy(Name);
62  }
63 }
64 
65 void C4ClientCore::SetUnknown(int32_t inID)
66 {
67  // save id
68  iID = inID;
69  // fill everything else with default values
70  Name.Ref("unknown"); CUID.Ref("unknown"); Nick.Ref("unknown");
71  Revision.Ref("unknown");
72  fActivated = fObserver = false;
73 }
74 
75 int32_t C4ClientCore::getDiffLevel(const C4ClientCore &CCore2) const
76 {
77  // nick & cuid won't ever be changed
78  if (CUID != CCore2.getCUID() || Nick != CCore2.getNick())
80  // identification changed?
81  if (iID != CCore2.getID() || Name != CCore2.getName())
83  // status change?
84  if (fActivated != CCore2.isActivated() || fObserver != CCore2.isObserver() || fLobbyReady != CCore2.isLobbyReady())
86  // otherwise: identical
87  return C4ClientCoreDL_None;
88 }
89 
90 // C4PacketBase virtuals
91 
93 {
94  pComp->Value(mkNamingAdapt(iID, "ID", C4ClientIDUnknown));
95  pComp->Value(mkNamingAdapt(fActivated, "Activated", false));
96  pComp->Value(mkNamingAdapt(fObserver, "Observer", false));
97  pComp->Value(mkNamingAdapt(fLobbyReady, "Ready", false));
98  pComp->Value(mkNamingAdapt(Name, "Name", ""));
99  pComp->Value(mkNamingAdapt(CUID, "CUID", ""));
100  pComp->Value(mkNamingAdapt(Nick, "Nick", ""));
101  pComp->Value(mkNamingAdapt(Revision, "Revision", ""));
102 }
103 
104 // *** C4Client
105 
106 C4Client::C4Client() = default;
107 
109  : Core(Core), pNext(nullptr)
110 {
111 
112 }
113 
115 {
116  // network client bind must be removed before
117  assert(!pNetClient);
118 }
119 
120 void C4Client::SetActivated(bool fnActivated)
121 {
122  Core.SetActivated(fnActivated);
123  // activity
124  if (fnActivated && pNetClient)
125  pNetClient->SetLastActivity(Game.FrameCounter);
126 }
127 
128 void C4Client::SetLobbyReady(bool fnLobbyReady, time_t *time_since_last_change)
129 {
130  // Change state
131  Core.SetLobbyReady(fnLobbyReady);
132  // Keep track of times
133  if (time_since_last_change)
134  {
135  time_t now = time(nullptr);
136  *time_since_last_change = now - last_lobby_ready_change;
137  last_lobby_ready_change = now;
138  }
139 }
140 
142 {
143  // set flag
144  fLocal = true;
145 }
146 
148 {
149  // remove players for this client
150  ::Players.RemoveAtClient(getID(), true);
151 }
152 
154 {
155  pComp->Value(Core);
156  // Assume this is a non-local client
157  if (pComp->isDeserializer())
158  fLocal = false;
159 }
160 
161 // *** C4ClientList
162 
163 C4ClientList::C4ClientList() = default;
164 
166 {
167  Clear();
168 }
169 
171 {
172  ClearNetwork();
173  while (pFirst)
174  {
175  C4Client *pClient = pFirst;
176  Remove(pClient, true);
177  delete pClient;
178  }
179 }
180 
182 {
183  // local client?
184  if (pClient->isLocal()) pLocal = pClient;
185  // already in list?
186  assert(!getClientByID(pClient->getID()));
187  // find insert position
188  C4Client *pPos = pFirst, *pPrev = nullptr;
189  for (; pPos; pPrev = pPos, pPos = pPos->pNext)
190  if (pPos->getID() > pClient->getID())
191  break;
192  // add to list
193  pClient->pNext = pPos;
194  (pPrev ? pPrev->pNext : pFirst) = pClient;
195  // register to network
196  if (pNetClients)
197  pClient->pNetClient = pNetClients->RegClient(pClient);
198 }
199 
201 {
202  for (C4Client *pClient = pFirst; pClient; pClient = pClient->pNext)
203  if (pClient->getID() == iID)
204  return pClient;
205  return nullptr;
206 }
207 
209 {
210  for (C4Client *pClient = pFirst; pClient; pClient = pClient->pNext)
211  if (pClient->getID() > iAfterID)
212  return pClient;
213  return nullptr;
214 }
215 
216 C4Client *C4ClientList::getClientByName(const char *szName) const
217 {
218  for (C4Client *pClient = pFirst; pClient; pClient = pClient->pNext)
219  if (SEqual(pClient->getName(), szName))
220  return pClient;
221  return nullptr;
222 }
223 
225 {
226  int32_t iCnt = 0;
227  for (C4Client *pClient = pFirst; pClient; pClient = pClient->pNext)
228  iCnt++;
229  return iCnt;
230 }
231 
233 {
234  StdStrBuf result;
235  for (C4Client *pClient = pFirst; pClient; pClient = pClient->pNext)
236  {
237  if (result.getSize()) result.Append(", ");
238  result.Append(pClient->getName());
239  }
240  return result;
241 }
242 
243 bool C4ClientList::Init(int32_t iLocalClientID)
244 {
245  Clear();
246  // Add local client (activated, not observing)
247  AddLocal(iLocalClientID, true, false);
248  return true;
249 }
250 
252 {
253  // clear list before
254  pnNetClients->Clear();
255  // set
256  pNetClients = pnNetClients;
257  // copy client list, create links
258  for (C4Client *pClient = pFirst; pClient; pClient = pClient->pNext)
259  pClient->pNetClient = pNetClients->RegClient(pClient);
260 }
261 
263 {
264  // clear the list (should remove links)
265  C4Network2ClientList *pOldNetClients = pNetClients;
266  pNetClients = nullptr;
267  if (pOldNetClients) pOldNetClients->Clear();
268 }
269 
270 bool C4ClientList::Remove(C4Client *pClient, bool fTemporary)
271 {
272  // first client in list?
273  if (pClient == pFirst)
274  pFirst = pClient->pNext;
275  else
276  {
277  // find previous
278  C4Client *pPrev;
279  for (pPrev = pFirst; pPrev && pPrev->pNext != pClient; pPrev = pPrev->pNext) {}
280  // not found?
281  if (!pPrev) return false;
282  // unlink
283  pPrev->pNext = pClient->pNext;
284  }
285  if (pClient == pLocal) pLocal = nullptr;
286  if (!fTemporary)
287  {
288  pClient->Remove();
289  // remove network client
290  if (pNetClients && pClient->getNetClient())
292  }
293  // done
294  return true;
295 }
296 
298 {
299  // client with same ID in list?
300  if (getClientByID(Core.getID()))
301  { Log("ClientList: Duplicated client ID!"); return nullptr; }
302  // create, add
303  C4Client *pClient = new C4Client(Core);
304  Add(pClient);
305  return pClient;
306 }
307 
308 C4Client *C4ClientList::AddLocal(int32_t iID, bool fActivated, bool fObserver)
309 {
310  // only one local client allowed
311  assert(!pLocal);
312  // create core
313  C4ClientCore LocalCore;
314  LocalCore.SetLocal(iID, fActivated, fObserver);
315  // create client
316  C4Client *pClient = new C4Client(LocalCore);
317  pClient->SetLocal();
318  // add
319  Add(pClient);
320  assert(pLocal);
321  return pClient;
322 }
323 
324 void C4ClientList::SetLocalID(int32_t iID)
325 {
326  if (!pLocal) return;
327  pLocal->SetID(iID);
328  // resort local client
329  C4Client *pSavedLocal = pLocal;
330  Remove(pLocal, true); Add(pSavedLocal);
331 }
332 
333 void C4ClientList::CtrlRemove(const C4Client *pClient, const char *szReason)
334 {
335  // host only
336  if (!pLocal || !pLocal->isHost() || !pClient) return;
337  // Net client? flag
338  if (pClient->getNetClient())
339  pClient->getNetClient()->SetStatus(NCS_Remove);
340  // add control
342  new C4ControlClientRemove(pClient->getID(), szReason),
343  CDT_Sync);
344 }
345 
347 {
348  // remove all remote clients
349  for (C4Client *pClient = pFirst, *pNext; pClient; pClient = pNext)
350  {
351  pNext = pClient->pNext;
352  // remove all clients except the local client
353  if (!pClient->isLocal())
354  {
355  Remove(pClient);
356  delete pClient;
357  }
358  }
359 }
360 
362 {
363  // remove clients that are not in the list
364  C4Client *pClient, *pNext;
365  for (pClient = pFirst; pClient; pClient = pNext)
366  {
367  pNext = pClient->pNext;
368  if (!List.getClientByID(pClient->getID()))
369  {
370  Remove(pClient);
371  delete pClient;
372  }
373  }
374  // add all clients
375  for (pClient = List.pFirst; pClient; pClient = pClient->pNext)
376  {
377  // already in list?
378  C4Client *pNewClient = getClientByID(pClient->getID());
379  if (pNewClient)
380  {
381  // core change
382  pNewClient->SetCore(pClient->getCore());
383  }
384  else
385  {
386  // add
387  pNewClient = Add(pClient->getCore());
388  }
389  }
390  return *this;
391 }
392 
394 {
395  // Clear existing data
396  bool deserializing = pComp->isDeserializer();
397  if (deserializing) Clear();
398  // Client count
399  uint32_t iClientCnt = getClientCnt();
400  pComp->Value(mkNamingCountAdapt(iClientCnt, "Client"));
401  // Compile all clients
402  if (pComp->isDeserializer())
403  for (uint32_t i = 0; i < iClientCnt; i++)
404  {
405  C4Client *pClient = new C4Client();
406  pComp->Value(mkNamingAdapt(*pClient, "Client"));
407  Add(pClient);
408  }
409  else
410  for (C4Client *pClient = pFirst; pClient; pClient = pClient->pNext)
411  pComp->Value(mkNamingAdapt(*pClient, "Client"));
412 }
const int32_t C4ClientCoreDL_Different
Definition: C4Client.h:32
const int32_t C4ClientCoreDL_IDChange
Definition: C4Client.h:31
const int32_t C4ClientCoreDL_None
Definition: C4Client.h:29
const int32_t C4ClientCoreDL_IDMatch
Definition: C4Client.h:30
const int32_t C4ClientIDUnknown
Definition: C4Client.h:24
C4Config Config
Definition: C4Config.cpp:930
C4GameControl Control
@ CDT_Sync
Definition: C4GameControl.h:35
C4Game Game
Definition: C4Globals.cpp:52
C4Application Application
Definition: C4Globals.cpp:44
bool Log(const char *szMessage)
Definition: C4Log.cpp:204
@ NCS_Remove
@ CID_ClientRemove
Definition: C4PacketBase.h:146
C4PlayerList Players
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
StdNamingCountAdapt< int_t > mkNamingCountAdapt(int_t &iCount, const char *szName)
Definition: StdAdaptors.h:1008
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:92
int iCnt
Definition: TstC4NetIO.cpp:32
const char * GetRevision() const
Definition: C4Application.h:72
const char * getNick() const
Definition: C4Client.h:71
bool fLobbyReady
Definition: C4Client.h:52
void CompileFunc(StdCompiler *pComp) override
Definition: C4Client.cpp:92
bool isObserver() const
Definition: C4Client.h:60
bool isLobbyReady() const
Definition: C4Client.h:61
int32_t getDiffLevel(const C4ClientCore &CCore2) const
Definition: C4Client.cpp:75
int32_t iID
Definition: C4Client.h:43
void SetActivated(bool fnActivated)
Definition: C4Client.h:64
const char * getName() const
Definition: C4Client.h:69
ValidatedStdCopyStrBuf< C4InVal::VAL_NameNoEmpty > Nick
Definition: C4Client.h:44
void SetUnknown(int32_t iID)
Definition: C4Client.cpp:65
bool fObserver
Definition: C4Client.h:52
int32_t getID() const
Definition: C4Client.h:57
ValidatedStdCopyStrBuf< C4InVal::VAL_NameAllowEmpty > Revision
Definition: C4Client.h:46
ValidatedStdCopyStrBuf< C4InVal::VAL_NameAllowEmpty > CUID
Definition: C4Client.h:45
const char * getCUID() const
Definition: C4Client.h:70
void SetLobbyReady(bool fnLobbyReady)
Definition: C4Client.h:66
void SetLocal(int32_t iID, bool fnActivated, bool fnObserver)
Definition: C4Client.cpp:38
ValidatedStdCopyStrBuf< C4InVal::VAL_NameNoEmpty > Name
Definition: C4Client.h:44
~C4ClientCore() override
bool fActivated
Definition: C4Client.h:52
bool isActivated() const
Definition: C4Client.h:59
void Remove()
Definition: C4Client.cpp:147
bool isLocal() const
Definition: C4Client.h:116
int32_t getID() const
Definition: C4Client.h:105
void SetCore(const C4ClientCore &NewCore)
Definition: C4Client.h:119
void SetID(int32_t iID)
Definition: C4Client.h:120
C4Network2Client * getNetClient() const
Definition: C4Client.h:117
void CompileFunc(StdCompiler *pComp)
Definition: C4Client.cpp:153
const C4ClientCore & getCore() const
Definition: C4Client.h:104
void SetLobbyReady(bool fnLobbyReady, time_t *time_since_last_change=nullptr)
Definition: C4Client.cpp:128
bool isHost() const
Definition: C4Client.h:106
void SetActivated(bool fnActivated)
Definition: C4Client.cpp:120
void SetLocal()
Definition: C4Client.cpp:141
void CompileFunc(StdCompiler *pComp)
Definition: C4Client.cpp:393
void InitNetwork(class C4Network2ClientList *pNetClients)
Definition: C4Client.cpp:251
C4ClientList & operator=(const C4ClientList &List)
Definition: C4Client.cpp:361
C4Client * pFirst
Definition: C4Client.h:149
void Clear()
Definition: C4Client.cpp:170
StdStrBuf GetAllClientNames() const
Definition: C4Client.cpp:232
bool Remove(C4Client *pClient, bool fTemporary=false)
Definition: C4Client.cpp:270
C4Client * getClientByID(int32_t iID) const
Definition: C4Client.cpp:200
void CtrlRemove(const C4Client *pClient, const char *szReason)
Definition: C4Client.cpp:333
C4Client * getClientByName(const char *szName) const
Definition: C4Client.cpp:216
bool Init(int32_t iLocalClientID=C4ClientIDHost)
Definition: C4Client.cpp:243
void Add(C4Client *pClient)
Definition: C4Client.cpp:181
C4Client * AddLocal(int32_t iID, bool fActivated, bool fObserver)
Definition: C4Client.cpp:308
class C4Network2ClientList * pNetClients
Definition: C4Client.h:155
C4Client * getNextClientByID(int32_t iAfterID) const
Definition: C4Client.cpp:208
void RemoveRemote()
Definition: C4Client.cpp:346
void ClearNetwork()
Definition: C4Client.cpp:262
int32_t getClientCnt() const
Definition: C4Client.cpp:224
C4Client * pLocal
Definition: C4Client.h:152
void SetLocalID(int32_t iID)
Definition: C4Client.cpp:324
char Participants[CFG_MaxString+1]
Definition: C4Config.h:39
const char * GetRegistrationData(const char *field)
Definition: C4Config.h:285
C4ConfigGeneral General
Definition: C4Config.h:255
C4ConfigNetwork Network
Definition: C4Config.h:259
ValidatedStdCopyStrBuf< C4InVal::VAL_NameAllowEmpty > Nick
Definition: C4Config.h:156
void DoInput(C4PacketType eCtrlType, C4ControlPacket *pPkt, C4ControlDeliveryType eDelivery)
int32_t FrameCounter
Definition: C4Game.h:129
void SetStatus(C4Network2ClientStatus enStatus)
void SetLastActivity(int32_t iTick)
C4Network2Client * RegClient(C4Client *pClient)
void DeleteClient(C4Network2Client *pClient)
bool RemoveAtClient(int iClient, bool fDisconnect)
void Value(const T &rStruct)
Definition: StdCompiler.h:161
virtual bool isDeserializer()
Definition: StdCompiler.h:53
size_t getSize() const
Definition: StdBuf.h:444
void Ref(const char *pnData)
Definition: StdBuf.h:455
void Copy()
Definition: StdBuf.h:467
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
size_t getLength() const
Definition: StdBuf.h:445
void CopyValidated(const char *szFromVal)