OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Network2Dialogs.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2004-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 // dialogs for network information
17 
18 #include "C4Include.h"
20 
21 #include "control/C4GameControl.h"
22 #include "game/C4Viewport.h"
23 #include "graphics/C4Draw.h"
25 #include "gui/C4GameOptions.h"
26 #include "gui/C4Startup.h"
27 #include "lib/StdColors.h"
28 #include "network/C4Network2.h"
30 #include "player/C4PlayerList.h"
31 
32 #ifndef HAVE_WINSOCK
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #endif
37 
38 // --------------------------------------------------
39 // C4Network2ClientDlg
40 
42  : C4GUI::InfoDialog(LoadResStr("IDS_NET_CLIENT_INFO"), 10), iClientID(iForClientID)
43 {
44  // initial text update
45  UpdateText();
46 }
47 
49 {
50  // begin updating (clears previous text)
52  // get core
53  const C4Client *pClient = Game.Clients.getClientByID(iClientID);
54  if (!pClient)
55  {
56  // client ID unknown
57  AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_UNKNOWNID"), iClientID);
58  }
59  else
60  {
61  // get client (may be nullptr for local info)
62  C4Network2Client *pNetClient = pClient->getNetClient();
63  // show some info
64  StdCopyStrBuf strInfo;
65  if (!pClient->isActivated()) { strInfo.Append(LoadResStr("IDS_MSG_INACTIVE")); strInfo.Append(" "); }
66  if (pClient->isLocal()) { strInfo.Append(LoadResStr("IDS_MSG_LOCAL")); strInfo.Append(" "); }
67  strInfo.AppendFormat("%s %s (ID #%d)%s",
68  LoadResStr(pClient->isHost() ? "IDS_MSG_HOST" : "IDS_MSG_CLIENT"),
69  pClient->getName(),
70  iClientID,
71  ::Network.isHost() && pNetClient && !pNetClient->isReady() ? " (!ack)" : "");
72  AddLine(strInfo.getData());
73  // show addresses
74  int iCnt;
75  if ((iCnt=pNetClient->getAddrCnt()))
76  {
77  AddLine(LoadResStr("IDS_NET_CLIENT_INFO_ADDRESSES"));
78  for (int i=0; i<iCnt; ++i)
79  {
80  C4Network2Address addr = pNetClient->getAddr(i);
81  AddLineFmt(" %d: %s",
82  i, // adress index
83  addr.toString().getData());
84  }
85  }
86  else
87  AddLine(LoadResStr("IDS_NET_CLIENT_INFO_NOADDRESSES"));
88  // show connection
89  if (pNetClient)
90  {
91  // connections
92  if (pNetClient->isConnected())
93  {
94  AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_CONNECTIONS"),
95  pNetClient->getMsgConn() == pNetClient->getDataConn() ? "Msg/Data" : "Msg",
97  pNetClient->getMsgConn()->getPeerAddr().ToString().getData(),
98  pNetClient->getMsgConn()->getPingTime());
99  if (pNetClient->getMsgConn() != pNetClient->getDataConn())
100  AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_CONNDATA"),
102  pNetClient->getDataConn()->getPeerAddr().ToString().getData(),
103  pNetClient->getDataConn()->getPingTime());
104  }
105  else
106  AddLine(LoadResStr("IDS_NET_CLIENT_INFO_NOCONNECTIONS"));
107  }
108  }
109  // update done
110  EndUpdateText();
111 }
112 
113 
114 // --------------------------------------------------
115 // C4Network2ClientListBox::ClientListItem
116 
117 C4Network2ClientListBox::ClientListItem::ClientListItem(class C4Network2ClientListBox *pForDlg, int iClientID) // ctor
118  : ListItem(pForDlg, iClientID), pStatusIcon(nullptr), pName(nullptr), pPing(nullptr), pActivateBtn(nullptr), pKickBtn(nullptr), last_sound_time(0)
119 {
120  // get associated client
121  const C4Client *pClient = GetClient();
122  // get size
123  int iIconSize = ::GraphicsResource.TextFont.GetLineHeight();
124  if (pForDlg->IsStartup()) iIconSize *= 2;
125  int iWidth = pForDlg->GetItemWidth();
126  int iVerticalIndent = 2;
127  SetBounds(C4Rect(0, 0, iWidth, iIconSize+2*iVerticalIndent));
128  C4GUI::ComponentAligner ca(GetContainedClientRect(), 0,iVerticalIndent);
129  // create subcomponents
130  bool fIsHost = pClient && pClient->isHost();
131  pStatusIcon = new C4GUI::Icon(ca.GetFromLeft(iIconSize), fIsHost ? C4GUI::Ico_Host : C4GUI::Ico_Client);
132  StdStrBuf sNameLabel;
133  if (pClient)
134  {
135  if (pForDlg->IsStartup())
136  sNameLabel.Ref(pClient->getName());
137  else
138  sNameLabel.Format("%s:%s", pClient->getName(), pClient->getNick());
139  }
140  else
141  {
142  sNameLabel.Ref("???");
143  }
144  pName = new C4GUI::Label(sNameLabel.getData(), iIconSize + IconLabelSpacing,iVerticalIndent, ALeft);
145  int iPingRightPos = GetBounds().Wdt - IconLabelSpacing;
146  if (::Network.isHost()) iPingRightPos -= 48;
147  if (::Network.isHost() && pClient && !pClient->isHost())
148  {
149  // activate/deactivate and kick btns for clients at host
150  if (!pForDlg->IsStartup())
151  {
152  pActivateBtn = new C4GUI::CallbackButtonEx<C4Network2ClientListBox::ClientListItem, C4GUI::IconButton>(C4GUI::Ico_Active, GetToprightCornerRect(std::max(iIconSize, 16),std::max(iIconSize, 16),2,1,1), 0, this, &ClientListItem::OnButtonActivate);
153  fShownActive = true;
154  }
155  pKickBtn = new C4GUI::CallbackButtonEx<C4Network2ClientListBox::ClientListItem, C4GUI::IconButton>(C4GUI::Ico_Kick, GetToprightCornerRect(std::max(iIconSize, 16),std::max(iIconSize, 16),2,1,0), 0, this, &ClientListItem::OnButtonKick);
156  pKickBtn->SetToolTip(LoadResStrNoAmp("IDS_NET_KICKCLIENT"));
157  }
158  if (!pForDlg->IsStartup()) if (pClient && !pClient->isLocal())
159  {
160  // wait time
161  pPing = new C4GUI::Label("???", iPingRightPos, iVerticalIndent, ARight);
162  pPing->SetToolTip(LoadResStr("IDS_DESC_CONTROLWAITTIME"));
163  }
164  // add components
165  AddElement(pStatusIcon); AddElement(pName);
166  if (pPing) AddElement(pPing);
167  if (pActivateBtn) AddElement(pActivateBtn);
168  if (pKickBtn) AddElement(pKickBtn);
169  // add to listbox (will eventually get moved)
170  pForDlg->AddElement(this);
171  // first-time update
172  Update();
173 }
174 
175 void C4Network2ClientListBox::ClientListItem::Update()
176 {
177  // update wait label
178  if (pPing)
179  {
180  int iWait = ::Control.Network.ClientPerfStat(iClientID);
181  pPing->SetText(FormatString("%d ms", iWait).getData());
182  pPing->SetColor(C4RGB(
183  Clamp(255-Abs(iWait)*5, 0, 255),
184  Clamp(255-iWait*5, 0, 255),
185  Clamp(255+iWait*5, 0, 255)));
186  }
187  // update activation status
188  const C4Client *pClient = GetClient(); if (!pClient) return;
189  bool fIsActive = pClient->isActivated();
190  if (fIsActive != fShownActive)
191  {
192  fShownActive = fIsActive;
193  if (!pClient->isHost()) pStatusIcon->SetIcon(fIsActive ? C4GUI::Ico_Client : C4GUI::Ico_ObserverClient);
194  if (pActivateBtn)
195  {
196  pActivateBtn->SetIcon(fIsActive ? C4GUI::Ico_Active : C4GUI::Ico_Inactive);
197  pActivateBtn->SetToolTip(LoadResStrNoAmp(fIsActive ? "IDS_NET_DEACTIVATECLIENT" : "IDS_NET_ACTIVATECLIENT"));
198  }
199  }
200  // update players in tooltip
201  StdStrBuf sCltPlrs(Game.PlayerInfos.GetActivePlayerNames(false, iClientID));
202  pName->SetToolTip(sCltPlrs.getData());
203  // update icon: Network status
205  C4Network2Client *pClt = pClient->getNetClient();
206  if (pClt)
207  {
208  switch (pClt->getStatus())
209  {
210  case NCS_Joining: // waiting for join data
211  case NCS_Chasing: // client is behind (status not acknowledged, isn't waited for)
212  case NCS_NotReady: // client is behind (status not acknowledged)
213  icoStatus = C4GUI::Ico_Loading;
214  break;
215 
216  case NCS_Ready: // client acknowledged network status
217  icoStatus = C4GUI::Ico_Ready;
218  break;
219 
220  case NCS_Remove: // client is to be removed
221  icoStatus = C4GUI::Ico_Kick;
222  break;
223 
224  default: // whatever
225  assert(false);
226  icoStatus = C4GUI::Ico_Loading;
227  break;
228  }
229  }
230  // sound icon?
231  if (last_sound_time)
232  {
233  time_t dt = time(nullptr) - last_sound_time;
234  if (dt >= SoundIconShowTime)
235  {
236  // stop showing sound icon
237  last_sound_time = 0;
238  }
239  else
240  {
241  // time not up yet: show sound icon
242  icoStatus = C4GUI::Ico_Sound;
243  }
244  }
245  // network OK - control ready?
246  if (!pForDlg->IsStartup() && (icoStatus == C4GUI::Ico_Ready))
247  {
248  if (!::Control.Network.ClientReady(iClientID, ::Control.ControlTick))
249  {
250  // control not ready
251  icoStatus = C4GUI::Ico_NetWait;
252  }
253  }
254  // set new icon
255  pStatusIcon->SetIcon(icoStatus);
256 }
257 
258 const C4Client *C4Network2ClientListBox::ClientListItem::GetClient() const
259 {
260  return Game.Clients.getClientByID(iClientID);
261 }
262 
263 C4Network2ClientListBox::ClientListItem *C4Network2ClientListBox::GetClientListItem(int32_t client_id)
264 {
265  // find list item that is not the connection item
266  // search through listbox
267  for (C4GUI::Element *list_item = GetFirst(); list_item; list_item = list_item->GetNext())
268  {
269  // only playerlistitems in this box
270  ListItem *list_item2 = static_cast<ListItem *>(list_item);
271  if (list_item2->GetClientID() == client_id)
272  if (list_item2->GetConnectionID() == -1)
273  return static_cast<ClientListItem *>(list_item2);
274  }
275  // nothing found
276  return nullptr;
277 }
278 
279 void C4Network2ClientListBox::ClientListItem::OnButtonActivate(C4GUI::Control *pButton)
280 {
281  // league: Do not deactivate clients with players
282  if (Game.Parameters.isLeague() && ::Players.GetAtClient(iClientID))
283  {
284  Log(LoadResStr("IDS_LOG_COMMANDNOTALLOWEDINLEAGUE"));
285  return;
286  }
287  // change to status that is not currently shown
289 }
290 
291 void C4Network2ClientListBox::ClientListItem::OnButtonKick(C4GUI::Control *pButton)
292 {
293  // try kick
294  // league: Kick needs voting
295  if (Game.Parameters.isLeague() && ::Players.GetAtClient(iClientID))
296  ::Network.Vote(VT_Kick, true, iClientID);
297  else
298  Game.Clients.CtrlRemove(GetClient(), LoadResStr(pForDlg->IsStartup() ? "IDS_MSG_KICKFROMSTARTUPDLG" : "IDS_MSG_KICKFROMCLIENTLIST"));
299 }
300 
301 void C4Network2ClientListBox::ClientListItem::SetSoundIcon()
302 {
303  // remember time for reset
304  last_sound_time = time(nullptr);
305  // force icon
306  Update();
307 }
308 
309 
310 // --------------------------------------------------
311 // C4Network2ClientListBox::ConnectionListItem
312 
313 C4Network2ClientListBox::ConnectionListItem::ConnectionListItem(class C4Network2ClientListBox *pForDlg, int32_t iClientID, int32_t iConnectionID) // ctor
314  : ListItem(pForDlg, iClientID), iConnID(iConnectionID), pDesc(nullptr), pPing(nullptr), pReconnectBtn(nullptr), pDisconnectBtn(nullptr)
315 {
316  // get size
318  int iIconSize = rUseFont.GetLineHeight();
319  int iWidth = pForDlg->GetItemWidth();
320  int iVerticalIndent = 2;
321  SetBounds(C4Rect(0, 0, iWidth, iIconSize+2*iVerticalIndent));
322  C4GUI::ComponentAligner ca(GetContainedClientRect(), 0,iVerticalIndent);
323  // left indent
324  ca.ExpandLeft(-iIconSize*2);
325  // create subcomponents
326  // reconnect/disconnect buttons
327  if (!Game.Parameters.isLeague())
328  {
329  pDisconnectBtn = new C4GUI::CallbackButtonEx<C4Network2ClientListBox::ConnectionListItem, C4GUI::IconButton>(C4GUI::Ico_Disconnect, ca.GetFromRight(iIconSize, iIconSize), 0, this, &ConnectionListItem::OnButtonDisconnect);
330  pDisconnectBtn->SetToolTip(LoadResStr("IDS_MENU_DISCONNECT"));
331  }
332  else
333  pDisconnectBtn = nullptr;
334  // ping time
335  int32_t sx=40, sy=iIconSize;
336  rUseFont.GetTextExtent("???? ms", sx,sy, true);
337  pPing = new C4GUI::Label("???", ca.GetFromRight(sx, sy), ARight);
338  pPing->SetToolTip(LoadResStr("IDS_NET_CONTROL_PING"));
339  // main description item
340  pDesc = new C4GUI::Label("???", ca.GetAll(), ALeft);
341  // add components
342  AddElement(pDesc);
343  AddElement(pPing);
344  if (pDisconnectBtn) AddElement(pDisconnectBtn);
345  // add to listbox (will eventually get moved)
346  pForDlg->AddElement(this);
347  // first-time update
348  Update();
349 }
350 
351 C4Network2IOConnection *C4Network2ClientListBox::ConnectionListItem::GetConnection() const
352 {
353  // get connection by connection ID
354  C4Network2Client *pNetClient = ::Network.Clients.GetClientByID(iClientID);
355  if (!pNetClient) return nullptr;
356  if (iConnID == 0) return pNetClient->getDataConn();
357  if (iConnID == 1) return pNetClient->getMsgConn();
358  return nullptr;
359 }
360 
361 void C4Network2ClientListBox::ConnectionListItem::Update()
362 {
363  C4Network2IOConnection *pConn = GetConnection();
364  if (!pConn)
365  {
366  // No connection: Shouldn't happen
367  pDesc->SetText("???");
368  pPing->SetText("???");
369  return;
370  }
371  // update connection ping
372  int iPing = pConn->getLag();
373  pPing->SetText(FormatString("%d ms", iPing).getData());
374  // update description
375  // get connection usage
376  const char *szConnType;
377  C4Network2Client *pNetClient = ::Network.Clients.GetClientByID(iClientID);
378  if (pNetClient->getDataConn() == pNetClient->getMsgConn())
379  szConnType = "Data/Msg";
380  else if (iConnID)
381  szConnType = "Msg";
382  else
383  szConnType = "Data";
384  // display info
385  pDesc->SetText(FormatString("%s: %s (%s l%d)",
386  szConnType,
388  pConn->getPeerAddr().ToString().getData(),
389  pConn->getPacketLoss()).getData());
390 }
391 
392 void C4Network2ClientListBox::ConnectionListItem::OnButtonDisconnect(C4GUI::Control *pButton)
393 {
394  // close connection
395  C4Network2IOConnection *pConn = GetConnection();
396  if (pConn)
397  {
398  pConn->Close();
399  }
400 }
401 
402 void C4Network2ClientListBox::ConnectionListItem::OnButtonReconnect(C4GUI::Control *pButton)
403 {
404  // 2do
405 }
406 
407 
408 // --------------------------------------------------
409 // C4Network2ClientListBox
410 
411 C4Network2ClientListBox::C4Network2ClientListBox(C4Rect &rcBounds, bool fStartup) : ListBox(rcBounds), fStartup(fStartup)
412 {
413  // hook into timer callback
414  Application.Add(this);
415  // initial update
416  Update();
417 }
418 
420 {
421  Application.Remove(this);
422 }
423 
425 {
426  // sync with client list
427  ListItem *pItem = static_cast<ListItem *>(pClientWindow->GetFirst()), *pNext;
428  const C4Client *pClient = nullptr;
429  while ((pClient = Game.Clients.getClient(pClient)))
430  {
431  // skip host in startup board
432  if (IsStartup() && pClient->isHost()) continue;
433  // deleted client(s) present? this will also delete unneeded client connections of previous client
434  while (pItem && (pItem->GetClientID() < pClient->getID()))
435  {
436  pNext = static_cast<ListItem *>(pItem->GetNext());
437  delete pItem; pItem = pNext;
438  }
439  // same present for update?
440  // need not check for connection ID, because a client item will always be placed before the corresponding connection items
441  if (pItem && pItem->GetClientID() == pClient->getID())
442  {
443  pItem->Update();
444  pItem = static_cast<ListItem *>(pItem->GetNext());
445  }
446  else
447  // not present: insert (or add if pItem=nullptr)
448  InsertElement(new ClientListItem(this, pClient->getID()), pItem);
449  // update connections for client
450  // but no connections in startup board
451  if (IsStartup()) continue;
452  // enumerate client connections
453  C4Network2Client *pNetClient = pClient->getNetClient();
454  if (!pNetClient) continue; // local client does not have connections
455  C4Network2IOConnection *pLastConn = nullptr;
456  for (int i = 0; i<2; ++i)
457  {
458  C4Network2IOConnection *pConn = i ? pNetClient->getMsgConn() : pNetClient->getDataConn();
459  if (!pConn) continue;
460  if (pConn == pLastConn) continue; // combined connection: Display only one
461  pLastConn = pConn;
462  // del leading items
463  while (pItem && ((pItem->GetClientID() < pClient->getID()) || ((pItem->GetClientID() == pClient->getID()) && (pItem->GetConnectionID() < i))))
464  {
465  pNext = static_cast<ListItem *>(pItem->GetNext());
466  delete pItem; pItem = pNext;
467  }
468  // update connection item
469  if (pItem && pItem->GetClientID() == pClient->getID() && pItem->GetConnectionID() == i)
470  {
471  pItem->Update();
472  pItem = static_cast<ListItem *>(pItem->GetNext());
473  }
474  else
475  {
476  // new connection: create it
477  InsertElement(new ConnectionListItem(this, pClient->getID(), i), pItem);
478  }
479  }
480  }
481  // del trailing items
482  while (pItem)
483  {
484  pNext = static_cast<ListItem *>(pItem->GetNext());
485  delete pItem; pItem = pNext;
486  }
487 }
488 
490 {
491  // sound icon on client element
492  ClientListItem *item = GetClientListItem(client_id);
493  if (item) item->SetSoundIcon();
494 }
495 
496 
497 // --------------------------------------------------
498 // C4Network2ClientListDlg
499 
500 // singleton
501 C4Network2ClientListDlg *C4Network2ClientListDlg::pInstance = nullptr;
502 
504  : Dialog(::pGUI->GetPreferredDlgRect().Wdt*3/4, ::pGUI->GetPreferredDlgRect().Hgt*3/4, LoadResStr("IDS_NET_CAPTION"), false)
505 {
506  // component layout
507  CStdFont *pUseFont = &::GraphicsResource.TextFont;
509  C4Rect rcStatus = caAll.GetFromBottom(pUseFont->GetLineHeight());
510  // create game options; max 1/2 of dialog height
511  pGameOptions = new C4GameOptionsList(caAll.GetFromTop(caAll.GetInnerHeight()/2), true, C4GameOptionsList::GOLS_Runtime);
512  pGameOptions->SetDecoration(false, nullptr, true, false);
513  pGameOptions->SetSelectionDiabled();
514  // but resize to actually used height
515  int32_t iFreedHeight = pGameOptions->ContractToElementHeight();
516  caAll.ExpandTop(iFreedHeight);
517  AddElement(pGameOptions);
518  // create client list box
519  AddElement(pListBox = new C4Network2ClientListBox(caAll.GetAll(), false));
520  // create status label
521  AddElement(pStatusLabel = new C4GUI::Label("", rcStatus));
522  // add timer
523  Application.Add(this);
524  // initial update
525  Update();
526 }
527 
529 {
530  if (this==pInstance) pInstance=nullptr; Application.Remove(this);
531 }
532 
534 {
535  // Compose status text
536  StdStrBuf sStatusText;
537  sStatusText.Format("Tick %d, Behind %d, Rate %d, PreSend %d, ACT: %d",
541  // Update status label
542  pStatusLabel->SetText(sStatusText.getData());
543 }
544 
546 {
547  // toggle off?
548  if (pInstance) { pInstance->Close(true); return true; }
549  // toggle on!
551 }
552 
554 {
555  if (singer) pListBox->SetClientSoundIcon(singer->getID());
556 }
557 
558 
559 // --------------------------------------------------
560 // C4Network2StartWaitDlg
561 
563  : C4GUI::Dialog(DialogWidth, DialogHeight, LoadResStr("IDS_NET_CAPTION"), false)
564 {
567  // create top label
568  C4GUI::Label *pLbl;
569  AddElement(pLbl = new C4GUI::Label(LoadResStr("IDS_NET_WAITFORSTART"), caAll.GetFromTop(25), ACenter));
570  // create client list box
571  AddElement(pClientListBox = new C4Network2ClientListBox(caAll.GetAll(), true));
572  // place abort button
573  C4GUI::Button *pBtnAbort = new C4GUI::CancelButton(caButtonArea.GetCentered(C4GUI_DefButtonWdt, C4GUI_ButtonHgt));
574  AddElement(pBtnAbort);
575 }
576 
577 
578 
579 // ---------------------------------------------------
580 // C4GameOptionButtons
581 
582 C4GameOptionButtons::C4GameOptionButtons(const C4Rect &rcBounds, bool fNetwork, bool fHost, bool fLobby)
583  : C4GUI::Window(), fNetwork(fNetwork), fHost(fHost), fLobby(fLobby), fCountdown(false)
584 {
585  SetBounds(rcBounds);
586  // calculate button size from area
587  int32_t iButtonCount = fNetwork ? fHost ? 6 : 3 : 2;
588  int32_t iIconSize = std::min<int32_t>(C4GUI_IconExHgt, rcBounds.Hgt), iIconSpacing = rcBounds.Wdt/(rcBounds.Wdt >= 400 ? 64 : 128);
589  if ((iIconSize+iIconSpacing*2)*iButtonCount > rcBounds.Wdt)
590  {
591  if (iIconSize*iButtonCount <= rcBounds.Wdt)
592  {
593  iIconSpacing = std::max<int32_t>(0, (rcBounds.Wdt-iIconSize*iButtonCount)/(iButtonCount*2)-1);
594  }
595  else
596  {
597  iIconSpacing = 0;
598  iIconSize = rcBounds.Wdt / iButtonCount;
599  }
600  }
601  C4GUI::ComponentAligner caButtonArea(rcBounds,0,0,true);
602  C4GUI::ComponentAligner caButtons(caButtonArea.GetCentered((iIconSize+2*iIconSpacing)*iButtonCount, iIconSize),iIconSpacing,0);
603  // add buttons
604  if (fNetwork && fHost)
605  {
606  bool fIsInternet = !!Config.Network.MasterServerSignUp, fIsDisabled = false;
607  // league currently implies master server signup, and can thus not be turned off
608  if (fLobby && Game.Parameters.isLeague())
609  {
610  fIsInternet = true;
611  fIsDisabled = true;
612  }
613  btnInternet = new C4GUI::CallbackButton<C4GameOptionButtons, C4GUI::IconButton>(fIsInternet ? C4GUI::Ico_Ex_InternetOn : C4GUI::Ico_Ex_InternetOff, caButtons.GetFromLeft(iIconSize, iIconSize), LoadResStr("IDS_DLGTIP_STARTINTERNETGAME"), &C4GameOptionButtons::OnBtnInternet, this);
614  btnInternet->SetEnabled(!fIsDisabled);
615  AddElement(btnInternet);
616  }
617  else btnInternet = nullptr;
618  bool fIsLeague = false;
619  // League button
620  if (fNetwork)
621  {
622  C4GUI::Icons eLeagueIcon;
623  fIsLeague = fLobby ? Game.Parameters.isLeague() : !!Config.Network.LeagueServerSignUp;
624  eLeagueIcon = fIsLeague ? C4GUI::Ico_Ex_LeagueOn : C4GUI::Ico_Ex_LeagueOff;
625  btnLeague = new C4GUI::CallbackButton<C4GameOptionButtons, C4GUI::IconButton>(eLeagueIcon, caButtons.GetFromLeft(iIconSize, iIconSize), LoadResStr("IDS_DLGTIP_STARTLEAGUEGAME"), &C4GameOptionButtons::OnBtnLeague, this);
626  btnLeague->SetEnabled(fHost && !fLobby);
627  AddElement(btnLeague);
628  }
629  else btnLeague=nullptr;
630  if (fNetwork && fHost)
631  {
632  btnPassword = new C4GUI::CallbackButton<C4GameOptionButtons, C4GUI::IconButton>(::Network.isPassworded() ? C4GUI::Ico_Ex_Locked : C4GUI::Ico_Ex_Unlocked, caButtons.GetFromLeft(iIconSize, iIconSize), LoadResStr("IDS_NET_PASSWORD_DESC"), &C4GameOptionButtons::OnBtnPassword, this);
633  AddElement(btnPassword);
634  btnComment = new C4GUI::CallbackButton<C4GameOptionButtons, C4GUI::IconButton>(C4GUI::Ico_Ex_Comment, caButtons.GetFromLeft(iIconSize, iIconSize), LoadResStr("IDS_DESC_COMMENTDESCRIPTIONFORTHIS"), &C4GameOptionButtons::OnBtnComment, this);
635  AddElement(btnComment);
636  }
637  else btnPassword=btnComment=nullptr;
638  btnRecord = new C4GUI::CallbackButton<C4GameOptionButtons, C4GUI::IconButton>(Game.Record || fIsLeague ? C4GUI::Ico_Ex_RecordOn : C4GUI::Ico_Ex_RecordOff, caButtons.GetFromLeft(iIconSize, iIconSize), LoadResStr("IDS_DLGTIP_RECORD"), &C4GameOptionButtons::OnBtnRecord, this);
639  btnRecord->SetEnabled(!fIsLeague);
640  AddElement(btnRecord);
641 }
642 
644 {
645  if (!fNetwork || !fHost) return;
647  // in lobby mode, do actual termination from masterserver
648  if (fLobby)
649  {
650  if (fCheck)
651  {
652  fCheck = ::Network.LeagueSignupEnable();
653  }
654  else
655  {
657  }
658  }
660  // also update league button, because turning off masterserver also turns off the league
661  if (!fCheck)
662  {
664  if (btnLeague)
665  btnLeague->SetIcon(C4GUI::Ico_Ex_LeagueOff);
666  }
667  // re-set in config for the case of failure
669 }
670 
672 {
673  if (!fNetwork || !fHost) return;
676  if (!Game.Record) OnBtnRecord(btnRecord);
677  btnRecord->SetEnabled(!fCheck);
678  // if the league is turned on, the game must be signed up at the masterserver
679  if (fCheck && !Config.Network.MasterServerSignUp) OnBtnInternet(btnInternet);
680  // refresh options in scenario selection dialogue
682 }
683 
685 {
686  Game.Record = !Game.Record;
689 }
690 
692 {
693  if (!fNetwork || !fHost) return;
694  // password is currently set - a single click only clears the password
696  {
697  StdStrBuf empty;
698  OnPasswordSet(empty);
699  return;
700  }
701  // password button pressed: Show dialog to set/change current password
702  C4GUI::InputDialog *pDlg;
704  pDlg->SetMaxText(CFG_MaxString);
705  const char *szPassPreset = ::Network.GetPassword();
706  if (!szPassPreset || !*szPassPreset) szPassPreset = Config.Network.LastPassword;
707  if (*szPassPreset) pDlg->SetInputText(szPassPreset);
708 }
709 
711 {
712  // password input dialog answered with OK: Set/clear network password
713  const char *szPass;
714  ::Network.SetPassword(szPass=rsNewPassword.getData());
715  // update icon to reflect if a password is set
717  // remember password for next round
718  bool fHasPassword = (szPass && *szPass);
719  if (fHasPassword)
720  {
722  }
723  // acoustic feedback
724  C4GUI::GUISound("UI::Confirmed");
725 }
726 
728 {
729  // update icon to reflect if a password is set
730  const char *szPass = ::Network.GetPassword();
731  bool fHasPassword = szPass && *szPass;
732  btnPassword->SetIcon(fHasPassword ? C4GUI::Ico_Ex_Locked : C4GUI::Ico_Ex_Unlocked);
733 }
734 
736 {
737  // password button pressed: Show dialog to set/change current password
738  C4GUI::InputDialog *pDlg;
740  pDlg->SetMaxText(C4MaxComment);
742 }
743 
745 {
746  // check for change; no reference invalidation if not changed
747  if (rsNewComment == Config.Network.Comment) return;
748  // Set in configuration, update reference
749  Config.Network.Comment.CopyValidated(rsNewComment.getData());
751  // message feedback
752  Log(LoadResStr("IDS_NET_COMMENTCHANGED"));
753  // acoustic feedback
754  C4GUI::GUISound("UI::Confirmed");
755 }
756 
758 {
759  fCountdown = fToVal;
760 }
761 
762 // ---------------------------------------------------
763 // C4Chart
764 
765 int GetValueDecade(int iVal)
766 {
767  // get enclosing decade
768  int iDec = 1;
769  while (iVal) { iVal/=10; iDec*=10; }
770  return iDec;
771 }
772 
773 int GetAxisStepRange(int iRange, int iMaxSteps)
774 {
775  // try in steps of 5s and 10s
776  int iDec = GetValueDecade(iRange);
777  if (iDec == 1) return 1;
778  int iNextStepDivider = 2;
779  while (iDec>=iNextStepDivider && iNextStepDivider*iRange/iDec <= iMaxSteps)
780  {
781  iDec/=iNextStepDivider;
782  iNextStepDivider = 7 - iNextStepDivider;
783  }
784  return iDec;
785 }
786 
788 {
789  typedef C4Graph::ValueType ValueType;
790  typedef C4Graph::TimeType TimeType;
791  // transparent w/o graph
792  if (!pDisplayGraph) return;
793  int iSeriesCount = pDisplayGraph->GetSeriesCount();
794  if (!iSeriesCount) return;
795  assert(iSeriesCount>0);
796  StdStrBuf sbuf;
797  pDisplayGraph->Update(); // update averages, etc.
798  // calc metrics
800  int YAxisWdt = 5,
801  XAxisHgt = 15;
802 
803  const int AxisArrowLen = 6,
804  AxisMarkerLen = 5,
805  AxisArrowThickness = 3,
806  AxisArrowIndent= 2; // margin between axis arrow and last value
807  int32_t YAxisMinStepHgt, XAxisMinStepWdt;
808  // get value range
809  int iMinTime = pDisplayGraph->GetStartTime();
810  int iMaxTime = pDisplayGraph->GetEndTime() - 1;
811  if (iMinTime >= iMaxTime) return;
812  ValueType iMinVal = pDisplayGraph->GetMinValue();
813  ValueType iMaxVal = pDisplayGraph->GetMaxValue();
814  if (iMinVal == iMaxVal) ++iMaxVal;
815  if (iMinVal > 0 && iMaxVal/iMinVal >= 2) iMinVal = 0; // go zero-based if this creates less than 50% unused space
816  else if (iMaxVal < 0 && iMinVal/iMaxVal >= 2) iMaxVal = 0;
817  int ddv;
818  if (iMaxVal>0 && (ddv=GetValueDecade(int(iMaxVal))/50))
819  iMaxVal = ((iMaxVal-(iMaxVal>0))/ddv+(iMaxVal>0))*ddv;
820  if (iMinVal && (ddv=GetValueDecade(int(iMinVal))/50))
821  iMinVal = ((iMinVal-(iMinVal<0))/ddv+(iMinVal<0))*ddv;
822  ValueType dv=iMaxVal-iMinVal; TimeType dt=iMaxTime-iMinTime;
823  // axis calculations
824  sbuf.Format("-%d", (int) std::max(Abs(iMaxVal), Abs(iMinVal)));
825  rFont.GetTextExtent(sbuf.getData(), XAxisMinStepWdt, YAxisMinStepHgt, false);
826  YAxisWdt += XAxisMinStepWdt; XAxisHgt += YAxisMinStepHgt;
827  XAxisMinStepWdt += 2; YAxisMinStepHgt += 2;
828  int tw = rcBounds.Wdt - YAxisWdt;
829  int th = rcBounds.Hgt - XAxisHgt;
830  int tx = rcBounds.x + int(cgo.TargetX) + YAxisWdt;
831  int ty = rcBounds.y + int(cgo.TargetY);
832  // show a legend, if more than one graph is shown
833  if (iSeriesCount > 1)
834  {
835  int iSeries = 0; const C4Graph *pSeries;
836  int32_t iLegendWdt = 0, Q,W;
837  while ((pSeries = pDisplayGraph->GetSeries(iSeries++)))
838  {
839  rFont.GetTextExtent(pSeries->GetTitle(), W, Q, true);
840  iLegendWdt = std::max(iLegendWdt, W);
841  }
842  tw -= iLegendWdt+1;
843  iSeries = 0;
844  int iYLegendDraw = (th - iSeriesCount*Q)/2 + ty;
845  while ((pSeries = pDisplayGraph->GetSeries(iSeries++)))
846  {
847  pDraw->TextOut(pSeries->GetTitle(), rFont, 1.0f, cgo.Surface, tx+tw, iYLegendDraw, pSeries->GetColorDw() | 0xff000000, ALeft, true);
848  iYLegendDraw += Q;
849  }
850  }
851  // safety: too small?
852  if (tw < 10 || th < 10) return;
853  // draw axis
854  pDraw->DrawLineDw(cgo.Surface, tx, ty+th, tx+tw-1, ty+th, C4RGB(0x91, 0x91, 0x91));
855  pDraw->DrawLineDw(cgo.Surface, tx+tw-1, ty+th, tx+tw-1-AxisArrowLen, ty+th-AxisArrowThickness, C4RGB(0x91, 0x91, 0x91));
856  pDraw->DrawLineDw(cgo.Surface, tx+tw-1, ty+th, tx+tw-1-AxisArrowLen, ty+th+AxisArrowThickness, C4RGB(0x91, 0x91, 0x91));
857  pDraw->DrawLineDw(cgo.Surface, tx, ty, tx, ty+th, C4RGB(0x91, 0x91, 0x91));
858  pDraw->DrawLineDw(cgo.Surface, tx, ty, tx-AxisArrowThickness, ty+AxisArrowLen, C4RGB(0x91, 0x91, 0x91));
859  pDraw->DrawLineDw(cgo.Surface, tx, ty, tx+AxisArrowThickness, ty+AxisArrowLen, C4RGB(0x91, 0x91, 0x91));
860  tw -= AxisArrowLen + AxisArrowIndent;
861  th -= AxisArrowLen + AxisArrowIndent; ty += AxisArrowLen + AxisArrowIndent;
862  // do axis numbering
863  int iXAxisSteps = GetAxisStepRange(dt, tw / XAxisMinStepWdt),
864  iYAxisSteps = GetAxisStepRange(int(dv), th / YAxisMinStepHgt);
865  int iX, iY, iTime, iVal;
866  iY = 0;
867  iTime = ((iMinTime-(iMinTime>0))/iXAxisSteps+(iMinTime>0))*iXAxisSteps;
868  for (; iTime <= iMaxTime; iTime += iXAxisSteps)
869  {
870  iX = tx + tw * (iTime-iMinTime) / dt;
871  pDraw->DrawLineDw(cgo.Surface, iX, ty+th+1, iX, ty+th+AxisMarkerLen, C4RGB(0x91, 0x91, 0x91));
872  sbuf.Format("%d", (int) iTime);
873  pDraw->TextOut(sbuf.getData(), rFont, 1.0f, cgo.Surface, iX, ty+th+AxisMarkerLen, 0xff7f7f7f, ACenter, false);
874  }
875  iVal = int( ((iMinVal-(iMinVal>0))/iYAxisSteps+(iMinVal>0))*iYAxisSteps );
876  for (; iVal <= iMaxVal; iVal += iYAxisSteps)
877  {
878  iY = ty+th - int((iVal-iMinVal) / dv * th);
879  pDraw->DrawLineDw(cgo.Surface, tx-AxisMarkerLen, iY, tx-1, iY, C4RGB(0x91, 0x91, 0x91));
880  sbuf.Format("%d", (int) iVal);
881  pDraw->TextOut(sbuf.getData(), rFont, 1.0f, cgo.Surface, tx-AxisMarkerLen, iY-rFont.GetLineHeight()/2, 0xff7f7f7f, ARight, false);
882  }
883  // draw graph series(es)
884  int iSeries = 0;
885  while (const C4Graph *pSeries = pDisplayGraph->GetSeries(iSeries++))
886  {
887  int iThisMinTime = std::max(iMinTime, pSeries->GetStartTime());
888  int iThisMaxTime = std::min(iMaxTime, pSeries->GetEndTime());
889  bool fAnyVal = false;
890  for (iX = 0; iX<tw; ++iX)
891  {
892  iTime = iMinTime + dt*iX/tw;
893  if (!Inside(iTime, iThisMinTime, iThisMaxTime)) continue;
894  int iY2 = int((-pSeries->GetValue(iTime) + iMinVal) * th / dv) + ty+th;
895  if (fAnyVal) pDraw->DrawLineDw(cgo.Surface, (float) (tx+iX-1), (float) iY, (float) (tx+iX), (float) iY2, pSeries->GetColorDw() | 0xff000000);
896  iY = iY2;
897  fAnyVal = true;
898  }
899  }
900 }
901 
902 C4Chart::C4Chart(C4Rect &rcBounds) : Element(), pDisplayGraph(nullptr), fOwnGraph(false)
903 {
904  this->rcBounds = rcBounds;
905 }
906 
908 {
909  if (fOwnGraph && pDisplayGraph) delete pDisplayGraph;
910 }
911 
912 
913 // singleton
914 C4ChartDialog *C4ChartDialog::pChartDlg=nullptr;
915 
916 C4ChartDialog::C4ChartDialog() : Dialog(DialogWidth, DialogHeight, LoadResStr("IDS_NET_STATISTICS"), false)
917 {
918  // register singleton
919  pChartDlg = this;
920  // add main chart switch component
922  pChartTabular = new C4GUI::Tabular(caAll.GetAll(), C4GUI::Tabular::tbTop);
923  AddElement(pChartTabular);
924  // add some graphs as subcomponents
925  AddChart(StdStrBuf("oc"));
926  AddChart(StdStrBuf("FPS"));
927  AddChart(StdStrBuf("NetIO"));
928  if (::Network.isEnabled())
929  AddChart(StdStrBuf("Pings"));
930  AddChart(StdStrBuf("Control"));
931  AddChart(StdStrBuf("APM"));
932 }
933 
934 void C4ChartDialog::AddChart(const StdStrBuf &rszName)
935 {
936  // get graph by name
937  if (!Game.pNetworkStatistics || !pChartTabular) return;
938  bool fOwnGraph = false;
939  C4Graph *pGraph = Game.pNetworkStatistics->GetGraphByName(rszName, fOwnGraph);
940  if (!pGraph) return;
941  // add sheet for name
942  C4GUI::Tabular::Sheet *pSheet = pChartTabular->AddSheet(rszName.getData());
943  if (!pSheet) { if (fOwnGraph) delete pGraph; return; }
944  // add chart to sheet
945  C4Chart *pNewChart = new C4Chart(pSheet->GetClientRect());
946  pNewChart->SetGraph(pGraph, fOwnGraph);
947  pSheet->AddElement(pNewChart);
948 }
949 
951 {
952  // close if open
953  if (pChartDlg) { pChartDlg->Close(false); return; }
954  // otherwise, open
955  C4ChartDialog *pDlg = new C4ChartDialog();
956  if (!::pGUI->ShowRemoveDlg(pDlg)) if (pChartDlg) delete pChartDlg;
957 }
const C4Network2Address & getAddr(int32_t i) const
const char * getData() const
Definition: StdBuf.h:442
const char * GetPassword() const
Definition: C4Network2.h:217
const C4Graph * pDisplayGraph
bool fHost
Definition: TstC4NetIO.cpp:31
void SetPassword(const char *szToPassword)
Definition: C4Network2.cpp:771
C4Network2ClientDlg(int iForClientID)
void OnBtnPassword(C4GUI::Control *btn)
#define C4GUI_ButtonAreaHgt
Definition: C4Gui.h:113
C4Config Config
Definition: C4Config.cpp:833
void ExpandTop(int32_t iByHgt)
Definition: C4Gui.h:2808
int GetLineHeight() const
Definition: C4FontLoader.h:125
C4Chart(C4Rect &rcBounds)
void GUISound(const char *szSound)
Definition: C4Gui.cpp:1175
#define C4GUI_ButtonHgt
Definition: C4Gui.h:111
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
void GetAll(C4Rect &rcOut)
Definition: C4Gui.cpp:1125
C4Network2Client * GetClientByID(int32_t iID) const
void SetCountdown(bool fToVal)
virtual const C4Graph * GetSeries(int iIndex) const =0
int32_t ControlTick
Definition: C4GameControl.h:89
bool isHost() const
Definition: C4Network2.h:209
C4Network2IO NetIO
Definition: C4Network2.h:110
void DrawElement(C4TargetFacet &cgo) override
int32_t GetInnerHeight() const
Definition: C4Gui.h:2806
C4Game Game
Definition: C4Globals.cpp:52
C4ConfigGeneral General
Definition: C4Config.h:251
C4Network2IOConnection * getMsgConn() const
#define C4GUI_IconExHgt
Definition: C4Gui.h:96
bool AddElement(Element *pChild, int32_t iIndent=0)
void SetToolTip(const char *szNewTooltip, bool is_immediate=false)
Definition: C4Gui.cpp:409
bool TextOut(const char *szText, CStdFont &rFont, float fZoom, C4Surface *sfcDest, float iTx, float iTy, DWORD dwFCol=0xffffffff, BYTE byForm=ALeft, bool fDoMarkup=true)
Definition: C4Draw.cpp:567
bool isActivated() const
Definition: C4Client.h:110
bool InsertElement(Element *pChild, Element *pInsertBefore, int32_t iIndent=0)
ValidatedStdCopyStrBuf< C4InVal::VAL_Comment > Comment
Definition: C4Config.h:146
virtual void Update() const
StdStrBuf ToString(int flags=0) const
Definition: C4NetIO.cpp:599
void Close(bool fOK)
const int ARight
Definition: C4Surface.h:41
bool isHost() const
Definition: C4Client.h:106
bool ShowRemoveDlg(Dialog *pDlg)
void Vote(C4ControlVoteType eType, bool fApprove=true, int32_t iData=0)
Definition: C4Rect.h:27
bool GetTextExtent(const char *szText, int32_t &rsx, int32_t &rsy, bool fCheckMarkup=true)
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
void AddElement(Element *pChild)
Element * GetFirst()
Definition: C4Gui.h:1571
void SetClientSoundIcon(int32_t client_id)
C4Network2Client * getNetClient() const
Definition: C4Client.h:117
C4Rect GetContainedClientRect()
Definition: C4Gui.h:448
void SetGraph(const C4Graph *pNewGraph, bool fOwn)
C4GraphicsResource GraphicsResource
void SetDecoration(bool fDrawBG, ScrollBarFacets *pToGfx, bool fAutoScroll, bool fDrawBorder=false)
Definition: C4Gui.h:1566
void CtrlRemove(const C4Client *pClient, const char *szReason)
Definition: C4Client.cpp:333
C4GameParameters & Parameters
Definition: C4Game.h:67
void Add(StdSchedulerProc *pProc)
const C4NetIO::addr_t & getPeerAddr() const
Definition: C4Network2IO.h:264
void DrawLineDw(C4Surface *sfcTarget, float x1, float y1, float x2, float y2, DWORD dwClr, float width=1.0f)
Definition: C4Draw.cpp:614
C4Player * GetAtClient(int iClient, int iIndex=0) const
virtual int GetSeriesCount() const =0
void OnBtnLeague(C4GUI::Control *btn)
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
C4Network2IOConnection * getDataConn() const
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:44
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:190
bool isConnected() const
int32_t getID() const
Definition: C4Client.h:105
int32_t Wdt
Definition: C4Rect.h:30
int32_t GetBehind(int32_t iTick) const
int32_t ClientPerfStat(int32_t iClientID)
int32_t getAvgControlSendTime() const
void SetMaxText(int32_t iMaxLen)
Definition: C4Gui.h:2419
void OnLeagueOptionChanged()
Definition: C4Startup.cpp:354
C4GUIScreen * pGUI
Definition: C4Gui.cpp:1191
void OnBtnInternet(C4GUI::Control *btn)
const unsigned int C4MaxComment
C4Network2 Network
Definition: C4Globals.cpp:53
bool GetFromTop(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1059
const char * LoadResStrNoAmp(const char *id)
Definition: StdResStr2.cpp:23
int32_t y
Definition: C4Rect.h:30
Element * GetFirst()
Definition: C4Gui.h:829
int iCnt
Definition: TstC4NetIO.cpp:32
C4GameOptionButtons(const C4Rect &rcBounds, bool fNetwork, bool fHost, bool fLobby)
~C4Chart() override
const int ACenter
Definition: C4Surface.h:41
virtual ValueType GetMinValue() const =0
void InvalidateReference()
C4GameControl Control
C4Rect GetToprightCornerRect(int32_t iWidth=16, int32_t iHeight=16, int32_t iHIndent=4, int32_t iVIndent=4, int32_t iIndexX=0)
Definition: C4Gui.cpp:399
int32_t DefRec
Definition: C4Config.h:47
C4Rect rcBounds
Definition: C4Gui.h:385
void DoInput(C4PacketType eCtrlType, C4ControlPacket *pPkt, C4ControlDeliveryType eDelivery)
bool LeagueSignupEnable()
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
char LastPassword[CFG_MaxString+1]
Definition: C4Config.h:158
C4PlayerList Players
C4Rect & GetClientRect() override
Definition: C4Gui.h:864
int getPingTime() const
Definition: C4Network2IO.h:273
C4ConfigNetwork Network
Definition: C4Config.h:255
#define C4GUI_DefButtonWdt
Definition: C4Gui.h:114
void OnBtnRecord(C4GUI::Control *btn)
C4Draw * pDraw
Definition: C4Draw.cpp:42
void OnBtnComment(C4GUI::Control *btn)
#define C4RGB(r, g, b)
Definition: StdColors.h:26
StdStrBuf GetActivePlayerNames(bool fCountInvisible, int32_t iAtClientID=-1) const
void SetInputText(const char *szToText)
void OnPasswordSet(const StdStrBuf &rsNewPassword)
bool isEnabled() const
Definition: C4Network2.h:203
C4Rect & GetBounds()
Definition: C4Gui.h:445
bool isReady() const
int32_t LeagueServerSignUp
Definition: C4Config.h:151
Icons
Definition: C4Gui.h:637
int32_t getControlPreSend() const
int32_t MasterServerSignUp
Definition: C4Config.h:147
int32_t x
Definition: C4Rect.h:30
void Ref(const char *pnData)
Definition: StdBuf.h:455
void Remove(StdSchedulerProc *pProc)
C4Network2ClientList Clients
Definition: C4Network2.h:116
Element * GetNext() const
Definition: C4Gui.h:449
float TargetX
Definition: C4Facet.h:165
C4PlayerInfoList & PlayerInfos
Definition: C4Game.h:71
virtual TimeType GetStartTime() const =0
C4Client * getClientByID(int32_t iID) const
Definition: C4Client.cpp:200
int32_t GetItemWidth()
Definition: C4Gui.h:1545
virtual ValueType GetMaxValue() const =0
const char * getName() const
Definition: C4Client.h:107
void SetBounds(const C4Rect &rcNewBound)
Definition: C4Gui.h:446
float ValueType
bool ClientReady(int32_t iClientID, int32_t iTick)
int32_t ContractToElementHeight()
C4GameControlNetwork Network
Definition: C4GameControl.h:67
int getPacketLoss() const
Definition: C4Network2IO.h:277
int GetValueDecade(int iVal)
bool isLocal() const
Definition: C4Client.h:116
StdStrBuf toString() const
const int ALeft
Definition: C4Surface.h:41
C4Network2ClientStatus getStatus() const
int GetAxisStepRange(int iRange, int iMaxSteps)
DWORD GetColorDw() const
const char * getNick() const
Definition: C4Client.h:109
bool Log(const char *szMessage)
Definition: C4Log.cpp:192
void AddLineFmt(const char *szFmtString,...) GNUC_FORMAT_ATTRIBUTE_O
C4ClientList & Clients
Definition: C4Game.h:69
#define C4GUI_DefDlgIndent
Definition: C4Gui.h:132
static C4Startup * Get()
Definition: C4Startup.h:133
bool Record
Definition: C4Game.h:123
bool isPassworded() const
Definition: C4Network2.h:218
bool isLeague() const
static void Toggle()
Sheet * AddSheet(const char *szTitle, int32_t icoTitle=Ico_None)
void SetIcon(Icons eUseIcon)
virtual Screen * GetScreen()
Definition: C4Gui.cpp:289
Element * pNext
Definition: C4Gui.h:377
int32_t Hgt
Definition: C4Rect.h:30
T Abs(T val)
Definition: Standard.h:42
C4Surface * Surface
Definition: C4Facet.h:117
C4Network2ClientListBox(C4Rect &rcBounds, bool fStartup)
float TargetY
Definition: C4Facet.h:165
void AddLine(const char *szText)
void OnSound(class C4Client *singer)
std::unique_ptr< C4Network2Stats > pNetworkStatistics
Definition: C4Game.h:95
const char * getNetIOName(C4NetIO *pNetIO)
C4NetIO * getNetClass() const
Definition: C4Network2IO.h:262
C4Client * getClient(const C4Client *pAfter=nullptr) const
Definition: C4Client.h:160
int32_t getAddrCnt() const
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
void LeagueSignupDisable()
virtual TimeType GetEndTime() const =0
void OnCommentSet(const StdStrBuf &rsNewComment)
void CopyValidated(const char *szFromVal)
C4Application Application
Definition: C4Globals.cpp:44
bool GetCentered(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
Definition: C4Gui.cpp:1133
bool GetFromBottom(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1109
void SetSelectionDiabled(bool fToVal=true)
Definition: C4Gui.h:1568
int32_t ControlRate
Definition: C4GameControl.h:88
void SetText(const char *szToText, bool fAllowHotkey=true)
Definition: C4GuiLabels.cpp:74
void UpdateText() override
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
const char * GetTitle() const
ScrollWindow * pClientWindow
Definition: C4Gui.h:1509
void SetEnabled(bool fToVal)
Definition: C4Gui.h:1131