]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu-div0test/nexuiz/serverlist.c
new server list refresh policy... (currently, the refresh button does nothing)
[divverent/nexuiz.git] / data / qcsrc / menu-div0test / nexuiz / serverlist.c
1 #ifdef INTERFACE
2 CLASS(NexuizServerList) EXTENDS(NexuizListBox)
3         METHOD(NexuizServerList, configureNexuizServerList, void(entity))
4         ATTRIB(NexuizServerList, rowsPerItem, float, 1)
5         METHOD(NexuizServerList, draw, void(entity))
6         METHOD(NexuizServerList, drawListBoxItem, void(entity, float, vector, float))
7         METHOD(NexuizServerList, clickListBoxItem, void(entity, float, vector))
8         METHOD(NexuizServerList, resizeNotify, void(entity, vector, vector, vector, vector))
9
10         ATTRIB(NexuizServerList, realFontSize, vector, '0 0 0')
11         ATTRIB(NexuizServerList, realUpperMargin, float, 0)
12         ATTRIB(NexuizServerList, columnPingOrigin, float, 0)
13         ATTRIB(NexuizServerList, columnPingSize, float, 0)
14         ATTRIB(NexuizServerList, columnNameOrigin, float, 0)
15         ATTRIB(NexuizServerList, columnNameSize, float, 0)
16         ATTRIB(NexuizServerList, columnMapOrigin, float, 0)
17         ATTRIB(NexuizServerList, columnMapSize, float, 0)
18         ATTRIB(NexuizServerList, columnPlayersOrigin, float, 0)
19         ATTRIB(NexuizServerList, columnPlayersSize, float, 0)
20
21         ATTRIB(NexuizServerList, selectedServer, string, string_null) // to restore selected server when needed
22         METHOD(NexuizServerList, setSelected, void(entity, float))
23         METHOD(NexuizServerList, setSortOrder, void(entity, float, float))
24         ATTRIB(NexuizServerList, nextRefreshTime, float, 0)
25         METHOD(NexuizServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear
26         ATTRIB(NexuizServerList, needsRefresh, float, 1)
27         METHOD(NexuizServerList, focusEnter, void(entity))
28         METHOD(NexuizServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
29         ATTRIB(NexuizServerList, sortButton1, entity, NULL)
30         ATTRIB(NexuizServerList, sortButton2, entity, NULL)
31         ATTRIB(NexuizServerList, sortButton3, entity, NULL)
32         ATTRIB(NexuizServerList, sortButton4, entity, NULL)
33         ATTRIB(NexuizServerList, connectButton, entity, NULL)
34         ATTRIB(NexuizServerList, currentSortOrder, float, 0)
35         ATTRIB(NexuizServerList, currentSortField, float, -1)
36         ATTRIB(NexuizServerList, lastClickedServer, float, -1)
37         ATTRIB(NexuizServerList, lastClickedTime, float, 0)
38 ENDCLASS(NexuizServerList)
39 entity makeNexuizServerList();
40 void ServerList_Connect_Click(entity btn, entity me);
41 void ServerList_Refresh_Click(entity btn, entity me);
42 #endif
43
44 #ifdef IMPLEMENTATION
45 float SLIST_FIELD_CNAME;
46 float SLIST_FIELD_PING;
47 float SLIST_FIELD_GAME;
48 float SLIST_FIELD_MOD;
49 float SLIST_FIELD_MAP;
50 float SLIST_FIELD_NAME;
51 float SLIST_FIELD_MAXPLAYERS;
52 float SLIST_FIELD_NUMPLAYERS;
53 float SLIST_FIELD_NUMHUMANS;
54 float SLIST_FIELD_NUMBOTS;
55 float SLIST_FIELD_PROTOCOL;
56 float SLIST_FIELD_FREESLOTS;
57 void ServerList_UpdateFieldIDs()
58 {
59         SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
60         SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
61         SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
62         SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
63         SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
64         SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
65         SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
66         SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
67         SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
68         SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
69         SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
70         SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
71 }
72
73 entity makeNexuizServerList()
74 {
75         entity me;
76         me = spawnNexuizServerList();
77         me.configureNexuizServerList(me);
78         return me;
79 }
80 void configureNexuizServerListNexuizServerList(entity me)
81 {
82         me.configureNexuizListBox(me);
83
84         ServerList_UpdateFieldIDs();
85
86         me.nItems = 0;
87 }
88 void setSelectedNexuizServerList(entity me, float i)
89 {
90         float save;
91         save = me.selectedItem;
92         setSelectedListBox(me, i);
93         /*
94         if(me.selectedItem == save)
95                 return;
96         */
97         if(me.nItems == 0)
98                 return;
99         if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
100                 return; // sorry, it would be wrong
101         if(me.selectedServer)
102                 strunzone(me.selectedServer);
103         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
104 }
105 void refreshServerListNexuizServerList(entity me, float mode)
106 {
107         // 0: just reparametrize
108         // 1: also ask for new servers
109         // 2: clear
110         print("refresh of type ", ftos(mode), "\n");
111         /* if(mode == 2) // borken
112         {
113                 // clear list
114                 localcmd("net_slist\n");
115                 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
116         }
117         else */
118         {
119                 resethostcachemasks();
120                 sethostcachesort(me.currentSortField, me.currentSortOrder < 0);
121                 resorthostcache();
122                 if(mode >= 1)
123                         refreshhostcache();
124         }
125 }
126 void focusEnterNexuizServerList(entity me)
127 {
128         if(time < me.nextRefreshTime)
129         {
130                 print("sorry, no refresh yet\n");
131                 return;
132         }
133         me.nextRefreshTime = time + 60;
134         me.refreshServerList(me, 1);
135 }
136 void drawNexuizServerList(entity me)
137 {
138         float i;
139
140         if(me.currentSortField == -1)
141         {
142                 me.setSortOrder(me, SLIST_FIELD_PING, +1);
143                 me.refreshServerList(me, 2);
144         }
145         else if(me.needsRefresh == 1)
146         {
147                 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
148         }
149         else if(me.needsRefresh == 2)
150         {
151                 me.needsRefresh = 0;
152                 me.refreshServerList(me, 0);
153         }
154
155         me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
156         me.connectButton.disabled = (me.nItems == 0);
157         for(i = 0; i < me.nItems; ++i)
158                 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
159                 {
160                         if(i != me.selectedItem)
161                         {
162                                 me.lastClickedServer = -1;
163                                 me.selectedItem = i;
164                         }
165                         break;
166                 }
167         drawListBox(me);
168 }
169 void ServerList_PingSort_Click(entity btn, entity me)
170 {
171         me.setSortOrder(me, SLIST_FIELD_PING, +1);
172 }
173 void ServerList_NameSort_Click(entity btn, entity me)
174 {
175         me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
176 }
177 void ServerList_MapSort_Click(entity btn, entity me)
178 {
179         me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
180 }
181 void ServerList_PlayerSort_Click(entity btn, entity me)
182 {
183         me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
184 }
185 void setSortOrderNexuizServerList(entity me, float field, float direction)
186 {
187         if(me.currentSortField == field)
188                 direction = -me.currentSortOrder;
189         me.currentSortOrder = direction;
190         me.currentSortField = field;
191         me.needsRefresh = 1;
192         me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
193         me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
194         me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
195         me.sortButton4.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
196         me.selectedItem = 0;
197         if(me.selectedServer)
198                 strunzone(me.selectedServer);
199         me.selectedServer = string_null;
200 }
201 void positionSortButtonNexuizServerList(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
202 {
203         vector originInLBSpace, sizeInLBSpace;
204         originInLBSpace = eY * (-me.itemHeight);
205         sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
206
207         vector originInDialogSpace, sizeInDialogSpace;
208         originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
209         sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
210
211         btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
212         btn.Container_size_x   =                         sizeInDialogSpace_x * theSize;
213         btn.setText(btn, theTitle);
214         btn.onClick = theFunc;
215         btn.onClickEntity = me;
216         btn.resized = 1;
217 }
218 void resizeNotifyNexuizServerList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
219 {
220         resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
221
222         me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
223         me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
224         me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
225
226         me.columnPingOrigin = 0;
227         me.columnPingSize = me.realFontSize_x * 4;
228         me.columnMapSize = me.realFontSize_x * 12;
229         me.columnPlayersSize = me.realFontSize_x * 6;
230         me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - 3 * me.realFontSize_x;
231         me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
232         me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
233         me.columnPlayersOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
234
235         me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
236         me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
237         me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
238         me.positionSortButton(me, me.sortButton4, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
239
240         float f;
241         f = me.currentSortField;
242         me.currentSortField = -1;
243         me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
244 }
245 void ServerList_Connect_Click(entity btn, entity me)
246 {
247         if(me.nItems > 0)
248                 localcmd("connect ", me.selectedServer, "\n");
249 }
250 void ServerList_Refresh_Click(entity btn, entity me)
251 {
252         refreshhostcache();
253 }
254 void clickListBoxItemNexuizServerList(entity me, float i, vector where)
255 {
256         if(i == me.lastClickedServer)
257                 if(time < me.lastClickedTime + 0.3)
258                 {
259                         // DOUBLE CLICK!
260                         ServerList_Connect_Click(NULL, me);
261                 }
262         me.lastClickedServer = i;
263         me.lastClickedTime = time;
264 }
265 void drawListBoxItemNexuizServerList(entity me, float i, vector absSize, float isSelected)
266 {
267         // layout: Ping, Server name, Map name, NP, TP, MP
268         string s;
269         float p;
270         vector theColor;
271         float theAlpha;
272
273         if(isSelected)
274                 draw_Fill('0 0 0', '1 1 0', '0 0 1', 0.5);
275
276         if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
277                 theAlpha = 0.2;
278         else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
279                 theAlpha = 0.5;
280         else
281                 theAlpha = 1;
282         
283         p = gethostcachenumber(SLIST_FIELD_PING, i);
284         if(p < 50)
285                 theColor = eX * (p / 50) + eY;
286         else if(p < 150)
287                 theColor = eX + eY * ((150 - p) / 100);
288         else if(p < 650)
289         {
290                 theColor = eX;
291                 theAlpha *= 0.1 + 0.9 * (650 - p) / 500;
292         }
293         else
294         {
295                 theColor = eX;
296                 theAlpha *= 0.1;
297         }
298         
299         s = ftos(p);
300         draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s) * me.realFontSize_x) * eX, s, me.realFontSize, theColor, theAlpha);
301         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize / me.realFontSize_x);
302         draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha);
303         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize / me.realFontSize_x);
304         draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha);
305         s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
306         draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha);
307 }
308 #endif