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