First attempt at implementing a cLineBlockTracer class
Not yet tested, will probably have lots of bugs, if it is at all usable.
This commit is contained in:
parent
106308796d
commit
5fe7008966
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<VisualStudioProject
|
<VisualStudioProject
|
||||||
ProjectType="Visual C++"
|
ProjectType="Visual C++"
|
||||||
Version="9,00"
|
Version="9,00"
|
||||||
@ -306,6 +306,10 @@
|
|||||||
RelativePath="..\source\BlockID.h"
|
RelativePath="..\source\BlockID.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\BlockTracer.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\ByteBuffer.cpp"
|
RelativePath="..\source\ByteBuffer.cpp"
|
||||||
>
|
>
|
||||||
@ -545,6 +549,14 @@
|
|||||||
RelativePath="..\source\LinearUpscale.h"
|
RelativePath="..\source\LinearUpscale.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\LineBlockTracer.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\LineBlockTracer.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\Log.cpp"
|
RelativePath="..\source\Log.cpp"
|
||||||
>
|
>
|
||||||
|
104
source/BlockTracer.h
Normal file
104
source/BlockTracer.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
|
||||||
|
// BlockTracer.h
|
||||||
|
|
||||||
|
// Declares the classes common for all blocktracers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd: World.h
|
||||||
|
class cWorld;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cBlockTracer abstract
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The callback class is used to notify the caller of individual events that are being traced.
|
||||||
|
*/
|
||||||
|
class cCallbacks abstract
|
||||||
|
{
|
||||||
|
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) = 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(int a_BlockX, int a_BlockY, int a_BlockZ) {}
|
||||||
|
|
||||||
|
/** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= 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(double a_BlockX, double a_BlockY, double a_BlockZ) {}
|
||||||
|
|
||||||
|
/** Called when the path goes into the world, from either below (a_BlockY < 0) or above (a_BlockY >= 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(double a_BlockX, double a_BlockY, double a_BlockZ) {}
|
||||||
|
|
||||||
|
/** 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Sets new world, returns the old one. Note that both need to be valid
|
||||||
|
cWorld & SetWorld(cWorld & a_World)
|
||||||
|
{
|
||||||
|
cWorld & Old = *m_World;
|
||||||
|
m_World = &a_World;
|
||||||
|
return Old;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Sets new callbacks, returns the old ones. Note that both need to be valid
|
||||||
|
cCallbacks & SetCallbacks(cCallbacks & a_NewCallbacks)
|
||||||
|
{
|
||||||
|
cCallbacks & Old = *m_Callbacks;
|
||||||
|
m_Callbacks = &a_NewCallbacks;
|
||||||
|
return Old;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// The world upon which to operate
|
||||||
|
cWorld * m_World;
|
||||||
|
|
||||||
|
/// The callback to use for reporting
|
||||||
|
cCallbacks * m_Callbacks;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
258
source/LineBlockTracer.cpp
Normal file
258
source/LineBlockTracer.cpp
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
|
||||||
|
// LineBlockTracer.cpp
|
||||||
|
|
||||||
|
// Implements the cLineBlockTracer class representing a cBlockTracer that traces along a straight line between two points
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "LineBlockTracer.h"
|
||||||
|
#include "Vector3d.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "Chunk.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cLineBlockTracer::cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) :
|
||||||
|
super(a_World, a_Callbacks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cLineBlockTracer::Trace(cWorld & a_World, cBlockTracer::cCallbacks & a_Callbacks, const Vector3d & a_Start, const Vector3d & a_End)
|
||||||
|
{
|
||||||
|
cLineBlockTracer Tracer(a_World, a_Callbacks);
|
||||||
|
return Tracer.Trace(a_Start.x, a_Start.y, a_Start.z, a_End.x, a_End.y, a_End.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
return Tracer.Trace(a_StartX, a_StartY, a_StartZ, a_EndX, a_EndY, a_EndZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ)
|
||||||
|
{
|
||||||
|
// Initialize the member veriables:
|
||||||
|
m_StartX = a_StartX;
|
||||||
|
m_StartY = a_StartY;
|
||||||
|
m_StartZ = a_StartZ;
|
||||||
|
m_EndX = a_EndX;
|
||||||
|
m_EndY = a_EndY;
|
||||||
|
m_EndZ = a_EndZ;
|
||||||
|
m_DirX = (m_StartX < m_EndX) ? 1 : -1;
|
||||||
|
m_DirY = (m_StartY < m_EndY) ? 1 : -1;
|
||||||
|
m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1;
|
||||||
|
|
||||||
|
// Check the start coords, adjust into the world:
|
||||||
|
if (m_StartY < 0)
|
||||||
|
{
|
||||||
|
if (m_EndY < 0)
|
||||||
|
{
|
||||||
|
// Nothing to trace
|
||||||
|
m_Callbacks->OnNoMoreHits();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
FixStartBelowWorld();
|
||||||
|
m_Callbacks->OnIntoWorld(m_StartX, m_StartY, m_StartZ);
|
||||||
|
}
|
||||||
|
else if (m_StartY >= cChunkDef::Height)
|
||||||
|
{
|
||||||
|
if (m_EndY >= cChunkDef::Height)
|
||||||
|
{
|
||||||
|
m_Callbacks->OnNoMoreHits();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
FixStartAboveWorld();
|
||||||
|
m_Callbacks->OnIntoWorld(m_StartX, m_StartY, m_StartZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CurrentX = (int)floor(m_StartX);
|
||||||
|
m_CurrentY = (int)floor(m_StartY);
|
||||||
|
m_CurrentZ = (int)floor(m_StartZ);
|
||||||
|
|
||||||
|
m_DiffX = m_EndX - m_StartX;
|
||||||
|
m_DiffY = m_EndY - m_StartY;
|
||||||
|
m_DiffZ = m_EndZ - m_StartZ;
|
||||||
|
|
||||||
|
// The actual trace is handled with ChunkMapCS locked by calling our Item() for the specified chunk
|
||||||
|
int BlockX = (int)floor(m_StartX);
|
||||||
|
int BlockZ = (int)floor(m_StartZ);
|
||||||
|
int ChunkX, ChunkZ;
|
||||||
|
cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
|
||||||
|
return m_World->DoWithChunk(ChunkX, ChunkZ, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 = (double)cChunkDef::Height - 0.00001;
|
||||||
|
CalcXZIntersection(Height, m_StartX, m_StartZ);
|
||||||
|
m_StartY = Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLineBlockTracer::FixStartBelowWorld(void)
|
||||||
|
{
|
||||||
|
CalcXZIntersection(0, m_StartX, m_StartZ);
|
||||||
|
m_StartY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLineBlockTracer::CalcXZIntersection(double a_Y, double & a_IntersectX, double & a_IntersectZ)
|
||||||
|
{
|
||||||
|
double Ratio = (m_StartY - a_Y) / (m_StartY - m_EndY);
|
||||||
|
a_IntersectX = m_StartX + (m_EndX - m_StartX) * Ratio;
|
||||||
|
a_IntersectZ = m_StartZ + (m_EndZ - m_StartZ) * 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;
|
||||||
|
double Coeff = 1;
|
||||||
|
enum eDirection
|
||||||
|
{
|
||||||
|
dirNONE,
|
||||||
|
dirX,
|
||||||
|
dirY,
|
||||||
|
dirZ,
|
||||||
|
} Direction = dirNONE;
|
||||||
|
if (abs(m_DiffX) > EPS)
|
||||||
|
{
|
||||||
|
double DestX = (m_DirX > 0) ? (m_CurrentX + 1) : m_CurrentX;
|
||||||
|
Coeff = (m_EndX - DestX) / m_DiffX;
|
||||||
|
Direction = dirX;
|
||||||
|
}
|
||||||
|
if (abs(m_DiffY) > EPS)
|
||||||
|
{
|
||||||
|
double DestY = (m_DirY > 0) ? (m_CurrentY + 1) : m_CurrentY;
|
||||||
|
double CoeffY = (DestY - m_StartY) / m_DiffY;
|
||||||
|
if (CoeffY < Coeff)
|
||||||
|
{
|
||||||
|
Coeff = CoeffY;
|
||||||
|
Direction = dirY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (abs(m_DiffZ) > EPS)
|
||||||
|
{
|
||||||
|
double DestZ = (m_DirZ > 0) ? (m_CurrentZ + 1) : m_CurrentZ;
|
||||||
|
double CoeffZ = (DestZ - m_StartZ) / m_DiffZ;
|
||||||
|
if (CoeffZ < Coeff)
|
||||||
|
{
|
||||||
|
Coeff = CoeffZ;
|
||||||
|
Direction = dirZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on the wall hit, adjust the current coords
|
||||||
|
switch (Direction)
|
||||||
|
{
|
||||||
|
case dirX: m_CurrentX += m_DirX; break;
|
||||||
|
case dirY: m_CurrentY += m_DirY; break;
|
||||||
|
case dirZ: m_CurrentZ += m_DirZ; break;
|
||||||
|
case dirNONE: return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cLineBlockTracer::Item(cChunk * a_Chunk)
|
||||||
|
{
|
||||||
|
ASSERT((m_CurrentY >= 0) && (m_CurrentY < cChunkDef::Height)); // This should be provided by FixStartAboveWorld() / FixStartBelowWorld()
|
||||||
|
|
||||||
|
// This is the actual line tracing loop.
|
||||||
|
bool Finished = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Report the current block through the callbacks:
|
||||||
|
if (a_Chunk == NULL)
|
||||||
|
{
|
||||||
|
m_Callbacks->OnNoChunk();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a_Chunk->IsValid())
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockType;
|
||||||
|
NIBBLETYPE BlockMeta;
|
||||||
|
int RelX = FAST_FLOOR_DIV(m_CurrentX, cChunkDef::Width);
|
||||||
|
int RelZ = FAST_FLOOR_DIV(m_CurrentZ, cChunkDef::Width);
|
||||||
|
a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta);
|
||||||
|
if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta))
|
||||||
|
{
|
||||||
|
// The callback terminated the trace
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ))
|
||||||
|
{
|
||||||
|
// The callback terminated the trace
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to next block
|
||||||
|
if (!MoveToNextBlock())
|
||||||
|
{
|
||||||
|
// We've reached the end
|
||||||
|
m_Callbacks->OnNoMoreHits();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the current chunk
|
||||||
|
if (a_Chunk != NULL)
|
||||||
|
{
|
||||||
|
a_Chunk = a_Chunk->GetNeighborChunk(m_CurrentX, m_CurrentZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_CurrentY < 0) || (m_CurrentY >= cChunkDef::Height))
|
||||||
|
{
|
||||||
|
// We've gone out of the world, that's the end of this trace
|
||||||
|
double IntersectX, IntersectZ;
|
||||||
|
CalcXZIntersection(m_CurrentY, IntersectX, IntersectZ);
|
||||||
|
if (m_Callbacks->OnOutOfWorld(IntersectX, m_CurrentY, IntersectZ))
|
||||||
|
{
|
||||||
|
// The callback terminated the trace
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_Callbacks->OnNoMoreHits();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
84
source/LineBlockTracer.h
Normal file
84
source/LineBlockTracer.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
// LineBlockTracer.h
|
||||||
|
|
||||||
|
// Declares the cLineBlockTracer class representing a cBlockTracer that traces along a straight line between two points
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BlockTracer.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd: Chunk.h
|
||||||
|
class cChunk;
|
||||||
|
|
||||||
|
// fwd: cChunkMap.h
|
||||||
|
typedef cItemCallback<cChunk> cChunkCallback;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cLineBlockTracer :
|
||||||
|
public cBlockTracer,
|
||||||
|
public cChunkCallback
|
||||||
|
{
|
||||||
|
typedef cBlockTracer super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
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(double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ);
|
||||||
|
|
||||||
|
// 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, double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ);
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// The start point of the trace
|
||||||
|
double m_StartX, m_StartY, m_StartZ;
|
||||||
|
|
||||||
|
// The end point of the trace
|
||||||
|
double m_EndX, m_EndY, m_EndZ;
|
||||||
|
|
||||||
|
// The difference in coords, End - Start
|
||||||
|
double m_DiffX, m_DiffY, m_DiffZ;
|
||||||
|
|
||||||
|
// The increment at which the block coords are going from Start to End; either +1 or -1
|
||||||
|
int m_DirX, m_DirY, m_DirZ;
|
||||||
|
|
||||||
|
// The current block
|
||||||
|
int m_CurrentX, m_CurrentY, m_CurrentZ;
|
||||||
|
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
// cChunkCallback overrides:
|
||||||
|
virtual bool Item(cChunk * a_Chunk) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user