Tracer replacement (#3704)
* Replaced cTracer usage with cLineBlockTracer. * Exported new cLineBlockTracer utility functions to Lua API.
This commit is contained in:
parent
7c4576a025
commit
2c3c1f1527
@ -977,52 +977,103 @@ return
|
|||||||
{
|
{
|
||||||
Desc = [[
|
Desc = [[
|
||||||
This class provides an easy-to-use interface for tracing lines through individual
|
This class provides an easy-to-use interface for tracing lines through individual
|
||||||
blocks in the world. It will call the provided callbacks according to what events it encounters along the
|
blocks in the world. It can either be used to call the provided callbacks according
|
||||||
way.</p>
|
to what events it encounters along the way, or there are shortcut functions used for
|
||||||
<p>
|
the most popular tracing reasons - line of sight and solid hits.
|
||||||
For the Lua API, there's only one static function exported that takes all the parameters necessary to do
|
|
||||||
the tracing. The Callbacks parameter is a table containing all the functions that will be called upon the
|
|
||||||
various events. See below for further information.
|
|
||||||
]],
|
]],
|
||||||
Functions =
|
Functions =
|
||||||
{
|
{
|
||||||
|
FirstSolidHitTrace =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
IsStatic = true,
|
||||||
|
Params =
|
||||||
|
{
|
||||||
|
{ Name = "World", Type = "cWorld" },
|
||||||
|
{ Name = "StartX", Type = "number" },
|
||||||
|
{ Name = "StartY", Type = "number" },
|
||||||
|
{ Name = "StartZ", Type = "number" },
|
||||||
|
{ Name = "EndX", Type = "number" },
|
||||||
|
{ Name = "EndY", Type = "number" },
|
||||||
|
{ Name = "EndZ", Type = "number" },
|
||||||
|
},
|
||||||
|
Returns =
|
||||||
|
{
|
||||||
|
{ Name = "HasHitSolid", Type = "boolean" },
|
||||||
|
{ Name = "HitCoords", Type = "Vector3d" },
|
||||||
|
{ Name = "HitBlockCoords", Type = "Vector3i" },
|
||||||
|
{ Name = "HitBlockFace", Type = "eBlockFace" },
|
||||||
|
},
|
||||||
|
Notes = "If the specified line hits a solid block, return true and the coordinates / face of the first such solid block hit. Returns false if there's no solid block on that line.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
IsStatic = true,
|
||||||
|
Params =
|
||||||
|
{
|
||||||
|
{ Name = "World", Type = "cWorld" },
|
||||||
|
{ Name = "Start", Type = "Vector3d" },
|
||||||
|
{ Name = "End", Type = "Vector3d" },
|
||||||
|
},
|
||||||
|
Returns =
|
||||||
|
{
|
||||||
|
{ Name = "HasHitSolid", Type = "boolean" },
|
||||||
|
{ Name = "HitCoords", Type = "Vector3d" },
|
||||||
|
{ Name = "HitBlockCoords", Type = "Vector3i" },
|
||||||
|
{ Name = "HitBlockFace", Type = "eBlockFace" },
|
||||||
|
},
|
||||||
|
Notes = "If the specified line hits a solid block, return true and the coordinates / face of the first such solid block hit. Returns false if there's no solid block on that line.",
|
||||||
|
},
|
||||||
|
}, -- FirstSolidHitTrace
|
||||||
|
LineOfSightTrace =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
IsStatic = true,
|
||||||
|
Params =
|
||||||
|
{
|
||||||
|
{ Name = "World", Type = "cWorld" },
|
||||||
|
{ Name = "StartX", Type = "number" },
|
||||||
|
{ Name = "StartY", Type = "number" },
|
||||||
|
{ Name = "StartZ", Type = "number" },
|
||||||
|
{ Name = "EndX", Type = "number" },
|
||||||
|
{ Name = "EndY", Type = "number" },
|
||||||
|
{ Name = "EndZ", Type = "number" },
|
||||||
|
{ Name = "Sight", Type = "number" },
|
||||||
|
},
|
||||||
|
Returns =
|
||||||
|
{
|
||||||
|
{ Name = "CanSee", Type = "boolean" },
|
||||||
|
},
|
||||||
|
Notes = "Returns true if the two points specified are within line of sight of each other. The Sight parameter specifies which blocks are considered transparent for the trace, it is a combination of {{cLineBlockTracer#eLineOfSight|losXXX}} values added together."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
IsStatic = true,
|
||||||
|
Params =
|
||||||
|
{
|
||||||
|
{ Name = "World", Type = "cWorld" },
|
||||||
|
{ Name = "Start", Type = "Vector3d" },
|
||||||
|
{ Name = "End", Type = "Vector3d" },
|
||||||
|
{ Name = "Sight", Type = "number" },
|
||||||
|
},
|
||||||
|
Returns =
|
||||||
|
{
|
||||||
|
{ Name = "CanSee", Type = "boolean" },
|
||||||
|
},
|
||||||
|
Notes = "Returns true if the two points specified are within line of sight of each other. The Sight parameter specifies which blocks are considered transparent for the trace, it is a combination of {{cLineBlockTracer#eLineOfSight|losXXX}} values added together."
|
||||||
|
},
|
||||||
|
}, -- LineOfSightTrace
|
||||||
Trace =
|
Trace =
|
||||||
{
|
{
|
||||||
IsStatic = true,
|
IsStatic = true,
|
||||||
Params =
|
Params =
|
||||||
{
|
{
|
||||||
{
|
{ Name = "World", Type = "cWorld" },
|
||||||
Name = "World",
|
{ Name = "Callbacks", Type = "table" },
|
||||||
Type = "cWorld",
|
{ Name = "StartX", Type = "number" },
|
||||||
},
|
{ Name = "StartY", Type = "number" },
|
||||||
{
|
{ Name = "StartZ", Type = "number" },
|
||||||
Name = "Callbacks",
|
{ Name = "EndX", Type = "number" },
|
||||||
Type = "table",
|
{ Name = "EndY", Type = "number" },
|
||||||
},
|
{ Name = "EndZ", Type = "number" },
|
||||||
{
|
|
||||||
Name = "StartX",
|
|
||||||
Type = "number",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name = "StartY",
|
|
||||||
Type = "number",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name = "StartZ",
|
|
||||||
Type = "number",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name = "EndX",
|
|
||||||
Type = "number",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name = "EndY",
|
|
||||||
Type = "number",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name = "EndZ",
|
|
||||||
Type = "number",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Returns =
|
Returns =
|
||||||
{
|
{
|
||||||
@ -1033,6 +1084,29 @@ various events. See below for further information.
|
|||||||
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 =
|
||||||
|
{
|
||||||
|
losAir =
|
||||||
|
{
|
||||||
|
Notes = "LineOfSight tracing can 'see' through air blocks.",
|
||||||
|
},
|
||||||
|
losWater =
|
||||||
|
{
|
||||||
|
Notes = "LineOfSight tracing can 'see' through water blocks.",
|
||||||
|
},
|
||||||
|
losLava =
|
||||||
|
{
|
||||||
|
Notes = "LineOfSight tracing can 'see' through lava blocks.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ConstantGroups =
|
||||||
|
{
|
||||||
|
eLineOfSight =
|
||||||
|
{
|
||||||
|
Include = "los.*",
|
||||||
|
TextBefore = "The following constants are used to speficy which blocks are see-through when tracing a LineOfSight trace. Add them together to make up the Sight parameter.",
|
||||||
|
},
|
||||||
|
},
|
||||||
AdditionalInfo =
|
AdditionalInfo =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -1109,16 +1183,15 @@ end
|
|||||||
cTracer =
|
cTracer =
|
||||||
{
|
{
|
||||||
Desc = [[
|
Desc = [[
|
||||||
A cTracer object is used to trace lines in the world. One thing you can use the cTracer for, is
|
This class is <b>OBSOLETE</b>, do not use it.
|
||||||
tracing what block a player is looking at, but you can do more with it if you want.</p>
|
See the {{cLineBlockTracer}} class for the replacement.
|
||||||
<p>
|
|
||||||
The cTracer is still a work in progress and is not documented at all.</p>
|
|
||||||
<p>
|
|
||||||
See also the {{cLineBlockTracer}} class for an alternative approach using callbacks.
|
|
||||||
]],
|
]],
|
||||||
Functions =
|
Functions =
|
||||||
{
|
{
|
||||||
|
Trace =
|
||||||
|
{
|
||||||
|
Notes = "<b>OBSOLETE</b>, use the {{cLineBlockTracer}} class instead.",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Vector3d =
|
Vector3d =
|
||||||
|
@ -1838,6 +1838,44 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function HandleConsoleHitTrace(a_Split)
|
||||||
|
local world = cRoot:Get():GetDefaultWorld()
|
||||||
|
local s = Vector3d(0, 70, 0)
|
||||||
|
local e = Vector3d(100, 75, 100)
|
||||||
|
if (tonumber(a_Split[2])) then
|
||||||
|
s.x = tonumber(a_Split[2])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[3])) then
|
||||||
|
s.y = tonumber(a_Split[3])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[4])) then
|
||||||
|
s.z = tonumber(a_Split[4])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[5])) then
|
||||||
|
e.x = tonumber(a_Split[5])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[6])) then
|
||||||
|
e.y = tonumber(a_Split[6])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[7])) then
|
||||||
|
e.z = tonumber(a_Split[7])
|
||||||
|
end
|
||||||
|
local res, hitCoords, hitBlockCoords, hitBlockFace = cLineBlockTracer:FirstSolidHitTrace(world, s, e)
|
||||||
|
if (res) then
|
||||||
|
return true, string.format("The line hits block {%d, %d, %d} at point {%f, %f, %f}, face %s",
|
||||||
|
hitBlockCoords.x, hitBlockCoords.y, hitBlockCoords.z,
|
||||||
|
hitCoords.x, hitCoords.y, hitCoords.z,
|
||||||
|
BlockFaceToString(hitBlockFace)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
return true, "The two points specified don't have a solid block between them."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Monitors the state of the "inh" entity-spawning hook
|
--- Monitors the state of the "inh" entity-spawning hook
|
||||||
-- if false, the hook is installed before the "inh" command processing
|
-- if false, the hook is installed before the "inh" command processing
|
||||||
local isInhHookInstalled = false
|
local isInhHookInstalled = false
|
||||||
@ -1954,6 +1992,40 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function HandleConsoleLosTrace(a_Split)
|
||||||
|
local world = cRoot:Get():GetDefaultWorld()
|
||||||
|
local s = Vector3d(0, 70, 0)
|
||||||
|
local e = Vector3d(100, 75, 100)
|
||||||
|
if (tonumber(a_Split[2])) then
|
||||||
|
s.x = tonumber(a_Split[2])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[3])) then
|
||||||
|
s.y = tonumber(a_Split[3])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[4])) then
|
||||||
|
s.z = tonumber(a_Split[4])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[5])) then
|
||||||
|
e.x = tonumber(a_Split[5])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[6])) then
|
||||||
|
e.y = tonumber(a_Split[6])
|
||||||
|
end
|
||||||
|
if (tonumber(a_Split[7])) then
|
||||||
|
e.z = tonumber(a_Split[7])
|
||||||
|
end
|
||||||
|
local res = cLineBlockTracer:LineOfSightTrace(world, s, e, cLineBlockTracer.losAir)
|
||||||
|
if (res) then
|
||||||
|
return true, "The two points can see each other."
|
||||||
|
else
|
||||||
|
return true, "The two points cannot see each other"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function HandleConsolePluginStats(a_Split)
|
function HandleConsolePluginStats(a_Split)
|
||||||
cPluginManager:ForEachPlugin(
|
cPluginManager:ForEachPlugin(
|
||||||
function (a_CBPlugin)
|
function (a_CBPlugin)
|
||||||
|
@ -290,6 +290,12 @@ g_PluginInfo =
|
|||||||
HelpString = "Tests the crypto hashing functions",
|
HelpString = "Tests the crypto hashing functions",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
["hittrace"] =
|
||||||
|
{
|
||||||
|
Handler = HandleConsoleHitTrace,
|
||||||
|
HelpString = "Tests the FirstSolidHit trace",
|
||||||
|
},
|
||||||
|
|
||||||
["inh"] =
|
["inh"] =
|
||||||
{
|
{
|
||||||
Handler = HandleConsoleInh,
|
Handler = HandleConsoleInh,
|
||||||
@ -302,6 +308,12 @@ g_PluginInfo =
|
|||||||
HelpString = "Loads the specified chunk into memory",
|
HelpString = "Loads the specified chunk into memory",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
["lostrace"] =
|
||||||
|
{
|
||||||
|
Handler = HandleConsoleLosTrace,
|
||||||
|
HelpString = "Tests a LineOfSight trace",
|
||||||
|
},
|
||||||
|
|
||||||
["pluginstats"] =
|
["pluginstats"] =
|
||||||
{
|
{
|
||||||
Handler = HandleConsolePluginStats,
|
Handler = HandleConsolePluginStats,
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
#include "../Entities/Player.h"
|
#include "../Entities/Player.h"
|
||||||
#include "LuaState.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 */
|
/** function: cWorld:SetSignLines */
|
||||||
static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
|
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_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_beginmodule(tolua_S, "cWorld");
|
||||||
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
|
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
|
||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
|
@ -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;
|
bool res = false;
|
||||||
if (!m_Callbacks->CallTableFn(
|
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)
|
static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
|
||||||
{
|
{
|
||||||
/* Supported function signatures:
|
/* Supported function signatures:
|
||||||
@ -3917,7 +4113,13 @@ void cManualBindings::Bind(lua_State * tolua_S)
|
|||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
|
|
||||||
tolua_beginmodule(tolua_S, "cLineBlockTracer");
|
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_endmodule(tolua_S);
|
||||||
|
|
||||||
tolua_beginmodule(tolua_S, "cLuaWindow");
|
tolua_beginmodule(tolua_S, "cLuaWindow");
|
||||||
|
@ -13,6 +13,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fwd: World.h
|
// fwd: World.h
|
||||||
class cWorld;
|
class cWorld;
|
||||||
|
|
||||||
@ -34,7 +40,7 @@ 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, 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
|
/** 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.
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include "../Chunk.h"
|
#include "../Chunk.h"
|
||||||
#include "../Simulator/FluidSimulator.h"
|
#include "../Simulator/FluidSimulator.h"
|
||||||
#include "../Bindings/PluginManager.h"
|
#include "../Bindings/PluginManager.h"
|
||||||
#include "../Tracer.h"
|
#include "../LineBlockTracer.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "Items/ItemHandler.h"
|
#include "Items/ItemHandler.h"
|
||||||
#include "../FastRandom.h"
|
#include "../FastRandom.h"
|
||||||
@ -1071,29 +1071,38 @@ void cEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
|||||||
// Get water direction
|
// Get water direction
|
||||||
Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ);
|
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)
|
switch (WaterDir)
|
||||||
{
|
{
|
||||||
case X_PLUS:
|
case X_PLUS:
|
||||||
|
{
|
||||||
m_WaterSpeed.x = 0.2f;
|
m_WaterSpeed.x = 0.2f;
|
||||||
m_bOnGround = false;
|
m_bOnGround = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case X_MINUS:
|
case X_MINUS:
|
||||||
|
{
|
||||||
m_WaterSpeed.x = -0.2f;
|
m_WaterSpeed.x = -0.2f;
|
||||||
m_bOnGround = false;
|
m_bOnGround = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Z_PLUS:
|
case Z_PLUS:
|
||||||
|
{
|
||||||
m_WaterSpeed.z = 0.2f;
|
m_WaterSpeed.z = 0.2f;
|
||||||
m_bOnGround = false;
|
m_bOnGround = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Z_MINUS:
|
case Z_MINUS:
|
||||||
|
{
|
||||||
m_WaterSpeed.z = -0.2f;
|
m_WaterSpeed.z = -0.2f;
|
||||||
m_bOnGround = false;
|
m_bOnGround = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fabs(m_WaterSpeed.x) < 0.05)
|
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)
|
if (NextSpeed.SqrLength() > 0.0f)
|
||||||
{
|
{
|
||||||
cTracer Tracer(GetWorld());
|
Vector3d HitCoords;
|
||||||
// Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse
|
Vector3i HitBlockCoords;
|
||||||
int DistanceToTrace = CeilC((NextSpeed * DtSec.count()).SqrLength()) * 2;
|
eBlockFace HitBlockFace;
|
||||||
bool HasHit = Tracer.Trace(NextPos, NextSpeed, DistanceToTrace);
|
if (cLineBlockTracer::FirstSolidHitTrace(*GetWorld(), NextPos, NextPos + NextSpeed, HitCoords, HitBlockCoords, HitBlockFace))
|
||||||
|
|
||||||
if (HasHit)
|
|
||||||
{
|
{
|
||||||
// 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)
|
// Set our position to where the block was hit, minus a bit:
|
||||||
// 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
|
// TODO: The real entity's m_Width should be taken into account here
|
||||||
if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * DtSec.count()).SqrLength())
|
NextPos = HitCoords - NextSpeed.NormalizeCopy() * 0.1;
|
||||||
|
if (HitBlockFace == BLOCK_FACE_YM)
|
||||||
{
|
{
|
||||||
// Block hit was within our projected path
|
// We hit the ground, adjust the position to the top of the block:
|
||||||
// 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.
|
m_bOnGround = true;
|
||||||
// For example: HitNormal.y = -1 : BLOCK_FACE_YM; HitNormal.y = 1 : BLOCK_FACE_YP
|
NextPos.y = HitBlockCoords.y + 1;
|
||||||
if (Tracer.HitNormal.x != 0.0f)
|
}
|
||||||
{
|
|
||||||
NextSpeed.x = 0.0f;
|
|
||||||
}
|
|
||||||
if (Tracer.HitNormal.y != 0.0f)
|
|
||||||
{
|
|
||||||
NextSpeed.y = 0.0f;
|
|
||||||
}
|
|
||||||
if (Tracer.HitNormal.z != 0.0f)
|
|
||||||
{
|
|
||||||
NextSpeed.z = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, set our position to the hit block (i.e. move part way along our intended trajectory)
|
// Avoid movement in the direction of the blockface that has been hit:
|
||||||
NextPos.Set(Tracer.RealHit.x, Tracer.RealHit.y, Tracer.RealHit.z);
|
switch (HitBlockFace)
|
||||||
NextPos.x += Tracer.HitNormal.x * 0.1;
|
{
|
||||||
NextPos.y += Tracer.HitNormal.y * 0.05;
|
case BLOCK_FACE_XM:
|
||||||
NextPos.z += Tracer.HitNormal.z * 0.1;
|
case BLOCK_FACE_XP:
|
||||||
|
|
||||||
if (Tracer.HitNormal.y == 1.0f) // Hit BLOCK_FACE_YP, we are on the ground
|
|
||||||
{
|
{
|
||||||
m_bOnGround = true;
|
NextSpeed.x = 0;
|
||||||
NextPos.y = FloorC(NextPos.y); // we clamp the height to 0 cos otherwise we'll constantly be slightly above the block
|
break;
|
||||||
|
}
|
||||||
|
case BLOCK_FACE_YM:
|
||||||
|
case BLOCK_FACE_YP:
|
||||||
|
{
|
||||||
|
NextSpeed.y = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BLOCK_FACE_ZM:
|
||||||
|
case BLOCK_FACE_ZP:
|
||||||
|
{
|
||||||
|
NextSpeed.z = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
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);
|
SetPosition(NextPos);
|
||||||
SetSpeed(NextSpeed);
|
SetSpeed(NextSpeed);
|
||||||
|
@ -56,7 +56,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, 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:
|
// DEBUG:
|
||||||
|
@ -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)
|
if (a_CBBlockType != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
|
@ -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))
|
if (IsBlockWater(a_BlockType))
|
||||||
{
|
{
|
||||||
|
@ -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))
|
if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType))
|
||||||
{
|
{
|
||||||
@ -241,7 +241,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, 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)
|
if (a_CBBlockType != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
@ -250,7 +250,7 @@ public:
|
|||||||
m_EntryFace = static_cast<eBlockFace>(a_CBEntryFace);
|
m_EntryFace = static_cast<eBlockFace>(a_CBEntryFace);
|
||||||
if (!cFluidSimulator::CanWashAway(a_CBBlockType) && !IsBlockLiquid(a_CBBlockType))
|
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)
|
m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ); // (Block could be washed away, replace it)
|
||||||
return true; // Abort tracing
|
return true; // Abort tracing
|
||||||
@ -263,7 +263,8 @@ public:
|
|||||||
Vector3d Start(a_Player->GetEyePosition());
|
Vector3d Start(a_Player->GetEyePosition());
|
||||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
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
|
// 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.x, Start.y, Start.z, End.x, End.y, End.z))
|
||||||
{
|
{
|
||||||
|
@ -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))
|
if (IsBlockWater(a_CBBlockType))
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "Vector3.h"
|
#include "Vector3.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include "Chunk.h"
|
#include "Chunk.h"
|
||||||
|
#include "BoundingBox.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ cLineBlockTracer::cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) :
|
|||||||
m_CurrentX(0),
|
m_CurrentX(0),
|
||||||
m_CurrentY(0),
|
m_CurrentY(0),
|
||||||
m_CurrentZ(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)
|
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);
|
cLineBlockTracer Tracer(a_World, a_Callbacks);
|
||||||
|
@ -33,6 +33,19 @@ class cLineBlockTracer :
|
|||||||
typedef cBlockTracer super;
|
typedef cBlockTracer super;
|
||||||
|
|
||||||
public:
|
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);
|
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()) */
|
||||||
@ -46,6 +59,24 @@ public:
|
|||||||
/** 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, const Vector3d & a_Start, const Vector3d & a_End);
|
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:
|
protected:
|
||||||
/** The start point of the trace */
|
/** The start point of the trace */
|
||||||
double m_StartX, m_StartY, m_StartZ;
|
double m_StartX, m_StartY, m_StartZ;
|
||||||
@ -63,7 +94,7 @@ protected:
|
|||||||
int m_CurrentX, m_CurrentY, m_CurrentZ;
|
int m_CurrentX, m_CurrentY, m_CurrentZ;
|
||||||
|
|
||||||
/** The face through which the current block has been entered */
|
/** 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 */
|
/** Adjusts the start point above the world to just at the world's top */
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
#include "../Entities/Player.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);
|
CheckEventSeePlayer(a_Chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetTarget() == nullptr)
|
auto target = GetTarget();
|
||||||
|
if (target == nullptr)
|
||||||
{
|
{
|
||||||
return;
|
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 MyHeadPosition = GetPosition() + Vector3d(0, GetHeight(), 0);
|
||||||
Vector3d AttackDirection(GetTarget()->GetPosition() + Vector3d(0, GetTarget()->GetHeight(), 0) - MyHeadPosition);
|
Vector3d TargetPosition = target->GetPosition() + Vector3d(0, target->GetHeight(), 0);
|
||||||
|
if (
|
||||||
|
TargetIsInRange() &&
|
||||||
if (TargetIsInRange() && !LineOfSight.Trace(MyHeadPosition, AttackDirection, static_cast<int>(AttackDirection.Length())) && (GetHealth() > 0.0))
|
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 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);
|
Attack(a_Dt);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "Enderman.h"
|
#include "Enderman.h"
|
||||||
#include "../Entities/Player.h"
|
#include "../Entities/Player.h"
|
||||||
#include "../Tracer.h"
|
#include "../LineBlockTracer.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -29,9 +29,8 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3d Direction = m_EndermanPos - a_Player->GetPosition();
|
// Don't check players who are more than SightDistance (64) blocks away
|
||||||
|
auto Direction = m_EndermanPos - a_Player->GetPosition();
|
||||||
// Don't check players who are more then SightDistance (64) blocks away
|
|
||||||
if (Direction.Length() > m_SightDistance)
|
if (Direction.Length() > m_SightDistance)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -43,19 +42,16 @@ public:
|
|||||||
return false;
|
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 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cTracer LineOfSight(a_Player->GetWorld());
|
// TODO: Check if endermen are angered through water in Vanilla
|
||||||
if (LineOfSight.Trace(m_EndermanPos, Direction, static_cast<int>(Direction.Length())))
|
if (!cLineBlockTracer::LineOfSightTrace(*a_Player->GetWorld(), m_EndermanPos, a_Player->GetPosition(), cLineBlockTracer::losAirWater))
|
||||||
{
|
{
|
||||||
// No direct line of sight
|
// No direct line of sight
|
||||||
return false;
|
return false;
|
||||||
|
10
src/Tracer.h
10
src/Tracer.h
@ -35,7 +35,10 @@ public:
|
|||||||
cTracer(cWorld * a_World);
|
cTracer(cWorld * a_World);
|
||||||
~cTracer();
|
~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)
|
bool Trace(const Vector3f & a_Start, const Vector3f & a_Direction, int a_Distance)
|
||||||
{
|
{
|
||||||
return Trace(a_Start, a_Direction, a_Distance, false);
|
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.
|
/** 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
|
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.
|
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);
|
bool Trace(const Vector3f & a_Start, const Vector3f & a_Direction, int a_Distance, bool a_LineOfSight);
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** Preps Tracer object for call of Trace function. Only used internally. */
|
/** Preps Tracer object for call of Trace function. Only used internally. */
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "Generating/ChunkDesc.h"
|
#include "Generating/ChunkDesc.h"
|
||||||
#include "SetChunkData.h"
|
#include "SetChunkData.h"
|
||||||
#include "DeadlockDetect.h"
|
#include "DeadlockDetect.h"
|
||||||
|
#include "LineBlockTracer.h"
|
||||||
|
|
||||||
// Serializers
|
// Serializers
|
||||||
#include "WorldStorage/ScoreboardSerializer.h"
|
#include "WorldStorage/ScoreboardSerializer.h"
|
||||||
@ -50,11 +51,6 @@
|
|||||||
#include "Bindings/PluginManager.h"
|
#include "Bindings/PluginManager.h"
|
||||||
#include "Blocks/BlockHandler.h"
|
#include "Blocks/BlockHandler.h"
|
||||||
|
|
||||||
#include "Tracer.h"
|
|
||||||
|
|
||||||
// DEBUG: Test out the cLineBlockTracer class by tracing a few lines:
|
|
||||||
#include "LineBlockTracer.h"
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#endif
|
#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)
|
cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, bool a_CheckLineOfSight)
|
||||||
{
|
{
|
||||||
cTracer LineOfSight(this);
|
|
||||||
|
|
||||||
double ClosestDistance = a_SightLimit;
|
double ClosestDistance = a_SightLimit;
|
||||||
cPlayer * ClosestPlayer = nullptr;
|
cPlayer * ClosestPlayer = nullptr;
|
||||||
|
|
||||||
@ -3208,22 +3201,23 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit,
|
|||||||
Vector3f Pos = (*itr)->GetPosition();
|
Vector3f Pos = (*itr)->GetPosition();
|
||||||
double Distance = (Pos - a_Pos).Length();
|
double Distance = (Pos - a_Pos).Length();
|
||||||
|
|
||||||
if (Distance < ClosestDistance)
|
// If the player is too far, skip them:
|
||||||
|
if (Distance > ClosestDistance)
|
||||||
{
|
{
|
||||||
if (a_CheckLineOfSight)
|
continue;
|
||||||
{
|
|
||||||
if (!LineOfSight.Trace(a_Pos, (Pos - a_Pos), static_cast<int>((Pos - a_Pos).Length())))
|
|
||||||
{
|
|
||||||
ClosestDistance = Distance;
|
|
||||||
ClosestPlayer = *itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ClosestDistance = Distance;
|
|
||||||
ClosestPlayer = *itr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check LineOfSight, if requested:
|
||||||
|
if (
|
||||||
|
a_CheckLineOfSight &&
|
||||||
|
!cLineBlockTracer::LineOfSightTrace(*this, a_Pos, Pos, cLineBlockTracer::losAirWater)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClosestDistance = Distance;
|
||||||
|
ClosestPlayer = *itr;
|
||||||
}
|
}
|
||||||
return ClosestPlayer;
|
return ClosestPlayer;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user