summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Harkness <me@bearbin.net>2020-05-04 23:04:21 +0200
committerGitHub <noreply@github.com>2020-05-04 23:04:21 +0200
commit4e4ef9052ebac129b2e792d6fd458df1e29f45d2 (patch)
tree9aef21bd749e84212d3b15fe2d366bd46d83e313
parentAdd two missing include guards (diff)
downloadcuberite-4e4ef9052ebac129b2e792d6fd458df1e29f45d2.tar
cuberite-4e4ef9052ebac129b2e792d6fd458df1e29f45d2.tar.gz
cuberite-4e4ef9052ebac129b2e792d6fd458df1e29f45d2.tar.bz2
cuberite-4e4ef9052ebac129b2e792d6fd458df1e29f45d2.tar.lz
cuberite-4e4ef9052ebac129b2e792d6fd458df1e29f45d2.tar.xz
cuberite-4e4ef9052ebac129b2e792d6fd458df1e29f45d2.tar.zst
cuberite-4e4ef9052ebac129b2e792d6fd458df1e29f45d2.zip
-rw-r--r--src/Entities/Minecart.cpp384
-rw-r--r--src/Entities/Minecart.h5
2 files changed, 280 insertions, 109 deletions
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index 8b93dc28c..2463200c7 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -158,6 +158,16 @@ void cMinecart::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
// Push cart upwards
AddPosY(1);
}
+ else
+ {
+ // When a minecart gets to a descending rail, it should go down.
+ chunk->GetBlockTypeMeta(relPos.addedY(-1), InsideType, InsideMeta);
+ if (IsBlockRail(InsideType))
+ {
+ // Push cart downwards
+ AddPosY(-1);
+ }
+ }
}
bool WasDetectorRail = false;
@@ -231,7 +241,8 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
SetSpeedX(0); // Correct diagonal movement from curved rails
// Execute both the entity and block collision checks
- bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
if (EntCol || BlckCol)
{
return;
@@ -250,7 +261,8 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
ApplyAcceleration({ 0.0, 0.0, -1.0 }, -0.1);
}
}
- break;
+
+ return;
}
case E_META_RAIL_XM_XP: // EASTWEST
{
@@ -259,7 +271,8 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
SetSpeedY(NO_SPEED);
SetSpeedZ(NO_SPEED);
- bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
if (EntCol || BlckCol)
{
return;
@@ -276,13 +289,21 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
ApplyAcceleration({ -1.0, 0.0, 0.0 }, -0.1);
}
}
- break;
+
+ return;
}
case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
{
SetYaw(270);
SetSpeedX(0);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
+
if (GetSpeedZ() >= 0)
{
// SpeedZ POSITIVE, going SOUTH
@@ -295,13 +316,21 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
AddSpeedZ(1); // Slow down
SetSpeedY(-GetSpeedZ()); // Upward movement is positive (0 minus negative number is positive number)
}
- break;
+
+ return;
}
case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
{
SetYaw(270);
SetSpeedX(0);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
+
if (GetSpeedZ() > 0)
{
// SpeedZ POSITIVE, going SOUTH
@@ -314,13 +343,21 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
AddSpeedZ(-0.5); // Speed up
SetSpeedY(GetSpeedZ()); // Downward movement negative
}
- break;
+
+ return;
}
case E_META_RAIL_ASCEND_XM: // ASCEND EAST
{
SetYaw(180);
SetSpeedZ(NO_SPEED);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
+
if (GetSpeedX() >= NO_SPEED)
{
AddSpeedX(0.5);
@@ -331,13 +368,21 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
AddSpeedX(1);
SetSpeedY(-GetSpeedX());
}
- break;
+
+ return;
}
case E_META_RAIL_ASCEND_XP: // ASCEND WEST
{
SetYaw(180);
SetSpeedZ(0);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
+
if (GetSpeedX() > 0)
{
AddSpeedX(-1);
@@ -348,7 +393,8 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
AddSpeedX(-0.5);
SetSpeedY(GetSpeedX());
}
- break;
+
+ return;
}
case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
{
@@ -356,12 +402,16 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart
SetSpeedY(0);
- TestBlockCollision(a_RailMeta);
- TestEntityCollision(a_RailMeta);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
// SnapToRail handles turning
- break;
+ return;
}
case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
{
@@ -369,10 +419,14 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
- TestBlockCollision(a_RailMeta);
- TestEntityCollision(a_RailMeta);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
- break;
+ return;
}
case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
{
@@ -380,10 +434,14 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
- TestBlockCollision(a_RailMeta);
- TestEntityCollision(a_RailMeta);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
- break;
+ return;
}
case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
{
@@ -391,17 +449,17 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::millisecon
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
- TestBlockCollision(a_RailMeta);
- TestEntityCollision(a_RailMeta);
+ auto BlckCol = TestBlockCollision(a_RailMeta);
+ auto EntCol = TestEntityCollision(a_RailMeta);
+ if (EntCol || BlckCol)
+ {
+ return;
+ }
- break;
- }
- default:
- {
- ASSERT(!"Unhandled rail meta!"); // Dun dun DUN!
- break;
+ return;
}
}
+ UNREACHABLE("Unsupported rail meta type");
}
@@ -724,14 +782,39 @@ void cMinecart::SnapToRail(NIBBLETYPE a_RailMeta)
+bool cMinecart::IsSolidBlockAtPosition(Vector3i a_Pos)
+{
+ BLOCKTYPE Block = m_World->GetBlock(a_Pos);
+ return !IsBlockRail(Block) && cBlockInfo::IsSolid(Block);
+}
+
+
+
+
+
bool cMinecart::IsSolidBlockAtOffset(int a_XOffset, int a_YOffset, int a_ZOffset)
{
- BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT + a_XOffset, POSY_TOINT + a_YOffset, POSZ_TOINT + a_ZOffset);
- if (IsBlockRail(Block) || !cBlockInfo::IsSolid(Block))
+ return IsSolidBlockAtPosition({POSX_TOINT + a_XOffset, POSY_TOINT + a_YOffset, POSZ_TOINT + a_ZOffset});
+}
+
+
+
+
+
+bool cMinecart::IsBlockCollisionAtOffset(Vector3i a_Offset)
+{
+ auto BlockPosition = GetPosition().Floor() + a_Offset;
+ if (!IsSolidBlockAtPosition(BlockPosition))
{
return false;
}
- return true;
+
+ auto bbBlock = cBoundingBox(
+ static_cast<Vector3d>(BlockPosition),
+ static_cast<Vector3d>(BlockPosition + Vector3i(1, 1, 1))
+ );
+
+ return GetBoundingBox().DoesIntersect(bbBlock);
}
@@ -740,135 +823,218 @@ bool cMinecart::IsSolidBlockAtOffset(int a_XOffset, int a_YOffset, int a_ZOffset
bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
{
+ auto SpeedX = GetSpeedX();
+ auto SpeedZ = GetSpeedZ();
+
+ // Don't do anything if minecarts aren't moving.
+ #ifdef __clang__
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wfloat-equal"
+ #endif
+
+ if ((SpeedX == 0) && (SpeedZ == 0))
+ {
+ return false;
+ }
+
+ #ifdef __clang__
+ #pragma clang diagnostic pop
+ #endif
+
+ auto StopTheCart = true;
+ auto StopOffset = Vector3d();
+
switch (a_RailMeta)
{
case E_META_RAIL_ZM_ZP:
{
- if (GetSpeedZ() > 0)
+ if (SpeedZ > 0)
{
- if (IsSolidBlockAtOffset(0, 0, 1))
- {
- // We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P
- cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, static_cast<int>(ceil(GetPosZ()))), 0.5, 1);
- cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
-
- if (bbBlock.DoesIntersect(bbMinecart))
- {
- SetSpeed(0, 0, 0);
- SetPosZ(floor(GetPosZ()) + 0.4);
- return true;
- }
- }
+ StopOffset = Vector3d(0, 0, 0.4);
+ StopTheCart = IsBlockCollisionAtOffset({0, 0, 1});
}
- else if (GetSpeedZ() < 0)
+ else // SpeedZ < 0
{
- if (IsSolidBlockAtOffset(0, 0, -1))
- {
- cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1), 0.5, 1);
- cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());
-
- if (bbBlock.DoesIntersect(bbMinecart))
- {
- SetSpeed(0, 0, 0);
- SetPosZ(floor(GetPosZ()) + 0.65);
- return true;
- }
- }
+ StopTheCart = IsBlockCollisionAtOffset({0, 0, -1});
+ StopOffset = Vector3d(0, 0, 0.65);
}
break;
}
case E_META_RAIL_XM_XP:
{
- if (GetSpeedX() > 0)
+ if (SpeedX > 0)
{
- if (IsSolidBlockAtOffset(1, 0, 0))
- {
- cBoundingBox bbBlock(Vector3d(static_cast<int>(ceil(GetPosX())), POSY_TOINT, POSZ_TOINT), 0.5, 1);
- cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
-
- if (bbBlock.DoesIntersect(bbMinecart))
- {
- SetSpeed(0, 0, 0);
- SetPosX(floor(GetPosX()) + 0.4);
- return true;
- }
- }
+ StopTheCart = IsBlockCollisionAtOffset({1, 0, 0});
+ StopOffset = Vector3d(0.4, 0, 0);
}
- else if (GetSpeedX() < 0)
+ else // SpeedX < 0
{
- if (IsSolidBlockAtOffset(-1, 0, 0))
- {
- cBoundingBox bbBlock(Vector3d(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT), 0.5, 1);
- cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
-
- if (bbBlock.DoesIntersect(bbMinecart))
- {
- SetSpeed(0, 0, 0);
- SetPosX(floor(GetPosX()) + 0.65);
- return true;
- }
- }
+ StopTheCart = IsBlockCollisionAtOffset({-1, 0, 0});
+ StopOffset = Vector3d(0.65, 0, 0);
}
break;
}
- case E_META_RAIL_CURVED_ZM_XM:
+
+ // Ascending rails check for one block on the way up, two on the way down.
+ case E_META_RAIL_ASCEND_XM:
{
- bool IsBlockXM = IsSolidBlockAtOffset(-1, 0, 0);
- bool IsBlockZM = IsSolidBlockAtOffset(0, 0, -1);
+ StopOffset = Vector3d(0.5, 0, 0);
- if (((GetSpeedZ() < 0) && IsBlockZM) || ((GetSpeedX() < 0) && IsBlockXM))
+ if (SpeedX < 0)
{
- SetSpeed(0, 0, 0);
- SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5);
- return true;
+ StopTheCart = IsBlockCollisionAtOffset({-1, 1, 0});
}
+ else // SpeedX > 0
+ {
+ StopTheCart = IsBlockCollisionAtOffset({1, 0, 0}) || IsBlockCollisionAtOffset({1, 1, 0});
+ }
+ break;
+ }
+ case E_META_RAIL_ASCEND_XP:
+ {
+ StopOffset = Vector3d(0.5, 0, 0);
+ if (SpeedX > 0)
+ {
+ StopTheCart = IsBlockCollisionAtOffset({1, 1, 0});
+ }
+ else // SpeedX < 0
+ {
+ StopTheCart = IsBlockCollisionAtOffset({-1, 0, 0}) || IsBlockCollisionAtOffset({-1, 1, 0});
+ }
break;
}
- case E_META_RAIL_CURVED_ZM_XP:
+ case E_META_RAIL_ASCEND_ZM:
+ {
+ StopOffset = Vector3d(0, 0, 0.5);
+
+ if (SpeedZ < 0)
+ {
+ StopTheCart = IsBlockCollisionAtOffset({0, 1, -1});
+ }
+ else // SpeedZ > 0
+ {
+ StopTheCart = IsBlockCollisionAtOffset({0, 0, 1}) || IsBlockCollisionAtOffset({0, 1, 1});
+ }
+ break;
+ }
+ case E_META_RAIL_ASCEND_ZP:
+ {
+ StopOffset = Vector3d(0, 0, 0.5);
+
+ if (SpeedZ > 0)
+ {
+ StopTheCart = IsBlockCollisionAtOffset({0, 1, 1});
+ }
+ else // SpeedZ < 0
+ {
+ StopTheCart = IsBlockCollisionAtOffset({0, 0, -1}) || IsBlockCollisionAtOffset({0, 1, -1});
+ }
+ break;
+ }
+
+ // Curved rails allow movement across both the x and z axes. But when the cart is
+ // moving towards one of the rail endpoints, it will always have velocity towards
+ // the direction of that endpoint in the same axis.
+ case E_META_RAIL_CURVED_ZP_XP:
{
- bool IsBlockXP = IsSolidBlockAtOffset(1, 0, 0);
- bool IsBlockZM = IsSolidBlockAtOffset(0, 0, -1);
+ StopOffset = Vector3d(0.5, 0, 0.5);
- if (((GetSpeedZ() < 0) && IsBlockZM) || ((GetSpeedX() > 0) && IsBlockXP))
+ if (SpeedZ > 0)
{
- SetSpeed(0, 0, 0);
- SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5);
- return true;
+ StopTheCart = IsBlockCollisionAtOffset({0, 0, 1});
+ break;
+ }
+ if (SpeedX > 0)
+ {
+ StopTheCart = IsBlockCollisionAtOffset({1, 0, 0});
+ break;
}
break;
+ UNREACHABLE("Invalid minecart movement");
}
case E_META_RAIL_CURVED_ZP_XM:
{
- bool IsBlockXM = IsSolidBlockAtOffset(-1, 0, 0);
- bool IsBlockZP = IsSolidBlockAtOffset(0, 0, +1);
+ StopOffset = Vector3d(0.5, 0, 0.5);
- if (((GetSpeedZ() > 0) && IsBlockZP) || ((GetSpeedX() < 0) && IsBlockXM))
+ if (SpeedZ > 0)
{
- SetSpeed(0, 0, 0);
- SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5);
- return true;
+ StopTheCart = IsBlockCollisionAtOffset({0, 0, 1});
+ break;
+ }
+ if (SpeedX < 0)
+ {
+ StopTheCart = IsBlockCollisionAtOffset({-1, 0, 0});
+ break;
}
break;
+ UNREACHABLE("Invalid minecart movement");
}
- case E_META_RAIL_CURVED_ZP_XP:
+ case E_META_RAIL_CURVED_ZM_XM:
{
- bool IsBlockXP = IsSolidBlockAtOffset(1, 0, 0);
- bool IsBlockZP = IsSolidBlockAtOffset(0, 0, 1);
+ StopOffset = Vector3d(0.5, 0, 0.5);
- if (((GetSpeedZ() > 0) && IsBlockZP) || ((GetSpeedX() > 0) && IsBlockXP))
+ if (SpeedZ < 0)
{
- SetSpeed(0, 0, 0);
- SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5);
- return true;
+ StopTheCart = IsBlockCollisionAtOffset({0, 0, -1});
+ break;
+ }
+ if (SpeedX < 0)
+ {
+ StopTheCart = IsBlockCollisionAtOffset({-1, 0, 0});
+ break;
}
break;
+ UNREACHABLE("Invalid minecart movement");
}
- default: break;
+ case E_META_RAIL_CURVED_ZM_XP:
+ {
+ StopOffset = Vector3d(0.5, 0, 0.5);
+
+ if (SpeedZ < 0)
+ {
+ StopTheCart = IsBlockCollisionAtOffset({0, 0, -1});
+ break;
+ }
+ if (SpeedX > 0)
+ {
+ StopTheCart = IsBlockCollisionAtOffset({1, 0, 0});
+ break;
+ }
+
+ break;
+ UNREACHABLE("Invalid minecart movement");
+ }
+ }
+
+ if (StopTheCart)
+ {
+ SetSpeed(0, 0, 0);
+
+ #ifdef __clang__
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wfloat-equal"
+ #endif
+
+ if (StopOffset.x != 0)
+ {
+ SetPosX(POSX_TOINT + StopOffset.x);
+ }
+ if (StopOffset.z != 0)
+ {
+ SetPosZ(POSZ_TOINT + StopOffset.z);
+ }
+
+ #ifdef __clang__
+ #pragma clang diagnostic pop
+ #endif
+
+ return true;
}
+
return false;
}
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index fe9ad8ce8..ad3b3d40d 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -83,8 +83,13 @@ protected:
void SnapToRail(NIBBLETYPE a_RailMeta);
/** Tests if a solid block is in front of a cart, and stops the cart (and returns true) if so; returns false if no obstruction */
bool TestBlockCollision(NIBBLETYPE a_RailMeta);
+ /** Tests if there is a block at the specified position which is impassable to minecarts */
+ bool IsSolidBlockAtPosition(Vector3i a_Offset);
/** Tests if a solid block is at a specific offset of the minecart position */
bool IsSolidBlockAtOffset(int a_XOffset, int a_YOffset, int a_ZOffset);
+
+ bool IsBlockCollisionAtOffset(Vector3i a_Offset);
+
/** Tests if this mincecart's bounding box is intersecting another entity's bounding box (collision) and pushes mincecart away if necessary */
bool TestEntityCollision(NIBBLETYPE a_RailMeta);