1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2006, Sven2
6 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18// Startup screen for non-parameterized engine start: Network game selection dialog
19
20#pragma once
21
22#include "C4Startup.h"
23#include "C4Network2Discover.h"
24#include "C4Network2Reference.h"
25#include "C4UpdateDlg.h"
26
27const int C4NetMasterServerQueryInterval = 30; // seconds after last and beforenew game query to master server
28const int C4NetRefRequestTimeout = 12; // seconds after which the reference request is interrupted
29const int C4NetReferenceTimeout = 42; // seconds after which references are removed from the list (C4NetRefRequestTimeout + C4NetMasterServerQueryInterval)
30const int C4NetErrorRefTimeout = 10; // seconds after which failed reference requestsare removed
31const int C4NetGameDiscoveryInterval = 30; // seconds
32const int C4NetMinRefreshInterval = 1; // seconds; minimum time between refreshes
33
34class C4StartupNetListEntry : public C4GUI::Window
35{
36public:
37 C4StartupNetListEntry(C4GUI::ListBox *pForListBox, C4GUI::Element *pInsertBefore, class C4StartupNetDlg *pNetDlg);
38 ~C4StartupNetListEntry();
39
40 enum QueryType // where the game ref is coming from
41 {
42 NRQT_Unknown, // unknown source
43 NRQT_GameDiscovery, // by UDP broadcast in local network
44 NRQT_Masterserver, // by internet masterserver
45 NRQT_DirectJoin, // by user-entered address
46 };
47
48 enum TimeoutType
49 {
50 TT_RefReqWait, // C4NetMasterServerQueryInterval for masterserver; C4NetErrorRefTimeout for other ref clients
51 TT_Reference, // C4NetReferenceTimeout
52 TT_Masterserver, // C4NetMasterServerQueryInterval
53 TT_Refresh, // Refresh as soon as possible
54 };
55
56 enum { InfoLabelCount = 5, MaxInfoIconCount = 10, };
57
58private:
59 C4StartupNetDlg *pNetDlg;
60 C4GUI::ListBox *pList;
61 StdStrBuf sRefClientAddress; // set during reference retrieval: reference server address
62 C4Network2RefClient *pRefClient; // set during reference retrieval: reference request client
63 C4Network2Reference *pRef; // set for retrieved references
64 bool fError; // if set, the label was changed to an error message and no more updates are done
65 StdStrBuf sError;
66 QueryType eQueryType; // valid if pRefClient is set: Where the ref query is originating
67
68 time_t iTimeout; // lifetime: If set, marks time when the item is removed or should re-query
69 time_t iRequestTimeout; // if this times out while the request remains busy, the ref client assumes that the tcp socket blocked upon request and aborts it
70 int32_t iNumFails; // number of times this reference has retried connecting
71
72 C4GUI::Icon *pIcon; // scenario icon
73 C4GUI::Label *pInfoLbl[InfoLabelCount]; // info labels for reference or query
74 C4GUI::Icon *pInfoIcons[MaxInfoIconCount]; // right-aligned status icons at topright position
75 int32_t iInfoLink; // if !=-1, index of the label that should be turned into a clickable link (for MotD-link)
76 int32_t iInfoIconCount;
77 int32_t iSortOrder;
78 bool fIsSmall; // set if the item is in collapsed state
79 bool fIsCollapsed; // set if the item is forced to collapsed state
80 bool fIsEnabled; // if not set, the item is grayed out
81 bool fIsImportant; // if set, the item is presented in yellow (lower priority than fIsEnabled)
82 C4Rect rctIconSmall; // bounds for small icon
83 C4Rect rctIconLarge; // bounds for large icon
84
85 StdStrBuf sInfoText[InfoLabelCount];
86
87 bool QueryReferences();
88 static const char *GetQueryTypeName(QueryType eQueryType); // name of QueryType values
89 void SetError(const char *szErrorText, TimeoutType eTimeout); // change secondary label to error label, mark error and set a removal timer
90 void SetTimeout(TimeoutType eTimeout);
91 C4StartupNetListEntry *AddReference(C4Network2Reference *pAddRef, C4GUI::Element *pInsertBefore); // add a reference list item to the same list
92 void InvalidateStatusIcons() { iInfoIconCount = 0; } // schedule all current status icons for removal when UpdateText is called next
93 void AddStatusIcon(C4GUI::Icons eIcon, const char *szToolTip); // add a status icon with the specified tooltip
94
95 void UpdateSmallState();
96 void UpdateEntrySize();
97 void UpdateText(); // strings to labels
98
99protected:
100 virtual int32_t GetListItemTopSpacing() override { return fIsCollapsed ? 5 : 10; }
101 virtual void DrawElement(C4FacetEx &cgo) override;
102
103 C4GUI::Element *GetNextLower(int32_t sortOrder); // returns the element before which this element should be inserted
104
105public:
106 void ClearRef(); // del any ref/refclient/error data
107 void SetRefQuery(const char *szAddress, QueryType eQueryType); // start loading references fromt he specified address
108 void SetReference(C4Network2Reference *pNewRef); // replace the reference
109
110 bool Execute(); // update stuff - if false is returned, the item is to be removed
111 void OnRequestFailed(); // called on connection error or timeout
112 bool OnReference(); // like Execute(), but only called if some reference was received
113 void UpdateCollapsed(bool fToCollapseValue);
114
115 const char *GetError() { return fError ? sError.getData() : nullptr; } // return error message, if any is set
116 C4Network2Reference *GrabReference(); // grab the reference so it won't be deleted when this item is removed
117 C4Network2Reference *GetReference() const { return pRef; } // have a look at the reference
118 bool IsSameHost(const C4Network2Reference *pRef2); // check whether the reference was created by the same host as this one
119 bool IsSameAddress(const C4Network2Reference *pRef2); // check whether there is at least one matching address (address and port)
120 bool IsSameRefQueryAddress(const char *szJoinAddress); // check whether reference query was created with same host address
121 const char *GetJoinAddress(); // ref queries only: Get direct join address
122};
123
124// startup dialog: Network game selection
125class C4StartupNetDlg : public C4StartupDlg, private C4InteractiveThread::Callback
126{
127public:
128 C4StartupNetDlg();
129 ~C4StartupNetDlg();
130
131private:
132 enum DlgMode { SNDM_GameList = 0, SNDM_Chat = 1 };
133 C4GUI::Tabular *pMainTabular; // main tabular control: Contains game selection list and chat control
134 C4GUI::ListBox *pGameSelList; // game selection listbox
135 C4KeyBinding *pKeyRefresh, *pKeyBack, *pKeyForward;
136 C4GUI::CallbackButton<C4StartupNetDlg, C4GUI::IconButton> *btnGameList, *btnChat; // left side buttons
137 C4GUI::CallbackButton<C4StartupNetDlg, C4GUI::IconButton> *btnInternet, *btnRecord; // right side buttons
138 C4GUI::Button *btnJoin, *btnRefresh;
139 C4GUI::Edit *pJoinAddressEdt;
140 class C4ChatControl *pChatCtrl;
141 C4GUI::WoodenLabel *pChatTitleLabel;
142 C4StartupNetListEntry *pMasterserverClient; // set if masterserver query is enabled: Checks clonk.de for new games
143 bool fIsCollapsed; // set if the number of games in the list requires them to be displayed in a condensed format
144 bool fUpdatingList; // set during list update - prevent selection update calls
145
146 C4Sec1TimerCallback<C4StartupNetDlg> *pSec1Timer; // engine timer hook for list updates
147
148 C4Network2IODiscoverClient DiscoverClient; // disocver client to search for local hosts
149
150 int iGameDiscoverInterval; // next time until a game discovery is started
151 time_t tLastRefresh; // time of last refresh
152 bool fIgnoreUpdate; // set after user pressed "No" on a server redirect once
153
154protected:
155 virtual bool HasBackground() override { return true; }
156 virtual void DrawElement(C4FacetEx &cgo) override;
157
158 virtual C4GUI::Control *GetDefaultControl() override; // get Auto-Focus control
159 C4GUI::Control *GetDlgModeFocusControl(); // get control to be focused when main tabular sheet changes
160
161 virtual bool OnEnter() override { DoOK(); return true; }
162 virtual bool OnEscape() override { DoBack(); return true; }
163 bool KeyBack() { return DoBack(); }
164 bool KeyRefresh() { DoRefresh(); return true; }
165 bool KeyForward() { DoOK(); return true; }
166
167 virtual void OnShown() override; // callback when shown: Start searching for games
168 virtual void OnClosed(bool fOK) override; // callback when dlg got closed: Return to main screen
169 void OnBackBtn(C4GUI::Control *btn) { DoBack(); }
170 void OnRefreshBtn(C4GUI::Control *btn) { DoRefresh(); }
171 void OnCreateGameBtn(C4GUI::Control *btn) { CreateGame(); }
172 void OnJoinGameBtn(C4GUI::Control *btn) { DoOK(); }
173 void OnSelChange(class C4GUI::Element *pEl) { UpdateSelection(fUpdateCollapsed: true); }
174 void OnSelDblClick(class C4GUI::Element *pEl) { DoOK(); }
175 void OnBtnGameList(C4GUI::Control *btn);
176 void OnBtnChat(C4GUI::Control *btn);
177 void OnBtnInternet(C4GUI::Control *btn);
178 void OnBtnRecord(C4GUI::Control *btn);
179 void OnBtnUpdate(C4GUI::Control *btn) { C4UpdateDlg::CheckForUpdates(pScreen: GetScreen()); }
180
181 C4GUI::InputResult OnJoinAddressEnter(C4GUI::Edit *edt, bool fPasting, bool fPastingMore)
182 {
183 DoOK(); return C4GUI::IR_Abort;
184 }
185
186 void OnChatTitleChange(const StdStrBuf &sNewTitle);
187
188private:
189 static bool IsOpen(C4StartupNetDlg *instance);
190 void UpdateMasterserver(); // creates masterserver object if masterserver is enabled; destroy otherwise
191 void UpdateList(bool fGotReference = false);
192 void UpdateCollapsed();
193 void UpdateSelection(bool fUpdateCollapsed);
194 void UpdateDlgMode(); // update button visibility after switching between game sel list and chat
195
196 void AddReferenceQuery(const char *szAddress, C4StartupNetListEntry::QueryType eQueryType); // add a ref searcher entry and start searching
197
198 DlgMode GetDlgMode();
199
200 // callback from C4Network2ReferenceClient
201 void OnThreadEvent(C4InteractiveEventType, const std::any &) override;
202
203public:
204 bool DoOK(); // join currently selected item
205 bool DoBack(); // abort dialog
206 void DoRefresh(); // restart network search
207 void CreateGame(); // switch to scenario selection in network mode
208
209 void OnReferenceEntryAdd(C4StartupNetListEntry *pEntry);
210
211 void OnSec1Timer(); // idle proc: update list
212
213 void SetIgnoreUpdate(bool to_val) { fIgnoreUpdate = to_val; }
214 bool GetIgnoreUpdate() const { return fIgnoreUpdate; }
215};
216