summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/DeprecatedBindings.cpp46
-rw-r--r--src/Bindings/ManualBindings.cpp206
-rw-r--r--src/BlockTracer.h8
-rw-r--r--src/Entities/Entity.cpp95
-rw-r--r--src/Entities/ProjectileEntity.cpp2
-rw-r--r--src/Items/ItemBoat.h2
-rw-r--r--src/Items/ItemBottle.h2
-rw-r--r--src/Items/ItemBucket.h9
-rw-r--r--src/Items/ItemLilypad.h2
-rw-r--r--src/LineBlockTracer.cpp94
-rw-r--r--src/LineBlockTracer.h33
-rw-r--r--src/Mobs/AggressiveMonster.cpp17
-rw-r--r--src/Mobs/Enderman.cpp20
-rw-r--r--src/Tracer.h10
-rw-r--r--src/World.cpp38
15 files changed, 482 insertions, 102 deletions
diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp
index 0ffc58cbb..029d4edb7 100644
--- a/src/Bindings/DeprecatedBindings.cpp
+++ b/src/Bindings/DeprecatedBindings.cpp
@@ -10,6 +10,7 @@
#include "../World.h"
#include "../Entities/Player.h"
#include "LuaState.h"
+#include "../Tracer.h"
@@ -291,6 +292,47 @@ tolua_lerror:
+/* method: Trace of class cTracer */
+static int tolua_cTracer_Trace(lua_State * a_LuaState)
+{
+ // Log a deprecation warning with stacktrace:
+ cLuaState S(a_LuaState);
+ LOGWARNING("The function cTracer:Trace is obsolete, use the cLineBlockTracer instead");
+ S.LogStackTrace();
+
+ // Check params:
+ if (
+ !S.CheckParamUserType(1, "cTracer") ||
+ !S.CheckParamUserType(2, "const Vector3<float>", 3) ||
+ !S.CheckParamNumber (4)
+ )
+ {
+ return 0;
+ }
+
+ // Read params:
+ cTracer * self;
+ Vector3d * start;
+ Vector3d * direction;
+ int distance;
+ bool lineOfSight = false;
+ if (!S.GetStackValues(1, self, start, direction, distance))
+ {
+ LOGWARNING("Cannot retrieve parameters for cTracer::Trace. Expected a cTracer (self), Vector3d, Vector3d, number and optional boolean.");
+ S.LogStackValues();
+ return 0;
+ }
+ S.GetStackValue(5, lineOfSight);
+
+ // Call and push the result:
+ S.Push(self->Trace(*start, *direction, distance, lineOfSight));
+ return 1;
+}
+
+
+
+
+
/** function: cWorld:SetSignLines */
static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
{
@@ -398,6 +440,10 @@ void DeprecatedBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "StringToMobType", tolua_AllToLua_StringToMobType00);
+ tolua_beginmodule(tolua_S, "cTracer");
+ tolua_function(tolua_S, "Trace", tolua_cTracer_Trace);
+ tolua_endmodule(tolua_S);
+
tolua_beginmodule(tolua_S, "cWorld");
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
tolua_endmodule(tolua_S);
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index c2392063a..1ad427331 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -2605,7 +2605,7 @@ public:
{
}
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{
bool res = false;
if (!m_Callbacks->CallTableFn(
@@ -2683,6 +2683,202 @@ protected:
+static int tolua_cLineBlockTracer_FirstSolidHitTrace(lua_State * tolua_S)
+{
+ /* Supported function signatures:
+ cLineBlockTracer:FirstSolidHitTrace(World, StartX, StartY, StartZ, EndX, EndY, EndZ) -> bool, [Vector3d, Vector3i, eBlockFace] // Canonical
+ cLineBlockTracer:FirstSolidHitTrace(World, Start, End) -> bool, [Vector3d, Vector3i, eBlockFace] // Canonical
+ cLineBlockTracer.FirstSolidHitTrace(World, StartX, StartY, StartZ, EndX, EndY, EndZ) -> bool, [Vector3d, Vector3i, eBlockFace]
+ cLineBlockTracer.FirstSolidHitTrace(World, Start, End) -> bool, [Vector3d, Vector3i, eBlockFace]
+ */
+
+ // If the first param is the cLineBlockTracer class, shift param index by one:
+ int idx = 1;
+ tolua_Error err;
+ if (tolua_isusertable(tolua_S, 1, "cLineBlockTracer", 0, &err))
+ {
+ idx = 2;
+ }
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(idx, "cWorld")
+ )
+ {
+ return 0;
+ }
+
+ if (L.IsParamNumber(idx + 1))
+ {
+ // This is the number variant of the call:
+ if (
+ !L.CheckParamNumber(idx + 1, idx + 6) ||
+ !L.CheckParamEnd(idx + 7)
+ )
+ {
+ return 0;
+ }
+ // Get the params:
+ cWorld * world;
+ double startX, startY, startZ;
+ double endX, endY, endZ;
+ if (!L.GetStackValues(idx, world, startX, startY, startZ, endX, endY, endZ))
+ {
+ LOGWARNING("cLineBlockTracer:FirstSolidHitTrace(): Cannot read parameters, aborting the trace.");
+ L.LogStackTrace();
+ L.LogStackValues("Values on the stack");
+ return 0;
+ }
+ Vector3d hitCoords;
+ Vector3i hitBlockCoords;
+ eBlockFace hitBlockFace;
+ auto isHit = cLineBlockTracer::FirstSolidHitTrace(*world, Vector3d(startX, startY, startZ), Vector3d(endX, endY, endZ), hitCoords, hitBlockCoords, hitBlockFace);
+ L.Push(isHit);
+ if (!isHit)
+ {
+ return 1;
+ }
+ L.Push(hitCoords);
+ L.Push(hitBlockCoords);
+ L.Push(hitBlockFace);
+ return 4;
+ }
+
+ if (L.IsParamUserType(idx + 1, "Vector3<double>"))
+ {
+ // This is the Vector3d-based variant of the call:
+ if (
+ !L.CheckParamUserType(idx + 1, "Vector3<double>", idx + 2) ||
+ !L.CheckParamEnd(idx + 3)
+ )
+ {
+ return 0;
+ }
+ // Get the params:
+ cWorld * world;
+ Vector3d * start;
+ Vector3d * end;
+ if (!L.GetStackValues(idx, world, start, end))
+ {
+ LOGWARNING("cLineBlockTracer:FirstSolidHitTrace(): Cannot read parameters, aborting the trace.");
+ L.LogStackTrace();
+ L.LogStackValues("Values on the stack");
+ return 0;
+ }
+ Vector3d hitCoords;
+ Vector3i hitBlockCoords;
+ eBlockFace hitBlockFace;
+ auto isHit = cLineBlockTracer::FirstSolidHitTrace(*world, start, end, hitCoords, hitBlockCoords, hitBlockFace);
+ L.Push(isHit);
+ if (!isHit)
+ {
+ return 1;
+ }
+ L.Push(hitCoords);
+ L.Push(hitBlockCoords);
+ L.Push(hitBlockFace);
+ return 4;
+ }
+
+ tolua_error(L, "cLineBlockTracer:FirstSolidHitTrace(): Invalid parameters, expected either a set of coords, or two Vector3d's", nullptr);
+ return 0;
+}
+
+
+
+
+
+static int tolua_cLineBlockTracer_LineOfSightTrace(lua_State * tolua_S)
+{
+ /* Supported function signatures:
+ cLineBlockTracer:LineOfSightTrace(World, StartX, StartY, StartZ, EndX, EndY, EndZ, Sight) -> bool // Canonical
+ cLineBlockTracer:LineOfSightTrace(World, Start, End, Sight) -> bool // Canonical
+ cLineBlockTracer.LineOfSightTrace(World, StartX, StartY, StartZ, EndX, EndY, EndZ, Sight) -> bool
+ cLineBlockTracer.LineOfSightTrace(World, Start, End, Sight) -> bool
+ */
+
+ // If the first param is the cLineBlockTracer class, shift param index by one:
+ int idx = 1;
+ tolua_Error err;
+ if (tolua_isusertable(tolua_S, 1, "cLineBlockTracer", 0, &err))
+ {
+ idx = 2;
+ }
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(idx, "cWorld")
+ )
+ {
+ return 0;
+ }
+
+ if (L.IsParamNumber(idx + 1))
+ {
+ // This is the number variant of the call:
+ if (
+ !L.CheckParamNumber(idx + 1, idx + 6) ||
+ // Optional param lineOfSight is not checked
+ !L.CheckParamEnd(idx + 8)
+ )
+ {
+ return 0;
+ }
+ // Get the params:
+ cWorld * world;
+ double startX, startY, startZ;
+ double endX, endY, endZ;
+ if (!L.GetStackValues(idx, world, startX, startY, startZ, endX, endY, endZ))
+ {
+ LOGWARNING("cLineBlockTracer:LineOfSightTrace(): Cannot read parameters, aborting the trace.");
+ L.LogStackTrace();
+ L.LogStackValues("Values on the stack");
+ return 0;
+ }
+ int lineOfSight = cLineBlockTracer::losAir | cLineBlockTracer::losWater;
+ L.GetStackValue(idx + 7, lineOfSight);
+ L.Push(cLineBlockTracer::LineOfSightTrace(*world, Vector3d(startX, startY, startZ), Vector3d(endX, endY, endZ), lineOfSight));
+ return 1;
+ }
+
+ if (L.IsParamUserType(idx + 1, "Vector3<double>"))
+ {
+ // This is the Vector3d-based variant of the call:
+ if (
+ !L.CheckParamUserType(idx + 1, "Vector3<double>", idx + 2) ||
+ // Optional param lineOfSight is not checked
+ !L.CheckParamEnd(idx + 4)
+ )
+ {
+ return 0;
+ }
+ // Get the params:
+ cWorld * world;
+ Vector3d * start;
+ Vector3d * end;
+ if (!L.GetStackValues(idx, world, start, end))
+ {
+ LOGWARNING("cLineBlockTracer:LineOfSightTrace(): Cannot read parameters, aborting the trace.");
+ L.LogStackTrace();
+ L.LogStackValues("Values on the stack");
+ return 0;
+ }
+ int lineOfSight = cLineBlockTracer::losAirWater;
+ L.GetStackValue(idx + 7, lineOfSight);
+ L.Push(cLineBlockTracer::LineOfSightTrace(*world, start, end, lineOfSight));
+ return 1;
+ }
+
+ tolua_error(L, "cLineBlockTracer:LineOfSightTrace(): Invalid parameters, expected either a set of coords, or two Vector3d's", nullptr);
+ return 0;
+}
+
+
+
+
+
static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
{
/* Supported function signatures:
@@ -3917,7 +4113,13 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cLineBlockTracer");
- tolua_function(tolua_S, "Trace", tolua_cLineBlockTracer_Trace);
+ tolua_function(tolua_S, "FirstSolidHitTrace", tolua_cLineBlockTracer_FirstSolidHitTrace);
+ tolua_function(tolua_S, "LineOfSightTrace", tolua_cLineBlockTracer_LineOfSightTrace);
+ tolua_function(tolua_S, "Trace", tolua_cLineBlockTracer_Trace);
+
+ tolua_constant(tolua_S, "losAir", cLineBlockTracer::losAir);
+ tolua_constant(tolua_S, "losWater", cLineBlockTracer::losWater);
+ tolua_constant(tolua_S, "losLava", cLineBlockTracer::losLava);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cLuaWindow");
diff --git a/src/BlockTracer.h b/src/BlockTracer.h
index 7444af488..2cb97c569 100644
--- a/src/BlockTracer.h
+++ b/src/BlockTracer.h
@@ -13,6 +13,12 @@
+#include "Defines.h"
+
+
+
+
+
// fwd: World.h
class cWorld;
@@ -34,7 +40,7 @@ public:
/** Called on each block encountered along the path, including the first block (path start)
When this callback returns true, the tracing is aborted.
*/
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) = 0;
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) = 0;
/** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded
When this callback returns true, the tracing is aborted.
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 7b1849b9f..dff7114d5 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -9,7 +9,7 @@
#include "../Chunk.h"
#include "../Simulator/FluidSimulator.h"
#include "../Bindings/PluginManager.h"
-#include "../Tracer.h"
+#include "../LineBlockTracer.h"
#include "Player.h"
#include "Items/ItemHandler.h"
#include "../FastRandom.h"
@@ -1071,29 +1071,38 @@ void cEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
// Get water direction
Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ);
- m_WaterSpeed *= 0.9f; // Reduce speed each tick
+ m_WaterSpeed *= 0.9; // Reduce speed each tick
switch (WaterDir)
{
case X_PLUS:
+ {
m_WaterSpeed.x = 0.2f;
m_bOnGround = false;
break;
+ }
case X_MINUS:
+ {
m_WaterSpeed.x = -0.2f;
m_bOnGround = false;
break;
+ }
case Z_PLUS:
+ {
m_WaterSpeed.z = 0.2f;
m_bOnGround = false;
break;
+ }
case Z_MINUS:
+ {
m_WaterSpeed.z = -0.2f;
m_bOnGround = false;
break;
-
- default:
- break;
+ }
+ default:
+ {
+ break;
+ }
}
if (fabs(m_WaterSpeed.x) < 0.05)
@@ -1110,60 +1119,54 @@ void cEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
if (NextSpeed.SqrLength() > 0.0f)
{
- cTracer Tracer(GetWorld());
- // Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse
- int DistanceToTrace = CeilC((NextSpeed * DtSec.count()).SqrLength()) * 2;
- bool HasHit = Tracer.Trace(NextPos, NextSpeed, DistanceToTrace);
-
- if (HasHit)
+ Vector3d HitCoords;
+ Vector3i HitBlockCoords;
+ eBlockFace HitBlockFace;
+ if (cLineBlockTracer::FirstSolidHitTrace(*GetWorld(), NextPos, NextPos + NextSpeed, HitCoords, HitBlockCoords, HitBlockFace))
{
- // Oh noez! We hit something: verify that the (hit position - current) was smaller or equal to the (position that we should travel without obstacles - current)
- // This is because previously, we traced with a length that was rounded up (due to integer limitations), and in the case that something was hit, we don't want to overshoot our projected movement
- if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * DtSec.count()).SqrLength())
+ // Set our position to where the block was hit, minus a bit:
+ // TODO: The real entity's m_Width should be taken into account here
+ NextPos = HitCoords - NextSpeed.NormalizeCopy() * 0.1;
+ if (HitBlockFace == BLOCK_FACE_YM)
{
- // Block hit was within our projected path
- // Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1.
- // For example: HitNormal.y = -1 : BLOCK_FACE_YM; HitNormal.y = 1 : BLOCK_FACE_YP
- if (Tracer.HitNormal.x != 0.0f)
+ // We hit the ground, adjust the position to the top of the block:
+ m_bOnGround = true;
+ NextPos.y = HitBlockCoords.y + 1;
+ }
+
+ // Avoid movement in the direction of the blockface that has been hit:
+ switch (HitBlockFace)
+ {
+ case BLOCK_FACE_XM:
+ case BLOCK_FACE_XP:
{
- NextSpeed.x = 0.0f;
+ NextSpeed.x = 0;
+ break;
}
- if (Tracer.HitNormal.y != 0.0f)
+ case BLOCK_FACE_YM:
+ case BLOCK_FACE_YP:
{
- NextSpeed.y = 0.0f;
+ NextSpeed.y = 0;
+ break;
}
- if (Tracer.HitNormal.z != 0.0f)
+ case BLOCK_FACE_ZM:
+ case BLOCK_FACE_ZP:
{
- NextSpeed.z = 0.0f;
+ NextSpeed.z = 0;
+ break;
}
-
- // Now, set our position to the hit block (i.e. move part way along our intended trajectory)
- NextPos.Set(Tracer.RealHit.x, Tracer.RealHit.y, Tracer.RealHit.z);
- NextPos.x += Tracer.HitNormal.x * 0.1;
- NextPos.y += Tracer.HitNormal.y * 0.05;
- NextPos.z += Tracer.HitNormal.z * 0.1;
-
- if (Tracer.HitNormal.y == 1.0f) // Hit BLOCK_FACE_YP, we are on the ground
+ default:
{
- m_bOnGround = true;
- NextPos.y = FloorC(NextPos.y); // we clamp the height to 0 cos otherwise we'll constantly be slightly above the block
+ break;
}
}
- else
- {
- // We have hit a block but overshot our intended trajectory, move normally, safe in the warm cocoon of knowledge that we won't appear to teleport forwards on clients,
- // and that this piece of software will come to be hailed as the epitome of performance and functionality in C++, never before seen, and of such a like that will never
- // be henceforth seen again in the time of programmers and man alike
- // </&sensationalist>
- NextPos += (NextSpeed * DtSec.count());
- }
- }
- else
- {
- // We didn't hit anything, so move =]
- NextPos += (NextSpeed * DtSec.count());
}
}
+ else
+ {
+ // We didn't hit anything, so move =]
+ NextPos += (NextSpeed * DtSec.count());
+ }
SetPosition(NextPos);
SetSpeed(NextSpeed);
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 3bded2b56..64522acef 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -56,7 +56,7 @@ protected:
double m_SlowdownCoeff;
// cCallbacks overrides:
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{
/*
// DEBUG:
diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h
index ced5ec3a8..493605483 100644
--- a/src/Items/ItemBoat.h
+++ b/src/Items/ItemBoat.h
@@ -50,7 +50,7 @@ public:
{
}
- virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override
+ virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
{
if (a_CBBlockType != E_BLOCK_AIR)
{
diff --git a/src/Items/ItemBottle.h b/src/Items/ItemBottle.h
index d2ca30def..092d5d81a 100644
--- a/src/Items/ItemBottle.h
+++ b/src/Items/ItemBottle.h
@@ -33,7 +33,7 @@ public:
{
}
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{
if (IsBlockWater(a_BlockType))
{
diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h
index 180a363ec..18b7bb46f 100644
--- a/src/Items/ItemBucket.h
+++ b/src/Items/ItemBucket.h
@@ -196,7 +196,7 @@ public:
{
}
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{
if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType))
{
@@ -241,7 +241,7 @@ public:
NIBBLETYPE m_ReplacedBlockMeta;
eBlockFace m_EntryFace;
- virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override
+ virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
{
if (a_CBBlockType != E_BLOCK_AIR)
{
@@ -250,7 +250,7 @@ public:
m_EntryFace = static_cast<eBlockFace>(a_CBEntryFace);
if (!cFluidSimulator::CanWashAway(a_CBBlockType) && !IsBlockLiquid(a_CBBlockType))
{
- AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, static_cast<eBlockFace>(a_CBEntryFace)); // Was an unwashawayable block, can't overwrite it!
+ AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, a_CBEntryFace); // Was an unwashawayable block, can't overwrite it!
}
m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ); // (Block could be washed away, replace it)
return true; // Abort tracing
@@ -263,7 +263,8 @@ public:
Vector3d Start(a_Player->GetEyePosition());
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
- // cTracer::Trace returns true when whole line was traversed. By returning true from the callback when we hit something, we ensure that this never happens if liquid could be placed
+ // cLineBlockTracer::Trace() returns true when whole line was traversed. By returning true from the callback when we hit something,
+ // we ensure that this never happens if liquid could be placed
// Use this to judge whether the position is valid
if (!Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z))
{
diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h
index 7eede5864..3d07efb03 100644
--- a/src/Items/ItemLilypad.h
+++ b/src/Items/ItemLilypad.h
@@ -57,7 +57,7 @@ public:
{
}
- virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override
+ virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
{
if (IsBlockWater(a_CBBlockType))
{
diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp
index c2e078faf..42e827cb9 100644
--- a/src/LineBlockTracer.cpp
+++ b/src/LineBlockTracer.cpp
@@ -8,6 +8,7 @@
#include "Vector3.h"
#include "World.h"
#include "Chunk.h"
+#include "BoundingBox.h"
@@ -31,7 +32,7 @@ cLineBlockTracer::cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) :
m_CurrentX(0),
m_CurrentY(0),
m_CurrentZ(0),
- m_CurrentFace(0)
+ m_CurrentFace(BLOCK_FACE_NONE)
{
}
@@ -49,6 +50,97 @@ bool cLineBlockTracer::Trace(cWorld & a_World, cBlockTracer::cCallbacks & a_Call
+bool cLineBlockTracer::LineOfSightTrace(cWorld & a_World, const Vector3d & a_Start, const Vector3d & a_End, int a_Sight)
+{
+ static class LineOfSightCallbacks:
+ public cLineBlockTracer::cCallbacks
+ {
+ bool m_IsAirOpaque;
+ bool m_IsWaterOpaque;
+ bool m_IsLavaOpaque;
+ public:
+ LineOfSightCallbacks(bool a_IsAirOpaque, bool a_IsWaterOpaque, bool a_IsLavaOpaque):
+ m_IsAirOpaque(a_IsAirOpaque),
+ m_IsWaterOpaque(a_IsWaterOpaque),
+ m_IsLavaOpaque(a_IsLavaOpaque)
+ {}
+
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
+ {
+ switch (a_BlockType)
+ {
+ case E_BLOCK_AIR: return m_IsAirOpaque;
+ case E_BLOCK_LAVA: return m_IsLavaOpaque;
+ case E_BLOCK_STATIONARY_LAVA: return m_IsLavaOpaque;
+ case E_BLOCK_STATIONARY_WATER: return m_IsWaterOpaque;
+ case E_BLOCK_WATER: return m_IsWaterOpaque;
+ default: return true;
+ }
+ }
+ } callbacks(
+ (a_Sight & losAir) == 0,
+ (a_Sight & losWater) == 0,
+ (a_Sight & losLava) == 0
+ );
+ return Trace(a_World, callbacks, a_Start, a_End);
+}
+
+
+
+
+
+bool cLineBlockTracer::FirstSolidHitTrace(
+ cWorld & a_World,
+ const Vector3d & a_Start, const Vector3d & a_End,
+ Vector3d & a_HitCoords,
+ Vector3i & a_HitBlockCoords, eBlockFace & a_HitBlockFace
+)
+{
+ class cSolidHitCallbacks:
+ public cCallbacks
+ {
+ public:
+ cSolidHitCallbacks(const Vector3d & a_CBStart, const Vector3d & a_CBEnd, Vector3d & a_CBHitCoords, Vector3i & a_CBHitBlockCoords, eBlockFace & a_CBHitBlockFace):
+ m_Start(a_CBStart),
+ m_End(a_CBEnd),
+ m_HitCoords(a_CBHitCoords),
+ m_HitBlockCoords(a_CBHitBlockCoords),
+ m_HitBlockFace(a_CBHitBlockFace)
+ {
+ }
+
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
+ {
+ if (!cBlockInfo::IsSolid(a_BlockType))
+ {
+ return false;
+ }
+
+ // We hit a solid block, calculate the exact hit coords and abort trace:
+ m_HitBlockCoords.Set(a_BlockX, a_BlockY, a_BlockZ);
+ m_HitBlockFace = a_EntryFace;
+ cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); // Bounding box of the block hit
+ double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs
+ eBlockFace Face; // Face hit
+ VERIFY(bb.CalcLineIntersection(m_Start, m_End, LineCoeff, Face));
+ m_HitCoords = m_Start + (m_End - m_Start) * LineCoeff; // Point where projectile goes into the hit block
+ return true;
+ }
+
+ protected:
+ const Vector3d & m_Start;
+ const Vector3d & m_End;
+ Vector3d & m_HitCoords;
+ Vector3i & m_HitBlockCoords;
+ eBlockFace & m_HitBlockFace;
+ } callbacks(a_Start, a_End, a_HitCoords, a_HitBlockCoords, a_HitBlockFace);
+ return !Trace(a_World, callbacks, a_Start, a_End);
+}
+
+
+
+
+
bool cLineBlockTracer::Trace(cWorld & a_World, cBlockTracer::cCallbacks &a_Callbacks, double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ)
{
cLineBlockTracer Tracer(a_World, a_Callbacks);
diff --git a/src/LineBlockTracer.h b/src/LineBlockTracer.h
index 37493ce5c..2851cfbd7 100644
--- a/src/LineBlockTracer.h
+++ b/src/LineBlockTracer.h
@@ -33,6 +33,19 @@ class cLineBlockTracer :
typedef cBlockTracer super;
public:
+ enum eLineOfSight
+ {
+ // Bit flags used for LineOfSightTrace's Sight parameter:
+ losAir = 1, // Can see through air
+ losWater = 2, // Can see through water
+ losLava = 4, // Can see through lava
+
+ // Common combinations:
+ losAirWaterLava = losAir | losWater | losLava,
+ losAirWater = losAir | losWater,
+ };
+
+
cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks);
/** Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) */
@@ -46,6 +59,24 @@ public:
/** Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) */
static bool Trace(cWorld & a_World, cCallbacks & a_Callbacks, const Vector3d & a_Start, const Vector3d & a_End);
+ /** Returns true if the two positions are within line of sight (not obscured by blocks).
+ a_Sight specifies which blocks are considered transparent for the trace, is an OR-combination of eLineOfSight constants. */
+ static bool LineOfSightTrace(cWorld & a_World, const Vector3d & a_Start, const Vector3d & a_End, int a_Sight);
+
+ /** Traces until the first solid block is hit (or until end, whichever comes first.
+ If a solid block was hit, returns true and fills a_HitCoords, a_HitBlockCoords and a_HitBlockFace.
+ If a_End is encountered without hitting any solid block, returns false and doesn't touch a_HitCoords, a_HitBlockCoords nor a_HitBlockFace.
+ a_HitCoords is the exact coords of the hit,
+ a_HitBlockCoords are the coords of the solid block that was hit,
+ a_HitBlockFace is the face of the solid block that was hit. */
+ static bool FirstSolidHitTrace(
+ cWorld & a_World,
+ const Vector3d & a_Start, const Vector3d & a_End,
+ Vector3d & a_HitCoords,
+ Vector3i & a_HitBlockCoords,
+ eBlockFace & a_HitBlockFace
+ );
+
protected:
/** The start point of the trace */
double m_StartX, m_StartY, m_StartZ;
@@ -63,7 +94,7 @@ protected:
int m_CurrentX, m_CurrentY, m_CurrentZ;
/** The face through which the current block has been entered */
- char m_CurrentFace;
+ eBlockFace m_CurrentFace;
/** Adjusts the start point above the world to just at the world's top */
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index d8bdc4af5..fec14e6e9 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -5,7 +5,7 @@
#include "../World.h"
#include "../Entities/Player.h"
-#include "../Tracer.h"
+#include "../LineBlockTracer.h"
@@ -70,17 +70,20 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
CheckEventSeePlayer(a_Chunk);
}
- if (GetTarget() == nullptr)
+ auto target = GetTarget();
+ if (target == nullptr)
{
return;
}
- cTracer LineOfSight(GetWorld());
+ // TODO: Currently all mobs see through lava, but only Nether-native mobs should be able to.
Vector3d MyHeadPosition = GetPosition() + Vector3d(0, GetHeight(), 0);
- Vector3d AttackDirection(GetTarget()->GetPosition() + Vector3d(0, GetTarget()->GetHeight(), 0) - MyHeadPosition);
-
-
- if (TargetIsInRange() && !LineOfSight.Trace(MyHeadPosition, AttackDirection, static_cast<int>(AttackDirection.Length())) && (GetHealth() > 0.0))
+ Vector3d TargetPosition = target->GetPosition() + Vector3d(0, target->GetHeight(), 0);
+ if (
+ TargetIsInRange() &&
+ cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetPosition, cLineBlockTracer::losAirWaterLava) &&
+ (GetHealth() > 0.0)
+ )
{
// Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls)
Attack(a_Dt);
diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp
index f58e2132c..3c0717f8f 100644
--- a/src/Mobs/Enderman.cpp
+++ b/src/Mobs/Enderman.cpp
@@ -3,7 +3,7 @@
#include "Enderman.h"
#include "../Entities/Player.h"
-#include "../Tracer.h"
+#include "../LineBlockTracer.h"
@@ -29,9 +29,8 @@ public:
return false;
}
- Vector3d Direction = m_EndermanPos - a_Player->GetPosition();
-
- // Don't check players who are more then SightDistance (64) blocks away
+ // Don't check players who are more than SightDistance (64) blocks away
+ auto Direction = m_EndermanPos - a_Player->GetPosition();
if (Direction.Length() > m_SightDistance)
{
return false;
@@ -43,19 +42,16 @@ public:
return false;
}
-
- Vector3d LookVector = a_Player->GetLookVector();
- double dot = Direction.Dot(LookVector);
-
- // 0.09 rad ~ 5 degrees
// If the player's crosshair is within 5 degrees of the enderman, it counts as looking
- if (dot <= cos(0.09))
+ auto LookVector = a_Player->GetLookVector();
+ auto dot = Direction.Dot(LookVector);
+ if (dot <= cos(0.09)) // 0.09 rad ~ 5 degrees
{
return false;
}
- cTracer LineOfSight(a_Player->GetWorld());
- if (LineOfSight.Trace(m_EndermanPos, Direction, static_cast<int>(Direction.Length())))
+ // TODO: Check if endermen are angered through water in Vanilla
+ if (!cLineBlockTracer::LineOfSightTrace(*a_Player->GetWorld(), m_EndermanPos, a_Player->GetPosition(), cLineBlockTracer::losAirWater))
{
// No direct line of sight
return false;
diff --git a/src/Tracer.h b/src/Tracer.h
index 8d1f494f7..e4ff1b12c 100644
--- a/src/Tracer.h
+++ b/src/Tracer.h
@@ -35,7 +35,10 @@ public:
cTracer(cWorld * a_World);
~cTracer();
- /** Determines if a collision occures along a line. Returns true if a collision occurs. */
+ // tolua_end
+
+ /** Determines if a collision occures along a line. Returns true if a collision occurs.
+ Exported manually to add deprecation warnings. */
bool Trace(const Vector3f & a_Start, const Vector3f & a_Direction, int a_Distance)
{
return Trace(a_Start, a_Direction, a_Distance, false);
@@ -44,9 +47,12 @@ public:
/** Determines if a collision occures along a line. Returns true if a collision occurs.
When a_LineOfSight is true, we don't use the standard collision detection rules. Instead we use
the rules for monster vision. E.g. Only water and air do not block vision.
- a_Distance is the number of iterations (blocks hits) that are tested. */
+ a_Distance is the number of iterations (blocks hits) that are tested.
+ Exported manually to add deprecation warnings. */
bool Trace(const Vector3f & a_Start, const Vector3f & a_Direction, int a_Distance, bool a_LineOfSight);
+ // tolua_begin
+
private:
/** Preps Tracer object for call of Trace function. Only used internally. */
diff --git a/src/World.cpp b/src/World.cpp
index 2614ead7b..447e2cf25 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -13,6 +13,7 @@
#include "Generating/ChunkDesc.h"
#include "SetChunkData.h"
#include "DeadlockDetect.h"
+#include "LineBlockTracer.h"
// Serializers
#include "WorldStorage/ScoreboardSerializer.h"
@@ -50,11 +51,6 @@
#include "Bindings/PluginManager.h"
#include "Blocks/BlockHandler.h"
-#include "Tracer.h"
-
-// DEBUG: Test out the cLineBlockTracer class by tracing a few lines:
-#include "LineBlockTracer.h"
-
#ifndef _WIN32
#include <stdlib.h>
#endif
@@ -3190,11 +3186,8 @@ bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cLambdaPlayerCallb
-// TODO: This interface is dangerous!
cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, bool a_CheckLineOfSight)
{
- cTracer LineOfSight(this);
-
double ClosestDistance = a_SightLimit;
cPlayer * ClosestPlayer = nullptr;
@@ -3208,22 +3201,23 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit,
Vector3f Pos = (*itr)->GetPosition();
double Distance = (Pos - a_Pos).Length();
- if (Distance < ClosestDistance)
+ // If the player is too far, skip them:
+ if (Distance > ClosestDistance)
{
- if (a_CheckLineOfSight)
- {
- if (!LineOfSight.Trace(a_Pos, (Pos - a_Pos), static_cast<int>((Pos - a_Pos).Length())))
- {
- ClosestDistance = Distance;
- ClosestPlayer = *itr;
- }
- }
- else
- {
- ClosestDistance = Distance;
- ClosestPlayer = *itr;
- }
+ continue;
}
+
+ // Check LineOfSight, if requested:
+ if (
+ a_CheckLineOfSight &&
+ !cLineBlockTracer::LineOfSightTrace(*this, a_Pos, Pos, cLineBlockTracer::losAirWater)
+ )
+ {
+ continue;
+ }
+
+ ClosestDistance = Distance;
+ ClosestPlayer = *itr;
}
return ClosestPlayer;
}