From c6b4ee8c9fb597b6f87f4cb756f43d5548ab2d66 Mon Sep 17 00:00:00 2001 From: "lapayo94@gmail.com" Date: Wed, 28 Dec 2011 21:00:35 +0000 Subject: - implemented the fire simulation in native c++ (cFireSimulator) - Changed the Durationsystem for Items. cPlayer::UseEquippedItem calls cItem::DamageItem this function damages the item if it has a duration. (needed the duration also in another place so this saves code ;)) - added some other burning blocks - the mobtypes for the settings.ini which i must have forgotten in the last commit git-svn-id: http://mc-server.googlecode.com/svn/trunk@150 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cBlockToPickup.cpp | 2 + source/cClientHandle.cpp | 127 ++++++++++++++++------------------------------ source/cFireSimulator.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++ source/cFireSimulator.h | 31 +++++++++++ source/cItem.cpp | 2 +- source/cItem.h | 53 +++++++++++++++++++ source/cPlayer.cpp | 10 ++++ source/cPlayer.h | 2 + source/cWorld.cpp | 17 +++++-- source/cWorld.h | 2 + 10 files changed, 280 insertions(+), 90 deletions(-) create mode 100644 source/cFireSimulator.cpp create mode 100644 source/cFireSimulator.h (limited to 'source') diff --git a/source/cBlockToPickup.cpp b/source/cBlockToPickup.cpp index 531c9601e..0caca7d1c 100644 --- a/source/cBlockToPickup.cpp +++ b/source/cBlockToPickup.cpp @@ -20,6 +20,8 @@ ENUM_ITEM_ID cBlockToPickup::ToPickup( unsigned char a_BlockID, ENUM_ITEM_ID a_U return E_ITEM_EMPTY; case E_BLOCK_GRASS: return E_ITEM_DIRT; + case E_BLOCK_FIRE: + return E_ITEM_EMPTY; case E_BLOCK_GLASS: return E_ITEM_EMPTY; case E_BLOCK_DIRT: diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index d65c47e8e..8c49411fe 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -587,8 +587,12 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) else { cWorld* World = m_Player->GetWorld(); + + char OldBlock = World->GetBlock(PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ); char MetaData = World->GetBlockMeta(PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ); + + bool bBroken = (PacketData->m_Status == 0x02) || g_BlockOneHitDig[(int)OldBlock] || ( (PacketData->m_Status == 0x00) && (m_Player->GetGameMode() == 1) ); if(bBroken == false) bBroken = (m_Player->GetInventory().GetEquippedItem().m_ItemID == E_ITEM_SHEARS && OldBlock == E_BLOCK_LEAVES); @@ -616,6 +620,20 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) } if(!cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_BLOCK_DIG, 2, PacketData, m_Player, &PickupItem ) ) { + int pX = PacketData->m_PosX, pY = PacketData->m_PosY, pZ = PacketData->m_PosZ; + + AddDirection(pX, (char &) pY, pZ, PacketData->m_Direction); + + char PossibleBlock = World->GetBlock(pX, pY, pZ); + + if(PossibleBlock == E_BLOCK_FIRE) + { + PacketData->m_PosX = pX; + PacketData->m_PosY = pY; + PacketData->m_PosZ = pZ; + bBroken = true; + } + if( bBroken ) // Block broken { if( World->DigBlock( PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ, PickupItem ) ) @@ -653,78 +671,8 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) World->SetBlock(PacketData->m_PosX, PacketData->m_PosY + 1, PacketData->m_PosZ, E_BLOCK_AIR, 0); } } - - int helditem = m_Player->GetInventory().GetEquippedItem().m_ItemID; - bool itemhasdur = false; - switch(helditem) - { - case 256 : itemhasdur = true; break; - case 257 : itemhasdur = true; break; - case 258 : itemhasdur = true; break; - case 267 : itemhasdur = true; break; - case 268 : itemhasdur = true; break; - case 269 : itemhasdur = true; break; - case 270 : itemhasdur = true; break; - case 271 : itemhasdur = true; break; - case 272 : itemhasdur = true; break; - case 273 : itemhasdur = true; break; - case 274 : itemhasdur = true; break; - case 275 : itemhasdur = true; break; - case 276 : itemhasdur = true; break; - case 277 : itemhasdur = true; break; - case 278 : itemhasdur = true; break; - case 279 : itemhasdur = true; break; - case 283 : itemhasdur = true; break; - case 284 : itemhasdur = true; break; - case 285 : itemhasdur = true; break; - case 286 : itemhasdur = true; break; - case 290 : itemhasdur = true; break; - case 291 : itemhasdur = true; break; - case 292 : itemhasdur = true; break; - case 293 : itemhasdur = true; break; - case 294 : itemhasdur = true; break; - case 359 : itemhasdur = true; break; - } - if (itemhasdur) - { - int maxhelditemdur = 1563; - switch(helditem) - { - case 256 : maxhelditemdur = 251; break; - case 257 : maxhelditemdur = 251; break; - case 258 : maxhelditemdur = 251; break; - case 267 : maxhelditemdur = 251; break; - case 268 : maxhelditemdur = 60; break; - case 269 : maxhelditemdur = 60; break; - case 270 : maxhelditemdur = 60; break; - case 271 : maxhelditemdur = 60; break; - case 272 : maxhelditemdur = 132; break; - case 273 : maxhelditemdur = 132; break; - case 274 : maxhelditemdur = 132; break; - case 275 : maxhelditemdur = 132; break; - case 276 : maxhelditemdur = 1563; break; - case 277 : maxhelditemdur = 1563; break; - case 278 : maxhelditemdur = 1563; break; - case 279 : maxhelditemdur = 1563; break; - case 283 : maxhelditemdur = 32; break; - case 284 : maxhelditemdur = 32; break; - case 285 : maxhelditemdur = 32; break; - case 286 : maxhelditemdur = 32; break; - case 290 : maxhelditemdur = 60; break; - case 291 : maxhelditemdur = 132; break; - case 292 : maxhelditemdur = 251; break; - case 293 : maxhelditemdur = 1563; break; - case 294 : maxhelditemdur = 32; break; - case 359 : maxhelditemdur = 251; break; - } - m_Player->GetInventory().GetEquippedItem().m_ItemHealth ++; - LOG("Health: %i", m_Player->GetInventory().GetEquippedItem().m_ItemHealth); - if (m_Player->GetInventory().GetEquippedItem().m_ItemHealth >= maxhelditemdur) - { - LOG("Player %s Broke ID: %i", GetUsername(), m_Player->GetInventory().GetEquippedItem().m_ItemID); - m_Player->GetInventory().RemoveItem( m_Player->GetInventory().GetEquippedItem()); - } - } + + m_Player->UseEquippedItem(); } } } @@ -901,6 +849,7 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) char MetaData = (char)Equipped.m_ItemHealth; bool LavaBucket = false; bool WaterBucket = false; + bool bRemoveItem = true; switch( PacketData->m_ItemType ) // Special handling for special items { @@ -1022,6 +971,11 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) PacketData->m_ItemType = E_BLOCK_WALLSIGN; } break; + case E_ITEM_FLINT_AND_STEEL: + PacketData->m_ItemType = E_ITEM_FIRE; + m_Player->UseEquippedItem(); + bRemoveItem = false; + break; default: break; }; @@ -1058,23 +1012,28 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) break; //happens when you place a block aiming at side of block like torch or stem } - if( (m_Player->GetGameMode() == 1) || (m_Player->GetInventory().RemoveItem( Item )) ) + if(bRemoveItem) { - if (isDoor) { - if ( ( m_Player->GetWorld()->GetBlock( X, Y+1, Z ) == E_BLOCK_AIR ) || ( m_Player->GetWorld()->GetBlock( X, Y+1, Z ) == E_BLOCK_AIR ) ) { - m_Player->GetWorld()->SetBlock( X, Y+1, Z, (char)PacketData->m_ItemType, MetaData + 8 ); - - m_Player->GetWorld()->SetBlock( X, Y, Z, (char)PacketData->m_ItemType, MetaData ); - } - } else { + if((m_Player->GetGameMode() != 1) && !m_Player->GetInventory().RemoveItem( Item )) + break; + } + if (isDoor) + { + if ( ( m_Player->GetWorld()->GetBlock( X, Y+1, Z ) == E_BLOCK_AIR ) || ( m_Player->GetWorld()->GetBlock( X, Y+1, Z ) == E_BLOCK_AIR ) ) + { + m_Player->GetWorld()->SetBlock( X, Y+1, Z, (char)PacketData->m_ItemType, MetaData + 8 ); m_Player->GetWorld()->SetBlock( X, Y, Z, (char)PacketData->m_ItemType, MetaData ); } - if (UpdateRedstone) { - cRedstone Redstone(m_Player->GetWorld()); - Redstone.ChangeRedstone( PacketData->m_PosX, PacketData->m_PosY+1, PacketData->m_PosZ, AddedCurrent ); - } + } else { + m_Player->GetWorld()->SetBlock( X, Y, Z, (char)PacketData->m_ItemType, MetaData ); + } + if (UpdateRedstone) + { + cRedstone Redstone(m_Player->GetWorld()); + Redstone.ChangeRedstone( PacketData->m_PosX, PacketData->m_PosY+1, PacketData->m_PosZ, AddedCurrent ); } + } } /* diff --git a/source/cFireSimulator.cpp b/source/cFireSimulator.cpp new file mode 100644 index 000000000..180ac9744 --- /dev/null +++ b/source/cFireSimulator.cpp @@ -0,0 +1,124 @@ +#include "cFireSimulator.h" +#include "cWorld.h" +#include "Vector3i.h" +#include "BlockID.h" +#include "Defines.h" +#include + +cFireSimulator::cFireSimulator( cWorld* a_World ) + : cSimulator(a_World) + , m_Blocks(new std::vector ) + , m_Buffer(new std::vector ) + , m_BurningBlocks(new std::vector ) +{ + +} + +cFireSimulator::~cFireSimulator() +{ + delete m_Buffer; + delete m_Blocks; + delete m_BurningBlocks; +} + +void cFireSimulator::Simulate( float a_Dt ) +{ + m_Buffer->clear(); + std::swap( m_Blocks, m_Buffer ); + + for( std::vector::iterator itr = m_Buffer->begin(); itr != m_Buffer->end(); ++itr ) + { + Vector3i *Pos = *itr; + + if(!IsAllowedBlock(m_World->GetBlock(Pos->x, Pos->y, Pos->z))) //Check wheather the block is still burning + continue; + + if(BurnBlockAround(Pos->x, Pos->y, Pos->z)) //Burn single block and if there was one -> next time again + _AddBlock(Pos->x, Pos->y, Pos->z); + else + if(!IsForeverBurnable(m_World->GetBlock(Pos->x, Pos->y - 1, Pos->z))) + m_World->SetBlock(Pos->x, Pos->y, Pos->z, E_BLOCK_AIR, 0); + + } + +} + + +bool cFireSimulator::IsAllowedBlock( char a_BlockID ) +{ + return a_BlockID == E_BLOCK_FIRE + || IsBlockLava(a_BlockID); +} + +void cFireSimulator::AddBlock(int a_X, int a_Y, int a_Z) +{ + char BlockID = m_World->GetBlock(a_X, a_Y, a_Z); + if(!IsAllowedBlock(BlockID)) //This should save very much time because it doesn´t have to iterate through all blocks + return; + + //check for duplicates + for( std::vector::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr ) + { + Vector3i *Pos = *itr; + if( Pos->x == a_X && Pos->y == a_Y && Pos->z == a_Z ) + return; + } + + _AddBlock(a_X, a_Y, a_Z); + +} + +void cFireSimulator::_AddBlock(int a_X, int a_Y, int a_Z) +{ + Vector3i *Block = new Vector3i(a_X, a_Y, a_Z); + m_Blocks->push_back(Block); + +} + +bool cFireSimulator::IsForeverBurnable( char a_BlockID ) +{ + return a_BlockID == E_BLOCK_BLOODSTONE; +} + +bool cFireSimulator::IsBurnable( char a_BlockID ) +{ + return a_BlockID == E_BLOCK_WOOD + || a_BlockID == E_BLOCK_LEAVES + || a_BlockID == E_BLOCK_LOG + || a_BlockID == E_BLOCK_WHITE_CLOTH + || a_BlockID == E_BLOCK_BOOKCASE + || a_BlockID == E_BLOCK_FENCE + || a_BlockID == E_BLOCK_TNT; +} + +bool cFireSimulator::BurnBlockAround(int a_X, int a_Y, int a_Z) +{ + return BurnBlock(a_X + 1, a_Y, a_Z) + || BurnBlock(a_X - 1, a_Y, a_Z) + || BurnBlock(a_X, a_Y + 1, a_Z) + || BurnBlock(a_X, a_Y - 1, a_Z) + || BurnBlock(a_X, a_Y, a_Z + 1) + || BurnBlock(a_X, a_Y, a_Z - 1); +} + +bool cFireSimulator::BurnBlock(int a_X, int a_Y, int a_Z) +{ + char BlockID = m_World->GetBlock(a_X, a_Y, a_Z); + if(IsBurnable(BlockID)) + { + m_World->SetBlock(a_X, a_Y, a_Z, E_BLOCK_FIRE, 0); + return true; + } + if(IsForeverBurnable(BlockID)) + { + char BlockAbove = m_World->GetBlock(a_X, a_Y + 1, a_Z); + if(BlockAbove == E_BLOCK_AIR) + { + m_World->SetBlock(a_X, a_Y + 1, a_Z, E_BLOCK_FIRE, 0); //Doesn´t notify the simulator so it won´t go off + return true; + } + return false; + } + + return false; +} \ No newline at end of file diff --git a/source/cFireSimulator.h b/source/cFireSimulator.h new file mode 100644 index 000000000..b6ac627fb --- /dev/null +++ b/source/cFireSimulator.h @@ -0,0 +1,31 @@ +#pragma once +#include "cSimulator.h" +#include "cBlockEntity.h" +#include "vector" + +class Vector3i; +class cWorld; +class cFireSimulator : public cSimulator +{ +public: + cFireSimulator( cWorld* a_World ); + ~cFireSimulator(); + + virtual void Simulate( float a_Dt ); + + virtual inline bool IsAllowedBlock( char a_BlockID ); + virtual inline bool IsBurnable( char a_BlockID ); + + virtual inline bool IsForeverBurnable( char a_BlockID ); + +protected: + virtual void AddBlock(int a_X, int a_Y, int a_Z); + virtual void _AddBlock(int a_X, int a_Y, int a_Z); + virtual inline bool BurnBlockAround(int a_X, int a_Y, int a_Z); + virtual inline bool BurnBlock(int a_X, int a_Y, int a_Z); + + std::vector *m_Blocks; + std::vector *m_Buffer; + + std::vector *m_BurningBlocks; +}; \ No newline at end of file diff --git a/source/cItem.cpp b/source/cItem.cpp index 20720a6e8..1233f1287 100644 --- a/source/cItem.cpp +++ b/source/cItem.cpp @@ -41,4 +41,4 @@ bool cItem::IsEnchantable(ENUM_ITEM_ID item) return false; -} \ No newline at end of file +} diff --git a/source/cItem.h b/source/cItem.h index c58079e87..c1b62495e 100644 --- a/source/cItem.h +++ b/source/cItem.h @@ -33,6 +33,58 @@ public: return ( (m_ItemID == a_Item.m_ItemID) && (m_ItemHealth == a_Item.m_ItemHealth) ); } //tolua_export + //TODO Sorry for writing the functions in the header. But somehow it doesn´t worked when I put them into the cpp File :s + + inline int GetMaxDuration() + { + switch(m_ItemID) + { + case 256: return 251; + case 257: return 251; + case 258: return 251; + case 259: return 65; //Lighter / Flint and Steel + case 267: return 251; + case 268: return 60; + case 269: return 60; + case 270: return 60; + case 271: return 60; + case 272: return 132; + case 273: return 132; + case 274: return 132; + case 275: return 132; + case 276: return 1563; + case 277: return 1563; + case 278: return 1563; + case 279: return 1563; + case 283: return 32; + case 284: return 32; + case 285: return 32; + case 286: return 32; + case 290: return 60; + case 291: return 132; + case 292: return 251; + case 293: return 1563; + case 294: return 32; + case 359: return 251; + default: return 0; + } + } + + //Damages a weapon. Returns true when destroyed + inline bool DamageItem() { + if(HasDuration()) + { + m_ItemHealth++; + + if(m_ItemHealth >= GetMaxDuration()) + return true; + + } + return false; + } + + inline bool HasDuration() { return GetMaxDuration() > 0; } + void GetJson( Json::Value & a_OutValue ); //tolua_export void FromJson( const Json::Value & a_Value ); //tolua_export @@ -41,4 +93,5 @@ public: ENUM_ITEM_ID m_ItemID; //tolua_export char m_ItemCount; //tolua_export short m_ItemHealth; //tolua_export + }; //tolua_export \ No newline at end of file diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index 7fbf1672b..92b16478a 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -830,4 +830,14 @@ const cPlayer::GroupList & cPlayer::GetGroups() const char* cPlayer::GetLoadedWorldName() { return m_pState->LoadedWorldName.c_str(); +} + +void cPlayer::UseEquippedItem() +{ + if(GetGameMode() != 1) //No damage in creative + if (GetInventory().GetEquippedItem().DamageItem()) + { + LOG("Player %s Broke ID: %i", GetClientHandle()->GetUsername(), GetInventory().GetEquippedItem().m_ItemID); + GetInventory().RemoveItem( GetInventory().GetEquippedItem()); + } } \ No newline at end of file diff --git a/source/cPlayer.h b/source/cPlayer.h index b0d446434..9f7535d7c 100644 --- a/source/cPlayer.h +++ b/source/cPlayer.h @@ -81,6 +81,8 @@ public: bool LoadFromDisk(); const char* GetLoadedWorldName(); + + void UseEquippedItem(); protected: diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 7e847d32c..501f78332 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -16,6 +16,7 @@ #include "cSimulatorManager.h" #include "cWaterSimulator.h" #include "cLavaSimulator.h" +#include "cFireSimulator.h" #include "cSandSimulator.h" #include "cChicken.h" #include "cSpider.h" @@ -126,6 +127,7 @@ cWorld::~cWorld() delete m_SandSimulator; delete m_WaterSimulator; delete m_LavaSimulator; + delete m_FireSimulator; UnloadUnusedChunks(); delete m_pState->pChunkGenerator; @@ -240,11 +242,13 @@ cWorld::cWorld( const char* a_WorldName ) m_WaterSimulator = new cWaterSimulator( this ); m_LavaSimulator = new cLavaSimulator( this ); m_SandSimulator = new cSandSimulator(this); + m_FireSimulator = new cFireSimulator(this); m_SimulatorManager = new cSimulatorManager(); m_SimulatorManager->RegisterSimulator(m_WaterSimulator, 6); m_SimulatorManager->RegisterSimulator(m_LavaSimulator, 12); m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1); + m_SimulatorManager->RegisterSimulator(m_FireSimulator, 10); memset( g_BlockLightValue, 0x0, 128 ); memset( g_BlockSpreadLightFalloff, 0xf, 128 ); // 0xf means total falloff @@ -299,6 +303,7 @@ cWorld::cWorld( const char* a_WorldName ) g_BlockOneHitDig[ E_BLOCK_REDSTONE_REPEATER_OFF ] = true; g_BlockOneHitDig[ E_BLOCK_REDSTONE_REPEATER_ON ] = true; g_BlockOneHitDig[ E_BLOCK_LOCKED_CHEST ] = true; + g_BlockOneHitDig [ E_BLOCK_FIRE ] = true; // Blocks that breaks when pushed by piston g_BlockPistonBreakable[ E_BLOCK_AIR ] = true; @@ -730,13 +735,15 @@ cChunk* cWorld::GetChunkOfBlock( int a_X, int a_Y, int a_Z ) void cWorld::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ) { - this->GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z); - - int ChunkX, ChunkY, ChunkZ; - AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); + int ChunkX, ChunkY, ChunkZ, X = a_X, Y = a_Y, Z = a_Z; + AbsoluteToRelative( X, Y, Z, ChunkX, ChunkY, ChunkZ ); cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - if( Chunk ) Chunk->SetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta ); + if( Chunk ) + { + Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta ); + this->GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z); + } } void cWorld::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ) diff --git a/source/cWorld.h b/source/cWorld.h index 72c6975d1..47c60fb87 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -16,6 +16,7 @@ enum ENUM_ITEM_ID; class cPacket; class cRedstone; +class cFireSimulator; class cWaterSimulator; class cLavaSimulator; class cSandSimulator; @@ -184,6 +185,7 @@ private: cSandSimulator *m_SandSimulator; cWaterSimulator* m_WaterSimulator; cLavaSimulator* m_LavaSimulator; + cFireSimulator* m_FireSimulator; cCriticalSection* m_ClientHandleCriticalSection; cCriticalSection* m_EntitiesCriticalSection; -- cgit v1.2.3