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