3174b75a786550e662499b183978a2b9c2d3b1c2
[oweals/minetest.git] / src / serverobject.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 #include "serverobject.h"
21 #include <fstream>
22 #include "environment.h"
23 #include "inventory.h"
24 #include "collision.h"
25
26 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
27
28 ServerActiveObject::ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos):
29         ActiveObject(id),
30         m_known_by_count(0),
31         m_removed(false),
32         m_static_exists(false),
33         m_static_block(1337,1337,1337),
34         m_env(env),
35         m_base_position(pos)
36 {
37 }
38
39 ServerActiveObject::~ServerActiveObject()
40 {
41 }
42
43 ServerActiveObject* ServerActiveObject::create(u8 type,
44                 ServerEnvironment *env, u16 id, v3f pos,
45                 const std::string &data)
46 {
47         // Find factory function
48         core::map<u16, Factory>::Node *n;
49         n = m_types.find(type);
50         if(n == NULL)
51         {
52                 // If factory is not found, just return.
53                 dstream<<"WARNING: ServerActiveObject: No factory for type="
54                                 <<type<<std::endl;
55                 return NULL;
56         }
57
58         Factory f = n->getValue();
59         ServerActiveObject *object = (*f)(env, id, pos, data);
60         return object;
61 }
62
63 void ServerActiveObject::registerType(u16 type, Factory f)
64 {
65         core::map<u16, Factory>::Node *n;
66         n = m_types.find(type);
67         if(n)
68                 return;
69         m_types.insert(type, f);
70 }
71
72
73 /*
74         TestSAO
75 */
76
77 // Prototype
78 TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0));
79
80 TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
81         ServerActiveObject(env, id, pos),
82         m_timer1(0),
83         m_age(0)
84 {
85         ServerActiveObject::registerType(getType(), create);
86 }
87
88 ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos,
89                 const std::string &data)
90 {
91         return new TestSAO(env, id, pos);
92 }
93
94 void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
95                 bool send_recommended)
96 {
97         m_age += dtime;
98         if(m_age > 10)
99         {
100                 m_removed = true;
101                 return;
102         }
103
104         m_base_position.Y += dtime * BS * 2;
105         if(m_base_position.Y > 8*BS)
106                 m_base_position.Y = 2*BS;
107
108         if(send_recommended == false)
109                 return;
110
111         m_timer1 -= dtime;
112         if(m_timer1 < 0.0)
113         {
114                 m_timer1 += 0.125;
115                 //dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
116
117                 std::string data;
118
119                 data += itos(0); // 0 = position
120                 data += " ";
121                 data += itos(m_base_position.X);
122                 data += " ";
123                 data += itos(m_base_position.Y);
124                 data += " ";
125                 data += itos(m_base_position.Z);
126
127                 ActiveObjectMessage aom(getId(), false, data);
128                 messages.push_back(aom);
129         }
130 }
131
132
133 /*
134         ItemSAO
135 */
136
137 // Prototype
138 ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), "");
139
140 ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
141                 const std::string inventorystring):
142         ServerActiveObject(env, id, pos),
143         m_inventorystring(inventorystring),
144         m_speed_f(0,0,0),
145         m_last_sent_position(0,0,0)
146 {
147         dstream<<"Server: ItemSAO created with inventorystring=\""
148                         <<m_inventorystring<<"\""<<std::endl;
149         ServerActiveObject::registerType(getType(), create);
150 }
151
152 ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
153                 const std::string &data)
154 {
155         std::istringstream is(data, std::ios::binary);
156         char buf[1];
157         // read version
158         is.read(buf, 1);
159         u8 version = buf[0];
160         // check if version is supported
161         if(version != 0)
162                 return NULL;
163         std::string inventorystring = deSerializeString(is);
164         dstream<<"ItemSAO::create(): Creating item \""
165                         <<inventorystring<<"\""<<std::endl;
166         return new ItemSAO(env, id, pos, inventorystring);
167 }
168
169 void ItemSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
170                 bool send_recommended)
171 {
172         assert(m_env);
173         core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
174         collisionMoveResult moveresult;
175         // Apply gravity
176         m_speed_f += v3f(0, -dtime*9.81*BS, 0);
177         // Maximum movement without glitches
178         f32 pos_max_d = BS*0.25;
179         // Limit speed
180         if(m_speed_f.getLength()*dtime > pos_max_d)
181                 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
182         v3f pos_f = getBasePosition();
183         v3f pos_f_old = pos_f;
184         moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
185                         box, dtime, pos_f, m_speed_f);
186         
187         if(send_recommended == false)
188                 return;
189
190         if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
191         {
192                 setBasePosition(pos_f);
193                 m_last_sent_position = pos_f;
194
195                 std::ostringstream os(std::ios::binary);
196                 char buf[6];
197                 // command (0 = update position)
198                 buf[0] = 0;
199                 os.write(buf, 1);
200                 // pos
201                 writeS32((u8*)buf, m_base_position.X*1000);
202                 os.write(buf, 4);
203                 writeS32((u8*)buf, m_base_position.Y*1000);
204                 os.write(buf, 4);
205                 writeS32((u8*)buf, m_base_position.Z*1000);
206                 os.write(buf, 4);
207                 // create message and add to list
208                 ActiveObjectMessage aom(getId(), false, os.str());
209                 messages.push_back(aom);
210         }
211 }
212
213 std::string ItemSAO::getClientInitializationData()
214 {
215         std::ostringstream os(std::ios::binary);
216         char buf[6];
217         // version
218         buf[0] = 0;
219         os.write(buf, 1);
220         // pos
221         writeS32((u8*)buf, m_base_position.X*1000);
222         os.write(buf, 4);
223         writeS32((u8*)buf, m_base_position.Y*1000);
224         os.write(buf, 4);
225         writeS32((u8*)buf, m_base_position.Z*1000);
226         os.write(buf, 4);
227         // inventorystring
228         os<<serializeString(m_inventorystring);
229         return os.str();
230 }
231
232 std::string ItemSAO::getStaticData()
233 {
234         dstream<<__FUNCTION_NAME<<std::endl;
235         std::ostringstream os(std::ios::binary);
236         char buf[1];
237         // version
238         buf[0] = 0;
239         os.write(buf, 1);
240         // inventorystring
241         os<<serializeString(m_inventorystring);
242         return os.str();
243 }
244
245 InventoryItem * ItemSAO::createInventoryItem()
246 {
247         try{
248                 std::istringstream is(m_inventorystring, std::ios_base::binary);
249                 InventoryItem *item = InventoryItem::deSerialize(is);
250                 dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
251                                 <<m_inventorystring<<"\" -> item="<<item
252                                 <<std::endl;
253                 return item;
254         }
255         catch(SerializationError &e)
256         {
257                 dstream<<__FUNCTION_NAME<<": serialization error: "
258                                 <<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
259                 return NULL;
260         }
261 }
262
263
264 /*
265         RatSAO
266 */
267
268 // Prototype
269 RatSAO proto_RatSAO(NULL, 0, v3f(0,0,0));
270
271 RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
272         ServerActiveObject(env, id, pos),
273         m_speed_f(0,0,0)
274 {
275         dstream<<"Server: RatSAO created"<<std::endl;
276         ServerActiveObject::registerType(getType(), create);
277
278         m_oldpos = v3f(0,0,0);
279         m_last_sent_position = v3f(0,0,0);
280         m_yaw = 0;
281         m_counter1 = 0;
282         m_counter2 = 0;
283         m_age = 0;
284         m_touching_ground = false;
285 }
286
287 ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos,
288                 const std::string &data)
289 {
290         std::istringstream is(data, std::ios::binary);
291         char buf[1];
292         // read version
293         is.read(buf, 1);
294         u8 version = buf[0];
295         // check if version is supported
296         if(version != 0)
297                 return NULL;
298         return new RatSAO(env, id, pos);
299 }
300
301 void RatSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
302                 bool send_recommended)
303 {
304         assert(m_env);
305
306         /*
307                 The AI
308         */
309
310         /*m_age += dtime;
311         if(m_age > 60)
312         {
313                 // Die
314                 m_removed = true;
315                 return;
316         }*/
317
318         // Apply gravity
319         m_speed_f.Y -= dtime*9.81*BS;
320
321         /*
322                 Move around if some player is close
323         */
324         bool player_is_close = false;
325         // Check connected players
326         core::list<Player*> players = m_env->getPlayers(true);
327         core::list<Player*>::Iterator i;
328         for(i = players.begin();
329                         i != players.end(); i++)
330         {
331                 Player *player = *i;
332                 v3f playerpos = player->getPosition();
333                 if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
334                 {
335                         player_is_close = true;
336                         break;
337                 }
338         }
339         
340         if(player_is_close == false)
341         {
342                 m_speed_f.X = 0;
343                 m_speed_f.Z = 0;
344         }
345         else
346         {
347                 // Move around
348                 v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
349                 f32 speed = 2*BS;
350                 m_speed_f.X = speed * dir.X;
351                 m_speed_f.Z = speed * dir.Z;
352
353                 if(m_touching_ground && (m_oldpos - m_base_position).getLength()
354                                 < dtime*speed/2)
355                 {
356                         m_counter1 -= dtime;
357                         if(m_counter1 < 0.0)
358                         {
359                                 m_counter1 += 1.0;
360                                 m_speed_f.Y = 5.0*BS;
361                         }
362                 }
363
364                 {
365                         m_counter2 -= dtime;
366                         if(m_counter2 < 0.0)
367                         {
368                                 m_counter2 += (float)(myrand()%100)/100*3.0;
369                                 m_yaw += ((float)(myrand()%200)-100)/100*180;
370                                 m_yaw = wrapDegrees(m_yaw);
371                         }
372                 }
373         }
374         
375         m_oldpos = m_base_position;
376
377         /*
378                 Move it, with collision detection
379         */
380
381         core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
382         collisionMoveResult moveresult;
383         // Maximum movement without glitches
384         f32 pos_max_d = BS*0.25;
385         // Limit speed
386         if(m_speed_f.getLength()*dtime > pos_max_d)
387                 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
388         v3f pos_f = getBasePosition();
389         v3f pos_f_old = pos_f;
390         moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
391                         box, dtime, pos_f, m_speed_f);
392         m_touching_ground = moveresult.touching_ground;
393         
394         setBasePosition(pos_f);
395
396         if(send_recommended == false)
397                 return;
398
399         if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
400         {
401                 m_last_sent_position = pos_f;
402
403                 std::ostringstream os(std::ios::binary);
404                 // command (0 = update position)
405                 writeU8(os, 0);
406                 // pos
407                 writeV3F1000(os, m_base_position);
408                 // yaw
409                 writeF1000(os, m_yaw);
410                 // create message and add to list
411                 ActiveObjectMessage aom(getId(), false, os.str());
412                 messages.push_back(aom);
413         }
414 }
415
416 std::string RatSAO::getClientInitializationData()
417 {
418         std::ostringstream os(std::ios::binary);
419         // version
420         writeU8(os, 0);
421         // pos
422         writeV3F1000(os, m_base_position);
423         return os.str();
424 }
425
426 std::string RatSAO::getStaticData()
427 {
428         dstream<<__FUNCTION_NAME<<std::endl;
429         std::ostringstream os(std::ios::binary);
430         // version
431         writeU8(os, 0);
432         return os.str();
433 }
434
435 InventoryItem* RatSAO::createPickedUpItem()
436 {
437         std::istringstream is("CraftItem rat 1", std::ios_base::binary);
438         InventoryItem *item = InventoryItem::deSerialize(is);
439         return item;
440 }
441
442