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

# User Rev Content
1 elmex 1.1 /*
2 pippijn 1.39 * 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 elmex 1.1
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 root 1.26 * maintanance (checking for lost connections and if data has arrived.)
33 elmex 1.1 */
34    
35 root 1.42 #define BG_SCRUB_RATE 4 // how often to send a face in the background
36 elmex 1.1
37     #include <global.h>
38 root 1.10 #include <sproto.h>
39     #include <sockproto.h>
40 elmex 1.1
41 pippijn 1.8 #include <sys/types.h>
42     #include <sys/time.h>
43     #include <sys/socket.h>
44     #include <netinet/in.h>
45     #include <netdb.h>
46 elmex 1.1
47 root 1.16 #include <unistd.h>
48     #include <arpa/inet.h>
49 elmex 1.1
50     #include <loader.h>
51    
52 root 1.20 #define MAX_QUEUE_DEPTH 500 //TODO
53 root 1.34 #define MAX_QUEUE_BACKLOG 3. //TODO
54 elmex 1.1
55 root 1.21 void
56     client::reset_state ()
57     {
58     if (!pl)
59     return;
60    
61     pl->run_on = 0;
62     pl->fire_on = 0;
63     }
64 elmex 1.1
65 root 1.20 void
66     client::queue_command (packet_type *handler, char *data, int datalen)
67 root 1.6 {
68 root 1.20 tstamp stamp = now ();
69 elmex 1.1
70 root 1.20 if (cmd_queue.size () >= MAX_QUEUE_DEPTH)
71 root 1.21 {
72     //TODO: just disconnect here?
73     reset_state ();
74     send_packet_printf ("drawinfo %d command queue overflow, ignoring.", NDI_RED);
75     }
76 root 1.20 else
77 root 1.24 {
78     cmd_queue.push_back (command ());
79     command &cmd = cmd_queue.back ();
80     cmd.stamp = stamp;
81     cmd.handler = handler;
82 root 1.25 cmd.data = salloc<char> (datalen + 1, data);
83 root 1.24 cmd.datalen = datalen;
84     }
85 root 1.20 }
86 elmex 1.1
87 root 1.20 bool
88     client::handle_command ()
89 elmex 1.1 {
90 root 1.26 bool skipping = false;
91 elmex 1.1
92 root 1.26 while (!cmd_queue.empty ()
93 root 1.38 && !(state == ST_PLAYING && pl->ob && pl->ob->speed_left <= 0))
94 root 1.26 {
95     command &cmd = cmd_queue.front ();
96 root 1.6
97 root 1.26 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 root 1.11
106 root 1.26 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 root 1.21 }
115 root 1.6
116 root 1.26 return false;
117 elmex 1.1 }
118    
119 root 1.6 void
120     flush_sockets (void)
121 elmex 1.1 {
122 root 1.19 for (sockvec::iterator i = clients.begin (); i != clients.end (); ++i)
123 root 1.31 (*i)->flush ();
124 elmex 1.1 }
125    
126     /**
127 root 1.10 * This checks the sockets for input, does the right thing.
128 elmex 1.1 *
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 root 1.6 void
134     doeric_server (void)
135 elmex 1.1 {
136     #ifdef CS_LOGSTATS
137 root 1.6 if ((time (NULL) - cst_lst.time_start) >= CS_LOGTIME)
138     write_cs_stats ();
139 elmex 1.1 #endif
140    
141 root 1.33 //TODO: should not be done here, either
142 pippijn 1.40 for (unsigned i = 0; i < clients.size (); ++i)
143 root 1.6 {
144 root 1.42 client *ns = clients [i];
145 elmex 1.1
146 root 1.42 ns->tick ();
147     ns->refcnt_chk ();
148     }
149     }
150    
151     void
152     client::tick ()
153     {
154     if (!pl || destroyed ())
155     return;
156 root 1.37
157 root 1.42 /* 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 root 1.20
162 root 1.42 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 root 1.6
170 root 1.42 draw_client_map (pl->ob);
171 root 1.20
172 root 1.42 if (update_look)
173     esrv_draw_look (pl->ob);
174 root 1.41
175 root 1.42 if (askface.empty ())
176     {
177 root 1.43 if (bg_scrub && !--bg_scrub && enable_bg_scrub)
178 root 1.42 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 root 1.41
196 root 1.42 send_image (face);
197 root 1.33
198 root 1.42 bg_scrub = BG_SCRUB_RATE;
199     }
200 elmex 1.1 }
201 root 1.43