]> git.lizzy.rs Git - minetest-m13.git/blob - src/utility.cpp
Update to 4.6 base
[minetest-m13.git] / src / utility.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /*
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
22 */
23
24 #include "utility.h"
25 #include "gettime.h"
26 #include "sha1.h"
27 #include "base64.h"
28 #include "log.h"
29 #include <iomanip>
30
31 TimeTaker::TimeTaker(const char *name, u32 *result)
32 {
33         m_name = name;
34         m_result = result;
35         m_running = true;
36         m_time1 = getTimeMs();
37 }
38
39 u32 TimeTaker::stop(bool quiet)
40 {
41         if(m_running)
42         {
43                 u32 time2 = getTimeMs();
44                 u32 dtime = time2 - m_time1;
45                 if(m_result != NULL)
46                 {
47                         (*m_result) += dtime;
48                 }
49                 else
50                 {
51                         if(quiet == false)
52                                 infostream<<m_name<<" took "<<dtime<<"ms"<<std::endl;
53                 }
54                 m_running = false;
55                 return dtime;
56         }
57         return 0;
58 }
59
60 u32 TimeTaker::getTime()
61 {
62         u32 time2 = getTimeMs();
63         u32 dtime = time2 - m_time1;
64         return dtime;
65 }
66
67 const v3s16 g_6dirs[6] =
68 {
69         // +right, +top, +back
70         v3s16( 0, 0, 1), // back
71         v3s16( 0, 1, 0), // top
72         v3s16( 1, 0, 0), // right
73         v3s16( 0, 0,-1), // front
74         v3s16( 0,-1, 0), // bottom
75         v3s16(-1, 0, 0) // left
76 };
77
78 const v3s16 g_26dirs[26] =
79 {
80         // +right, +top, +back
81         v3s16( 0, 0, 1), // back
82         v3s16( 0, 1, 0), // top
83         v3s16( 1, 0, 0), // right
84         v3s16( 0, 0,-1), // front
85         v3s16( 0,-1, 0), // bottom
86         v3s16(-1, 0, 0), // left
87         // 6
88         v3s16(-1, 1, 0), // top left
89         v3s16( 1, 1, 0), // top right
90         v3s16( 0, 1, 1), // top back
91         v3s16( 0, 1,-1), // top front
92         v3s16(-1, 0, 1), // back left
93         v3s16( 1, 0, 1), // back right
94         v3s16(-1, 0,-1), // front left
95         v3s16( 1, 0,-1), // front right
96         v3s16(-1,-1, 0), // bottom left
97         v3s16( 1,-1, 0), // bottom right
98         v3s16( 0,-1, 1), // bottom back
99         v3s16( 0,-1,-1), // bottom front
100         // 18
101         v3s16(-1, 1, 1), // top back-left
102         v3s16( 1, 1, 1), // top back-right
103         v3s16(-1, 1,-1), // top front-left
104         v3s16( 1, 1,-1), // top front-right
105         v3s16(-1,-1, 1), // bottom back-left
106         v3s16( 1,-1, 1), // bottom back-right
107         v3s16(-1,-1,-1), // bottom front-left
108         v3s16( 1,-1,-1), // bottom front-right
109         // 26
110 };
111
112 const v3s16 g_27dirs[27] =
113 {
114         // +right, +top, +back
115         v3s16( 0, 0, 1), // back
116         v3s16( 0, 1, 0), // top
117         v3s16( 1, 0, 0), // right
118         v3s16( 0, 0,-1), // front
119         v3s16( 0,-1, 0), // bottom
120         v3s16(-1, 0, 0), // left
121         // 6
122         v3s16(-1, 1, 0), // top left
123         v3s16( 1, 1, 0), // top right
124         v3s16( 0, 1, 1), // top back
125         v3s16( 0, 1,-1), // top front
126         v3s16(-1, 0, 1), // back left
127         v3s16( 1, 0, 1), // back right
128         v3s16(-1, 0,-1), // front left
129         v3s16( 1, 0,-1), // front right
130         v3s16(-1,-1, 0), // bottom left
131         v3s16( 1,-1, 0), // bottom right
132         v3s16( 0,-1, 1), // bottom back
133         v3s16( 0,-1,-1), // bottom front
134         // 18
135         v3s16(-1, 1, 1), // top back-left
136         v3s16( 1, 1, 1), // top back-right
137         v3s16(-1, 1,-1), // top front-left
138         v3s16( 1, 1,-1), // top front-right
139         v3s16(-1,-1, 1), // bottom back-left
140         v3s16( 1,-1, 1), // bottom back-right
141         v3s16(-1,-1,-1), // bottom front-left
142         v3s16( 1,-1,-1), // bottom front-right
143         // 26
144         v3s16(0,0,0),
145 };
146
147 static unsigned long next = 1;
148
149 /* RAND_MAX assumed to be 32767 */
150 int myrand(void)
151 {
152    next = next * 1103515245 + 12345;
153    return((unsigned)(next/65536) % 32768);
154 }
155
156 void mysrand(unsigned seed)
157 {
158    next = seed;
159 }
160
161 int myrand_range(int min, int max)
162 {
163         if(max-min > MYRAND_MAX)
164         {
165                 errorstream<<"WARNING: myrand_range: max-min > MYRAND_MAX"<<std::endl;
166                 assert(0);
167         }
168         if(min > max)
169         {
170                 assert(0);
171                 return max;
172         }
173         return (myrand()%(max-min+1))+min;
174 }
175
176 /*
177         blockpos: position of block in block coordinates
178         camera_pos: position of camera in nodes
179         camera_dir: an unit vector pointing to camera direction
180         range: viewing range
181 */
182 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
183                 f32 camera_fov, f32 range, f32 *distance_ptr)
184 {
185         v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE;
186         
187         // Block center position
188         v3f blockpos(
189                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
190                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
191                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
192         );
193
194         // Block position relative to camera
195         v3f blockpos_relative = blockpos - camera_pos;
196
197         // Distance in camera direction (+=front, -=back)
198         f32 dforward = blockpos_relative.dotProduct(camera_dir);
199
200         // Total distance
201         f32 d = blockpos_relative.getLength();
202
203         if(distance_ptr)
204                 *distance_ptr = d;
205         
206         // If block is very close, it is always in sight
207         if(d < 1.44*1.44*MAP_BLOCKSIZE*BS/2)
208                 return true;
209
210         // If block is far away, it's not in sight
211         if(d > range * BS)
212                 return false;
213
214         // Maximum radius of a block
215         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
216         
217         // If block is (nearly) touching the camera, don't
218         // bother validating further (that is, render it anyway)
219         if(d < block_max_radius)
220                 return true;
221         
222         // Cosine of the angle between the camera direction
223         // and the block direction (camera_dir is an unit vector)
224         f32 cosangle = dforward / d;
225         
226         // Compensate for the size of the block
227         // (as the block has to be shown even if it's a bit off FOV)
228         // This is an estimate, plus an arbitary factor
229         cosangle += block_max_radius / d * 0.5;
230
231         // If block is not in the field of view, skip it
232         if(cosangle < cos(camera_fov / 2))
233                 return false;
234
235         return true;
236 }
237
238 // Creates a string encoded in JSON format (almost equivalent to a C string literal)
239 std::string serializeJsonString(const std::string &plain)
240 {
241         std::ostringstream os(std::ios::binary);
242         os<<"\"";
243         for(size_t i = 0; i < plain.size(); i++)
244         {
245                 char c = plain[i];
246                 switch(c)
247                 {
248                         case '"': os<<"\\\""; break;
249                         case '\\': os<<"\\\\"; break;
250                         case '/': os<<"\\/"; break;
251                         case '\b': os<<"\\b"; break;
252                         case '\f': os<<"\\f"; break;
253                         case '\n': os<<"\\n"; break;
254                         case '\r': os<<"\\r"; break;
255                         case '\t': os<<"\\t"; break;
256                         default:
257                         {
258                                 if(c >= 32 && c <= 126)
259                                 {
260                                         os<<c;
261                                 }
262                                 else
263                                 {
264                                         u32 cnum = (u32) (u8) c;
265                                         os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
266                                 }
267                                 break;
268                         }
269                 }
270         }
271         os<<"\"";
272         return os.str();
273 }
274
275 // Reads a string encoded in JSON format
276 std::string deSerializeJsonString(std::istream &is)
277 {
278         std::ostringstream os(std::ios::binary);
279         char c, c2;
280
281         // Parse initial doublequote
282         is >> c;
283         if(c != '"')
284                 throw SerializationError("JSON string must start with doublequote");
285
286         // Parse characters
287         for(;;)
288         {
289                 c = is.get();
290                 if(is.eof())
291                         throw SerializationError("JSON string ended prematurely");
292                 if(c == '"')
293                 {
294                         return os.str();
295                 }
296                 else if(c == '\\')
297                 {
298                         c2 = is.get();
299                         if(is.eof())
300                                 throw SerializationError("JSON string ended prematurely");
301                         switch(c2)
302                         {
303                                 default:  os<<c2; break;
304                                 case 'b': os<<'\b'; break;
305                                 case 'f': os<<'\f'; break;
306                                 case 'n': os<<'\n'; break;
307                                 case 'r': os<<'\r'; break;
308                                 case 't': os<<'\t'; break;
309                                 case 'u':
310                                 {
311                                         char hexdigits[4+1];
312                                         is.read(hexdigits, 4);
313                                         if(is.eof())
314                                                 throw SerializationError("JSON string ended prematurely");
315                                         hexdigits[4] = 0;
316                                         std::istringstream tmp_is(hexdigits, std::ios::binary);
317                                         int hexnumber;
318                                         tmp_is >> std::hex >> hexnumber;
319                                         os<<((char)hexnumber);
320                                         break;
321                                 }
322                         }
323                 }
324                 else
325                 {
326                         os<<c;
327                 }
328         }
329         return os.str();
330 }
331
332 // Get an sha-1 hash of the player's name combined with
333 // the password entered. That's what the server uses as
334 // their password. (Exception : if the password field is
335 // blank, we send a blank password - this is for backwards
336 // compatibility with password-less players).
337 std::string translatePassword(std::string playername, std::wstring password)
338 {
339         if(password.length() == 0)
340                 return "";
341
342         std::string slt = playername + wide_to_narrow(password);
343         SHA1 sha1;
344         sha1.addBytes(slt.c_str(), slt.length());
345         unsigned char *digest = sha1.getDigest();
346         std::string pwd = base64_encode(digest, 20);
347         free(digest);
348         return pwd;
349 }
350
351
352
353 PointedThing::PointedThing():
354         type(POINTEDTHING_NOTHING),
355         node_undersurface(0,0,0),
356         node_abovesurface(0,0,0),
357         object_id(-1)
358 {}
359
360 std::string PointedThing::dump() const
361 {
362         std::ostringstream os(std::ios::binary);
363         if(type == POINTEDTHING_NOTHING)
364         {
365                 os<<"[nothing]";
366         }
367         else if(type == POINTEDTHING_NODE)
368         {
369                 const v3s16 &u = node_undersurface;
370                 const v3s16 &a = node_abovesurface;
371                 os<<"[node under="<<u.X<<","<<u.Y<<","<<u.Z
372                         << " above="<<a.X<<","<<a.Y<<","<<a.Z<<"]";
373         }
374         else if(type == POINTEDTHING_OBJECT)
375         {
376                 os<<"[object "<<object_id<<"]";
377         }
378         else
379         {
380                 os<<"[unknown PointedThing]";
381         }
382         return os.str();
383 }
384
385 void PointedThing::serialize(std::ostream &os) const
386 {
387         writeU8(os, 0); // version
388         writeU8(os, (u8)type);
389         if(type == POINTEDTHING_NOTHING)
390         {
391                 // nothing
392         }
393         else if(type == POINTEDTHING_NODE)
394         {
395                 writeV3S16(os, node_undersurface);
396                 writeV3S16(os, node_abovesurface);
397         }
398         else if(type == POINTEDTHING_OBJECT)
399         {
400                 writeS16(os, object_id);
401         }
402 }
403
404 void PointedThing::deSerialize(std::istream &is)
405 {
406         int version = readU8(is);
407         if(version != 0) throw SerializationError(
408                         "unsupported PointedThing version");
409         type = (PointedThingType) readU8(is);
410         if(type == POINTEDTHING_NOTHING)
411         {
412                 // nothing
413         }
414         else if(type == POINTEDTHING_NODE)
415         {
416                 node_undersurface = readV3S16(is);
417                 node_abovesurface = readV3S16(is);
418         }
419         else if(type == POINTEDTHING_OBJECT)
420         {
421                 object_id = readS16(is);
422         }
423         else
424         {
425                 throw SerializationError(
426                         "unsupported PointedThingType");
427         }
428 }
429
430 bool PointedThing::operator==(const PointedThing &pt2) const
431 {
432         if(type != pt2.type)
433                 return false;
434         if(type == POINTEDTHING_NODE)
435         {
436                 if(node_undersurface != pt2.node_undersurface)
437                         return false;
438                 if(node_abovesurface != pt2.node_abovesurface)
439                         return false;
440         }
441         else if(type == POINTEDTHING_OBJECT)
442         {
443                 if(object_id != pt2.object_id)
444                         return false;
445         }
446         return true;
447 }
448
449 bool PointedThing::operator!=(const PointedThing &pt2) const
450 {
451         return !(*this == pt2);
452 }