mirror of
https://github.com/cuberite/cuberite.git
synced 2025-01-07 03:16:55 +08:00
Explosions: improve performance
This commit is contained in:
parent
9d0623a665
commit
284f54ed81
@ -32,7 +32,7 @@
|
||||
#include "../Generating/ChunkDesc.h"
|
||||
#include "../HTTP/UrlParser.h"
|
||||
#include "../Item.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Physics/Tracers/LineBlockTracer.h"
|
||||
#include "../Server.h"
|
||||
#include "../Root.h"
|
||||
#include "../StringCompression.h"
|
||||
@ -2871,9 +2871,9 @@ tolua_lerror:
|
||||
|
||||
|
||||
|
||||
/** Provides interface between a Lua table of callbacks and the cBlockTracer::cCallbacks */
|
||||
/** Provides interface between a Lua table of callbacks and the BlockTracerCallbacks */
|
||||
class cLuaBlockTracerCallbacks :
|
||||
public cBlockTracer::cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
public:
|
||||
cLuaBlockTracerCallbacks(cLuaState::cTableRefPtr && a_Callbacks):
|
||||
@ -2962,7 +2962,7 @@ protected:
|
||||
|
||||
|
||||
|
||||
/** Provides interface between a Lua table of callbacks and the cBlockTracer::cCallbacks
|
||||
/** Provides interface between a Lua table of callbacks and the BlockTracerCallbacks
|
||||
This is the deprecated version of cLuaBlockTracerCallback, used when the plugin calls
|
||||
the Trace function with number-based coords. */
|
||||
class cLuaBlockTracerCallbacksOld :
|
||||
@ -3093,7 +3093,7 @@ static int tolua_cLineBlockTracer_FirstSolidHitTrace(lua_State * tolua_S)
|
||||
Vector3d hitCoords;
|
||||
Vector3i hitBlockCoords;
|
||||
eBlockFace hitBlockFace;
|
||||
auto isHit = cLineBlockTracer::FirstSolidHitTrace(*world, Vector3d(startX, startY, startZ), Vector3d(endX, endY, endZ), hitCoords, hitBlockCoords, hitBlockFace);
|
||||
auto isHit = LineBlockTracer::FirstSolidHitTrace(*world, Vector3d(startX, startY, startZ), Vector3d(endX, endY, endZ), hitCoords, hitBlockCoords, hitBlockFace);
|
||||
L.Push(isHit);
|
||||
if (!isHit)
|
||||
{
|
||||
@ -3129,7 +3129,7 @@ static int tolua_cLineBlockTracer_FirstSolidHitTrace(lua_State * tolua_S)
|
||||
Vector3d hitCoords;
|
||||
Vector3i hitBlockCoords;
|
||||
eBlockFace hitBlockFace;
|
||||
auto isHit = cLineBlockTracer::FirstSolidHitTrace(*world, start, end, hitCoords, hitBlockCoords, hitBlockFace);
|
||||
auto isHit = LineBlockTracer::FirstSolidHitTrace(*world, start, end, hitCoords, hitBlockCoords, hitBlockFace);
|
||||
L.Push(isHit);
|
||||
if (!isHit)
|
||||
{
|
||||
@ -3197,9 +3197,9 @@ static int tolua_cLineBlockTracer_LineOfSightTrace(lua_State * tolua_S)
|
||||
L.LogStackValues("Values on the stack");
|
||||
return 0;
|
||||
}
|
||||
int lineOfSight = cLineBlockTracer::losAir | cLineBlockTracer::losWater;
|
||||
int lineOfSight = LineBlockTracer::LineOfSight::AirWater;
|
||||
L.GetStackValue(idx + 7, lineOfSight);
|
||||
L.Push(cLineBlockTracer::LineOfSightTrace(*world, Vector3d(startX, startY, startZ), Vector3d(endX, endY, endZ), lineOfSight));
|
||||
L.Push(LineBlockTracer::LineOfSightTrace(*world, Vector3d(startX, startY, startZ), Vector3d(endX, endY, endZ), static_cast<LineBlockTracer::LineOfSight>(lineOfSight)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3225,9 +3225,9 @@ static int tolua_cLineBlockTracer_LineOfSightTrace(lua_State * tolua_S)
|
||||
L.LogStackValues("Values on the stack");
|
||||
return 0;
|
||||
}
|
||||
int lineOfSight = cLineBlockTracer::losAirWater;
|
||||
int lineOfSight = LineBlockTracer::LineOfSight::AirWater;
|
||||
L.GetStackValue(idx + 7, lineOfSight);
|
||||
L.Push(cLineBlockTracer::LineOfSightTrace(*world, start, end, lineOfSight));
|
||||
L.Push(LineBlockTracer::LineOfSightTrace(*world, start, end, static_cast<LineBlockTracer::LineOfSight>(lineOfSight)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3292,7 +3292,7 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
|
||||
L.LogStackTrace();
|
||||
// Trace:
|
||||
cLuaBlockTracerCallbacksOld tracerCallbacks(std::move(callbacks));
|
||||
bool res = cLineBlockTracer::Trace(*world, tracerCallbacks, start, end);
|
||||
bool res = LineBlockTracer::Trace(*world, tracerCallbacks, start, end);
|
||||
tolua_pushboolean(L, res ? 1 : 0);
|
||||
return 1;
|
||||
}
|
||||
@ -3311,7 +3311,7 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
|
||||
}
|
||||
// Trace:
|
||||
cLuaBlockTracerCallbacks tracerCallbacks(std::move(callbacks));
|
||||
bool res = cLineBlockTracer::Trace(*world, tracerCallbacks, start, end);
|
||||
bool res = LineBlockTracer::Trace(*world, tracerCallbacks, start, end);
|
||||
tolua_pushboolean(L, res ? 1 : 0);
|
||||
return 1;
|
||||
}
|
||||
@ -4640,9 +4640,9 @@ void cManualBindings::Bind(lua_State * tolua_S)
|
||||
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_constant(tolua_S, "losAir", LineBlockTracer::LineOfSight::Air);
|
||||
tolua_constant(tolua_S, "losWater", LineBlockTracer::LineOfSight::Water);
|
||||
tolua_constant(tolua_S, "losLava", LineBlockTracer::LineOfSight::Lava);
|
||||
tolua_endmodule(tolua_S);
|
||||
|
||||
tolua_beginmodule(tolua_S, "cLuaWindow");
|
||||
|
@ -785,7 +785,7 @@ void cChunk::MoveEntityToNewChunk(OwnedEntity a_Entity)
|
||||
cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width);
|
||||
if (Neighbor == nullptr)
|
||||
{
|
||||
LOGWARNING("%s: Entity at %p (%s, ID %d) moving to a non-existent chunk.",
|
||||
LOGD("%s: Entity at %p (%s, ID %d) moving to a non-existent chunk",
|
||||
__FUNCTION__, static_cast<void *>(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID()
|
||||
);
|
||||
|
||||
|
@ -45,7 +45,11 @@ void cEnderCrystal::SetShowBottom(bool a_ShowBottom)
|
||||
void cEnderCrystal::SetBeamTarget(Vector3i a_BeamTarget)
|
||||
{
|
||||
m_BeamTarget = a_BeamTarget;
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
|
||||
if (m_DisplayBeam)
|
||||
{
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "../Chunk.h"
|
||||
#include "../Simulator/FluidSimulator.h"
|
||||
#include "../Bindings/PluginManager.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Physics/Tracers/LineBlockTracer.h"
|
||||
#include "../Items/ItemHandler.h"
|
||||
#include "../FastRandom.h"
|
||||
#include "../NetherPortalScanner.h"
|
||||
@ -1157,7 +1157,7 @@ void cEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
Vector3i HitBlockCoords;
|
||||
eBlockFace HitBlockFace;
|
||||
Vector3d wantNextPos = NextPos + NextSpeed * DtSec.count();
|
||||
auto isHit = cLineBlockTracer::FirstSolidHitTrace(*GetWorld(), NextPos, wantNextPos, HitCoords, HitBlockCoords, HitBlockFace);
|
||||
auto isHit = LineBlockTracer::FirstSolidHitTrace(*GetWorld(), NextPos, wantNextPos, HitCoords, HitBlockCoords, HitBlockFace);
|
||||
if (isHit)
|
||||
{
|
||||
// Set our position to where the block was hit:
|
||||
|
@ -116,12 +116,13 @@ private:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cPickup:
|
||||
|
||||
cPickup::cPickup(Vector3d a_Position, cItem && a_Item, Vector3d a_Speed, cTickTime a_CollectionDelay, cTickTime a_Lifetime) :
|
||||
cPickup::cPickup(Vector3d a_Position, cItem && a_Item, Vector3d a_Speed, cTickTime a_CollectionDelay, cTickTime a_Lifetime, bool a_CanCombine) :
|
||||
Super(etPickup, a_Position, 0.25f, 0.25f),
|
||||
m_Item(std::move(a_Item)),
|
||||
m_RemainingCollectionDelay(a_CollectionDelay),
|
||||
m_RemainingLifetime(a_Lifetime),
|
||||
m_IsCollected(false)
|
||||
m_IsCollected(false),
|
||||
m_IsCombinable(a_CanCombine)
|
||||
{
|
||||
SetGravity(-16.0f);
|
||||
SetAirDrag(0.02f);
|
||||
|
@ -26,7 +26,7 @@ public: // tolua_export
|
||||
|
||||
CLASS_PROTODEF(cPickup)
|
||||
|
||||
cPickup(Vector3d a_Position, cItem && a_Item, Vector3d a_Speed, cTickTime a_CollectionDelay, cTickTime a_Lifetime);
|
||||
cPickup(Vector3d a_Position, cItem && a_Item, Vector3d a_Speed, cTickTime a_CollectionDelay, cTickTime a_Lifetime, bool a_CanCombine);
|
||||
|
||||
cItem & GetItem(void) {return m_Item; } // tolua_export
|
||||
const cItem & GetItem(void) const {return m_Item; }
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "ProjectileEntity.h"
|
||||
#include "../BlockInfo.h"
|
||||
#include "../ClientHandle.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Physics/Tracers/LineBlockTracer.h"
|
||||
#include "../BoundingBox.h"
|
||||
#include "../ChunkMap.h"
|
||||
#include "../Chunk.h"
|
||||
@ -34,7 +34,7 @@
|
||||
// cProjectileTracerCallback:
|
||||
|
||||
class cProjectileTracerCallback :
|
||||
public cBlockTracer::cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
public:
|
||||
cProjectileTracerCallback(cProjectileEntity * a_Projectile) :
|
||||
@ -411,7 +411,7 @@ void cProjectileEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a
|
||||
|
||||
// Trace the tick's worth of movement as a line:
|
||||
cProjectileTracerCallback TracerCallback(this);
|
||||
if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
|
||||
if (!LineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
|
||||
{
|
||||
// Something has been hit, abort all other processing
|
||||
return;
|
||||
|
@ -2,7 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Entities/Boat.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Physics/Tracers/LineBlockTracer.h"
|
||||
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ public:
|
||||
|
||||
// Find the actual placement position by tracing line of sight until non-air block:
|
||||
class cCallbacks:
|
||||
public cBlockTracer::cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
public:
|
||||
Vector3d m_Pos;
|
||||
@ -62,7 +62,7 @@ public:
|
||||
} Callbacks;
|
||||
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
|
||||
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
|
||||
cLineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||
LineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||
if (!Callbacks.m_HasFound)
|
||||
{
|
||||
return false;
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos) const
|
||||
{
|
||||
class cCallbacks:
|
||||
public cBlockTracer::cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
public:
|
||||
Vector3i m_Pos;
|
||||
@ -57,7 +57,7 @@ public:
|
||||
} Callbacks;
|
||||
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
|
||||
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
|
||||
cLineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||
LineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||
if (!Callbacks.m_HasHitFluid)
|
||||
{
|
||||
return false;
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "../World.h"
|
||||
#include "../Simulator/FluidSimulator.h"
|
||||
#include "../Blocks/BlockHandler.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Physics/Tracers/LineBlockTracer.h"
|
||||
#include "../Blocks/ChunkInterface.h"
|
||||
|
||||
|
||||
@ -185,7 +185,7 @@ public:
|
||||
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos) const
|
||||
{
|
||||
class cCallbacks :
|
||||
public cBlockTracer::cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
public:
|
||||
Vector3i m_Pos;
|
||||
@ -213,11 +213,10 @@ public:
|
||||
}
|
||||
} Callbacks;
|
||||
|
||||
cLineBlockTracer Tracer(*a_World, Callbacks);
|
||||
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
|
||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
||||
|
||||
Tracer.Trace(Start, End);
|
||||
LineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||
|
||||
if (!Callbacks.m_HasHitFluid)
|
||||
{
|
||||
@ -236,7 +235,7 @@ public:
|
||||
bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta, eBlockFace & a_BlockFace) const
|
||||
{
|
||||
class cCallbacks :
|
||||
public cBlockTracer::cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
public:
|
||||
Vector3i m_Pos;
|
||||
@ -262,14 +261,13 @@ public:
|
||||
}
|
||||
} Callbacks;
|
||||
|
||||
cLineBlockTracer Tracer(*a_World, Callbacks);
|
||||
Vector3d Start(a_Player->GetEyePosition());
|
||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
||||
|
||||
// cLineBlockTracer::Trace() returns true when whole line was traversed. By returning true from the callback when we hit something,
|
||||
// LineBlockTracer::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, End))
|
||||
if (!LineBlockTracer::Trace(*a_World, Callbacks, Start, End))
|
||||
{
|
||||
a_BlockPos = Callbacks.m_Pos;
|
||||
a_BlockType = Callbacks.m_ReplacedBlockType;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "ItemHandler.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Physics/Tracers/LineBlockTracer.h"
|
||||
|
||||
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
}
|
||||
|
||||
class cCallbacks:
|
||||
public cBlockTracer::cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
public:
|
||||
|
||||
@ -118,7 +118,7 @@ public:
|
||||
|
||||
const auto EyePosition = a_Player->GetEyePosition();
|
||||
const auto End = EyePosition + a_Player->GetLookVector() * 5;
|
||||
if (cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, EyePosition, End))
|
||||
if (LineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, EyePosition, End))
|
||||
{
|
||||
// The line traced to completion; no suitable water was found:
|
||||
return false;
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "../World.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Physics/Tracers/LineBlockTracer.h"
|
||||
|
||||
|
||||
|
||||
@ -68,11 +68,11 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
if (
|
||||
(GetTarget() != nullptr) &&
|
||||
TargetIsInRange() &&
|
||||
cLineBlockTracer::LineOfSightTrace(
|
||||
LineBlockTracer::LineOfSightTrace(
|
||||
*GetWorld(),
|
||||
GetPosition().addedY(GetHeight()),
|
||||
GetTarget()->GetPosition().addedY(GetTarget()->GetHeight()),
|
||||
(IsNetherNative() ? cLineBlockTracer::losAirWaterLava : cLineBlockTracer::losAirWater)
|
||||
(IsNetherNative() ? LineBlockTracer::LineOfSight::AirWaterLava : LineBlockTracer::LineOfSight::AirWater)
|
||||
) &&
|
||||
(GetHealth() > 0.0)
|
||||
)
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "Chunk.h"
|
||||
#include "Enderman.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Physics/Tracers/LineBlockTracer.h"
|
||||
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ public:
|
||||
}
|
||||
|
||||
// TODO: Check if endermen are angered through water in Vanilla
|
||||
if (!cLineBlockTracer::LineOfSightTrace(*a_Player.GetWorld(), m_EndermanHeadPosition, PlayerHeadPosition, cLineBlockTracer::losAirWater))
|
||||
if (!LineBlockTracer::LineOfSightTrace(*a_Player.GetWorld(), m_EndermanHeadPosition, PlayerHeadPosition, LineBlockTracer::LineOfSight::AirWater))
|
||||
{
|
||||
// No direct line of sight
|
||||
return false;
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "IncludeAllMonsters.h"
|
||||
#include "LineBlockTracer.h"
|
||||
#include "Physics/Tracers/LineBlockTracer.h"
|
||||
#include "../BlockInfo.h"
|
||||
#include "../Root.h"
|
||||
#include "../Server.h"
|
||||
@ -754,7 +754,7 @@ void cMonster::CheckEventSeePlayer(cChunk & a_Chunk)
|
||||
// TODO: Currently all mobs see through lava, but only Nether-native mobs should be able to.
|
||||
if (
|
||||
(TargetDistance < ClosestDistance) &&
|
||||
cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, cLineBlockTracer::losAirWaterLava)
|
||||
LineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, LineBlockTracer::LineOfSight::AirWaterLava)
|
||||
)
|
||||
{
|
||||
TargetPlayer = &a_Player;
|
||||
@ -800,7 +800,7 @@ void cMonster::CheckEventLostPlayer(const std::chrono::milliseconds a_Dt)
|
||||
|
||||
const auto MyHeadPosition = GetPosition().addedY(GetHeight());
|
||||
const auto TargetHeadPosition = Target->GetPosition().addedY(Target->GetHeight());
|
||||
if (!cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, cLineBlockTracer::losAirWaterLava))
|
||||
if (!LineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, LineBlockTracer::LineOfSight::AirWaterLava))
|
||||
{
|
||||
if ((m_LoseSightAbandonTargetTimer += a_Dt) > std::chrono::seconds(4))
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "Zombie.h"
|
||||
#include "../World.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
|
||||
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "ZombieVillager.h"
|
||||
#include "../World.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../Entities/Player.h"
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "Chunk.h"
|
||||
#include "ClientHandle.h"
|
||||
#include "Entities/FallingBlock.h"
|
||||
#include "LineBlockTracer.h"
|
||||
#include "Physics/Tracers/LineBlockTracer.h"
|
||||
#include "Simulator/SandSimulator.h"
|
||||
|
||||
|
||||
@ -22,27 +22,10 @@ namespace Explodinator
|
||||
static const auto TraceCubeSideLength = 16U;
|
||||
static const auto BoundingBoxStepUnit = 0.5;
|
||||
|
||||
/** Converts an absolute floating-point Position into a Chunk-relative one. */
|
||||
static Vector3f AbsoluteToRelative(const Vector3f a_Position, const cChunkCoords a_ChunkPosition)
|
||||
{
|
||||
return { a_Position.x - a_ChunkPosition.m_ChunkX * cChunkDef::Width, a_Position.y, a_Position.z - a_ChunkPosition.m_ChunkZ * cChunkDef::Width };
|
||||
}
|
||||
|
||||
/** Make a From Chunk-relative Position into a To Chunk-relative position. */
|
||||
static Vector3f RebaseRelativePosition(const cChunkCoords a_From, const cChunkCoords a_To, const Vector3f a_Position)
|
||||
{
|
||||
return
|
||||
{
|
||||
a_Position.x + (a_From.m_ChunkX - a_To.m_ChunkX) * cChunkDef::Width,
|
||||
a_Position.y,
|
||||
a_Position.z + (a_From.m_ChunkZ - a_To.m_ChunkZ) * cChunkDef::Width
|
||||
};
|
||||
}
|
||||
|
||||
/** Returns how much of an explosion Destruction Lazor's (tm) intensity the given block attenuates.
|
||||
Values are scaled as 0.3 * (0.3 + Wiki) since some compilers miss the constant folding optimisation.
|
||||
Wiki values are https://minecraft.gamepedia.com/Explosion#Blast_resistance as of 2021-02-06. */
|
||||
static float GetExplosionAbsorption(const BLOCKTYPE Block)
|
||||
static constexpr float GetExplosionAbsorption(const BLOCKTYPE Block)
|
||||
{
|
||||
switch (Block)
|
||||
{
|
||||
@ -162,7 +145,7 @@ namespace Explodinator
|
||||
/** Calculates the approximate percentage of an Entity's bounding box that is exposed to an explosion centred at Position. */
|
||||
static float CalculateEntityExposure(const cChunk & a_Chunk, const cEntity & a_Entity, const Vector3f a_Position, const int a_SquareRadius)
|
||||
{
|
||||
class LineOfSightCallbacks final : public cLineBlockTracer::cCallbacks
|
||||
class LineOfSightCallbacks final : public BlockTracerCallbacks
|
||||
{
|
||||
virtual bool OnNextBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
|
||||
{
|
||||
@ -173,7 +156,6 @@ namespace Explodinator
|
||||
const Vector3d Position = a_Position;
|
||||
unsigned Unobstructed = 0, Total = 0;
|
||||
const auto Box = a_Entity.GetBoundingBox();
|
||||
cLineBlockTracer Tracer(*a_Chunk.GetWorld(), Callback);
|
||||
|
||||
for (double X = Box.GetMinX(); X < Box.GetMaxX(); X += BoundingBoxStepUnit)
|
||||
{
|
||||
@ -182,6 +164,7 @@ namespace Explodinator
|
||||
for (double Z = Box.GetMinZ(); Z < Box.GetMaxZ(); Z += BoundingBoxStepUnit)
|
||||
{
|
||||
const Vector3d Destination{X, Y, Z};
|
||||
|
||||
if ((Destination - Position).SqrLength() > a_SquareRadius)
|
||||
{
|
||||
// Don't bother with points outside our designated area-of-effect
|
||||
@ -189,7 +172,7 @@ namespace Explodinator
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Tracer.Trace(a_Position, Destination))
|
||||
if (LineBlockTracer::Trace(a_Chunk, Callback, Position, Destination))
|
||||
{
|
||||
Unobstructed++;
|
||||
}
|
||||
@ -257,120 +240,66 @@ namespace Explodinator
|
||||
}
|
||||
|
||||
/** Sets the block at the given position, updating surroundings. */
|
||||
static void SetBlock(cWorld & a_World, cChunk & a_Chunk, const Vector3i a_AbsolutePosition, const Vector3i a_RelativePosition, const BLOCKTYPE a_DestroyedBlock, const BLOCKTYPE a_NewBlock, const cEntity * const a_ExplodingEntity)
|
||||
static void SetBlock(cChunk & a_Chunk, const Vector3i a_AbsolutePosition, const Vector3i a_RelativePosition, const BLOCKTYPE a_CurrentBlock, const NIBBLETYPE a_CurrentMeta, const BLOCKTYPE a_NewBlock, const cEntity * const a_ExplodingEntity)
|
||||
{
|
||||
const auto DestroyedMeta = a_Chunk.GetMeta(a_RelativePosition);
|
||||
|
||||
// SetBlock wakes up all simulators for the area, so that water and lava flows and sand falls into the blasted holes
|
||||
// It also is responsible for calling cBlockHandler::OnNeighborChanged to pop off blocks that fail CanBeAt
|
||||
// An explicit call to cBlockHandler::OnBroken handles the destruction of multiblock structures
|
||||
// References at (FS #391, GH #4418):
|
||||
a_Chunk.SetBlock(a_RelativePosition, a_NewBlock, 0);
|
||||
|
||||
cChunkInterface Interface(a_World.GetChunkMap());
|
||||
cBlockHandler::For(a_DestroyedBlock).OnBroken(Interface, a_World, a_AbsolutePosition, a_DestroyedBlock, DestroyedMeta, a_ExplodingEntity);
|
||||
auto & World = *a_Chunk.GetWorld();
|
||||
cChunkInterface Interface(World.GetChunkMap());
|
||||
cBlockHandler::For(a_CurrentBlock).OnBroken(Interface, World, a_AbsolutePosition, a_CurrentBlock, a_CurrentMeta, a_ExplodingEntity);
|
||||
}
|
||||
|
||||
/** Work out what should happen when an explosion destroys the given block.
|
||||
Tasks include lighting TNT, dropping pickups, setting fire and flinging shrapnel according to Minecraft rules.
|
||||
OK, _mostly_ Minecraft rules. */
|
||||
static void DestroyBlock(cChunk & a_Chunk, const Vector3i a_Position, const int a_Power, const bool a_Fiery, const cEntity * const a_ExplodingEntity)
|
||||
static void DestroyBlock(MTRand & a_Random, cChunk & a_Chunk, const Vector3i a_AbsolutePosition, const Vector3i a_RelativePosition, const BLOCKTYPE a_CurrentBlock, const NIBBLETYPE a_CurrentMeta, const cBoundingBox a_ExplosionBounds, const int a_Power, const bool a_Fiery, const cEntity * const a_ExplodingEntity)
|
||||
{
|
||||
const auto DestroyedBlock = a_Chunk.GetBlock(a_Position);
|
||||
if (DestroyedBlock == E_BLOCK_AIR)
|
||||
{
|
||||
// There's nothing left for us here, but a barren and empty land
|
||||
// Let's go.
|
||||
return;
|
||||
}
|
||||
|
||||
auto & World = *a_Chunk.GetWorld();
|
||||
auto & Random = GetRandomProvider();
|
||||
const auto Absolute = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
|
||||
|
||||
if (DestroyedBlock == E_BLOCK_TNT) // If the block is TNT we should set it off
|
||||
if (a_CurrentBlock == E_BLOCK_TNT) // If the block is TNT we should set it off
|
||||
{
|
||||
// Random fuse between 10 to 30 game ticks.
|
||||
const int FuseTime = Random.RandInt(10, 30);
|
||||
const int FuseTime = a_Random.RandInt(10, 30);
|
||||
|
||||
// Activate the TNT, with initial velocity and no fuse sound:
|
||||
World.SpawnPrimedTNT(Vector3d(0.5, 0, 0.5) + Absolute, FuseTime, 1, false);
|
||||
World.SpawnPrimedTNT(Vector3d(0.5, 0, 0.5) + a_AbsolutePosition, FuseTime, 1, false);
|
||||
}
|
||||
else if ((a_ExplodingEntity != nullptr) && (a_ExplodingEntity->IsTNT() || BlockAlwaysDrops(DestroyedBlock) || Random.RandBool(1.f / a_Power))) // For TNT explosions, destroying a block that always drops, or if RandBool, drop pickups
|
||||
else if ((a_ExplodingEntity != nullptr) && (a_ExplodingEntity->IsTNT() || BlockAlwaysDrops(a_CurrentBlock) || a_Random.RandBool(1.f / a_Power))) // For TNT explosions, destroying a block that always drops, or if RandBool, drop pickups
|
||||
{
|
||||
const auto DestroyedMeta = a_Chunk.GetMeta(a_Position);
|
||||
a_Chunk.GetWorld()->SpawnItemPickups(cBlockHandler::For(DestroyedBlock).ConvertToPickups(DestroyedMeta), Absolute);
|
||||
for (auto & Item : cBlockHandler::For(a_CurrentBlock).ConvertToPickups(a_CurrentMeta))
|
||||
{
|
||||
World.SpawnItemPickup(Vector3d(0.5, 0, 0.5) + a_AbsolutePosition, std::move(Item), Vector3d(), a_ExplosionBounds);
|
||||
}
|
||||
}
|
||||
else if (a_Fiery && Random.RandBool(1 / 3.0)) // 33% chance of starting fires if it can start fires
|
||||
else if (a_Fiery && a_Random.RandBool(1 / 3.0)) // 33% chance of starting fires if it can start fires
|
||||
{
|
||||
const auto Below = a_Position.addedY(-1);
|
||||
const auto Below = a_AbsolutePosition.addedY(-1);
|
||||
if ((Below.y >= 0) && cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(Below)))
|
||||
{
|
||||
// Start a fire:
|
||||
SetBlock(World, a_Chunk, Absolute, a_Position, DestroyedBlock, E_BLOCK_FIRE, a_ExplodingEntity);
|
||||
SetBlock(a_Chunk, a_AbsolutePosition, a_RelativePosition, a_CurrentBlock, a_CurrentMeta, E_BLOCK_FIRE, a_ExplodingEntity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (const auto Shrapnel = World.GetTNTShrapnelLevel(); (Shrapnel > slNone) && Random.RandBool(0)) // Currently 0% chance of flinging stuff around
|
||||
else if (const auto Shrapnel = World.GetTNTShrapnelLevel(); (Shrapnel > slNone) && a_Random.RandBool(0)) // Currently 0% chance of flinging stuff around
|
||||
{
|
||||
// If the block is shrapnel-able, make a falling block entity out of it:
|
||||
if (
|
||||
((Shrapnel == slAll) && cBlockInfo::FullyOccupiesVoxel(DestroyedBlock)) ||
|
||||
((Shrapnel == slGravityAffectedOnly) && cSandSimulator::IsAllowedBlock(DestroyedBlock))
|
||||
((Shrapnel == slAll) && cBlockInfo::FullyOccupiesVoxel(a_CurrentBlock)) ||
|
||||
((Shrapnel == slGravityAffectedOnly) && cSandSimulator::IsAllowedBlock(a_CurrentBlock))
|
||||
)
|
||||
{
|
||||
const auto DestroyedMeta = a_Chunk.GetMeta(a_Position);
|
||||
auto FallingBlock = std::make_unique<cFallingBlock>(Vector3d(0.5, 0, 0.5) + Absolute, DestroyedBlock, DestroyedMeta);
|
||||
auto FallingBlock = std::make_unique<cFallingBlock>(Vector3d(0.5, 0, 0.5) + a_AbsolutePosition, a_CurrentBlock, a_CurrentMeta);
|
||||
// TODO: correct velocity FallingBlock->SetSpeedY(40);
|
||||
FallingBlock->Initialize(std::move(FallingBlock), World);
|
||||
}
|
||||
}
|
||||
|
||||
SetBlock(World, a_Chunk, Absolute, a_Position, DestroyedBlock, E_BLOCK_AIR, a_ExplodingEntity);
|
||||
}
|
||||
|
||||
/** Traces the path taken by one Explosion Lazor (tm) with given direction and intensity, that will destroy blocks until it is exhausted. */
|
||||
static void DestructionTrace(cChunk * a_Chunk, Vector3f a_Origin, const Vector3f a_Direction, const int a_Power, const bool a_Fiery, float a_Intensity, const cEntity * const a_ExplodingEntity)
|
||||
{
|
||||
// The current position the ray is at.
|
||||
auto Checkpoint = a_Origin;
|
||||
|
||||
// The displacement that the ray in one iteration step should travel.
|
||||
const auto Step = a_Direction.NormalizeCopy() * StepUnit;
|
||||
|
||||
// Loop until intensity runs out:
|
||||
while (a_Intensity > 0)
|
||||
{
|
||||
auto Position = Checkpoint.Floor();
|
||||
if (!cChunkDef::IsValidHeight(Position))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const auto Neighbour = a_Chunk->GetRelNeighborChunkAdjustCoords(Position);
|
||||
if ((Neighbour == nullptr) || !Neighbour->IsValid())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
a_Intensity -= GetExplosionAbsorption(Neighbour->GetBlock(Position));
|
||||
if (a_Intensity <= 0)
|
||||
{
|
||||
// The ray is exhausted:
|
||||
break;
|
||||
}
|
||||
|
||||
DestroyBlock(*Neighbour, Position, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
|
||||
// Adjust coordinates to be relative to the neighbour chunk:
|
||||
Checkpoint = RebaseRelativePosition(a_Chunk->GetPos(), Neighbour->GetPos(), Checkpoint);
|
||||
a_Origin = RebaseRelativePosition(a_Chunk->GetPos(), Neighbour->GetPos(), a_Origin);
|
||||
a_Chunk = Neighbour;
|
||||
|
||||
// Increment the simulation, weaken the ray:
|
||||
Checkpoint += Step;
|
||||
a_Intensity -= StepAttenuation;
|
||||
}
|
||||
SetBlock(a_Chunk, a_AbsolutePosition, a_RelativePosition, a_CurrentBlock, a_CurrentMeta, E_BLOCK_AIR, a_ExplodingEntity);
|
||||
}
|
||||
|
||||
/** Returns a random intensity for an Explosion Lazor (tm) as a function of the explosion's power. */
|
||||
@ -379,12 +308,78 @@ namespace Explodinator
|
||||
return a_Power * (0.7f + a_Random.RandReal(0.6f));
|
||||
}
|
||||
|
||||
/** Traces the path taken by one Explosion Lazor (tm) with given direction and random intensity, that will destroy blocks until it is exhausted. */
|
||||
static void DestructionTrace(MTRand & a_Random, cChunk * a_Chunk, Vector3f a_Origin, const Vector3f a_Direction, const cBoundingBox a_ExplosionBounds, const int a_Power, const bool a_Fiery, const cEntity * const a_ExplodingEntity)
|
||||
{
|
||||
// The current position the ray is at.
|
||||
auto Checkpoint = a_Origin;
|
||||
|
||||
auto Position = Checkpoint.Floor();
|
||||
|
||||
auto Intensity = RandomIntensity(a_Random, a_Power);
|
||||
|
||||
// The displacement that the ray in one iteration step should travel.
|
||||
const auto Step = a_Direction.NormalizeCopy() * StepUnit;
|
||||
|
||||
// Loop until intensity runs out:
|
||||
while (Intensity > 0)
|
||||
{
|
||||
if (!cChunkDef::IsValidHeight(Position))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Vector3i RelativePosition;
|
||||
|
||||
if (!a_Chunk->GetChunkAndRelByAbsolute(Position, &a_Chunk, RelativePosition))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
BLOCKTYPE CurrentBlock;
|
||||
NIBBLETYPE CurrentMeta;
|
||||
a_Chunk->GetBlockTypeMeta(RelativePosition, CurrentBlock, CurrentMeta);
|
||||
|
||||
Intensity -= GetExplosionAbsorption(CurrentBlock);
|
||||
if (Intensity <= 0)
|
||||
{
|
||||
// The ray is exhausted:
|
||||
break;
|
||||
}
|
||||
|
||||
if (CurrentBlock != E_BLOCK_AIR)
|
||||
{
|
||||
DestroyBlock(a_Random, *a_Chunk, Position, RelativePosition, CurrentBlock, CurrentMeta, a_ExplosionBounds, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
}
|
||||
|
||||
// Increment the simulation, weaken the ray:
|
||||
Checkpoint += Step;
|
||||
Intensity -= StepAttenuation;
|
||||
|
||||
for (int i = 0; i != 2; i++)
|
||||
{
|
||||
const auto PreviousPosition = Position;
|
||||
Position = Checkpoint.Floor();
|
||||
|
||||
if (Position != PreviousPosition)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Checkpoint += Step;
|
||||
Intensity -= StepAttenuation + GetExplosionAbsorption(E_BLOCK_AIR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sends out Explosion Lazors (tm) originating from the given position that destroy blocks. */
|
||||
static void DamageBlocks(cChunk & a_Chunk, const Vector3f a_Position, const int a_Power, const bool a_Fiery, const cEntity * const a_ExplodingEntity)
|
||||
{
|
||||
// Oh boy... Better hope you have a hot cache, 'cos this little manoeuvre's gonna cost us 1352 raytraces in one tick...
|
||||
const int HalfSide = TraceCubeSideLength / 2;
|
||||
|
||||
auto & Random = GetRandomProvider();
|
||||
const int HalfSide = TraceCubeSideLength / 2;
|
||||
const cBoundingBox ExplosionBounds(a_Position, TraceCubeSideLength);
|
||||
|
||||
// The following loops implement the tracing algorithm described in http://minecraft.gamepedia.com/Explosion
|
||||
|
||||
@ -394,8 +389,8 @@ namespace Explodinator
|
||||
{
|
||||
for (float OffsetZ = -HalfSide; OffsetZ < HalfSide; OffsetZ++)
|
||||
{
|
||||
DestructionTrace(&a_Chunk, a_Position, Vector3f(OffsetX, +HalfSide, OffsetZ), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
|
||||
DestructionTrace(&a_Chunk, a_Position, Vector3f(OffsetX, -HalfSide, OffsetZ), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
|
||||
DestructionTrace(Random, &a_Chunk, a_Position, Vector3f(OffsetX, +HalfSide, OffsetZ), ExplosionBounds, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
DestructionTrace(Random, &a_Chunk, a_Position, Vector3f(OffsetX, -HalfSide, OffsetZ), ExplosionBounds, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,8 +399,8 @@ namespace Explodinator
|
||||
{
|
||||
for (float OffsetY = -HalfSide + 1; OffsetY < HalfSide - 1; OffsetY++)
|
||||
{
|
||||
DestructionTrace(&a_Chunk, a_Position, Vector3f(OffsetX, OffsetY, +HalfSide), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
|
||||
DestructionTrace(&a_Chunk, a_Position, Vector3f(OffsetX, OffsetY, -HalfSide), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
|
||||
DestructionTrace(Random, &a_Chunk, a_Position, Vector3f(OffsetX, OffsetY, +HalfSide), ExplosionBounds, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
DestructionTrace(Random, &a_Chunk, a_Position, Vector3f(OffsetX, OffsetY, -HalfSide), ExplosionBounds, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,8 +409,8 @@ namespace Explodinator
|
||||
{
|
||||
for (float OffsetY = -HalfSide + 1; OffsetY < HalfSide - 1; OffsetY++)
|
||||
{
|
||||
DestructionTrace(&a_Chunk, a_Position, Vector3f(+HalfSide, OffsetY, OffsetZ), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
|
||||
DestructionTrace(&a_Chunk, a_Position, Vector3f(-HalfSide, OffsetY, OffsetZ), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
|
||||
DestructionTrace(Random, &a_Chunk, a_Position, Vector3f(+HalfSide, OffsetY, OffsetZ), ExplosionBounds, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
DestructionTrace(Random, &a_Chunk, a_Position, Vector3f(-HalfSide, OffsetY, OffsetZ), ExplosionBounds, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -435,7 +430,7 @@ namespace Explodinator
|
||||
{
|
||||
LagTheClient(a_Chunk, a_Position, a_Power);
|
||||
DamageEntities(a_Chunk, a_Position, a_Power);
|
||||
DamageBlocks(a_Chunk, AbsoluteToRelative(a_Position, a_Chunk.GetPos()), a_Power, a_Fiery, a_ExplodingEntity);
|
||||
DamageBlocks(a_Chunk, a_Position, a_Power, a_Fiery, a_ExplodingEntity);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
// BlockTracer.h
|
||||
|
||||
// Declares the classes common for all blocktracers
|
||||
// Declares the callback common to all blocktracers
|
||||
|
||||
|
||||
|
||||
@ -9,118 +9,61 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "Defines.h"
|
||||
#include "ChunkDef.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd: World.h
|
||||
class cWorld;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockTracer abstract
|
||||
/** The callback class is used to notify the caller of individual events that are being traced. */
|
||||
class BlockTracerCallbacks abstract
|
||||
{
|
||||
public:
|
||||
/** The callback class is used to notify the caller of individual events that are being traced.
|
||||
*/
|
||||
class cCallbacks abstract
|
||||
{
|
||||
public:
|
||||
// Force a virtual destructor in descendants:
|
||||
virtual ~cCallbacks() {}
|
||||
|
||||
/** 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(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) = 0;
|
||||
|
||||
/** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded
|
||||
When this callback returns true, the tracing is aborted.
|
||||
*/
|
||||
virtual bool OnNextBlockNoData(Vector3i a_BlockPos, eBlockFace a_EntryFace)
|
||||
{
|
||||
UNUSED(a_BlockPos);
|
||||
UNUSED(a_EntryFace);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Called when the path goes out of world, either below (a_BlockPos.y < 0) or above (a_BlockPos.y >= cChunkDef::Height)
|
||||
The coords specify the exact point at which the path exited the world.
|
||||
If this callback returns true, the tracing is aborted.
|
||||
Note that some paths can go out of the world and come back again (parabola),
|
||||
in such a case this callback is followed by OnIntoWorld() and further OnNextBlock() calls
|
||||
*/
|
||||
virtual bool OnOutOfWorld(Vector3d a_BlockPos)
|
||||
{
|
||||
UNUSED(a_BlockPos);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Called when the path goes into the world, from either below (a_BlockPos.y < 0) or above (a_BlockPos.y >= cChunkDef::Height)
|
||||
The coords specify the exact point at which the path entered the world.
|
||||
If this callback returns true, the tracing is aborted.
|
||||
Note that some paths can go out of the world and come back again (parabola),
|
||||
in such a case this callback is followed by further OnNextBlock() calls
|
||||
*/
|
||||
virtual bool OnIntoWorld(Vector3d a_BlockPos)
|
||||
{
|
||||
UNUSED(a_BlockPos);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Called when the path is sure not to hit any more blocks.
|
||||
Note that for some shapes this might never happen (line with constant Y)
|
||||
*/
|
||||
virtual void OnNoMoreHits(void) {}
|
||||
|
||||
/** Called when the block tracing walks into a chunk that is not allocated.
|
||||
This usually means that the tracing is aborted.
|
||||
*/
|
||||
virtual void OnNoChunk(void) {}
|
||||
} ;
|
||||
|
||||
|
||||
/** Creates the BlockTracer parent with the specified callbacks */
|
||||
cBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) :
|
||||
m_World(&a_World),
|
||||
m_Callbacks(&a_Callbacks)
|
||||
|
||||
// Force a virtual destructor in descendants:
|
||||
virtual ~BlockTracerCallbacks() {}
|
||||
|
||||
/** 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(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) = 0;
|
||||
|
||||
/** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded
|
||||
When this callback returns true, the tracing is aborted. */
|
||||
virtual bool OnNextBlockNoData(Vector3i a_BlockPos, eBlockFace a_EntryFace)
|
||||
{
|
||||
UNUSED(a_BlockPos);
|
||||
UNUSED(a_EntryFace);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Sets new world, returns the old one. Note that both need to be valid */
|
||||
cWorld & SetWorld(cWorld & a_World)
|
||||
/** Called when the path goes out of world, either below (a_BlockPos.y < 0) or above (a_BlockPos.y >= cChunkDef::Height)
|
||||
The coords specify the exact point at which the path exited the world.
|
||||
If this callback returns true, the tracing is aborted.
|
||||
Note that some paths can go out of the world and come back again (parabola),
|
||||
in such a case this callback is followed by OnIntoWorld() and further OnNextBlock() calls. */
|
||||
virtual bool OnOutOfWorld(Vector3d a_BlockPos)
|
||||
{
|
||||
cWorld & Old = *m_World;
|
||||
m_World = &a_World;
|
||||
return Old;
|
||||
UNUSED(a_BlockPos);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Sets new callbacks, returns the old ones. Note that both need to be valid */
|
||||
cCallbacks & SetCallbacks(cCallbacks & a_NewCallbacks)
|
||||
/** Called when the path goes into the world, from either below (a_BlockPos.y < 0) or above (a_BlockPos.y >= cChunkDef::Height)
|
||||
The coords specify the exact point at which the path entered the world.
|
||||
If this callback returns true, the tracing is aborted.
|
||||
Note that some paths can go out of the world and come back again (parabola),
|
||||
in such a case this callback is followed by further OnNextBlock() calls. */
|
||||
virtual bool OnIntoWorld(Vector3d a_BlockPos)
|
||||
{
|
||||
cCallbacks & Old = *m_Callbacks;
|
||||
m_Callbacks = &a_NewCallbacks;
|
||||
return Old;
|
||||
UNUSED(a_BlockPos);
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** The world upon which to operate */
|
||||
cWorld * m_World;
|
||||
/** Called when the path is sure not to hit any more blocks.
|
||||
Note that for some shapes this might never happen (line with constant Y). */
|
||||
virtual void OnNoMoreHits(void) {}
|
||||
|
||||
/** The callback to use for reporting */
|
||||
cCallbacks * m_Callbacks;
|
||||
/** Called when the block tracing walks into a chunk that is not allocated.
|
||||
This usually means that the tracing is aborted. */
|
||||
virtual void OnNoChunk(void) {}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -14,35 +14,186 @@
|
||||
|
||||
|
||||
|
||||
cLineBlockTracer::cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) :
|
||||
Super(a_World, a_Callbacks),
|
||||
m_Start(),
|
||||
m_End(),
|
||||
m_Diff(),
|
||||
m_Dir(),
|
||||
m_Current(),
|
||||
m_CurrentFace(BLOCK_FACE_NONE)
|
||||
static Vector3d CalcXZIntersection(double a_Y, const Vector3d a_Start, const Vector3d a_End)
|
||||
{
|
||||
const double Ratio = (a_Start.y - a_Y) / (a_Start.y - a_End.y);
|
||||
return { a_Start.x + (a_End.x - a_Start.x) * Ratio, a_Y, a_Start.z + (a_End.z - a_Start.z) * Ratio };
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLineBlockTracer::Trace(cWorld & a_World, cBlockTracer::cCallbacks & a_Callbacks, const Vector3d a_Start, const Vector3d a_End)
|
||||
static Vector3d FixStartAboveWorld(const Vector3d a_Start, const Vector3d a_End)
|
||||
{
|
||||
cLineBlockTracer Tracer(a_World, a_Callbacks);
|
||||
return Tracer.Trace(a_Start, a_End);
|
||||
// We must set the start Y to less than cChunkDef::Height so that it is considered inside the world later on.
|
||||
// Therefore we use an EPS-offset from the height, as small as reasonably possible.
|
||||
const double Height = static_cast<double>(cChunkDef::Height) - 0.00001;
|
||||
return CalcXZIntersection(Height, a_Start, a_End);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLineBlockTracer::LineOfSightTrace(cWorld & a_World, const Vector3d & a_Start, const Vector3d & a_End, int a_Sight)
|
||||
static Vector3d FixStartBelowWorld(const Vector3d a_Start, const Vector3d a_End)
|
||||
{
|
||||
return CalcXZIntersection(0, a_Start, a_End);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static eBlockFace MoveToNextBlock(Vector3i & a_CurrentBlock, const Vector3i a_Adjustment, const Vector3d a_Direction, const Vector3d a_Start, const Vector3i a_StepOffset, const eBlockFace a_StepXFace, const eBlockFace a_StepYFace, const eBlockFace a_StepZFace)
|
||||
{
|
||||
const auto Coeff = (Vector3d(a_CurrentBlock + a_Adjustment) - a_Start) / a_Direction;
|
||||
|
||||
if (Coeff.x <= Coeff.y)
|
||||
{
|
||||
if (Coeff.x <= Coeff.z)
|
||||
{
|
||||
a_CurrentBlock.x += a_StepOffset.x;
|
||||
return a_StepXFace;
|
||||
}
|
||||
}
|
||||
else if (Coeff.y <= Coeff.z)
|
||||
{
|
||||
a_CurrentBlock.y += a_StepOffset.y;
|
||||
return a_StepYFace;
|
||||
}
|
||||
|
||||
a_CurrentBlock.z += a_StepOffset.z;
|
||||
return a_StepZFace;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool LineBlockTracer::Trace(const cChunk & a_Chunk, BlockTracerCallbacks & a_Callbacks, Vector3d a_Start, Vector3d a_End)
|
||||
{
|
||||
// Clamp the start coords into the world by advancing them along the line:
|
||||
if (a_Start.y < 0)
|
||||
{
|
||||
if (a_End.y < 0)
|
||||
{
|
||||
// Nothing to trace:
|
||||
a_Callbacks.OnNoMoreHits();
|
||||
return true;
|
||||
}
|
||||
|
||||
a_Start = FixStartBelowWorld(a_Start, a_End);
|
||||
a_Callbacks.OnIntoWorld(a_Start);
|
||||
}
|
||||
else if (a_Start.y >= cChunkDef::Height)
|
||||
{
|
||||
if (a_End.y >= cChunkDef::Height)
|
||||
{
|
||||
a_Callbacks.OnNoMoreHits();
|
||||
return true;
|
||||
}
|
||||
|
||||
a_Start = FixStartAboveWorld(a_Start, a_End);
|
||||
a_Callbacks.OnIntoWorld(a_Start);
|
||||
}
|
||||
|
||||
const auto EndPosition = a_End.Floor();
|
||||
const auto Direction = a_End - a_Start;
|
||||
const bool XPositive = a_Start.x <= a_End.x;
|
||||
const bool YPositive = a_Start.y <= a_End.y;
|
||||
const bool ZPositive = a_Start.z <= a_End.z;
|
||||
const auto StepXFace = XPositive ? BLOCK_FACE_XM : BLOCK_FACE_XP;
|
||||
const auto StepYFace = YPositive ? BLOCK_FACE_YM : BLOCK_FACE_YP;
|
||||
const auto StepZFace = ZPositive ? BLOCK_FACE_ZM : BLOCK_FACE_ZP;
|
||||
const Vector3i Adjustment(XPositive ? 1 : 0, YPositive ? 1 : 0, ZPositive ? 1 : 0);
|
||||
const Vector3i StepOffset(XPositive ? 1 : -1, YPositive ? 1 : -1, ZPositive ? 1 : -1);
|
||||
|
||||
auto Position = a_Start.Floor();
|
||||
auto Chunk = const_cast<cChunk &>(a_Chunk).GetNeighborChunk(Position.x, Position.z);
|
||||
|
||||
// We should always start in a valid chunk:
|
||||
ASSERT(Chunk != nullptr);
|
||||
|
||||
// This is guaranteed by FixStartAboveWorld() / FixStartBelowWorld():
|
||||
ASSERT(cChunkDef::IsValidHeight(Position));
|
||||
|
||||
// This is the actual line tracing loop.
|
||||
for (;;)
|
||||
{
|
||||
if (Position == EndPosition)
|
||||
{
|
||||
// We've reached the end
|
||||
a_Callbacks.OnNoMoreHits();
|
||||
return true;
|
||||
}
|
||||
|
||||
// The face of the next block the line just entered.
|
||||
const auto CurrentFace = MoveToNextBlock(Position, Adjustment, Direction, a_Start, StepOffset, StepXFace, StepYFace, StepZFace);
|
||||
|
||||
if (!cChunkDef::IsValidHeight(Position))
|
||||
{
|
||||
// We've gone out of the world, that's the end of this trace.
|
||||
if (a_Callbacks.OnOutOfWorld(CalcXZIntersection(static_cast<double>(Position.y), a_Start, a_End)))
|
||||
{
|
||||
// The callback terminated the trace
|
||||
return false;
|
||||
}
|
||||
a_Callbacks.OnNoMoreHits();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update the current chunk:
|
||||
Chunk = Chunk->GetNeighborChunk(Position.x, Position.z);
|
||||
if (Chunk == nullptr)
|
||||
{
|
||||
a_Callbacks.OnNoChunk();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Report the current block through the callbacks:
|
||||
if (Chunk->IsValid())
|
||||
{
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
int RelX = Position.x - Chunk->GetPosX() * cChunkDef::Width;
|
||||
int RelZ = Position.z - Chunk->GetPosZ() * cChunkDef::Width;
|
||||
Chunk->GetBlockTypeMeta(RelX, Position.y, RelZ, BlockType, BlockMeta);
|
||||
if (a_Callbacks.OnNextBlock(Position, BlockType, BlockMeta, CurrentFace))
|
||||
{
|
||||
// The callback terminated the trace.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (a_Callbacks.OnNextBlockNoData(Position, CurrentFace))
|
||||
{
|
||||
// The callback terminated the trace.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool LineBlockTracer::Trace(cWorld & a_World, BlockTracerCallbacks & a_Callbacks, const Vector3d a_Start, const Vector3d a_End)
|
||||
{
|
||||
int BlockX = FloorC(a_Start.x);
|
||||
int BlockZ = FloorC(a_Start.z);
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
|
||||
return a_World.DoWithChunk(ChunkX, ChunkZ, [&a_Callbacks, a_Start, a_End](cChunk & a_Chunk) { return Trace(a_Chunk, a_Callbacks, a_Start, a_End); });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool LineBlockTracer::LineOfSightTrace(cWorld & a_World, const Vector3d & a_Start, const Vector3d & a_End, LineOfSight a_Sight)
|
||||
{
|
||||
static class LineOfSightCallbacks:
|
||||
public cLineBlockTracer::cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
bool m_IsAirOpaque;
|
||||
bool m_IsWaterOpaque;
|
||||
@ -67,9 +218,9 @@ bool cLineBlockTracer::LineOfSightTrace(cWorld & a_World, const Vector3d & a_Sta
|
||||
}
|
||||
}
|
||||
} callbacks(
|
||||
(a_Sight & losAir) == 0,
|
||||
(a_Sight & losWater) == 0,
|
||||
(a_Sight & losLava) == 0
|
||||
(a_Sight & LineOfSight::Air) == 0,
|
||||
(a_Sight & LineOfSight::Water) == 0,
|
||||
(a_Sight & LineOfSight::Lava) == 0
|
||||
);
|
||||
return Trace(a_World, callbacks, a_Start, a_End);
|
||||
}
|
||||
@ -78,7 +229,7 @@ bool cLineBlockTracer::LineOfSightTrace(cWorld & a_World, const Vector3d & a_Sta
|
||||
|
||||
|
||||
|
||||
bool cLineBlockTracer::FirstSolidHitTrace(
|
||||
bool LineBlockTracer::FirstSolidHitTrace(
|
||||
cWorld & a_World,
|
||||
const Vector3d & a_Start, const Vector3d & a_End,
|
||||
Vector3d & a_HitCoords,
|
||||
@ -86,7 +237,7 @@ bool cLineBlockTracer::FirstSolidHitTrace(
|
||||
)
|
||||
{
|
||||
class cSolidHitCallbacks:
|
||||
public cCallbacks
|
||||
public BlockTracerCallbacks
|
||||
{
|
||||
public:
|
||||
cSolidHitCallbacks(const Vector3d & a_CBStart, const Vector3d & a_CBEnd, Vector3d & a_CBHitCoords, Vector3i & a_CBHitBlockCoords, eBlockFace & a_CBHitBlockFace):
|
||||
@ -129,218 +280,3 @@ bool cLineBlockTracer::FirstSolidHitTrace(
|
||||
} callbacks(a_Start, a_End, a_HitCoords, a_HitBlockCoords, a_HitBlockFace);
|
||||
return !Trace(a_World, callbacks, a_Start, a_End);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLineBlockTracer::Trace(const Vector3d a_Start, const Vector3d a_End)
|
||||
{
|
||||
// Initialize the member veriables:
|
||||
m_Start = a_Start;
|
||||
m_End = a_End;
|
||||
m_Dir.x = (m_Start.x < m_End.x) ? 1 : -1;
|
||||
m_Dir.y = (m_Start.y < m_End.y) ? 1 : -1;
|
||||
m_Dir.z = (m_Start.z < m_End.z) ? 1 : -1;
|
||||
m_CurrentFace = BLOCK_FACE_NONE;
|
||||
|
||||
// Check the start coords, adjust into the world:
|
||||
if (m_Start.y < 0)
|
||||
{
|
||||
if (m_End.y < 0)
|
||||
{
|
||||
// Nothing to trace
|
||||
m_Callbacks->OnNoMoreHits();
|
||||
return true;
|
||||
}
|
||||
FixStartBelowWorld();
|
||||
m_Callbacks->OnIntoWorld(m_Start);
|
||||
}
|
||||
else if (m_Start.y >= cChunkDef::Height)
|
||||
{
|
||||
if (m_End.y >= cChunkDef::Height)
|
||||
{
|
||||
m_Callbacks->OnNoMoreHits();
|
||||
return true;
|
||||
}
|
||||
FixStartAboveWorld();
|
||||
m_Callbacks->OnIntoWorld(m_Start);
|
||||
}
|
||||
|
||||
m_Current = m_Start.Floor();
|
||||
|
||||
m_Diff = m_End - m_Start;
|
||||
|
||||
// The actual trace is handled with ChunkMapCS locked by calling our ChunkCallback for the specified chunk
|
||||
int BlockX = FloorC(m_Start.x);
|
||||
int BlockZ = FloorC(m_Start.z);
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
|
||||
return m_World->DoWithChunk(ChunkX, ChunkZ, [this](cChunk & a_Chunk) { return ChunkCallback(&a_Chunk); });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cLineBlockTracer::FixStartAboveWorld(void)
|
||||
{
|
||||
// We must set the start Y to less than cChunkDef::Height so that it is considered inside the world later on
|
||||
// Therefore we use an EPS-offset from the height, as small as reasonably possible.
|
||||
const double Height = static_cast<double>(cChunkDef::Height) - 0.00001;
|
||||
CalcXZIntersection(Height, m_Start.x, m_Start.z);
|
||||
m_Start.y = Height;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cLineBlockTracer::FixStartBelowWorld(void)
|
||||
{
|
||||
CalcXZIntersection(0, m_Start.x, m_Start.z);
|
||||
m_Start.y = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cLineBlockTracer::CalcXZIntersection(double a_Y, double & a_IntersectX, double & a_IntersectZ)
|
||||
{
|
||||
double Ratio = (m_Start.y - a_Y) / (m_Start.y - m_End.y);
|
||||
a_IntersectX = m_Start.x + (m_End.x - m_Start.x) * Ratio;
|
||||
a_IntersectZ = m_Start.z + (m_End.z - m_Start.z) * Ratio;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLineBlockTracer::MoveToNextBlock(void)
|
||||
{
|
||||
// Find out which of the current block's walls gets hit by the path:
|
||||
static const double EPS = 0.00001;
|
||||
enum
|
||||
{
|
||||
dirNONE,
|
||||
dirX,
|
||||
dirY,
|
||||
dirZ,
|
||||
} Direction = dirNONE;
|
||||
|
||||
// Calculate the next YZ wall hit:
|
||||
double Coeff = 1;
|
||||
if (std::abs(m_Diff.x) > EPS)
|
||||
{
|
||||
double DestX = (m_Dir.x > 0) ? (m_Current.x + 1) : m_Current.x;
|
||||
double CoeffX = (DestX - m_Start.x) / m_Diff.x;
|
||||
if (CoeffX <= 1) // We need to include equality for the last block in the trace
|
||||
{
|
||||
Coeff = CoeffX;
|
||||
Direction = dirX;
|
||||
}
|
||||
}
|
||||
|
||||
// If the next XZ wall hit is closer, use it instead:
|
||||
if (std::abs(m_Diff.y) > EPS)
|
||||
{
|
||||
double DestY = (m_Dir.y > 0) ? (m_Current.y + 1) : m_Current.y;
|
||||
double CoeffY = (DestY - m_Start.y) / m_Diff.y;
|
||||
if (CoeffY <= Coeff) // We need to include equality for the last block in the trace
|
||||
{
|
||||
Coeff = CoeffY;
|
||||
Direction = dirY;
|
||||
}
|
||||
}
|
||||
|
||||
// If the next XY wall hit is closer, use it instead:
|
||||
if (std::abs(m_Diff.z) > EPS)
|
||||
{
|
||||
double DestZ = (m_Dir.z > 0) ? (m_Current.z + 1) : m_Current.z;
|
||||
double CoeffZ = (DestZ - m_Start.z) / m_Diff.z;
|
||||
if (CoeffZ <= Coeff) // We need to include equality for the last block in the trace
|
||||
{
|
||||
Direction = dirZ;
|
||||
}
|
||||
}
|
||||
|
||||
// Based on the wall hit, adjust the current coords
|
||||
switch (Direction)
|
||||
{
|
||||
case dirX: m_Current.x += m_Dir.x; m_CurrentFace = (m_Dir.x > 0) ? BLOCK_FACE_XM : BLOCK_FACE_XP; break;
|
||||
case dirY: m_Current.y += m_Dir.y; m_CurrentFace = (m_Dir.y > 0) ? BLOCK_FACE_YM : BLOCK_FACE_YP; break;
|
||||
case dirZ: m_Current.z += m_Dir.z; m_CurrentFace = (m_Dir.z > 0) ? BLOCK_FACE_ZM : BLOCK_FACE_ZP; break;
|
||||
case dirNONE: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLineBlockTracer::ChunkCallback(cChunk * a_Chunk)
|
||||
{
|
||||
ASSERT((m_Current.y >= 0) && (m_Current.y < cChunkDef::Height)); // This should be provided by FixStartAboveWorld() / FixStartBelowWorld()
|
||||
|
||||
// This is the actual line tracing loop.
|
||||
for (;;)
|
||||
{
|
||||
// Our caller (DoWithChunk callback) should never give nothing:
|
||||
ASSERT(a_Chunk != nullptr);
|
||||
|
||||
// Move to next block
|
||||
if (!MoveToNextBlock())
|
||||
{
|
||||
// We've reached the end
|
||||
m_Callbacks->OnNoMoreHits();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((m_Current.y < 0) || (m_Current.y >= cChunkDef::Height))
|
||||
{
|
||||
// We've gone out of the world, that's the end of this trace
|
||||
double IntersectX, IntersectZ;
|
||||
CalcXZIntersection(m_Current.y, IntersectX, IntersectZ);
|
||||
if (m_Callbacks->OnOutOfWorld({IntersectX, double(m_Current.y), IntersectZ}))
|
||||
{
|
||||
// The callback terminated the trace
|
||||
return false;
|
||||
}
|
||||
m_Callbacks->OnNoMoreHits();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update the current chunk
|
||||
a_Chunk = a_Chunk->GetNeighborChunk(m_Current.x, m_Current.z);
|
||||
if (a_Chunk == nullptr)
|
||||
{
|
||||
m_Callbacks->OnNoChunk();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Report the current block through the callbacks:
|
||||
if (a_Chunk->IsValid())
|
||||
{
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
int RelX = m_Current.x - a_Chunk->GetPosX() * cChunkDef::Width;
|
||||
int RelZ = m_Current.z - a_Chunk->GetPosZ() * cChunkDef::Width;
|
||||
a_Chunk->GetBlockTypeMeta(RelX, m_Current.y, RelZ, BlockType, BlockMeta);
|
||||
if (m_Callbacks->OnNextBlock(m_Current, BlockType, BlockMeta, m_CurrentFace))
|
||||
{
|
||||
// The callback terminated the trace
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_Callbacks->OnNextBlockNoData(m_Current, m_CurrentFace))
|
||||
{
|
||||
// The callback terminated the trace
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
// LineBlockTracer.h
|
||||
|
||||
// Declares the cLineBlockTracer class representing a cBlockTracer that traces along a straight line between two points
|
||||
// Declares the LineBlockTracer namespace representing a tracer that visits every block along a straight line between two points
|
||||
|
||||
|
||||
|
||||
@ -15,47 +15,36 @@
|
||||
|
||||
|
||||
|
||||
// fwd: Chunk.h
|
||||
class cChunk;
|
||||
class cWorld;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cLineBlockTracer:
|
||||
public cBlockTracer
|
||||
namespace LineBlockTracer
|
||||
{
|
||||
using Super = cBlockTracer;
|
||||
|
||||
public:
|
||||
|
||||
enum eLineOfSight
|
||||
/* Bit flags used for LineOfSightTrace's Sight parameter. */
|
||||
enum LineOfSight
|
||||
{
|
||||
// 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
|
||||
Air = 1, // Can see through air.
|
||||
Water = 2, // Can see through water.
|
||||
Lava = 4, // Can see through lava.
|
||||
|
||||
// Common combinations:
|
||||
losAirWaterLava = losAir | losWater | losLava,
|
||||
losAirWater = losAir | losWater,
|
||||
AirWaterLava = Air | Water | Lava,
|
||||
AirWater = Air | Water,
|
||||
};
|
||||
|
||||
|
||||
cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks);
|
||||
/** Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) */
|
||||
bool Trace(const cChunk & a_Chunk, BlockTracerCallbacks & a_Callbacks, Vector3d a_Start, Vector3d a_End);
|
||||
|
||||
/** Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) */
|
||||
bool Trace(Vector3d a_Start, Vector3d a_End);
|
||||
|
||||
|
||||
// Utility functions for simple one-line usage:
|
||||
|
||||
/** 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);
|
||||
bool Trace(cWorld & a_World, BlockTracerCallbacks & 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);
|
||||
bool LineOfSightTrace(cWorld & a_World, const Vector3d & a_Start, const Vector3d & a_End, LineOfSight 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.
|
||||
@ -63,48 +52,11 @@ public:
|
||||
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(
|
||||
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 */
|
||||
Vector3d m_Start;
|
||||
|
||||
/** The end point of the trace */
|
||||
Vector3d m_End;
|
||||
|
||||
/** The difference in coords, End - Start */
|
||||
Vector3d m_Diff;
|
||||
|
||||
/** The increment at which the block coords are going from Start to End; either +1 or -1 */
|
||||
Vector3i m_Dir;
|
||||
|
||||
/** The current block */
|
||||
Vector3i m_Current;
|
||||
|
||||
/** The face through which the current block has been entered */
|
||||
eBlockFace m_CurrentFace;
|
||||
|
||||
|
||||
/** Adjusts the start point above the world to just at the world's top */
|
||||
void FixStartAboveWorld(void);
|
||||
|
||||
/** Adjusts the start point below the world to just at the world's bottom */
|
||||
void FixStartBelowWorld(void);
|
||||
|
||||
/** Calculates the XZ coords of an intersection with the specified Yconst plane; assumes that such an intersection exists */
|
||||
void CalcXZIntersection(double a_Y, double & a_IntersectX, double & a_IntersectZ);
|
||||
|
||||
/** Moves m_Current to the next block on the line; returns false if no move is possible (reached the end) */
|
||||
bool MoveToNextBlock(void);
|
||||
|
||||
bool ChunkCallback(cChunk * a_Chunk);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "Generating/ComposableGenerator.h"
|
||||
#include "SetChunkData.h"
|
||||
#include "DeadlockDetect.h"
|
||||
#include "LineBlockTracer.h"
|
||||
#include "Physics/Tracers/LineBlockTracer.h"
|
||||
#include "UUID.h"
|
||||
#include "BlockInServerPluginInterface.h"
|
||||
|
||||
@ -1844,7 +1844,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, Vector3d
|
||||
|
||||
UInt32 cWorld::SpawnItemPickup(Vector3d a_Position, cItem && a_Item, Vector3d a_Speed, cTickTime a_CollectionDelay, cTickTime a_Lifetime, bool a_CanCombine)
|
||||
{
|
||||
auto Pickup = std::make_unique<cPickup>(a_Position, std::move(a_Item), a_Speed, a_CollectionDelay, a_Lifetime);
|
||||
auto Pickup = std::make_unique<cPickup>(a_Position, std::move(a_Item), a_Speed, a_CollectionDelay, a_Lifetime, a_CanCombine);
|
||||
auto PickupPtr = Pickup.get();
|
||||
|
||||
if (!PickupPtr->Initialize(std::move(Pickup), *this))
|
||||
@ -2413,7 +2413,7 @@ bool cWorld::DoWithNearestPlayer(Vector3d a_Pos, double a_RangeLimit, cPlayerLis
|
||||
// Check LineOfSight, if requested:
|
||||
if (
|
||||
a_CheckLineOfSight &&
|
||||
!cLineBlockTracer::LineOfSightTrace(*this, a_Pos, Pos, cLineBlockTracer::losAirWater)
|
||||
!LineBlockTracer::LineOfSightTrace(*this, a_Pos, Pos, LineBlockTracer::LineOfSight::AirWater)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
|
@ -1942,7 +1942,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
|
||||
return;
|
||||
}
|
||||
|
||||
auto Pickup = std::make_unique<cPickup>(Vector3d(), std::move(Item), Vector3d(), 0_tick, 0_tick); // Pickup delay loaded later
|
||||
auto Pickup = std::make_unique<cPickup>(Vector3d(), std::move(Item), Vector3d(), 0_tick, 0_tick, true); // Pickup delay loaded later
|
||||
if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user