1
0
Fork 0

Entities handle chunks properly again

* Entities properly handle chunks
* Changed EntityStatus enums to be less shouty
This commit is contained in:
Tiger Wang 2014-04-12 13:16:48 +01:00
parent b3f6afefe9
commit c0c47d33c5
10 changed files with 127 additions and 127 deletions

View File

@ -2101,7 +2101,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo
} }
// Update the statistics: // Update the statistics:
m_NumExplosionsThisTick += 1; m_NumExplosionsThisTick++;
m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion); m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion);
} }

View File

@ -330,7 +330,7 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
AddSpeed(a_TDI.Knockback * 2); AddSpeed(a_TDI.Knockback * 2);
} }
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT); m_World->BroadcastEntityStatus(*this, esGenericHurt);
if (m_Health <= 0) if (m_Health <= 0)
{ {
@ -479,7 +479,7 @@ void cEntity::KilledBy(cEntity * a_Killer)
GetDrops(Drops, a_Killer); GetDrops(Drops, a_Killer);
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ()); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD); m_World->BroadcastEntityStatus(*this, esGenericDead);
} }
@ -519,37 +519,36 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
} }
else else
{ {
if (a_Chunk.IsValid()) if (!a_Chunk.IsValid())
{ {
cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT); return;
if ((NextChunk == NULL) || !NextChunk->IsValid())
{
return;
}
TickBurning(*NextChunk);
if (GetPosY() < VOID_BOUNDARY)
{
TickInVoid(*NextChunk);
}
else
{
m_TicksSinceLastVoidDamage = 0;
}
if (IsMob() || IsPlayer())
{
// Set swimming state
SetSwimState(*NextChunk);
// Handle drowning
HandleAir();
}
HandlePhysics(a_Dt, *NextChunk);
} }
// Position changed -> super::Tick() called
GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, POSX_TOINT, POSZ_TOINT)
TickBurning(*NextChunk);
if (GetPosY() < VOID_BOUNDARY)
{
TickInVoid(*NextChunk);
}
else
{
m_TicksSinceLastVoidDamage = 0;
}
if (IsMob() || IsPlayer())
{
// Set swimming state
SetSwimState(*NextChunk);
// Handle drowning
HandleAir();
}
// None of the above functions change position, we remain in the chunk of NextChunk
HandlePhysics(a_Dt, *NextChunk);
} }
} }
@ -559,34 +558,30 @@ 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)
{ {
int BlockX = POSX_TOINT;
int BlockY = POSY_TOINT;
int BlockZ = POSZ_TOINT;
// Position changed -> super::HandlePhysics() called
GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, BlockX, BlockZ)
// TODO Add collision detection with entities. // TODO Add collision detection with entities.
a_Dt /= 1000; // Convert from msec to sec 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 BlockY = (int) floor(NextPos.y);
int BlockZ = (int) floor(NextPos.z);
if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{ {
// Outside of the world // Outside of the world
AddSpeedY(m_Gravity * a_Dt);
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); AddPosition(GetSpeed() * a_Dt);
// See if we can commit our changes. If not, we will discard them.
if (NextChunk != NULL)
{
SetSpeed(NextSpeed);
NextPos += (NextSpeed * a_Dt);
SetPosition(NextPos);
}
return; return;
} }
int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width); int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width); int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ ); BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block
{ {
if (m_bOnGround) // check if it's still on the ground if (m_bOnGround) // check if it's still on the ground
@ -616,7 +611,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
bool IsNoAirSurrounding = true; bool IsNoAirSurrounding = true;
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
{ {
if (!a_Chunk.UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
{ {
// The pickup is too close to an unloaded chunk, bail out of any physics handling // The pickup is too close to an unloaded chunk, bail out of any physics handling
return; return;
@ -764,20 +759,8 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
} }
} }
BlockX = (int) floor(NextPos.x); SetPosition(NextPos);
BlockZ = (int) floor(NextPos.z); SetSpeed(NextSpeed);
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
// See if we can commit our changes. If not, we will discard them.
if (NextChunk != NULL)
{
if (NextPos.x != GetPosX()) SetPosX(NextPos.x);
if (NextPos.y != GetPosY()) SetPosY(NextPos.y);
if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z);
if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x);
if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y);
if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z);
}
} }
@ -981,13 +964,13 @@ void cEntity::HandleAir(void)
} }
else else
{ {
m_AirTickTimer -= 1; m_AirTickTimer--;
} }
} }
else else
{ {
// Reduce air supply // Reduce air supply
m_AirLevel -= 1; m_AirLevel--;
} }
} }
else else
@ -1099,15 +1082,15 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude) void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{ {
//We need to keep updating the clients when there is movement or if there was a change in speed and after 2 ticks // Send velocity packet every two ticks if: speed is not negligible or speed was set (as indicated by the DirtySpeed flag)
if( (m_Speed.SqrLength() > 0.0004f || m_bDirtySpeed) && (m_World->GetWorldAge() - m_TimeLastSpeedPacket >= 2)) if (((m_Speed.SqrLength() > 0.0004f) || m_bDirtySpeed) && ((m_World->GetWorldAge() - m_TimeLastSpeedPacket) >= 2))
{ {
m_World->BroadcastEntityVelocity(*this,a_Exclude); m_World->BroadcastEntityVelocity(*this,a_Exclude);
m_bDirtySpeed = false; m_bDirtySpeed = false;
m_TimeLastSpeedPacket = m_World->GetWorldAge(); m_TimeLastSpeedPacket = m_World->GetWorldAge();
} }
//Have to process position related packets this every two ticks // Have to process position related packets this every two ticks
if (m_World->GetWorldAge() % 2 == 0) if (m_World->GetWorldAge() % 2 == 0)
{ {
int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0)); int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0));

View File

@ -32,6 +32,8 @@
#define POSZ_TOINT (int)floor(GetPosZ()) #define POSZ_TOINT (int)floor(GetPosZ())
#define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT) #define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT)
#define GET_AND_VERIFY_CURRENT_CHUNK(ChunkVarName, X, Z) cChunk * ChunkVarName = a_Chunk.GetNeighborChunk(X, Z); if ((ChunkVarName == NULL) || !ChunkVarName->IsValid()) { return; }
@ -88,23 +90,42 @@ public:
} ; } ;
// tolua_end // tolua_end
enum enum eEntityStatus
{ {
ENTITY_STATUS_HURT = 2, // TODO: Investiagate 0, 1, and 5 as Wiki.vg is not certain
ENTITY_STATUS_DEAD = 3,
ENTITY_STATUS_WOLF_TAMING = 6, // Entity becomes coloured red
ENTITY_STATUS_WOLF_TAMED = 7, esGenericHurt = 2,
ENTITY_STATUS_WOLF_SHAKING = 8, // Entity plays death animation (entity falls to ground)
ENTITY_STATUS_EATING_ACCEPTED = 9, esGenericDead = 3,
ENTITY_STATUS_SHEEP_EATING = 10, // Iron Golem plays attack animation (arms lift and fall)
ENTITY_STATUS_GOLEM_ROSING = 11, esIronGolemAttacking = 4,
ENTITY_STATUS_VILLAGER_HEARTS = 12, // Wolf taming particles spawn (smoke)
ENTITY_STATUS_VILLAGER_ANGRY = 13, esWolfTaming = 6,
ENTITY_STATUS_VILLAGER_HAPPY = 14, // Wolf tamed particles spawn (hearts)
ENTITY_STATUS_WITCH_MAGICKING = 15, esWolfTamed = 7,
// Wolf plays water removal animation (shaking and water particles)
esWolfDryingWater = 8,
// Informs client that eating was accepted
esPlayerEatingAccepted = 9,
// Sheep plays eating animation (head lowers to ground)
esSheepEating = 10,
// Iron Golem holds gift to villager children
esIronGolemGivingPlant = 11,
// Villager spawns heart particles
esVillagerBreeding = 12,
// Villager spawns thunderclound particles
esVillagerAngry = 13,
// Villager spawns green crosses
esVillagerHappy = 14,
// Witch spawns magic particle (TODO: investigation into what this is)
esWitchMagicking = 15,
// It seems 16 (zombie conversion) is now done with metadata // It seems 16 (zombie conversion) is now done with metadata
ENTITY_STATUS_FIREWORK_EXPLODE= 17,
// Informs client to explode a firework based on its metadata
esFireworkExploding = 17,
} ; } ;
enum enum

View File

@ -98,45 +98,44 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
if (!m_bCollected) if (!m_bCollected)
{ {
int BlockY = (int) floor(GetPosY()); int BlockY = POSY_TOINT;
int BlockX = POSX_TOINT;
int BlockZ = POSZ_TOINT;
if ((BlockY >= 0) && (BlockY < cChunkDef::Height)) // Don't do anything except for falling when outside the world if ((BlockY >= 0) && (BlockY < cChunkDef::Height)) // Don't do anything except for falling when outside the world
{ {
int BlockX = (int) floor(GetPosX());
int BlockZ = (int) floor(GetPosZ());
// Position might have changed due to physics. So we have to make sure we have the correct chunk. // Position might have changed due to physics. So we have to make sure we have the correct chunk.
cChunk * CurrentChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); GET_AND_VERIFY_CURRENT_CHUNK(CurrentChunk, BlockX, BlockZ)
if (CurrentChunk != NULL) // Make sure the chunk is loaded
{ int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width);
int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width); int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
// If the pickup is on the bottommost block position, make it think the void is made of air: (#131) // If the pickup is on the bottommost block position, make it think the void is made of air: (#131)
BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ); BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ);
if ( if (
IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) || IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) ||
IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE) IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE)
) )
{
m_bCollected = true;
m_Timer = 0; // We have to reset the timer.
m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick.
if (m_Timer > 500.f)
{ {
m_bCollected = true; Destroy(true);
m_Timer = 0; // We have to reset the timer. return;
m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick.
if (m_Timer > 500.f)
{
Destroy(true);
return;
}
} }
}
if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me
{
cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this);
m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
if (PickupCombiningCallback.FoundMatchingPickup())
{ {
cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this); m_World->BroadcastEntityMetadata(*this);
m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
if (PickupCombiningCallback.FoundMatchingPickup())
{
m_World->BroadcastEntityMetadata(*this);
}
} }
} }
} }
@ -156,7 +155,7 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
return; return;
} }
if (GetPosY() < -8) // Out of this world and no more visible! if (GetPosY() < VOID_BOUNDARY) // Out of this world and no more visible!
{ {
Destroy(true); Destroy(true);
return; return;

View File

@ -49,9 +49,6 @@ public:
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
private: private:
Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
Vector3d m_WaterSpeed;
/** The number of ticks that the entity has existed / timer between collect and destroy; in msec */ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer; float m_Timer;

View File

@ -590,7 +590,7 @@ void cPlayer::FinishEating(void)
m_EatingFinishTick = -1; m_EatingFinishTick = -1;
// Send the packets: // Send the packets:
m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED); m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
m_World->BroadcastEntityAnimation(*this, 0); m_World->BroadcastEntityAnimation(*this, 0);
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);

View File

@ -791,7 +791,7 @@ void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks) if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
{ {
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE); m_World->BroadcastEntityStatus(*this, esFireworkExploding);
Destroy(); Destroy();
} }

View File

@ -101,7 +101,7 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
{ {
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
{ {
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING); m_World->BroadcastEntityStatus(*this, esSheepEating);
m_TimeToStopEating = 40; m_TimeToStopEating = 40;
} }
} }

View File

@ -30,7 +30,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
{ {
if (m_World->GetTickRandomNumber(5) == 3) if (m_World->GetTickRandomNumber(5) == 3)
{ {
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_VILLAGER_ANGRY); m_World->BroadcastEntityStatus(*this, esVillagerAngry);
} }
} }
} }

View File

@ -75,12 +75,12 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
SetMaxHealth(20); SetMaxHealth(20);
SetIsTame(true); SetIsTame(true);
SetOwner(a_Player.GetName()); SetOwner(a_Player.GetName());
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMED); m_World->BroadcastEntityStatus(*this, esWolfTamed);
m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5); m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
} }
else else
{ {
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMING); m_World->BroadcastEntityStatus(*this, esWolfTaming);
m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5); m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
} }
} }