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, 5 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

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 * Copyright (©) 2001 Mark Wedel
7 * Copyright (©) 1992 Frank Tore Johansen
8 *
9 * 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 *
14 * 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 *
19 * 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 *
23 * The authors can be reached via e-mail to <support@deliantra.net>
24 */
25
26 /*
27 * 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 #include "crc.h"
39
40 #define MAX_IMAGE_SIZE 10000
41
42 /**
43 * client requested an image. send it rate-limited
44 * before flushing.
45 */
46 void
47 AskFaceCmd (char *buf, int len, client *ns)
48 {
49 int idx = 0, pri = 0;
50
51 sscanf (buf, "%d %d", &idx, &pri);
52
53 //TODO: somehow fetch default priority from send_fx here
54
55 const faceinfo *f = face_info (idx);
56
57 if (!f)
58 return; // doh
59
60 int set = ns->tileset;
61
62 if (!f->face [set].chksum_len)
63 set = 0;
64
65 /* cfperl_ix calls cf::face::ix which loads the data */
66 /* and then calls cf::client::send_ix to actually queue the ix */
67 cfperl_ix (ns, set, idx, pri);
68 }
69
70 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
83 auto pos = ixface.end ();
84
85 // the by far most common case will be to insert
86 // near the end, so little looping.
87 while (pos != ixface.begin ())
88 {
89 --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 {
94 ++pos;
95 break;
96 }
97 }
98
99 ixface.insert (pos, ix);
100
101 #if 0
102 for (auto &&i : ixface)
103 fprintf (stderr, "<%d,%d> ", i.pri, i.ofs);
104 fprintf (stderr, "\n");
105 #endif
106 }
107
108 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 /**
119 * Sends a face offer (fx) to a client.
120 * 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 void
126 client::send_face (faceidx facenum, int pri)
127 {
128 // never send face 0. ever. it does not exist.
129 if (!facenum)
130 return;
131
132 faceinfo *f = face_info (facenum);
133
134 if (!f)
135 {
136 LOG (llevError | logBacktrace, "client::send_face (%d) out of bounds??\n", facenum);
137 return;
138 }
139
140 // refuse to send non-image faces unless requested
141 if (!fx_want [f->type])
142 return;
143
144 if (faces_sent [facenum])
145 return;
146
147 faces_sent [facenum] = true;
148
149 fxface.push_back (facenum);
150 }
151
152 void client::flush_fx ()
153 {
154 while (!fxface.empty ())
155 {
156 packet fx ("fx");
157 packet sx ("sx");
158 int type = 0;
159
160 do
161 {
162 faceidx facenum = fxface.back (); fxface.pop_back ();
163
164 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 const facedata *d = f->data (tileset);
175
176 fx << ber32 (facenum)
177 << data8 (d->chksum, d->chksum_len);
178
179 if (smoothing)
180 {
181 faceinfo *f = face_info (facenum);
182
183 if (f->smooth)
184 {
185 send_face (f->smooth, -110);
186
187 sx << ber32 (facenum)
188 << ber32 (f->smooth)
189 << ber32 (f->smoothlevel);
190 }
191 }
192 }
193 }
194 while (!fxface.empty ()
195 && fx.room () > ber32::size + CHKSUM_MAXLEN + 1 + 3 /* type switch */
196 && sx.room () > ber32::size * 3);
197
198 send_packet (fx);
199 if (sx.length () > 3) send_packet (sx);
200 }
201 }
202
203 // 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 send_face (ob->face, 10);
211
212 if (ob->animation_id)
213 {
214 const animation &anim = ob->anim ();
215
216 for (int i = 0; i < anim.num_animations; i++)
217 send_face (anim.faces [i], -10);
218 }
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 * are added in contiguous order, so if the number is in the valid
233 * range, it must be a valid animation.
234 */
235 if (anim_num < 0 || anim_num >= animations.size ())
236 {
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 send_face (animations[anim_num].faces[i], -20);
252 sl << uint16 (animations[anim_num].faces[i]);
253 }
254
255 send_packet (sl);
256
257 anims_sent[anim_num] = 1;
258 }
259
260 void
261 client::invalidate_face (faceidx idx)
262 {
263 if (!faces_sent [idx])
264 return;
265
266 faces_sent [idx] = false;
267 send_face (idx);
268 //TODO: check for active ix and abort it.
269 }
270
271 void
272 client::invalidate_all_faces ()
273 {
274 for (faceidx i = 0; i < faces_sent.size (); ++i)
275 invalidate_face (i);
276 }
277