the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "com.mojang.nbt.h"
3#include "net.minecraft.world.entity.h"
4#include "net.minecraft.world.entity.player.h"
5#include "net.minecraft.world.item.h"
6#include "net.minecraft.world.level.h"
7#include "net.minecraft.world.level.material.h"
8#include "net.minecraft.world.level.tile.h"
9#include "net.minecraft.world.phys.h"
10#include "net.minecraft.world.damagesource.h"
11#include "Boat.h"
12
13const double Boat::MAX_SPEED = 0.35;
14const double Boat::MAX_COLLISION_SPEED = MAX_SPEED * 0.75;
15const double Boat::MIN_ACCELERATION = 0.07;
16const double Boat::MAX_ACCELERATION = 0.35;
17
18// 4J - added for common ctor code
19void Boat::_init()
20{
21 doLerp = true;
22 acceleration = MIN_ACCELERATION;
23
24 lSteps = 0;
25 lx = ly = lz = lyr = lxr = 0.0;
26 lxd = lyd = lzd = 0.0;
27
28 blocksBuilding = true;
29 setSize(1.5f, 0.6f);
30 heightOffset = bbHeight / 2.0f;
31
32 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
33 // the derived version of the function is called
34 this->defineSynchedData();
35}
36
37
38
39Boat::Boat(Level *level) : Entity( level )
40{
41
42 _init();
43}
44
45
46bool Boat::makeStepSound()
47{
48 return false;
49}
50
51void Boat::defineSynchedData()
52{
53 entityData->define(DATA_ID_HURT, 0);
54 entityData->define(DATA_ID_HURTDIR, 1);
55 entityData->define(DATA_ID_DAMAGE, 0.0f);
56}
57
58
59AABB *Boat::getCollideAgainstBox(shared_ptr<Entity> entity)
60{
61 return entity->bb;
62}
63
64AABB *Boat::getCollideBox()
65{
66 return bb;
67}
68
69bool Boat::isPushable()
70{
71 return true;
72}
73
74Boat::Boat(Level *level, double x, double y, double z) : Entity( level )
75{
76 _init();
77 setPos(x, y + heightOffset, z);
78
79 xd = 0;
80 yd = 0;
81 zd = 0;
82
83 xo = x;
84 yo = y;
85 zo = z;
86}
87
88double Boat::getRideHeight()
89{
90 return bbHeight * 0.0f - 0.3f;
91}
92
93bool Boat::hurt(DamageSource *source, float hurtDamage)
94{
95 if (isInvulnerable()) return false;
96 if (level->isClientSide || removed) return true;
97
98 // 4J-JEV: Fix for #88212,
99 // Untrusted players shouldn't be able to damage minecarts or boats.
100 if (dynamic_cast<EntityDamageSource *>(source) != NULL)
101 {
102 shared_ptr<Entity> attacker = source->getDirectEntity();
103
104 if ( attacker->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(attacker)->isAllowedToHurtEntity( shared_from_this() ))
105 {
106 return false;
107 }
108 }
109
110 setHurtDir(-getHurtDir());
111 setHurtTime(10);
112
113 // 4J Stu - If someone is riding in this, then it can tick multiple times which causes the damage to
114 // decrease too quickly. So just make the damage a bit higher to start with for similar behaviour
115 // to an unridden one. Only do this change if the riding player is attacking it.
116 if( rider.lock() != NULL && rider.lock() == source->getEntity() ) hurtDamage += 1;
117
118 setDamage(getDamage() + hurtDamage * 10);
119 markHurt();
120
121 // 4J Stu - Brought froward from 12w36 to fix #46611 - TU5: Gameplay: Minecarts and boat requires more hits than one to be destroyed in creative mode
122 // 4J-PB - Fix for XB1 #175735 - [CRASH] [Multi-Plat]: Code: Gameplay: Placing a boat on harmful surfaces causes the game to crash
123 bool creativePlayer = (source->getEntity() != NULL) && source->getEntity()->instanceof(eTYPE_PLAYER) && dynamic_pointer_cast<Player>(source->getEntity())->abilities.instabuild;
124
125 if (creativePlayer || getDamage() > 20 * 2)
126 {
127 if (rider.lock() != NULL) rider.lock()->ride( shared_from_this() );
128 if (!creativePlayer) spawnAtLocation(Item::boat_Id, 1, 0);
129 remove();
130 }
131 return true;
132}
133
134void Boat::animateHurt()
135{
136 setHurtDir(-getHurtDir());
137 setHurtTime(10);
138 setDamage(getDamage() * 11);
139}
140
141bool Boat::isPickable()
142{
143 return !removed;
144}
145
146
147void Boat::lerpTo(double x, double y, double z, float yRot, float xRot, int steps)
148{
149 if (doLerp)
150 {
151 lSteps = steps + 5;
152 }
153 else
154 {
155 double xdiff = x - this->x;
156 double ydiff = y - this->y;
157 double zdiff = z - this->z;
158 double diff = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff;
159
160 if (diff > 1)
161 {
162 lSteps = 3;
163 }
164 else
165 {
166 return;
167 }
168 }
169
170 lx = x;
171 ly = y;
172 lz = z;
173 lyr = yRot;
174 lxr = xRot;
175
176 xd = lxd;
177 yd = lyd;
178 zd = lzd;
179}
180
181void Boat::lerpMotion(double xd, double yd, double zd)
182{
183 lxd = this->xd = xd;
184 lyd = this->yd = yd;
185 lzd = this->zd = zd;
186}
187
188void Boat::tick()
189{
190 Entity::tick();
191 if (getHurtTime() > 0) setHurtTime(getHurtTime() - 1);
192 if (getDamage() > 0) setDamage(getDamage() - 1);
193 xo = x;
194 yo = y;
195 zo = z;
196
197
198 int steps = 5;
199 double waterPercentage = 0;
200 for (int i = 0; i < steps; i++)
201 {
202 double y0 = bb->y0 + (bb->y1 - bb->y0) * (i + 0) / steps - 2 / 16.0f;
203 double y1 = bb->y0 + (bb->y1 - bb->y0) * (i + 1) / steps - 2 / 16.0f;
204 AABB *bb2 = AABB::newTemp(bb->x0, y0, bb->z0, bb->x1, y1, bb->z1);
205 if (level->containsLiquid(bb2, Material::water))
206 {
207 waterPercentage += 1.0 / steps;
208 }
209 }
210
211 double lastSpeed = sqrt(xd * xd + zd * zd);
212 if (lastSpeed > MAX_COLLISION_SPEED)
213 {
214 double xa = cos(yRot * PI / 180);
215 double za = sin(yRot * PI / 180);
216
217 for (int i = 0; i < 1 + lastSpeed * 60; i++)
218 {
219
220 double side = (random->nextFloat() * 2 - 1);
221
222 double side2 = (random->nextInt(2) * 2 - 1) * 0.7;
223 if (random->nextBoolean())
224 {
225 double xx = x - xa * side * 0.8 + za * side2;
226 double zz = z - za * side * 0.8 - xa * side2;
227 level->addParticle(eParticleType_splash, xx, y - 2 / 16.0f, zz, +xd, yd, +zd);
228 }
229 else
230 {
231 double xx = x + xa + za * side * 0.7;
232 double zz = z + za - xa * side * 0.7;
233 level->addParticle(eParticleType_splash, xx, y - 2 / 16.0f, zz, +xd, yd, +zd);
234 }
235 }
236 }
237
238 if (level->isClientSide && doLerp)
239 {
240 if (lSteps > 0)
241 {
242 double xt = x + (lx - x) / lSteps;
243 double yt = y + (ly - y) / lSteps;
244 double zt = z + (lz - z) / lSteps;
245
246 double yrd = Mth::wrapDegrees(lyr - yRot);
247
248 yRot += (float) ( (yrd) / lSteps );
249 xRot += (float) ( (lxr - xRot) / lSteps );
250
251 lSteps--;
252 setPos(xt, yt, zt);
253 setRot(yRot, xRot);
254 }
255 else
256 {
257#if 1
258 // Original
259 //double xt = x + xd;
260 //double yt = y + yd;
261 //double zt = z + zd;
262 //this->setPos(xt, yt, zt);
263
264 // 4J Stu - Fix for various boat bugs, ensure that we check collision on client-side movement
265 move(xd,yd,zd);
266
267 if (onGround)
268 {
269 xd *= 0.5f;
270 yd *= 0.5f;
271 zd *= 0.5f;
272 }
273 xd *= 0.99f;
274 yd *= 0.95f;
275 zd *= 0.99f;
276#else
277 // 4J Stu - Fix for #8280 - Gameplay : Boats behave erratically when exited next to land.
278 // The client shouldn't change the position of the boat
279 double xt = x;// + xd;
280 double yt = y + yd;
281 double zt = z;// + zd;
282 this->setPos(xt, yt, zt);
283
284 // 4J Stu - Fix for #9579 - GAMEPLAY: Boats with a player in them slowly sink under the water over time, and with no player in them they float into the sky.
285 // Just make the boats bob up and down rather than any other client-side movement when not receiving packets from server
286 if (waterPercentage < 1)
287 {
288 double bob = waterPercentage * 2 - 1;
289 yd += 0.04f * bob;
290 }
291 else
292 {
293 if (yd < 0) yd /= 2;
294 yd += 0.007f;
295 }
296 //if (onGround)
297 //{
298 xd *= 0.5f;
299 yd *= 0.5f;
300 zd *= 0.5f;
301 //}
302 //xd *= 0.99f;
303 //yd *= 0.95f;
304 //zd *= 0.99f;
305#endif
306 }
307 return;
308 }
309
310 if (waterPercentage < 1)
311 {
312 double bob = waterPercentage * 2 - 1;
313 yd += 0.04f * bob;
314 }
315 else
316 {
317 if (yd < 0) yd /= 2;
318 yd += 0.007f;
319 }
320
321
322 if ( rider.lock() != NULL && rider.lock()->instanceof(eTYPE_LIVINGENTITY) )
323 {
324 shared_ptr<LivingEntity> livingRider = dynamic_pointer_cast<LivingEntity>(rider.lock());
325 double forward = livingRider->yya;
326
327 if (forward > 0)
328 {
329 double riderXd = -sin(livingRider->yRot * PI / 180);
330 double riderZd = cos(livingRider->yRot * PI / 180);
331 xd += riderXd * acceleration * 0.05f;
332 zd += riderZd * acceleration * 0.05f;
333 }
334 }
335
336 double curSpeed = sqrt(xd * xd + zd * zd);
337
338 if (curSpeed > MAX_SPEED)
339 {
340 double ratio = MAX_SPEED / curSpeed;
341
342 xd *= ratio;
343 zd *= ratio;
344 curSpeed = MAX_SPEED;
345 }
346
347 if (curSpeed > lastSpeed && acceleration < MAX_ACCELERATION)
348 {
349 acceleration += (MAX_ACCELERATION - acceleration) / 35;
350 if (acceleration > MAX_ACCELERATION) acceleration = MAX_ACCELERATION;
351 }
352 else
353 {
354 acceleration -= (acceleration - MIN_ACCELERATION) / 35;
355 if (acceleration < MIN_ACCELERATION) acceleration = MIN_ACCELERATION;
356 }
357
358 if (onGround)
359 {
360 xd *= 0.5f;
361 yd *= 0.5f;
362 zd *= 0.5f;
363 }
364 move(xd, yd, zd);
365
366 if ((horizontalCollision && lastSpeed > 0.20))
367 {
368 if (!level->isClientSide && !removed)
369 {
370 remove();
371 for (int i = 0; i < 3; i++)
372 {
373 spawnAtLocation(Tile::wood_Id, 1, 0);
374 }
375 for (int i = 0; i < 2; i++)
376 {
377 spawnAtLocation(Item::stick->id, 1, 0);
378 }
379 }
380 }
381 else
382 {
383 xd *= 0.99f;
384 yd *= 0.95f;
385 zd *= 0.99f;
386 }
387
388 xRot = 0;
389 double yRotT = yRot;
390 double xDiff = xo - x;
391 double zDiff = zo - z;
392 if (xDiff * xDiff + zDiff * zDiff > 0.001)
393 {
394 yRotT = (float) (atan2(zDiff, xDiff) * 180 / PI);
395 }
396
397 double rotDiff = Mth::wrapDegrees(yRotT - yRot);
398
399 if (rotDiff > 20) rotDiff = 20;
400 if (rotDiff < -20) rotDiff = -20;
401
402 yRot += (float) rotDiff;
403 setRot(yRot, xRot);
404
405 if(level->isClientSide) return;
406
407 vector<shared_ptr<Entity> > *entities = level->getEntities(shared_from_this(), bb->grow(0.2f, 0, 0.2f));
408 if (entities != NULL && !entities->empty())
409 {
410 AUTO_VAR(itEnd, entities->end());
411 for (AUTO_VAR(it, entities->begin()); it != itEnd; it++)
412 {
413 shared_ptr<Entity> e = (*it); // entities->at(i);
414 if (e != rider.lock() && e->isPushable() && e->GetType() == eTYPE_BOAT)
415 {
416 e->push(shared_from_this());
417 }
418 }
419 }
420
421 for (int i = 0; i < 4; i++)
422 {
423 int xx = Mth::floor(x + ((i % 2) - 0.5) * 0.8);
424 int zz = Mth::floor(z + ((i / 2) - 0.5) * 0.8);
425
426 for (int j = 0; j < 2; j++)
427 {
428 int yy = Mth::floor(y) + j;
429 int tile = level->getTile(xx, yy, zz);
430
431 if (tile == Tile::topSnow_Id)
432 {
433 level->removeTile(xx, yy, zz);
434 }
435 else if (tile == Tile::waterLily_Id)
436 {
437 level->destroyTile(xx, yy, zz, true);
438 }
439 }
440
441 }
442
443 if (rider.lock() != NULL)
444 {
445 if (rider.lock()->removed) rider = weak_ptr<Entity>();
446 }
447}
448
449void Boat::positionRider()
450{
451 if (rider.lock() == NULL) return;
452
453 double xa = cos(yRot * PI / 180) * 0.4;
454 double za = sin(yRot * PI / 180) * 0.4;
455 rider.lock()->setPos(x + xa, y + getRideHeight() + rider.lock()->getRidingHeight(), z + za);
456}
457
458
459void Boat::addAdditonalSaveData(CompoundTag *base)
460{
461}
462
463void Boat::readAdditionalSaveData(CompoundTag *base)
464{
465}
466
467
468float Boat::getShadowHeightOffs()
469{
470 return 0;
471}
472
473wstring Boat::getName()
474{
475 return L"Boat";
476}
477
478bool Boat::interact(shared_ptr<Player> player)
479{
480 if ( (rider.lock() != NULL) && rider.lock()->instanceof(eTYPE_PLAYER) && (rider.lock() != player) ) return true;
481 if (!level->isClientSide)
482 {
483 // 4J HEG - Fixed issue with player not being able to dismount boat (issue #4446)
484 player->ride( rider.lock() == player ? nullptr : shared_from_this() );
485 }
486 return true;
487}
488
489void Boat::setDamage(float damage)
490{
491 entityData->set(DATA_ID_DAMAGE, damage);
492}
493
494float Boat::getDamage()
495{
496 return entityData->getFloat(DATA_ID_DAMAGE);
497}
498
499void Boat::setHurtTime(int hurtTime)
500{
501 entityData->set(DATA_ID_HURT, hurtTime);
502}
503
504int Boat::getHurtTime()
505{
506 return entityData->getInteger(DATA_ID_HURT);
507}
508
509void Boat::setHurtDir(int hurtDir)
510{
511 entityData->set(DATA_ID_HURTDIR, hurtDir);
512}
513
514int Boat::getHurtDir()
515{
516 return entityData->getInteger(DATA_ID_HURTDIR);
517}
518
519bool Boat::getDoLerp()
520{
521 return doLerp;
522}
523
524void Boat::setDoLerp(bool doLerp)
525{
526 this->doLerp = doLerp;
527}