ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.79
Committed: Sat Dec 1 20:22:13 2018 UTC (5 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.78: +1 -1 lines
Log Message:
slight cleanup

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.55 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.69 *
4 root 1.77 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 root 1.76 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 root 1.63 * Copyright (©) 2001 Mark Wedel
7     * Copyright (©) 1992 Frank Tore Johansen
8 root 1.69 *
9 root 1.60 * Deliantra is free software: you can redistribute it and/or modify it under
10     * the terms of the Affero GNU General Public License as published by the
11     * Free Software Foundation, either version 3 of the License, or (at your
12     * option) any later version.
13 root 1.69 *
14 root 1.44 * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18 root 1.69 *
19 root 1.60 * You should have received a copy of the Affero GNU General Public License
20     * and the GNU General Public License along with this program. If not, see
21     * <http://www.gnu.org/licenses/>.
22 root 1.69 *
23 root 1.55 * The authors can be reached via e-mail to <support@deliantra.net>
24 root 1.17 */
25 elmex 1.1
26 root 1.73 /*
27 elmex 1.1 * Image related communication
28     *
29     * This file deals with the image related communication to the
30     * client. I've located all the functions in this file - this
31     * localizes it more, and means that we don't need to declare
32     * things like all the structures as globals.
33     */
34    
35     #include <global.h>
36     #include <sproto.h>
37    
38 root 1.20 #include "crc.h"
39    
40 elmex 1.1 #define MAX_IMAGE_SIZE 10000
41    
42     /**
43 root 1.43 * client requested an image. send it rate-limited
44     * before flushing.
45 elmex 1.1 */
46 root 1.3 void
47 root 1.43 AskFaceCmd (char *buf, int len, client *ns)
48 elmex 1.1 {
49 root 1.43 int idx = 0, pri = 0;
50    
51     sscanf (buf, "%d %d", &idx, &pri);
52    
53 root 1.51 //TODO: somehow fetch default priority from send_fx here
54    
55 root 1.73 const faceinfo *f = face_info (idx);
56 root 1.43
57 root 1.73 if (!f)
58 root 1.43 return; // doh
59    
60 root 1.73 int set = ns->tileset;
61    
62 root 1.74 if (!f->face [set].chksum_len)
63 root 1.73 set = 0;
64    
65 root 1.72 /* cfperl_ix calls cf::face::ix which loads the data */
66     /* and then calls cf::client::send_ix to actually queue the ix */
67 root 1.73 cfperl_ix (ns, set, idx, pri);
68 root 1.72 }
69 root 1.43
70 root 1.72 void
71     client::ix_send (faceidx idx, sint16 pri, SV *data_sv)
72     {
73     STRLEN size;
74     char *data = SvPVbyte (data_sv, size);
75     ixsend ix;
76    
77     ix.pri = pri;
78     ix.idx = idx;
79     ix.ofs = size;
80     ix.data = (uint8 *)data;
81     ix.data_sv = SvREFCNT_inc (data_sv);
82 root 1.43
83 root 1.79 auto pos = ixface.end ();
84 root 1.46
85 root 1.58 // the by far most common case will be to insert
86     // near the end, so little looping.
87 root 1.72 while (pos != ixface.begin ())
88 root 1.46 {
89 root 1.58 --pos;
90    
91     // sort within 2k bins, to slightly prefer smaller images
92     if (pri > pos->pri || (pri == pos->pri && (ix.ofs >> 11) <= (pos->ofs >> 11)))
93 root 1.46 {
94 root 1.58 ++pos;
95     break;
96 root 1.46 }
97     }
98    
99 root 1.72 ixface.insert (pos, ix);
100 root 1.45
101     #if 0
102 root 1.78 for (auto &&i : ixface)
103     fprintf (stderr, "<%d,%d> ", i.pri, i.ofs);
104 root 1.46 fprintf (stderr, "\n");
105 root 1.45 #endif
106 root 1.43 }
107    
108 root 1.72 void
109     client::ix_pop ()
110     {
111     ixsend &ix = ixface.back ();
112    
113     SvREFCNT_dec (ix.data_sv);
114    
115     ixface.pop_back ();
116     }
117    
118 root 1.43 /**
119 root 1.70 * Sends a face offer (fx) to a client.
120 elmex 1.1 * If nocache is true (nonzero), ignore the cache setting from the client -
121     * this is needed for the askface, in which we really do want to send the
122     * face (and askface is the only place that should be setting it). Otherwise,
123     * we look at the facecache, and if set, send the image name.
124     */
125 root 1.3 void
126 root 1.50 client::send_face (faceidx facenum, int pri)
127 elmex 1.1 {
128 root 1.28 // never send face 0. ever. it does not exist.
129     if (!facenum)
130     return;
131    
132 root 1.50 faceinfo *f = face_info (facenum);
133 root 1.28
134 root 1.50 if (!f)
135 root 1.3 {
136 root 1.54 LOG (llevError | logBacktrace, "client::send_face (%d) out of bounds??\n", facenum);
137 root 1.3 return;
138     }
139    
140 root 1.68 // refuse to send non-image faces unless requested
141 root 1.50 if (!fx_want [f->type])
142     return;
143 root 1.49
144 root 1.50 if (faces_sent [facenum])
145 root 1.48 return;
146    
147 root 1.68 faces_sent [facenum] = true;
148 root 1.32
149 root 1.58 fxface.push_back (facenum);
150 root 1.32 }
151    
152 root 1.39 void client::flush_fx ()
153     {
154     while (!fxface.empty ())
155     {
156 root 1.40 packet fx ("fx");
157     packet sx ("sx");
158 root 1.50 int type = 0;
159 root 1.39
160     do
161     {
162     faceidx facenum = fxface.back (); fxface.pop_back ();
163    
164 root 1.50 if (const faceinfo *f = face_info (facenum))
165     {
166     if (f->type != type)
167     {
168     type = f->type;
169    
170     fx << ber32 (0)
171     << uint8 (1) << uint8 (type);
172     }
173    
174 root 1.73 const facedata *d = f->data (tileset);
175 root 1.39
176 root 1.40 fx << ber32 (facenum)
177 root 1.62 << data8 (d->chksum, d->chksum_len);
178 root 1.39
179 root 1.40 if (smoothing)
180     {
181     faceinfo *f = face_info (facenum);
182    
183     if (f->smooth)
184     {
185 root 1.50 send_face (f->smooth, -110);
186    
187 root 1.40 sx << ber32 (facenum)
188     << ber32 (f->smooth)
189     << ber32 (f->smoothlevel);
190     }
191     }
192 root 1.39 }
193     }
194 root 1.40 while (!fxface.empty ()
195 root 1.62 && fx.room () > ber32::size + CHKSUM_MAXLEN + 1 + 3 /* type switch */
196 root 1.40 && sx.room () > ber32::size * 3);
197 root 1.39
198 root 1.40 send_packet (fx);
199     if (sx.length () > 3) send_packet (sx);
200 root 1.39 }
201     }
202    
203 root 1.28 // send all faces of this object to the client
204     // this uses more bandwidth initially, but makes
205     // animations look much smoother, and every client
206     // is supposed to do client-side caching anyways.
207     void
208     client::send_faces (object *ob)
209     {
210 root 1.50 send_face (ob->face, 10);
211 root 1.28
212     if (ob->animation_id)
213     {
214 root 1.59 const animation &anim = ob->anim ();
215 root 1.28
216     for (int i = 0; i < anim.num_animations; i++)
217 root 1.50 send_face (anim.faces [i], -10);
218 root 1.28 }
219     }
220    
221     /**
222     * Need to send an animation sequence to the client.
223     * We will send appropriate face commands to the client if we haven't
224     * sent them the face yet (this can become quite costly in terms of
225     * how much we are sending - on the other hand, this should only happen
226     * when the player logs in and picks stuff up.
227     */
228     void
229     client::send_animation (short anim_num)
230     {
231     /* Do some checking on the anim_num we got. Note that the animations
232 root 1.61 * are added in contiguous order, so if the number is in the valid
233 root 1.28 * range, it must be a valid animation.
234     */
235 root 1.41 if (anim_num < 0 || anim_num >= animations.size ())
236 root 1.28 {
237     LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
238     return;
239     }
240    
241     packet sl ("anim");
242    
243     sl << uint16 (anim_num)
244     << uint16 (0); /* flags - not used right now */
245    
246     /* Build up the list of faces. Also, send any information (ie, the
247     * the face itself) down to the client.
248     */
249     for (int i = 0; i < animations[anim_num].num_animations; i++)
250     {
251 root 1.50 send_face (animations[anim_num].faces[i], -20);
252 root 1.61 sl << uint16 (animations[anim_num].faces[i]);
253 elmex 1.1 }
254 root 1.6
255 root 1.28 send_packet (sl);
256    
257     anims_sent[anim_num] = 1;
258 elmex 1.1 }
259    
260 root 1.66 void
261     client::invalidate_face (faceidx idx)
262     {
263 root 1.75 if (!faces_sent [idx])
264     return;
265    
266 root 1.66 faces_sent [idx] = false;
267 root 1.75 send_face (idx);
268     //TODO: check for active ix and abort it.
269 root 1.66 }
270    
271     void
272     client::invalidate_all_faces ()
273     {
274 root 1.75 for (faceidx i = 0; i < faces_sent.size (); ++i)
275     invalidate_face (i);
276 root 1.66 }
277