From c9c2a4f479474fe03acce598ba2687a0f4817083 Mon Sep 17 00:00:00 2001 From: JoannisO Date: Mon, 26 May 2014 08:44:16 +0200 Subject: [PATCH 01/48] Added Arrow- and FireCharge-Dispensing to DispenserEntity. --- src/BlockEntities/DispenserEntity.cpp | 107 +++++++++++++++++++++----- src/BlockEntities/DispenserEntity.h | 15 ++-- 2 files changed, 95 insertions(+), 27 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 2a32f69d9..7257513df 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -6,8 +6,10 @@ #include "../Simulator/FluidSimulator.h" #include "../Chunk.h" - - +#include "../World.h" +#include "../Entities/ArrowEntity.h" +#include "../Entities/FireChargeEntity.h" +#include "../Matrix4.h" cDispenserEntity::cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : @@ -69,7 +71,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) } break; } // E_ITEM_BUCKET - + case E_ITEM_WATER_BUCKET: { LOGD("Dispensing water bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); @@ -83,7 +85,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) } break; } - + case E_ITEM_LAVA_BUCKET: { LOGD("Dispensing lava bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); @@ -97,7 +99,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) } break; } - + case E_ITEM_SPAWN_EGG: { double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); @@ -108,7 +110,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) } break; } - + case E_BLOCK_TNT: { // Spawn a primed TNT entity, if space allows: @@ -128,7 +130,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_FIRE, 0); - + bool ItemBroke = m_Contents.DamageItem(a_SlotNum, 1); if (ItemBroke) @@ -138,13 +140,63 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) } break; } - + case E_ITEM_FIRE_CHARGE: { - // TODO: Spawn fireball entity + Vector3d Speed = GetProjectileLookVector(a_Chunk); + + double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); + double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); + + + cFireChargeEntity* fireCharge = new cFireChargeEntity(NULL /*was this*/, MobX, (double) DispY + 0.3, MobZ, Speed); + + + if (fireCharge == NULL) + { + break; + } + if (!fireCharge->Initialize(m_World)) + { + + delete fireCharge; + break; + } + m_World->BroadcastSpawnEntity(*fireCharge); + + m_Contents.ChangeSlotCount(a_SlotNum, -1); + break; } - + + case E_ITEM_ARROW: + { + Vector3d Speed = GetProjectileLookVector(a_Chunk); + + double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); + double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); + + + cArrowEntity* Arrow = new cArrowEntity(NULL /*was this*/, MobX, (double) DispY + 0.3, MobZ, Speed); + + + if (Arrow == NULL) + { + break; + } + if (!Arrow->Initialize(m_World)) + { + + delete Arrow; + break; + } + m_World->BroadcastSpawnEntity(*Arrow); + + m_Contents.ChangeSlotCount(a_SlotNum, -1); + + break; + } + default: { DropFromSlot(a_Chunk, a_SlotNum); @@ -154,8 +206,29 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) } +Vector3d cDispenserEntity::GetProjectileLookVector(cChunk & a_Chunk) +{ + NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); + int Direction = 0; + switch (Meta) + { + case E_META_DROPSPENSER_FACING_YP: Direction = 0; break; // YP & YM don't have associated smoke dirs, just do 4 (centre of block) + case E_META_DROPSPENSER_FACING_YM: Direction = 0; break; + case E_META_DROPSPENSER_FACING_XM: Direction = 90; break; // WEST + case E_META_DROPSPENSER_FACING_XP: Direction = 270; break; // EAST + case E_META_DROPSPENSER_FACING_ZM: Direction = 180; break; + case E_META_DROPSPENSER_FACING_ZP: Direction = 0; break; + } + Matrix4d m; + m.Init(Vector3d(), 0, Direction, 0); + Vector3d Look = m.Transform(Vector3d(0, 0, 1)); + Vector3d Speed = Look * 20; + Speed.y = Speed.y + 1; + + return Speed; +} bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_BucketItemType) @@ -167,14 +240,14 @@ bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_BucketItemType) m_Contents.SetSlot(a_SlotNum, LiquidBucket); return true; } - + // There are stacked buckets at the selected slot, see if a full bucket will fit somewhere else if (m_Contents.HowManyCanFit(LiquidBucket) < 1) { // Cannot fit into m_Contents return false; } - + m_Contents.ChangeSlotCount(a_SlotNum, -1); m_Contents.AddItem(LiquidBucket); return true; @@ -195,7 +268,7 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum // Not a suitable block in front return false; } - + cItem EmptyBucket(E_ITEM_BUCKET, 1); if (m_Contents.GetSlot(a_SlotNum).m_ItemCount == 1) { @@ -203,20 +276,16 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum m_Contents.SetSlot(a_SlotNum, EmptyBucket); return true; } - + // There are full buckets stacked at this slot, check if we can fit in the empty bucket if (m_Contents.HowManyCanFit(EmptyBucket) < 1) { // The empty bucket wouldn't fit into m_Contents return false; } - + // The empty bucket fits in, remove one full bucket and add the empty one m_Contents.ChangeSlotCount(a_SlotNum, -1); m_Contents.AddItem(EmptyBucket); return true; } - - - - diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index fdfe4e5b4..02a34be37 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -12,11 +12,11 @@ class cDispenserEntity : public cDropSpenserEntity { typedef cDropSpenserEntity super; - + public: // tolua_end - + /// Constructor used for normal operation cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); @@ -25,14 +25,13 @@ public: private: // cDropSpenser overrides: virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) override; - + /// If such a bucket can fit, adds it to m_Contents and returns true bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType); - + + // Returns how to aim the projectile + Vector3d GetProjectileLookVector(cChunk & a_Chunk); + /// If the a_BlockInFront is liquidable and the empty bucket can fit, does the m_Contents processing and returns true bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum); } ; // tolua_export - - - - From 74801f564775ae4c6b70834f76167a54b8a84826 Mon Sep 17 00:00:00 2001 From: JoannisO Date: Mon, 26 May 2014 14:47:04 +0200 Subject: [PATCH 02/48] - Added support for more types of projectiles in the Dispenser - Improved the method of spawning projectiles in the world - Added another method for spawning the projectiles --- src/BlockEntities/DispenserEntity.cpp | 82 ++++++++++++++------------- src/BlockEntities/DispenserEntity.h | 7 +++ 2 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 7257513df..e2032a041 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -9,9 +9,12 @@ #include "../World.h" #include "../Entities/ArrowEntity.h" #include "../Entities/FireChargeEntity.h" +#include "../Entities/ProjectileEntity.h" #include "../Matrix4.h" + + cDispenserEntity::cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : super(E_BLOCK_DISPENSER, a_BlockX, a_BlockY, a_BlockZ, a_World) { @@ -143,56 +146,37 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { - Vector3d Speed = GetProjectileLookVector(a_Chunk); - - double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); - double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - - - cFireChargeEntity* fireCharge = new cFireChargeEntity(NULL /*was this*/, MobX, (double) DispY + 0.3, MobZ, Speed); - - - if (fireCharge == NULL) - { - break; - } - if (!fireCharge->Initialize(m_World)) - { - - delete fireCharge; - break; - } - m_World->BroadcastSpawnEntity(*fireCharge); - - m_Contents.ChangeSlotCount(a_SlotNum, -1); + spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge); break; } case E_ITEM_ARROW: { - Vector3d Speed = GetProjectileLookVector(a_Chunk); + spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow); - double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); - double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); + break; + } + case E_ITEM_SNOWBALL: + { + // Not working as there is no such entity yet? + spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball); - cArrowEntity* Arrow = new cArrowEntity(NULL /*was this*/, MobX, (double) DispY + 0.3, MobZ, Speed); + break; + } + case E_ITEM_EGG: + { + // Not working as there is no such entity yet? + spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg); - if (Arrow == NULL) - { - break; - } - if (!Arrow->Initialize(m_World)) - { + break; + } - delete Arrow; - break; - } - m_World->BroadcastSpawnEntity(*Arrow); - - m_Contents.ChangeSlotCount(a_SlotNum, -1); + case E_ITEM_FIREWORK_ROCKET: + { + spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFirework); break; } @@ -206,6 +190,20 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) } + +void cDispenserEntity::spawnProjectileFromDispenser(cChunk& a_Chunk, int& DispX, int& DispY, int& DispZ, cProjectileEntity::eKind kind) +{ + Vector3d Speed = GetProjectileLookVector(a_Chunk); + cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); + + double EntityX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); + double EntityZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); + + m_World->CreateProjectile((double) EntityX, (double) DispY, (double) EntityZ, cProjectileEntity::pkArrow, NULL, NULL, &Speed); +} + + + Vector3d cDispenserEntity::GetProjectileLookVector(cChunk & a_Chunk) { NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); @@ -231,6 +229,10 @@ Vector3d cDispenserEntity::GetProjectileLookVector(cChunk & a_Chunk) } + + + + bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_BucketItemType) { cItem LiquidBucket(a_BucketItemType, 1); @@ -289,3 +291,7 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum m_Contents.AddItem(EmptyBucket); return true; } + + + + diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 02a34be37..9290bee5c 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -29,9 +29,16 @@ private: /// If such a bucket can fit, adds it to m_Contents and returns true bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType); + // Spawns a projectile of the given kind in front of the dispenser + void spawnProjectileFromDispenser(cChunk& a_Chunk, int& DispX, int& DispY, int& DispZ, cProjectileEntity::eKind kind); + // Returns how to aim the projectile Vector3d GetProjectileLookVector(cChunk & a_Chunk); /// If the a_BlockInFront is liquidable and the empty bucket can fit, does the m_Contents processing and returns true bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum); } ; // tolua_export + + + + From 1128dc783f4ee0913f3395c0a79ebdbbce2cfdee Mon Sep 17 00:00:00 2001 From: Joannis Date: Tue, 27 May 2014 11:08:06 +0200 Subject: [PATCH 03/48] - Fixed the ampersands and asterisks to fit the format. - Fixed the method "SpawnProjectileFromDispenser" to use CamelCasing. --- src/BlockEntities/DispenserEntity.cpp | 14 +++++++------- src/BlockEntities/DispenserEntity.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index e2032a041..0f64118ef 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -146,14 +146,14 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { - spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge); + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge); break; } case E_ITEM_ARROW: { - spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow); + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow); break; } @@ -161,7 +161,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_SNOWBALL: { // Not working as there is no such entity yet? - spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball); + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball); break; } @@ -169,14 +169,14 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_EGG: { // Not working as there is no such entity yet? - spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg); + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg); break; } case E_ITEM_FIREWORK_ROCKET: { - spawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFirework); + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFirework); break; } @@ -191,7 +191,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) -void cDispenserEntity::spawnProjectileFromDispenser(cChunk& a_Chunk, int& DispX, int& DispY, int& DispZ, cProjectileEntity::eKind kind) +void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & DispX, int & DispY, int & DispZ, cProjectileEntity::eKind kind) { Vector3d Speed = GetProjectileLookVector(a_Chunk); cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); @@ -199,7 +199,7 @@ void cDispenserEntity::spawnProjectileFromDispenser(cChunk& a_Chunk, int& DispX, double EntityX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double EntityZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - m_World->CreateProjectile((double) EntityX, (double) DispY, (double) EntityZ, cProjectileEntity::pkArrow, NULL, NULL, &Speed); + m_World->CreateProjectile((double) EntityX, (double) DispY, (double) EntityZ, cProjectileEntity::pkArrow, NULL, NULL, & Speed); } diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 9290bee5c..8bc2475c9 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -30,7 +30,7 @@ private: bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType); // Spawns a projectile of the given kind in front of the dispenser - void spawnProjectileFromDispenser(cChunk& a_Chunk, int& DispX, int& DispY, int& DispZ, cProjectileEntity::eKind kind); + void SpawnProjectileFromDispenser(cChunk& a_Chunk, int& DispX, int& DispY, int& DispZ, cProjectileEntity::eKind kind); // Returns how to aim the projectile Vector3d GetProjectileLookVector(cChunk & a_Chunk); From e5fd782524cdf4b838ad689baef44a61aa4933c2 Mon Sep 17 00:00:00 2001 From: Joannis Date: Wed, 28 May 2014 09:10:09 +0200 Subject: [PATCH 04/48] - Implemented vertical dispensing for projectiles. - Fixed some terrible commit issues on my side. --- src/BlockEntities/DispenserEntity.cpp | 54 +++++++++++++++++++-------- src/BlockEntities/DispenserEntity.h | 2 +- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 0f64118ef..638a844e6 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -147,6 +147,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge); + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } @@ -154,6 +155,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_ARROW: { SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow); + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } @@ -162,6 +164,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { // Not working as there is no such entity yet? SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball); + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } @@ -170,6 +173,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { // Not working as there is no such entity yet? SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg); + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } @@ -177,6 +181,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIREWORK_ROCKET: { SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFirework); + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } @@ -199,7 +204,7 @@ void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & Disp double EntityX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double EntityZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - m_World->CreateProjectile((double) EntityX, (double) DispY, (double) EntityZ, cProjectileEntity::pkArrow, NULL, NULL, & Speed); + m_World->CreateProjectile((double) EntityX, (double) DispY + 0.5, (double) EntityZ, cProjectileEntity::pkArrow, NULL, NULL, &Speed); } @@ -210,22 +215,45 @@ Vector3d cDispenserEntity::GetProjectileLookVector(cChunk & a_Chunk) int Direction = 0; switch (Meta) { - case E_META_DROPSPENSER_FACING_YP: Direction = 0; break; // YP & YM don't have associated smoke dirs, just do 4 (centre of block) - case E_META_DROPSPENSER_FACING_YM: Direction = 0; break; - case E_META_DROPSPENSER_FACING_XM: Direction = 90; break; // WEST - case E_META_DROPSPENSER_FACING_XP: Direction = 270; break; // EAST + case E_META_DROPSPENSER_FACING_YP: Direction = -1; break; // UP + case E_META_DROPSPENSER_FACING_YM: Direction = -2; break; // DOWN + case E_META_DROPSPENSER_FACING_XM: Direction = 90; break; // WEST + case E_META_DROPSPENSER_FACING_XP: Direction = 270; break; // EAST case E_META_DROPSPENSER_FACING_ZM: Direction = 180; break; case E_META_DROPSPENSER_FACING_ZP: Direction = 0; break; } - Matrix4d m; - m.Init(Vector3d(), 0, Direction, 0); - Vector3d Look = m.Transform(Vector3d(0, 0, 1)); + if(Direction >= 0) + { + Matrix4d m; + m.Init(Vector3d(), 0, Direction, 0); + Vector3d Look = m.Transform(Vector3d(0, 0, 1)); - Vector3d Speed = Look * 20; - Speed.y = Speed.y + 1; + Vector3d Speed = Look * 20; + Speed.y = Speed.y + 1; - return Speed; + return Speed; + + } else if(Direction == -1) + { + Matrix4d m; + m.Init(Vector3d(), 0, 180, 0); + Vector3d Look = m.Transform(Vector3d(0, 1, 0)); + + Vector3d Speed = Look * 20; + + return Speed; + + } else { + + Matrix4d m; + m.Init(Vector3d(), 0, -360, 0); + Vector3d Look = m.Transform(Vector3d(0, -1, 0)); + + Vector3d Speed = Look * 20; + + return Speed; + } } @@ -291,7 +319,3 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum m_Contents.AddItem(EmptyBucket); return true; } - - - - diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 8bc2475c9..0b7cd6bea 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -30,7 +30,7 @@ private: bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType); // Spawns a projectile of the given kind in front of the dispenser - void SpawnProjectileFromDispenser(cChunk& a_Chunk, int& DispX, int& DispY, int& DispZ, cProjectileEntity::eKind kind); + void SpawnProjectileFromDispenser(cChunk & a_Chunk, int & DispX, int & DispY, int & DispZ, cProjectileEntity::eKind kind); // Returns how to aim the projectile Vector3d GetProjectileLookVector(cChunk & a_Chunk); From 4bc02781af063456db438885d7f3cc8830d5cd92 Mon Sep 17 00:00:00 2001 From: JoannisO Date: Wed, 28 May 2014 14:34:33 +0200 Subject: [PATCH 05/48] - Fixed an issue where dispensers would only shoot arrows (appearantly some commits didn't come through) - Cleaned up the code according to suggestions. --- src/BlockEntities/DispenserEntity.cpp | 57 +++++++++++---------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 638a844e6..2b0487c4a 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -198,13 +198,13 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & DispX, int & DispY, int & DispZ, cProjectileEntity::eKind kind) { - Vector3d Speed = GetProjectileLookVector(a_Chunk); + Vector3d Angle = GetProjectileLookVector(a_Chunk); cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); double EntityX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double EntityZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - m_World->CreateProjectile((double) EntityX, (double) DispY + 0.5, (double) EntityZ, cProjectileEntity::pkArrow, NULL, NULL, &Speed); + m_World->CreateProjectile((double) EntityX, (double) DispY + 0.5, (double) EntityZ, kind, NULL, NULL, &Angle); } @@ -213,47 +213,38 @@ Vector3d cDispenserEntity::GetProjectileLookVector(cChunk & a_Chunk) { NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); int Direction = 0; + Matrix4d m; + Vector3d Look; + switch (Meta) { - case E_META_DROPSPENSER_FACING_YP: Direction = -1; break; // UP - case E_META_DROPSPENSER_FACING_YM: Direction = -2; break; // DOWN + case E_META_DROPSPENSER_FACING_YP: + m.Init(Vector3d(), 0, 180, 0); + Look = m.Transform(Vector3d(0, 1, 0)); + + return Look * 20; // UP + break; + + case E_META_DROPSPENSER_FACING_YM: + m.Init(Vector3d(), 0, -360, 0); + Look = m.Transform(Vector3d(0, -1, 0)); + + return Look * 20;; // DOWN + break; + case E_META_DROPSPENSER_FACING_XM: Direction = 90; break; // WEST case E_META_DROPSPENSER_FACING_XP: Direction = 270; break; // EAST case E_META_DROPSPENSER_FACING_ZM: Direction = 180; break; case E_META_DROPSPENSER_FACING_ZP: Direction = 0; break; } - if(Direction >= 0) - { - Matrix4d m; - m.Init(Vector3d(), 0, Direction, 0); - Vector3d Look = m.Transform(Vector3d(0, 0, 1)); + m.Init(Vector3d(), 0, Direction, 0); + Look = m.Transform(Vector3d(0, 0, 1)); - Vector3d Speed = Look * 20; - Speed.y = Speed.y + 1; + Vector3d Angle = Look * 20; + Angle.y = Angle.y + 1; - return Speed; - - } else if(Direction == -1) - { - Matrix4d m; - m.Init(Vector3d(), 0, 180, 0); - Vector3d Look = m.Transform(Vector3d(0, 1, 0)); - - Vector3d Speed = Look * 20; - - return Speed; - - } else { - - Matrix4d m; - m.Init(Vector3d(), 0, -360, 0); - Vector3d Look = m.Transform(Vector3d(0, -1, 0)); - - Vector3d Speed = Look * 20; - - return Speed; - } + return Angle; } From 427bddc18970bb66aa1f396c4fd19e52e3ad602d Mon Sep 17 00:00:00 2001 From: JoannisO Date: Wed, 28 May 2014 15:16:45 +0200 Subject: [PATCH 06/48] - Removed breaks. I thought it wouldn't compile without them but the issue was appearantly solved with an earlier commit. --- src/BlockEntities/DispenserEntity.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 2b0487c4a..341994be8 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -223,14 +223,12 @@ Vector3d cDispenserEntity::GetProjectileLookVector(cChunk & a_Chunk) Look = m.Transform(Vector3d(0, 1, 0)); return Look * 20; // UP - break; case E_META_DROPSPENSER_FACING_YM: m.Init(Vector3d(), 0, -360, 0); Look = m.Transform(Vector3d(0, -1, 0)); return Look * 20;; // DOWN - break; case E_META_DROPSPENSER_FACING_XM: Direction = 90; break; // WEST case E_META_DROPSPENSER_FACING_XP: Direction = 270; break; // EAST From ab633c8bd65b333630053334cb1119f38788698d Mon Sep 17 00:00:00 2001 From: JoannisO Date: Thu, 29 May 2014 20:19:36 +0200 Subject: [PATCH 07/48] - Prefixed all args with "a_" - Added braces around the cases. --- src/BlockEntities/DispenserEntity.cpp | 14 +++++++++----- src/BlockEntities/DispenserEntity.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 341994be8..799d41a1e 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -196,15 +196,15 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) -void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & DispX, int & DispY, int & DispZ, cProjectileEntity::eKind kind) +void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind) { Vector3d Angle = GetProjectileLookVector(a_Chunk); - cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); + cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(a_DispX, a_DispZ); - double EntityX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); - double EntityZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); + double EntityX = 0.5 + (a_DispX + DispChunk->GetPosX() * cChunkDef::Width); + double EntityZ = 0.5 + (a_DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - m_World->CreateProjectile((double) EntityX, (double) DispY + 0.5, (double) EntityZ, kind, NULL, NULL, &Angle); + m_World->CreateProjectile((double) EntityX, (double) a_DispY + 0.5, (double) EntityZ, a_kind, NULL, NULL, &Angle); } @@ -219,16 +219,20 @@ Vector3d cDispenserEntity::GetProjectileLookVector(cChunk & a_Chunk) switch (Meta) { case E_META_DROPSPENSER_FACING_YP: + { m.Init(Vector3d(), 0, 180, 0); Look = m.Transform(Vector3d(0, 1, 0)); return Look * 20; // UP + } case E_META_DROPSPENSER_FACING_YM: + { m.Init(Vector3d(), 0, -360, 0); Look = m.Transform(Vector3d(0, -1, 0)); return Look * 20;; // DOWN + } case E_META_DROPSPENSER_FACING_XM: Direction = 90; break; // WEST case E_META_DROPSPENSER_FACING_XP: Direction = 270; break; // EAST diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 0b7cd6bea..76aaccd3c 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -30,7 +30,7 @@ private: bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType); // Spawns a projectile of the given kind in front of the dispenser - void SpawnProjectileFromDispenser(cChunk & a_Chunk, int & DispX, int & DispY, int & DispZ, cProjectileEntity::eKind kind); + void SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind); // Returns how to aim the projectile Vector3d GetProjectileLookVector(cChunk & a_Chunk); From b436359237a9faa1dc5709e4359b73aa6faf4f78 Mon Sep 17 00:00:00 2001 From: JoannisO Date: Sat, 31 May 2014 16:08:15 +0200 Subject: [PATCH 08/48] - Changed the name of the ProjectileLookVector method. Note: I still think the new name is unclear. Any other suggestions are welcome. --- src/BlockEntities/DispenserEntity.cpp | 4 ++-- src/BlockEntities/DispenserEntity.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 799d41a1e..db1b405cd 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -198,7 +198,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind) { - Vector3d Angle = GetProjectileLookVector(a_Chunk); + Vector3d Angle = GetShootVector(a_Chunk); cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(a_DispX, a_DispZ); double EntityX = 0.5 + (a_DispX + DispChunk->GetPosX() * cChunkDef::Width); @@ -209,7 +209,7 @@ void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_Di -Vector3d cDispenserEntity::GetProjectileLookVector(cChunk & a_Chunk) +Vector3d cDispenserEntity::GetShootVector(cChunk & a_Chunk) { NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); int Direction = 0; diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 76aaccd3c..adbe2070c 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -33,7 +33,7 @@ private: void SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind); // Returns how to aim the projectile - Vector3d GetProjectileLookVector(cChunk & a_Chunk); + Vector3d GetShootVector(cChunk & a_Chunk); /// If the a_BlockInFront is liquidable and the empty bucket can fit, does the m_Contents processing and returns true bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum); From 545478802b7a8b81ecb9d20ad3355eff1427f575 Mon Sep 17 00:00:00 2001 From: Joannis Date: Tue, 3 Jun 2014 09:26:14 +0200 Subject: [PATCH 09/48] - Added doxy comments and exported to lua - Manipulation of the ShootVector is not to be done by the function that wants to spawn a projectile. --- src/BlockEntities/DispenserEntity.cpp | 74 +++++++++++++++++++++------ src/BlockEntities/DispenserEntity.h | 12 ++--- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index db1b405cd..043a140e3 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -146,7 +146,18 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge); + if(Meta == E_META_DROPSPENSER_FACING_YP || Meta == E_META_DROPSPENSER_FACING_YM) + { + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge, GetShootVector(a_Chunk) * 20); + } + else + { + Vector3d ShootVector = GetShootVector(a_Chunk); + ShootVector = ShootVector * 20; + + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge, ShootVector); + } + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -154,7 +165,19 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_ARROW: { - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow); + if(Meta == E_META_DROPSPENSER_FACING_YP || Meta == E_META_DROPSPENSER_FACING_YM) + { + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow, GetShootVector(a_Chunk) * 20); + } + else + { + Vector3d ShootVector = GetShootVector(a_Chunk); + ShootVector = ShootVector * 20; + ShootVector.y = ShootVector.y + 1; + + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow, ShootVector); + } + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -162,8 +185,19 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_SNOWBALL: { - // Not working as there is no such entity yet? - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball); + if(Meta == E_META_DROPSPENSER_FACING_YP || Meta == E_META_DROPSPENSER_FACING_YM) + { + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball, GetShootVector(a_Chunk) * 20); + } + else + { + Vector3d ShootVector = GetShootVector(a_Chunk); + ShootVector = ShootVector * 20; + ShootVector.y = ShootVector.y + 1; + + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball, ShootVector); + } + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -171,8 +205,19 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_EGG: { - // Not working as there is no such entity yet? - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg); + if(Meta == E_META_DROPSPENSER_FACING_YP || Meta == E_META_DROPSPENSER_FACING_YM) + { + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg, GetShootVector(a_Chunk) * 20); + } + else + { + Vector3d ShootVector = GetShootVector(a_Chunk); + ShootVector = ShootVector * 20; + ShootVector.y = ShootVector.y + 1; + + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg, ShootVector); + } + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -180,7 +225,8 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIREWORK_ROCKET: { - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFirework); + SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFirework, GetShootVector(a_Chunk) * 0); + m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -196,15 +242,14 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) -void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind) +void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector) { - Vector3d Angle = GetShootVector(a_Chunk); cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(a_DispX, a_DispZ); double EntityX = 0.5 + (a_DispX + DispChunk->GetPosX() * cChunkDef::Width); double EntityZ = 0.5 + (a_DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - m_World->CreateProjectile((double) EntityX, (double) a_DispY + 0.5, (double) EntityZ, a_kind, NULL, NULL, &Angle); + m_World->CreateProjectile((double) EntityX, (double) a_DispY + 0.5, (double) EntityZ, a_kind, NULL, NULL, &a_ShootVector); } @@ -223,7 +268,7 @@ Vector3d cDispenserEntity::GetShootVector(cChunk & a_Chunk) m.Init(Vector3d(), 0, 180, 0); Look = m.Transform(Vector3d(0, 1, 0)); - return Look * 20; // UP + return Look; // UP } case E_META_DROPSPENSER_FACING_YM: @@ -231,7 +276,7 @@ Vector3d cDispenserEntity::GetShootVector(cChunk & a_Chunk) m.Init(Vector3d(), 0, -360, 0); Look = m.Transform(Vector3d(0, -1, 0)); - return Look * 20;; // DOWN + return Look; // DOWN } case E_META_DROPSPENSER_FACING_XM: Direction = 90; break; // WEST @@ -243,10 +288,7 @@ Vector3d cDispenserEntity::GetShootVector(cChunk & a_Chunk) m.Init(Vector3d(), 0, Direction, 0); Look = m.Transform(Vector3d(0, 0, 1)); - Vector3d Angle = Look * 20; - Angle.y = Angle.y + 1; - - return Angle; + return Look; } diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index adbe2070c..558cf41c5 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -22,6 +22,12 @@ public: static const char * GetClassStatic(void) { return "cDispenserEntity"; } + /** Spawns a projectile of the given kind in front of the dispenser */ + void SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector); // tolua_export + + /** Returns how to aim the projectile */ + Vector3d GetShootVector(cChunk & a_Chunk); // tolua_export + private: // cDropSpenser overrides: virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) override; @@ -29,12 +35,6 @@ private: /// If such a bucket can fit, adds it to m_Contents and returns true bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType); - // Spawns a projectile of the given kind in front of the dispenser - void SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind); - - // Returns how to aim the projectile - Vector3d GetShootVector(cChunk & a_Chunk); - /// If the a_BlockInFront is liquidable and the empty bucket can fit, does the m_Contents processing and returns true bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum); } ; // tolua_export From daae75b30b7d5e70a26e1518cd7c75988dbfdf9f Mon Sep 17 00:00:00 2001 From: JoannisO Date: Tue, 3 Jun 2014 17:21:38 +0200 Subject: [PATCH 10/48] - Cleaned up the code massively - Stopped using cChunk in the GetShootVector class. Parameter is now the Metadata of the block - Stopped using cChunk in the SpawnProjectileFromDispenser method now using coordinates and finding the chunk by itself. - Removed the matrix calculations from GetShootVector. --- src/BlockEntities/DispenserEntity.cpp | 113 +++++++------------------- src/BlockEntities/DispenserEntity.h | 8 +- 2 files changed, 31 insertions(+), 90 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 043a140e3..2ac7c085c 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -146,17 +146,11 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { - if(Meta == E_META_DROPSPENSER_FACING_YP || Meta == E_META_DROPSPENSER_FACING_YM) - { - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge, GetShootVector(a_Chunk) * 20); - } - else - { - Vector3d ShootVector = GetShootVector(a_Chunk); - ShootVector = ShootVector * 20; + cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); + int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); + int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFireCharge, ShootVector); - } + SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20); m_Contents.ChangeSlotCount(a_SlotNum, -1); @@ -165,18 +159,11 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_ARROW: { - if(Meta == E_META_DROPSPENSER_FACING_YP || Meta == E_META_DROPSPENSER_FACING_YM) - { - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow, GetShootVector(a_Chunk) * 20); - } - else - { - Vector3d ShootVector = GetShootVector(a_Chunk); - ShootVector = ShootVector * 20; - ShootVector.y = ShootVector.y + 1; + cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); + int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); + int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkArrow, ShootVector); - } + SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20); m_Contents.ChangeSlotCount(a_SlotNum, -1); @@ -185,18 +172,11 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_SNOWBALL: { - if(Meta == E_META_DROPSPENSER_FACING_YP || Meta == E_META_DROPSPENSER_FACING_YM) - { - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball, GetShootVector(a_Chunk) * 20); - } - else - { - Vector3d ShootVector = GetShootVector(a_Chunk); - ShootVector = ShootVector * 20; - ShootVector.y = ShootVector.y + 1; + cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); + int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); + int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkSnowball, ShootVector); - } + SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20); m_Contents.ChangeSlotCount(a_SlotNum, -1); @@ -205,27 +185,18 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_EGG: { - if(Meta == E_META_DROPSPENSER_FACING_YP || Meta == E_META_DROPSPENSER_FACING_YM) - { - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg, GetShootVector(a_Chunk) * 20); - } - else - { - Vector3d ShootVector = GetShootVector(a_Chunk); - ShootVector = ShootVector * 20; - ShootVector.y = ShootVector.y + 1; + cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); + int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); + int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkEgg, ShootVector); - } - - m_Contents.ChangeSlotCount(a_SlotNum, -1); + SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20); break; } case E_ITEM_FIREWORK_ROCKET: { - SpawnProjectileFromDispenser(a_Chunk, DispX, DispY, DispZ, cProjectileEntity::pkFirework, GetShootVector(a_Chunk) * 0); + // TODO: Add the fireworks entity m_Contents.ChangeSlotCount(a_SlotNum, -1); @@ -242,60 +213,34 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) -void cDispenserEntity::SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector) +void cDispenserEntity::SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector) { - cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(a_DispX, a_DispZ); + if(a_kind != E_ITEM_FIRE_CHARGE) + a_ShootVector.y = a_ShootVector.y + 1; - double EntityX = 0.5 + (a_DispX + DispChunk->GetPosX() * cChunkDef::Width); - double EntityZ = 0.5 + (a_DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - - m_World->CreateProjectile((double) EntityX, (double) a_DispY + 0.5, (double) EntityZ, a_kind, NULL, NULL, &a_ShootVector); + m_World->CreateProjectile((double) a_BlockX + 0.5, (double) a_BlockY + 0.5, (double) a_BlockZ + 0.5, a_kind, NULL, NULL, &a_ShootVector); } - -Vector3d cDispenserEntity::GetShootVector(cChunk & a_Chunk) +Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE & a_Meta) { - NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); - int Direction = 0; - Matrix4d m; - Vector3d Look; - - switch (Meta) + switch(a_Meta) { - case E_META_DROPSPENSER_FACING_YP: - { - m.Init(Vector3d(), 0, 180, 0); - Look = m.Transform(Vector3d(0, 1, 0)); + case E_META_DROPSPENSER_FACING_YP: return Vector3d(0, 1, 0); // UP + case E_META_DROPSPENSER_FACING_YM: return Vector3d(0, -1, 0); // DOWN - return Look; // UP - } + case E_META_DROPSPENSER_FACING_XM: return Vector3d(-1, 0, 0); // WEST + case E_META_DROPSPENSER_FACING_XP: return Vector3d(1, 0, 0); // EAST - case E_META_DROPSPENSER_FACING_YM: - { - m.Init(Vector3d(), 0, -360, 0); - Look = m.Transform(Vector3d(0, -1, 0)); - - return Look; // DOWN - } - - case E_META_DROPSPENSER_FACING_XM: Direction = 90; break; // WEST - case E_META_DROPSPENSER_FACING_XP: Direction = 270; break; // EAST - case E_META_DROPSPENSER_FACING_ZM: Direction = 180; break; - case E_META_DROPSPENSER_FACING_ZP: Direction = 0; break; + case E_META_DROPSPENSER_FACING_ZM: return Vector3d(0, 0, -1); + case E_META_DROPSPENSER_FACING_ZP: return Vector3d(0, 0, 1); } - - m.Init(Vector3d(), 0, Direction, 0); - Look = m.Transform(Vector3d(0, 0, 1)); - - return Look; } - bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_BucketItemType) { cItem LiquidBucket(a_BucketItemType, 1); diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 558cf41c5..5a2de7965 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -23,10 +23,10 @@ public: static const char * GetClassStatic(void) { return "cDispenserEntity"; } /** Spawns a projectile of the given kind in front of the dispenser */ - void SpawnProjectileFromDispenser(cChunk & a_Chunk, int & a_DispX, int & a_DispY, int & a_DispZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector); // tolua_export + void SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector); /** Returns how to aim the projectile */ - Vector3d GetShootVector(cChunk & a_Chunk); // tolua_export + Vector3d GetShootVector(NIBBLETYPE & a_Meta); private: // cDropSpenser overrides: @@ -38,7 +38,3 @@ private: /// If the a_BlockInFront is liquidable and the empty bucket can fit, does the m_Contents processing and returns true bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum); } ; // tolua_export - - - - From 2ecf425c39452a96398346d114525eeff7cbf50a Mon Sep 17 00:00:00 2001 From: JoannisO Date: Tue, 3 Jun 2014 18:19:06 +0200 Subject: [PATCH 11/48] - Fixed a bug where I used the FireCharge ITEM instead of the Projectile ENUM --- src/BlockEntities/DispenserEntity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 2ac7c085c..904ab871b 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -215,7 +215,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) void cDispenserEntity::SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector) { - if(a_kind != E_ITEM_FIRE_CHARGE) + if(a_kind != cProjectileEntity::pkFireCharge) a_ShootVector.y = a_ShootVector.y + 1; m_World->CreateProjectile((double) a_BlockX + 0.5, (double) a_BlockY + 0.5, (double) a_BlockZ + 0.5, a_kind, NULL, NULL, &a_ShootVector); From c0716bfcf6cce720f41e98544eb4a4532a694a0a Mon Sep 17 00:00:00 2001 From: JoannisO Date: Tue, 3 Jun 2014 19:39:56 +0200 Subject: [PATCH 12/48] - Fixed a bug where I didn't return anything in the GetShootVector function. This was however passed as "working" by GCC. --- src/BlockEntities/DispenserEntity.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 904ab871b..bbf924417 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -235,6 +235,8 @@ Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE & a_Meta) case E_META_DROPSPENSER_FACING_ZM: return Vector3d(0, 0, -1); case E_META_DROPSPENSER_FACING_ZP: return Vector3d(0, 0, 1); } + + return Vector3d(0, 1, 0); } From 7993caa553e3317da21763226bf6bd5c2e965f8c Mon Sep 17 00:00:00 2001 From: JoannisO Date: Tue, 3 Jun 2014 19:43:15 +0200 Subject: [PATCH 13/48] - Fixed an issue where there were 2 "DispChunk"-s in the same function. Resused the initial one. --- src/BlockEntities/DispenserEntity.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index bbf924417..a4a660034 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -38,7 +38,10 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) // Would dispense into / interact with a non-loaded chunk, ignore the tick return; } + BLOCKTYPE DispBlock = DispChunk->GetBlock(DispX, DispY, DispZ); + int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); + int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); // Dispense the item: switch (m_Contents.GetSlot(a_SlotNum).m_ItemType) @@ -146,10 +149,6 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { - cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); - int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); - int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20); m_Contents.ChangeSlotCount(a_SlotNum, -1); @@ -159,10 +158,6 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_ARROW: { - cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); - int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); - int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20); m_Contents.ChangeSlotCount(a_SlotNum, -1); @@ -172,10 +167,6 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_SNOWBALL: { - cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); - int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); - int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20); m_Contents.ChangeSlotCount(a_SlotNum, -1); @@ -185,12 +176,10 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_EGG: { - cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); - int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); - int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20); + m_Contents.ChangeSlotCount(a_SlotNum, -1); + break; } From 2c103a713e0ce77ccb8b86c98e2571d5ba6dd9c0 Mon Sep 17 00:00:00 2001 From: JoannisO Date: Wed, 4 Jun 2014 12:35:45 +0200 Subject: [PATCH 14/48] - Fixed a lot of astethics --- src/BlockEntities/DispenserEntity.cpp | 26 +++++++++++++------------- src/BlockEntities/DispenserEntity.h | 5 ++++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index a4a660034..242ac4024 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -10,7 +10,6 @@ #include "../Entities/ArrowEntity.h" #include "../Entities/FireChargeEntity.h" #include "../Entities/ProjectileEntity.h" -#include "../Matrix4.h" @@ -150,7 +149,6 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20); - m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -159,7 +157,6 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_ARROW: { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20); - m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -168,7 +165,6 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_SNOWBALL: { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20); - m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -177,7 +173,6 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_EGG: { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20); - m_Contents.ChangeSlotCount(a_SlotNum, -1); break; @@ -202,10 +197,12 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) -void cDispenserEntity::SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector) +void cDispenserEntity::SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_Kind, Vector3d a_ShootVector) { - if(a_kind != cProjectileEntity::pkFireCharge) + if( a_kind != cProjectileEntity::pkFireCharge ) + { a_ShootVector.y = a_ShootVector.y + 1; + } m_World->CreateProjectile((double) a_BlockX + 0.5, (double) a_BlockY + 0.5, (double) a_BlockZ + 0.5, a_kind, NULL, NULL, &a_ShootVector); } @@ -215,14 +212,14 @@ Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE & a_Meta) { switch(a_Meta) { - case E_META_DROPSPENSER_FACING_YP: return Vector3d(0, 1, 0); // UP - case E_META_DROPSPENSER_FACING_YM: return Vector3d(0, -1, 0); // DOWN + case E_META_DROPSPENSER_FACING_YP: return Vector3d(0, 1, 0); // UP + case E_META_DROPSPENSER_FACING_YM: return Vector3d(0, -1, 0); // DOWN - case E_META_DROPSPENSER_FACING_XM: return Vector3d(-1, 0, 0); // WEST - case E_META_DROPSPENSER_FACING_XP: return Vector3d(1, 0, 0); // EAST + case E_META_DROPSPENSER_FACING_XM: return Vector3d(-1, 0, 0); // WEST + case E_META_DROPSPENSER_FACING_XP: return Vector3d(1, 0, 0); // EAST - case E_META_DROPSPENSER_FACING_ZM: return Vector3d(0, 0, -1); - case E_META_DROPSPENSER_FACING_ZP: return Vector3d(0, 0, 1); + case E_META_DROPSPENSER_FACING_ZM: return Vector3d(0, 0, -1); + case E_META_DROPSPENSER_FACING_ZP: return Vector3d(0, 0, 1); } return Vector3d(0, 1, 0); @@ -290,3 +287,6 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum m_Contents.AddItem(EmptyBucket); return true; } + + + diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 5a2de7965..9410a1129 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -23,7 +23,7 @@ public: static const char * GetClassStatic(void) { return "cDispenserEntity"; } /** Spawns a projectile of the given kind in front of the dispenser */ - void SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_kind, Vector3d a_ShootVector); + void SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_Kind, Vector3d a_ShootVector); /** Returns how to aim the projectile */ Vector3d GetShootVector(NIBBLETYPE & a_Meta); @@ -38,3 +38,6 @@ private: /// If the a_BlockInFront is liquidable and the empty bucket can fit, does the m_Contents processing and returns true bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum); } ; // tolua_export + + + From e5b345a9c95225c18728f5692bf12ffae82ba4cd Mon Sep 17 00:00:00 2001 From: JoannisO Date: Wed, 4 Jun 2014 12:37:51 +0200 Subject: [PATCH 15/48] - Fixed variable names in a function. --- src/BlockEntities/DispenserEntity.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 242ac4024..7b468bdea 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -199,12 +199,12 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) void cDispenserEntity::SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_Kind, Vector3d a_ShootVector) { - if( a_kind != cProjectileEntity::pkFireCharge ) + if( a_Kind != cProjectileEntity::pkFireCharge ) { a_ShootVector.y = a_ShootVector.y + 1; } - m_World->CreateProjectile((double) a_BlockX + 0.5, (double) a_BlockY + 0.5, (double) a_BlockZ + 0.5, a_kind, NULL, NULL, &a_ShootVector); + m_World->CreateProjectile((double) a_BlockX + 0.5, (double) a_BlockY + 0.5, (double) a_BlockZ + 0.5, a_Kind, NULL, NULL, &a_ShootVector); } From 852e162f95742d5c5454e458ed7883e4b0209a73 Mon Sep 17 00:00:00 2001 From: JoannisO Date: Wed, 4 Jun 2014 12:40:01 +0200 Subject: [PATCH 16/48] - Removed the code that removed fireworks from a dispenser even thought they weren't launched. --- src/BlockEntities/DispenserEntity.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 7b468bdea..475125719 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -181,9 +181,6 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIREWORK_ROCKET: { // TODO: Add the fireworks entity - - m_Contents.ChangeSlotCount(a_SlotNum, -1); - break; } From 720ae4f75777a8286014e9934429ab248df6d9e9 Mon Sep 17 00:00:00 2001 From: JoannisO Date: Thu, 5 Jun 2014 12:26:27 +0200 Subject: [PATCH 17/48] - Fixed a lot of alignment --- src/BlockEntities/DispenserEntity.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 475125719..97e25ca6d 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -196,7 +196,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) void cDispenserEntity::SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_Kind, Vector3d a_ShootVector) { - if( a_Kind != cProjectileEntity::pkFireCharge ) + if (a_Kind != cProjectileEntity::pkFireCharge) { a_ShootVector.y = a_ShootVector.y + 1; } @@ -209,14 +209,14 @@ Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE & a_Meta) { switch(a_Meta) { - case E_META_DROPSPENSER_FACING_YP: return Vector3d(0, 1, 0); // UP - case E_META_DROPSPENSER_FACING_YM: return Vector3d(0, -1, 0); // DOWN + case E_META_DROPSPENSER_FACING_YP: return Vector3d( 0, 1, 0); // UP + case E_META_DROPSPENSER_FACING_YM: return Vector3d( 0, -1, 0); // DOWN - case E_META_DROPSPENSER_FACING_XM: return Vector3d(-1, 0, 0); // WEST - case E_META_DROPSPENSER_FACING_XP: return Vector3d(1, 0, 0); // EAST + case E_META_DROPSPENSER_FACING_XM: return Vector3d(-1, 0, 0); // WEST + case E_META_DROPSPENSER_FACING_XP: return Vector3d( 1, 0, 0); // EAST - case E_META_DROPSPENSER_FACING_ZM: return Vector3d(0, 0, -1); - case E_META_DROPSPENSER_FACING_ZP: return Vector3d(0, 0, 1); + case E_META_DROPSPENSER_FACING_ZM: return Vector3d( 0, 0, -1); + case E_META_DROPSPENSER_FACING_ZP: return Vector3d( 0, 0, 1); } return Vector3d(0, 1, 0); From 1ff1a93866ab81e3868588a256f446a902a1a8c4 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 10 Jun 2014 22:59:45 +0200 Subject: [PATCH 18/48] Initial Mesa Bryce implementation. --- src/Generating/DistortedHeightmap.cpp | 4 +- src/Generating/DistortedHeightmap.h | 6 +- src/Generating/HeiGen.cpp | 89 +++++++++++++++++++++++++++ src/Generating/HeiGen.h | 21 +++++++ 4 files changed, 116 insertions(+), 4 deletions(-) diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp index eb9fe92ba..e50f36d57 100644 --- a/src/Generating/DistortedHeightmap.cpp +++ b/src/Generating/DistortedHeightmap.cpp @@ -282,7 +282,7 @@ cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGen & a_BiomeGen) : m_OceanFloorSelect(a_Seed + 3000), m_MesaFloor(a_Seed + 4000), m_BiomeGen(a_BiomeGen), - m_UnderlyingHeiGen(a_Seed, a_BiomeGen), + m_UnderlyingHeiGen(a_Seed), m_HeightGen(m_UnderlyingHeiGen, 64), m_IsInitialized(false) { @@ -308,6 +308,8 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile) return; } + ((cTerrainHeightGen &)m_UnderlyingHeiGen).InitializeHeightGen(a_IniFile); + // Read the params from the INI file: m_SeaLevel = a_IniFile.GetValueSetI("Generator", "DistortedHeightmapSeaLevel", 62); m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyX", 10); diff --git a/src/Generating/DistortedHeightmap.h b/src/Generating/DistortedHeightmap.h index e6b3c9d3f..31fb17df2 100644 --- a/src/Generating/DistortedHeightmap.h +++ b/src/Generating/DistortedHeightmap.h @@ -64,9 +64,9 @@ protected: int m_CurChunkZ; NOISE_DATATYPE m_DistortedHeightmap[17 * 257 * 17]; - cBiomeGen & m_BiomeGen; - cHeiGenBiomal m_UnderlyingHeiGen; // This generator provides us with base heightmap (before distortion) - cHeiGenCache m_HeightGen; // Cache above m_UnderlyingHeiGen + cBiomeGen & m_BiomeGen; + cHeiGenMesaBryce m_UnderlyingHeiGen; // This generator provides us with base heightmap (before distortion) + cHeiGenCache m_HeightGen; // Cache above m_UnderlyingHeiGen /// Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization. cChunkDef::HeightMap m_CurChunkHeights; diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index 25ac912fd..dedf3fe3f 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -47,6 +47,10 @@ cTerrainHeightGen * cTerrainHeightGen::CreateHeightGen(cIniFile &a_IniFile, cBio { res = new cEndGen(a_Seed); } + else if (NoCaseCompare(HeightGenName, "MesaBryce") == 0) + { + res = new cHeiGenMesaBryce(a_Seed); + } else if (NoCaseCompare(HeightGenName, "Mountains") == 0) { res = new cHeiGenMountains(a_Seed); @@ -366,6 +370,91 @@ void cHeiGenMountains::InitializeHeightGen(cIniFile & a_IniFile) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cHeiGenMesaBryce: + +cHeiGenMesaBryce::cHeiGenMesaBryce(int a_Seed) : + m_Seed(a_Seed), + m_PerlinHFHA(a_Seed), + m_PerlinLFLA(a_Seed + 10) +{ +} + + + + + +void cHeiGenMesaBryce::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) +{ + NOISE_DATATYPE StartX = (NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width); + NOISE_DATATYPE EndX = (NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + cChunkDef::Width - 1); + NOISE_DATATYPE StartZ = (NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width); + NOISE_DATATYPE EndZ = (NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + cChunkDef::Width - 1); + NOISE_DATATYPE Workspace[16 * 16]; + NOISE_DATATYPE Noise1[16 * 16]; + NOISE_DATATYPE Noise2[16 * 16]; + NOISE_DATATYPE Noise3[16 * 16]; + m_PerlinHFHA.Generate2D(Noise1, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); + m_PerlinLFLA.Generate2D(Noise2, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); + m_PerlinTops.Generate2D(Noise3, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); + for (int z = 0; z < cChunkDef::Width; z++) + { + int IdxZ = z * cChunkDef::Width; + for (int x = 0; x < cChunkDef::Width; x++) + { + int idx = IdxZ + x; + // int hei = 70 + (int)(std::min(Noise1[idx], Noise2[idx]) * 15); + int hei; + if (Noise1[idx] > 1.5f) + { + hei = 83 + (int)floor(Noise3[idx]); + } + else + { + hei = 63 + (int)floor(Noise2[idx]); + } + /* + NOISE_DATATYPE v1 = sqrt(sqrt(std::max(Noise1[idx], (NOISE_DATATYPE)0))) - 50; + int hei = 60 + (int)floor(std::max(v1, 5 + Noise2[idx])); + */ + if (hei < 10) + { + hei = 10; + } + if (hei > 250) + { + hei = 250; + } + cChunkDef::SetHeight(a_HeightMap, x , z, hei); + } // for x + } // for z +} + + + + + +void cHeiGenMesaBryce::InitializeHeightGen(cIniFile & a_IniFile) +{ + // TODO: Read the params from an INI file + // m_PerlinHFHA.AddOctave(0.32f, 0.1); + /* + m_PerlinHFHA.AddOctave(0.13f, 17800000); + m_PerlinHFHA.AddOctave(0.12f, 19000000); + */ + m_PerlinHFHA.AddOctave(0.13f, 2); + m_PerlinHFHA.AddOctave(0.12f, 2); + + m_PerlinLFLA.AddOctave(0.04f, 1); + m_PerlinLFLA.AddOctave(0.02f, 2); + + m_PerlinTops.AddOctave(0.1f, 8); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cHeiGenBiomal: diff --git a/src/Generating/HeiGen.h b/src/Generating/HeiGen.h index 5c106c7d9..5fc4f4abc 100644 --- a/src/Generating/HeiGen.h +++ b/src/Generating/HeiGen.h @@ -127,6 +127,27 @@ protected: +class cHeiGenMesaBryce : + public cTerrainHeightGen +{ +public: + cHeiGenMesaBryce(int a_Seed); + +protected: + int m_Seed; + cPerlinNoise m_PerlinHFHA; // HighFrequencyHighAmplitude, for the hills + cPerlinNoise m_PerlinLFLA; // LowFrequencyLowAmplitude, for the floor + cPerlinNoise m_PerlinTops; + + // cTerrainHeightGen overrides: + virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override; + virtual void InitializeHeightGen(cIniFile & a_IniFile) override; +} ; + + + + + class cHeiGenBiomal : public cTerrainHeightGen { From d5679f51dedc7998e56f683a876e5b22887a3488 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 11 Jun 2014 07:39:18 +0100 Subject: [PATCH 19/48] Removed derpbadge. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6d9492f0..9e55001ef 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer) [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team) [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) +MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer) [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) ======== MCServer is a Minecraft server that is written in C++ and designed to be efficient with memory and CPU, as well as having a flexible Lua Plugin API. From 5950212829e87041306f29754c3412389bc62390 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 11 Jun 2014 07:40:58 +0100 Subject: [PATCH 20/48] Test --- CONTRIBUTORS | 1 - 1 file changed, 1 deletion(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 8b10525da..b7f94a717 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -27,5 +27,4 @@ UltraCoderRU worktycho xoft - Please add yourself to this list if you contribute to MCServer. From fd2ff3845e444cb364efff6dcb101c9e7a583bf1 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 11 Jun 2014 08:49:33 +0100 Subject: [PATCH 21/48] Update GETTING-STARTED.md --- GETTING-STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GETTING-STARTED.md b/GETTING-STARTED.md index 1ac6fe989..4d992597e 100644 --- a/GETTING-STARTED.md +++ b/GETTING-STARTED.md @@ -10,7 +10,7 @@ I'd say that the important topics are: * Differnt types of blocks and how they act. * Mobs, what they do and how. * Redstone, pistons, and automation. -* Farming +* Farming. * Fighting, health and the hunger system. Useful Resources From 8695928dd17e96baed46da18d085b51f831e4bab Mon Sep 17 00:00:00 2001 From: worktycho Date: Wed, 11 Jun 2014 09:37:00 +0100 Subject: [PATCH 22/48] Update GETTING-STARTED.md --- GETTING-STARTED.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/GETTING-STARTED.md b/GETTING-STARTED.md index 4d992597e..eb7d1b713 100644 --- a/GETTING-STARTED.md +++ b/GETTING-STARTED.md @@ -3,7 +3,7 @@ Hello! Thanks for wanting to work on this project :smile:, and I hope that this Minecraft Basics ---------------- -If you don't play Minecraft or don't have a great knowledge of the basic systems, you should get to know them. The [Minecraft Wiki](http://minecraft.gamepedia.com/Minecraft_Wiki) is quite useful for this task, although some youtubers are also fairly good at teaching the basics and just playing is quite good too. +If you don't play Minecraft or don't have a great knowledge of the basic systems, you should get to know them. The [Minecraft Wiki](http://minecraft.gamepedia.com/Minecraft_Wiki) is quite useful for this task, although some youtubers are also fairly good at teaching the basics and just playing is quite good too. It is possabile to contribute without knowing minecraft in detail though. I'd say that the important topics are: @@ -39,7 +39,7 @@ You'll also need CMake to generate the makefile to build from. **Windows:** -If you use Windows, your best bet is the MSVC2008 (available as a free download in the Express edition from MS) or MSVS2013 (ditto), solution files for both are currently in the repo. +If you use Windows, your best bet is the MSVC2008 (available as a free download in the Express edition from MS) or MSVS2013 (ditto), solution files for which can be generated with cmake. You'll also need cmake to generate the project files. Setting up the Repo ------------------- @@ -85,7 +85,7 @@ Basically, the process is: **Windows:** -You need to first execute the `src/Bindings/AllToLua.bat` script file, then just open the solution file in your MSVC of choice and build. +You need to first generate a project file with `cmake . -DCMAKE_BUILD_TYPE=DEBUG` then execute the `src/Bindings/AllToLua.bat` script file, then just open the solution file in your MSVC of choice and build. How to Run ---------- @@ -99,18 +99,18 @@ There are a few fairly easy issues for you to get started with, as well as some **Easy**: - * #288 - * #385 - * #402 - * #380 - * #503 - * #491 + * #140 + * #493 + * #577 + * #381 + * #752 * Clean up some of the compiler warnings. (Check [Travis CI](http://travis-ci.org/mc-server/MCServer) for a list of them.) With clang, there are over 10000 lines of warnings to clean up. **More Difficult**: - * #17 - * #398 + * #133 + * #134 + * #215 You may also want to write some plugins. They are written in lua, with excellent API documentation available via [APIDump](http://mc-server.xoft.cz/LuaAPI). The [Core](https://github.com/mc-server/Core) plugin should also help quite a bit here. From 3e258523821e67a5892fe44dd585bae896866d9a Mon Sep 17 00:00:00 2001 From: worktycho Date: Wed, 11 Jun 2014 10:04:34 +0100 Subject: [PATCH 23/48] Removed assert that is now informed by type system --- src/ByteBuffer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 4de89f7c1..d77f402fd 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -762,7 +762,6 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, size_t a_NumChars) // Reads 2 * a_NumChars bytes and interprets it as a UTF16 string, converting it into UTF8 string a_String CHECK_THREAD; CheckValid(); - ASSERT(a_NumChars >= 0); AString RawData; if (!ReadString(RawData, a_NumChars * 2)) { From 7cb88e8c06a2d86f7563cac1e0911f51801a3dee Mon Sep 17 00:00:00 2001 From: worktycho Date: Wed, 11 Jun 2014 10:21:24 +0100 Subject: [PATCH 24/48] Added coverity badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e55001ef..b0f1cde35 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer) [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) +MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer) [![Coverity Scan Build Status](https://scan.coverity.com/projects/1930/badge.svg)](https://scan.coverity.com/projects/1930) [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) ======== MCServer is a Minecraft server that is written in C++ and designed to be efficient with memory and CPU, as well as having a flexible Lua Plugin API. From c3c3782c67265f2844dc66667d3e6bc79a6b25ff Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 11 Jun 2014 10:33:16 +0100 Subject: [PATCH 25/48] Add new IsWeatherWet hook for cauldrons. @madmaxoft can you comment? --- src/World.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/World.h b/src/World.h index abdc3120c..b0fed84ba 100644 --- a/src/World.h +++ b/src/World.h @@ -708,12 +708,23 @@ public: eWeather GetWeather (void) const { return m_Weather; }; bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } + bool IsWeatherSunny(int a_BlockX, int a_BlockZ) const { + return (m_Weather == wSunny) + } bool IsWeatherRain (void) const { return (m_Weather == wRain); } + bool IsWeatherRain (int a_BlockX, int a_BlockZ) const { + return (m_Weather == wRain) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) + } bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } + bool IsWeatherStorm(int a_BlockX, int a_BlockZ) const { + return (m_Weather == wStorm) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) + } /** Returns true if the current weather has any precipitation - rain or storm */ bool IsWeatherWet (void) const { return (m_Weather != wSunny); } - + bool IsWeatherWet (int a_BlockX, int a_BlockZ) const { + return (m_Weather != wSunny) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) + } // tolua_end cChunkGenerator & GetGenerator(void) { return m_Generator; } From c5010ebcc13c29a567755d938dabfa5250de73fc Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 11 Jun 2014 13:01:52 +0100 Subject: [PATCH 26/48] Add DoxyComments to he weather things. Also changed the function names. --- src/World.h | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/World.h b/src/World.h index b0fed84ba..ac275b991 100644 --- a/src/World.h +++ b/src/World.h @@ -707,22 +707,39 @@ public: /** Returns the current weather. Instead of comparing values directly to the weather constants, use IsWeatherXXX() functions, if possible */ eWeather GetWeather (void) const { return m_Weather; }; + /** Returns true if the current weather is sun */ bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } - bool IsWeatherSunny(int a_BlockX, int a_BlockZ) const { + + /** Returns true if it is sunny at the specified location. This takes into accunt biomes. */ + bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const + { return (m_Weather == wSunny) } - bool IsWeatherRain (void) const { return (m_Weather == wRain); } - bool IsWeatherRain (int a_BlockX, int a_BlockZ) const { + + /** Returns true if the current weather is rain */ + bool IsWeatherRain(void) const { return (m_Weather == wRain); } + + /** Returns true if it is raining at the specified location. This takes into accunt biomes. */ + bool IsWeatherRainAt (int a_BlockX, int a_BlockZ) const + { return (m_Weather == wRain) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) } + + /** Returns true if the current weather is stormy */ bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } - bool IsWeatherStorm(int a_BlockX, int a_BlockZ) const { + + /** Returns true if the weather is stormy at the specified location. This takes into accunt biomes. */ + bool IsWeatherStormAt(int a_BlockX, int a_BlockZ) const + { return (m_Weather == wStorm) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) } - /** Returns true if the current weather has any precipitation - rain or storm */ - bool IsWeatherWet (void) const { return (m_Weather != wSunny); } - bool IsWeatherWet (int a_BlockX, int a_BlockZ) const { + /** Returns true if the current weather has any precipitation - rain, storm or snow */ + bool IsWeatherWet(void) const { return (m_Weather != wSunny); } + + /** Returns true if it is raining, stormy or snowing at the specified location. This takes into accunt biomes. */ + bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) const + { return (m_Weather != wSunny) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) } // tolua_end From 711113cd2b9deaa2f556c446885e976a79fadcbf Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 11 Jun 2014 13:10:10 +0100 Subject: [PATCH 27/48] Updated unnecessary function :/ --- src/World.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/World.h b/src/World.h index ac275b991..11c262e3a 100644 --- a/src/World.h +++ b/src/World.h @@ -710,9 +710,13 @@ public: /** Returns true if the current weather is sun */ bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } - /** Returns true if it is sunny at the specified location. This takes into accunt biomes. */ + /** Returns true if it is sunny at the specified location. This takes into accunt biomes. + This function is identical to IsWeatherSunny except for two extra parameters that aren't used, but bearbin insists :/ + */ bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const { + UNUSED(a_BlockX); + UNUSED(a_BlockZ); return (m_Weather == wSunny) } From 7e4abcfe2d2b1b5d5f73ebb990b24427323624e8 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 11 Jun 2014 14:14:54 +0200 Subject: [PATCH 28/48] Revert "Initial Mesa Bryce implementation." This reverts commit 1ff1a93866ab81e3868588a256f446a902a1a8c4. --- src/Generating/DistortedHeightmap.cpp | 4 +- src/Generating/DistortedHeightmap.h | 6 +- src/Generating/HeiGen.cpp | 89 --------------------------- src/Generating/HeiGen.h | 21 ------- 4 files changed, 4 insertions(+), 116 deletions(-) diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp index e50f36d57..eb9fe92ba 100644 --- a/src/Generating/DistortedHeightmap.cpp +++ b/src/Generating/DistortedHeightmap.cpp @@ -282,7 +282,7 @@ cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGen & a_BiomeGen) : m_OceanFloorSelect(a_Seed + 3000), m_MesaFloor(a_Seed + 4000), m_BiomeGen(a_BiomeGen), - m_UnderlyingHeiGen(a_Seed), + m_UnderlyingHeiGen(a_Seed, a_BiomeGen), m_HeightGen(m_UnderlyingHeiGen, 64), m_IsInitialized(false) { @@ -308,8 +308,6 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile) return; } - ((cTerrainHeightGen &)m_UnderlyingHeiGen).InitializeHeightGen(a_IniFile); - // Read the params from the INI file: m_SeaLevel = a_IniFile.GetValueSetI("Generator", "DistortedHeightmapSeaLevel", 62); m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyX", 10); diff --git a/src/Generating/DistortedHeightmap.h b/src/Generating/DistortedHeightmap.h index 31fb17df2..e6b3c9d3f 100644 --- a/src/Generating/DistortedHeightmap.h +++ b/src/Generating/DistortedHeightmap.h @@ -64,9 +64,9 @@ protected: int m_CurChunkZ; NOISE_DATATYPE m_DistortedHeightmap[17 * 257 * 17]; - cBiomeGen & m_BiomeGen; - cHeiGenMesaBryce m_UnderlyingHeiGen; // This generator provides us with base heightmap (before distortion) - cHeiGenCache m_HeightGen; // Cache above m_UnderlyingHeiGen + cBiomeGen & m_BiomeGen; + cHeiGenBiomal m_UnderlyingHeiGen; // This generator provides us with base heightmap (before distortion) + cHeiGenCache m_HeightGen; // Cache above m_UnderlyingHeiGen /// Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization. cChunkDef::HeightMap m_CurChunkHeights; diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index dedf3fe3f..25ac912fd 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -47,10 +47,6 @@ cTerrainHeightGen * cTerrainHeightGen::CreateHeightGen(cIniFile &a_IniFile, cBio { res = new cEndGen(a_Seed); } - else if (NoCaseCompare(HeightGenName, "MesaBryce") == 0) - { - res = new cHeiGenMesaBryce(a_Seed); - } else if (NoCaseCompare(HeightGenName, "Mountains") == 0) { res = new cHeiGenMountains(a_Seed); @@ -370,91 +366,6 @@ void cHeiGenMountains::InitializeHeightGen(cIniFile & a_IniFile) -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cHeiGenMesaBryce: - -cHeiGenMesaBryce::cHeiGenMesaBryce(int a_Seed) : - m_Seed(a_Seed), - m_PerlinHFHA(a_Seed), - m_PerlinLFLA(a_Seed + 10) -{ -} - - - - - -void cHeiGenMesaBryce::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) -{ - NOISE_DATATYPE StartX = (NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width); - NOISE_DATATYPE EndX = (NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + cChunkDef::Width - 1); - NOISE_DATATYPE StartZ = (NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width); - NOISE_DATATYPE EndZ = (NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + cChunkDef::Width - 1); - NOISE_DATATYPE Workspace[16 * 16]; - NOISE_DATATYPE Noise1[16 * 16]; - NOISE_DATATYPE Noise2[16 * 16]; - NOISE_DATATYPE Noise3[16 * 16]; - m_PerlinHFHA.Generate2D(Noise1, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); - m_PerlinLFLA.Generate2D(Noise2, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); - m_PerlinTops.Generate2D(Noise3, 16, 16, StartX, EndX, StartZ, EndZ, Workspace); - for (int z = 0; z < cChunkDef::Width; z++) - { - int IdxZ = z * cChunkDef::Width; - for (int x = 0; x < cChunkDef::Width; x++) - { - int idx = IdxZ + x; - // int hei = 70 + (int)(std::min(Noise1[idx], Noise2[idx]) * 15); - int hei; - if (Noise1[idx] > 1.5f) - { - hei = 83 + (int)floor(Noise3[idx]); - } - else - { - hei = 63 + (int)floor(Noise2[idx]); - } - /* - NOISE_DATATYPE v1 = sqrt(sqrt(std::max(Noise1[idx], (NOISE_DATATYPE)0))) - 50; - int hei = 60 + (int)floor(std::max(v1, 5 + Noise2[idx])); - */ - if (hei < 10) - { - hei = 10; - } - if (hei > 250) - { - hei = 250; - } - cChunkDef::SetHeight(a_HeightMap, x , z, hei); - } // for x - } // for z -} - - - - - -void cHeiGenMesaBryce::InitializeHeightGen(cIniFile & a_IniFile) -{ - // TODO: Read the params from an INI file - // m_PerlinHFHA.AddOctave(0.32f, 0.1); - /* - m_PerlinHFHA.AddOctave(0.13f, 17800000); - m_PerlinHFHA.AddOctave(0.12f, 19000000); - */ - m_PerlinHFHA.AddOctave(0.13f, 2); - m_PerlinHFHA.AddOctave(0.12f, 2); - - m_PerlinLFLA.AddOctave(0.04f, 1); - m_PerlinLFLA.AddOctave(0.02f, 2); - - m_PerlinTops.AddOctave(0.1f, 8); -} - - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cHeiGenBiomal: diff --git a/src/Generating/HeiGen.h b/src/Generating/HeiGen.h index 5fc4f4abc..5c106c7d9 100644 --- a/src/Generating/HeiGen.h +++ b/src/Generating/HeiGen.h @@ -127,27 +127,6 @@ protected: -class cHeiGenMesaBryce : - public cTerrainHeightGen -{ -public: - cHeiGenMesaBryce(int a_Seed); - -protected: - int m_Seed; - cPerlinNoise m_PerlinHFHA; // HighFrequencyHighAmplitude, for the hills - cPerlinNoise m_PerlinLFLA; // LowFrequencyLowAmplitude, for the floor - cPerlinNoise m_PerlinTops; - - // cTerrainHeightGen overrides: - virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override; - virtual void InitializeHeightGen(cIniFile & a_IniFile) override; -} ; - - - - - class cHeiGenBiomal : public cTerrainHeightGen { From c09207cabcecb94b134f92e2dbfdad69da930b43 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 11 Jun 2014 13:20:31 +0100 Subject: [PATCH 29/48] SMICOLOSL Meant to be semicolons up there. --- src/World.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/World.h b/src/World.h index 11c262e3a..a72904f6a 100644 --- a/src/World.h +++ b/src/World.h @@ -717,7 +717,7 @@ public: { UNUSED(a_BlockX); UNUSED(a_BlockZ); - return (m_Weather == wSunny) + return (m_Weather == wSunny); } /** Returns true if the current weather is rain */ @@ -726,7 +726,7 @@ public: /** Returns true if it is raining at the specified location. This takes into accunt biomes. */ bool IsWeatherRainAt (int a_BlockX, int a_BlockZ) const { - return (m_Weather == wRain) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) + return (m_Weather == wRain) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } /** Returns true if the current weather is stormy */ @@ -735,7 +735,7 @@ public: /** Returns true if the weather is stormy at the specified location. This takes into accunt biomes. */ bool IsWeatherStormAt(int a_BlockX, int a_BlockZ) const { - return (m_Weather == wStorm) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) + return (m_Weather == wStorm) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } /** Returns true if the current weather has any precipitation - rain, storm or snow */ @@ -744,7 +744,7 @@ public: /** Returns true if it is raining, stormy or snowing at the specified location. This takes into accunt biomes. */ bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) const { - return (m_Weather != wSunny) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))) + return (m_Weather != wSunny) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } // tolua_end From bd25069c25574f96ebf02de7360131bfe3504f04 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 11 Jun 2014 13:21:57 +0100 Subject: [PATCH 30/48] Update APIDesc.lua --- MCServer/Plugins/APIDump/APIDesc.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 40bfe79ac..1f43a6172 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2294,10 +2294,13 @@ end IsGameModeCreative = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmCreative." }, IsGameModeSurvival = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmSurvival." }, IsPVPEnabled = { Params = "", Return = "bool", Notes = "Returns whether PVP is enabled in the world settings." }, - IsWeatherRain = { Params = "", Return = "bool", Notes = "Returns true if the current weather is rain." }, - IsWeatherStorm = { Params = "", Return = "bool", Notes = "Returns true if the current weather is a storm." }, + IsWeatherRain = { Params = "", Return = "bool", Notes = "Returns true if the current world is raining." }, + IsWeatherRainAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location is raining (takes into account biomes)." }, + IsWeatherStorm = { Params = "", Return = "bool", Notes = "Returns true if the current world is stormy." }, + IsWeatherStormAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location is stormy (takes into account biomes)." }, IsWeatherSunny = { Params = "", Return = "bool", Notes = "Returns true if the current weather is sunny." }, - IsWeatherWet = { Params = "", Return = "bool", Notes = "Returns true if the current weather has any precipitation (rain or storm)." }, + IsWeatherWet = { Params = "", Return = "bool", Notes = "Returns true if the current world has any precipitation (rain or storm)." }, + IsWeatherWetAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location has any precipitation (rain or storm) (takes into account biomes)." }, QueueBlockForTick = { Params = "BlockX, BlockY, BlockZ, TicksToWait", Return = "", Notes = "Queues the specified block to be ticked after the specified number of gameticks." }, QueueSaveAllChunks = { Params = "", Return = "", Notes = "Queues all chunks to be saved in the world storage thread" }, QueueSetBlock = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta, TickDelay", Return = "", Notes = "Queues the block to be set to the specified blocktype and meta after the specified amount of game ticks. Uses SetBlock() for the actual setting, so simulators are woken up and block entities are handled correctly." }, From b3300e3854861d6957f5dac30ce0c7b027a3e2ad Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 11 Jun 2014 14:22:27 +0200 Subject: [PATCH 31/48] Added cBlockArea:GetCoordRange to Lua API. --- src/Bindings/ManualBindings.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 14d9d16fc..acfd6f4f8 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2538,6 +2538,37 @@ static int tolua_cBlockArea_GetSize(lua_State * tolua_S) +static int tolua_cBlockArea_GetCoordRange(lua_State * tolua_S) +{ + // function cBlockArea::GetCoordRange() + // Returns all three sizes of the area, miuns one, so that they represent the maximum coord value + // Exported manually because there's no direct C++ equivalent, + // plus tolua would generate extra input params for the outputs + + cLuaState L(tolua_S); + if (!L.CheckParamUserType(1, "cBlockArea")) + { + return 0; + } + + cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL); + if (self == NULL) + { + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", NULL); + return 0; + } + + // Push the three origin coords: + lua_pushnumber(tolua_S, self->GetSizeX() - 1); + lua_pushnumber(tolua_S, self->GetSizeY() - 1); + lua_pushnumber(tolua_S, self->GetSizeZ() - 1); + return 3; +} + + + + + static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S) { // function cBlockArea::LoadFromSchematicFile @@ -2926,6 +2957,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_beginmodule(tolua_S, "cBlockArea"); tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta); + tolua_function(tolua_S, "GetCoordRange", tolua_cBlockArea_GetCoordRange); tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin); tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta); tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize); From 97bfccfdc0088705a4546d7d6369f3801946c1ba Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 11 Jun 2014 14:34:47 +0200 Subject: [PATCH 32/48] APIDump: Documented cBlockArea:GetCoordRange(). --- MCServer/Plugins/APIDump/APIDesc.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 40bfe79ac..800d1170e 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -114,6 +114,7 @@ g_APIDesc = GetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified absolute coords" }, GetBlockType = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified absolute coords" }, GetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified absolute coords" }, + GetCoordRange = {Params = "", Return = "MaxX, MaxY, MaxZ", Notes = "Returns the maximum relative coords in all 3 axes. See also GetSize()." }, GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the object is currently holding" }, GetOrigin = { Params = "", Return = "OriginX, OriginY, OriginZ", Notes = "Returns the origin coords of where the area was read from." }, GetOriginX = { Params = "", Return = "number", Notes = "Returns the origin x-coord" }, @@ -124,7 +125,7 @@ g_APIDesc = GetRelBlockSkyLight = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified relative coords" }, GetRelBlockType = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified relative coords" }, GetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified relative coords" }, - GetSize = { Params = "", Return = "SizeX, SizeY, SizeZ", Notes = "Returns the size of the area in all 3 axes." }, + GetSize = { Params = "", Return = "SizeX, SizeY, SizeZ", Notes = "Returns the size of the area in all 3 axes. See also GetCoordRange()." }, GetSizeX = { Params = "", Return = "number", Notes = "Returns the size of the held data in the x-axis" }, GetSizeY = { Params = "", Return = "number", Notes = "Returns the size of the held data in the y-axis" }, GetSizeZ = { Params = "", Return = "number", Notes = "Returns the size of the held data in the z-axis" }, From c335b8d77346541799b9c62e4fc78ef217cc4f63 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 11 Jun 2014 13:34:49 +0100 Subject: [PATCH 33/48] Update APIDesc.lua --- MCServer/Plugins/APIDump/APIDesc.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 1f43a6172..8442f6d80 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2299,6 +2299,7 @@ end IsWeatherStorm = { Params = "", Return = "bool", Notes = "Returns true if the current world is stormy." }, IsWeatherStormAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location is stormy (takes into account biomes)." }, IsWeatherSunny = { Params = "", Return = "bool", Notes = "Returns true if the current weather is sunny." }, + IsWeatherSunnyAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the current weather is sunny at the specified location (takes into account biomes)." }, IsWeatherWet = { Params = "", Return = "bool", Notes = "Returns true if the current world has any precipitation (rain or storm)." }, IsWeatherWetAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location has any precipitation (rain or storm) (takes into account biomes)." }, QueueBlockForTick = { Params = "BlockX, BlockY, BlockZ, TicksToWait", Return = "", Notes = "Queues the specified block to be ticked after the specified number of gameticks." }, From f7913d3b742e13595e3ded99820a13ade8a3b674 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 11 Jun 2014 13:37:04 +0100 Subject: [PATCH 34/48] IsWeatherSunnyAt does something useful :D --- src/World.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/World.h b/src/World.h index a72904f6a..f9471e881 100644 --- a/src/World.h +++ b/src/World.h @@ -710,20 +710,16 @@ public: /** Returns true if the current weather is sun */ bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } - /** Returns true if it is sunny at the specified location. This takes into accunt biomes. - This function is identical to IsWeatherSunny except for two extra parameters that aren't used, but bearbin insists :/ - */ + /** Returns true if it is sunny at the specified location. This takes into account biomes. */ bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const { - UNUSED(a_BlockX); - UNUSED(a_BlockZ); - return (m_Weather == wSunny); + return (IsWeatherSunny() || IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } /** Returns true if the current weather is rain */ bool IsWeatherRain(void) const { return (m_Weather == wRain); } - /** Returns true if it is raining at the specified location. This takes into accunt biomes. */ + /** Returns true if it is raining at the specified location. This takes into account biomes. */ bool IsWeatherRainAt (int a_BlockX, int a_BlockZ) const { return (m_Weather == wRain) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); @@ -732,7 +728,7 @@ public: /** Returns true if the current weather is stormy */ bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } - /** Returns true if the weather is stormy at the specified location. This takes into accunt biomes. */ + /** Returns true if the weather is stormy at the specified location. This takes into account biomes. */ bool IsWeatherStormAt(int a_BlockX, int a_BlockZ) const { return (m_Weather == wStorm) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); @@ -741,7 +737,7 @@ public: /** Returns true if the current weather has any precipitation - rain, storm or snow */ bool IsWeatherWet(void) const { return (m_Weather != wSunny); } - /** Returns true if it is raining, stormy or snowing at the specified location. This takes into accunt biomes. */ + /** Returns true if it is raining, stormy or snowing at the specified location. This takes into account biomes. */ bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) const { return (m_Weather != wSunny) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); From 1a9467574e462f467dc9e1a9cc45b68c87276968 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 11 Jun 2014 13:40:34 +0100 Subject: [PATCH 35/48] Reduced code duplication call @maxmaxoft! calling... call connected (0:20) call ended --- src/World.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/World.h b/src/World.h index f9471e881..7469c1054 100644 --- a/src/World.h +++ b/src/World.h @@ -722,7 +722,7 @@ public: /** Returns true if it is raining at the specified location. This takes into account biomes. */ bool IsWeatherRainAt (int a_BlockX, int a_BlockZ) const { - return (m_Weather == wRain) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); + return (IsWeatherRain() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } /** Returns true if the current weather is stormy */ @@ -731,16 +731,16 @@ public: /** Returns true if the weather is stormy at the specified location. This takes into account biomes. */ bool IsWeatherStormAt(int a_BlockX, int a_BlockZ) const { - return (m_Weather == wStorm) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); + return (IsWeatherStorm() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } /** Returns true if the current weather has any precipitation - rain, storm or snow */ - bool IsWeatherWet(void) const { return (m_Weather != wSunny); } + bool IsWeatherWet(void) const { return !IsWeatherSunny(); } /** Returns true if it is raining, stormy or snowing at the specified location. This takes into account biomes. */ bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) const { - return (m_Weather != wSunny) && (!IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); + return (IsWeatherWet() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } // tolua_end From e24830f0b12597896d895855298e8dde5f448b5b Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 11 Jun 2014 13:49:57 +0100 Subject: [PATCH 36/48] Compile fix --- src/World.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/World.h b/src/World.h index 7469c1054..45b42b280 100644 --- a/src/World.h +++ b/src/World.h @@ -597,7 +597,7 @@ public: void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); /** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value */ - EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ); + EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ) const; /** Sets the biome at the specified coords. Returns true if successful, false if not (chunk not loaded). Doesn't resend the chunk to clients, use ForceSendChunkTo() for that. */ From 70c20d77721f69e9f04a27630a4e4b65c5be601f Mon Sep 17 00:00:00 2001 From: worktycho Date: Wed, 11 Jun 2014 16:23:53 +0100 Subject: [PATCH 37/48] Fixed constness --- lib/tolua++/src/bin/basic_lua.h | 139 ++++++++++++++------------ lib/tolua++/src/bin/declaration_lua.h | 2 +- src/World.h | 10 +- 3 files changed, 79 insertions(+), 72 deletions(-) diff --git a/lib/tolua++/src/bin/basic_lua.h b/lib/tolua++/src/bin/basic_lua.h index effd79ee9..913ebeef8 100644 --- a/lib/tolua++/src/bin/basic_lua.h +++ b/lib/tolua++/src/bin/basic_lua.h @@ -688,73 +688,80 @@ static const unsigned char lua_basic_lua[] = { 0x74, 0x70, 0x75, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x6f, 0x6b, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x20, 0x70, 0x75, 0x73, 0x68, 0x65, 0x72, 0x73, 0x0a, 0x0a, - 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x69, 0x73, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20, + 0x20, 0x2d, 0x2d, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, + 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x6e, 0x64, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x69, 0x70, + 0x6c, 0x65, 0x2d, 0x64, 0x6f, 0x74, 0x2d, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x68, 0x65, 0x73, 0x69, 0x73, 0x20, 0x64, 0x75, 0x65, 0x20, 0x74, + 0x6f, 0x20, 0x70, 0x72, 0x65, 0x2d, 0x70, 0x61, 0x72, 0x73, 0x69, 0x6e, + 0x67, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x20, 0x70, 0x75, 0x73, 0x68, 0x65, 0x72, 0x73, + 0x0a, 0x0a, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x5f, + 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, + 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, + 0x0a, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, - 0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x20, 0x3d, - 0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x75, 0x6e, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, - 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, - 0x7d, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x73, 0x5f, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, - 0x7d, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x7b, - 0x7d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x5f, 0x62, 0x61, 0x73, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x66, 0x75, 0x6e, - 0x63, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, - 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x67, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b, - 0x74, 0x5d, 0x0a, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x63, - 0x6c, 0x61, 0x73, 0x73, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x69, 0x66, - 0x20, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x5b, 0x63, 0x6c, 0x61, 0x73, 0x73, - 0x2e, 0x74, 0x79, 0x70, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, - 0x6e, 0x63, 0x73, 0x5b, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, - 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x67, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5b, - 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x62, 0x74, 0x79, 0x70, 0x65, 0x5d, - 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65, 0x74, 0x5f, - 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x20, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x73, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x28, 0x74, - 0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x75, 0x73, 0x68, - 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20, - 0x6f, 0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x70, 0x75, - 0x73, 0x68, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x22, 0x0a, - 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x72, 0x65, - 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x75, 0x6e, + 0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x73, + 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, + 0x20, 0x7b, 0x7d, 0x0a, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x6f, + 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, + 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x73, 0x29, 0x0a, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, + 0x73, 0x5b, 0x74, 0x5d, 0x0a, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, + 0x69, 0x66, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x73, 0x5b, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, + 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x73, 0x5b, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x67, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, + 0x73, 0x5b, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x2e, 0x62, 0x74, 0x79, 0x70, + 0x65, 0x5d, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x65, 0x6e, 0x64, 0x0a, + 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65, + 0x74, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, 0x73, 0x65, - 0x28, 0x74, 0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x6f, - 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20, - 0x6f, 0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x74, 0x6f, - 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x22, 0x0a, 0x65, 0x6e, - 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x67, 0x65, 0x74, 0x5f, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x5f, - 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, - 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x22, 0x20, 0x2e, 0x2e, - 0x20, 0x74, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x6f, 0x72, 0x20, - 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x28, - 0x74, 0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x73, 0x5f, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x20, 0x6f, - 0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x75, - 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x22, 0x0a, 0x65, 0x6e, 0x64, - 0x0a + 0x28, 0x74, 0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x75, + 0x73, 0x68, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x29, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, + 0x70, 0x75, 0x73, 0x68, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x74, 0x6f, 0x5f, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x5d, 0x20, + 0x6f, 0x72, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, + 0x73, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, + 0x74, 0x6f, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x29, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, + 0x74, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x22, 0x0a, + 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x69, 0x66, + 0x20, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x74, + 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x22, 0x20, + 0x2e, 0x2e, 0x20, 0x74, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x69, 0x73, 0x5f, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x74, 0x5d, 0x20, 0x6f, + 0x72, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, 0x73, + 0x65, 0x28, 0x74, 0x2c, 0x20, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, + 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, + 0x20, 0x6f, 0x72, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, + 0x73, 0x75, 0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x22, 0x0a, 0x65, + 0x6e, 0x64, 0x0a }; -unsigned int lua_basic_lua_len = 9073; +unsigned int lua_basic_lua_len = 9159; diff --git a/lib/tolua++/src/bin/declaration_lua.h b/lib/tolua++/src/bin/declaration_lua.h index 28deb4f60..a562a7779 100644 --- a/lib/tolua++/src/bin/declaration_lua.h +++ b/lib/tolua++/src/bin/declaration_lua.h @@ -1154,7 +1154,7 @@ static const unsigned char lua_declaration_lua[] = { 0x72, 0x6d, 0x3a, 0x20, 0x6d, 0x6f, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x31, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28, - 0x73, 0x2c, 0x22, 0x28, 0x25, 0x62, 0x5c, 0x5b, 0x5c, 0x5d, 0x29, 0x22, + 0x73, 0x2c, 0x22, 0x28, 0x25, 0x62, 0x25, 0x5b, 0x25, 0x5d, 0x29, 0x22, 0x2c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6e, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28, 0x6e, 0x2c, 0x27, 0x25, 0x2a, 0x27, 0x2c, 0x27, 0x5c, 0x31, diff --git a/src/World.h b/src/World.h index 45b42b280..0a8dcffc4 100644 --- a/src/World.h +++ b/src/World.h @@ -597,7 +597,7 @@ public: void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); /** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value */ - EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ) const; + EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ); /** Sets the biome at the specified coords. Returns true if successful, false if not (chunk not loaded). Doesn't resend the chunk to clients, use ForceSendChunkTo() for that. */ @@ -711,7 +711,7 @@ public: bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } /** Returns true if it is sunny at the specified location. This takes into account biomes. */ - bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const + bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) { return (IsWeatherSunny() || IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } @@ -720,7 +720,7 @@ public: bool IsWeatherRain(void) const { return (m_Weather == wRain); } /** Returns true if it is raining at the specified location. This takes into account biomes. */ - bool IsWeatherRainAt (int a_BlockX, int a_BlockZ) const + bool IsWeatherRainAt (int a_BlockX, int a_BlockZ) { return (IsWeatherRain() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } @@ -729,7 +729,7 @@ public: bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } /** Returns true if the weather is stormy at the specified location. This takes into account biomes. */ - bool IsWeatherStormAt(int a_BlockX, int a_BlockZ) const + bool IsWeatherStormAt(int a_BlockX, int a_BlockZ) { return (IsWeatherStorm() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } @@ -738,7 +738,7 @@ public: bool IsWeatherWet(void) const { return !IsWeatherSunny(); } /** Returns true if it is raining, stormy or snowing at the specified location. This takes into account biomes. */ - bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) const + bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) { return (IsWeatherWet() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } From f9fd5193602f4cbf0b201e13e9b410b264d09bf2 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 11 Jun 2014 17:26:10 +0100 Subject: [PATCH 38/48] Changed the teleport permissions to the new ones. --- src/GroupManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 523697b07..e570bb2b1 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -123,7 +123,7 @@ bool cGroupManager::LoadGroups() IniFile.SetValue("Owner", "Permissions", "*", true); IniFile.SetValue("Owner", "Color", "2", true); - IniFile.SetValue("Moderator", "Permissions", "core.time,core.item,core.teleport,core.ban,core.unban,core.save-all,core.toggledownfall"); + IniFile.SetValue("Moderator", "Permissions", "core.time,core.item,core.tpa,core.tpaccept,core.ban,core.unban,core.save-all,core.toggledownfall"); IniFile.SetValue("Moderator", "Color", "2", true); IniFile.SetValue("Moderator", "Inherits", "Player", true); From 7cf544079f910ac8068b67ad39178ad040816367 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 11 Jun 2014 19:12:29 +0200 Subject: [PATCH 39/48] Roads in villages are made out of wooden planks if they generate on water. --- src/Generating/VillageGen.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index b9cb056ad..9917141ed 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -116,7 +116,8 @@ public: int a_Density, cPiecePool & a_Prefabs, cTerrainHeightGen & a_HeightGen, - BLOCKTYPE a_RoadBlock + BLOCKTYPE a_RoadBlock, + BLOCKTYPE a_WaterRoadBlock ) : super(a_OriginX, a_OriginZ), m_Seed(a_Seed), @@ -126,7 +127,8 @@ public: m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, 255, a_OriginZ + a_MaxSize), m_Prefabs(a_Prefabs), m_HeightGen(a_HeightGen), - m_RoadBlock(a_RoadBlock) + m_RoadBlock(a_RoadBlock), + m_WaterRoadBlock(a_WaterRoadBlock) { // Generate the pieces for this village; don't care about the Y coord: cBFSPieceGenerator pg(*this, a_Seed); @@ -179,6 +181,9 @@ protected: /** The block to use for the roads. */ BLOCKTYPE m_RoadBlock; + + /** The block used for the roads if the road is on water. */ + BLOCKTYPE m_WaterRoadBlock; // cGridStructGen::cStructure overrides: @@ -239,7 +244,14 @@ protected: { for (int x = MinX; x <= MaxX; x++) { - a_Chunk.SetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, m_RoadBlock); + if (IsBlockWater(a_Chunk.GetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z))) + { + a_Chunk.SetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, m_WaterRoadBlock); + } + else + { + a_Chunk.SetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, m_RoadBlock); + } } } } @@ -374,6 +386,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_ // If just one is not, no village is created, because it's likely that an unfriendly biome is too close cVillagePiecePool * VillagePrefabs = NULL; BLOCKTYPE RoadBlock = E_BLOCK_GRAVEL; + BLOCKTYPE WaterRoadBlock = E_BLOCK_PLANKS; int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 11; cVillagePiecePool * PlainsVillage = g_PlainsVillagePools[rnd % ARRAYCOUNT(g_PlainsVillagePools)]; cVillagePiecePool * DesertVillage = g_DesertVillagePools[rnd % ARRAYCOUNT(g_DesertVillagePools)]; @@ -422,7 +435,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_ { return cStructurePtr(); } - return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, Density, *VillagePrefabs, m_HeightGen, RoadBlock)); + return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, Density, *VillagePrefabs, m_HeightGen, RoadBlock, WaterRoadBlock)); } From 220e6f5880354c9984e18718f723331bb904df45 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 11 Jun 2014 19:46:24 +0200 Subject: [PATCH 40/48] DispenserEntity code cleanup after PR merge. --- src/BlockEntities/DispenserEntity.cpp | 41 ++++++++++++--------------- src/BlockEntities/DispenserEntity.h | 19 ++++++++----- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index 97e25ca6d..c02c68afa 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -150,31 +150,27 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20); m_Contents.ChangeSlotCount(a_SlotNum, -1); - break; } case E_ITEM_ARROW: { - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20); + SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); m_Contents.ChangeSlotCount(a_SlotNum, -1); - break; } case E_ITEM_SNOWBALL: { - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20); + SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); m_Contents.ChangeSlotCount(a_SlotNum, -1); - break; } case E_ITEM_EGG: { - SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20); + SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); m_Contents.ChangeSlotCount(a_SlotNum, -1); - break; } @@ -194,31 +190,30 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) -void cDispenserEntity::SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_Kind, Vector3d a_ShootVector) -{ - if (a_Kind != cProjectileEntity::pkFireCharge) - { - a_ShootVector.y = a_ShootVector.y + 1; - } - m_World->CreateProjectile((double) a_BlockX + 0.5, (double) a_BlockY + 0.5, (double) a_BlockZ + 0.5, a_Kind, NULL, NULL, &a_ShootVector); + +void cDispenserEntity::SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_ShootVector) +{ + m_World->CreateProjectile((double)a_BlockX + 0.5, (double)a_BlockY + 0.5, (double)a_BlockZ + 0.5, a_Kind, NULL, NULL, &a_ShootVector); } -Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE & a_Meta) + + + +Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE a_Meta) { - switch(a_Meta) + switch (a_Meta) { - case E_META_DROPSPENSER_FACING_YP: return Vector3d( 0, 1, 0); // UP - case E_META_DROPSPENSER_FACING_YM: return Vector3d( 0, -1, 0); // DOWN - - case E_META_DROPSPENSER_FACING_XM: return Vector3d(-1, 0, 0); // WEST - case E_META_DROPSPENSER_FACING_XP: return Vector3d( 1, 0, 0); // EAST - + case E_META_DROPSPENSER_FACING_YP: return Vector3d( 0, 1, 0); + case E_META_DROPSPENSER_FACING_YM: return Vector3d( 0, -1, 0); + case E_META_DROPSPENSER_FACING_XM: return Vector3d(-1, 0, 0); + case E_META_DROPSPENSER_FACING_XP: return Vector3d( 1, 0, 0); case E_META_DROPSPENSER_FACING_ZM: return Vector3d( 0, 0, -1); case E_META_DROPSPENSER_FACING_ZP: return Vector3d( 0, 0, 1); } - + LOGWARNING("Unhandled dispenser meta: %d", a_Meta); + ASSERT(!"Unhandled dispenser facing"); return Vector3d(0, 1, 0); } diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h index 9410a1129..b33d08342 100644 --- a/src/BlockEntities/DispenserEntity.h +++ b/src/BlockEntities/DispenserEntity.h @@ -17,25 +17,30 @@ public: // tolua_end - /// Constructor used for normal operation + /** Constructor used for normal operation */ cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); static const char * GetClassStatic(void) { return "cDispenserEntity"; } - /** Spawns a projectile of the given kind in front of the dispenser */ - void SpawnProjectileFromDispenser(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cProjectileEntity::eKind a_Kind, Vector3d a_ShootVector); + // tolua_begin + + /** Spawns a projectile of the given kind in front of the dispenser with the specified speed. */ + void SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_Speed); - /** Returns how to aim the projectile */ - Vector3d GetShootVector(NIBBLETYPE & a_Meta); + /** Returns a unit vector in the cardinal direction of where the dispenser is facing. */ + Vector3d GetShootVector(NIBBLETYPE a_Meta); + + // tolua_end private: // cDropSpenser overrides: virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) override; - /// If such a bucket can fit, adds it to m_Contents and returns true + /** If such a bucket can fit, adds it to m_Contents and returns true */ bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType); - /// If the a_BlockInFront is liquidable and the empty bucket can fit, does the m_Contents processing and returns true + /** If the a_BlockInFront can be washed away by liquid and the empty bucket can fit, + does the m_Contents processing and returns true. Returns false otherwise. */ bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum); } ; // tolua_export From 3e7384d9210b726a12ec6244aa0419474f08c6d3 Mon Sep 17 00:00:00 2001 From: Qais Patankar Date: Thu, 12 Jun 2014 15:01:24 +0100 Subject: [PATCH 41/48] Fix typo in handy_functions.lua --- MCServer/Plugins/Handy/handy_functions.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MCServer/Plugins/Handy/handy_functions.lua b/MCServer/Plugins/Handy/handy_functions.lua index c142ffd08..af43f663a 100644 --- a/MCServer/Plugins/Handy/handy_functions.lua +++ b/MCServer/Plugins/Handy/handy_functions.lua @@ -6,7 +6,7 @@ function GetHandyVersion() return HANDY_VERSION end -- Checks if handy is in proper version -function CheckForRequiedVersion( inVersion ) +function CheckForRequiredVersion( inVersion ) if( inVersion > HANDY_VERSION ) then return false end return true end @@ -213,4 +213,4 @@ end function BoolToString( inValue ) if( inValue == true ) then return 1 end return 0 -end \ No newline at end of file +end From 1bce1ac4327965453d7709503c5f0b4d8b3edea6 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 12 Jun 2014 17:13:39 +0100 Subject: [PATCH 42/48] Fixed two redstone bugs * Fixed chunk border powering * Fixed quick place-replace powering --- src/Simulator/IncrementalRedstoneSimulator.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index b32a57165..eff11bd01 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -65,6 +65,7 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width; RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width; a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); + a_OtherChunk->SetIsRedstoneDirty(true); } else { @@ -199,6 +200,7 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, } else { + itr->DataTwo = false; itr->Data = Block; // Update block information } return; @@ -802,11 +804,15 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int { if (a_Itr->a_RelBlockPos == Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { + // Leave a_Itr at where we found the entry break; } } } + // a_Itr may be passed with m_RepeatersDelayList::end, however, we can guarantee this iterator is always valid because... + // ...QueueRepeaterPowerChange is called to add an entry (and the above code updates iterator). However, if the repeater was locked or something similar... + // ...we will never get here because of the returns. if (a_Itr->a_ElapsedTicks >= a_Itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks? { if (a_Itr->ShouldPowerOn) From 9254666a85f9e4562081bea336c8be0e612fa44d Mon Sep 17 00:00:00 2001 From: tycho Date: Thu, 12 Jun 2014 18:00:53 +0100 Subject: [PATCH 43/48] automaticlly build tolua and generate bindings as part of build. --- src/Bindings/tolua++.exe | Bin 200704 -> 0 bytes src/CMakeLists.txt | 169 ++++++++++++++++++++------------------- 2 files changed, 85 insertions(+), 84 deletions(-) delete mode 100644 src/Bindings/tolua++.exe diff --git a/src/Bindings/tolua++.exe b/src/Bindings/tolua++.exe deleted file mode 100644 index ba3a6b0c703968167e89e26e649c1dc33c49cdaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200704 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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 900577526..c5156e50c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,91 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include") set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++) set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs) +set(BINDING_DEPENDECIES + tolua + ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/virtual_method_hooks.lua + ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/AllToLua.pkg + Bindings/LuaFunctions.h + Bindings/LuaWindow.h + Bindings/Plugin.h + Bindings/PluginLua.h + Bindings/PluginManager.h + Bindings/WebPlugin.h + BiomeDef.h + BlockArea.h + BlockEntities/BlockEntity.h + BlockEntities/BlockEntityWithItems.h + BlockEntities/ChestEntity.h + BlockEntities/DispenserEntity.h + BlockEntities/DropSpenserEntity.h + BlockEntities/DropperEntity.h + BlockEntities/FurnaceEntity.h + BlockEntities/HopperEntity.h + BlockEntities/JukeboxEntity.h + BlockEntities/NoteEntity.h + BlockEntities/SignEntity.h + BlockEntities/MobHeadEntity.h + BlockEntities/FlowerPotEntity.h + BlockID.h + BoundingBox.h + ChatColor.h + ChunkDef.h + ClientHandle.h + CraftingRecipes.h + Cuboid.h + Defines.h + Enchantments.h + Entities/Effects.h + Entities/Entity.h + Entities/Floater.h + Entities/Pawn.h + Entities/Painting.h + Entities/Pickup.h + Entities/Player.h + Entities/ProjectileEntity.h + Entities/ArrowEntity.h + Entities/ThrownEggEntity.h + Entities/ThrownEnderPearlEntity.h + Entities/ExpBottleEntity.h + Entities/ThrownSnowballEntity.h + Entities/FireChargeEntity.h + Entities/FireworkEntity.h + Entities/GhastFireballEntity.h + Entities/TNTEntity.h + Entities/ExpOrb.h + Entities/HangingEntity.h + Entities/ItemFrame.h + Generating/ChunkDesc.h + Group.h + Inventory.h + Item.h + ItemGrid.h + Mobs/Monster.h + OSSupport/File.h + Root.h + Server.h + StringUtils.h + Tracer.h + UI/Window.h + Vector3.h + WebAdmin.h + World.h +) + +include_directories(Bindings) +include_directories(.) + +ADD_CUSTOM_COMMAND( + # add any new generated bindings here + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/Bindings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/Bindings.h + + # command execuded to regerate bindings + COMMAND tolua -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/ + + # add any new generation dependencies here + DEPENDS ${BINDING_DEPENDECIES} +) if (NOT MSVC) @@ -15,91 +100,7 @@ if (NOT MSVC) # lib dependencies are not included - set(BINDING_DEPENDECIES - tolua - ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/virtual_method_hooks.lua - ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/AllToLua.pkg - Bindings/LuaFunctions.h - Bindings/LuaWindow.h - Bindings/Plugin.h - Bindings/PluginLua.h - Bindings/PluginManager.h - Bindings/WebPlugin.h - BiomeDef.h - BlockArea.h - BlockEntities/BlockEntity.h - BlockEntities/BlockEntityWithItems.h - BlockEntities/ChestEntity.h - BlockEntities/DispenserEntity.h - BlockEntities/DropSpenserEntity.h - BlockEntities/DropperEntity.h - BlockEntities/FurnaceEntity.h - BlockEntities/HopperEntity.h - BlockEntities/JukeboxEntity.h - BlockEntities/NoteEntity.h - BlockEntities/SignEntity.h - BlockEntities/MobHeadEntity.h - BlockEntities/FlowerPotEntity.h - BlockID.h - BoundingBox.h - ChatColor.h - ChunkDef.h - ClientHandle.h - CraftingRecipes.h - Cuboid.h - Defines.h - Enchantments.h - Entities/Effects.h - Entities/Entity.h - Entities/Floater.h - Entities/Pawn.h - Entities/Painting.h - Entities/Pickup.h - Entities/Player.h - Entities/ProjectileEntity.h - Entities/ArrowEntity.h - Entities/ThrownEggEntity.h - Entities/ThrownEnderPearlEntity.h - Entities/ExpBottleEntity.h - Entities/ThrownSnowballEntity.h - Entities/FireChargeEntity.h - Entities/FireworkEntity.h - Entities/GhastFireballEntity.h - Entities/TNTEntity.h - Entities/ExpOrb.h - Entities/HangingEntity.h - Entities/ItemFrame.h - Generating/ChunkDesc.h - Group.h - Inventory.h - Item.h - ItemGrid.h - Mobs/Monster.h - OSSupport/File.h - Root.h - Server.h - StringUtils.h - Tracer.h - UI/Window.h - Vector3.h - WebAdmin.h - World.h - ) - include_directories(Bindings) - include_directories(.) - - ADD_CUSTOM_COMMAND( - # add any new generated bindings here - OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/Bindings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/Bindings.h - - # command execuded to regerate bindings - COMMAND tolua -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/ - - # add any new generation dependencies here - DEPENDS ${BINDING_DEPENDECIES} - ) #add cpp files here add_library(Bindings Bindings/Bindings From 383c5c2c89661bfadab7c3b8bbfcf57401e952f2 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Thu, 12 Jun 2014 19:31:16 +0100 Subject: [PATCH 44/48] Typo Correction --- GETTING-STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GETTING-STARTED.md b/GETTING-STARTED.md index eb7d1b713..d78b2f84f 100644 --- a/GETTING-STARTED.md +++ b/GETTING-STARTED.md @@ -3,7 +3,7 @@ Hello! Thanks for wanting to work on this project :smile:, and I hope that this Minecraft Basics ---------------- -If you don't play Minecraft or don't have a great knowledge of the basic systems, you should get to know them. The [Minecraft Wiki](http://minecraft.gamepedia.com/Minecraft_Wiki) is quite useful for this task, although some youtubers are also fairly good at teaching the basics and just playing is quite good too. It is possabile to contribute without knowing minecraft in detail though. +If you don't play Minecraft or don't have a great knowledge of the basic systems, you should get to know them. The [Minecraft Wiki](http://minecraft.gamepedia.com/Minecraft_Wiki) is quite useful for this task, although some youtubers are also fairly good at teaching the basics and just playing is quite good too. It is possible to contribute without knowing minecraft in detail though. I'd say that the important topics are: From 72043f5b0cc2e930c2a616d84a8fea25f7224c59 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 13 Jun 2014 00:09:01 +0200 Subject: [PATCH 45/48] APIDump: Added the Info.lua article. Fixes #504. --- MCServer/Plugins/APIDump/APIDesc.lua | 1 + MCServer/Plugins/APIDump/InfoFile.html | 246 +++++++++++++++++++++++++ 2 files changed, 247 insertions(+) create mode 100644 MCServer/Plugins/APIDump/InfoFile.html diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index c97e2dbf8..19ca971e2 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2934,6 +2934,7 @@ end { -- No sorting is provided for these, they will be output in the same order as defined here { FileName = "Writing-a-MCServer-plugin.html", Title = "Writing a MCServer plugin" }, + { FileName = "InfoFile.html", Title = "Using the Info.lua file" }, { FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" }, { FileName = "SettingUpZeroBrane.html", Title = "Setting up the ZeroBrane Studio Lua IDE" }, { FileName = "UsingChunkStays.html", Title = "Using ChunkStays" }, diff --git a/MCServer/Plugins/APIDump/InfoFile.html b/MCServer/Plugins/APIDump/InfoFile.html new file mode 100644 index 000000000..3fff06d20 --- /dev/null +++ b/MCServer/Plugins/APIDump/InfoFile.html @@ -0,0 +1,246 @@ + + + + MCServer - Info.lua file + + + + + + + + + + From f76420ac55edd82e06042a93927e275e5799d59f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 13 Jun 2014 09:38:25 +0200 Subject: [PATCH 46/48] Removed an unused fwd declaration. --- src/World.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/World.h b/src/World.h index 0a8dcffc4..3e63e2b8c 100644 --- a/src/World.h +++ b/src/World.h @@ -47,7 +47,6 @@ class cFlowerPotEntity; class cFurnaceEntity; class cNoteEntity; class cMobHeadEntity; -class cMobCensus; class cCompositeChat; class cCuboid; From b0f1707d50895d47634095592f68da63621f6507 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Fri, 13 Jun 2014 23:16:52 +0200 Subject: [PATCH 47/48] Fixed ChunkWorx stop button giving an error --- MCServer/Plugins/ChunkWorx/chunkworx_web.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MCServer/Plugins/ChunkWorx/chunkworx_web.lua b/MCServer/Plugins/ChunkWorx/chunkworx_web.lua index 6c5eab676..9aec38b12 100644 --- a/MCServer/Plugins/ChunkWorx/chunkworx_web.lua +++ b/MCServer/Plugins/ChunkWorx/chunkworx_web.lua @@ -43,7 +43,7 @@ function HandleRequest_Generation( Request ) local Content = "" if (Request.PostParams["AGHRRRR"] ~= nil) then GENERATION_STATE = 0 - WW_instance:SaveAllChunks() + WW_instance:QueueSaveAllChunks() WW_instance:QueueUnloadUnusedChunks() LOGERROR("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": works ABORTED by admin") end From 4b28a24514316f04d596e248a75b382701a01217 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 14 Jun 2014 09:51:42 +0100 Subject: [PATCH 48/48] Reduced cPluginManager code duplication --- src/Bindings/PluginManager.cpp | 464 +++++++++++++-------------------- 1 file changed, 178 insertions(+), 286 deletions(-) diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index acfc91bf8..9bcd8e3b7 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -14,6 +14,13 @@ #include "inifile/iniFile.h" #include "../Entities/Player.h" +#define FIND_HOOK(a_HookName) HookMap::iterator Plugins = m_Hooks.find(a_HookName); +#define VERIFY_HOOK \ + if (Plugins == m_Hooks.end()) \ + { \ + return false; \ + } + @@ -192,7 +199,7 @@ void cPluginManager::Tick(float a_Dt) ReloadPluginsNow(); } - HookMap::iterator Plugins = m_Hooks.find(HOOK_TICK); + FIND_HOOK(HOOK_TICK); if (Plugins != m_Hooks.end()) { for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) @@ -208,11 +215,9 @@ void cPluginManager::Tick(float a_Dt) bool cPluginManager::CallHookBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_BLOCK_SPREAD); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_BLOCK_SPREAD); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnBlockSpread(a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source)) @@ -233,11 +238,9 @@ bool cPluginManager::CallHookBlockToPickups( cItems & a_Pickups ) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_BLOCK_TO_PICKUPS); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_BLOCK_TO_PICKUPS); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnBlockToPickups(a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups)) @@ -275,11 +278,8 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) return true; // Cancel sending } - HookMap::iterator Plugins = m_Hooks.find(HOOK_CHAT); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_CHAT); + VERIFY_HOOK; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { @@ -298,11 +298,9 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) bool cPluginManager::CallHookChunkAvailable(cWorld * a_World, int a_ChunkX, int a_ChunkZ) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_CHUNK_AVAILABLE); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_CHUNK_AVAILABLE); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnChunkAvailable(a_World, a_ChunkX, a_ChunkZ)) @@ -319,11 +317,9 @@ bool cPluginManager::CallHookChunkAvailable(cWorld * a_World, int a_ChunkX, int bool cPluginManager::CallHookChunkGenerated(cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_CHUNK_GENERATED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_CHUNK_GENERATED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnChunkGenerated(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc)) @@ -340,11 +336,9 @@ bool cPluginManager::CallHookChunkGenerated(cWorld * a_World, int a_ChunkX, int bool cPluginManager::CallHookChunkGenerating(cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_CHUNK_GENERATING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_CHUNK_GENERATING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnChunkGenerating(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc)) @@ -361,11 +355,9 @@ bool cPluginManager::CallHookChunkGenerating(cWorld * a_World, int a_ChunkX, int bool cPluginManager::CallHookChunkUnloaded(cWorld * a_World, int a_ChunkX, int a_ChunkZ) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_CHUNK_UNLOADED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_CHUNK_UNLOADED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnChunkUnloaded(a_World, a_ChunkX, a_ChunkZ)) @@ -382,11 +374,9 @@ bool cPluginManager::CallHookChunkUnloaded(cWorld * a_World, int a_ChunkX, int a bool cPluginManager::CallHookChunkUnloading(cWorld * a_World, int a_ChunkX, int a_ChunkZ) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_CHUNK_UNLOADING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_CHUNK_UNLOADING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnChunkUnloading(a_World, a_ChunkX, a_ChunkZ)) @@ -403,11 +393,9 @@ bool cPluginManager::CallHookChunkUnloading(cWorld * a_World, int a_ChunkX, int bool cPluginManager::CallHookCollectingPickup(cPlayer * a_Player, cPickup & a_Pickup) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_COLLECTING_PICKUP); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_COLLECTING_PICKUP); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnCollectingPickup(a_Player, &a_Pickup)) @@ -424,11 +412,9 @@ bool cPluginManager::CallHookCollectingPickup(cPlayer * a_Player, cPickup & a_Pi bool cPluginManager::CallHookCraftingNoRecipe(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_CRAFTING_NO_RECIPE); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_CRAFTING_NO_RECIPE); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnCraftingNoRecipe(a_Player, a_Grid, a_Recipe)) @@ -445,11 +431,9 @@ bool cPluginManager::CallHookCraftingNoRecipe(const cPlayer * a_Player, const cC bool cPluginManager::CallHookDisconnect(cClientHandle & a_Client, const AString & a_Reason) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_DISCONNECT); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_DISCONNECT); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnDisconnect(a_Client, a_Reason)) @@ -466,11 +450,9 @@ bool cPluginManager::CallHookDisconnect(cClientHandle & a_Client, const AString bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_EXECUTE_COMMAND); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_EXECUTE_COMMAND); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnExecuteCommand(a_Player, a_Split)) @@ -487,11 +469,9 @@ bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVec bool cPluginManager::CallHookExploded(cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_EXPLODED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_EXPLODED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnExploded(a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData)) @@ -508,11 +488,9 @@ bool cPluginManager::CallHookExploded(cWorld & a_World, double a_ExplosionSize, bool cPluginManager::CallHookExploding(cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_EXPLODING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_EXPLODING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnExploding(a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData)) @@ -529,11 +507,9 @@ bool cPluginManager::CallHookExploding(cWorld & a_World, double & a_ExplosionSiz bool cPluginManager::CallHookHandshake(cClientHandle * a_ClientHandle, const AString & a_Username) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_HANDSHAKE); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_HANDSHAKE); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnHandshake(a_ClientHandle, a_Username)) @@ -550,11 +526,9 @@ bool cPluginManager::CallHookHandshake(cClientHandle * a_ClientHandle, const ASt bool cPluginManager::CallHookHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_HOPPER_PULLING_ITEM); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_HOPPER_PULLING_ITEM); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnHopperPullingItem(a_World, a_Hopper, a_DstSlotNum, a_SrcEntity, a_SrcSlotNum)) @@ -571,11 +545,9 @@ bool cPluginManager::CallHookHopperPullingItem(cWorld & a_World, cHopperEntity & bool cPluginManager::CallHookHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_HOPPER_PUSHING_ITEM); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_HOPPER_PUSHING_ITEM); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnHopperPushingItem(a_World, a_Hopper, a_SrcSlotNum, a_DstEntity, a_DstSlotNum)) @@ -592,11 +564,9 @@ bool cPluginManager::CallHookHopperPushingItem(cWorld & a_World, cHopperEntity & bool cPluginManager::CallHookKilling(cEntity & a_Victim, cEntity * a_Killer) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_KILLING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_KILLING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnKilling(a_Victim, a_Killer)) @@ -613,11 +583,9 @@ bool cPluginManager::CallHookKilling(cEntity & a_Victim, cEntity * a_Killer) bool cPluginManager::CallHookLogin(cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_LOGIN); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_LOGIN); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnLogin(a_Client, a_ProtocolVersion, a_Username)) @@ -634,11 +602,9 @@ bool cPluginManager::CallHookLogin(cClientHandle * a_Client, int a_ProtocolVersi bool cPluginManager::CallHookPlayerAnimation(cPlayer & a_Player, int a_Animation) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_ANIMATION); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_ANIMATION); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerAnimation(a_Player, a_Animation)) @@ -655,11 +621,9 @@ bool cPluginManager::CallHookPlayerAnimation(cPlayer & a_Player, int a_Animation bool cPluginManager::CallHookPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_BREAKING_BLOCK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_BREAKING_BLOCK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerBreakingBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta)) @@ -676,11 +640,9 @@ bool cPluginManager::CallHookPlayerBreakingBlock(cPlayer & a_Player, int a_Block bool cPluginManager::CallHookPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_BROKEN_BLOCK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_BROKEN_BLOCK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerBrokenBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta)) @@ -697,11 +659,9 @@ bool cPluginManager::CallHookPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, bool cPluginManager::CallHookPlayerDestroyed(cPlayer & a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_DESTROYED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_DESTROYED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerDestroyed(a_Player)) @@ -718,11 +678,9 @@ bool cPluginManager::CallHookPlayerDestroyed(cPlayer & a_Player) bool cPluginManager::CallHookPlayerEating(cPlayer & a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_EATING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_EATING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerEating(a_Player)) @@ -739,11 +697,9 @@ bool cPluginManager::CallHookPlayerEating(cPlayer & a_Player) bool cPluginManager::CallHookPlayerFished(cPlayer & a_Player, const cItems a_Reward) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_FISHED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_FISHED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerFished(a_Player, a_Reward)) @@ -760,11 +716,9 @@ bool cPluginManager::CallHookPlayerFished(cPlayer & a_Player, const cItems a_Rew bool cPluginManager::CallHookPlayerFishing(cPlayer & a_Player, cItems a_Reward) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_FISHING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_FISHING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerFishing(a_Player, a_Reward)) @@ -781,11 +735,9 @@ bool cPluginManager::CallHookPlayerFishing(cPlayer & a_Player, cItems a_Reward) bool cPluginManager::CallHookPlayerJoined(cPlayer & a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_JOINED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_JOINED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerJoined(a_Player)) @@ -802,11 +754,9 @@ bool cPluginManager::CallHookPlayerJoined(cPlayer & a_Player) bool cPluginManager::CallHookPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_LEFT_CLICK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_LEFT_CLICK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerLeftClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status)) @@ -823,11 +773,9 @@ bool cPluginManager::CallHookPlayerLeftClick(cPlayer & a_Player, int a_BlockX, i bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_MOVING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_MOVING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerMoved(a_Player)) @@ -844,11 +792,9 @@ bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player) bool cPluginManager::CallHookPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_PLACED_BLOCK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_PLACED_BLOCK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerPlacedBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta)) @@ -865,11 +811,9 @@ bool cPluginManager::CallHookPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, bool cPluginManager::CallHookPlayerPlacingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_PLACING_BLOCK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_PLACING_BLOCK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerPlacingBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta)) @@ -886,11 +830,9 @@ bool cPluginManager::CallHookPlayerPlacingBlock(cPlayer & a_Player, int a_BlockX bool cPluginManager::CallHookPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_RIGHT_CLICK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_RIGHT_CLICK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerRightClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) @@ -907,11 +849,9 @@ bool cPluginManager::CallHookPlayerRightClick(cPlayer & a_Player, int a_BlockX, bool cPluginManager::CallHookPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_RIGHT_CLICKING_ENTITY); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_RIGHT_CLICKING_ENTITY); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerRightClickingEntity(a_Player, a_Entity)) @@ -928,11 +868,9 @@ bool cPluginManager::CallHookPlayerRightClickingEntity(cPlayer & a_Player, cEnti bool cPluginManager::CallHookPlayerShooting(cPlayer & a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_SHOOTING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_SHOOTING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerShooting(a_Player)) @@ -949,11 +887,9 @@ bool cPluginManager::CallHookPlayerShooting(cPlayer & a_Player) bool cPluginManager::CallHookPlayerSpawned(cPlayer & a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_SPAWNED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_SPAWNED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerSpawned(a_Player)) @@ -970,11 +906,9 @@ bool cPluginManager::CallHookPlayerSpawned(cPlayer & a_Player) bool cPluginManager::CallHookPlayerTossingItem(cPlayer & a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_TOSSING_ITEM); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_TOSSING_ITEM); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerTossingItem(a_Player)) @@ -991,11 +925,9 @@ bool cPluginManager::CallHookPlayerTossingItem(cPlayer & a_Player) bool cPluginManager::CallHookPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_USED_BLOCK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_USED_BLOCK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerUsedBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta)) @@ -1012,11 +944,9 @@ bool cPluginManager::CallHookPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, i bool cPluginManager::CallHookPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_USED_ITEM); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_USED_ITEM); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerUsedItem(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) @@ -1033,11 +963,9 @@ bool cPluginManager::CallHookPlayerUsedItem(cPlayer & a_Player, int a_BlockX, in bool cPluginManager::CallHookPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_USING_BLOCK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_USING_BLOCK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerUsingBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta)) @@ -1054,11 +982,9 @@ bool cPluginManager::CallHookPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, bool cPluginManager::CallHookPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_USING_ITEM); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLAYER_USING_ITEM); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPlayerUsingItem(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) @@ -1075,11 +1001,9 @@ bool cPluginManager::CallHookPlayerUsingItem(cPlayer & a_Player, int a_BlockX, i bool cPluginManager::CallHookPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLUGIN_MESSAGE); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLUGIN_MESSAGE); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPluginMessage(a_Client, a_Channel, a_Message)) @@ -1096,11 +1020,9 @@ bool cPluginManager::CallHookPluginMessage(cClientHandle & a_Client, const AStri bool cPluginManager::CallHookPluginsLoaded(void) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PLUGINS_LOADED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PLUGINS_LOADED); + VERIFY_HOOK; + bool res = false; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { @@ -1115,11 +1037,9 @@ bool cPluginManager::CallHookPluginsLoaded(void) bool cPluginManager::CallHookPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_POST_CRAFTING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_POST_CRAFTING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPostCrafting(a_Player, a_Grid, a_Recipe)) @@ -1136,11 +1056,9 @@ bool cPluginManager::CallHookPostCrafting(const cPlayer * a_Player, const cCraft bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PRE_CRAFTING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PRE_CRAFTING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnPreCrafting(a_Player, a_Grid, a_Recipe)) @@ -1157,11 +1075,9 @@ bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCrafti bool cPluginManager::CallHookProjectileHitBlock(cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_BLOCK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PROJECTILE_HIT_BLOCK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnProjectileHitBlock(a_Projectile, a_BlockX, a_BlockY, a_BlockZ, a_Face, a_BlockHitPos)) @@ -1178,11 +1094,9 @@ bool cPluginManager::CallHookProjectileHitBlock(cProjectileEntity & a_Projectile bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_ENTITY); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_PROJECTILE_HIT_ENTITY); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnProjectileHitEntity(a_Projectile, a_HitEntity)) @@ -1199,11 +1113,9 @@ bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectil bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_ENTITY); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_SPAWNED_ENTITY); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnSpawnedEntity(a_World, a_Entity)) @@ -1219,11 +1131,9 @@ bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity) bool cPluginManager::CallHookSpawnedMonster(cWorld & a_World, cMonster & a_Monster) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_MONSTER); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_SPAWNED_MONSTER); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnSpawnedMonster(a_World, a_Monster)) @@ -1239,11 +1149,9 @@ bool cPluginManager::CallHookSpawnedMonster(cWorld & a_World, cMonster & a_Monst bool cPluginManager::CallHookSpawningEntity(cWorld & a_World, cEntity & a_Entity) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNING_ENTITY); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_SPAWNING_ENTITY); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnSpawningEntity(a_World, a_Entity)) @@ -1260,11 +1168,9 @@ bool cPluginManager::CallHookSpawningEntity(cWorld & a_World, cEntity & a_Entity bool cPluginManager::CallHookSpawningMonster(cWorld & a_World, cMonster & a_Monster) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNING_MONSTER); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_SPAWNING_MONSTER); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnSpawningMonster(a_World, a_Monster)) @@ -1281,11 +1187,9 @@ bool cPluginManager::CallHookSpawningMonster(cWorld & a_World, cMonster & a_Mons bool cPluginManager::CallHookTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_TAKE_DAMAGE); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_TAKE_DAMAGE); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnTakeDamage(a_Receiver, a_TDI)) @@ -1302,11 +1206,9 @@ bool cPluginManager::CallHookTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a bool cPluginManager::CallHookUpdatingSign(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_UPDATING_SIGN); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_UPDATING_SIGN); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnUpdatingSign(a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player)) @@ -1323,11 +1225,9 @@ bool cPluginManager::CallHookUpdatingSign(cWorld * a_World, int a_BlockX, int a_ bool cPluginManager::CallHookUpdatedSign(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_UPDATED_SIGN); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_UPDATED_SIGN); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnUpdatedSign(a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player)) @@ -1344,11 +1244,9 @@ bool cPluginManager::CallHookUpdatedSign(cWorld * a_World, int a_BlockX, int a_B bool cPluginManager::CallHookWeatherChanged(cWorld & a_World) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_WEATHER_CHANGED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_WEATHER_CHANGED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnWeatherChanged(a_World)) @@ -1365,11 +1263,9 @@ bool cPluginManager::CallHookWeatherChanged(cWorld & a_World) bool cPluginManager::CallHookWeatherChanging(cWorld & a_World, eWeather & a_NewWeather) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_WEATHER_CHANGING); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_WEATHER_CHANGING); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnWeatherChanging(a_World, a_NewWeather)) @@ -1386,11 +1282,9 @@ bool cPluginManager::CallHookWeatherChanging(cWorld & a_World, eWeather & a_NewW bool cPluginManager::CallHookWorldStarted(cWorld & a_World) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_WORLD_STARTED); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_WORLD_STARTED); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnWorldStarted(a_World)) @@ -1407,11 +1301,9 @@ bool cPluginManager::CallHookWorldStarted(cWorld & a_World) bool cPluginManager::CallHookWorldTick(cWorld & a_World, float a_Dt, int a_LastTickDurationMSec) { - HookMap::iterator Plugins = m_Hooks.find(HOOK_WORLD_TICK); - if (Plugins == m_Hooks.end()) - { - return false; - } + FIND_HOOK(HOOK_WORLD_TICK); + VERIFY_HOOK; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnWorldTick(a_World, a_Dt, a_LastTickDurationMSec))
+

Info.lua file

+

Contents

+
+ + +
+

Introduction

+ +

For a long time MCServer plugins were plagued by poor documentation. The plugins worked, people who wrote them knew how to use them, but for anyone new to the plugin it was a terrible ordeal learning how to use it. Most of the times, the plugin authors only wrote what commands the plugin supported, sometimes not even that. Then, there was a call to action to put an end to this, to make documenting the plugins easy and at the same time centralized. Thus, the Info.lua file was born.

+ +

Most plugins have some parts that are the same across all the plugins. These are commands, console commands and their permissions. If a plugin implemented a command, it would practically copy & paste the same code over and over again. So it makes sense to extract only unique information, centralize it and automate all the parts around it. This was another reason for the Info.lua file - it is a central hub of commands, console commands and their permissions.

+ +

Last, but not least, we want to make a plugin repository on the web in the future, a repository that would store plugins, their descriptions, comments. It makes sense that the centralized information can be parsed by the repository automatically, so that advanced things, such as searching for a plugin based on a command, or determining whether two plugins collide command-wise, are possible.

+ +

After this file format has been devised, a tool has been written that allows for an easy generation of the documentation for the plugin in various formats. It outputs the documentation in a format that is perfect for pasting into the forum. It generates documentation in a Markup format to use in README.md on GitHub and similar sites. The clever thing is that you don't need to keep all those formats in sync manually - you edit the Info.lua file and this tool will re-generate the documentation for you.

+ +

So to sum up, the Info.lua file contains the plugins' commands, console commands, their permissions and possibly the overall plugin documentation, in a structured manner that can be parsed by a program, yet is human readable and editable.

+ + +
+

The overall structure

+ +

The file consist of a declaration of a single Lua table, g_PluginInfo. This table contains all the information, structured, as its members. Each member can be a structure by itself. The entire file is a valid Lua source file, so any tool that syntax-checks Lua source can syntax-check this file. The file is somewhat forward- and backward- compatible, in the sense that it can be extended in any way without breaking.

+

Here's a skeleton of the file:

+
+g_PluginInfo =
+{
+	Name = "Example Plugin",
+	Date = "2014-06-12",
+	Description = "This is an example plugin that shows how to use the Info.lua file",
+	
+	-- The following members will be documented in greater detail later:
+	AdditionalInformation = {},
+	Commands = {},
+	ConsoleCommands = {},
+	Permissions = {},
+}
+
+

As you can see, the structure is pretty straightforward. Note that the order of the elements inside the table is not important (Lua property).

+ +

The first few elements are for book-keeping. They declare the plugin's name, the date in ISO-format, representing the version of the plugin, and the description. The idea is that the description sums up what the plugin is all about, within some two or three sentences.

+ + +
+

AdditionalInformation table

+ +

This table is used for more detailed description of the plugin. If there is any non-trivial setup process, dependencies, describe them here. This is where the description should get detailed. Don't worry about using several paragraphs of text here, if it makes the plugin easier to understand.

+ +

The table should have the following layout:

+
+AdditionalInformation =
+{
+	{
+		Title = "Chapter 1",
+		Contents = "Describe one big aspect of the plugin here",
+	},
+	{
+		Title = "Chapter 2",
+		Contents = "Describe another big topic",
+	},
+}
+
+

The idea here is that the tool that is used to generate the documentation from the Info.lua file will create a linkified table of contents and then each of the information elements' contents. This information should be all that is needed to successfully configure, run and manage the plugin.

+ + +
+

Commands table

+ +

The commands table lists all the commands that the plugin implements, together with their handler functions, required permissions, help strings and further information. The table supports recursion, which allows plugins to create multi-word commands easily (such as "//schematic load" and "//schematic save"), each having its own separate handler.

+ +

The table uses structure similar to the following:

+
+Commands =
+{
+	["/cmd1"] =
+	{
+		HelpString = "Performs the first action",
+		Permission = "firstplugin.cmds.1",
+		Alias = "/c1",
+		Handler = HandleCmd1,
+		ParameterCombinations =
+		{
+			{
+				Params = "x y z",
+				Help = "Performs the first action at the specified coordinates",
+			},
+			{
+				Params = "-p",
+				Help = "Performs the first action at the player's coordinates",
+			}
+		},
+	},
+	["/cmd2"] =
+	{
+		Alias = {"/c2", "//c2" },
+		Subcommands =
+		{
+			sub1 =  -- This declares a "/cmd2 sub1" command
+			{
+				HelpString = "Performs the second action's first subcommand",
+				Permission = "firstplugin.cmds.2.1",
+				Alias = "1",
+				Handler = HandleCmd2Sub1,
+				ParameterCombinations =
+				{
+					{
+						Params = "x y z",
+						Help = "Performs the second action's first subcommand at the specified coordinates",
+					},
+					{
+						Params = "-p",
+						Help = "Performs the second action's first subcommand at the player's coordinates",
+					}
+				},
+			},
+			sub2 =  -- Declares a "/cmd2 sub2" command
+			{
+				HelpString = "Performs the second action's second subcommand",
+				Permission = "firstplugin.cmds.2.2",
+				Handler = HandleCmd2Sub2,
+			},
+		},
+	},
+}
+
+ +

Although it may seem overwhelming at first, there is a "method to this madness". Each element of the Commands table defines one command. Most commands start with a slash, so the special Lua syntax for table elements with non-standard names needs to be applied (["/cmd1"] =). The command can either specify subcommands, or a handler function (specifying both is UndefinedBehavior). Subcommands uses the same structure as the entire Commands table, recursively.

+ +

The permission element specifies that the command is only available with the specified permission. Note that the permission for subcommand's parent isn't checked when the subcommand is called. This means that specifying the permission for a command that has subcommands has no effect whatsoever, but is discouraged because we may add processing for that in the future.

+ +

The ParameterCombinations table is used only for generating the documentation, it lists the various combinations of parameters that the command supports. It's worth specifying even if the command supports only one combination, because that combination will get documented this way.

+ +

The Alias member specifies any possible aliases for the command. Each alias is registered separately and if there is a subcommand table, it is applied to all aliases, just as one would expect. You can specify either a single string as the value (if there's only one alias), or a table of strings for multiple aliases. Commands with no aliases do not need to specify this member at all.

+ + +
+

ConsoleCommands table

+ +

This table serves a purpose similar to that of the Commands table, only these commands are provided for the server console. Therefore, there are no permissions specified for these commands. Since most console commands don't use a leading slash, the command names don't need the special syntax. Also, the handler function doesn't receive the Player parameter.

+ +

Here's an example of a ConsoleCommands table:

+
+ConsoleCommands =
+{
+	concmd =
+	{
+		HelpString = "Performs the console action",
+		Subcommands =
+		{
+			sub1 =
+			{
+				HelpString = "Performs the console action's first subcommand",
+				Handler = HandleConCmdSub1,
+				ParameterCombinations =
+				{
+					{
+						Params = "x y z",
+						Help = "Performs the console action's first subcommand at the specified coordinates",
+					},
+				},
+			},
+			sub2 =
+			{
+				HelpString = "Performs the console action's second subcommand",
+				Handler = HandleConCmdSub2,
+			},
+		},
+	},
+}
+
+ + +
+

Permissions table

+ +

The purpose of this table is to document permissions that the plugin uses. The documentation generator automatically collects the permissions specified in the Command table; the Permissions table adds a description for these permissions and may declare other permissions that aren't specifically included in the Command table.

+ +
+Permissions =
+{
+	["firstplugin.cmd.1.1"] =
+	{
+		Description = "Allows the players to build high towers using the first action.",
+		RecommendedGroups = "players",
+	},
+	["firstplugin.cmd.2.1"] =
+	{
+		Description = "Allows the players to kill entities using the second action. Note that this may be misused to kill other players, too.",
+		RecommendedGroups = "admins, mods",
+	},
+}
+
+ +

The RecommendedGroup element lists, in plain English, the intended groups for which the permission should be enabled on a typical server. Plugin authors are advised to create reasonable defaults, prefering security to openness, so that admins using these settings blindly don't expose their servers to malicious users.

+ + +
+

Using the file in code

+ +

Just writing the Info.lua file and saving it to the plugin folder is not enough for it to actually be used. Your plugin needs to include the following boilerplate code, preferably in its Initialize() function:

+
+-- Use the InfoReg shared library to process the Info.lua file:
+dofile(cPluginManager:GetPluginsPath() .. "/InfoReg.lua")
+RegisterPluginInfoCommands()
+RegisterPluginInfoConsoleCommands()
+
+ +

Of course, if your plugin doesn't have any console commands, it doesn't need to call the RegisterPluginInfoConsoleCommands() function, and similarly if it doesn't have any in-game commands, it doesn't need to call the RegisterPluginInfoCommands() function.

+ + +
+

Examples

+ +

There are several plugins that already implement this approach. You can visit them for inspiration and to see what the generated documentation looks like:

+ + + +