ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/loop.C
Revision: 1.43
Committed: Fri Mar 16 02:37:54 2007 UTC (17 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.42: +2 -1 lines
Log Message:
- implement yet another bug workaround for gcfclient. its rather sad.

when bg scrubbing, the server sends images in advance, about twice per second.

then receiving a new image, gcfclient destroys the imventory and rebuilds it
(the widgets). this makes using it rather hard, as twice per seconds all widgets
go away and are replaced by new ones, so mouse clicks, if not fast enough, will
be ignored, making the client rather hard to use.

soo.... only to background sending for cfplus, which needs it least.

File Contents

# Content
1 /*
2 * CrossFire, A Multiplayer game for X-windows
3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 * Copyright (C) 2002-2003 Mark Wedel & The Crossfire Development Team
6 * Copyright (C) 1992 Frank Tore Johansen
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * The author can be reached via e-mail to <crossfire@schmorp.de>
23 */
24
25 /**
26 * \file
27 * Main client/server loops.
28 *
29 * \date 2003-12-02
30 *
31 * loop.c mainly deals with initialization and higher level socket
32 * maintanance (checking for lost connections and if data has arrived.)
33 */
34
35 #define BG_SCRUB_RATE 4 // how often to send a face in the background
36
37 #include <global.h>
38 #include <sproto.h>
39 #include <sockproto.h>
40
41 #include <sys/types.h>
42 #include <sys/time.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <netdb.h>
46
47 #include <unistd.h>
48 #include <arpa/inet.h>
49
50 #include <loader.h>
51
52 #define MAX_QUEUE_DEPTH 500 //TODO
53 #define MAX_QUEUE_BACKLOG 3. //TODO
54
55 void
56 client::reset_state ()
57 {
58 if (!pl)
59 return;
60
61 pl->run_on = 0;
62 pl->fire_on = 0;
63 }
64
65 void
66 client::queue_command (packet_type *handler, char *data, int datalen)
67 {
68 tstamp stamp = now ();
69
70 if (cmd_queue.size () >= MAX_QUEUE_DEPTH)
71 {
72 //TODO: just disconnect here?
73 reset_state ();
74 send_packet_printf ("drawinfo %d command queue overflow, ignoring.", NDI_RED);
75 }
76 else
77 {
78 cmd_queue.push_back (command ());
79 command &cmd = cmd_queue.back ();
80 cmd.stamp = stamp;
81 cmd.handler = handler;
82 cmd.data = salloc<char> (datalen + 1, data);
83 cmd.datalen = datalen;
84 }
85 }
86
87 bool
88 client::handle_command ()
89 {
90 bool skipping = false;
91
92 while (!cmd_queue.empty ()
93 && !(state == ST_PLAYING && pl->ob && pl->ob->speed_left <= 0))
94 {
95 command &cmd = cmd_queue.front ();
96
97 if (cmd.stamp + MAX_QUEUE_BACKLOG < now ())
98 {
99 if (!skipping)
100 {
101 skipping = true;
102 reset_state ();
103 send_packet_printf ("drawinfo %d ignoring delayed commands.", NDI_RED);
104 }
105
106 cmd_queue.pop_front ();
107 }
108 else
109 {
110 execute (cmd.handler, cmd.data, cmd.datalen);
111 cmd_queue.pop_front ();
112 return true;
113 }
114 }
115
116 return false;
117 }
118
119 void
120 flush_sockets (void)
121 {
122 for (sockvec::iterator i = clients.begin (); i != clients.end (); ++i)
123 (*i)->flush ();
124 }
125
126 /**
127 * This checks the sockets for input, does the right thing.
128 *
129 * A bit of this code is grabbed out of socket.c
130 * There are 2 lists we need to look through - init_sockets is a list
131 *
132 */
133 void
134 doeric_server (void)
135 {
136 #ifdef CS_LOGSTATS
137 if ((time (NULL) - cst_lst.time_start) >= CS_LOGTIME)
138 write_cs_stats ();
139 #endif
140
141 //TODO: should not be done here, either
142 for (unsigned i = 0; i < clients.size (); ++i)
143 {
144 client *ns = clients [i];
145
146 ns->tick ();
147 ns->refcnt_chk ();
148 }
149 }
150
151 void
152 client::tick ()
153 {
154 if (!pl || destroyed ())
155 return;
156
157 /* Update the players stats once per tick. More efficient than
158 * sending them whenever they change, and probably just as useful
159 */
160 esrv_update_stats (pl);
161
162 if (last_weight != -1 && last_weight != WEIGHT (pl->ob))
163 {
164 esrv_update_item (UPD_WEIGHT, pl->ob, pl->ob);
165 if (last_weight != WEIGHT (pl->ob))
166 LOG (llevError, "esrv_update_item(UPD_WEIGHT) did not set player weight: is %lu, should be %lu\n",
167 (unsigned long) last_weight, WEIGHT (pl->ob));
168 }
169
170 draw_client_map (pl->ob);
171
172 if (update_look)
173 esrv_draw_look (pl->ob);
174
175 if (askface.empty ())
176 {
177 if (bg_scrub && !--bg_scrub && enable_bg_scrub)
178 while (scrub_idx < faces.size () - 1)
179 {
180 ++scrub_idx;
181 if (!faces_sent [scrub_idx])
182 {
183 send_face (scrub_idx);
184 bg_scrub = 1; // send up to one face per tick, unless an image was requested
185 break;
186 }
187 }
188 }
189 else
190 while (!askface.empty () && outputbuffer_len () < max_rate)
191 {
192 // use a lifo to send most recently requested images
193 faceidx face = askface.back ();
194 askface.pop_back ();
195
196 send_image (face);
197
198 bg_scrub = BG_SCRUB_RATE;
199 }
200 }
201