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:
m_NumExplosionsThisTick += 1;
m_NumExplosionsThisTick++;
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);
}
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
m_World->BroadcastEntityStatus(*this, esGenericHurt);
if (m_Health <= 0)
{
@ -479,7 +479,7 @@ void cEntity::KilledBy(cEntity * a_Killer)
GetDrops(Drops, a_Killer);
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
{
if (a_Chunk.IsValid())
if (!a_Chunk.IsValid())
{
cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT);
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);
return;
}
// 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)
{
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.
a_Dt /= 1000; // Convert from msec to sec
Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ());
Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ());
int BlockX = (int) floor(NextPos.x);
int BlockY = (int) floor(NextPos.y);
int BlockZ = (int) floor(NextPos.z);
Vector3d NextPos = Vector3d(GetPosX(), GetPosY(), GetPosZ());
Vector3d NextSpeed = Vector3d(GetSpeedX(), GetSpeedY(), GetSpeedZ());
if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{
// Outside of the world
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
// See if we can commit our changes. If not, we will discard them.
if (NextChunk != NULL)
{
SetSpeed(NextSpeed);
NextPos += (NextSpeed * a_Dt);
SetPosition(NextPos);
}
// Outside of the world
AddSpeedY(m_Gravity * a_Dt);
AddPosition(GetSpeed() * a_Dt);
return;
}
int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width);
BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ );
BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
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 (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;
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
return;
@ -764,20 +759,8 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
}
BlockX = (int) floor(NextPos.x);
BlockZ = (int) floor(NextPos.z);
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);
}
SetPosition(NextPos);
SetSpeed(NextSpeed);
}
@ -981,13 +964,13 @@ void cEntity::HandleAir(void)
}
else
{
m_AirTickTimer -= 1;
m_AirTickTimer--;
}
}
else
{
// Reduce air supply
m_AirLevel -= 1;
m_AirLevel--;
}
}
else
@ -1099,15 +1082,15 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
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
if( (m_Speed.SqrLength() > 0.0004f || m_bDirtySpeed) && (m_World->GetWorldAge() - m_TimeLastSpeedPacket >= 2))
// 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))
{
m_World->BroadcastEntityVelocity(*this,a_Exclude);
m_bDirtySpeed = false;
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)
{
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 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
enum
enum eEntityStatus
{
ENTITY_STATUS_HURT = 2,
ENTITY_STATUS_DEAD = 3,
ENTITY_STATUS_WOLF_TAMING = 6,
ENTITY_STATUS_WOLF_TAMED = 7,
ENTITY_STATUS_WOLF_SHAKING = 8,
ENTITY_STATUS_EATING_ACCEPTED = 9,
ENTITY_STATUS_SHEEP_EATING = 10,
ENTITY_STATUS_GOLEM_ROSING = 11,
ENTITY_STATUS_VILLAGER_HEARTS = 12,
ENTITY_STATUS_VILLAGER_ANGRY = 13,
ENTITY_STATUS_VILLAGER_HAPPY = 14,
ENTITY_STATUS_WITCH_MAGICKING = 15,
// TODO: Investiagate 0, 1, and 5 as Wiki.vg is not certain
// Entity becomes coloured red
esGenericHurt = 2,
// Entity plays death animation (entity falls to ground)
esGenericDead = 3,
// Iron Golem plays attack animation (arms lift and fall)
esIronGolemAttacking = 4,
// Wolf taming particles spawn (smoke)
esWolfTaming = 6,
// Wolf tamed particles spawn (hearts)
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
ENTITY_STATUS_FIREWORK_EXPLODE= 17,
// Informs client to explode a firework based on its metadata
esFireworkExploding = 17,
} ;
enum

View File

@ -98,45 +98,44 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
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
{
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.
cChunk * CurrentChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
if (CurrentChunk != NULL) // Make sure the chunk is loaded
{
int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
GET_AND_VERIFY_CURRENT_CHUNK(CurrentChunk, BlockX, BlockZ)
int RelBlockX = BlockX - (CurrentChunk->GetPosX() * 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)
BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ);
// 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 BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ);
if (
IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) ||
IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE)
)
if (
IsBlockLava(BlockBelow) || (BlockBelow == 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;
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)
{
Destroy(true);
return;
}
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->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
if (PickupCombiningCallback.FoundMatchingPickup())
{
m_World->BroadcastEntityMetadata(*this);
}
m_World->BroadcastEntityMetadata(*this);
}
}
}
@ -156,7 +155,7 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
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);
return;

View File

@ -49,9 +49,6 @@ public:
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
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 */
float m_Timer;

View File

@ -590,7 +590,7 @@ void cPlayer::FinishEating(void)
m_EatingFinishTick = -1;
// Send the packets:
m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED);
m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
m_World->BroadcastEntityAnimation(*this, 0);
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)
{
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE);
m_World->BroadcastEntityStatus(*this, esFireworkExploding);
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)
{
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING);
m_World->BroadcastEntityStatus(*this, esSheepEating);
m_TimeToStopEating = 40;
}
}

View File

@ -30,7 +30,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
{
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);
SetIsTame(true);
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);
}
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);
}
}