1
0

Use Vector3 for cLineBlockTracer and cBlockTracer (#4715)

* cLineBlockTracer uses Vector
This commit is contained in:
mBornand 2020-05-08 11:04:07 +02:00 committed by GitHub
parent c4ca11b372
commit 1565d9b3ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 424 additions and 220 deletions

View File

@ -1010,6 +1010,7 @@ the most popular tracing reasons - line of sight and solid hits.
}, },
}, -- LineOfSightTrace }, -- LineOfSightTrace
Trace = Trace =
{
{ {
IsStatic = true, IsStatic = true,
Params = Params =
@ -1029,9 +1030,27 @@ the most popular tracing reasons - line of sight and solid hits.
Type = "boolean", Type = "boolean",
}, },
}, },
Notes = "(OBSOLETE, use the Vector3-based overload instead) Performs the trace on the specified line. Returns true if the entire trace was processed (no callback returned true)",
},
{
IsStatic = true,
Params =
{
{ Name = "World", Type = "cWorld" },
{ Name = "Callbacks", Type = "table" },
{ Name = "Start", Type = "Vector3d" },
{ Name = "End", Type = "Vector3d" },
},
Returns =
{
{
Type = "boolean",
},
},
Notes = "Performs the trace on the specified line. Returns true if the entire trace was processed (no callback returned true)", Notes = "Performs the trace on the specified line. Returns true if the entire trace was processed (no callback returned true)",
}, },
}, },
},
Constants = Constants =
{ {
losAir = losAir =
@ -1064,7 +1083,39 @@ The Callbacks in the Trace() function is a table that contains named functions.
individual functions from that table for the events that occur on the line - hitting a block, going out of individual functions from that table for the events that occur on the line - hitting a block, going out of
valid world data etc. The following table lists all the available callbacks. If the callback function is valid world data etc. The following table lists all the available callbacks. If the callback function is
not defined, Cuberite skips it. Each function can return a bool value, if it returns true, the tracing is not defined, Cuberite skips it. Each function can return a bool value, if it returns true, the tracing is
aborted and Trace() returns false.</p> aborted and Trace() returns false.<br>
Note: The folowing can only be used when using the Vector3-based Trace() function. When using
the number-based overload, the callbacks receive number-based coordinates (see Deprecated
Callbacks below).</p>
<p>
<table><tr><th>Name</th><th>Parameters</th><th>Notes</th></tr>
<tr><td>OnNextBlock</td><td>BlockPos, BlockType, BlockMeta, EntryFace</td>
<td>Called when the ray hits a new valid block. The block type and meta is given. EntryFace is one of the
BLOCK_FACE_ constants indicating which "side" of the block got hit by the ray.</td></tr>
<tr><td>OnNextBlockNoData</td><td>BlockPos, EntryFace</td>
<td>Called when the ray hits a new block, but the block is in an unloaded chunk - no valid data is
available. Only the coords and the entry face are given.</td></tr>
<tr><td>OnOutOfWorld</td><td>BlockPos</td>
<td>Called when the ray goes outside of the world (Y-wise); the coords specify the exact exit point. Note
that for other paths than lines (considered for future implementations) the path may leave the world and
go back in again later, in such a case this callback is followed by OnIntoWorld() and further
OnNextBlock() calls.</td></tr>
<tr><td>OnIntoWorld</td><td>BlockPos</td>
<td>Called when the ray enters the world (Y-wise); the coords specify the exact entry point.</td></tr>
<tr><td>OnNoMoreHits</td><td>&nbsp;</td>
<td>Called when the path is sure not to hit any more blocks. This is the final callback, no more
callbacks are called after this function. Unlike the other callbacks, this function doesn't have a return
value.</td></tr>
<tr><td>OnNoChunk</td><td>&nbsp;</td>
<td>Called when the ray enters a chunk that is not loaded. This usually means that the tracing is aborted.
Unlike the other callbacks, this function doesn't have a return value.</td></tr>
</table>
]],
},
{
Header = "Deprecated Callbacks",
Contents = [[
When using the deprecated number-based Trace function, Cuberite will instead assume the following signatures for the callbacks:</p>
<p> <p>
<table><tr><th>Name</th><th>Parameters</th><th>Notes</th></tr> <table><tr><th>Name</th><th>Parameters</th><th>Notes</th></tr>
<tr><td>OnNextBlock</td><td>BlockX, BlockY, BlockZ, BlockType, BlockMeta, EntryFace</td> <tr><td>OnNextBlock</td><td>BlockX, BlockY, BlockZ, BlockType, BlockMeta, EntryFace</td>
@ -1080,14 +1131,8 @@ aborted and Trace() returns false.</p>
OnNextBlock() calls.</td></tr> OnNextBlock() calls.</td></tr>
<tr><td>OnIntoWorld</td><td>X, Y, Z</td> <tr><td>OnIntoWorld</td><td>X, Y, Z</td>
<td>Called when the ray enters the world (Y-wise); the coords specify the exact entry point.</td></tr> <td>Called when the ray enters the world (Y-wise); the coords specify the exact entry point.</td></tr>
<tr><td>OnNoMoreHits</td><td>&nbsp;</td>
<td>Called when the path is sure not to hit any more blocks. This is the final callback, no more
callbacks are called after this function. Unlike the other callbacks, this function doesn't have a return
value.</td></tr>
<tr><td>OnNoChunk</td><td>&nbsp;</td>
<td>Called when the ray enters a chunk that is not loaded. This usually means that the tracing is aborted.
Unlike the other callbacks, this function doesn't have a return value.</td></tr>
</table> </table>
]], ]],
}, },
{ {
@ -1101,12 +1146,12 @@ function HandleSpideyCmd(a_Split, a_Player)
local World = a_Player:GetWorld(); local World = a_Player:GetWorld();
local Callbacks = { local Callbacks = {
OnNextBlock = function(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta) OnNextBlock = function(a_BlockPos, a_BlockType, a_BlockMeta)
if (a_BlockType ~= E_BLOCK_AIR) then if (a_BlockType ~= E_BLOCK_AIR) then
-- abort the trace -- abort the trace
return true; return true;
end end
World:SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COBWEB, 0); World:SetBlock(a_BlockPos, E_BLOCK_COBWEB, 0);
end end
}; };
@ -1118,7 +1163,7 @@ function HandleSpideyCmd(a_Split, a_Player)
local Start = EyePos + LookVector + LookVector; local Start = EyePos + LookVector + LookVector;
local End = EyePos + LookVector * 50; local End = EyePos + LookVector * 50;
cLineBlockTracer.Trace(World, Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z); cLineBlockTracer.Trace(World, Callbacks, Start, End);
return true; return true;
end end

View File

@ -1178,12 +1178,12 @@ function HandleSpideyCmd(a_Split, a_Player)
local World = a_Player:GetWorld(); local World = a_Player:GetWorld();
local Callbacks = { local Callbacks = {
OnNextBlock = function(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta) OnNextBlock = function(a_BlockPos, a_BlockType, a_BlockMeta)
if (a_BlockType ~= E_BLOCK_AIR) then if (a_BlockType ~= E_BLOCK_AIR) then
-- abort the trace -- abort the trace
return true; return true;
end end
World:SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COBWEB, 0); World:SetBlock(a_BlockPos, E_BLOCK_COBWEB, 0);
end end
}; };
@ -1195,7 +1195,7 @@ function HandleSpideyCmd(a_Split, a_Player)
local Start = EyePos + LookVector + LookVector; local Start = EyePos + LookVector + LookVector;
local End = EyePos + LookVector * 50; local End = EyePos + LookVector * 50;
cLineBlockTracer.Trace(World, Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z); cLineBlockTracer.Trace(World, Callbacks, Start, End);
return true; return true;
end end
@ -2421,6 +2421,89 @@ function HandleConsoleTestTracer(a_Split, a_EntireCmd)
return true, "No such world" return true, "No such world"
end end
-- Define the callbacks to use for tracing:
local Callbacks =
{
OnNextBlock = function(a_BlockPos, a_BlockType, a_BlockMeta, a_EntryFace)
LOG(string.format("{%d, %d, %d}: %s", a_Block.x, a_Block.y, a_Block.z, ItemToString(cItem(a_BlockType, 1, a_BlockMeta))))
end,
OnNextBlockNoData = function(a_BlockPos, a_EntryFace)
LOG(string.format("{%d, %d, %d} (no data)", a_Block.x, a_Block.y, a_Block.z))
end,
OnNoChunk = function()
LOG("Chunk not loaded")
end,
OnNoMoreHits = function()
LOG("Trace finished")
end,
OnOutOfWorld = function()
LOG("Out of world")
end,
OnIntoWorld = function()
LOG("Into world")
end,
}
-- Approximate the chunks needed for the trace by iterating over all chunks and measuring their center's distance from the traced line
local Chunks = {}
local sx = math.floor(Coords[1] / 16)
local sz = math.floor(Coords[3] / 16)
local ex = math.floor(Coords[4] / 16)
local ez = math.floor(Coords[6] / 16)
local sgnx = (sx < ex) and 1 or -1
local sgnz = (sz < ez) and 1 or -1
for z = sz, ez, sgnz do
local ChunkCenterZ = z * 16 + 8
for x = sx, ex, sgnx do
local ChunkCenterX = x * 16 + 8
local sqdist = SqDistPtFromLine(ChunkCenterX, ChunkCenterZ, Coords[1], Coords[3], Coords[4], Coords[6])
if (sqdist <= 128) then
table.insert(Chunks, {x, z})
end
end
end
-- Load the chunks and do the trace once loaded:
local startPos = Vector3i(Coords[1], Coords[2], Coords[3])
local endPos = Vector3i(Coords[4], Coords[5], Coords[6])
World:ChunkStay(Chunks,
nil,
function()
cLineBlockTracer:Trace(World, Callbacks, startPos, endPos)
end
)
return true
end
function HandleConsoleTestTracerDeprecated(a_Split, a_EntireCmd)
-- Check required params:
if not(a_Split[7]) then
return true, "Usage: " .. a_Split[1] .. " <x1> <y1> <z1> <x2> <y2> <z2> [<WorldName>]"
end
local Coords = {}
for i = 1, 6 do
local v = tonumber(a_Split[i + 1])
if not(v) then
return true, "Parameter " .. (i + 1) .. " (" .. tostring(a_Split[i + 1]) .. ") not a number "
end
Coords[i] = v
end
-- Get the world in which to test:
local World
if (a_Split[8]) then
World = cRoot:GetWorld(a_Split[2])
else
World = cRoot:Get():GetDefaultWorld()
end
if not(World) then
return true, "No such world"
end
-- Define the callbacks to use for tracing: -- Define the callbacks to use for tracing:
local Callbacks = local Callbacks =
{ {
@ -2716,9 +2799,9 @@ function HandleBlkCmd(a_Split, a_Player)
local World = a_Player:GetWorld(); local World = a_Player:GetWorld();
local Callbacks = { local Callbacks = {
OnNextBlock = function(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta) OnNextBlock = function(a_BlockPos, a_BlockType, a_BlockMeta)
if (a_BlockType ~= E_BLOCK_AIR) then if (a_BlockType ~= E_BLOCK_AIR) then
a_Player:SendMessage("Block at " .. a_BlockX .. ", " .. a_BlockY .. ", " .. a_BlockZ .. " is " .. a_BlockType .. ":" .. a_BlockMeta) a_Player:SendMessage("Block at " .. a_BlockPos.x .. ", " .. a_BlockPos.y .. ", " .. a_BlockPos.z .. " is " .. a_BlockType .. ":" .. a_BlockMeta)
return true; return true;
end end
end end
@ -2730,7 +2813,7 @@ function HandleBlkCmd(a_Split, a_Player)
local End = EyePos + LookVector * 50; local End = EyePos + LookVector * 50;
cLineBlockTracer.Trace(World, Callbacks, EyePos.x, EyePos.y, EyePos.z, End.x, End.y, End.z); cLineBlockTracer.Trace(World, Callbacks, EyePos, End);
return true; return true;
end end
@ -2760,6 +2843,3 @@ function HandleTeamsCmd(a_Split, a_Player)
end end

View File

@ -392,6 +392,12 @@ g_PluginInfo =
HelpString = "Tests the cLineBlockTracer", HelpString = "Tests the cLineBlockTracer",
}, },
["testtracerdeprecated"] =
{
Handler = HandleConsoleTestTracerDeprecated,
HelpString = "Tests the cLineBlockTracer's deprecated API",
},
["testurlclient"] = ["testurlclient"] =
{ {
Handler = HandleConsoleTestUrlClient, Handler = HandleConsoleTestUrlClient,
@ -414,4 +420,3 @@ g_PluginInfo =

View File

@ -2823,65 +2823,68 @@ public:
{ {
} }
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override virtual bool OnNextBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{ {
bool res = false; bool res = false;
if (!m_Callbacks->CallTableFn( if (m_Callbacks->CallTableFn(
"OnNextBlock", "OnNextBlock",
a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_EntryFace, a_BlockPos,
cLuaState::Return, res a_BlockType,
)) a_BlockMeta,
a_EntryFace,
cLuaState::Return, res)
)
{ {
return res;
}
// No such function in the table, skip the callback // No such function in the table, skip the callback
return false; return false;
} }
return res;
}
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override virtual bool OnNextBlockNoData(Vector3i a_BlockPos, char a_EntryFace) override
{ {
bool res = false; bool res = false;
if (!m_Callbacks->CallTableFn( if (m_Callbacks->CallTableFn(
"OnNextBlockNoData", "OnNextBlockNoData",
a_BlockX, a_BlockY, a_BlockZ, a_EntryFace, a_BlockPos,
cLuaState::Return, res a_EntryFace,
)) cLuaState::Return, res)
)
{ {
return res;
}
// No such function in the table, skip the callback // No such function in the table, skip the callback
return false; return false;
} }
return res;
}
virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override virtual bool OnOutOfWorld(Vector3d a_BlockPos) override
{ {
bool res = false; bool res = false;
if (!m_Callbacks->CallTableFn( if (m_Callbacks->CallTableFn(
"OnOutOfWorld", "OnOutOfWorld",
a_BlockX, a_BlockY, a_BlockZ, a_BlockPos,
cLuaState::Return, res cLuaState::Return, res)
)) )
{ {
return res;
}
// No such function in the table, skip the callback // No such function in the table, skip the callback
return false; return false;
} }
return res;
}
virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override virtual bool OnIntoWorld(Vector3d a_BlockPos) override
{ {
bool res = false; bool res = false;
if (!m_Callbacks->CallTableFn( if (m_Callbacks->CallTableFn("OnIntoWorld",
"OnIntoWorld", a_BlockPos,
a_BlockX, a_BlockY, a_BlockZ, cLuaState::Return, res)
cLuaState::Return, res )
))
{ {
return res;
}
// No such function in the table, skip the callback // No such function in the table, skip the callback
return false; return false;
} }
return res;
}
virtual void OnNoMoreHits(void) override virtual void OnNoMoreHits(void) override
{ {
@ -2895,7 +2898,88 @@ public:
protected: protected:
cLuaState::cTableRefPtr m_Callbacks; cLuaState::cTableRefPtr m_Callbacks;
} ; };
/** Provides interface between a Lua table of callbacks and the cBlockTracer::cCallbacks
This is the deprecated version of cLuaBlockTracerCallback, used when the plugin calls
the Trace function with number-based coords. */
class cLuaBlockTracerCallbacksOld :
public cLuaBlockTracerCallbacks
{
public:
cLuaBlockTracerCallbacksOld(cLuaState::cTableRefPtr && a_Callbacks):
cLuaBlockTracerCallbacks(std::move(a_Callbacks))
{
}
virtual bool OnNextBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{
bool res = false;
if (m_Callbacks->CallTableFn(
"OnNextBlock",
a_BlockPos.x, a_BlockPos.y, a_BlockPos.z,
a_BlockType,
a_BlockMeta,
a_EntryFace,
cLuaState::Return, res)
)
{
return res;
}
// No such function in the table, skip the callback
return false;
}
virtual bool OnNextBlockNoData(Vector3i a_BlockPos, char a_EntryFace) override
{
bool res = false;
if (m_Callbacks->CallTableFn(
"OnNextBlockNoData",
a_BlockPos.x, a_BlockPos.y, a_BlockPos.z,
a_EntryFace,
cLuaState::Return, res)
)
{
return res;
}
// No such function in the table, skip the callback
return false;
}
virtual bool OnOutOfWorld(Vector3d a_BlockPos) override
{
bool res = false;
if (m_Callbacks->CallTableFn(
"OnOutOfWorld",
a_BlockPos.x, a_BlockPos.y, a_BlockPos.z,
cLuaState::Return, res)
)
{
return res;
}
// No such function in the table, skip the callback
return false;
}
virtual bool OnIntoWorld(Vector3d a_BlockPos) override
{
bool res = false;
if (m_Callbacks->CallTableFn(
"OnIntoWorld",
a_BlockPos.x, a_BlockPos.y, a_BlockPos.z,
cLuaState::Return, res)
)
{
return res;
}
// No such function in the table, skip the callback
return false;
}
};
@ -3100,8 +3184,10 @@ static int tolua_cLineBlockTracer_LineOfSightTrace(lua_State * tolua_S)
static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S) static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
{ {
/* Supported function signatures: /* Supported function signatures:
cLineBlockTracer:Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ) // Canonical cLineBlockTracer:Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ) // Canonical // DEPRECATED
cLineBlockTracer.Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ) cLineBlockTracer.Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ) // DEPRECATED
cLineBlockTracer:Trace(World, Callbacks, Start, End) // Canonical
cLineBlockTracer.Trace(World, Callbacks, Start, End)
*/ */
// If the first param is the cLineBlockTracer class, shift param index by one: // If the first param is the cLineBlockTracer class, shift param index by one:
@ -3116,9 +3202,7 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
cLuaState L(tolua_S); cLuaState L(tolua_S);
if ( if (
!L.CheckParamUserType(idx, "cWorld") || !L.CheckParamUserType(idx, "cWorld") ||
!L.CheckParamTable (idx + 1) || !L.CheckParamTable (idx + 1)
!L.CheckParamNumber (idx + 2, idx + 7) ||
!L.CheckParamEnd (idx + 8)
) )
{ {
return 0; return 0;
@ -3126,22 +3210,54 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
// Get the params: // Get the params:
cWorld * world; cWorld * world;
double startX, startY, startZ; Vector3d start;
double endX, endY, endZ; Vector3d end;
cLuaState::cTableRefPtr callbacks; cLuaState::cTableRefPtr callbacks;
if (!L.GetStackValues(idx, world, callbacks, startX, startY, startZ, endX, endY, endZ)) if (
L.IsParamNumber (idx + 2) &&
L.IsParamNumber (idx + 3) &&
L.IsParamNumber (idx + 4) &&
L.IsParamNumber (idx + 5) &&
L.IsParamNumber (idx + 6) &&
L.IsParamNumber (idx + 7) &&
L.CheckParamEnd (idx + 8)
)
{
if (!L.GetStackValues(idx, world, callbacks, start.x, start.y, start.z, end.x, end.y, end.z))
{ {
LOGWARNING("cLineBlockTracer:Trace(): Cannot read parameters (starting at idx %d), aborting the trace.", idx); LOGWARNING("cLineBlockTracer:Trace(): Cannot read parameters (starting at idx %d), aborting the trace.", idx);
L.LogStackTrace(); L.LogStackTrace();
L.LogStackValues("Values on the stack"); L.LogStackValues("Values on the stack");
return 0; return 0;
} }
LOGWARNING("cLineBlockTracer:Trace(): Using plain numbers is deprecated, use Vector3 coords instead.");
L.LogStackTrace();
// Trace: // Trace:
cLuaBlockTracerCallbacks tracerCallbacks(std::move(callbacks)); cLuaBlockTracerCallbacksOld tracerCallbacks(std::move(callbacks));
bool res = cLineBlockTracer::Trace(*world, tracerCallbacks, startX, startY, startZ, endX, endY, endZ); bool res = cLineBlockTracer::Trace(*world, tracerCallbacks, start, end);
tolua_pushboolean(L, res ? 1 : 0); tolua_pushboolean(L, res ? 1 : 0);
return 1; return 1;
}
else if (
L.IsParamVector3(idx + 2) &&
L.IsParamVector3(idx + 3) &&
L.CheckParamEnd (idx + 4)
)
{
if (!L.GetStackValues(idx, world, callbacks, start, end))
{
LOGWARNING("cLineBlockTracer:Trace(): Cannot read parameters (starting at idx %d), aborting the trace.", idx);
L.LogStackTrace();
L.LogStackValues("Values on the stack");
return 0;
}
// Trace:
cLuaBlockTracerCallbacks tracerCallbacks(std::move(callbacks));
bool res = cLineBlockTracer::Trace(*world, tracerCallbacks, start, end);
tolua_pushboolean(L, res ? 1 : 0);
return 1;
}
return L.ApiParamError("Invalid overload of cLineBlockTracer:Trace()");
} }

View File

@ -40,45 +40,39 @@ public:
/** Called on each block encountered along the path, including the first block (path start) /** Called on each block encountered along the path, including the first block (path start)
When this callback returns true, the tracing is aborted. 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, eBlockFace a_EntryFace) = 0; virtual bool OnNextBlock(Vector3i a_BlockPos, 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 /** 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. When this callback returns true, the tracing is aborted.
*/ */
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) virtual bool OnNextBlockNoData(Vector3i a_BlockPos, char a_EntryFace)
{ {
UNUSED(a_BlockX); UNUSED(a_BlockPos);
UNUSED(a_BlockY);
UNUSED(a_BlockZ);
UNUSED(a_EntryFace); UNUSED(a_EntryFace);
return false; return false;
} }
/** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) /** Called when the path goes out of world, either below (a_BlockPos.y < 0) or above (a_BlockPos.y >= cChunkDef::Height)
The coords specify the exact point at which the path exited the world. The coords specify the exact point at which the path exited the world.
If this callback returns true, the tracing is aborted. If this callback returns true, the tracing is aborted.
Note that some paths can go out of the world and come back again (parabola), Note that some paths can go out of the world and come back again (parabola),
in such a case this callback is followed by OnIntoWorld() and further OnNextBlock() calls in such a case this callback is followed by OnIntoWorld() and further OnNextBlock() calls
*/ */
virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) virtual bool OnOutOfWorld(Vector3d a_BlockPos)
{ {
UNUSED(a_BlockX); UNUSED(a_BlockPos);
UNUSED(a_BlockY);
UNUSED(a_BlockZ);
return false; return false;
} }
/** Called when the path goes into the world, from either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) /** Called when the path goes into the world, from either below (a_BlockPos.y < 0) or above (a_BlockPos.y >= cChunkDef::Height)
The coords specify the exact point at which the path entered the world. The coords specify the exact point at which the path entered the world.
If this callback returns true, the tracing is aborted. If this callback returns true, the tracing is aborted.
Note that some paths can go out of the world and come back again (parabola), Note that some paths can go out of the world and come back again (parabola),
in such a case this callback is followed by further OnNextBlock() calls in such a case this callback is followed by further OnNextBlock() calls
*/ */
virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) virtual bool OnIntoWorld(Vector3d a_BlockPos)
{ {
UNUSED(a_BlockX); UNUSED(a_BlockPos);
UNUSED(a_BlockY);
UNUSED(a_BlockZ);
return false; return false;
} }

View File

@ -50,7 +50,7 @@ protected:
double m_SlowdownCoeff; double m_SlowdownCoeff;
// cCallbacks overrides: // cCallbacks overrides:
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override virtual bool OnNextBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{ {
/* /*
// DEBUG: // DEBUG:
@ -65,7 +65,7 @@ protected:
if (cBlockInfo::IsSolid(a_BlockType)) if (cBlockInfo::IsSolid(a_BlockType))
{ {
// The projectile hit a solid block, calculate the exact hit coords: // The projectile hit a solid block, calculate the exact hit coords:
cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); // Bounding box of the block hit cBoundingBox bb(a_BlockPos, a_BlockPos + Vector3i(1, 1, 1)); // Bounding box of the block hit
const Vector3d LineStart = m_Projectile->GetPosition(); // Start point for the imaginary line that goes through the block hit const Vector3d LineStart = m_Projectile->GetPosition(); // Start point for the imaginary line that goes through the block hit
const Vector3d LineEnd = LineStart + m_Projectile->GetSpeed(); // End point for the imaginary line that goes through the block hit const Vector3d LineEnd = LineStart + m_Projectile->GetSpeed(); // End point for the imaginary line that goes through the block hit
double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs
@ -75,7 +75,7 @@ protected:
{ {
Vector3d Intersection = LineStart + m_Projectile->GetSpeed() * LineCoeff; // Point where projectile goes into the hit block Vector3d Intersection = LineStart + m_Projectile->GetSpeed() * LineCoeff; // Point where projectile goes into the hit block
if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockX, a_BlockY, a_BlockZ, Face, Intersection)) if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, Face, Intersection))
{ {
return false; return false;
} }
@ -455,6 +455,3 @@ void cProjectileEntity::CollectedBy(cPlayer & a_Dest)
UNUSED(a_Dest); UNUSED(a_Dest);
} }

View File

@ -52,11 +52,11 @@ public:
{ {
} }
virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override virtual bool OnNextBlock(Vector3i a_CBBlockPos, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
{ {
if (a_CBBlockType != E_BLOCK_AIR) if (a_CBBlockType != E_BLOCK_AIR)
{ {
m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ); m_Pos = a_CBBlockPos;
m_HasFound = true; m_HasFound = true;
return true; return true;
} }

View File

@ -43,7 +43,7 @@ public:
{ {
} }
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override virtual bool OnNextBlock(Vector3i a_BlockPosition, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{ {
if (IsBlockWater(a_BlockType)) if (IsBlockWater(a_BlockType))
{ {
@ -52,7 +52,7 @@ public:
return false; return false;
} }
m_HasHitFluid = true; m_HasHitFluid = true;
m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ); m_Pos = a_BlockPosition;
return true; return true;
} }
return false; return false;

View File

@ -197,7 +197,7 @@ public:
{ {
} }
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override virtual bool OnNextBlock(Vector3i a_BlockPosition, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{ {
if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType)) if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType))
{ {
@ -206,7 +206,7 @@ public:
return false; return false;
} }
m_HasHitFluid = true; m_HasHitFluid = true;
m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ); m_Pos = a_BlockPosition;
return true; return true;
} }
return false; return false;
@ -217,7 +217,7 @@ public:
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector()); Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z); Tracer.Trace(Start, End);
if (!Callbacks.m_HasHitFluid) if (!Callbacks.m_HasHitFluid)
{ {
@ -244,7 +244,7 @@ public:
NIBBLETYPE m_ReplacedBlockMeta; NIBBLETYPE m_ReplacedBlockMeta;
eBlockFace m_EntryFace; eBlockFace m_EntryFace;
virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override virtual bool OnNextBlock(Vector3i a_CBBlockPos, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
{ {
if ((a_CBBlockType != E_BLOCK_AIR) && !IsBlockLiquid(a_CBBlockType)) if ((a_CBBlockType != E_BLOCK_AIR) && !IsBlockLiquid(a_CBBlockType))
{ {
@ -253,9 +253,9 @@ public:
m_EntryFace = static_cast<eBlockFace>(a_CBEntryFace); m_EntryFace = static_cast<eBlockFace>(a_CBEntryFace);
if (!cFluidSimulator::CanWashAway(a_CBBlockType)) if (!cFluidSimulator::CanWashAway(a_CBBlockType))
{ {
AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, a_CBEntryFace); // Was an unwashawayable block, can't overwrite it! a_CBBlockPos = AddFaceDirection(a_CBBlockPos, 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) m_Pos = a_CBBlockPos; // (Block could be washed away, replace it)
return true; // Abort tracing return true; // Abort tracing
} }
return false; return false;
@ -269,7 +269,7 @@ public:
// cLineBlockTracer::Trace() returns true when whole line was traversed. By returning true from the callback when we hit something, // 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 // we ensure that this never happens if liquid could be placed
// Use this to judge whether the position is valid // Use this to judge whether the position is valid
if (!Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z)) if (!Tracer.Trace(Start, End))
{ {
a_BlockPos = Callbacks.m_Pos; a_BlockPos = Callbacks.m_Pos;
a_BlockType = Callbacks.m_ReplacedBlockType; a_BlockType = Callbacks.m_ReplacedBlockType;

View File

@ -66,7 +66,7 @@ public:
{ {
} }
virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override virtual bool OnNextBlock(Vector3i a_CBBlockPos, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
{ {
if (IsBlockWater(a_CBBlockType)) if (IsBlockWater(a_CBBlockType))
{ {
@ -74,7 +74,7 @@ public:
{ {
return false; return false;
} }
AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, BLOCK_FACE_YP); // Always place pad at top of water block a_CBBlockPos = AddFaceDirection(a_CBBlockPos, BLOCK_FACE_YP); // Always place pad at top of water block
if ( if (
!IsBlockWater(a_CBBlockType) && !IsBlockWater(a_CBBlockType) &&
cBlockInfo::FullyOccupiesVoxel(a_CBBlockType) cBlockInfo::FullyOccupiesVoxel(a_CBBlockType)
@ -84,7 +84,7 @@ public:
return true; return true;
} }
m_HasHitFluid = true; m_HasHitFluid = true;
m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ); m_Pos = a_CBBlockPos;
return true; return true;
} }
return false; return false;
@ -96,7 +96,7 @@ public:
} Callbacks; } Callbacks;
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector(); auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5; auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z); cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, Start, End);
if (Callbacks.m_HasHitFluid) if (Callbacks.m_HasHitFluid)
{ {

View File

@ -16,21 +16,11 @@
cLineBlockTracer::cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) : cLineBlockTracer::cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) :
Super(a_World, a_Callbacks), Super(a_World, a_Callbacks),
m_StartX(0.0), m_Start(),
m_StartY(0.0), m_End(),
m_StartZ(0.0), m_Diff(),
m_EndX(0.0), m_Dir(),
m_EndY(0.0), m_Current(),
m_EndZ(0.0),
m_DiffX(0.0),
m_DiffY(0.0),
m_DiffZ(0.0),
m_DirX(0),
m_DirY(0),
m_DirZ(0),
m_CurrentX(0),
m_CurrentY(0),
m_CurrentZ(0),
m_CurrentFace(BLOCK_FACE_NONE) m_CurrentFace(BLOCK_FACE_NONE)
{ {
} }
@ -39,10 +29,10 @@ cLineBlockTracer::cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) :
bool cLineBlockTracer::Trace(cWorld & a_World, cBlockTracer::cCallbacks & a_Callbacks, const Vector3d & a_Start, const Vector3d & a_End) bool cLineBlockTracer::Trace(cWorld & a_World, cBlockTracer::cCallbacks & a_Callbacks, const Vector3d a_Start, const Vector3d a_End)
{ {
cLineBlockTracer Tracer(a_World, a_Callbacks); cLineBlockTracer Tracer(a_World, a_Callbacks);
return Tracer.Trace(a_Start.x, a_Start.y, a_Start.z, a_End.x, a_End.y, a_End.z); return Tracer.Trace(a_Start, a_End);
} }
@ -64,7 +54,7 @@ bool cLineBlockTracer::LineOfSightTrace(cWorld & a_World, const Vector3d & a_Sta
m_IsLavaOpaque(a_IsLavaOpaque) 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 virtual bool OnNextBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{ {
switch (a_BlockType) switch (a_BlockType)
{ {
@ -108,7 +98,7 @@ bool cLineBlockTracer::FirstSolidHitTrace(
{ {
} }
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override virtual bool OnNextBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
{ {
if (!cBlockInfo::IsSolid(a_BlockType)) if (!cBlockInfo::IsSolid(a_BlockType))
{ {
@ -116,9 +106,9 @@ bool cLineBlockTracer::FirstSolidHitTrace(
} }
// We hit a solid block, calculate the exact hit coords and abort trace: // We hit a solid block, calculate the exact hit coords and abort trace:
m_HitBlockCoords.Set(a_BlockX, a_BlockY, a_BlockZ); m_HitBlockCoords = a_BlockPos;
m_HitBlockFace = a_EntryFace; 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 cBoundingBox bb(a_BlockPos, a_BlockPos + Vector3i(1, 1, 1)); // Bounding box of the block hit
double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs
eBlockFace Face; // Face hit eBlockFace Face; // Face hit
if (!bb.CalcLineIntersection(m_Start, m_End, LineCoeff, Face)) if (!bb.CalcLineIntersection(m_Start, m_End, LineCoeff, Face))
@ -144,64 +134,46 @@ bool cLineBlockTracer::FirstSolidHitTrace(
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) bool cLineBlockTracer::Trace(const Vector3d a_Start, const Vector3d a_End)
{
cLineBlockTracer Tracer(a_World, a_Callbacks);
return Tracer.Trace(a_StartX, a_StartY, a_StartZ, a_EndX, a_EndY, a_EndZ);
}
bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ)
{ {
// Initialize the member veriables: // Initialize the member veriables:
m_StartX = a_StartX; m_Start = a_Start;
m_StartY = a_StartY; m_End = a_End;
m_StartZ = a_StartZ; m_Dir.x = (m_Start.x < m_End.x) ? 1 : -1;
m_EndX = a_EndX; m_Dir.y = (m_Start.y < m_End.y) ? 1 : -1;
m_EndY = a_EndY; m_Dir.z = (m_Start.z < m_End.z) ? 1 : -1;
m_EndZ = a_EndZ;
m_DirX = (m_StartX < m_EndX) ? 1 : -1;
m_DirY = (m_StartY < m_EndY) ? 1 : -1;
m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1;
m_CurrentFace = BLOCK_FACE_NONE; m_CurrentFace = BLOCK_FACE_NONE;
// Check the start coords, adjust into the world: // Check the start coords, adjust into the world:
if (m_StartY < 0) if (m_Start.y < 0)
{ {
if (m_EndY < 0) if (m_End.y < 0)
{ {
// Nothing to trace // Nothing to trace
m_Callbacks->OnNoMoreHits(); m_Callbacks->OnNoMoreHits();
return true; return true;
} }
FixStartBelowWorld(); FixStartBelowWorld();
m_Callbacks->OnIntoWorld(m_StartX, m_StartY, m_StartZ); m_Callbacks->OnIntoWorld(m_Start);
} }
else if (m_StartY >= cChunkDef::Height) else if (m_Start.y >= cChunkDef::Height)
{ {
if (m_EndY >= cChunkDef::Height) if (m_End.y >= cChunkDef::Height)
{ {
m_Callbacks->OnNoMoreHits(); m_Callbacks->OnNoMoreHits();
return true; return true;
} }
FixStartAboveWorld(); FixStartAboveWorld();
m_Callbacks->OnIntoWorld(m_StartX, m_StartY, m_StartZ); m_Callbacks->OnIntoWorld(m_Start);
} }
m_CurrentX = FloorC(m_StartX); m_Current = m_Start.Floor();
m_CurrentY = FloorC(m_StartY);
m_CurrentZ = FloorC(m_StartZ);
m_DiffX = m_EndX - m_StartX; m_Diff = m_End - m_Start;
m_DiffY = m_EndY - m_StartY;
m_DiffZ = m_EndZ - m_StartZ;
// The actual trace is handled with ChunkMapCS locked by calling our ChunkCallback for the specified chunk // The actual trace is handled with ChunkMapCS locked by calling our ChunkCallback for the specified chunk
int BlockX = FloorC(m_StartX); int BlockX = FloorC(m_Start.x);
int BlockZ = FloorC(m_StartZ); int BlockZ = FloorC(m_Start.z);
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ); cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
return m_World->DoWithChunk(ChunkX, ChunkZ, [this](cChunk & a_Chunk) { return ChunkCallback(&a_Chunk); }); return m_World->DoWithChunk(ChunkX, ChunkZ, [this](cChunk & a_Chunk) { return ChunkCallback(&a_Chunk); });
@ -216,8 +188,8 @@ void cLineBlockTracer::FixStartAboveWorld(void)
// We must set the start Y to less than cChunkDef::Height so that it is considered inside the world later on // We must set the start Y to less than cChunkDef::Height so that it is considered inside the world later on
// Therefore we use an EPS-offset from the height, as small as reasonably possible. // Therefore we use an EPS-offset from the height, as small as reasonably possible.
const double Height = static_cast<double>(cChunkDef::Height) - 0.00001; const double Height = static_cast<double>(cChunkDef::Height) - 0.00001;
CalcXZIntersection(Height, m_StartX, m_StartZ); CalcXZIntersection(Height, m_Start.x, m_Start.z);
m_StartY = Height; m_Start.y = Height;
} }
@ -226,8 +198,8 @@ void cLineBlockTracer::FixStartAboveWorld(void)
void cLineBlockTracer::FixStartBelowWorld(void) void cLineBlockTracer::FixStartBelowWorld(void)
{ {
CalcXZIntersection(0, m_StartX, m_StartZ); CalcXZIntersection(0, m_Start.x, m_Start.z);
m_StartY = 0; m_Start.y = 0;
} }
@ -236,9 +208,9 @@ void cLineBlockTracer::FixStartBelowWorld(void)
void cLineBlockTracer::CalcXZIntersection(double a_Y, double & a_IntersectX, double & a_IntersectZ) void cLineBlockTracer::CalcXZIntersection(double a_Y, double & a_IntersectX, double & a_IntersectZ)
{ {
double Ratio = (m_StartY - a_Y) / (m_StartY - m_EndY); double Ratio = (m_Start.y - a_Y) / (m_Start.y - m_End.y);
a_IntersectX = m_StartX + (m_EndX - m_StartX) * Ratio; a_IntersectX = m_Start.x + (m_End.x - m_Start.x) * Ratio;
a_IntersectZ = m_StartZ + (m_EndZ - m_StartZ) * Ratio; a_IntersectZ = m_Start.z + (m_End.z - m_Start.z) * Ratio;
} }
@ -259,10 +231,10 @@ bool cLineBlockTracer::MoveToNextBlock(void)
// Calculate the next YZ wall hit: // Calculate the next YZ wall hit:
double Coeff = 1; double Coeff = 1;
if (std::abs(m_DiffX) > EPS) if (std::abs(m_Diff.x) > EPS)
{ {
double DestX = (m_DirX > 0) ? (m_CurrentX + 1) : m_CurrentX; double DestX = (m_Dir.x > 0) ? (m_Current.x + 1) : m_Current.x;
double CoeffX = (DestX - m_StartX) / m_DiffX; double CoeffX = (DestX - m_Start.x) / m_Diff.x;
if (CoeffX <= 1) // We need to include equality for the last block in the trace if (CoeffX <= 1) // We need to include equality for the last block in the trace
{ {
Coeff = CoeffX; Coeff = CoeffX;
@ -271,10 +243,10 @@ bool cLineBlockTracer::MoveToNextBlock(void)
} }
// If the next XZ wall hit is closer, use it instead: // If the next XZ wall hit is closer, use it instead:
if (std::abs(m_DiffY) > EPS) if (std::abs(m_Diff.y) > EPS)
{ {
double DestY = (m_DirY > 0) ? (m_CurrentY + 1) : m_CurrentY; double DestY = (m_Dir.y > 0) ? (m_Current.y + 1) : m_Current.y;
double CoeffY = (DestY - m_StartY) / m_DiffY; double CoeffY = (DestY - m_Start.y) / m_Diff.y;
if (CoeffY <= Coeff) // We need to include equality for the last block in the trace if (CoeffY <= Coeff) // We need to include equality for the last block in the trace
{ {
Coeff = CoeffY; Coeff = CoeffY;
@ -283,10 +255,10 @@ bool cLineBlockTracer::MoveToNextBlock(void)
} }
// If the next XY wall hit is closer, use it instead: // If the next XY wall hit is closer, use it instead:
if (std::abs(m_DiffZ) > EPS) if (std::abs(m_Diff.z) > EPS)
{ {
double DestZ = (m_DirZ > 0) ? (m_CurrentZ + 1) : m_CurrentZ; double DestZ = (m_Dir.z > 0) ? (m_Current.z + 1) : m_Current.z;
double CoeffZ = (DestZ - m_StartZ) / m_DiffZ; double CoeffZ = (DestZ - m_Start.z) / m_Diff.z;
if (CoeffZ <= Coeff) // We need to include equality for the last block in the trace if (CoeffZ <= Coeff) // We need to include equality for the last block in the trace
{ {
Direction = dirZ; Direction = dirZ;
@ -296,9 +268,9 @@ bool cLineBlockTracer::MoveToNextBlock(void)
// Based on the wall hit, adjust the current coords // Based on the wall hit, adjust the current coords
switch (Direction) switch (Direction)
{ {
case dirX: m_CurrentX += m_DirX; m_CurrentFace = (m_DirX > 0) ? BLOCK_FACE_XM : BLOCK_FACE_XP; break; case dirX: m_Current.x += m_Dir.x; m_CurrentFace = (m_Dir.x > 0) ? BLOCK_FACE_XM : BLOCK_FACE_XP; break;
case dirY: m_CurrentY += m_DirY; m_CurrentFace = (m_DirY > 0) ? BLOCK_FACE_YM : BLOCK_FACE_YP; break; case dirY: m_Current.y += m_Dir.y; m_CurrentFace = (m_Dir.y > 0) ? BLOCK_FACE_YM : BLOCK_FACE_YP; break;
case dirZ: m_CurrentZ += m_DirZ; m_CurrentFace = (m_DirZ > 0) ? BLOCK_FACE_ZM : BLOCK_FACE_ZP; break; case dirZ: m_Current.z += m_Dir.z; m_CurrentFace = (m_Dir.z > 0) ? BLOCK_FACE_ZM : BLOCK_FACE_ZP; break;
case dirNONE: return false; case dirNONE: return false;
} }
return true; return true;
@ -310,7 +282,7 @@ bool cLineBlockTracer::MoveToNextBlock(void)
bool cLineBlockTracer::ChunkCallback(cChunk * a_Chunk) bool cLineBlockTracer::ChunkCallback(cChunk * a_Chunk)
{ {
ASSERT((m_CurrentY >= 0) && (m_CurrentY < cChunkDef::Height)); // This should be provided by FixStartAboveWorld() / FixStartBelowWorld() ASSERT((m_Current.y >= 0) && (m_Current.y < cChunkDef::Height)); // This should be provided by FixStartAboveWorld() / FixStartBelowWorld()
// This is the actual line tracing loop. // This is the actual line tracing loop.
for (;;) for (;;)
@ -330,12 +302,12 @@ bool cLineBlockTracer::ChunkCallback(cChunk * a_Chunk)
return true; return true;
} }
if ((m_CurrentY < 0) || (m_CurrentY >= cChunkDef::Height)) if ((m_Current.y < 0) || (m_Current.y >= cChunkDef::Height))
{ {
// We've gone out of the world, that's the end of this trace // We've gone out of the world, that's the end of this trace
double IntersectX, IntersectZ; double IntersectX, IntersectZ;
CalcXZIntersection(m_CurrentY, IntersectX, IntersectZ); CalcXZIntersection(m_Current.y, IntersectX, IntersectZ);
if (m_Callbacks->OnOutOfWorld(IntersectX, m_CurrentY, IntersectZ)) if (m_Callbacks->OnOutOfWorld({IntersectX, double(m_Current.y), IntersectZ}))
{ {
// The callback terminated the trace // The callback terminated the trace
return false; return false;
@ -345,7 +317,7 @@ bool cLineBlockTracer::ChunkCallback(cChunk * a_Chunk)
} }
// Update the current chunk // Update the current chunk
a_Chunk = a_Chunk->GetNeighborChunk(m_CurrentX, m_CurrentZ); a_Chunk = a_Chunk->GetNeighborChunk(m_Current.x, m_Current.z);
if (a_Chunk == nullptr) if (a_Chunk == nullptr)
{ {
m_Callbacks->OnNoChunk(); m_Callbacks->OnNoChunk();
@ -356,16 +328,16 @@ bool cLineBlockTracer::ChunkCallback(cChunk * a_Chunk)
{ {
BLOCKTYPE BlockType; BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta; NIBBLETYPE BlockMeta;
int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width; int RelX = m_Current.x - a_Chunk->GetPosX() * cChunkDef::Width;
int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width; int RelZ = m_Current.z - a_Chunk->GetPosZ() * cChunkDef::Width;
a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta); a_Chunk->GetBlockTypeMeta(RelX, m_Current.y, RelZ, BlockType, BlockMeta);
if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta, m_CurrentFace)) if (m_Callbacks->OnNextBlock(m_Current, BlockType, BlockMeta, m_CurrentFace))
{ {
// The callback terminated the trace // The callback terminated the trace
return false; return false;
} }
} }
else if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ, m_CurrentFace)) else if (m_Callbacks->OnNextBlockNoData(m_Current, m_CurrentFace))
{ {
// The callback terminated the trace // The callback terminated the trace
return false; return false;
@ -375,4 +347,3 @@ bool cLineBlockTracer::ChunkCallback(cChunk * a_Chunk)

View File

@ -45,15 +45,13 @@ public:
cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks); cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks);
/** Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) */ /** Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) */
bool Trace(double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ); bool Trace(Vector3d a_Start, Vector3d a_End);
// Utility functions for simple one-line usage: // Utility functions for simple one-line usage:
/** Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) */ /** 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, double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ); static bool Trace(cWorld & a_World, cCallbacks & a_Callbacks, const Vector3d a_Start, const Vector3d a_End);
/** 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). /** 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. */ a_Sight specifies which blocks are considered transparent for the trace, is an OR-combination of eLineOfSight constants. */
@ -75,19 +73,19 @@ public:
protected: protected:
/** The start point of the trace */ /** The start point of the trace */
double m_StartX, m_StartY, m_StartZ; Vector3d m_Start;
/** The end point of the trace */ /** The end point of the trace */
double m_EndX, m_EndY, m_EndZ; Vector3d m_End;
/** The difference in coords, End - Start */ /** The difference in coords, End - Start */
double m_DiffX, m_DiffY, m_DiffZ; Vector3d m_Diff;
/** The increment at which the block coords are going from Start to End; either +1 or -1 */ /** The increment at which the block coords are going from Start to End; either +1 or -1 */
int m_DirX, m_DirY, m_DirZ; Vector3i m_Dir;
/** The current block */ /** The current block */
int m_CurrentX, m_CurrentY, m_CurrentZ; Vector3i m_Current;
/** The face through which the current block has been entered */ /** The face through which the current block has been entered */
eBlockFace m_CurrentFace; eBlockFace m_CurrentFace;
@ -110,5 +108,3 @@ protected: