1
0

Merged in the Projectiles branch.

Although the projectiles are not yet finished, the branch has several bugfixes that are needed in master as well.
This commit is contained in:
madmaxoft 2013-08-30 14:32:07 +02:00
commit c28ccdc9d5
35 changed files with 1530 additions and 381 deletions

View File

@ -45,6 +45,7 @@ function Initialize(Plugin)
PluginManager:BindCommand("/spidey", "debuggers", HandleSpideyCmd, "- Shoots a line of web blocks until it hits non-air"); PluginManager:BindCommand("/spidey", "debuggers", HandleSpideyCmd, "- Shoots a line of web blocks until it hits non-air");
PluginManager:BindCommand("/ench", "debuggers", HandleEnchCmd, "- Provides an instant dummy enchantment window"); PluginManager:BindCommand("/ench", "debuggers", HandleEnchCmd, "- Provides an instant dummy enchantment window");
PluginManager:BindCommand("/fs", "debuggers", HandleFoodStatsCmd, "- Turns regular foodstats message on or off"); PluginManager:BindCommand("/fs", "debuggers", HandleFoodStatsCmd, "- Turns regular foodstats message on or off");
PluginManager:BindCommand("/arr", "debuggers", HandleArrowCmd, "- Creates an arrow going away from the player");
-- Enable the following line for BlockArea / Generator interface testing: -- Enable the following line for BlockArea / Generator interface testing:
-- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED);
@ -794,6 +795,7 @@ function HandleEnchCmd(a_Split, a_Player)
Wnd:SetProperty(0, 10); Wnd:SetProperty(0, 10);
Wnd:SetProperty(1, 15); Wnd:SetProperty(1, 15);
Wnd:SetProperty(2, 25); Wnd:SetProperty(2, 25);
return true;
end end
@ -802,6 +804,22 @@ end
function HandleFoodStatsCmd(a_Split, a_Player) function HandleFoodStatsCmd(a_Split, a_Player)
g_ShowFoodStats = not(g_ShowFoodStats); g_ShowFoodStats = not(g_ShowFoodStats);
return true;
end
function HandleArrowCmd(a_Split, a_Player)
local World = a_Player:GetWorld();
local Pos = a_Player:GetEyePosition();
local Speed = a_Player:GetLookVector();
Speed:Normalize();
Pos = Pos + Speed;
World:CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity.pkArrow, a_Player, Speed * 10);
return true;
end end

View File

@ -1159,6 +1159,10 @@
RelativePath="..\source\Entities\Player.h" RelativePath="..\source\Entities\Player.h"
> >
</File> </File>
<File
RelativePath="..\source\Entities\ProjectileEntity.cpp"
>
</File>
<File <File
RelativePath="..\source\Entities\ProjectileEntity.h" RelativePath="..\source\Entities\ProjectileEntity.h"
> >
@ -2235,6 +2239,10 @@
RelativePath="..\source\items\ItemBed.h" RelativePath="..\source\items\ItemBed.h"
> >
</File> </File>
<File
RelativePath="..\source\Items\ItemBow.h"
>
</File>
<File <File
RelativePath="..\source\Items\ItemBrewingStand.h" RelativePath="..\source\Items\ItemBrewingStand.h"
> >

View File

@ -27,6 +27,8 @@ $cfile "ClientHandle.h"
$cfile "Entities/Entity.h" $cfile "Entities/Entity.h"
$cfile "Entities/Pawn.h" $cfile "Entities/Pawn.h"
$cfile "Entities/Player.h" $cfile "Entities/Player.h"
$cfile "Entities/Pickup.h"
$cfile "Entities/ProjectileEntity.h"
$cfile "PluginManager.h" $cfile "PluginManager.h"
$cfile "Plugin.h" $cfile "Plugin.h"
$cfile "PluginLua.h" $cfile "PluginLua.h"
@ -45,7 +47,6 @@ $cfile "BlockEntities/DropperEntity.h"
$cfile "BlockEntities/FurnaceEntity.h" $cfile "BlockEntities/FurnaceEntity.h"
$cfile "WebAdmin.h" $cfile "WebAdmin.h"
$cfile "WebPlugin.h" $cfile "WebPlugin.h"
$cfile "Entities/Pickup.h"
$cfile "Root.h" $cfile "Root.h"
$cfile "Vector3f.h" $cfile "Vector3f.h"
$cfile "Vector3d.h" $cfile "Vector3d.h"

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* /*
** Lua binding: AllToLua ** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 08/27/13 08:55:57. ** Generated automatically by tolua++-1.0.92 on 08/30/13 14:30:25.
*/ */
/* Exported function */ /* Exported function */

View File

@ -367,7 +367,9 @@ enum ENUM_ITEM_ID
// Keep these two as the last values of the disc list, without a number - they will get their correct number assigned automagically by C++ // Keep these two as the last values of the disc list, without a number - they will get their correct number assigned automagically by C++
// IsValidItem() depends on this! // IsValidItem() depends on this!
E_ITEM_LAST_DISC_PLUS_ONE, ///< Useless, really, but needs to be present for the following value E_ITEM_LAST_DISC_PLUS_ONE, ///< Useless, really, but needs to be present for the following value
E_ITEM_LAST_DISC = E_ITEM_LAST_DISC_PLUS_ONE - 1 ///< Maximum disc itemtype number used E_ITEM_LAST_DISC = E_ITEM_LAST_DISC_PLUS_ONE - 1, ///< Maximum disc itemtype number used
E_ITEM_LAST = E_ITEM_LAST_DISC, ///< Maximum valid ItemType
}; };

View File

@ -31,12 +31,12 @@ public:
/** Called on each block encountered along the path, including the first block (path start) /** Called on each block encountered along the path, including the first block (path start)
When this callback returns true, the tracing is aborted. When this callback returns true, the tracing is aborted.
*/ */
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) = 0;
/** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded /** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded
When this callback returns true, the tracing is aborted. When this callback returns true, the tracing is aborted.
*/ */
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) { return false; } virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) { return false; }
/** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) /** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height)
The coords specify the exact point at which the path exited the world. The coords specify the exact point at which the path exited the world.

View File

@ -576,8 +576,8 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
// A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch) // A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
return; return;
} }
ItemHandler->OnItemShoot(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
} }
LOGINFO("%s: Status SHOOT not implemented", __FUNCTION__);
return; return;
} }
@ -790,16 +790,16 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c
BLOCKTYPE BlockType; BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta; NIBBLETYPE BlockMeta;
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
cBlockHandler * Handler = cBlockHandler::GetBlockHandler(BlockType); cBlockHandler * BlockHandler = cBlockHandler::GetBlockHandler(BlockType);
if (Handler->IsUseable() && !m_Player->IsCrouched()) if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
{ {
if (PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta)) if (PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
{ {
// A plugin doesn't agree with using the block, abort // A plugin doesn't agree with using the block, abort
return; return;
} }
Handler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); BlockHandler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta); PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
return; return;
} }

View File

@ -144,6 +144,10 @@ bool cEntity::Initialize(cWorld * a_World)
m_World->AddEntity(this); m_World->AddEntity(this);
cPluginManager::Get()->CallHookSpawnedEntity(*a_World, *this); cPluginManager::Get()->CallHookSpawnedEntity(*a_World, *this);
// Spawn the entity on the clients:
a_World->BroadcastSpawnEntity(*this);
return true; return true;
} }
@ -477,7 +481,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{ {
// TODO Add collision detection with entities. // TODO Add collision detection with entities.
a_Dt /= 1000; a_Dt /= 1000; // Convert from msec to sec
Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ()); Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ());
Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ()); Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ());
int BlockX = (int) floor(NextPos.x); int BlockX = (int) floor(NextPos.x);
@ -493,7 +497,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
} }
// Make sure we got the correct chunk and a valid one. No one ever knows... // Make sure we got the correct chunk and a valid one. No one ever knows...
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX,BlockZ); cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
if (NextChunk != NULL) if (NextChunk != NULL)
{ {
int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width); int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
@ -512,11 +516,12 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
} }
else else
{ {
//Push out entity. // Push out entity.
m_bOnGround = true; m_bOnGround = true;
NextPos.y += 0.2; NextPos.y += 0.2;
LOGD("Entity #%d (%s) is inside a block at {%d,%d,%d}", LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
m_UniqueID, GetClass(), BlockX, BlockY, BlockZ); m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
);
} }
if (!m_bOnGround) if (!m_bOnGround)
@ -524,34 +529,40 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
float fallspeed; float fallspeed;
if (IsBlockWater(BlockIn)) if (IsBlockWater(BlockIn))
{ {
fallspeed = -3.0f * a_Dt; //Fall slower in water. fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
} }
else if (BlockIn == E_BLOCK_COBWEB) else if (BlockIn == E_BLOCK_COBWEB)
{ {
NextSpeed.y *= 0.05; //Reduce overall falling speed NextSpeed.y *= 0.05; // Reduce overall falling speed
fallspeed = 0; //No falling. fallspeed = 0; // No falling.
} }
else else
{ {
//Normal gravity // Normal gravity
fallspeed = m_Gravity * a_Dt; fallspeed = m_Gravity * a_Dt;
} }
NextSpeed.y += fallspeed; NextSpeed.y += fallspeed;
} }
else else
{ {
//Friction // Friction
if (NextSpeed.SqrLength() > 0.0004f) if (NextSpeed.SqrLength() > 0.0004f)
{ {
NextSpeed.x *= 0.7f/(1+a_Dt); NextSpeed.x *= 0.7f / (1 + a_Dt);
if ( fabs(NextSpeed.x) < 0.05 ) NextSpeed.x = 0; if (fabs(NextSpeed.x) < 0.05)
NextSpeed.z *= 0.7f/(1+a_Dt); {
if ( fabs(NextSpeed.z) < 0.05 ) NextSpeed.z = 0; NextSpeed.x = 0;
}
NextSpeed.z *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.z) < 0.05)
{
NextSpeed.z = 0;
}
} }
} }
//Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
//might have different speed modifiers according to terrain. // might have different speed modifiers according to terrain.
if (BlockIn == E_BLOCK_COBWEB) if (BlockIn == E_BLOCK_COBWEB)
{ {
NextSpeed.x *= 0.25; NextSpeed.x *= 0.25;
@ -1028,9 +1039,9 @@ void cEntity::SetMass(double a_Mass)
} }
else else
{ {
//Make sure that mass is not zero. 1g is the default because we // Make sure that mass is not zero. 1g is the default because we
//have to choose a number. It's perfectly legal to have a mass // have to choose a number. It's perfectly legal to have a mass
//less than 1g as long as is NOT equal or less than zero. // less than 1g as long as is NOT equal or less than zero.
m_Mass = 0.001; m_Mass = 0.001;
} }
} }

View File

@ -90,12 +90,13 @@ public:
etPlayer, etPlayer,
etPickup, etPickup,
etMonster, etMonster,
etMob = etMonster, // DEPRECATED, use etMonster instead!
etFallingBlock, etFallingBlock,
etMinecart, etMinecart,
etTNT, etTNT,
etProjectile,
// DEPRECATED older constants, left over for compatibility reasons (plugins) // DEPRECATED older constants, left over for compatibility reasons (plugins)
etMob = etMonster, // DEPRECATED, use etMonster instead!
eEntityType_Entity = etEntity, eEntityType_Entity = etEntity,
eEntityType_Player = etPlayer, eEntityType_Player = etPlayer,
eEntityType_Pickup = etPickup, eEntityType_Pickup = etPickup,
@ -162,7 +163,7 @@ public:
void SetPosY (double a_PosY); void SetPosY (double a_PosY);
void SetPosZ (double a_PosZ); void SetPosZ (double a_PosZ);
void SetPosition(double a_PosX, double a_PosY, double a_PosZ); void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x,a_Pos.y,a_Pos.z);} void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); }
void SetRot (const Vector3f & a_Rot); void SetRot (const Vector3f & a_Rot);
void SetRotation(double a_Rotation); void SetRotation(double a_Rotation);
void SetPitch (double a_Pitch); void SetPitch (double a_Pitch);

View File

@ -22,20 +22,6 @@ cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_Block
bool cFallingBlock::Initialize(cWorld * a_World)
{
if (super::Initialize(a_World))
{
a_World->BroadcastSpawnEntity(*this);
return true;
}
return false;
}
void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle) void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
{ {
a_ClientHandle.SendSpawnFallingBlock(*this); a_ClientHandle.SendSpawnFallingBlock(*this);

View File

@ -29,7 +29,6 @@ public:
NIBBLETYPE GetBlockMeta(void) const { return m_BlockMeta; } NIBBLETYPE GetBlockMeta(void) const { return m_BlockMeta; }
// cEntity overrides: // cEntity overrides:
virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override;

View File

@ -22,20 +22,6 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
bool cMinecart::Initialize(cWorld * a_World)
{
if (super::Initialize(a_World))
{
a_World->BroadcastSpawnEntity(*this);
return true;
}
return false;
}
void cMinecart::SpawnOn(cClientHandle & a_ClientHandle) void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
{ {
char Type = 0; char Type = 0;

View File

@ -35,7 +35,6 @@ public:
} ; } ;
// cEntity overrides: // cEntity overrides:
virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override;

View File

@ -40,20 +40,6 @@ cPickup::cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem
bool cPickup::Initialize(cWorld * a_World)
{
if (super::Initialize(a_World))
{
a_World->BroadcastSpawnEntity(*this);
return true;
}
return false;
}
void cPickup::SpawnOn(cClientHandle & a_Client) void cPickup::SpawnOn(cClientHandle & a_Client)
{ {
a_Client.SendPickupSpawn(*this); a_Client.SendPickupSpawn(*this);

View File

@ -26,8 +26,6 @@ public:
cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem & a_Item, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem & a_Item, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export
virtual bool Initialize(cWorld * a_World) override;
cItem & GetItem(void) {return m_Item; } // tolua_export cItem & GetItem(void) {return m_Item; } // tolua_export
const cItem & GetItem(void) const {return m_Item; } const cItem & GetItem(void) const {return m_Item; }

View File

@ -64,6 +64,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_IsSwimming(false) , m_IsSwimming(false)
, m_IsSubmerged(false) , m_IsSubmerged(false)
, m_EatingFinishTick(-1) , m_EatingFinishTick(-1)
, m_IsChargingBow(false)
, m_BowCharge(0)
{ {
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(), a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
@ -214,6 +216,13 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
// Handle air drowning stuff // Handle air drowning stuff
HandleAir(); HandleAir();
// Handle charging the bow:
if (m_IsChargingBow)
{
m_BowCharge += 1;
LOGD("Player \"%s\" charging bow: %d", m_PlayerName.c_str(), m_BowCharge);
}
if (m_bDirtyPosition) if (m_bDirtyPosition)
{ {
// Apply food exhaustion from movement: // Apply food exhaustion from movement:
@ -253,6 +262,41 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
void cPlayer::StartChargingBow(void)
{
LOGD("Player \"%s\" started charging their bow", m_PlayerName.c_str());
m_IsChargingBow = true;
m_BowCharge = 0;
}
int cPlayer::FinishChargingBow(void)
{
LOGD("Player \"%s\" finished charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
int res = m_BowCharge;
m_IsChargingBow = false;
m_BowCharge = 0;
return res;
}
void cPlayer::CancelChargingBow(void)
{
LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
m_IsChargingBow = false;
m_BowCharge = 0;
}
void cPlayer::SetTouchGround(bool a_bTouchGround) void cPlayer::SetTouchGround(bool a_bTouchGround)
{ {
// If just // If just

View File

@ -63,6 +63,18 @@ public:
/// Returns the currently equipped boots; empty item if none /// Returns the currently equipped boots; empty item if none
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); } virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
/// Starts charging the equipped bow
void StartChargingBow(void);
/// Finishes charging the current bow. Returns the number of ticks for which the bow has been charged
int FinishChargingBow(void);
/// Cancels the current bow charging
void CancelChargingBow(void);
/// Returns true if the player is currently charging the bow
bool IsChargingBox(void) const { return m_IsChargingBow; }
void SetTouchGround( bool a_bTouchGround ); void SetTouchGround( bool a_bTouchGround );
inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; } inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; }
double GetEyeHeight(void) const; // tolua_export double GetEyeHeight(void) const; // tolua_export
@ -352,6 +364,9 @@ protected:
/// The world tick in which eating will be finished. -1 if not eating /// The world tick in which eating will be finished. -1 if not eating
Int64 m_EatingFinishTick; Int64 m_EatingFinishTick;
bool m_IsChargingBow;
int m_BowCharge;
virtual void Destroyed(void); virtual void Destroyed(void);
/// Filters out damage for creative mode /// Filters out damage for creative mode

View File

@ -0,0 +1,296 @@
// ProjectileEntity.cpp
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
#include "Globals.h"
#include "ProjectileEntity.h"
#include "../ClientHandle.h"
#include "Player.h"
#include "../LineBlockTracer.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProjectileTracerCallback:
class cProjectileTracerCallback :
public cBlockTracer::cCallbacks
{
public:
cProjectileTracerCallback(cProjectileEntity * a_Projectile) :
m_Projectile(a_Projectile)
{
}
protected:
cProjectileEntity * m_Projectile;
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{
if (g_BlockIsSolid[a_BlockType])
{
// The projectile hit a solid block
m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace);
return true;
}
// Convey some special effects from special blocks:
switch (a_BlockType)
{
case E_BLOCK_LAVA:
case E_BLOCK_STATIONARY_LAVA:
{
m_Projectile->StartBurning(30);
break;
}
case E_BLOCK_WATER:
case E_BLOCK_STATIONARY_WATER:
{
m_Projectile->StopBurning();
break;
}
} // switch (a_BlockType)
// Continue tracing
return false;
}
} ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProjectileEntity:
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) :
super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height),
m_ProjectileKind(a_Kind),
m_Creator(a_Creator),
m_IsInGround(false)
{
}
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) :
super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height),
m_ProjectileKind(a_Kind),
m_Creator(a_Creator),
m_IsInGround(false)
{
SetSpeed(a_Speed);
}
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed)
{
Vector3d Speed;
if (a_Speed != NULL)
{
Speed = *a_Speed;
}
switch (a_Kind)
{
case pkArrow: return new cArrowEntity(a_Creator, a_X, a_Y, a_Z, Speed);
// TODO: the rest
}
LOGWARNING("%s: Unknown kind: %d", __FUNCTION__, a_Kind);
return NULL;
}
void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
{
// TODO: Set proper position based on what face was hit
switch (a_BlockFace)
{
case BLOCK_FACE_TOP: SetPosition(0.5 + a_BlockX, 1.0 + a_BlockY, 0.5 + a_BlockZ); break;
case BLOCK_FACE_BOTTOM: SetPosition(0.5 + a_BlockX, a_BlockY, 0.5 + a_BlockZ); break;
case BLOCK_FACE_EAST: SetPosition( a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
case BLOCK_FACE_WEST: SetPosition(1.0 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
case BLOCK_FACE_NORTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 1.0 + a_BlockZ); break;
case BLOCK_FACE_SOUTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, a_BlockZ); break;
case BLOCK_FACE_NONE: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
}
SetSpeed(0, 0, 0);
// DEBUG:
LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, hit solid block at face %d",
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
a_BlockFace
);
m_IsInGround = true;
}
AString cProjectileEntity::GetMCAClassName(void) const
{
switch (m_ProjectileKind)
{
case pkArrow: return "Arrow";
case pkSnowball: return "Snowball";
case pkEgg: return "Egg";
case pkGhastFireball: return "Fireball";
case pkFireCharge: return "SmallFireball";
case pkEnderPearl: return "ThrownEnderPearl";
case pkExpBottle: return "ThrownExpBottle";
case pkSplashPotion: return "ThrownPotion";
case pkWitherSkull: return "WitherSkull";
case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
}
ASSERT(!"Unhandled projectile entity kind!");
return "";
}
void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate();
}
void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
if (m_IsInGround)
{
// Already-grounded projectiles don't move at all
return;
}
Vector3d PerTickSpeed = GetSpeed() / 20;
Vector3d Pos = GetPosition();
// Trace the tick's worth of movement as a line:
Vector3d NextPos = Pos + PerTickSpeed;
cProjectileTracerCallback TracerCallback(this);
if (cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
{
// Nothing in the way, update the position
SetPosition(NextPos);
}
// Add gravity effect to the vertical speed component:
SetSpeedY(GetSpeedY() + m_Gravity / 20);
// DEBUG:
LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}",
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
GetSpeedX(), GetSpeedY(), GetSpeedZ()
);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cArrowEntity:
cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d a_Speed) :
super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
m_PickupState(psNoPickup),
m_DamageCoeff(2)
{
SetSpeed(a_Speed);
SetMass(0.1);
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f}",
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ()
);
}
cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
super(pkArrow, &a_Player, PosFromPlayerPos(a_Player), SpeedFromPlayerLook(a_Player, a_Force), 0.5, 0.5),
m_PickupState(psInSurvivalOrCreative),
m_DamageCoeff(2)
{
}
Vector3d cArrowEntity::PosFromPlayerPos(const cPlayer & a_Player)
{
Vector3d res = a_Player.GetEyePosition();
// Adjust the position to be just outside the player's bounding box:
res.x += 0.16 * cos(a_Player.GetPitch());
res.y += -0.1;
res.z += 0.16 * sin(a_Player.GetPitch());
return res;
}
Vector3d cArrowEntity::SpeedFromPlayerLook(const cPlayer & a_Player, double a_Force)
{
Vector3d res = a_Player.GetLookVector();
res.Normalize();
// TODO: Add a slight random change (+-0.0075 in each direction)
return res * a_Force * 1.5 * 20;
}
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
{
switch (m_PickupState)
{
case psNoPickup: return false;
case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
case psInCreative: return a_Player.IsGameModeCreative();
}
ASSERT(!"Unhandled pickup state");
return false;
}
void cArrowEntity::SpawnOn(cClientHandle & a_Client)
{
a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0);
}

View File

@ -1,7 +1,7 @@
// ProjectileEntity.h // ProjectileEntity.h
// Declares the cProjectileEntity class representing the common base class for projectiles // Declares the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
@ -29,8 +29,8 @@ public:
pkArrow = 60, pkArrow = 60,
pkSnowball = 61, pkSnowball = 61,
pkEgg = 62, pkEgg = 62,
pkGhastFireball = 63, // TODO: Unverified TypeID, check this in ProtoProxy pkGhastFireball = 63,
pkFireCharge = 64, // TODO: Unverified TypeID, check this in ProtoProxy pkFireCharge = 64,
pkEnderPearl = 65, pkEnderPearl = 65,
pkExpBottle = 75, pkExpBottle = 75,
pkSplashPotion = 73, pkSplashPotion = 73,
@ -38,17 +38,48 @@ public:
pkFishingFloat = 90, pkFishingFloat = 90,
} ; } ;
// tolua_end
CLASS_PROTODEF(cProjectileEntity);
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height); cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
/// Called by the physics blocktracer when the entity hits a solid block, the coords and the face hit is given static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
virtual void OnHitSolidBlock(double a_BlockX, double a_BlockY, double a_BlockZ, char a_BlockFace) {};
/// Called by the physics blocktracer when the entity hits a solid block, the block's coords and the face hit is given
virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
// tolua_begin
/// Returns the kind of the projectile (fast class identification)
eKind GetProjectileKind(void) const { return m_ProjectileKind; }
/// Returns the entity who created this projectile; may be NULL
cEntity * GetCreator(void) { return m_Creator; }
/// Returns the string that is used as the entity type (class name) in MCA files
AString GetMCAClassName(void) const;
/// Returns true if the projectile has hit the ground and is stuck there
bool IsInGround(void) const { return m_IsInGround; }
protected: protected:
eKind m_Kind; eKind m_ProjectileKind;
/// The entity who has created this projectile; may be NULL (e. g. for dispensers) /// The entity who has created this projectile; may be NULL (e. g. for dispensers)
cEntity * m_Creator; cEntity * m_Creator;
/// True if the projectile has hit the ground and is stuck there
bool m_IsInGround;
// tolua_end
// cEntity overrides:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
// tolua_begin
} ; } ;
@ -58,9 +89,64 @@ protected:
class cArrowEntity : class cArrowEntity :
public cProjectileEntity public cProjectileEntity
{ {
typedef cProjectileEntity super;
public: public:
cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
cArrowEntity(cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height); enum ePickupState
{
psNoPickup = 0,
psInSurvivalOrCreative = 1,
psInCreative = 2,
} ;
// tolua_end
CLASS_PROTODEF(cArrowEntity);
/// Creates a new arrow with psNoPickup state and default damage modifier coeff
cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d a_Speed);
/// Creates a new arrow as shot by a player, initializes it from the player object
cArrowEntity(cPlayer & a_Player, double a_Force);
// tolua_begin
/// Returns the initial arrow position, as defined by the player eye position + adjustment.
static Vector3d PosFromPlayerPos(const cPlayer & a_Player);
/// Returns the initial arrow speed, as defined by the player look vector and the force coefficient
static Vector3d SpeedFromPlayerLook(const cPlayer & a_Player, double a_Force);
/// Returns whether the arrow can be picked up by players
ePickupState GetPickupState(void) const { return m_PickupState; }
/// Sets a new pickup state
void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
/// Returns the damage modifier coeff.
double GetDamageCoeff(void) const { return m_DamageCoeff; }
/// Sets the damage modifier coeff
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
/// Returns true if the specified player can pick the arrow up
bool CanPickup(const cPlayer & a_Player) const;
// tolua_end
protected:
/// Determines when the arrow can be picked up by players
ePickupState m_PickupState;
/// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
double m_DamageCoeff;
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_Client) override;
// tolua_begin
} ; } ;
// tolua_end // tolua_end

View File

@ -29,20 +29,6 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) :
bool cTNTEntity::Initialize(cWorld * a_World)
{
if (super::Initialize(a_World))
{
a_World->BroadcastSpawnEntity(*this);
return true;
}
return false;
}
void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle) void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
{ {
a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT

View File

@ -19,7 +19,6 @@ public:
cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec); cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec);
// cEntity overrides: // cEntity overrides:
virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override;

80
source/Items/ItemBow.h Normal file
View File

@ -0,0 +1,80 @@
// ItemBow.h
// Declares the cItemBowHandler class representing the itemhandler for bows
#pragma once
#include "../Entities/ProjectileEntity.h"
class cItemBowHandler :
public cItemHandler
{
typedef cItemHandler super;
public:
cItemBowHandler(void) :
super(E_ITEM_BOW)
{
}
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
{
ASSERT(a_Player != NULL);
// Check if the player has an arrow in the inventory, or is in Creative:
if (!(a_Player->IsGameModeCreative() || a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW))))
{
return false;
}
a_Player->StartChargingBow();
return true;
}
virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override
{
// Actual shot - produce the arrow with speed based on the ticks that the bow was charged
ASSERT(a_Player != NULL);
int BowCharge = a_Player->FinishChargingBow();
double Force = (double)BowCharge / 20;
Force = (Force * Force + 2 * Force) / 3; // This formula is used by the 1.6.2 client
if (Force < 0.1)
{
// Too little force, ignore the shot
return;
}
if (Force > 1)
{
Force = 1;
}
// Create the arrow entity:
cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2);
if (Arrow == NULL)
{
return;
}
if (!Arrow->Initialize(a_Player->GetWorld()))
{
delete Arrow;
return;
}
a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow);
}
} ;

View File

@ -8,6 +8,7 @@
// Handlers: // Handlers:
#include "ItemBed.h" #include "ItemBed.h"
#include "ItemBow.h"
#include "ItemBrewingStand.h" #include "ItemBrewingStand.h"
#include "ItemBucket.h" #include "ItemBucket.h"
#include "ItemCauldron.h" #include "ItemCauldron.h"
@ -47,18 +48,24 @@ cItemHandler * cItemHandler::m_ItemHandler[2268];
cItemHandler *cItemHandler::GetItemHandler(int a_ItemType) cItemHandler * cItemHandler::GetItemHandler(int a_ItemType)
{ {
if(a_ItemType < 0) a_ItemType = 0; if (a_ItemType < 0)
{
ASSERT(!"Bad item type");
a_ItemType = 0;
}
if(!m_HandlerInitialized) if (!m_HandlerInitialized)
{ //We have to initialize {
// We need to initialize
memset(m_ItemHandler, 0, sizeof(m_ItemHandler)); memset(m_ItemHandler, 0, sizeof(m_ItemHandler));
m_HandlerInitialized = true; m_HandlerInitialized = true;
} }
if(m_ItemHandler[a_ItemType]) if (m_ItemHandler[a_ItemType] == NULL)
return m_ItemHandler[a_ItemType]; {
m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType); m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType);
}
return m_ItemHandler[a_ItemType]; return m_ItemHandler[a_ItemType];
} }
@ -77,6 +84,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType); case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType);
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType); case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
case E_ITEM_BED: return new cItemBedHandler(a_ItemType); case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
case E_ITEM_BOW: return new cItemBowHandler;
case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType); case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType); case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType); case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);

View File

@ -21,8 +21,11 @@ class cItemHandler
public: public:
cItemHandler(int a_ItemType); cItemHandler(int a_ItemType);
/// Called when the player tries to use the item. Return false to make the item unusable. DEFAULT: False /// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); //eg for fishing or hoes virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir);
/// Called when the client sends the SHOOT status in the lclk packet
virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) {}
/// Called while the player diggs a block using this item /// Called while the player diggs a block using this item
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace); virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
@ -88,7 +91,7 @@ protected:
int m_ItemType; int m_ItemType;
static cItemHandler *CreateItemHandler(int m_ItemType); static cItemHandler *CreateItemHandler(int m_ItemType);
static cItemHandler *m_ItemHandler[2268]; static cItemHandler * m_ItemHandler[E_ITEM_LAST + 1];
static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized
}; };

View File

@ -55,6 +55,7 @@ bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ,
m_DirX = (m_StartX < m_EndX) ? 1 : -1; m_DirX = (m_StartX < m_EndX) ? 1 : -1;
m_DirY = (m_StartY < m_EndY) ? 1 : -1; m_DirY = (m_StartY < m_EndY) ? 1 : -1;
m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1; m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1;
m_CurrentFace = BLOCK_FACE_NONE;
// Check the start coords, adjust into the world: // Check the start coords, adjust into the world:
if (m_StartY < 0) if (m_StartY < 0)
@ -178,9 +179,9 @@ bool cLineBlockTracer::MoveToNextBlock(void)
// Based on the wall hit, adjust the current coords // Based on the wall hit, adjust the current coords
switch (Direction) switch (Direction)
{ {
case dirX: m_CurrentX += m_DirX; break; case dirX: m_CurrentX += m_DirX; m_CurrentFace = (m_DirX > 0) ? BLOCK_FACE_EAST : BLOCK_FACE_WEST; break;
case dirY: m_CurrentY += m_DirY; break; case dirY: m_CurrentY += m_DirY; m_CurrentFace = (m_DirY > 0) ? BLOCK_FACE_BOTTOM : BLOCK_FACE_TOP; break;
case dirZ: m_CurrentZ += m_DirZ; break; case dirZ: m_CurrentZ += m_DirZ; m_CurrentFace = (m_DirZ > 0) ? BLOCK_FACE_SOUTH : BLOCK_FACE_NORTH; break;
case dirNONE: return false; case dirNONE: return false;
} }
return true; return true;
@ -211,7 +212,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk)
int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width; int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width;
int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width; int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width;
a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta); a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta);
if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta)) if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta, m_CurrentFace))
{ {
// The callback terminated the trace // The callback terminated the trace
return false; return false;
@ -219,7 +220,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk)
} }
else else
{ {
if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ)) if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ, m_CurrentFace))
{ {
// The callback terminated the trace // The callback terminated the trace
return false; return false;

View File

@ -61,6 +61,9 @@ protected:
// The current block // The current block
int m_CurrentX, m_CurrentY, m_CurrentZ; int m_CurrentX, m_CurrentY, m_CurrentZ;
// The face through which the current block has been entered
char m_CurrentFace;
/// Adjusts the start point above the world to just at the world's top /// Adjusts the start point above the world to just at the world's top
void FixStartAboveWorld(void); void FixStartAboveWorld(void);

View File

@ -1649,7 +1649,7 @@ public:
{ {
} }
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{ {
if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock")) if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock"))
{ {
@ -1661,6 +1661,7 @@ public:
m_LuaState.Push(a_BlockZ); m_LuaState.Push(a_BlockZ);
m_LuaState.Push(a_BlockType); m_LuaState.Push(a_BlockType);
m_LuaState.Push(a_BlockMeta); m_LuaState.Push(a_BlockMeta);
m_LuaState.Push(a_EntryFace);
if (!m_LuaState.CallFunction(1)) if (!m_LuaState.CallFunction(1))
{ {
return false; return false;
@ -1674,7 +1675,7 @@ public:
return res; return res;
} }
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) override virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override
{ {
if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData")) if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData"))
{ {
@ -1684,6 +1685,7 @@ public:
m_LuaState.Push(a_BlockX); m_LuaState.Push(a_BlockX);
m_LuaState.Push(a_BlockY); m_LuaState.Push(a_BlockY);
m_LuaState.Push(a_BlockZ); m_LuaState.Push(a_BlockZ);
m_LuaState.Push(a_EntryFace);
if (!m_LuaState.CallFunction(1)) if (!m_LuaState.CallFunction(1))
{ {
return false; return false;

View File

@ -30,12 +30,13 @@ public: // tolua_export
void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; } void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; } void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; }
Vector3d operator + ( const Vector3d& v2 ) const { return Vector3d( x + v2.x, y + v2.y, z + v2.z ); } // tolua_export Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); } // tolua_export
Vector3d operator + ( const Vector3d* v2 ) const { return Vector3d( x + v2->x, y + v2->y, z + v2->z ); } // tolua_export Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); } // tolua_export
Vector3d operator - ( const Vector3d& v2 ) const { return Vector3d( x - v2.x, y - v2.y, z - v2.z ); } // tolua_export Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); } // tolua_export
Vector3d operator - ( const Vector3d* v2 ) const { return Vector3d( x - v2->x, y - v2->y, z - v2->z ); } // tolua_export Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); } // tolua_export
Vector3d operator * ( const double f ) const { return Vector3d( x * f, y * f, z * f ); } // tolua_export Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); } // tolua_export
Vector3d operator * ( const Vector3d& v2 ) const { return Vector3d( x * v2.x, y * v2.y, z * v2.z ); } // tolua_export Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); } // tolua_export
Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); } // tolua_export
double x, y, z; // tolua_export double x, y, z; // tolua_export

View File

@ -5,8 +5,6 @@
#include "World.h" #include "World.h"
#include "ChunkDef.h" #include "ChunkDef.h"
#include "ClientHandle.h" #include "ClientHandle.h"
#include "Entities/Pickup.h"
#include "Entities/Player.h"
#include "Server.h" #include "Server.h"
#include "Item.h" #include "Item.h"
#include "Root.h" #include "Root.h"
@ -14,6 +12,11 @@
#include "ChunkMap.h" #include "ChunkMap.h"
#include "OSSupport/Timer.h" #include "OSSupport/Timer.h"
// Entities (except mobs):
#include "Entities/Pickup.h"
#include "Entities/Player.h"
#include "Entities/TNTEntity.h"
// Simulators: // Simulators:
#include "Simulator/SimulatorManager.h" #include "Simulator/SimulatorManager.h"
#include "Simulator/FloodyFluidSimulator.h" #include "Simulator/FloodyFluidSimulator.h"
@ -55,7 +58,6 @@
#include "PluginManager.h" #include "PluginManager.h"
#include "Blocks/BlockHandler.h" #include "Blocks/BlockHandler.h"
#include "Vector3d.h" #include "Vector3d.h"
#include "Entities/TNTEntity.h"
#include "Tracer.h" #include "Tracer.h"
#include "tolua++.h" #include "tolua++.h"
@ -2647,6 +2649,26 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed)
{
cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Speed);
if (Projectile == NULL)
{
return -1;
}
if (!Projectile->Initialize(this))
{
delete Projectile;
return -1;
}
BroadcastSpawnEntity(*Projectile);
return Projectile->GetUniqueID();
}
void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Results) void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Results)
{ {
cCSLock Lock(m_CSPlayers); cCSLock Lock(m_CSPlayers);

View File

@ -21,6 +21,7 @@
#include "LightingThread.h" #include "LightingThread.h"
#include "Item.h" #include "Item.h"
#include "Mobs/Monster.h" #include "Mobs/Monster.h"
#include "Entities/ProjectileEntity.h"
@ -573,6 +574,9 @@ public:
/// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export
/// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
/// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread!
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); } int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }

View File

@ -22,6 +22,8 @@
#include "../Entities/Minecart.h" #include "../Entities/Minecart.h"
#include "../Mobs/Monster.h" #include "../Mobs/Monster.h"
#include "../Entities/Pickup.h" #include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
@ -330,6 +332,62 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
{
m_Writer.BeginCompound("");
AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName());
Vector3d Pos = a_Projectile->GetPosition();
m_Writer.AddShort("xTile", (Int16)floor(Pos.x));
m_Writer.AddShort("yTile", (Int16)floor(Pos.y));
m_Writer.AddShort("zTile", (Int16)floor(Pos.z));
m_Writer.AddShort("inTile", 0); // TODO: Query the block type (is it needed?)
m_Writer.AddShort("shake", 0); // TODO: Any shake?
m_Writer.AddByte ("inGround", a_Projectile->IsInGround() ? 1 : 0);
switch (a_Projectile->GetProjectileKind())
{
case cProjectileEntity::pkArrow:
{
m_Writer.AddByte("inData", 0); // TODO: Query the block meta (is it needed?)
m_Writer.AddByte("pickup", ((cArrowEntity *)a_Projectile)->GetPickupState());
m_Writer.AddDouble("damage", ((cArrowEntity *)a_Projectile)->GetDamageCoeff());
break;
}
case cProjectileEntity::pkGhastFireball:
{
m_Writer.AddInt("ExplosionPower", 1);
// fall-through:
}
case cProjectileEntity::pkFireCharge:
case cProjectileEntity::pkWitherSkull:
{
m_Writer.BeginList("Motion", TAG_Double);
m_Writer.AddDouble("", a_Projectile->GetSpeedX());
m_Writer.AddDouble("", a_Projectile->GetSpeedY());
m_Writer.AddDouble("", a_Projectile->GetSpeedZ());
m_Writer.EndList();
break;
}
default:
{
ASSERT(!"Unsaved projectile entity!");
}
} // switch (ProjectileKind)
cEntity * Creator = a_Projectile->GetCreator();
if (Creator != NULL)
{
if (Creator->GetEntityType() == cEntity::etPlayer)
{
m_Writer.AddString("ownerName", ((cPlayer *)Creator)->GetName());
}
}
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart) void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{ {
m_Writer.BeginList("Items", TAG_Compound); m_Writer.BeginList("Items", TAG_Compound);
@ -403,10 +461,11 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
switch (a_Entity->GetEntityType()) switch (a_Entity->GetEntityType())
{ {
case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *)a_Entity); break; case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *) a_Entity); break;
case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break; case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break;
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break; case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break; case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
case cEntity::etPlayer: return; // Players aren't saved into the world case cEntity::etPlayer: return; // Players aren't saved into the world
default: default:
{ {

View File

@ -36,6 +36,7 @@ class cMinecartWithHopper;
class cMonster; class cMonster;
class cPickup; class cPickup;
class cItemGrid; class cItemGrid;
class cProjectileEntity;
@ -97,6 +98,7 @@ protected:
void AddMinecartEntity (cMinecart * a_Minecart); void AddMinecartEntity (cMinecart * a_Minecart);
void AddMonsterEntity (cMonster * a_Monster); void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup); void AddPickupEntity (cPickup * a_Pickup);
void AddProjectileEntity (cProjectileEntity * a_Projectile);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart); void AddMinecartChestContents(cMinecartWithChest * a_Minecart);

View File

@ -20,13 +20,13 @@
#include "../Item.h" #include "../Item.h"
#include "../ItemGrid.h" #include "../ItemGrid.h"
#include "../StringCompression.h" #include "../StringCompression.h"
#include "../Entities/Entity.h"
#include "../OSSupport/MakeDir.h" #include "../OSSupport/MakeDir.h"
#include "FastNBT.h" #include "FastNBT.h"
#include "../Mobs/Monster.h"
#include "../Entities/FallingBlock.h" #include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h" #include "../Entities/Minecart.h"
#include "../Mobs/Monster.h"
#include "../Entities/Pickup.h" #include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
@ -956,6 +956,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{ {
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx); LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
} }
if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0)
{
LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
// TODO: other entities // TODO: other entities
} }
@ -1043,7 +1047,7 @@ void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT
return; return;
} }
//TODO: Everything to do with TNT carts // TODO: Everything to do with TNT carts
a_Entities.push_back(Minecart.release()); a_Entities.push_back(Minecart.release());
} }
@ -1060,7 +1064,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT
return; return;
} }
//TODO: Everything to do with hopper carts // TODO: Everything to do with hopper carts
a_Entities.push_back(Minecart.release()); a_Entities.push_back(Minecart.release());
} }
@ -1093,6 +1097,45 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
if (!LoadEntityBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx))
{
return;
}
// Load pickup state:
int PickupIdx = a_NBT.FindChildByName(a_TagIdx, "pickup");
if (PickupIdx > 0)
{
Arrow->SetPickupState((cArrowEntity::ePickupState)a_NBT.GetByte(PickupIdx));
}
else
{
// Try the older "player" tag:
int PlayerIdx = a_NBT.FindChildByName(a_TagIdx, "player");
if (PlayerIdx > 0)
{
Arrow->SetPickupState((a_NBT.GetByte(PlayerIdx) == 0) ? cArrowEntity::psNoPickup : cArrowEntity::psInSurvivalOrCreative);
}
}
// Load damage:
int DamageIdx = a_NBT.FindChildByName(a_TagIdx, "damage");
if (DamageIdx > 0)
{
Arrow->SetDamageCoeff(a_NBT.GetDouble(DamageIdx));
}
// Store the new arrow in the entities list:
a_Entities.push_back(Arrow.release());
}
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx) bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
{ {
double Pos[3]; double Pos[3];

View File

@ -145,6 +145,7 @@ protected:
void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
/// Loads entity common data from the NBT compound; returns true if successful /// Loads entity common data from the NBT compound; returns true if successful
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx); bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);