Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 : the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14 :
15 : You should have received a copy of the GNU Lesser 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 "content_sao.h"
21 : #include "util/serialize.h"
22 : #include "util/mathconstants.h"
23 : #include "collision.h"
24 : #include "environment.h"
25 : #include "settings.h"
26 : #include "profiler.h"
27 : #include "serialization.h" // For compressZlib
28 : #include "tool.h" // For ToolCapabilities
29 : #include "gamedef.h"
30 : #include "player.h"
31 : #include "server.h"
32 : #include "scripting_game.h"
33 : #include "genericobject.h"
34 : #include "log.h"
35 :
36 1 : std::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
37 :
38 : /*
39 : TestSAO
40 : */
41 :
42 1 : class TestSAO : public ServerActiveObject
43 : {
44 : public:
45 1 : TestSAO(ServerEnvironment *env, v3f pos):
46 : ServerActiveObject(env, pos),
47 : m_timer1(0),
48 1 : m_age(0)
49 : {
50 1 : ServerActiveObject::registerType(getType(), create);
51 1 : }
52 1 : ActiveObjectType getType() const
53 1 : { return ACTIVEOBJECT_TYPE_TEST; }
54 :
55 0 : static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
56 : const std::string &data)
57 : {
58 0 : return new TestSAO(env, pos);
59 : }
60 :
61 0 : void step(float dtime, bool send_recommended)
62 : {
63 0 : m_age += dtime;
64 0 : if(m_age > 10)
65 : {
66 0 : m_removed = true;
67 0 : return;
68 : }
69 :
70 0 : m_base_position.Y += dtime * BS * 2;
71 0 : if(m_base_position.Y > 8*BS)
72 0 : m_base_position.Y = 2*BS;
73 :
74 0 : if(send_recommended == false)
75 0 : return;
76 :
77 0 : m_timer1 -= dtime;
78 0 : if(m_timer1 < 0.0)
79 : {
80 0 : m_timer1 += 0.125;
81 :
82 0 : std::string data;
83 :
84 0 : data += itos(0); // 0 = position
85 0 : data += " ";
86 0 : data += itos(m_base_position.X);
87 0 : data += " ";
88 0 : data += itos(m_base_position.Y);
89 0 : data += " ";
90 0 : data += itos(m_base_position.Z);
91 :
92 0 : ActiveObjectMessage aom(getId(), false, data);
93 0 : m_messages_out.push(aom);
94 : }
95 : }
96 :
97 0 : bool getCollisionBox(aabb3f *toset) {
98 0 : return false;
99 : }
100 :
101 0 : bool collideWithObjects() {
102 0 : return false;
103 : }
104 :
105 : private:
106 : float m_timer1;
107 : float m_age;
108 : };
109 :
110 : // Prototype (registers item for deserialization)
111 1 : TestSAO proto_TestSAO(NULL, v3f(0,0,0));
112 :
113 : /*
114 : LuaEntitySAO
115 : */
116 :
117 : // Prototype (registers item for deserialization)
118 1 : LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
119 :
120 1 : LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
121 : const std::string &name, const std::string &state):
122 : ServerActiveObject(env, pos),
123 : m_init_name(name),
124 : m_init_state(state),
125 : m_registered(false),
126 : m_hp(-1),
127 : m_velocity(0,0,0),
128 : m_acceleration(0,0,0),
129 : m_yaw(0),
130 : m_properties_sent(true),
131 : m_last_sent_yaw(0),
132 : m_last_sent_position(0,0,0),
133 : m_last_sent_velocity(0,0,0),
134 : m_last_sent_position_timer(0),
135 : m_last_sent_move_precision(0),
136 : m_armor_groups_sent(false),
137 : m_animation_speed(0),
138 : m_animation_blend(0),
139 : m_animation_loop(true),
140 : m_animation_sent(false),
141 : m_bone_position_sent(false),
142 : m_attachment_parent_id(0),
143 1 : m_attachment_sent(false)
144 : {
145 : // Only register type if no environment supplied
146 1 : if(env == NULL){
147 1 : ServerActiveObject::registerType(getType(), create);
148 1 : return;
149 : }
150 :
151 : // Initialize something to armor groups
152 0 : m_armor_groups["fleshy"] = 100;
153 : }
154 :
155 2 : LuaEntitySAO::~LuaEntitySAO()
156 : {
157 1 : if(m_registered){
158 0 : m_env->getScriptIface()->luaentity_Remove(m_id);
159 : }
160 1 : }
161 :
162 0 : void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
163 : {
164 0 : ServerActiveObject::addedToEnvironment(dtime_s);
165 :
166 : // Create entity from name
167 0 : m_registered = m_env->getScriptIface()->
168 0 : luaentity_Add(m_id, m_init_name.c_str());
169 :
170 0 : if(m_registered){
171 : // Get properties
172 0 : m_env->getScriptIface()->
173 0 : luaentity_GetProperties(m_id, &m_prop);
174 : // Initialize HP from properties
175 0 : m_hp = m_prop.hp_max;
176 : // Activate entity, supplying serialized state
177 0 : m_env->getScriptIface()->
178 0 : luaentity_Activate(m_id, m_init_state.c_str(), dtime_s);
179 : }
180 0 : }
181 :
182 0 : ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
183 : const std::string &data)
184 : {
185 0 : std::string name;
186 0 : std::string state;
187 0 : s16 hp = 1;
188 0 : v3f velocity;
189 0 : float yaw = 0;
190 0 : if(data != ""){
191 0 : std::istringstream is(data, std::ios::binary);
192 : // read version
193 0 : u8 version = readU8(is);
194 : // check if version is supported
195 0 : if(version == 0){
196 0 : name = deSerializeString(is);
197 0 : state = deSerializeLongString(is);
198 : }
199 0 : else if(version == 1){
200 0 : name = deSerializeString(is);
201 0 : state = deSerializeLongString(is);
202 0 : hp = readS16(is);
203 0 : velocity = readV3F1000(is);
204 0 : yaw = readF1000(is);
205 : }
206 : }
207 : // create object
208 0 : infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
209 0 : <<state<<"\")"<<std::endl;
210 0 : LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
211 0 : sao->m_hp = hp;
212 0 : sao->m_velocity = velocity;
213 0 : sao->m_yaw = yaw;
214 0 : return sao;
215 : }
216 :
217 0 : bool LuaEntitySAO::isAttached()
218 : {
219 0 : if(!m_attachment_parent_id)
220 0 : return false;
221 : // Check if the parent still exists
222 0 : ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
223 0 : if(obj)
224 0 : return true;
225 0 : return false;
226 : }
227 :
228 0 : void LuaEntitySAO::step(float dtime, bool send_recommended)
229 : {
230 0 : if(!m_properties_sent)
231 : {
232 0 : m_properties_sent = true;
233 0 : std::string str = getPropertyPacket();
234 : // create message and add to list
235 0 : ActiveObjectMessage aom(getId(), true, str);
236 0 : m_messages_out.push(aom);
237 : }
238 :
239 : // If attached, check that our parent is still there. If it isn't, detach.
240 0 : if(m_attachment_parent_id && !isAttached())
241 : {
242 0 : m_attachment_parent_id = 0;
243 0 : m_attachment_bone = "";
244 0 : m_attachment_position = v3f(0,0,0);
245 0 : m_attachment_rotation = v3f(0,0,0);
246 0 : sendPosition(false, true);
247 : }
248 :
249 0 : m_last_sent_position_timer += dtime;
250 :
251 : // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
252 : // If the object gets detached this comes into effect automatically from the last known origin
253 0 : if(isAttached())
254 : {
255 0 : v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
256 0 : m_base_position = pos;
257 0 : m_velocity = v3f(0,0,0);
258 0 : m_acceleration = v3f(0,0,0);
259 : }
260 : else
261 : {
262 0 : if(m_prop.physical){
263 0 : core::aabbox3d<f32> box = m_prop.collisionbox;
264 0 : box.MinEdge *= BS;
265 0 : box.MaxEdge *= BS;
266 0 : collisionMoveResult moveresult;
267 0 : f32 pos_max_d = BS*0.25; // Distance per iteration
268 0 : v3f p_pos = m_base_position;
269 0 : v3f p_velocity = m_velocity;
270 0 : v3f p_acceleration = m_acceleration;
271 0 : moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
272 : pos_max_d, box, m_prop.stepheight, dtime,
273 : p_pos, p_velocity, p_acceleration,
274 0 : this, m_prop.collideWithObjects);
275 :
276 : // Apply results
277 0 : m_base_position = p_pos;
278 0 : m_velocity = p_velocity;
279 0 : m_acceleration = p_acceleration;
280 : } else {
281 0 : m_base_position += dtime * m_velocity + 0.5 * dtime
282 0 : * dtime * m_acceleration;
283 0 : m_velocity += dtime * m_acceleration;
284 : }
285 :
286 0 : if((m_prop.automatic_face_movement_dir) &&
287 0 : (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)){
288 0 : m_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI + m_prop.automatic_face_movement_dir_offset;
289 : }
290 : }
291 :
292 0 : if(m_registered){
293 0 : m_env->getScriptIface()->luaentity_Step(m_id, dtime);
294 : }
295 :
296 0 : if(send_recommended == false)
297 0 : return;
298 :
299 0 : if(!isAttached())
300 : {
301 : // TODO: force send when acceleration changes enough?
302 0 : float minchange = 0.2*BS;
303 0 : if(m_last_sent_position_timer > 1.0){
304 0 : minchange = 0.01*BS;
305 0 : } else if(m_last_sent_position_timer > 0.2){
306 0 : minchange = 0.05*BS;
307 : }
308 0 : float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
309 0 : move_d += m_last_sent_move_precision;
310 0 : float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
311 0 : if(move_d > minchange || vel_d > minchange ||
312 0 : fabs(m_yaw - m_last_sent_yaw) > 1.0){
313 0 : sendPosition(true, false);
314 : }
315 : }
316 :
317 0 : if(m_armor_groups_sent == false){
318 0 : m_armor_groups_sent = true;
319 : std::string str = gob_cmd_update_armor_groups(
320 0 : m_armor_groups);
321 : // create message and add to list
322 0 : ActiveObjectMessage aom(getId(), true, str);
323 0 : m_messages_out.push(aom);
324 : }
325 :
326 0 : if(m_animation_sent == false){
327 0 : m_animation_sent = true;
328 : std::string str = gob_cmd_update_animation(
329 0 : m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop);
330 : // create message and add to list
331 0 : ActiveObjectMessage aom(getId(), true, str);
332 0 : m_messages_out.push(aom);
333 : }
334 :
335 0 : if(m_bone_position_sent == false){
336 0 : m_bone_position_sent = true;
337 0 : for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
338 0 : std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
339 : // create message and add to list
340 0 : ActiveObjectMessage aom(getId(), true, str);
341 0 : m_messages_out.push(aom);
342 : }
343 : }
344 :
345 0 : if(m_attachment_sent == false){
346 0 : m_attachment_sent = true;
347 0 : std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
348 : // create message and add to list
349 0 : ActiveObjectMessage aom(getId(), true, str);
350 0 : m_messages_out.push(aom);
351 : }
352 : }
353 :
354 0 : std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
355 : {
356 0 : std::ostringstream os(std::ios::binary);
357 :
358 0 : if(protocol_version >= 14)
359 : {
360 0 : writeU8(os, 1); // version
361 0 : os<<serializeString(""); // name
362 0 : writeU8(os, 0); // is_player
363 0 : writeS16(os, getId()); //id
364 0 : writeV3F1000(os, m_base_position);
365 0 : writeF1000(os, m_yaw);
366 0 : writeS16(os, m_hp);
367 :
368 0 : writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here
369 0 : os<<serializeLongString(getPropertyPacket()); // message 1
370 0 : os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
371 0 : os<<serializeLongString(gob_cmd_update_animation(
372 0 : m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3
373 0 : for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
374 0 : os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
375 : }
376 0 : os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
377 : }
378 : else
379 : {
380 0 : writeU8(os, 0); // version
381 0 : os<<serializeString(""); // name
382 0 : writeU8(os, 0); // is_player
383 0 : writeV3F1000(os, m_base_position);
384 0 : writeF1000(os, m_yaw);
385 0 : writeS16(os, m_hp);
386 0 : writeU8(os, 2); // number of messages stuffed in here
387 0 : os<<serializeLongString(getPropertyPacket()); // message 1
388 0 : os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
389 : }
390 :
391 : // return result
392 0 : return os.str();
393 : }
394 :
395 0 : std::string LuaEntitySAO::getStaticData()
396 : {
397 0 : verbosestream<<__FUNCTION_NAME<<std::endl;
398 0 : std::ostringstream os(std::ios::binary);
399 : // version
400 0 : writeU8(os, 1);
401 : // name
402 0 : os<<serializeString(m_init_name);
403 : // state
404 0 : if(m_registered){
405 0 : std::string state = m_env->getScriptIface()->
406 0 : luaentity_GetStaticdata(m_id);
407 0 : os<<serializeLongString(state);
408 : } else {
409 0 : os<<serializeLongString(m_init_state);
410 : }
411 : // hp
412 0 : writeS16(os, m_hp);
413 : // velocity
414 0 : writeV3F1000(os, m_velocity);
415 : // yaw
416 0 : writeF1000(os, m_yaw);
417 0 : return os.str();
418 : }
419 :
420 0 : int LuaEntitySAO::punch(v3f dir,
421 : const ToolCapabilities *toolcap,
422 : ServerActiveObject *puncher,
423 : float time_from_last_punch)
424 : {
425 0 : if (!m_registered){
426 : // Delete unknown LuaEntities when punched
427 0 : m_removed = true;
428 0 : return 0;
429 : }
430 :
431 : // It's best that attachments cannot be punched
432 0 : if (isAttached())
433 0 : return 0;
434 :
435 0 : ItemStack *punchitem = NULL;
436 0 : ItemStack punchitem_static;
437 0 : if (puncher) {
438 0 : punchitem_static = puncher->getWieldedItem();
439 0 : punchitem = &punchitem_static;
440 : }
441 :
442 : PunchDamageResult result = getPunchDamage(
443 : m_armor_groups,
444 : toolcap,
445 : punchitem,
446 0 : time_from_last_punch);
447 :
448 0 : if (result.did_punch) {
449 0 : setHP(getHP() - result.damage);
450 :
451 0 : if (result.damage > 0) {
452 0 : std::string punchername = puncher ? puncher->getDescription() : "nil";
453 :
454 0 : actionstream << getDescription() << " punched by "
455 0 : << punchername << ", damage " << result.damage
456 0 : << " hp, health now " << getHP() << " hp" << std::endl;
457 : }
458 :
459 0 : std::string str = gob_cmd_punched(result.damage, getHP());
460 : // create message and add to list
461 0 : ActiveObjectMessage aom(getId(), true, str);
462 0 : m_messages_out.push(aom);
463 : }
464 :
465 0 : if (getHP() == 0)
466 0 : m_removed = true;
467 :
468 0 : m_env->getScriptIface()->luaentity_Punch(m_id, puncher,
469 0 : time_from_last_punch, toolcap, dir);
470 :
471 0 : return result.wear;
472 : }
473 :
474 0 : void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
475 : {
476 0 : if (!m_registered)
477 0 : return;
478 : // It's best that attachments cannot be clicked
479 0 : if (isAttached())
480 0 : return;
481 0 : m_env->getScriptIface()->luaentity_Rightclick(m_id, clicker);
482 : }
483 :
484 0 : void LuaEntitySAO::setPos(v3f pos)
485 : {
486 0 : if(isAttached())
487 0 : return;
488 0 : m_base_position = pos;
489 0 : sendPosition(false, true);
490 : }
491 :
492 0 : void LuaEntitySAO::moveTo(v3f pos, bool continuous)
493 : {
494 0 : if(isAttached())
495 0 : return;
496 0 : m_base_position = pos;
497 0 : if(!continuous)
498 0 : sendPosition(true, true);
499 : }
500 :
501 0 : float LuaEntitySAO::getMinimumSavedMovement()
502 : {
503 0 : return 0.1 * BS;
504 : }
505 :
506 0 : std::string LuaEntitySAO::getDescription()
507 : {
508 0 : std::ostringstream os(std::ios::binary);
509 0 : os<<"LuaEntitySAO at (";
510 0 : os<<(m_base_position.X/BS)<<",";
511 0 : os<<(m_base_position.Y/BS)<<",";
512 0 : os<<(m_base_position.Z/BS);
513 0 : os<<")";
514 0 : return os.str();
515 : }
516 :
517 0 : void LuaEntitySAO::setHP(s16 hp)
518 : {
519 0 : if(hp < 0) hp = 0;
520 0 : m_hp = hp;
521 0 : }
522 :
523 0 : s16 LuaEntitySAO::getHP() const
524 : {
525 0 : return m_hp;
526 : }
527 :
528 0 : void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
529 : {
530 0 : m_armor_groups = armor_groups;
531 0 : m_armor_groups_sent = false;
532 0 : }
533 :
534 0 : ItemGroupList LuaEntitySAO::getArmorGroups()
535 : {
536 0 : return m_armor_groups;
537 : }
538 :
539 0 : void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop)
540 : {
541 0 : m_animation_range = frame_range;
542 0 : m_animation_speed = frame_speed;
543 0 : m_animation_blend = frame_blend;
544 0 : m_animation_loop = frame_loop;
545 0 : m_animation_sent = false;
546 0 : }
547 :
548 0 : void LuaEntitySAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop)
549 : {
550 0 : *frame_range = m_animation_range;
551 0 : *frame_speed = m_animation_speed;
552 0 : *frame_blend = m_animation_blend;
553 0 : *frame_loop = m_animation_loop;
554 0 : }
555 :
556 0 : void LuaEntitySAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
557 : {
558 0 : m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
559 0 : m_bone_position_sent = false;
560 0 : }
561 :
562 0 : void LuaEntitySAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation)
563 : {
564 0 : *position = m_bone_position[bone].X;
565 0 : *rotation = m_bone_position[bone].Y;
566 0 : }
567 :
568 0 : void LuaEntitySAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation)
569 : {
570 : // Attachments need to be handled on both the server and client.
571 : // If we just attach on the server, we can only copy the position of the parent. Attachments
572 : // are still sent to clients at an interval so players might see them lagging, plus we can't
573 : // read and attach to skeletal bones.
574 : // If we just attach on the client, the server still sees the child at its original location.
575 : // This breaks some things so we also give the server the most accurate representation
576 : // even if players only see the client changes.
577 :
578 0 : m_attachment_parent_id = parent_id;
579 0 : m_attachment_bone = bone;
580 0 : m_attachment_position = position;
581 0 : m_attachment_rotation = rotation;
582 0 : m_attachment_sent = false;
583 0 : }
584 :
585 0 : void LuaEntitySAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
586 : v3f *rotation)
587 : {
588 0 : *parent_id = m_attachment_parent_id;
589 0 : *bone = m_attachment_bone;
590 0 : *position = m_attachment_position;
591 0 : *rotation = m_attachment_rotation;
592 0 : }
593 :
594 0 : ObjectProperties* LuaEntitySAO::accessObjectProperties()
595 : {
596 0 : return &m_prop;
597 : }
598 :
599 0 : void LuaEntitySAO::notifyObjectPropertiesModified()
600 : {
601 0 : m_properties_sent = false;
602 0 : }
603 :
604 0 : void LuaEntitySAO::setVelocity(v3f velocity)
605 : {
606 0 : m_velocity = velocity;
607 0 : }
608 :
609 0 : v3f LuaEntitySAO::getVelocity()
610 : {
611 0 : return m_velocity;
612 : }
613 :
614 0 : void LuaEntitySAO::setAcceleration(v3f acceleration)
615 : {
616 0 : m_acceleration = acceleration;
617 0 : }
618 :
619 0 : v3f LuaEntitySAO::getAcceleration()
620 : {
621 0 : return m_acceleration;
622 : }
623 :
624 0 : void LuaEntitySAO::setYaw(float yaw)
625 : {
626 0 : m_yaw = yaw;
627 0 : }
628 :
629 0 : float LuaEntitySAO::getYaw()
630 : {
631 0 : return m_yaw;
632 : }
633 :
634 0 : void LuaEntitySAO::setTextureMod(const std::string &mod)
635 : {
636 0 : std::string str = gob_cmd_set_texture_mod(mod);
637 : // create message and add to list
638 0 : ActiveObjectMessage aom(getId(), true, str);
639 0 : m_messages_out.push(aom);
640 0 : }
641 :
642 0 : void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
643 : bool select_horiz_by_yawpitch)
644 : {
645 : std::string str = gob_cmd_set_sprite(
646 : p,
647 : num_frames,
648 : framelength,
649 : select_horiz_by_yawpitch
650 0 : );
651 : // create message and add to list
652 0 : ActiveObjectMessage aom(getId(), true, str);
653 0 : m_messages_out.push(aom);
654 0 : }
655 :
656 0 : std::string LuaEntitySAO::getName()
657 : {
658 0 : return m_init_name;
659 : }
660 :
661 0 : std::string LuaEntitySAO::getPropertyPacket()
662 : {
663 0 : return gob_cmd_set_properties(m_prop);
664 : }
665 :
666 0 : void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
667 : {
668 : // If the object is attached client-side, don't waste bandwidth sending its position to clients
669 0 : if(isAttached())
670 0 : return;
671 :
672 0 : m_last_sent_move_precision = m_base_position.getDistanceFrom(
673 0 : m_last_sent_position);
674 0 : m_last_sent_position_timer = 0;
675 0 : m_last_sent_yaw = m_yaw;
676 0 : m_last_sent_position = m_base_position;
677 0 : m_last_sent_velocity = m_velocity;
678 : //m_last_sent_acceleration = m_acceleration;
679 :
680 0 : float update_interval = m_env->getSendRecommendedInterval();
681 :
682 : std::string str = gob_cmd_update_position(
683 : m_base_position,
684 : m_velocity,
685 : m_acceleration,
686 : m_yaw,
687 : do_interpolate,
688 : is_movement_end,
689 : update_interval
690 0 : );
691 : // create message and add to list
692 0 : ActiveObjectMessage aom(getId(), false, str);
693 0 : m_messages_out.push(aom);
694 : }
695 :
696 0 : bool LuaEntitySAO::getCollisionBox(aabb3f *toset) {
697 0 : if (m_prop.physical)
698 : {
699 : //update collision box
700 0 : toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
701 0 : toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
702 :
703 0 : toset->MinEdge += m_base_position;
704 0 : toset->MaxEdge += m_base_position;
705 :
706 0 : return true;
707 : }
708 :
709 0 : return false;
710 : }
711 :
712 0 : bool LuaEntitySAO::collideWithObjects(){
713 0 : return m_prop.collideWithObjects;
714 : }
715 :
716 : /*
717 : PlayerSAO
718 : */
719 :
720 : // No prototype, PlayerSAO does not need to be deserialized
721 :
722 0 : PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
723 : const std::set<std::string> &privs, bool is_singleplayer):
724 : ServerActiveObject(env_, v3f(0,0,0)),
725 : m_player(player_),
726 : m_peer_id(peer_id_),
727 : m_inventory(NULL),
728 : m_damage(0),
729 : m_last_good_position(0,0,0),
730 : m_time_from_last_punch(0),
731 : m_nocheat_dig_pos(32767, 32767, 32767),
732 : m_nocheat_dig_time(0),
733 : m_wield_index(0),
734 : m_position_not_sent(false),
735 : m_armor_groups_sent(false),
736 : m_properties_sent(true),
737 : m_privs(privs),
738 : m_is_singleplayer(is_singleplayer),
739 : m_animation_speed(0),
740 : m_animation_blend(0),
741 : m_animation_loop(true),
742 : m_animation_sent(false),
743 : m_bone_position_sent(false),
744 : m_attachment_parent_id(0),
745 : m_attachment_sent(false),
746 : m_nametag_color(video::SColor(255, 255, 255, 255)),
747 : m_nametag_sent(false),
748 : // public
749 : m_physics_override_speed(1),
750 : m_physics_override_jump(1),
751 : m_physics_override_gravity(1),
752 : m_physics_override_sneak(true),
753 : m_physics_override_sneak_glitch(true),
754 0 : m_physics_override_sent(false)
755 : {
756 : assert(m_player); // pre-condition
757 : assert(m_peer_id != 0); // pre-condition
758 0 : setBasePosition(m_player->getPosition());
759 0 : m_inventory = &m_player->inventory;
760 0 : m_armor_groups["fleshy"] = 100;
761 :
762 0 : m_prop.hp_max = PLAYER_MAX_HP;
763 0 : m_prop.physical = false;
764 0 : m_prop.weight = 75;
765 0 : m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
766 : // start of default appearance, this should be overwritten by LUA
767 0 : m_prop.visual = "upright_sprite";
768 0 : m_prop.visual_size = v2f(1, 2);
769 0 : m_prop.textures.clear();
770 0 : m_prop.textures.push_back("player.png");
771 0 : m_prop.textures.push_back("player_back.png");
772 0 : m_prop.colors.clear();
773 0 : m_prop.colors.push_back(video::SColor(255, 255, 255, 255));
774 0 : m_prop.spritediv = v2s16(1,1);
775 : // end of default appearance
776 0 : m_prop.is_visible = true;
777 0 : m_prop.makes_footstep_sound = true;
778 0 : }
779 :
780 0 : PlayerSAO::~PlayerSAO()
781 : {
782 0 : if(m_inventory != &m_player->inventory)
783 0 : delete m_inventory;
784 :
785 0 : }
786 :
787 0 : std::string PlayerSAO::getDescription()
788 : {
789 0 : return std::string("player ") + m_player->getName();
790 : }
791 :
792 : // Called after id has been set and has been inserted in environment
793 0 : void PlayerSAO::addedToEnvironment(u32 dtime_s)
794 : {
795 0 : ServerActiveObject::addedToEnvironment(dtime_s);
796 0 : ServerActiveObject::setBasePosition(m_player->getPosition());
797 0 : m_player->setPlayerSAO(this);
798 0 : m_player->peer_id = m_peer_id;
799 0 : m_last_good_position = m_player->getPosition();
800 0 : }
801 :
802 : // Called before removing from environment
803 0 : void PlayerSAO::removingFromEnvironment()
804 : {
805 0 : ServerActiveObject::removingFromEnvironment();
806 0 : if(m_player->getPlayerSAO() == this)
807 : {
808 0 : m_player->setPlayerSAO(NULL);
809 0 : m_player->peer_id = 0;
810 0 : m_env->savePlayer(m_player->getName());
811 0 : m_env->removePlayer(m_player->getName());
812 : }
813 0 : }
814 :
815 0 : bool PlayerSAO::isStaticAllowed() const
816 : {
817 0 : return false;
818 : }
819 :
820 0 : std::string PlayerSAO::getClientInitializationData(u16 protocol_version)
821 : {
822 0 : std::ostringstream os(std::ios::binary);
823 :
824 0 : if(protocol_version >= 15)
825 : {
826 0 : writeU8(os, 1); // version
827 0 : os<<serializeString(m_player->getName()); // name
828 0 : writeU8(os, 1); // is_player
829 0 : writeS16(os, getId()); //id
830 0 : writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
831 0 : writeF1000(os, m_player->getYaw());
832 0 : writeS16(os, getHP());
833 :
834 0 : writeU8(os, 6 + m_bone_position.size()); // number of messages stuffed in here
835 0 : os<<serializeLongString(getPropertyPacket()); // message 1
836 0 : os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
837 0 : os<<serializeLongString(gob_cmd_update_animation(
838 0 : m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3
839 0 : for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
840 0 : os<<serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size
841 : }
842 0 : os<<serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4
843 0 : os<<serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed,
844 0 : m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak,
845 0 : m_physics_override_sneak_glitch)); // 5
846 0 : os << serializeLongString(gob_cmd_update_nametag_attributes(m_nametag_color)); // 6
847 : }
848 : else
849 : {
850 0 : writeU8(os, 0); // version
851 0 : os<<serializeString(m_player->getName()); // name
852 0 : writeU8(os, 1); // is_player
853 0 : writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
854 0 : writeF1000(os, m_player->getYaw());
855 0 : writeS16(os, getHP());
856 0 : writeU8(os, 2); // number of messages stuffed in here
857 0 : os<<serializeLongString(getPropertyPacket()); // message 1
858 0 : os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
859 : }
860 :
861 : // return result
862 0 : return os.str();
863 : }
864 :
865 0 : std::string PlayerSAO::getStaticData()
866 : {
867 0 : FATAL_ERROR("Deprecated function (?)");
868 : return "";
869 : }
870 :
871 0 : bool PlayerSAO::isAttached()
872 : {
873 0 : if(!m_attachment_parent_id)
874 0 : return false;
875 : // Check if the parent still exists
876 0 : ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
877 0 : if(obj)
878 0 : return true;
879 0 : return false;
880 : }
881 :
882 0 : void PlayerSAO::step(float dtime, bool send_recommended)
883 : {
884 0 : if(!m_properties_sent)
885 : {
886 0 : m_properties_sent = true;
887 0 : std::string str = getPropertyPacket();
888 : // create message and add to list
889 0 : ActiveObjectMessage aom(getId(), true, str);
890 0 : m_messages_out.push(aom);
891 : }
892 :
893 : // If attached, check that our parent is still there. If it isn't, detach.
894 0 : if(m_attachment_parent_id && !isAttached())
895 : {
896 0 : m_attachment_parent_id = 0;
897 0 : m_attachment_bone = "";
898 0 : m_attachment_position = v3f(0,0,0);
899 0 : m_attachment_rotation = v3f(0,0,0);
900 0 : m_player->setPosition(m_last_good_position);
901 0 : ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
902 : }
903 :
904 : //dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl;
905 :
906 : // Set lag pool maximums based on estimated lag
907 0 : const float LAG_POOL_MIN = 5.0;
908 0 : float lag_pool_max = m_env->getMaxLagEstimate() * 2.0;
909 0 : if(lag_pool_max < LAG_POOL_MIN)
910 0 : lag_pool_max = LAG_POOL_MIN;
911 0 : m_dig_pool.setMax(lag_pool_max);
912 0 : m_move_pool.setMax(lag_pool_max);
913 :
914 : // Increment cheat prevention timers
915 0 : m_dig_pool.add(dtime);
916 0 : m_move_pool.add(dtime);
917 0 : m_time_from_last_punch += dtime;
918 0 : m_nocheat_dig_time += dtime;
919 :
920 : // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
921 : // If the object gets detached this comes into effect automatically from the last known origin
922 0 : if(isAttached())
923 : {
924 0 : v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
925 0 : m_last_good_position = pos;
926 0 : m_player->setPosition(pos);
927 : }
928 :
929 0 : if(send_recommended == false)
930 0 : return;
931 :
932 : // If the object is attached client-side, don't waste bandwidth sending its position to clients
933 0 : if(m_position_not_sent && !isAttached())
934 : {
935 0 : m_position_not_sent = false;
936 0 : float update_interval = m_env->getSendRecommendedInterval();
937 0 : v3f pos;
938 0 : if(isAttached()) // Just in case we ever do send attachment position too
939 0 : pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
940 : else
941 0 : pos = m_player->getPosition() + v3f(0,BS*1,0);
942 : std::string str = gob_cmd_update_position(
943 : pos,
944 : v3f(0,0,0),
945 : v3f(0,0,0),
946 0 : m_player->getYaw(),
947 : true,
948 : false,
949 : update_interval
950 0 : );
951 : // create message and add to list
952 0 : ActiveObjectMessage aom(getId(), false, str);
953 0 : m_messages_out.push(aom);
954 : }
955 :
956 0 : if(m_armor_groups_sent == false) {
957 0 : m_armor_groups_sent = true;
958 : std::string str = gob_cmd_update_armor_groups(
959 0 : m_armor_groups);
960 : // create message and add to list
961 0 : ActiveObjectMessage aom(getId(), true, str);
962 0 : m_messages_out.push(aom);
963 : }
964 :
965 0 : if(m_physics_override_sent == false){
966 0 : m_physics_override_sent = true;
967 : std::string str = gob_cmd_update_physics_override(m_physics_override_speed,
968 : m_physics_override_jump, m_physics_override_gravity,
969 0 : m_physics_override_sneak, m_physics_override_sneak_glitch);
970 : // create message and add to list
971 0 : ActiveObjectMessage aom(getId(), true, str);
972 0 : m_messages_out.push(aom);
973 : }
974 :
975 0 : if(m_animation_sent == false){
976 0 : m_animation_sent = true;
977 : std::string str = gob_cmd_update_animation(
978 0 : m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop);
979 : // create message and add to list
980 0 : ActiveObjectMessage aom(getId(), true, str);
981 0 : m_messages_out.push(aom);
982 : }
983 :
984 0 : if(m_bone_position_sent == false){
985 0 : m_bone_position_sent = true;
986 0 : for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
987 0 : std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
988 : // create message and add to list
989 0 : ActiveObjectMessage aom(getId(), true, str);
990 0 : m_messages_out.push(aom);
991 : }
992 : }
993 :
994 0 : if(m_attachment_sent == false){
995 0 : m_attachment_sent = true;
996 0 : std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
997 : // create message and add to list
998 0 : ActiveObjectMessage aom(getId(), true, str);
999 0 : m_messages_out.push(aom);
1000 : }
1001 :
1002 0 : if (m_nametag_sent == false) {
1003 0 : m_nametag_sent = true;
1004 0 : std::string str = gob_cmd_update_nametag_attributes(m_nametag_color);
1005 : // create message and add to list
1006 0 : ActiveObjectMessage aom(getId(), true, str);
1007 0 : m_messages_out.push(aom);
1008 : }
1009 : }
1010 :
1011 0 : void PlayerSAO::setBasePosition(const v3f &position)
1012 : {
1013 : // This needs to be ran for attachments too
1014 0 : ServerActiveObject::setBasePosition(position);
1015 0 : m_position_not_sent = true;
1016 0 : }
1017 :
1018 0 : void PlayerSAO::setPos(v3f pos)
1019 : {
1020 0 : if(isAttached())
1021 0 : return;
1022 0 : m_player->setPosition(pos);
1023 : // Movement caused by this command is always valid
1024 0 : m_last_good_position = pos;
1025 0 : ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
1026 : }
1027 :
1028 0 : void PlayerSAO::moveTo(v3f pos, bool continuous)
1029 : {
1030 0 : if(isAttached())
1031 0 : return;
1032 0 : m_player->setPosition(pos);
1033 : // Movement caused by this command is always valid
1034 0 : m_last_good_position = pos;
1035 0 : ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
1036 : }
1037 :
1038 0 : void PlayerSAO::setYaw(float yaw)
1039 : {
1040 0 : m_player->setYaw(yaw);
1041 0 : ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
1042 0 : }
1043 :
1044 0 : void PlayerSAO::setPitch(float pitch)
1045 : {
1046 0 : m_player->setPitch(pitch);
1047 0 : ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
1048 0 : }
1049 :
1050 0 : int PlayerSAO::punch(v3f dir,
1051 : const ToolCapabilities *toolcap,
1052 : ServerActiveObject *puncher,
1053 : float time_from_last_punch)
1054 : {
1055 : // It's best that attachments cannot be punched
1056 0 : if (isAttached())
1057 0 : return 0;
1058 :
1059 0 : if (!toolcap)
1060 0 : return 0;
1061 :
1062 : // No effect if PvP disabled
1063 0 : if (g_settings->getBool("enable_pvp") == false) {
1064 0 : if (puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
1065 0 : std::string str = gob_cmd_punched(0, getHP());
1066 : // create message and add to list
1067 0 : ActiveObjectMessage aom(getId(), true, str);
1068 0 : m_messages_out.push(aom);
1069 0 : return 0;
1070 : }
1071 : }
1072 :
1073 : HitParams hitparams = getHitParams(m_armor_groups, toolcap,
1074 0 : time_from_last_punch);
1075 :
1076 0 : std::string punchername = "nil";
1077 :
1078 0 : if (puncher != 0)
1079 0 : punchername = puncher->getDescription();
1080 :
1081 0 : PlayerSAO *playersao = m_player->getPlayerSAO();
1082 :
1083 0 : bool damage_handled = m_env->getScriptIface()->on_punchplayer(playersao,
1084 : puncher, time_from_last_punch, toolcap, dir,
1085 0 : hitparams.hp);
1086 :
1087 0 : if (!damage_handled) {
1088 0 : setHP(getHP() - hitparams.hp);
1089 : } else { // override client prediction
1090 0 : if (puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
1091 0 : std::string str = gob_cmd_punched(0, getHP());
1092 : // create message and add to list
1093 0 : ActiveObjectMessage aom(getId(), true, str);
1094 0 : m_messages_out.push(aom);
1095 : }
1096 : }
1097 :
1098 :
1099 0 : actionstream << "Player " << m_player->getName() << " punched by "
1100 0 : << punchername;
1101 0 : if (!damage_handled) {
1102 0 : actionstream << ", damage " << hitparams.hp << " HP";
1103 : } else {
1104 0 : actionstream << ", damage handled by lua";
1105 : }
1106 0 : actionstream << std::endl;
1107 :
1108 0 : return hitparams.wear;
1109 : }
1110 :
1111 0 : void PlayerSAO::rightClick(ServerActiveObject *clicker)
1112 : {
1113 0 : }
1114 :
1115 0 : s16 PlayerSAO::getHP() const
1116 : {
1117 0 : return m_player->hp;
1118 : }
1119 :
1120 0 : s16 PlayerSAO::readDamage()
1121 : {
1122 0 : s16 damage = m_damage;
1123 0 : m_damage = 0;
1124 0 : return damage;
1125 : }
1126 :
1127 0 : void PlayerSAO::setHP(s16 hp)
1128 : {
1129 0 : s16 oldhp = m_player->hp;
1130 :
1131 0 : s16 hp_change = m_env->getScriptIface()->on_player_hpchange(this,
1132 0 : hp - oldhp);
1133 0 : if (hp_change == 0)
1134 0 : return;
1135 0 : hp = oldhp + hp_change;
1136 :
1137 0 : if (hp < 0)
1138 0 : hp = 0;
1139 0 : else if (hp > PLAYER_MAX_HP)
1140 0 : hp = PLAYER_MAX_HP;
1141 :
1142 0 : if(hp < oldhp && g_settings->getBool("enable_damage") == false) {
1143 0 : return;
1144 : }
1145 :
1146 0 : m_player->hp = hp;
1147 :
1148 0 : if (oldhp > hp)
1149 0 : m_damage += (oldhp - hp);
1150 :
1151 : // Update properties on death
1152 0 : if ((hp == 0) != (oldhp == 0))
1153 0 : m_properties_sent = false;
1154 : }
1155 :
1156 0 : u16 PlayerSAO::getBreath() const
1157 : {
1158 0 : return m_player->getBreath();
1159 : }
1160 :
1161 0 : void PlayerSAO::setBreath(u16 breath)
1162 : {
1163 0 : m_player->setBreath(breath);
1164 0 : }
1165 :
1166 0 : void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
1167 : {
1168 0 : m_armor_groups = armor_groups;
1169 0 : m_armor_groups_sent = false;
1170 0 : }
1171 :
1172 0 : ItemGroupList PlayerSAO::getArmorGroups()
1173 : {
1174 0 : return m_armor_groups;
1175 : }
1176 :
1177 0 : void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop)
1178 : {
1179 : // store these so they can be updated to clients
1180 0 : m_animation_range = frame_range;
1181 0 : m_animation_speed = frame_speed;
1182 0 : m_animation_blend = frame_blend;
1183 0 : m_animation_loop = frame_loop;
1184 0 : m_animation_sent = false;
1185 0 : }
1186 :
1187 0 : void PlayerSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop)
1188 : {
1189 0 : *frame_range = m_animation_range;
1190 0 : *frame_speed = m_animation_speed;
1191 0 : *frame_blend = m_animation_blend;
1192 0 : *frame_loop = m_animation_loop;
1193 0 : }
1194 :
1195 0 : void PlayerSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
1196 : {
1197 : // store these so they can be updated to clients
1198 0 : m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
1199 0 : m_bone_position_sent = false;
1200 0 : }
1201 :
1202 0 : void PlayerSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation)
1203 : {
1204 0 : *position = m_bone_position[bone].X;
1205 0 : *rotation = m_bone_position[bone].Y;
1206 0 : }
1207 :
1208 0 : void PlayerSAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation)
1209 : {
1210 : // Attachments need to be handled on both the server and client.
1211 : // If we just attach on the server, we can only copy the position of the parent. Attachments
1212 : // are still sent to clients at an interval so players might see them lagging, plus we can't
1213 : // read and attach to skeletal bones.
1214 : // If we just attach on the client, the server still sees the child at its original location.
1215 : // This breaks some things so we also give the server the most accurate representation
1216 : // even if players only see the client changes.
1217 :
1218 0 : m_attachment_parent_id = parent_id;
1219 0 : m_attachment_bone = bone;
1220 0 : m_attachment_position = position;
1221 0 : m_attachment_rotation = rotation;
1222 0 : m_attachment_sent = false;
1223 0 : }
1224 :
1225 0 : void PlayerSAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
1226 : v3f *rotation)
1227 : {
1228 0 : *parent_id = m_attachment_parent_id;
1229 0 : *bone = m_attachment_bone;
1230 0 : *position = m_attachment_position;
1231 0 : *rotation = m_attachment_rotation;
1232 0 : }
1233 :
1234 0 : ObjectProperties* PlayerSAO::accessObjectProperties()
1235 : {
1236 0 : return &m_prop;
1237 : }
1238 :
1239 0 : void PlayerSAO::notifyObjectPropertiesModified()
1240 : {
1241 0 : m_properties_sent = false;
1242 0 : }
1243 :
1244 0 : void PlayerSAO::setNametagColor(video::SColor color)
1245 : {
1246 0 : m_nametag_color = color;
1247 0 : m_nametag_sent = false;
1248 0 : }
1249 :
1250 0 : video::SColor PlayerSAO::getNametagColor()
1251 : {
1252 0 : return m_nametag_color;
1253 : }
1254 :
1255 0 : Inventory* PlayerSAO::getInventory()
1256 : {
1257 0 : return m_inventory;
1258 : }
1259 0 : const Inventory* PlayerSAO::getInventory() const
1260 : {
1261 0 : return m_inventory;
1262 : }
1263 :
1264 0 : InventoryLocation PlayerSAO::getInventoryLocation() const
1265 : {
1266 0 : InventoryLocation loc;
1267 0 : loc.setPlayer(m_player->getName());
1268 0 : return loc;
1269 : }
1270 :
1271 0 : std::string PlayerSAO::getWieldList() const
1272 : {
1273 0 : return "main";
1274 : }
1275 :
1276 0 : int PlayerSAO::getWieldIndex() const
1277 : {
1278 0 : return m_wield_index;
1279 : }
1280 :
1281 0 : void PlayerSAO::setWieldIndex(int i)
1282 : {
1283 0 : if(i != m_wield_index) {
1284 0 : m_wield_index = i;
1285 : }
1286 0 : }
1287 :
1288 0 : void PlayerSAO::disconnected()
1289 : {
1290 0 : m_peer_id = 0;
1291 0 : m_removed = true;
1292 0 : if(m_player->getPlayerSAO() == this)
1293 : {
1294 0 : m_player->setPlayerSAO(NULL);
1295 0 : m_player->peer_id = 0;
1296 : }
1297 0 : }
1298 :
1299 0 : std::string PlayerSAO::getPropertyPacket()
1300 : {
1301 0 : m_prop.is_visible = (true);
1302 0 : return gob_cmd_set_properties(m_prop);
1303 : }
1304 :
1305 0 : bool PlayerSAO::checkMovementCheat()
1306 : {
1307 0 : bool cheated = false;
1308 0 : if(isAttached() || m_is_singleplayer ||
1309 0 : g_settings->getBool("disable_anticheat"))
1310 : {
1311 0 : m_last_good_position = m_player->getPosition();
1312 : }
1313 : else
1314 : {
1315 : /*
1316 : Check player movements
1317 :
1318 : NOTE: Actually the server should handle player physics like the
1319 : client does and compare player's position to what is calculated
1320 : on our side. This is required when eg. players fly due to an
1321 : explosion. Altough a node-based alternative might be possible
1322 : too, and much more lightweight.
1323 : */
1324 :
1325 0 : float player_max_speed = 0;
1326 0 : if(m_privs.count("fast") != 0){
1327 : // Fast speed
1328 0 : player_max_speed = m_player->movement_speed_fast;
1329 : } else {
1330 : // Normal speed
1331 0 : player_max_speed = m_player->movement_speed_walk;
1332 : }
1333 : // Tolerance. With the lag pool we shouldn't need it.
1334 : //player_max_speed *= 2.5;
1335 : //player_max_speed_up *= 2.5;
1336 :
1337 0 : v3f diff = (m_player->getPosition() - m_last_good_position);
1338 0 : float d_vert = diff.Y;
1339 0 : diff.Y = 0;
1340 0 : float d_horiz = diff.getLength();
1341 0 : float required_time = d_horiz/player_max_speed;
1342 0 : if(d_vert > 0 && d_vert/player_max_speed > required_time)
1343 0 : required_time = d_vert/player_max_speed;
1344 0 : if(m_move_pool.grab(required_time)){
1345 0 : m_last_good_position = m_player->getPosition();
1346 : } else {
1347 0 : actionstream<<"Player "<<m_player->getName()
1348 0 : <<" moved too fast; resetting position"
1349 0 : <<std::endl;
1350 0 : m_player->setPosition(m_last_good_position);
1351 0 : cheated = true;
1352 : }
1353 : }
1354 0 : return cheated;
1355 : }
1356 :
1357 0 : bool PlayerSAO::getCollisionBox(aabb3f *toset) {
1358 : //update collision box
1359 0 : *toset = m_player->getCollisionbox();
1360 :
1361 0 : toset->MinEdge += m_base_position;
1362 0 : toset->MaxEdge += m_base_position;
1363 :
1364 0 : return true;
1365 : }
1366 :
1367 0 : bool PlayerSAO::collideWithObjects(){
1368 0 : return true;
1369 3 : }
1370 :
|