From 9692f20a99e32a7859e4e8522393d116f11517ba Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 13 Nov 2013 19:36:04 +0000 Subject: Fixed link error with clang on x86_64. --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 338470592..e056a61ec 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -103,7 +103,7 @@ endif UNAME := $(shell uname -s) ifeq ($(UNAME),Linux) - LNK_LIBS = -lstdc++ -ldl + LNK_LIBS = -lstdc++ -ldl -lm else LNK_LIBS = -lstdc++ -lltdl endif -- cgit v1.2.3 From 26ac6881cd5985eefe08fc7307f4d09442b68fd1 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 13 Nov 2013 19:41:05 +0000 Subject: Fixed some of the comments in the makefile. --- GNUmakefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index e056a61ec..de1da1455 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -46,6 +46,7 @@ ifeq ($(release),1) ################ # release build - fastest run-time, no gdb support ################ + CC_OPTIONS = -s -g -O3 -DNDEBUG CXX_OPTIONS = -s -g -O3 -DNDEBUG LNK_OPTIONS = -pthread -O3 @@ -56,6 +57,7 @@ ifeq ($(profile),1) ################ # profile build - a release build with symbols and profiling engine built in ################ + CC_OPTIONS = -s -g -ggdb -O3 -pg -DNDEBUG CXX_OPTIONS = -s -g -ggdb -O3 -pg -DNDEBUG LNK_OPTIONS = -pthread -ggdb -O3 -pg @@ -66,6 +68,7 @@ ifeq ($(pedantic),1) ################ # pedantic build - basically a debug build with lots of warnings ################ + CC_OPTIONS = -s -g -ggdb -D_DEBUG -Wall -Wextra -pedantic -ansi -Wno-long-long CXX_OPTIONS = -s -g -ggdb -D_DEBUG -Wall -Wextra -pedantic -ansi -Wno-long-long LNK_OPTIONS = -pthread -ggdb @@ -76,6 +79,7 @@ else # debug build - fully traceable by gdb in C++ code, slowest # Since C code is used only for supporting libraries (zlib, lua), it is still O3-optimized ################ + CC_OPTIONS = -s -ggdb -g -D_DEBUG -O3 CXX_OPTIONS = -s -ggdb -g -D_DEBUG LNK_OPTIONS = -pthread -g -ggdb @@ -140,7 +144,6 @@ endif ################################################### # INCLUDE directories for MCServer -# INCLUDE = -I.\ -Isource\ @@ -162,9 +165,6 @@ INCLUDE = -I.\ ################################################### # Build MCServer -# - -# 2012_11_08 _X: Removed: squirrel_3_0_1_stable SOURCES := $(shell find CryptoPP lua-5.1.4 jsoncpp-src-0.5.0 zlib-1.2.7 source tolua++-1.0.93 iniFile expat '(' -name '*.cpp' -o -name '*.c' ')') SOURCES := $(filter-out %minigzip.c %lua.c %tolua.c %toluabind.c %LeakFinder.cpp %StackWalker.cpp %example.c,$(SOURCES)) -- cgit v1.2.3 From cd8894fca680eb315110ad481bf6d54090792a99 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 13 Nov 2013 19:53:39 +0000 Subject: Got rid of warnings caused by the -s option on Clang, and it doesn't seem to do anything anyway. --- GNUmakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index de1da1455..e40748bef 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -47,8 +47,8 @@ ifeq ($(release),1) # release build - fastest run-time, no gdb support ################ -CC_OPTIONS = -s -g -O3 -DNDEBUG -CXX_OPTIONS = -s -g -O3 -DNDEBUG +CC_OPTIONS = -g -O3 -DNDEBUG +CXX_OPTIONS = -g -O3 -DNDEBUG LNK_OPTIONS = -pthread -O3 BUILDDIR = build/release/ -- cgit v1.2.3 From 3ea3da8b3f1800e6d13919f6ee2bd6d088c1906e Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 13 Nov 2013 20:09:24 +0000 Subject: Removed unnecessary format data. --- source/Log.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Log.cpp b/source/Log.cpp index fc19595db..a0de4531b 100644 --- a/source/Log.cpp +++ b/source/Log.cpp @@ -124,7 +124,7 @@ void cLog::Log(const char * a_Format, va_list argList) #endif if (m_File) { - fprintf(m_File, "%s\n", Line.c_str(), m_File); + fprintf(m_File, "%s\n", Line.c_str()); fflush(m_File); } -- cgit v1.2.3 From 56c23305d53e4113cfbd41f39252a19ab67c1f23 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Wed, 13 Nov 2013 20:13:35 +0000 Subject: Added the last bit of the enum, and alpha-sorted the switch. --- source/BlockID.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/source/BlockID.cpp b/source/BlockID.cpp index f8949577e..4467d7e82 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -461,23 +461,26 @@ eDimension StringToDimension(const AString & a_DimensionString) /// Translates damage type constant to a string representation (built-in). AString DamageTypeToString(eDamageType a_DamageType) { + // Make sure to keep this alpha-sorted. switch (a_DamageType) { + case dtAdmin: return "dtAdmin"; case dtAttack: return "dtAttack"; - case dtRangedAttack: return "dtRangedAttack"; - case dtLightning: return "dtLightning"; - case dtFalling: return "dtFalling"; - case dtDrowning: return "dtDrowning"; - case dtSuffocating: return "dtSuffocation"; - case dtStarving: return "dtStarving"; case dtCactusContact: return "dtCactusContact"; - case dtLavaContact: return "dtLavaContact"; - case dtPoisoning: return "dtPoisoning"; - case dtOnFire: return "dtOnFire"; + case dtDrowning: return "dtDrowning"; + case dtEnderPearl: return "dtEnderPearl"; + case dtFalling: return "dtFalling"; case dtFireContact: return "dtFireContact"; case dtInVoid: return "dtInVoid"; + case dtLavaContact: return "dtLavaContact"; + case dtLightning: return "dtLightning"; + case dtOnFire: return "dtOnFire"; + case dtPoisoning: return "dtPoisoning"; case dtPotionOfHarming: return "dtPotionOfHarming"; - case dtAdmin: return "dtAdmin"; + case dtRangedAttack: return "dtRangedAttack"; + case dtStarving: return "dtStarving"; + case dtSuffocating: return "dtSuffocation"; + } // Unknown damage type: -- cgit v1.2.3 From dc94b927534f6216a0ace7690ba250b69c014407 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Thu, 14 Nov 2013 07:38:59 +0000 Subject: Silenced another warning. --- source/Generating/StructGen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/Generating/StructGen.cpp b/source/Generating/StructGen.cpp index 2180261aa..bd8f5d581 100644 --- a/source/Generating/StructGen.cpp +++ b/source/Generating/StructGen.cpp @@ -274,6 +274,7 @@ int cStructGenTrees::GetNumTrees( case biExtremeHillsEdge: Add = 5; break; case biJungle: Add = 120; break; case biJungleHills: Add = 90; break; + default: Add = 0; break; } NumTrees += Add; } -- cgit v1.2.3 From 444e6e4fa74e987880133bb52433b047ff3981b2 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Thu, 14 Nov 2013 07:42:03 +0000 Subject: Silenced yet another not completed enum warning. --- source/Generating/StructGen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/Generating/StructGen.cpp b/source/Generating/StructGen.cpp index bd8f5d581..d9859aab5 100644 --- a/source/Generating/StructGen.cpp +++ b/source/Generating/StructGen.cpp @@ -595,6 +595,7 @@ void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc) } // for y break; } + default: break; } // switch (biome) } // for z, x -- cgit v1.2.3 From 3328c80aec768cf0e64e48eb40e50bf02bfff59c Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Thu, 14 Nov 2013 07:42:54 +0000 Subject: Fixed another one. --- source/Generating/StructGen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/Generating/StructGen.cpp b/source/Generating/StructGen.cpp index d9859aab5..c18783304 100644 --- a/source/Generating/StructGen.cpp +++ b/source/Generating/StructGen.cpp @@ -620,6 +620,7 @@ bool cStructGenDirectOverhangs::HasWantedBiome(cChunkDesc & a_ChunkDesc) const { return true; } + default: break; } } // for i return false; -- cgit v1.2.3 From ea778c70278aa4032565c1c7a450f345a38c1105 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Fri, 15 Nov 2013 01:46:41 +1100 Subject: fixed XpGetPercentage --- VC2013/MCServer.sdf | Bin 61997056 -> 58261504 bytes source/Entities/Player.cpp | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/VC2013/MCServer.sdf b/VC2013/MCServer.sdf index f0501bef6..fabac10ba 100644 Binary files a/VC2013/MCServer.sdf and b/VC2013/MCServer.sdf differ diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 098417dc5..f5c28b326 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -318,8 +318,10 @@ int cPlayer::XpGetLevel() float cPlayer::XpGetPercentage() { int currentLevel = CalcLevelFromXp(m_XpTotal); + int currentLevel_XpBase = XpForLevel(currentLevel); - return (float)m_XpTotal / (float)XpForLevel(1+currentLevel); + return (float)(m_XpTotal - currentLevel_XpBase) / + (float)(XpForLevel(1+currentLevel) - currentLevel_XpBase); } -- cgit v1.2.3 From f6e16ce15082d867ed182690e3a80435cf60dc84 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Fri, 15 Nov 2013 08:35:02 +1100 Subject: cProtocol add SendExperience() and debugging --- MCServer/Plugins/Debuggers/Debuggers.lua | 6 ++++++ source/Protocol/Protocol.h | 3 ++- source/Protocol/Protocol125.cpp | 15 +++++++++++++++ source/Protocol/Protocol125.h | 1 + source/Protocol/Protocol17x.cpp | 12 ++++++++++++ source/Protocol/Protocol17x.h | 1 + source/Protocol/ProtocolRecognizer.cpp | 10 ++++++++++ source/Protocol/ProtocolRecognizer.h | 1 + 8 files changed, 48 insertions(+), 1 deletion(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 04a15a002..119e1525e 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -44,6 +44,7 @@ function Initialize(Plugin) PluginManager:BindCommand("/fs", "debuggers", HandleFoodStatsCmd, "- Turns regular foodstats message on or off"); PluginManager:BindCommand("/arr", "debuggers", HandleArrowCmd, "- Creates an arrow going away from the player"); PluginManager:BindCommand("/fb", "debuggers", HandleFireballCmd, "- Creates a ghast fireball as if shot by the player"); + PluginManager:BindCommand("/xpa", "debuggers", HandleAddExperience, "- Adds 200 experience to the player"); -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); @@ -839,3 +840,8 @@ end +function HandleAddExperience(a_Split, a_Player) + a_Player->AddExperience(200); + + return true; +end \ No newline at end of file diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index 5023ea227..c00c3cad4 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -22,9 +22,9 @@ class cWindow; class cInventory; class cPawn; class cPickup; +class cWorld; class cMonster; class cChunkDataSerializer; -class cWorld; class cFallingBlock; @@ -85,6 +85,7 @@ public: virtual void SendPlayerPosition (void) = 0; virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendRespawn (void) = 0; + virtual void SendSetExperience (void) = 0; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0; diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index 9f2770815..08a2b8656 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -72,6 +72,7 @@ enum PACKET_ENT_STATUS = 0x26, PACKET_ATTACH_ENTITY = 0x27, PACKET_METADATA = 0x28, + PACKET_EXPERIENCE = 0x2b, PACKET_PRE_CHUNK = 0x32, PACKET_MAP_CHUNK = 0x33, PACKET_MULTI_BLOCK = 0x34, @@ -690,6 +691,20 @@ void cProtocol125::SendRespawn(void) +void cProtocol125::SendSetExperience(void) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_EXPERIENCE); + WriteFloat (m_Client->GetPlayer()->XpGetPercentage()); + WriteShort (m_Client->GetPlayer()->XpGetLevel()); + WriteShort (m_Client->GetPlayer()->XpGetTotal()); + Flush(); +} + + + + + void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { // Not needed in this protocol version diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index db913bb57..48309a961 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -62,6 +62,7 @@ public: virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; + virtual void SendSetExperience (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp index 628b8e071..b14c52cba 100644 --- a/source/Protocol/Protocol17x.cpp +++ b/source/Protocol/Protocol17x.cpp @@ -597,6 +597,18 @@ void cProtocol172::SendRespawn(void) +void cProtocol172::SendSetExperience (void) +{ + cPacketizer Pkt(*this, 0x1F); //Experience Packet + Pkt.WriteFloat(m_Client->GetPlayer()->XpGetPercentage()); + Pkt.WriteShort(m_Client->GetPlayer()->XpGetLevel()); + Pkt.WriteShort(m_Client->GetPlayer()->XpGetTotal()); +} + + + + + void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8 { cPacketizer Pkt(*this, 0x29); // Sound Effect packet diff --git a/source/Protocol/Protocol17x.h b/source/Protocol/Protocol17x.h index 844069403..99ae3a087 100644 --- a/source/Protocol/Protocol17x.h +++ b/source/Protocol/Protocol17x.h @@ -72,6 +72,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 + virtual void SendSetExperience (void) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp index 9234785b5..283c20811 100644 --- a/source/Protocol/ProtocolRecognizer.cpp +++ b/source/Protocol/ProtocolRecognizer.cpp @@ -466,6 +466,16 @@ void cProtocolRecognizer::SendRespawn(void) +void cProtocolRecognizer::SendSetExperience(void) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendSetExperience(); +} + + + + + void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { ASSERT(m_Protocol != NULL); diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index c085e2cd8..a32772282 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -97,6 +97,7 @@ public: virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; + virtual void SendSetExperience (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; -- cgit v1.2.3 From 8fa4f38202d20b9f7ebf49943354aa0da1070f87 Mon Sep 17 00:00:00 2001 From: nesco Date: Thu, 14 Nov 2013 23:15:19 +0100 Subject: Update Giant.cpp --- source/Mobs/Giant.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/Mobs/Giant.cpp b/source/Mobs/Giant.cpp index f41977535..c0ad3d0a6 100644 --- a/source/Mobs/Giant.cpp +++ b/source/Mobs/Giant.cpp @@ -1,4 +1,3 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Giant.h" @@ -8,9 +7,10 @@ cGiant::cGiant(void) : - // TODO: The size is only a guesstimate, measure in vanilla and fix the size values here - super("Giant", mtGiant, "mob.zombie.hurt", "mob.zombie.death", 2.0, 13.5) + // 6.0 * (0.6|1.8) + super("Giant", mtGiant, "mob.zombie.hurt", "mob.zombie.death", 3.6, 10.8) { + this->SetMaxHealth(100); } -- cgit v1.2.3 From 15c330664a78a34b5138ec5fc8089b77656e172e Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 14 Nov 2013 22:39:14 +0000 Subject: Fixed arrow bugs * Fixed arrows hitting blocks wrong --- MCServer/Plugins/Core | 2 +- source/Entities/ProjectileEntity.cpp | 65 +++++++++++++++++++++++------------- source/Entities/ProjectileEntity.h | 4 ++- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core index 9ec55bcdc..de53a607f 160000 --- a/MCServer/Plugins/Core +++ b/MCServer/Plugins/Core @@ -1 +1 @@ -Subproject commit 9ec55bcdcaf8b3eea8e98e3e502890295dda14d6 +Subproject commit de53a607f30c583e08c06b6e5eb936cd278ab8cd diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index c63b9523b..279e009cf 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -287,7 +287,11 @@ AString cProjectileEntity::GetMCAClassName(void) const void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); - BroadcastMovementUpdate(); + + if (GetProjectileKind() != pkArrow) // See cArrow::Tick + { + BroadcastMovementUpdate(); + } } @@ -391,7 +395,8 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a m_IsCritical(false), m_Timer(0), m_bIsCollected(false), - m_HitBlockPos(Vector3i(0, 0, 0)) + m_HitBlockPos(Vector3i(0, 0, 0)), + m_HitGroundTimer(0) { SetSpeed(a_Speed); SetMass(0.1); @@ -414,7 +419,8 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : m_IsCritical((a_Force >= 1)), m_Timer(0), m_bIsCollected(false), - m_HitBlockPos(0, 0, 0) + m_HitBlockPos(0, 0, 0), + m_HitGroundTimer(0) { } @@ -440,37 +446,29 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { - if (a_HitFace == BLOCK_FACE_NONE) - { - return; - } - super::OnHitSolidBlock(a_HitPos, a_HitFace); int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; - if (a_HitFace != BLOCK_FACE_YP) + if (a_HitFace != BLOCK_FACE_NONE) { - AddFaceDirection(a_X, a_Y, a_Z, a_HitFace); - } - else if (a_HitFace == BLOCK_FACE_YP) // These conditions because xoft got a little confused on block face directions, so AddFace works with all but YP & YM - { - a_Y--; - } - else - { - a_Y++; + if (a_HitFace != BLOCK_FACE_YP) + { + AddFaceDirection(a_X, a_Y, a_Z, a_HitFace); + } + else if (a_HitFace == BLOCK_FACE_YP) // These conditions because xoft got a little confused on block face directions, so AddFace works with all but YP & YM + { + a_Y--; + } + else + { + a_Y++; + } } m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); // Broadcast arrow hit sound m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - - // Broadcast the position and speed packets before teleporting: - BroadcastMovementUpdate(); - - // Teleport the entity to the exact hit coords: - m_World->BroadcastTeleportEntity(*this); } @@ -542,6 +540,25 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) if (m_IsInGround) { + // When an arrow hits, the client sometimes doesn't think it's in the ground, and therefore it keeps on moving (glitches) + // Temporary fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised + // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync + // BroadcastMovementUpdate seems to be part of its cause, but why? + // TODO: Find cause of arrow syncing issues and fix + + if (m_HitGroundTimer != -1) // Sent a teleport already, don't do again + { + if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case + { + m_World->BroadcastTeleportEntity(*this); + m_HitGroundTimer = -1; + } + else + { + m_HitGroundTimer += a_Dt; + } + } + int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width; int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width; cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 28dd76935..f62b53a42 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -83,7 +83,7 @@ protected: /// True if the projectile has hit the ground and is stuck there bool m_IsInGround; - + // cEntity overrides: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; @@ -159,6 +159,8 @@ protected: /// Timer for pickup collection animation or five minute timeout float m_Timer; + float m_HitGroundTimer; + /// If true, the arrow is in the process of being collected - don't go to anyone else bool m_bIsCollected; -- cgit v1.2.3 From 1b2e6e74736f975386879aa5eb064df5b2f88dac Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Fri, 15 Nov 2013 22:42:09 +1100 Subject: added cProtocol function to pass xp to client --- MCServer/Plugins/Debuggers/Debuggers.lua | 2 +- source/Bindings.cpp | 12 ++++++------ source/Bindings.h | 2 +- source/ClientHandle.cpp | 9 +++++++++ source/ClientHandle.h | 1 + source/Entities/Player.cpp | 32 +++++++++++++++++++------------- source/Entities/Player.h | 14 +++++++------- 7 files changed, 44 insertions(+), 28 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 119e1525e..cd7da359b 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -841,7 +841,7 @@ end function HandleAddExperience(a_Split, a_Player) - a_Player->AddExperience(200); + a_Player:AddExperience(200); return true; end \ No newline at end of file diff --git a/source/Bindings.cpp b/source/Bindings.cpp index c7f6ada19..cc892a70f 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/14/13 17:13:46. +** Generated automatically by tolua++-1.0.92 on 11/15/13 18:43:44. */ #ifndef __cplusplus @@ -7708,7 +7708,7 @@ static int tolua_AllToLua_cPlayer_SetExperience00(lua_State* tolua_S) #endif { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); - int a_XpTotal = ((int) tolua_tonumber(tolua_S,2,0)); + short a_XpTotal = ((short) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetExperience'", NULL); #endif @@ -7742,12 +7742,12 @@ static int tolua_AllToLua_cPlayer_AddExperience00(lua_State* tolua_S) #endif { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); - int a_Xp_delta = ((int) tolua_tonumber(tolua_S,2,0)); + short a_Xp_delta = ((short) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddExperience'", NULL); #endif { - int tolua_ret = (int) self->AddExperience(a_Xp_delta); + short tolua_ret = (short) self->AddExperience(a_Xp_delta); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } @@ -7779,7 +7779,7 @@ static int tolua_AllToLua_cPlayer_XpGetTotal00(lua_State* tolua_S) if (!self) tolua_error(tolua_S,"invalid 'self' in function 'XpGetTotal'", NULL); #endif { - int tolua_ret = (int) self->XpGetTotal(); + short tolua_ret = (short) self->XpGetTotal(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } @@ -7811,7 +7811,7 @@ static int tolua_AllToLua_cPlayer_XpGetLevel00(lua_State* tolua_S) if (!self) tolua_error(tolua_S,"invalid 'self' in function 'XpGetLevel'", NULL); #endif { - int tolua_ret = (int) self->XpGetLevel(); + short tolua_ret = (short) self->XpGetLevel(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } diff --git a/source/Bindings.h b/source/Bindings.h index eb6c566a7..b17fd02ae 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/14/13 17:13:47. +** Generated automatically by tolua++-1.0.92 on 11/15/13 18:43:45. */ /* Exported function */ diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index f8fd4a8b7..73852b886 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -1873,6 +1873,15 @@ void cClientHandle::SendRespawn(void) +void cClientHandle::SendSetExperience(void) +{ + m_Protocol->SendSetExperience(); +} + + + + + void cClientHandle::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch); diff --git a/source/ClientHandle.h b/source/ClientHandle.h index 3844937ad..4b37d39b5 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -120,6 +120,7 @@ public: void SendPlayerPosition (void); void SendPlayerSpawn (const cPlayer & a_Player); void SendRespawn (void); + void SendSetExperience (void); void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch); // a_Src coords are Block * 8 void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data); void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index f5c28b326..00c2ea76c 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -262,7 +262,7 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) -int cPlayer::CalcLevelFromXp(int a_XpTotal) +short cPlayer::CalcLevelFromXp(short a_XpTotal) { //level 0 to 15 if(a_XpTotal <= XP_TO_LEVEL15) @@ -273,18 +273,18 @@ int cPlayer::CalcLevelFromXp(int a_XpTotal) //level 30+ if(a_XpTotal > XP_TO_LEVEL30) { - return (int) (151.5 + sqrt( 22952.25 - (14 * (2220 - a_XpTotal)))) / 7; + return (short) (151.5 + sqrt( 22952.25 - (14 * (2220 - a_XpTotal)))) / 7; } //level 16 to 30 - return (int) ( 29.5 + sqrt( 870.25 - (6 * ( 360 - a_XpTotal )))) / 3; + return (short) ( 29.5 + sqrt( 870.25 - (6 * ( 360 - a_XpTotal )))) / 3; } -int cPlayer::XpForLevel(int a_Level) +short cPlayer::XpForLevel(short a_Level) { //level 0 to 15 if(a_Level <= 15) @@ -295,18 +295,18 @@ int cPlayer::XpForLevel(int a_Level) //level 30+ if(a_Level >= 31) { - return (int) ( (3.5 * a_Level * a_Level) - (151.5 * a_Level) + 2220 ); + return (short) ( (3.5 * a_Level * a_Level) - (151.5 * a_Level) + 2220 ); } //level 16 to 30 - return (int) ( (1.5 * a_Level * a_Level) - (29.5 * a_Level) + 360 ); + return (short) ( (1.5 * a_Level * a_Level) - (29.5 * a_Level) + 360 ); } -int cPlayer::XpGetLevel() +short cPlayer::XpGetLevel() { return CalcLevelFromXp(m_XpTotal); } @@ -317,8 +317,8 @@ int cPlayer::XpGetLevel() float cPlayer::XpGetPercentage() { - int currentLevel = CalcLevelFromXp(m_XpTotal); - int currentLevel_XpBase = XpForLevel(currentLevel); + short int currentLevel = CalcLevelFromXp(m_XpTotal); + short int currentLevel_XpBase = XpForLevel(currentLevel); return (float)(m_XpTotal - currentLevel_XpBase) / (float)(XpForLevel(1+currentLevel) - currentLevel_XpBase); @@ -328,9 +328,9 @@ float cPlayer::XpGetPercentage() -bool cPlayer::SetExperience(int a_XpTotal) +bool cPlayer::SetExperience(short int a_XpTotal) { - if(!(a_XpTotal >= 0) || (a_XpTotal > (INT_MAX - m_XpTotal))) + if(!(a_XpTotal >= 0) || (a_XpTotal > (SHRT_MAX - m_XpTotal))) { LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_XpTotal); return false; //oops, they gave us a dodgey number @@ -338,6 +338,9 @@ bool cPlayer::SetExperience(int a_XpTotal) m_XpTotal = a_XpTotal; + //send details to client + m_ClientHandle->SendSetExperience(); + return true; } @@ -345,7 +348,7 @@ bool cPlayer::SetExperience(int a_XpTotal) -int cPlayer::AddExperience(int a_Xp_delta) +short cPlayer::AddExperience(short a_Xp_delta) { if(a_Xp_delta < 0) { @@ -359,6 +362,9 @@ int cPlayer::AddExperience(int a_Xp_delta) m_XpTotal += a_Xp_delta; + //send details to client + m_ClientHandle->SendSetExperience(); + return m_XpTotal; } @@ -1420,7 +1426,7 @@ bool cPlayer::LoadFromDisk() m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); - SetExperience(root.get("experience", 0).asInt()); + //SetExperience(root.get("experience", 0).asInt()); m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); diff --git a/source/Entities/Player.h b/source/Entities/Player.h index ab2f94d4c..1e43dd954 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -71,18 +71,18 @@ public: Returns true on success "should" really only be called at init or player death, plugins excepted */ - bool SetExperience(int a_XpTotal); + bool SetExperience(short a_XpTotal); /* Adds Xp, "should" not inc more than MAX_EXPERIENCE_ORB_SIZE unless you're a plugin being funny, *cough* cheating Returns the new total experience, -1 on error */ - int AddExperience(int a_Xp_delta); + short AddExperience(short a_Xp_delta); /// Gets the experience total - XpTotal - inline int XpGetTotal(void) { return m_XpTotal; } + inline short XpGetTotal(void) { return m_XpTotal; } /// Gets the current level - XpLevel - int XpGetLevel(void); + short XpGetLevel(void); /// Gets the experience bar percentage - XpP float XpGetPercentage(void); @@ -413,13 +413,13 @@ protected: Int64 m_EatingFinishTick; /// Player Xp level - int m_XpTotal; + short int m_XpTotal; /// Caculates the Xp needed for a given level, ref: http://minecraft.gamepedia.com/XP - static int XpForLevel(int a_Level); + static short XpForLevel(short int a_Level); /// inverse of XpAtLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations - static int CalcLevelFromXp(int a_XpTotal); + static short CalcLevelFromXp(short int a_XpTotal); bool m_IsChargingBow; int m_BowCharge; -- cgit v1.2.3 From c868d31377149ca0e01610deecfb85f56bde0b64 Mon Sep 17 00:00:00 2001 From: nesco Date: Fri, 15 Nov 2013 14:06:58 +0100 Subject: Update Giant.cpp --- source/Mobs/Giant.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Mobs/Giant.cpp b/source/Mobs/Giant.cpp index c0ad3d0a6..44ee58e92 100644 --- a/source/Mobs/Giant.cpp +++ b/source/Mobs/Giant.cpp @@ -10,7 +10,7 @@ cGiant::cGiant(void) : // 6.0 * (0.6|1.8) super("Giant", mtGiant, "mob.zombie.hurt", "mob.zombie.death", 3.6, 10.8) { - this->SetMaxHealth(100); + } -- cgit v1.2.3 From d3269f37fa3e582dc6cd82c296e6997d196ebab8 Mon Sep 17 00:00:00 2001 From: nesco Date: Fri, 15 Nov 2013 14:18:53 +0100 Subject: Update items.ini --- MCServer/items.ini | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/MCServer/items.ini b/MCServer/items.ini index 7eb8f56b4..bc19467a7 100644 --- a/MCServer/items.ini +++ b/MCServer/items.ini @@ -118,7 +118,21 @@ dkgreenwool=35:13 redwool=35:14 blackwool=35:15 dandelion=37 -flower=38 + +; Obsolete, use "dandelion" instead (kept for compatibility, will be removed) +flower=37 + +; Obselete, use a specific flower name instead +rose=38 + +poppy=38 +blueorchid=38:1 +allium=38:2 +redtulip=38:4 +orangetulip=38:5 +whitetulip=38:6 +pinktulip=38:7 +oxeyedaisy=38:8 brownmushroom=39 redmushroom=40 gold=41 -- cgit v1.2.3 From 04dff4882a3d75f3a0d432fb3377cc3f59fdf251 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 02:23:50 +1100 Subject: finished #143 I believe --- MCServer/Plugins/Debuggers/Debuggers.lua | 11 +++++++++++ source/Bindings.cpp | 2 +- source/Bindings.h | 2 +- source/ClientHandle.cpp | 7 +++++-- source/ClientHandle.h | 2 +- source/Entities/Player.cpp | 19 ++++++++++++++++--- source/Entities/Player.h | 2 ++ source/Protocol/Protocol.h | 2 +- source/Protocol/Protocol125.cpp | 2 +- source/Protocol/Protocol125.h | 2 +- source/Protocol/Protocol17x.cpp | 2 +- source/Protocol/Protocol17x.h | 2 +- source/Protocol/ProtocolRecognizer.cpp | 4 ++-- source/Protocol/ProtocolRecognizer.h | 2 +- 14 files changed, 45 insertions(+), 16 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 7b1217b95..badce8508 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -46,6 +46,7 @@ function Initialize(Plugin) PluginManager:BindCommand("/arr", "debuggers", HandleArrowCmd, "- Creates an arrow going away from the player"); PluginManager:BindCommand("/fb", "debuggers", HandleFireballCmd, "- Creates a ghast fireball as if shot by the player"); PluginManager:BindCommand("/xpa", "debuggers", HandleAddExperience, "- Adds 200 experience to the player"); + PluginManager:BindCommand("/xpr", "debuggers", HandleRemoveXp, "- Remove all xp"); -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); @@ -852,3 +853,13 @@ function HandleAddExperience(a_Split, a_Player) return true; end + + + + + +function HandleRemoveXp(a_Split, a_Player) + a_Player:SetExperience(0); + + return true; +end diff --git a/source/Bindings.cpp b/source/Bindings.cpp index a2dcc58c6..be0bbd8af 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/15/13 10:14:19. +** Generated automatically by tolua++-1.0.92 on 11/16/13 02:20:34. */ #ifndef __cplusplus diff --git a/source/Bindings.h b/source/Bindings.h index 13f398a4d..42c158096 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/15/13 10:14:20. +** Generated automatically by tolua++-1.0.92 on 11/16/13 02:20:35. */ /* Exported function */ diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index 73852b886..daf09d4ea 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -260,6 +260,9 @@ void cClientHandle::Authenticate(void) // Send health m_Player->SendHealth(); + + // Send experience + m_Player->SendExperience(); // Send gamemode (1.6.1 movementSpeed): SendGameMode(m_Player->GetGameMode()); @@ -1873,9 +1876,9 @@ void cClientHandle::SendRespawn(void) -void cClientHandle::SendSetExperience(void) +void cClientHandle::SendExperience(void) { - m_Protocol->SendSetExperience(); + m_Protocol->SendExperience(); } diff --git a/source/ClientHandle.h b/source/ClientHandle.h index 4b37d39b5..d3e257aee 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -120,7 +120,7 @@ public: void SendPlayerPosition (void); void SendPlayerSpawn (const cPlayer & a_Player); void SendRespawn (void); - void SendSetExperience (void); + void SendExperience (void); void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch); // a_Src coords are Block * 8 void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data); void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 00c2ea76c..651a0b2a6 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -339,7 +339,7 @@ bool cPlayer::SetExperience(short int a_XpTotal) m_XpTotal = a_XpTotal; //send details to client - m_ClientHandle->SendSetExperience(); + SendExperience(); return true; } @@ -363,7 +363,7 @@ short cPlayer::AddExperience(short a_Xp_delta) m_XpTotal += a_Xp_delta; //send details to client - m_ClientHandle->SendSetExperience(); + SendExperience(); return m_XpTotal; } @@ -615,6 +615,18 @@ void cPlayer::SendHealth(void) +void cPlayer::SendExperience(void) +{ + if (m_ClientHandle != NULL) + { + m_ClientHandle->SendExperience(); + } +} + + + + + void cPlayer::ClearInventoryPaintSlots(void) { // Clear the list of slots that are being inventory-painted. Used by cWindow only @@ -1419,12 +1431,13 @@ bool cPlayer::LoadFromDisk() SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble()); } - m_Health = root.get("health", 0).asInt(); + m_Health = root.get("health", 0).asInt(); m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); + m_XpTotal = root.get("experience", 0).asInt(); //SetExperience(root.get("experience", 0).asInt()); diff --git a/source/Entities/Player.h b/source/Entities/Player.h index 1e43dd954..aeec9f361 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -269,6 +269,8 @@ public: void UseEquippedItem(void); void SendHealth(void); + + void SendExperience(void); // In UI windows, the item that the player is dragging: bool IsDraggingItem(void) const { return !m_DraggingItem.IsEmpty(); } diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index c00c3cad4..98eeec789 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -85,7 +85,7 @@ public: virtual void SendPlayerPosition (void) = 0; virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendRespawn (void) = 0; - virtual void SendSetExperience (void) = 0; + virtual void SendExperience (void) = 0; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0; diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index 08a2b8656..c2dc1c9ce 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -691,7 +691,7 @@ void cProtocol125::SendRespawn(void) -void cProtocol125::SendSetExperience(void) +void cProtocol125::SendExperience(void) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_EXPERIENCE); diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index 48309a961..cd208eaba 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -62,7 +62,7 @@ public: virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; - virtual void SendSetExperience (void) override; + virtual void SendExperience (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp index b14c52cba..7ff2b54b1 100644 --- a/source/Protocol/Protocol17x.cpp +++ b/source/Protocol/Protocol17x.cpp @@ -597,7 +597,7 @@ void cProtocol172::SendRespawn(void) -void cProtocol172::SendSetExperience (void) +void cProtocol172::SendExperience (void) { cPacketizer Pkt(*this, 0x1F); //Experience Packet Pkt.WriteFloat(m_Client->GetPlayer()->XpGetPercentage()); diff --git a/source/Protocol/Protocol17x.h b/source/Protocol/Protocol17x.h index 99ae3a087..6e8574d98 100644 --- a/source/Protocol/Protocol17x.h +++ b/source/Protocol/Protocol17x.h @@ -72,7 +72,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 - virtual void SendSetExperience (void) override; + virtual void SendExperience (void) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp index 283c20811..64bd83075 100644 --- a/source/Protocol/ProtocolRecognizer.cpp +++ b/source/Protocol/ProtocolRecognizer.cpp @@ -466,10 +466,10 @@ void cProtocolRecognizer::SendRespawn(void) -void cProtocolRecognizer::SendSetExperience(void) +void cProtocolRecognizer::SendExperience(void) { ASSERT(m_Protocol != NULL); - m_Protocol->SendSetExperience(); + m_Protocol->SendExperience(); } diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index a32772282..c2beb2014 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -97,7 +97,7 @@ public: virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; - virtual void SendSetExperience (void) override; + virtual void SendExperience (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; -- cgit v1.2.3 From a94a6d48a0d6121c6951f01a81474e718f045430 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 02:32:04 +1100 Subject: alignment fixes :) --- source/ClientHandle.h | 2 +- source/Entities/Player.cpp | 2 +- source/Protocol/Protocol.h | 2 +- source/Protocol/Protocol125.h | 2 +- source/Protocol/Protocol17x.h | 2 +- source/Protocol/ProtocolRecognizer.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/ClientHandle.h b/source/ClientHandle.h index d3e257aee..b887bb11a 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -120,7 +120,7 @@ public: void SendPlayerPosition (void); void SendPlayerSpawn (const cPlayer & a_Player); void SendRespawn (void); - void SendExperience (void); + void SendExperience (void); void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch); // a_Src coords are Block * 8 void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data); void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 651a0b2a6..f25483375 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -1437,7 +1437,7 @@ bool cPlayer::LoadFromDisk() m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); - m_XpTotal = root.get("experience", 0).asInt(); + m_XpTotal = (short) root.get("experience", 0).asInt(); //SetExperience(root.get("experience", 0).asInt()); diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index 98eeec789..542060ece 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -85,7 +85,7 @@ public: virtual void SendPlayerPosition (void) = 0; virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendRespawn (void) = 0; - virtual void SendExperience (void) = 0; + virtual void SendExperience (void) = 0; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0; diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index cd208eaba..c5f44c818 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -62,7 +62,7 @@ public: virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; - virtual void SendExperience (void) override; + virtual void SendExperience (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; diff --git a/source/Protocol/Protocol17x.h b/source/Protocol/Protocol17x.h index 6e8574d98..e3f2ad922 100644 --- a/source/Protocol/Protocol17x.h +++ b/source/Protocol/Protocol17x.h @@ -72,7 +72,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 - virtual void SendExperience (void) override; + virtual void SendExperience (void) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index c2beb2014..03f48fb35 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -97,7 +97,7 @@ public: virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; - virtual void SendExperience (void) override; + virtual void SendExperience (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; -- cgit v1.2.3 From 7a0d2033b6faccaae49883f778b5641689b95238 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 15 Nov 2013 22:47:57 +0000 Subject: Switchified If, ElseIf statement Also updated comments --- source/Entities/ProjectileEntity.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 279e009cf..9d927e39b 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -449,19 +449,25 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) super::OnHitSolidBlock(a_HitPos, a_HitFace); int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; - if (a_HitFace != BLOCK_FACE_NONE) + // Projectiles mistakenly think a face faces the direction a player faces when looking directly at said face + // This therefore breaks YP & YM of AddFaceDirection - see #350 for more details + switch (a_HitFace) { - if (a_HitFace != BLOCK_FACE_YP) - { - AddFaceDirection(a_X, a_Y, a_Z, a_HitFace); - } - else if (a_HitFace == BLOCK_FACE_YP) // These conditions because xoft got a little confused on block face directions, so AddFace works with all but YP & YM + case BLOCK_FACE_NONE: break; // Block tracer sometimes returns this, in this case, the coords will be correct + case BLOCK_FACE_YP: { a_Y--; + break; } - else + case BLOCK_FACE_YM: { a_Y++; + break; + } + default: + { + AddFaceDirection(a_X, a_Y, a_Z, a_HitFace); + break; } } @@ -540,11 +546,10 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) if (m_IsInGround) { - // When an arrow hits, the client sometimes doesn't think it's in the ground, and therefore it keeps on moving (glitches) - // Temporary fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised + // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL + // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing) // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync - // BroadcastMovementUpdate seems to be part of its cause, but why? - // TODO: Find cause of arrow syncing issues and fix + // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position if (m_HitGroundTimer != -1) // Sent a teleport already, don't do again { -- cgit v1.2.3 From c0c8fe1bcd68c35435eafdfd3dbb9793fba970cd Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 20:29:57 +1100 Subject: fix possible threadlock issue, changed function names to be closer to standard --- source/Entities/Player.cpp | 48 +++++++++++++++++++++++++++++----------------- source/Entities/Player.h | 23 ++++++++++++++-------- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index f25483375..891506802 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -67,6 +67,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_IsChargingBow(false) , m_BowCharge(0) , m_XpTotal(0) + , m_IsExperienceDirty(false) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), @@ -222,6 +223,12 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) { m_BowCharge += 1; } + + //handle updating experience + if (m_bDirtyExperience) + { + SendExperience(); + } if (m_bDirtyPosition) { @@ -306,21 +313,21 @@ short cPlayer::XpForLevel(short a_Level) -short cPlayer::XpGetLevel() +short cPlayer::GetXpLevel() { - return CalcLevelFromXp(m_XpTotal); + return CalcLevelFromXp(m_CurrentXp); } -float cPlayer::XpGetPercentage() +float cPlayer::GetXpPercentage() { - short int currentLevel = CalcLevelFromXp(m_XpTotal); + short int currentLevel = CalcLevelFromXp(m_CurrentXp); short int currentLevel_XpBase = XpForLevel(currentLevel); - return (float)(m_XpTotal - currentLevel_XpBase) / + return (float)(m_CurrentXp - currentLevel_XpBase) / (float)(XpForLevel(1+currentLevel) - currentLevel_XpBase); } @@ -328,18 +335,18 @@ float cPlayer::XpGetPercentage() -bool cPlayer::SetExperience(short int a_XpTotal) +bool cPlayer::SetCurrentExperience(short int a_XpTotal) { - if(!(a_XpTotal >= 0) || (a_XpTotal > (SHRT_MAX - m_XpTotal))) + if(!(a_XpTotal >= 0) || (a_XpTotal > (SHRT_MAX - m_CurrentXp))) { LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_XpTotal); return false; //oops, they gave us a dodgey number } - m_XpTotal = a_XpTotal; + m_CurrentXp = a_XpTotal; - //send details to client - SendExperience(); + // Set experience to be updated + m_bDirtyExperience = true; return true; } @@ -352,20 +359,24 @@ short cPlayer::AddExperience(short a_Xp_delta) { if(a_Xp_delta < 0) { - //value was negative, abort and report + // Value was negative, abort and report LOGWARNING("Attempt was made to increment Xp by %d, must be positive", a_Xp_delta); - return -1; //should we instead just return the current Xp? + return -1; // Should we instead just return the current Xp? } - - LOGD("Player \"%s\" earnt %d experience", m_PlayerName.c_str(), a_Xp_delta); - m_XpTotal += a_Xp_delta; + m_CurrentXp += a_Xp_delta; + + // Update total for score calculation + m_LifetimeTotalXp += a_Xp_delta; + + LOGD("Player \"%s\" earnt %d experience, total is now: %d", + m_PlayerName.c_str(), a_Xp_delta, m_XpTotal); - //send details to client - SendExperience(); + // Set experience to be updated + m_bDirtyExperience = true; - return m_XpTotal; + return m_CurrentXp; } @@ -620,6 +631,7 @@ void cPlayer::SendExperience(void) if (m_ClientHandle != NULL) { m_ClientHandle->SendExperience(); + m_bDirtyExperience = false; } } diff --git a/source/Entities/Player.h b/source/Entities/Player.h index aeec9f361..2fc0d5ac9 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -71,21 +71,24 @@ public: Returns true on success "should" really only be called at init or player death, plugins excepted */ - bool SetExperience(short a_XpTotal); + bool SetCurrentExperience(short a_XpTotal); /* Adds Xp, "should" not inc more than MAX_EXPERIENCE_ORB_SIZE unless you're a plugin being funny, *cough* cheating - Returns the new total experience, -1 on error + Returns the new current experience, -1 on error */ short AddExperience(short a_Xp_delta); - /// Gets the experience total - XpTotal - inline short XpGetTotal(void) { return m_XpTotal; } + /// Gets the experience total - XpTotal for score on death + inline short GetXpLifetimeTotal(void) { return m_LifetimeTotalXp; } + + /// Gets the currrent experience + inline short GetCurrentXp(void) { return m_CurrentXp; } /// Gets the current level - XpLevel - short XpGetLevel(void); + short GetXpLevel(void); /// Gets the experience bar percentage - XpP - float XpGetPercentage(void); + float GetXpPercentage(void); // tolua_end @@ -415,13 +418,17 @@ protected: Int64 m_EatingFinishTick; /// Player Xp level - short int m_XpTotal; + short int m_LifetimeTotalXp; + short int m_CurrentXp; + + // flag saying we need to send a xp update to client + bool m_bDirtyExperience; /// Caculates the Xp needed for a given level, ref: http://minecraft.gamepedia.com/XP static short XpForLevel(short int a_Level); /// inverse of XpAtLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations - static short CalcLevelFromXp(short int a_XpTotal); + static short CalcLevelFromXp(short int a_XpCurrent); bool m_IsChargingBow; int m_BowCharge; -- cgit v1.2.3 From 359539293782713d47e51775b65ee91fc89994e4 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 21:38:57 +1100 Subject: fixed bug and added SpendExperience() --- source/Bindings.cpp | 127 +++++++++++++++++++++++++++++++--------- source/Bindings.h | 2 +- source/Entities/Player.cpp | 41 +++++++++++-- source/Entities/Player.h | 4 ++ source/Protocol/Protocol125.cpp | 6 +- source/Protocol/Protocol17x.cpp | 6 +- 6 files changed, 146 insertions(+), 40 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index be0bbd8af..a03ee37e0 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/16/13 02:20:34. +** Generated automatically by tolua++-1.0.92 on 11/16/13 21:19:32. */ #ifndef __cplusplus @@ -7650,9 +7650,9 @@ static int tolua_AllToLua_cEntity_IsInvisible00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: SetExperience of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_SetExperience00 -static int tolua_AllToLua_cPlayer_SetExperience00(lua_State* tolua_S) +/* method: SetCurrentExperience of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_SetCurrentExperience00 +static int tolua_AllToLua_cPlayer_SetCurrentExperience00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7668,17 +7668,17 @@ static int tolua_AllToLua_cPlayer_SetExperience00(lua_State* tolua_S) cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); short a_XpTotal = ((short) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetExperience'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetCurrentExperience'", NULL); #endif { - bool tolua_ret = (bool) self->SetExperience(a_XpTotal); + bool tolua_ret = (bool) self->SetCurrentExperience(a_XpTotal); tolua_pushboolean(tolua_S,(bool)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'SetExperience'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'SetCurrentExperience'.",&tolua_err); return 0; #endif } @@ -7718,9 +7718,75 @@ static int tolua_AllToLua_cPlayer_AddExperience00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: XpGetTotal of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_XpGetTotal00 -static int tolua_AllToLua_cPlayer_XpGetTotal00(lua_State* tolua_S) +/* method: SpendExperience of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_SpendExperience00 +static int tolua_AllToLua_cPlayer_SpendExperience00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cPlayer",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); + short a_Xp_delta = ((short) tolua_tonumber(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SpendExperience'", NULL); +#endif + { + short tolua_ret = (short) self->SpendExperience(a_Xp_delta); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SpendExperience'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetXpLifetimeTotal of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetXpLifetimeTotal00 +static int tolua_AllToLua_cPlayer_GetXpLifetimeTotal00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cPlayer",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetXpLifetimeTotal'", NULL); +#endif + { + short tolua_ret = (short) self->GetXpLifetimeTotal(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetXpLifetimeTotal'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetCurrentXp of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetCurrentXp00 +static int tolua_AllToLua_cPlayer_GetCurrentXp00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7734,25 +7800,25 @@ static int tolua_AllToLua_cPlayer_XpGetTotal00(lua_State* tolua_S) { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'XpGetTotal'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetCurrentXp'", NULL); #endif { - short tolua_ret = (short) self->XpGetTotal(); + short tolua_ret = (short) self->GetCurrentXp(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'XpGetTotal'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetCurrentXp'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: XpGetLevel of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_XpGetLevel00 -static int tolua_AllToLua_cPlayer_XpGetLevel00(lua_State* tolua_S) +/* method: GetXpLevel of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetXpLevel00 +static int tolua_AllToLua_cPlayer_GetXpLevel00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7766,25 +7832,25 @@ static int tolua_AllToLua_cPlayer_XpGetLevel00(lua_State* tolua_S) { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'XpGetLevel'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetXpLevel'", NULL); #endif { - short tolua_ret = (short) self->XpGetLevel(); + short tolua_ret = (short) self->GetXpLevel(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'XpGetLevel'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetXpLevel'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: XpGetPercentage of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_XpGetPercentage00 -static int tolua_AllToLua_cPlayer_XpGetPercentage00(lua_State* tolua_S) +/* method: GetXpPercentage of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetXpPercentage00 +static int tolua_AllToLua_cPlayer_GetXpPercentage00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7798,17 +7864,17 @@ static int tolua_AllToLua_cPlayer_XpGetPercentage00(lua_State* tolua_S) { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'XpGetPercentage'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetXpPercentage'", NULL); #endif { - float tolua_ret = (float) self->XpGetPercentage(); + float tolua_ret = (float) self->GetXpPercentage(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'XpGetPercentage'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetXpPercentage'.",&tolua_err); return 0; #endif } @@ -30417,11 +30483,14 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"EATING_TICKS",cPlayer::EATING_TICKS); tolua_constant(tolua_S,"MAX_AIR_LEVEL",cPlayer::MAX_AIR_LEVEL); tolua_constant(tolua_S,"DROWNING_TICKS",cPlayer::DROWNING_TICKS); - tolua_function(tolua_S,"SetExperience",tolua_AllToLua_cPlayer_SetExperience00); + tolua_constant(tolua_S,"MIN_EXPERIENCE",cPlayer::MIN_EXPERIENCE); + tolua_function(tolua_S,"SetCurrentExperience",tolua_AllToLua_cPlayer_SetCurrentExperience00); tolua_function(tolua_S,"AddExperience",tolua_AllToLua_cPlayer_AddExperience00); - tolua_function(tolua_S,"XpGetTotal",tolua_AllToLua_cPlayer_XpGetTotal00); - tolua_function(tolua_S,"XpGetLevel",tolua_AllToLua_cPlayer_XpGetLevel00); - tolua_function(tolua_S,"XpGetPercentage",tolua_AllToLua_cPlayer_XpGetPercentage00); + tolua_function(tolua_S,"SpendExperience",tolua_AllToLua_cPlayer_SpendExperience00); + tolua_function(tolua_S,"GetXpLifetimeTotal",tolua_AllToLua_cPlayer_GetXpLifetimeTotal00); + tolua_function(tolua_S,"GetCurrentXp",tolua_AllToLua_cPlayer_GetCurrentXp00); + tolua_function(tolua_S,"GetXpLevel",tolua_AllToLua_cPlayer_GetXpLevel00); + tolua_function(tolua_S,"GetXpPercentage",tolua_AllToLua_cPlayer_GetXpPercentage00); tolua_function(tolua_S,"GetEyeHeight",tolua_AllToLua_cPlayer_GetEyeHeight00); tolua_function(tolua_S,"GetEyePosition",tolua_AllToLua_cPlayer_GetEyePosition00); tolua_function(tolua_S,"IsOnGround",tolua_AllToLua_cPlayer_IsOnGround00); diff --git a/source/Bindings.h b/source/Bindings.h index 42c158096..fd1ac3242 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/16/13 02:20:35. +** Generated automatically by tolua++-1.0.92 on 11/16/13 21:19:33. */ /* Exported function */ diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 891506802..e8fc795d7 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -66,8 +66,9 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_EatingFinishTick(-1) , m_IsChargingBow(false) , m_BowCharge(0) - , m_XpTotal(0) - , m_IsExperienceDirty(false) + , m_CurrentXp(0) + , m_LifetimeTotalXp(0) + , m_bDirtyExperience(false) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), @@ -383,6 +384,31 @@ short cPlayer::AddExperience(short a_Xp_delta) +short cPlayer::SpendExperience(short a_Xp_delta) +{ + if(a_Xp_delta < 0) + { + // Value was negative, abort and report + LOGWARNING("Attempt was made to decrement Xp by %d, must be positive", + a_Xp_delta); + return -1; // Should we instead just return the current Xp? + } + + m_CurrentXp -= a_Xp_delta; + + LOGD("Player \"%s\" spent %d experience, total is now: %d", + m_PlayerName.c_str(), a_Xp_delta, m_XpTotal); + + // Set experience to be updated + m_bDirtyExperience = true; + + return m_CurrentXp; +} + + + + + void cPlayer::StartChargingBow(void) { LOGD("Player \"%s\" started charging their bow", m_PlayerName.c_str()); @@ -791,6 +817,11 @@ void cPlayer::Respawn(void) m_FoodLevel = MAX_FOOD_LEVEL; m_FoodSaturationLevel = 5; + // Reset Experience + m_CurrentXp = MIN_EXPERIENCE; + m_LifetimeTotalXp = MIN_EXPERIENCE; + // ToDo: send score to client? How? + m_ClientHandle->SendRespawn(); // Extinguish the fire: @@ -1449,7 +1480,8 @@ bool cPlayer::LoadFromDisk() m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); - m_XpTotal = (short) root.get("experience", 0).asInt(); + m_LifetimeTotalXp = (short) root.get("xpTotal", 0).asInt(); + m_CurrentXp = (short) root.get("xpCurrent", 0).asInt(); //SetExperience(root.get("experience", 0).asInt()); @@ -1493,7 +1525,8 @@ bool cPlayer::SaveToDisk() root["rotation"] = JSON_PlayerRotation; root["inventory"] = JSON_Inventory; root["health"] = m_Health; - root["experience"] = m_XpTotal; + root["xpTotal"] = m_LifetimeTotalXp; + root["xpCurrent"] = m_CurrentXp; root["air"] = m_AirLevel; root["food"] = m_FoodLevel; root["foodSaturation"] = m_FoodSaturationLevel; diff --git a/source/Entities/Player.h b/source/Entities/Player.h index 2fc0d5ac9..01a864149 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -32,6 +32,7 @@ public: EATING_TICKS = 30, ///< Number of ticks it takes to eat an item MAX_AIR_LEVEL = 300, DROWNING_TICKS = 10, //number of ticks per heart of damage + MIN_EXPERIENCE = 0, } ; // tolua_end @@ -78,6 +79,9 @@ public: */ short AddExperience(short a_Xp_delta); + /// "Spend" some experience - ie on enchanting, returns new currentXp + short SpendExperience(short a_Xp_delta); + /// Gets the experience total - XpTotal for score on death inline short GetXpLifetimeTotal(void) { return m_LifetimeTotalXp; } diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index c2dc1c9ce..54be65b12 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -695,9 +695,9 @@ void cProtocol125::SendExperience(void) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_EXPERIENCE); - WriteFloat (m_Client->GetPlayer()->XpGetPercentage()); - WriteShort (m_Client->GetPlayer()->XpGetLevel()); - WriteShort (m_Client->GetPlayer()->XpGetTotal()); + WriteFloat (m_Client->GetPlayer()->GetXpPercentage()); + WriteShort (m_Client->GetPlayer()->GetXpLevel()); + WriteShort (m_Client->GetPlayer()->GetCurrentXp()); Flush(); } diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp index 7ff2b54b1..ae1df7395 100644 --- a/source/Protocol/Protocol17x.cpp +++ b/source/Protocol/Protocol17x.cpp @@ -600,9 +600,9 @@ void cProtocol172::SendRespawn(void) void cProtocol172::SendExperience (void) { cPacketizer Pkt(*this, 0x1F); //Experience Packet - Pkt.WriteFloat(m_Client->GetPlayer()->XpGetPercentage()); - Pkt.WriteShort(m_Client->GetPlayer()->XpGetLevel()); - Pkt.WriteShort(m_Client->GetPlayer()->XpGetTotal()); + Pkt.WriteFloat(m_Client->GetPlayer()->GetXpPercentage()); + Pkt.WriteShort(m_Client->GetPlayer()->GetXpLevel()); + Pkt.WriteShort(m_Client->GetPlayer()->GetCurrentXp()); } -- cgit v1.2.3 From b72ced31649f8a851ffe60778e8a603bda941dc9 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 22:00:45 +1100 Subject: removed SpendExperience and changed AddExperience to handle removing Xp --- MCServer/Plugins/Debuggers/Debuggers.lua | 2 +- source/Bindings.cpp | 51 +++++--------------------------- source/Bindings.h | 2 +- source/Entities/Player.cpp | 37 +++++------------------ source/Entities/Player.h | 7 ++--- 5 files changed, 20 insertions(+), 79 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index badce8508..69e724b30 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -849,7 +849,7 @@ end function HandleAddExperience(a_Split, a_Player) - a_Player:AddExperience(200); + a_Player:DelatExperience(200); return true; end diff --git a/source/Bindings.cpp b/source/Bindings.cpp index a03ee37e0..9fdd28383 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/16/13 21:19:32. +** Generated automatically by tolua++-1.0.92 on 11/16/13 21:58:48. */ #ifndef __cplusplus @@ -7684,9 +7684,9 @@ static int tolua_AllToLua_cPlayer_SetCurrentExperience00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: AddExperience of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_AddExperience00 -static int tolua_AllToLua_cPlayer_AddExperience00(lua_State* tolua_S) +/* method: DeltaExperience of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_DeltaExperience00 +static int tolua_AllToLua_cPlayer_DeltaExperience00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7702,51 +7702,17 @@ static int tolua_AllToLua_cPlayer_AddExperience00(lua_State* tolua_S) cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); short a_Xp_delta = ((short) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddExperience'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeltaExperience'", NULL); #endif { - short tolua_ret = (short) self->AddExperience(a_Xp_delta); + short tolua_ret = (short) self->DeltaExperience(a_Xp_delta); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'AddExperience'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: SpendExperience of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_SpendExperience00 -static int tolua_AllToLua_cPlayer_SpendExperience00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cPlayer",0,&tolua_err) || - !tolua_isnumber(tolua_S,2,0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); - short a_Xp_delta = ((short) tolua_tonumber(tolua_S,2,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SpendExperience'", NULL); -#endif - { - short tolua_ret = (short) self->SpendExperience(a_Xp_delta); - tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'SpendExperience'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'DeltaExperience'.",&tolua_err); return 0; #endif } @@ -30485,8 +30451,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"DROWNING_TICKS",cPlayer::DROWNING_TICKS); tolua_constant(tolua_S,"MIN_EXPERIENCE",cPlayer::MIN_EXPERIENCE); tolua_function(tolua_S,"SetCurrentExperience",tolua_AllToLua_cPlayer_SetCurrentExperience00); - tolua_function(tolua_S,"AddExperience",tolua_AllToLua_cPlayer_AddExperience00); - tolua_function(tolua_S,"SpendExperience",tolua_AllToLua_cPlayer_SpendExperience00); + tolua_function(tolua_S,"DeltaExperience",tolua_AllToLua_cPlayer_DeltaExperience00); tolua_function(tolua_S,"GetXpLifetimeTotal",tolua_AllToLua_cPlayer_GetXpLifetimeTotal00); tolua_function(tolua_S,"GetCurrentXp",tolua_AllToLua_cPlayer_GetCurrentXp00); tolua_function(tolua_S,"GetXpLevel",tolua_AllToLua_cPlayer_GetXpLevel00); diff --git a/source/Bindings.h b/source/Bindings.h index fd1ac3242..996207055 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/16/13 21:19:33. +** Generated automatically by tolua++-1.0.92 on 11/16/13 21:58:48. */ /* Exported function */ diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index e8fc795d7..bdcf0aae9 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -338,7 +338,7 @@ float cPlayer::GetXpPercentage() bool cPlayer::SetCurrentExperience(short int a_XpTotal) { - if(!(a_XpTotal >= 0) || (a_XpTotal > (SHRT_MAX - m_CurrentXp))) + if(!(a_XpTotal >= 0) || (a_XpTotal > (SHRT_MAX - m_LifetimeTotalXp))) { LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_XpTotal); return false; //oops, they gave us a dodgey number @@ -356,12 +356,13 @@ bool cPlayer::SetCurrentExperience(short int a_XpTotal) -short cPlayer::AddExperience(short a_Xp_delta) +short cPlayer::DeltaExperience(short a_Xp_delta) { - if(a_Xp_delta < 0) + //ToDo: figure out a better name?... + if(a_Xp_delta > (SHRT_MAX - m_LifetimeTotalXp) || (m_CurrentXp + a_Xp_delta) < MIN_EXPERIENCE) { // Value was negative, abort and report - LOGWARNING("Attempt was made to increment Xp by %d, must be positive", + LOGWARNING("Attempt was made to increment Xp by %d, which was invalid", a_Xp_delta); return -1; // Should we instead just return the current Xp? } @@ -369,34 +370,12 @@ short cPlayer::AddExperience(short a_Xp_delta) m_CurrentXp += a_Xp_delta; // Update total for score calculation - m_LifetimeTotalXp += a_Xp_delta; - - LOGD("Player \"%s\" earnt %d experience, total is now: %d", - m_PlayerName.c_str(), a_Xp_delta, m_XpTotal); - - // Set experience to be updated - m_bDirtyExperience = true; - - return m_CurrentXp; -} - - - - - -short cPlayer::SpendExperience(short a_Xp_delta) -{ - if(a_Xp_delta < 0) + if(a_Xp_delta > 0) { - // Value was negative, abort and report - LOGWARNING("Attempt was made to decrement Xp by %d, must be positive", - a_Xp_delta); - return -1; // Should we instead just return the current Xp? + m_LifetimeTotalXp += a_Xp_delta; } - m_CurrentXp -= a_Xp_delta; - - LOGD("Player \"%s\" spent %d experience, total is now: %d", + LOGD("Player \"%s\" earnt %d experience, total is now: %d", m_PlayerName.c_str(), a_Xp_delta, m_XpTotal); // Set experience to be updated diff --git a/source/Entities/Player.h b/source/Entities/Player.h index 01a864149..463a6d8dc 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -74,13 +74,10 @@ public: */ bool SetCurrentExperience(short a_XpTotal); - /* Adds Xp, "should" not inc more than MAX_EXPERIENCE_ORB_SIZE unless you're a plugin being funny, *cough* cheating + /* changes Xp by Xp_delta, you "shouldn't" not inc more than MAX_EXPERIENCE_ORB_SIZE Returns the new current experience, -1 on error */ - short AddExperience(short a_Xp_delta); - - /// "Spend" some experience - ie on enchanting, returns new currentXp - short SpendExperience(short a_Xp_delta); + short DeltaExperience(short a_Xp_delta); /// Gets the experience total - XpTotal for score on death inline short GetXpLifetimeTotal(void) { return m_LifetimeTotalXp; } -- cgit v1.2.3 From 25ccc33252b1c105c6c13ae23200b5aa49b7ed39 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 22:05:34 +1100 Subject: updated plugin --- MCServer/Plugins/Debuggers/Debuggers.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 69e724b30..491d294e2 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -849,7 +849,7 @@ end function HandleAddExperience(a_Split, a_Player) - a_Player:DelatExperience(200); + a_Player:DeltaExperience(200); return true; end -- cgit v1.2.3 From b3bb34974fddfae6cea9ca59d71f95e32621793d Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 22:17:46 +1100 Subject: updated plugin again... --- MCServer/Plugins/Debuggers/Debuggers.lua | 2 +- source/Entities/Player.cpp | 8 ++++---- source/Entities/Player.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 491d294e2..9350606cc 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -859,7 +859,7 @@ end function HandleRemoveXp(a_Split, a_Player) - a_Player:SetExperience(0); + a_Player:SetCurrentExperience(0); return true; end diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index bdcf0aae9..38b41fb19 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -336,15 +336,15 @@ float cPlayer::GetXpPercentage() -bool cPlayer::SetCurrentExperience(short int a_XpTotal) +bool cPlayer::SetCurrentExperience(short int a_CurrentXp) { - if(!(a_XpTotal >= 0) || (a_XpTotal > (SHRT_MAX - m_LifetimeTotalXp))) + if(!(a_CurrentXp >= 0) || (a_CurrentXp > (SHRT_MAX - m_LifetimeTotalXp))) { - LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_XpTotal); + LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_CurrentXp); return false; //oops, they gave us a dodgey number } - m_CurrentXp = a_XpTotal; + m_CurrentXp = a_CurrentXp; // Set experience to be updated m_bDirtyExperience = true; diff --git a/source/Entities/Player.h b/source/Entities/Player.h index 463a6d8dc..5abca9899 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -429,7 +429,7 @@ protected: static short XpForLevel(short int a_Level); /// inverse of XpAtLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations - static short CalcLevelFromXp(short int a_XpCurrent); + static short CalcLevelFromXp(short int a_CurrentXp); bool m_IsChargingBow; int m_BowCharge; -- cgit v1.2.3 From d2d8b1d0736c2af002dc3b91f5281fa4d866470f Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 22:43:42 +1100 Subject: edited comment and changed error behavior of DeltaXp --- source/Entities/Player.cpp | 12 +++++++++--- source/Entities/Player.h | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 38b41fb19..129d7df56 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -359,16 +359,22 @@ bool cPlayer::SetCurrentExperience(short int a_CurrentXp) short cPlayer::DeltaExperience(short a_Xp_delta) { //ToDo: figure out a better name?... - if(a_Xp_delta > (SHRT_MAX - m_LifetimeTotalXp) || (m_CurrentXp + a_Xp_delta) < MIN_EXPERIENCE) + if(a_Xp_delta > (SHRT_MAX - m_LifetimeTotalXp)) { - // Value was negative, abort and report - LOGWARNING("Attempt was made to increment Xp by %d, which was invalid", + // Value was bad, abort and report + LOGWARNING("Attempt was made to increment Xp by %d, which was bad", a_Xp_delta); return -1; // Should we instead just return the current Xp? } m_CurrentXp += a_Xp_delta; + // Make sure they didn't subtract too much + if(m_CurrentXp < 0) + { + m_CurrentXp = 0; + } + // Update total for score calculation if(a_Xp_delta > 0) { diff --git a/source/Entities/Player.h b/source/Entities/Player.h index 5abca9899..bda25715d 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -74,7 +74,8 @@ public: */ bool SetCurrentExperience(short a_XpTotal); - /* changes Xp by Xp_delta, you "shouldn't" not inc more than MAX_EXPERIENCE_ORB_SIZE + /* changes Xp by Xp_delta, you "shouldn't" inc more than MAX_EXPERIENCE_ORB_SIZE + Wont't allow xp to go negative Returns the new current experience, -1 on error */ short DeltaExperience(short a_Xp_delta); -- cgit v1.2.3 From c7f38761ed1cc524e98db754cadb2c6af1578b88 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sat, 16 Nov 2013 22:46:27 +1100 Subject: removed magic number --- source/Entities/Player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 129d7df56..ccc7b89f1 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -370,9 +370,9 @@ short cPlayer::DeltaExperience(short a_Xp_delta) m_CurrentXp += a_Xp_delta; // Make sure they didn't subtract too much - if(m_CurrentXp < 0) + if(m_CurrentXp < MIN_EXPERIENCE) { - m_CurrentXp = 0; + m_CurrentXp = MIN_EXPERIENCE; } // Update total for score calculation -- cgit v1.2.3 From cd1c4058940c12a88419c1d417ff2534050a0565 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sun, 17 Nov 2013 00:13:53 +1100 Subject: minor change in LOGD call --- source/Entities/Player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index ccc7b89f1..436ae0cfc 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -381,8 +381,8 @@ short cPlayer::DeltaExperience(short a_Xp_delta) m_LifetimeTotalXp += a_Xp_delta; } - LOGD("Player \"%s\" earnt %d experience, total is now: %d", - m_PlayerName.c_str(), a_Xp_delta, m_XpTotal); + LOGD("Player \"%s\" gained/lost %d experience, total is now: %d", + m_PlayerName.c_str(), a_Xp_delta, m_CurrentXp); // Set experience to be updated m_bDirtyExperience = true; -- cgit v1.2.3 From 07b7a419fe6c52bca4e5e54d1144a84e2df06403 Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sun, 17 Nov 2013 01:06:54 +1100 Subject: removed *.sdf file --- VC2013/MCServer.sdf | Bin 58261504 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 VC2013/MCServer.sdf diff --git a/VC2013/MCServer.sdf b/VC2013/MCServer.sdf deleted file mode 100644 index fabac10ba..000000000 Binary files a/VC2013/MCServer.sdf and /dev/null differ -- cgit v1.2.3 From eca23ed0b3558d5c6bca960a599924b888fd2468 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 17:49:14 +0000 Subject: Always warn about everything! This should help me in my efforts. --- GNUmakefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GNUmakefile b/GNUmakefile index e40748bef..d8afc0525 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -88,6 +88,10 @@ endif endif endif +################################################## +# Always be warning. + +CXX_OPTIONS += -Wall ################################################### # Fix Crypto++ warnings in clang -- cgit v1.2.3 From 2f2fe8ab0c73bdc1e5b10cf815595757328b61d2 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 17:53:27 +0000 Subject: Revert "Fixed another one." This reverts commit 3328c80aec768cf0e64e48eb40e50bf02bfff59c. --- source/Generating/StructGen.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/Generating/StructGen.cpp b/source/Generating/StructGen.cpp index c18783304..d9859aab5 100644 --- a/source/Generating/StructGen.cpp +++ b/source/Generating/StructGen.cpp @@ -620,7 +620,6 @@ bool cStructGenDirectOverhangs::HasWantedBiome(cChunkDesc & a_ChunkDesc) const { return true; } - default: break; } } // for i return false; -- cgit v1.2.3 From 33e1439c809b8791e14e7946ab77cb3d6f9a3093 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 17:53:55 +0000 Subject: Revert "Silenced yet another not completed enum warning." This reverts commit 444e6e4fa74e987880133bb52433b047ff3981b2. --- source/Generating/StructGen.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/Generating/StructGen.cpp b/source/Generating/StructGen.cpp index d9859aab5..bd8f5d581 100644 --- a/source/Generating/StructGen.cpp +++ b/source/Generating/StructGen.cpp @@ -595,7 +595,6 @@ void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc) } // for y break; } - default: break; } // switch (biome) } // for z, x -- cgit v1.2.3 From ab676060fa72e82773db4f0fbe53012483518f16 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 17:54:18 +0000 Subject: Revert "Silenced another warning." This reverts commit dc94b927534f6216a0ace7690ba250b69c014407. --- source/Generating/StructGen.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/Generating/StructGen.cpp b/source/Generating/StructGen.cpp index bd8f5d581..2180261aa 100644 --- a/source/Generating/StructGen.cpp +++ b/source/Generating/StructGen.cpp @@ -274,7 +274,6 @@ int cStructGenTrees::GetNumTrees( case biExtremeHillsEdge: Add = 5; break; case biJungle: Add = 120; break; case biJungleHills: Add = 90; break; - default: Add = 0; break; } NumTrees += Add; } -- cgit v1.2.3 From 9060fbf4b59c5e44de463b391eb6e5d1532ca9ef Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:15:12 +0000 Subject: Fixed a warning about unsigned int comparison - probably was a real issue. --- source/PluginManager.cpp | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp index 3ac2366ca..b384383e5 100644 --- a/source/PluginManager.cpp +++ b/source/PluginManager.cpp @@ -113,9 +113,13 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) FindPlugins(); cServer::BindBuiltInConsoleCommands(); - - unsigned int KeyNum = a_SettingsIni.FindKey("Plugins"); + + // Check if the Plugins section exists. + int KeyNum = a_SettingsIni.FindKey("Plugins"); + + // If it does, how many plugins are there? unsigned int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); + if (KeyNum == -1) { InsertDefaultPlugins(a_SettingsIni); @@ -202,7 +206,7 @@ void cPluginManager::Tick(float a_Dt) bool cPluginManager::CallHookBlockToPickups( cWorld * a_World, cEntity * a_Digger, - int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, + int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups ) { @@ -247,7 +251,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) { return false; } - + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnChat(a_Player, a_Message)) @@ -255,7 +259,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) return true; } } - + return false; } @@ -1230,27 +1234,27 @@ bool cPluginManager::CallHookWorldTick(cWorld & a_World, float a_Dt) bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions) { ASSERT(a_Player != NULL); - + AStringVector Split(StringSplit(a_Command, " ")); if (Split.empty()) { return false; } - + CommandMap::iterator cmd = m_Commands.find(Split[0]); if (cmd == m_Commands.end()) { // Command not found return false; } - + // Ask plugins first if a command is okay to execute the command: if (CallHookExecuteCommand(a_Player, Split)) { LOGINFO("Player \"%s\" tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player->GetName().c_str(), Split[0].c_str()); return false; } - + if ( a_ShouldCheckPermissions && !cmd->second.m_Permission.empty() && @@ -1262,8 +1266,8 @@ bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command } ASSERT(cmd->second.m_Plugin != NULL); - - return cmd->second.m_Plugin->HandleCommand(Split, a_Player); + + return cmd->second.m_Plugin->HandleCommand(Split, a_Player); } @@ -1320,7 +1324,7 @@ bool cPluginManager::DisablePlugin(const AString & a_PluginName) { return false; } - + if (itr->first.compare(a_PluginName) == 0) // _X 2013_02_01: wtf? Isn't this supposed to be what find() does? { m_DisablePluginList.push_back(itr->second); @@ -1365,7 +1369,7 @@ void cPluginManager::RemovePlugin(cPlugin * a_Plugin) break; } } - + RemovePluginCommands(a_Plugin); RemovePluginConsoleCommands(a_Plugin); RemoveHooks(a_Plugin); @@ -1386,7 +1390,7 @@ void cPluginManager::RemovePluginCommands(cPlugin * a_Plugin) { a_Plugin->ClearCommands(); } - + for (CommandMap::iterator itr = m_Commands.begin(); itr != m_Commands.end();) { if (itr->second.m_Plugin == a_Plugin) @@ -1414,7 +1418,7 @@ bool cPluginManager::BindCommand(const AString & a_Command, cPlugin * a_Plugin, LOGWARNING("Command \"%s\" is already bound to plugin \"%s\".", a_Command.c_str(), cmd->second.m_Plugin->GetName().c_str()); return false; } - + m_Commands[a_Command].m_Plugin = a_Plugin; m_Commands[a_Command].m_Permission = a_Permission; m_Commands[a_Command].m_HelpString = a_HelpString; @@ -1484,7 +1488,7 @@ void cPluginManager::RemovePluginConsoleCommands(cPlugin * a_Plugin) { a_Plugin->ClearConsoleCommands(); } - + for (CommandMap::iterator itr = m_ConsoleCommands.begin(); itr != m_ConsoleCommands.end();) { if (itr->second.m_Plugin == a_Plugin) @@ -1519,7 +1523,7 @@ bool cPluginManager::BindConsoleCommand(const AString & a_Command, cPlugin * a_P } return false; } - + m_ConsoleCommands[a_Command].m_Plugin = a_Plugin; m_ConsoleCommands[a_Command].m_Permission = ""; m_ConsoleCommands[a_Command].m_HelpString = a_HelpString; @@ -1561,20 +1565,20 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma { return false; } - + CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]); if (cmd == m_ConsoleCommands.end()) { // Command not found return false; } - + if (cmd->second.m_Plugin == NULL) { // This is a built-in command return false; } - + // Ask plugins first if a command is okay to execute the console command: if (CallHookExecuteCommand(NULL, a_Split)) { @@ -1582,7 +1586,7 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma return false; } - return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output); + return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output); } @@ -1656,7 +1660,7 @@ void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook) unsigned int cPluginManager::GetNumPlugins() const { - return m_Plugins.size(); + return m_Plugins.size(); } -- cgit v1.2.3 From 5337fee8e084e787151b2c460d0130cffcdbccfa Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:26:46 +0000 Subject: Fixed a warning about brackets. Is this the right way round? This is how C++ interprets it, so it should be changed if this is the wrong way round. --- source/Generating/MineShafts.cpp | 116 +++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/source/Generating/MineShafts.cpp b/source/Generating/MineShafts.cpp index 3131b5429..e7884f243 100644 --- a/source/Generating/MineShafts.cpp +++ b/source/Generating/MineShafts.cpp @@ -41,8 +41,8 @@ public: mskCrossing, mskStaircase, } ; - - + + enum eDirection { dirXP, @@ -50,8 +50,8 @@ public: dirXM, dirZM, } ; - - + + cStructGenMineShafts::cMineShaftSystem & m_ParentSystem; eKind m_Kind; cCuboid m_BoundingBox; @@ -62,25 +62,25 @@ public: m_Kind(a_Kind) { } - + cMineShaft(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, eKind a_Kind, const cCuboid & a_BoundingBox) : m_ParentSystem(a_ParentSystem), m_Kind(a_Kind), m_BoundingBox(a_BoundingBox) { } - + /// Returns true if this mineshaft intersects the specified cuboid bool DoesIntersect(const cCuboid & a_Other) { return m_BoundingBox.DoesIntersect(a_Other); } - + /** If recursion level is not too large, appends more branches to the parent system, using exit points specific to this class. */ virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) = 0; - + /// Imprints this shape into the specified chunk's data virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) = 0; } ; @@ -95,10 +95,10 @@ class cMineShaftDirtRoom : public cMineShaft { typedef cMineShaft super; - + public: cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem & a_Parent, cNoise & a_Noise); - + // cMineShaft overrides: virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override; virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override; @@ -112,7 +112,7 @@ class cMineShaftCorridor : public cMineShaft { typedef cMineShaft super; - + public: /** Creates a new Corridor attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. @@ -123,36 +123,36 @@ public: int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise & a_Noise ); - + protected: static const int MAX_SEGMENTS = 5; - + int m_NumSegments; eDirection m_Direction; bool m_HasFullBeam[MAX_SEGMENTS]; ///< If true, segment at that index has a full beam support (planks in the top center block) int m_ChestPosition; ///< If <0, no chest; otherwise an offset from m_BoundingBox's p1.x or p1.z, depenging on m_Direction int m_SpawnerPosition; ///< If <0, no spawner; otherwise an offset from m_BoundingBox's p1.x or p1.z, depenging on m_Direction bool m_HasTracks; ///< If true, random tracks will be placed on the floor - + cMineShaftCorridor( cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox, int a_NumSegments, eDirection a_Direction, cNoise & a_Noise ); - + // cMineShaft overrides: virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override; virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override; /// Places a chest, if the corridor has one void PlaceChest(cChunkDesc & a_ChunkDesc); - + /// If this corridor has tracks, places them randomly void PlaceTracks(cChunkDesc & a_ChunkDesc); - + /// If this corridor has a spawner, places the spawner void PlaceSpawner(cChunkDesc & a_ChunkDesc); - + /// Randomly places torches around the central beam block void PlaceTorches(cChunkDesc & a_ChunkDesc); } ; @@ -165,7 +165,7 @@ class cMineShaftCrossing : public cMineShaft { typedef cMineShaft super; - + public: /** Creates a new Crossing attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. @@ -176,10 +176,10 @@ public: int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise & a_Noise ); - + protected: cMineShaftCrossing(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox); - + // cMineShaft overrides: virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override; virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override; @@ -193,14 +193,14 @@ class cMineShaftStaircase : public cMineShaft { typedef cMineShaft super; - + public: enum eSlope { sUp, sDown, } ; - + /** Creates a new Staircase attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. May return NULL if cannot fit. @@ -210,12 +210,12 @@ public: int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise & a_Noise ); - + protected: eDirection m_Direction; eSlope m_Slope; - - + + cMineShaftStaircase( cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox, @@ -257,7 +257,7 @@ public: /// Carves the system into the chunk data void ProcessChunk(cChunkDesc & a_Chunk); - + /** Creates new cMineShaft descendant connected at the specified point, heading the specified direction, if it fits, appends it to the list and calls its AppendBranches() */ @@ -266,7 +266,7 @@ public: cMineShaft::eDirection a_Direction, cNoise & a_Noise, int a_RecursionLevel ); - + /// Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid bool CanAppend(const cCuboid & a_BoundingBox); } ; @@ -294,7 +294,7 @@ cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem( m_ChanceTorch(1000) // TODO: settable { m_MineShafts.reserve(100); - + cMineShaft * Start = new cMineShaftDirtRoom(*this, a_Noise); m_MineShafts.push_back(Start); @@ -302,9 +302,9 @@ cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem( Start->m_BoundingBox.p1.x - a_MaxSystemSize / 2, 2, Start->m_BoundingBox.p1.z - a_MaxSystemSize / 2, Start->m_BoundingBox.p2.x + a_MaxSystemSize / 2, 50, Start->m_BoundingBox.p2.z + a_MaxSystemSize / 2 ); - + Start->AppendBranches(0, a_Noise); - + for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr) { ASSERT((*itr)->m_BoundingBox.IsSorted()); @@ -341,7 +341,7 @@ void cStructGenMineShafts::cMineShaftSystem::ProcessChunk(cChunkDesc & a_Chunk) void cStructGenMineShafts::cMineShaftSystem::AppendBranch( - int a_PivotX, int a_PivotY, int a_PivotZ, + int a_PivotX, int a_PivotY, int a_PivotZ, cMineShaft::eDirection a_Direction, cNoise & a_Noise, int a_RecursionLevel ) @@ -350,7 +350,7 @@ void cStructGenMineShafts::cMineShaftSystem::AppendBranch( { return; } - + cMineShaft * Next = NULL; int rnd = (a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_RecursionLevel * 16, a_PivotZ) / 13) % m_ProbLevelStaircase; if (rnd < m_ProbLevelCorridor) @@ -384,7 +384,7 @@ bool cStructGenMineShafts::cMineShaftSystem::CanAppend(const cCuboid & a_Boundin // Too far away, or too low / too high return false; } - + // Check intersections: for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr) { @@ -436,7 +436,7 @@ void cMineShaftDirtRoom::AppendBranches(int a_RecursionLevel, cNoise & a_Noise) rnd >>= 4; m_ParentSystem.AppendBranch(x, m_BoundingBox.p1.y + (rnd % Height), m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel); } - + for (int z = m_BoundingBox.p1.z + 1; z < m_BoundingBox.p2.z; z += 4) { int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x, a_RecursionLevel, z) / 13; @@ -464,13 +464,13 @@ void cMineShaftDirtRoom::ProcessChunk(cChunkDesc & a_ChunkDesc) // Early bailout - cannot intersect this chunk return; } - + // Chunk-relative coords of the boundaries: int MinX = std::max(BlockX, m_BoundingBox.p1.x) - BlockX; int MaxX = std::min(BlockX + cChunkDef::Width, m_BoundingBox.p2.x + 1) - BlockX; int MinZ = std::max(BlockZ, m_BoundingBox.p1.z) - BlockZ; int MaxZ = std::min(BlockZ + cChunkDef::Width, m_BoundingBox.p2.z + 1) - BlockZ; - + // Carve the room out: for (int z = MinZ; z < MaxZ; z++) { @@ -513,7 +513,7 @@ cMineShaftCorridor::cMineShaftCorridor( rnd >>= 2; } m_HasTracks = ((rnd % 4) < 2); // 50 % chance of tracks - + rnd = a_Noise.IntNoise3DInt(a_BoundingBox.p1.z, a_BoundingBox.p1.x, a_BoundingBox.p1.y) / 7; int ChestCheck = rnd % 250; rnd >>= 8; @@ -597,7 +597,7 @@ void cMineShaftCorridor::AppendBranches(int a_RecursionLevel, cNoise & a_Noise) } break; } - + case dirZM: { m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel); @@ -646,14 +646,14 @@ void cMineShaftCorridor::ProcessChunk(cChunkDesc & a_ChunkDesc) Top.p2.y += 1; Top.p1.y = Top.p2.y; a_ChunkDesc.FillRelCuboid(RelBoundingBox, E_BLOCK_AIR, 0); - a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_AIR, 0, BlockX ^ BlockZ + BlockX, 8000); + a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_AIR, 0, (BlockX ^ (BlockZ + BlockX)), 8000); if (m_SpawnerPosition >= 0) { // Cobwebs around the spider spawner - a_ChunkDesc.RandomFillRelCuboid(RelBoundingBox, E_BLOCK_COBWEB, 0, BlockX ^ BlockZ + BlockZ, 8000); - a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, BlockX ^ BlockZ + BlockX, 5000); + a_ChunkDesc.RandomFillRelCuboid(RelBoundingBox, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockZ)), 8000); + a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockX)), 5000); } - a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, BlockX ^ BlockZ + BlockX + 10, 500); + a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockX + 10)), 500); RelBoundingBox.p1.y = m_BoundingBox.p1.y; RelBoundingBox.p2.y = m_BoundingBox.p1.y; a_ChunkDesc.FloorRelCuboid(RelBoundingBox, E_BLOCK_PLANKS, 0); @@ -693,7 +693,7 @@ void cMineShaftCorridor::ProcessChunk(cChunkDesc & a_ChunkDesc) } // for i - NumSegments break; } - + case dirZM: case dirZP: { @@ -729,7 +729,7 @@ void cMineShaftCorridor::ProcessChunk(cChunkDesc & a_ChunkDesc) break; } // case dirZ? } // for i - + PlaceChest(a_ChunkDesc); PlaceTracks(a_ChunkDesc); PlaceSpawner(a_ChunkDesc); // (must be after Tracks!) @@ -762,7 +762,7 @@ void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc) { return; } - + int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; int x, z; @@ -777,7 +777,7 @@ void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc) Meta = E_META_CHEST_FACING_ZP; break; } - + case dirZM: case dirZP: { @@ -829,7 +829,7 @@ void cMineShaftCorridor::PlaceTracks(cChunkDesc & a_ChunkDesc) Meta = E_META_TRACKS_X; break; } - + case dirZM: case dirZP: { @@ -921,7 +921,7 @@ void cMineShaftCorridor::PlaceTorches(cChunkDesc & a_ChunkDesc) } // for i break; } - + case dirZM: case dirZP: { @@ -1041,7 +1041,7 @@ void cMineShaftCrossing::AppendBranches(int a_RecursionLevel, cNoise & a_Noise) // This exit is not available (two-level exit on a one-level crossing) continue; } - + int Height = m_BoundingBox.p1.y + Exits[i].y; m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Exits[i].x, Height, m_BoundingBox.p1.z + Exits[i].z, Exits[i].dir, a_Noise, a_RecursionLevel); } // for i @@ -1089,7 +1089,7 @@ void cMineShaftCrossing::ProcessChunk(cChunkDesc & a_ChunkDesc) a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Mid, Ceil, box.p1.z, box.p1.z, E_BLOCK_AIR, 0); a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Mid, Ceil, box.p2.z, box.p2.z, E_BLOCK_AIR, 0); } - + // The floor, if needed: box.p2.y = box.p1.y; a_ChunkDesc.FloorRelCuboid(box, E_BLOCK_PLANKS, 0); @@ -1198,7 +1198,7 @@ void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc) // No intersection between this staircase and this chunk return; } - + int SFloor = RelB.p1.y + ((m_Slope == sDown) ? 5 : 1); int DFloor = RelB.p1.y + ((m_Slope == sDown) ? 1 : 5); int Add = (m_Slope == sDown) ? -1 : 1; @@ -1221,7 +1221,7 @@ void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc) } break; } - + case dirXP: { a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p1.x + 1, SFloor, SFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0); @@ -1253,7 +1253,7 @@ void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc) } break; } - + case dirZP: { a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, SFloor, SFloor + 2, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_AIR, 0); @@ -1269,7 +1269,7 @@ void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc) } break; } - + } // switch (m_Direction) } @@ -1359,7 +1359,7 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk( ++itr; } } // for itr - m_Cache[] - + for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) { int RealX = (BaseX + x) * m_GridSize; @@ -1381,11 +1381,11 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk( } } // for z } // for x - + // Copy a_MineShafts into m_Cache to the beginning: cMineShaftSystems MineShaftsCopy(a_MineShafts); m_Cache.splice(m_Cache.begin(), MineShaftsCopy, MineShaftsCopy.begin(), MineShaftsCopy.end()); - + // Trim the cache if it's too long: if (m_Cache.size() > 100) { -- cgit v1.2.3 From 574e8f1419e9da7472bcd5b0813cc1d0e33fcf17 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:27:30 +0000 Subject: Fixed unsigned integer comparison. --- source/Generating/MineShafts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Generating/MineShafts.cpp b/source/Generating/MineShafts.cpp index e7884f243..bd8da6515 100644 --- a/source/Generating/MineShafts.cpp +++ b/source/Generating/MineShafts.cpp @@ -1034,7 +1034,7 @@ void cMineShaftCrossing::AppendBranches(int a_RecursionLevel, cNoise & a_Noise) { 5, 5, 2, dirXP}, { 2, 5, 5, dirZP}, } ; - for (int i = 0; i < ARRAYCOUNT(Exits); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(Exits); i++) { if (m_BoundingBox.p1.y + Exits[i].y >= m_BoundingBox.p2.y) { -- cgit v1.2.3 From f217981de99037e8e8e37222992886235f64b05b Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:34:54 +0000 Subject: Fixed another unsigned integer comparison. --- source/Generating/DistortedHeightmap.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/Generating/DistortedHeightmap.cpp b/source/Generating/DistortedHeightmap.cpp index 98eab31b5..7e46c251e 100644 --- a/source/Generating/DistortedHeightmap.cpp +++ b/source/Generating/DistortedHeightmap.cpp @@ -30,7 +30,7 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[biNumBiomes /* biExtremeHills */ {16.0f, 16.0f}, /* biForest */ { 3.0f, 3.0f}, /* biTaiga */ { 1.5f, 1.5f}, - + /* biSwampland */ { 0.0f, 0.0f}, /* biRiver */ { 0.0f, 0.0f}, /* biNether */ { 0.0f, 0.0f}, // Unused, but must be here due to indexing @@ -81,7 +81,7 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile) { return; } - + // 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); @@ -103,8 +103,8 @@ void cDistortedHeightmap::PrepareState(int a_ChunkX, int a_ChunkZ) } m_CurChunkX = a_ChunkX; m_CurChunkZ = a_ChunkZ; - - + + m_HeightGen.GenHeightMap(a_ChunkX, a_ChunkZ, m_CurChunkHeights); UpdateDistortAmps(); GenerateHeightArray(); @@ -126,13 +126,13 @@ void cDistortedHeightmap::GenerateHeightArray(void) NOISE_DATATYPE EndY = ((NOISE_DATATYPE)(257)) / m_FrequencyY; NOISE_DATATYPE StartZ = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width)) / m_FrequencyZ; NOISE_DATATYPE EndZ = ((NOISE_DATATYPE)((m_CurChunkZ + 1) * cChunkDef::Width - 1)) / m_FrequencyZ; - + m_NoiseDistortX.Generate3D(DistortNoiseX, DIM_X, DIM_Y, DIM_Z, StartX, EndX, StartY, EndY, StartZ, EndZ, Workspace); m_NoiseDistortZ.Generate3D(DistortNoiseZ, DIM_X, DIM_Y, DIM_Z, StartX, EndX, StartY, EndY, StartZ, EndZ, Workspace); // The distorted heightmap, before linear upscaling NOISE_DATATYPE DistHei[DIM_X * DIM_Y * DIM_Z]; - + // Distort the heightmap using the distortion: for (int z = 0; z < DIM_Z; z++) { @@ -151,7 +151,7 @@ void cDistortedHeightmap::GenerateHeightArray(void) } } } - + // Upscale the distorted heightmap into full dimensions: LinearUpscale3DArray( DistHei, DIM_X, DIM_Y, DIM_Z, @@ -208,7 +208,7 @@ void cDistortedHeightmap::ComposeTerrain(cChunkDesc & a_ChunkDesc) // Prepare the internal state for generating this chunk: PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()); - + // Compose: a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); for (int z = 0; z < cChunkDef::Width; z++) @@ -348,7 +348,7 @@ int cDistortedHeightmap::GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z) { return cChunkDef::GetHeight(m_CurChunkHeights, RelX, RelZ); } - + // Ask the cache: HEIGHTTYPE res = 0; if (m_HeightGen.GetHeightAt(ChunkX, ChunkZ, RelX, RelZ, res)) @@ -356,7 +356,7 @@ int cDistortedHeightmap::GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z) // The height was in the cache return res; } - + // The height is not in the cache, generate full heightmap and get it there: cChunkDef::HeightMap Heightmap; m_HeightGen.GenHeightMap(ChunkX, ChunkZ, Heightmap); @@ -385,7 +385,7 @@ void cDistortedHeightmap::UpdateDistortAmps(void) GetDistortAmpsAt(Biomes, x * INTERPOL_X, z * INTERPOL_Z, m_DistortAmpX[x + DIM_X * z], m_DistortAmpZ[x + DIM_X * z]); } } -} +} @@ -430,7 +430,7 @@ void cDistortedHeightmap::GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_R // For each biome type that has a nonzero count, calc its amps and add it: NOISE_DATATYPE AmpX = 0; NOISE_DATATYPE AmpZ = 0; - for (int i = 0; i < ARRAYCOUNT(BiomeCounts); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(BiomeCounts); i++) { AmpX += BiomeCounts[i] * m_GenParam[i].m_DistortAmpX; AmpZ += BiomeCounts[i] * m_GenParam[i].m_DistortAmpZ; -- cgit v1.2.3 From d3360051b160cb67115fa0f1d6a9be9424489529 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:37:43 +0000 Subject: Fixed typo causing buggy code. --- source/LinearUpscale.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/source/LinearUpscale.h b/source/LinearUpscale.h index b7ac84c6a..b337b3219 100644 --- a/source/LinearUpscale.h +++ b/source/LinearUpscale.h @@ -31,7 +31,7 @@ Linearly interpolates values in the array between the equidistant anchor points Works in-place (input is already present at the correct output coords) */ template void LinearUpscale2DArrayInPlace( - TYPE * a_Array, + TYPE * a_Array, int a_SizeX, int a_SizeY, // Dimensions of the array int a_AnchorStepX, int a_AnchorStepY // Distances between the anchor points in each direction ) @@ -53,7 +53,7 @@ template void LinearUpscale2DArrayInPlace( Idx += a_AnchorStepX; } // for x } // for y - + // Now interpolate in rows, each row has values in the anchor columns int LastXCell = a_SizeX - a_AnchorStepX; for (int y = 0; y < a_SizeY; y++) @@ -92,7 +92,7 @@ template void LinearUpscale2DArray( // Feel free to enlarge them if needed, but keep in mind that they're on the stack const int MAX_UPSCALE_X = 128; const int MAX_UPSCALE_Y = 128; - + ASSERT(a_Src != NULL); ASSERT(a_Dst != NULL); ASSERT(a_SrcSizeX > 0); @@ -101,7 +101,7 @@ template void LinearUpscale2DArray( ASSERT(a_UpscaleY > 0); ASSERT(a_UpscaleX <= MAX_UPSCALE_X); ASSERT(a_UpscaleY <= MAX_UPSCALE_Y); - + // Pre-calculate the upscaling ratios: TYPE RatioX[MAX_UPSCALE_X]; TYPE RatioY[MAX_UPSCALE_Y]; @@ -113,7 +113,7 @@ template void LinearUpscale2DArray( { RatioY[y] = (TYPE)y / a_UpscaleY; } - + // Interpolate each XY cell: int DstSizeX = (a_SrcSizeX - 1) * a_UpscaleX + 1; int DstSizeY = (a_SrcSizeY - 1) * a_UpscaleY + 1; @@ -163,7 +163,7 @@ template void LinearUpscale3DArray( const int MAX_UPSCALE_X = 128; const int MAX_UPSCALE_Y = 128; const int MAX_UPSCALE_Z = 128; - + ASSERT(a_Src != NULL); ASSERT(a_Dst != NULL); ASSERT(a_SrcSizeX > 0); @@ -175,11 +175,11 @@ template void LinearUpscale3DArray( ASSERT(a_UpscaleX <= MAX_UPSCALE_X); ASSERT(a_UpscaleY <= MAX_UPSCALE_Y); ASSERT(a_UpscaleZ <= MAX_UPSCALE_Z); - + // Pre-calculate the upscaling ratios: TYPE RatioX[MAX_UPSCALE_X]; TYPE RatioY[MAX_UPSCALE_Y]; - TYPE RatioZ[MAX_UPSCALE_Y]; + TYPE RatioZ[MAX_UPSCALE_Z]; for (int x = 0; x <= a_UpscaleX; x++) { RatioX[x] = (TYPE)x / a_UpscaleX; @@ -192,7 +192,7 @@ template void LinearUpscale3DArray( { RatioZ[z] = (TYPE)z / a_UpscaleZ; } - + // Interpolate each XYZ cell: int DstSizeX = (a_SrcSizeX - 1) * a_UpscaleX + 1; int DstSizeY = (a_SrcSizeY - 1) * a_UpscaleY + 1; -- cgit v1.2.3 From a319973e50e06de7e2fae96058aafdb1daceab1a Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:43:40 +0000 Subject: Fixed yet another unsigned integer comparison. --- source/Generating/Noise3DGenerator.cpp | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/source/Generating/Noise3DGenerator.cpp b/source/Generating/Noise3DGenerator.cpp index f47c64430..c47b3f8a2 100644 --- a/source/Generating/Noise3DGenerator.cpp +++ b/source/Generating/Noise3DGenerator.cpp @@ -25,8 +25,8 @@ public: DoTest1(); DoTest2(); } - - + + void DoTest1(void) { float In[3 * 3 * 3]; @@ -39,8 +39,8 @@ public: LinearUpscale3DArray(In, 3, 3, 3, Out, 8, 16, 17); Debug3DNoise(Out, 17, 33, 35, "Upscale3D test"); } - - + + void DoTest2(void) { float In[3 * 3]; @@ -53,7 +53,7 @@ public: LinearUpscale2DArray(In, 3, 3, Out, 8, 16); Debug2DNoise(Out, 17, 33, "Upscale2D test"); } - + } gTest; //*/ @@ -72,7 +72,7 @@ cNoise3DGenerator::cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator) : m_Perlin.AddOctave(1, (NOISE_DATATYPE)0.5); m_Perlin.AddOctave((NOISE_DATATYPE)0.5, 1); m_Perlin.AddOctave((NOISE_DATATYPE)0.5, 2); - + #if 0 // DEBUG: Test the noise generation: // NOTE: In order to be able to run MCS with this code, you need to increase the default thread stack size @@ -84,7 +84,7 @@ cNoise3DGenerator::cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator) : m_FrequencyY = 4; m_FrequencyZ = 4; m_AirThreshold = 0.5; - + const int NumChunks = 4; NOISE_DATATYPE Noise[NumChunks][cChunkDef::Width * cChunkDef::Width * cChunkDef::Height]; for (int x = 0; x < NumChunks; x++) @@ -153,7 +153,7 @@ cNoise3DGenerator::~cNoise3DGenerator() void cNoise3DGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) { m_World = a_World; - + // Params: m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62); m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0); @@ -170,7 +170,7 @@ void cNoise3DGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) void cNoise3DGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) { - for (int i = 0; i < ARRAYCOUNT(a_BiomeMap); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(a_BiomeMap); i++) { a_BiomeMap[i] = biExtremeHills; } @@ -184,7 +184,7 @@ void cNoise3DGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_Ch { NOISE_DATATYPE Noise[17 * 257 * 17]; GenerateNoiseArray(a_ChunkX, a_ChunkZ, Noise); - + // Output noise into chunk: for (int z = 0; z < cChunkDef::Width; z++) { @@ -207,7 +207,7 @@ void cNoise3DGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_Ch } } } - + UpdateHeightmap(a_ChunkDesc); ComposeTerrain (a_ChunkDesc); } @@ -228,11 +228,11 @@ void cNoise3DGenerator::GenerateNoiseArray(int a_ChunkX, int a_ChunkZ, NOISE_DAT NOISE_DATATYPE EndZ = ((NOISE_DATATYPE)((a_ChunkZ + 1) * cChunkDef::Width) - 1) / m_FrequencyZ; NOISE_DATATYPE StartY = 0; NOISE_DATATYPE EndY = ((NOISE_DATATYPE)256) / m_FrequencyY; - + m_Perlin.Generate3D(NoiseO, DIM_X, DIM_Y, DIM_Z, StartX, EndX, StartY, EndY, StartZ, EndZ, NoiseW); - + // DEBUG: Debug3DNoise(NoiseO, DIM_X, DIM_Y, DIM_Z, Printf("Chunk_%d_%d_orig", a_ChunkX, a_ChunkZ)); - + // Precalculate a "height" array: NOISE_DATATYPE Height[DIM_X * DIM_Z]; // Output for the cubic noise heightmap ("source") m_Cubic.Generate2D(Height, DIM_X, DIM_Z, StartX / 25, EndX / 25, StartZ / 25, EndZ / 25); @@ -240,7 +240,7 @@ void cNoise3DGenerator::GenerateNoiseArray(int a_ChunkX, int a_ChunkZ, NOISE_DAT { Height[i] = abs(Height[i]) * m_HeightAmplification + 1; } - + // Modify the noise by height data: for (int y = 0; y < DIM_Y; y++) { @@ -257,13 +257,13 @@ void cNoise3DGenerator::GenerateNoiseArray(int a_ChunkX, int a_ChunkZ, NOISE_DAT } // DEBUG: Debug3DNoise(NoiseO, DIM_X, DIM_Y, DIM_Z, Printf("Chunk_%d_%d_hei", a_ChunkX, a_ChunkZ)); - + // Upscale the Perlin noise into full-blown chunk dimensions: LinearUpscale3DArray( NoiseO, DIM_X, DIM_Y, DIM_Z, a_OutNoise, UPSCALE_X, UPSCALE_Y, UPSCALE_Z ); - + // DEBUG: Debug3DNoise(a_OutNoise, 17, 257, 17, Printf("Chunk_%d_%d_lerp", a_ChunkX, a_ChunkZ)); } @@ -383,12 +383,12 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) } m_LastChunkX = a_ChunkX; m_LastChunkZ = a_ChunkZ; - + // Upscaling parameters: const int UPSCALE_X = 8; const int UPSCALE_Y = 4; const int UPSCALE_Z = 8; - + const int DIM_X = 1 + cChunkDef::Width / UPSCALE_X; const int DIM_Y = 1 + cChunkDef::Height / UPSCALE_Y; const int DIM_Z = 1 + cChunkDef::Width / UPSCALE_Z; @@ -405,7 +405,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) Height[x + 17 * z] = val * val * val; } } - + int idx = 0; for (int y = 0; y < 257; y += UPSCALE_Y) { @@ -419,7 +419,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) for (int x = 0; x < 17; x += UPSCALE_X) { NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; - CurFloor[x + 17 * z] = + CurFloor[x + 17 * z] = m_Noise1.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 + m_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) + m_Noise3.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2 + @@ -429,7 +429,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) // Linear-interpolate this XZ floor: LinearUpscale2DArrayInPlace(CurFloor, 17, 17, UPSCALE_X, UPSCALE_Z); } - + // Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis for (int y = 1; y < cChunkDef::Height; y++) { @@ -455,7 +455,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) idx += 1; // Skipping one X column } } - + // The noise array is now fully interpolated /* // DEBUG: Output two images of the array, sliced by XY and XZ: @@ -504,7 +504,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) { GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ); - + for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) @@ -529,9 +529,9 @@ void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Hei void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc) { GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()); - + a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); - + // Make basic terrain composition: for (int z = 0; z < cChunkDef::Width; z++) { -- cgit v1.2.3 From 5687ca7bad4c83be16dd932c7f598fb699057a3e Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:44:19 +0000 Subject: Fixed another one... --- source/Generating/Noise3DGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Generating/Noise3DGenerator.cpp b/source/Generating/Noise3DGenerator.cpp index c47b3f8a2..e44f5f135 100644 --- a/source/Generating/Noise3DGenerator.cpp +++ b/source/Generating/Noise3DGenerator.cpp @@ -236,7 +236,7 @@ void cNoise3DGenerator::GenerateNoiseArray(int a_ChunkX, int a_ChunkZ, NOISE_DAT // Precalculate a "height" array: NOISE_DATATYPE Height[DIM_X * DIM_Z]; // Output for the cubic noise heightmap ("source") m_Cubic.Generate2D(Height, DIM_X, DIM_Z, StartX / 25, EndX / 25, StartZ / 25, EndZ / 25); - for (int i = 0; i < ARRAYCOUNT(Height); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(Height); i++) { Height[i] = abs(Height[i]) * m_HeightAmplification + 1; } -- cgit v1.2.3 From eb77bfc1b340ddc218fcf073918e998e25c722e5 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:46:06 +0000 Subject: Those variables weren't used. It seems strange for them to be there, is the code written wrong? --- source/Generating/Noise3DGenerator.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/Generating/Noise3DGenerator.cpp b/source/Generating/Noise3DGenerator.cpp index e44f5f135..c39bb5594 100644 --- a/source/Generating/Noise3DGenerator.cpp +++ b/source/Generating/Noise3DGenerator.cpp @@ -389,10 +389,6 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) const int UPSCALE_Y = 4; const int UPSCALE_Z = 8; - const int DIM_X = 1 + cChunkDef::Width / UPSCALE_X; - const int DIM_Y = 1 + cChunkDef::Height / UPSCALE_Y; - const int DIM_Z = 1 + cChunkDef::Width / UPSCALE_Z; - // Precalculate a "height" array: NOISE_DATATYPE Height[17 * 17]; // x + 17 * z for (int z = 0; z < 17; z += UPSCALE_Z) -- cgit v1.2.3 From c1880e1162001b72b7fbecbf4f4a1af9820bdee8 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:47:25 +0000 Subject: Got rid of another unused variable. --- source/Generating/Noise3DGenerator.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/Generating/Noise3DGenerator.cpp b/source/Generating/Noise3DGenerator.cpp index c39bb5594..03626a800 100644 --- a/source/Generating/Noise3DGenerator.cpp +++ b/source/Generating/Noise3DGenerator.cpp @@ -402,7 +402,6 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) } } - int idx = 0; for (int y = 0; y < 257; y += UPSCALE_Y) { NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)y) / m_FrequencyY; -- cgit v1.2.3 From 9ac95fc24ac48919a85318c5c2015f5cfa023a36 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:50:33 +0000 Subject: Got rid of yet another unused variable. --- source/Generating/Caves.cpp | 101 ++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/source/Generating/Caves.cpp b/source/Generating/Caves.cpp index 4221ea187..5aebc111b 100644 --- a/source/Generating/Caves.cpp +++ b/source/Generating/Caves.cpp @@ -55,7 +55,7 @@ struct cCaveDefPoint int m_BlockY; int m_BlockZ; int m_Radius; - + cCaveDefPoint(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Radius) : m_BlockX(a_BlockX), m_BlockY(a_BlockY), @@ -78,22 +78,22 @@ class cCaveTunnel int m_MinBlockX, m_MaxBlockX; int m_MinBlockY, m_MaxBlockY; int m_MinBlockZ, m_MaxBlockZ; - + /// Generates the shaping defpoints for the ravine, based on the ravine block coords and noise void Randomize(cNoise & a_Noise); - + /// Refines (adds and smooths) defpoints from a_Src into a_Dst; returns false if no refinement possible (segments too short) bool RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & a_Dst); - + /// Does rounds of smoothing, two passes of RefineDefPoints(), as long as they return true void Smooth(void); - + /// Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block void FinishLinear(void); - + /// Calculates the bounding box of the points present void CalcBoundingBox(void); - + public: cCaveDefPoints m_Points; @@ -102,14 +102,14 @@ public: int a_BlockEndX, int a_BlockEndY, int a_BlockEndZ, int a_EndRadius, cNoise & a_Noise ); - + /// Carves the tunnel into the chunk specified void ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, + int a_ChunkX, int a_ChunkZ, + cChunkDef::BlockTypes & a_BlockTypes, cChunkDef::HeightMap & a_HeightMap ); - + #ifdef _DEBUG AString ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const; #endif // _DEBUG @@ -128,17 +128,17 @@ public: // The generating block position; is read directly in cStructGenWormNestCaves::GetCavesForChunk() int m_BlockX; int m_BlockZ; - + cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise); ~cCaveSystem(); - + /// Carves the cave system into the chunk specified void ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, + int a_ChunkX, int a_ChunkZ, + cChunkDef::BlockTypes & a_BlockTypes, cChunkDef::HeightMap & a_HeightMap ); - + #ifdef _DEBUG AString ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const; #endif // _DEBUG @@ -146,15 +146,15 @@ public: protected: int m_Size; cCaveTunnels m_Tunnels; - + void Clear(void); /// Generates a_Segment successive tunnels, with possible branches. Generates the same output for the same [x, y, z, a_Segments] void GenerateTunnelsFromPoint( - int a_OriginX, int a_OriginY, int a_OriginZ, + int a_OriginX, int a_OriginY, int a_OriginZ, cNoise & a_Noise, int a_Segments ); - + /// Returns a radius based on the location provided. int GetRadius(cNoise & a_Noise, int a_OriginX, int a_OriginY, int a_OriginZ); } ; @@ -174,19 +174,19 @@ cCaveTunnel::cCaveTunnel( { m_Points.push_back(cCaveDefPoint(a_BlockStartX, a_BlockStartY, a_BlockStartZ, a_StartRadius)); m_Points.push_back(cCaveDefPoint(a_BlockEndX, a_BlockEndY, a_BlockEndZ, a_EndRadius)); - + if ((a_BlockStartY <= 0) && (a_BlockEndY <= 0)) { // Don't bother detailing this cave, it's under the world anyway return; } - + Randomize(a_Noise); Smooth(); - + // We know that the linear finishing won't affect the bounding box, so let's calculate it now, as we have less data: CalcBoundingBox(); - + FinishLinear(); } @@ -308,7 +308,7 @@ void cCaveTunnel::FinishLinear(void) // For each segment, use Bresenham's 3D line algorithm to draw a "line" of defpoints cCaveDefPoints Pts; std::swap(Pts, m_Points); - + m_Points.reserve(Pts.size() * 3); int PrevX = Pts.front().m_BlockX; int PrevY = Pts.front().m_BlockY; @@ -324,7 +324,6 @@ void cCaveTunnel::FinishLinear(void) int sx = (PrevX < x1) ? 1 : -1; int sy = (PrevY < y1) ? 1 : -1; int sz = (PrevZ < z1) ? 1 : -1; - int err = dx - dz; int R = itr->m_Radius; if (dx >= std::max(dy, dz)) // x dominant @@ -418,7 +417,7 @@ void cCaveTunnel::FinishLinear(void) PrevY += sy; yd -= dz; } - + // move along z PrevZ += sz; xd += dx; @@ -453,8 +452,8 @@ void cCaveTunnel::CalcBoundingBox(void) void cCaveTunnel::ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, + int a_ChunkX, int a_ChunkZ, + cChunkDef::BlockTypes & a_BlockTypes, cChunkDef::HeightMap & a_HeightMap ) { @@ -485,7 +484,7 @@ void cCaveTunnel::ProcessChunk( // Cannot intersect, bail out early continue; } - + // Carve out a sphere around the xyz point, m_Radius in diameter; skip 3/7 off the top and bottom: int DifX = itr->m_BlockX - BlockStartX; // substitution for faster calc int DifY = itr->m_BlockY; @@ -493,7 +492,7 @@ void cCaveTunnel::ProcessChunk( int Bottom = std::max(itr->m_BlockY - 3 * itr->m_Radius / 7, 1); int Top = std::min(itr->m_BlockY + 3 * itr->m_Radius / 7, (int)(cChunkDef::Height)); int SqRad = itr->m_Radius * itr->m_Radius; - for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++) + for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++) { for (int y = Bottom; y <= Top; y++) { @@ -527,9 +526,9 @@ void cCaveTunnel::ProcessChunk( } // for y } // for x, z } // for itr - m_Points[] - + /* - #ifdef _DEBUG + #ifdef _DEBUG // For debugging purposes, outline the shape of the cave using glowstone, *after* carving the entire cave: for (cCaveDefPoints::const_iterator itr = m_Points.begin(), end = m_Points.end(); itr != end; ++itr) { @@ -587,7 +586,7 @@ cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_BlockX, int a_BlockZ, in int OriginX = a_BlockX + (a_Noise.IntNoise3DInt(13 * a_BlockX, 17 * a_BlockZ, 11 * i) / 19) % a_MaxOffset; int OriginZ = a_BlockZ + (a_Noise.IntNoise3DInt(17 * a_BlockX, 13 * a_BlockZ, 11 * i) / 23) % a_MaxOffset; int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_BlockX, 13 * a_BlockZ, 11 * i) / 17) % 20; - + // Generate three branches from the origin point: // The tunnels generated depend on X, Y, Z and Branches, // for the same set of numbers it generates the same offsets! @@ -613,8 +612,8 @@ cStructGenWormNestCaves::cCaveSystem::~cCaveSystem() void cStructGenWormNestCaves::cCaveSystem::ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, + int a_ChunkX, int a_ChunkZ, + cChunkDef::BlockTypes & a_BlockTypes, cChunkDef::HeightMap & a_HeightMap ) { @@ -645,14 +644,14 @@ AString cStructGenWormNestCaves::cCaveSystem::ExportAsSVG(int a_Color, int a_Off AppendPrintf(SVG, "\n", a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5 ); - + // A gray line from the base point to the first point of the ravine, for identification: AppendPrintf(SVG, "\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, - a_OffsetX + m_Tunnels.front()->m_Points.front().m_BlockX, + a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, + a_OffsetX + m_Tunnels.front()->m_Points.front().m_BlockX, a_OffsetZ + m_Tunnels.front()->m_Points.front().m_BlockZ ); - + // Offset guides: if (a_OffsetX > 0) { @@ -666,7 +665,7 @@ AString cStructGenWormNestCaves::cCaveSystem::ExportAsSVG(int a_Color, int a_Off a_OffsetZ, a_OffsetZ ); } - + return SVG; } #endif // _DEBUG @@ -689,7 +688,7 @@ void cStructGenWormNestCaves::cCaveSystem::Clear(void) void cStructGenWormNestCaves::cCaveSystem::GenerateTunnelsFromPoint( - int a_OriginX, int a_OriginY, int a_OriginZ, + int a_OriginX, int a_OriginY, int a_OriginZ, cNoise & a_Noise, int a_NumSegments ) { @@ -727,7 +726,7 @@ int cStructGenWormNestCaves::cCaveSystem::GetRadius(cNoise & a_Noise, int a_Orig // We want mapping 384 -> 3, 0 -> 19, 768 -> 19, so divide by 24 to get [0 .. 31] with center at 16, then use abs() to fold around the center int res = 3 + abs((sum / 24) - 16); */ - + // Algorithm of choice: random value in the range of zero to random value - heavily towards zero int res = MIN_RADIUS + (rnd >> 8) % ((rnd % (MAX_RADIUS - MIN_RADIUS)) + 1); return res; @@ -815,7 +814,7 @@ void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStru ++itr; } } // for itr - m_Cache[] - + for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) { int RealX = (BaseX + x) * m_Grid; @@ -837,11 +836,11 @@ void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStru } } } - + // Copy a_Caves into m_Cache to the beginning: cCaveSystems CavesCopy(a_Caves); m_Cache.splice(m_Cache.begin(), CavesCopy, CavesCopy.begin(), CavesCopy.end()); - + // Trim the cache if it's too long: if (m_Cache.size() > 100) { @@ -855,7 +854,7 @@ void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStru std::advance(itr, 100); m_Cache.erase(itr, m_Cache.end()); } - + /* // Uncomment this block for debugging the caves' shapes in 2D using an SVG export #ifdef _DEBUG @@ -869,7 +868,7 @@ void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStru SVG.append((*itr)->ExportAsSVG(Color, 512, 512)); } SVG.append("\n"); - + AString fnam; Printf(fnam, "wnc\\%03d_%03d.svg", a_ChunkX, a_ChunkZ); cFile File(fnam, cFile::fmWrite); @@ -905,13 +904,13 @@ static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise ) void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc) { cNoise Noise(m_Seed); - for (int z = 0; z < cChunkDef::Width; z++) + for (int z = 0; z < cChunkDef::Width; z++) { const float zz = (float)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z); for (int x = 0; x < cChunkDef::Width; x++) { const float xx = (float)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + x); - + int Top = a_ChunkDesc.GetHeight(x, z); for (int y = 1; y < Top; ++y ) { @@ -940,13 +939,13 @@ void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenDualRidgeCaves::GenStructures(cChunkDesc & a_ChunkDesc) { - for (int z = 0; z < cChunkDef::Width; z++) + for (int z = 0; z < cChunkDef::Width; z++) { const float zz = (float)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z) / 10; for (int x = 0; x < cChunkDef::Width; x++) { const float xx = (float)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + x) / 10; - + int Top = a_ChunkDesc.GetHeight(x, z); for (int y = 1; y <= Top; ++y) { -- cgit v1.2.3 From 45aebbd5abe653045a6b647aec61df32b227bc78 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:52:48 +0000 Subject: This is a copy-paste fail, right? --- source/Generating/Caves.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Generating/Caves.cpp b/source/Generating/Caves.cpp index 5aebc111b..535ca4fb2 100644 --- a/source/Generating/Caves.cpp +++ b/source/Generating/Caves.cpp @@ -461,7 +461,7 @@ void cCaveTunnel::ProcessChunk( int BaseZ = a_ChunkZ * cChunkDef::Width; if ( (BaseX > m_MaxBlockX) || (BaseX + cChunkDef::Width < m_MinBlockX) || - (BaseX > m_MaxBlockX) || (BaseX + cChunkDef::Width < m_MinBlockX) + (BaseZ > m_MaxBlockZ) || (BaseZ + cChunkDef::Width < m_MinBlockZ) ) { // Tunnel does not intersect the chunk at all, bail out -- cgit v1.2.3 From 755fe9cb2188e64369ef4067d9074dd629744e02 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:54:01 +0000 Subject: WaveNoise not used, removing. --- source/Generating/Caves.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/Generating/Caves.cpp b/source/Generating/Caves.cpp index 535ca4fb2..df45bb4c2 100644 --- a/source/Generating/Caves.cpp +++ b/source/Generating/Caves.cpp @@ -950,7 +950,6 @@ void cStructGenDualRidgeCaves::GenStructures(cChunkDesc & a_ChunkDesc) for (int y = 1; y <= Top; ++y) { const float yy = (float)y / 10; - const float WaveNoise = 1; float n1 = m_Noise1.CubicNoise3D(xx, yy, zz); float n2 = m_Noise2.CubicNoise3D(xx, yy, zz); float n3 = m_Noise1.CubicNoise3D(xx * 4, yy * 4, zz * 4) / 4; -- cgit v1.2.3 From 0150de36888404782f8a27b9a23400ced1c7084b Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:55:49 +0000 Subject: Fixed some unsigned int comparison warnings. --- source/Generating/ChunkGenerator.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/source/Generating/ChunkGenerator.cpp b/source/Generating/ChunkGenerator.cpp index 59a00b540..33c956eba 100644 --- a/source/Generating/ChunkGenerator.cpp +++ b/source/Generating/ChunkGenerator.cpp @@ -15,10 +15,10 @@ /// If the generation queue size exceeds this number, a warning will be output -const int QUEUE_WARNING_LIMIT = 1000; +const unsigned int QUEUE_WARNING_LIMIT = 1000; /// If the generation queue size exceeds this number, chunks with no clients will be skipped -const int QUEUE_SKIP_LIMIT = 500; +const unsigned int QUEUE_SKIP_LIMIT = 500; @@ -53,7 +53,7 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) m_World = a_World; m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", rnd.randInt()); AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable"); - + if (NoCaseCompare(GeneratorName, "Noise3D") == 0) { m_Generator = new cNoise3DGenerator(*this); @@ -72,9 +72,9 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) LOGERROR("Generator could not start, aborting the server"); return false; } - + m_Generator->Initialize(a_World, a_IniFile); - + return super::Start(); } @@ -101,7 +101,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk { { cCSLock Lock(m_CS); - + // Check if it is already in the queue: for (cChunkCoordsList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr) { @@ -111,7 +111,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk return; } } // for itr - m_Queue[] - + // Add to queue, issue a warning if too many: if (m_Queue.size() >= QUEUE_WARNING_LIMIT) { @@ -119,7 +119,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk } m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); } - + m_Event.Set(); } @@ -196,7 +196,7 @@ void cChunkGenerator::Execute(void) int NumChunksGenerated = 0; // Number of chunks generated since the queue was last empty clock_t GenerationStart = clock(); // Clock tick when the queue started to fill clock_t LastReportTick = clock(); // Clock tick of the last report made (so that performance isn't reported too often) - + while (!m_ShouldTerminate) { cCSLock Lock(m_CS); @@ -219,7 +219,7 @@ void cChunkGenerator::Execute(void) GenerationStart = clock(); LastReportTick = clock(); } - + cChunkCoords coords = m_Queue.front(); // Get next coord from queue m_Queue.erase( m_Queue.begin() ); // Remove coordinate from queue bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); @@ -243,19 +243,19 @@ void cChunkGenerator::Execute(void) // Already generated, ignore request continue; } - + if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) { LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); continue; } - + LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - + // Save the chunk right after generating, so that we don't have to generate it again on next run m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - + NumChunksGenerated++; } // while (!bStop) } @@ -269,17 +269,17 @@ void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) cRoot::Get()->GetPluginManager()->CallHookChunkGenerating(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc); cRoot::Get()->GetPluginManager()->CallHookChunkGenerated(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); - + #ifdef _DEBUG // Verify that the generator has produced valid data: ChunkDesc.VerifyHeightmap(); #endif - + cChunkDef::BlockNibbles BlockMetas; ChunkDesc.CompressBlockMetas(BlockMetas); - + m_World->SetChunkData( - a_ChunkX, a_ChunkZ, + a_ChunkX, a_ChunkZ, ChunkDesc.GetBlockTypes(), BlockMetas, NULL, NULL, // We don't have lighting, chunk will be lighted when needed &ChunkDesc.GetHeightMap(), &ChunkDesc.GetBiomeMap(), -- cgit v1.2.3 From ef8ac545d8d9f93bfc489f61365b960731a16bd8 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:57:03 +0000 Subject: Fixed another one. --- source/Generating/EndGen.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/source/Generating/EndGen.cpp b/source/Generating/EndGen.cpp index 3eba5c47b..90a8071fa 100644 --- a/source/Generating/EndGen.cpp +++ b/source/Generating/EndGen.cpp @@ -18,7 +18,7 @@ enum INTERPOL_X = 4, INTERPOL_Y = 4, INTERPOL_Z = 4, - + // Size of chunk data, downscaled before interpolation: DIM_X = 16 / INTERPOL_X + 1, DIM_Y = 256 / INTERPOL_Y + 1, @@ -59,7 +59,7 @@ void cEndGen::Initialize(cIniFile & a_IniFile) m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "EndGenFrequencyX", m_FrequencyX); m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "EndGenFrequencyY", m_FrequencyY); m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "EndGenFrequencyZ", m_FrequencyZ); - + // Recalculate the min and max chunk coords of the island m_MaxChunkX = (m_IslandSizeX + cChunkDef::Width - 1) / cChunkDef::Width; m_MinChunkX = -m_MaxChunkX; @@ -75,15 +75,15 @@ void cEndGen::Initialize(cIniFile & a_IniFile) void cEndGen::PrepareState(int a_ChunkX, int a_ChunkZ) { ASSERT(!IsChunkOutsideRange(a_ChunkX, a_ChunkZ)); // Should be filtered before calling this function - + if ((m_LastChunkX == a_ChunkX) && (m_LastChunkZ == a_ChunkZ)) { return; } - + m_LastChunkX = a_ChunkX; m_LastChunkZ = a_ChunkZ; - + GenerateNoiseArray(); } @@ -96,7 +96,7 @@ void cEndGen::GenerateNoiseArray(void) { NOISE_DATATYPE NoiseData[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y] NOISE_DATATYPE Workspace[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y] - + // Generate the downscaled noise: NOISE_DATATYPE StartX = ((NOISE_DATATYPE)(m_LastChunkX * cChunkDef::Width)) / m_FrequencyX; NOISE_DATATYPE EndX = ((NOISE_DATATYPE)((m_LastChunkX + 1) * cChunkDef::Width)) / m_FrequencyX; @@ -105,7 +105,7 @@ void cEndGen::GenerateNoiseArray(void) NOISE_DATATYPE StartY = 0; NOISE_DATATYPE EndY = ((NOISE_DATATYPE)257) / m_FrequencyY; m_Perlin.Generate3D(NoiseData, DIM_X, DIM_Z, DIM_Y, StartX, EndX, StartZ, EndZ, StartY, EndY, Workspace); - + // Add distance: int idx = 0; for (int y = 0; y < DIM_Y; y++) @@ -125,7 +125,7 @@ void cEndGen::GenerateNoiseArray(void) } // for x } // for z } // for y - + // Upscale into real chunk size: LinearUpscale3DArray(NoiseData, DIM_X, DIM_Z, DIM_Y, m_NoiseArray, INTERPOL_X, INTERPOL_Z, INTERPOL_Y); } @@ -133,14 +133,14 @@ void cEndGen::GenerateNoiseArray(void) - + /// Returns true if the chunk is outside of the island's dimensions bool cEndGen::IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ) { return ( (a_ChunkX < m_MinChunkX) || (a_ChunkX > m_MaxChunkX) || (a_ChunkZ < m_MinChunkZ) || (a_ChunkZ > m_MaxChunkZ) - ); + ); } @@ -151,15 +151,15 @@ void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_ { if (IsChunkOutsideRange(a_ChunkX, a_ChunkZ)) { - for (int i = 0; i < ARRAYCOUNT(a_HeightMap); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(a_HeightMap); i++) { a_HeightMap[i] = 0; } return; } - + PrepareState(a_ChunkX, a_ChunkZ); - + int MaxY = std::min((int)(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1); for (int z = 0; z < cChunkDef::Width; z++) { @@ -189,9 +189,9 @@ void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc) a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); return; } - + PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()); - + int MaxY = std::min((int)(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1); for (int z = 0; z < cChunkDef::Width; z++) { -- cgit v1.2.3 From f4f906563fdf60c2de61df8ed02d51c5591c8639 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:58:17 +0000 Subject: another --- source/Generating/ChunkDesc.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/Generating/ChunkDesc.cpp b/source/Generating/ChunkDesc.cpp index dc6c74a3c..4e2a85abe 100644 --- a/source/Generating/ChunkDesc.cpp +++ b/source/Generating/ChunkDesc.cpp @@ -270,7 +270,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX a_MaxRelX += 1; a_MaxRelY += 1; a_MaxRelZ += 1; - + // Check coords validity: if (a_MinRelX < 0) { @@ -313,7 +313,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX LOGWARNING("%s: MaxRelY more than chunk height, adjusting to chunk height", __FUNCTION__); a_MaxRelY = cChunkDef::Height - 1; } - + if (a_MinRelZ < 0) { LOGWARNING("%s: MinRelZ less than zero, adjusting to zero", __FUNCTION__); @@ -370,7 +370,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX HEIGHTTYPE cChunkDesc::GetMaxHeight(void) const { HEIGHTTYPE MaxHeight = m_HeightMap[0]; - for (int i = 1; i < ARRAYCOUNT(m_HeightMap); i++) + for (unsigned int i = 1; i < ARRAYCOUNT(m_HeightMap); i++) { if (m_HeightMap[i] > MaxHeight) { @@ -397,7 +397,7 @@ void cChunkDesc::FillRelCuboid( int MaxX = std::min(a_MaxX, cChunkDef::Width - 1); int MaxY = std::min(a_MaxY, cChunkDef::Height - 1); int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1); - + for (int y = MinY; y <= MaxY; y++) { for (int z = MinZ; z <= MaxZ; z++) @@ -428,7 +428,7 @@ void cChunkDesc::ReplaceRelCuboid( int MaxX = std::min(a_MaxX, cChunkDef::Width - 1); int MaxY = std::min(a_MaxY, cChunkDef::Height - 1); int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1); - + for (int y = MinY; y <= MaxY; y++) { for (int z = MinZ; z <= MaxZ; z++) @@ -464,7 +464,7 @@ void cChunkDesc::FloorRelCuboid( int MaxX = std::min(a_MaxX, cChunkDef::Width - 1); int MaxY = std::min(a_MaxY, cChunkDef::Height - 1); int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1); - + for (int y = MinY; y <= MaxY; y++) { for (int z = MinZ; z <= MaxZ; z++) @@ -505,7 +505,7 @@ void cChunkDesc::RandomFillRelCuboid( int MaxX = std::min(a_MaxX, cChunkDef::Width - 1); int MaxY = std::min(a_MaxY, cChunkDef::Height - 1); int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1); - + for (int y = MinY; y <= MaxY; y++) { for (int z = MinZ; z <= MaxZ; z++) -- cgit v1.2.3 From dbf2982e52b71e106923d4f36c6006fe68ca29e5 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 16 Nov 2013 18:58:38 +0000 Subject: And another... --- source/Generating/ChunkDesc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Generating/ChunkDesc.cpp b/source/Generating/ChunkDesc.cpp index 4e2a85abe..df7574c58 100644 --- a/source/Generating/ChunkDesc.cpp +++ b/source/Generating/ChunkDesc.cpp @@ -538,7 +538,7 @@ void cChunkDesc::AddBlockEntity(cBlockEntity * a_BlockEntity) void cChunkDesc::CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas) { const NIBBLETYPE * AreaMetas = m_BlockArea.GetBlockMetas(); - for (int i = 0; i < ARRAYCOUNT(a_DestMetas); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(a_DestMetas); i++) { a_DestMetas[i] = AreaMetas[2 * i] | (AreaMetas[2 * i + 1] << 4); } -- cgit v1.2.3 From 6ff6929ca6c599418f98fe750c04a76774075c18 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 16 Nov 2013 20:58:17 +0000 Subject: General fixes [SEE DESC] * Fixed faulty block face enumeration and functions + Added fireworks and exp bottle spawning * Fixed arrows again --- source/Defines.h | 40 ++++++------ source/Entities/ProjectileEntity.cpp | 120 ++++++++++++++++++++++++++++++----- source/Entities/ProjectileEntity.h | 55 ++++++++++++++++ source/Items/ItemHandler.cpp | 2 + source/Items/ItemThrowable.h | 44 +++++++++++++ 5 files changed, 226 insertions(+), 35 deletions(-) diff --git a/source/Defines.h b/source/Defines.h index 5621aeac1..06410cab4 100644 --- a/source/Defines.h +++ b/source/Defines.h @@ -59,20 +59,20 @@ enum enum eBlockFace { BLOCK_FACE_NONE = -1, // Interacting with no block face - swinging the item in the air - BLOCK_FACE_XM = 5, // Interacting with the X- face of the block - BLOCK_FACE_XP = 4, // Interacting with the X+ face of the block + BLOCK_FACE_XM = 4, // Interacting with the X- face of the block + BLOCK_FACE_XP = 5, // Interacting with the X+ face of the block BLOCK_FACE_YM = 0, // Interacting with the Y- face of the block BLOCK_FACE_YP = 1, // Interacting with the Y+ face of the block - BLOCK_FACE_ZM = 3, // Interacting with the Z- face of the block - BLOCK_FACE_ZP = 2, // Interacting with the Z+ face of the block + BLOCK_FACE_ZM = 2, // Interacting with the Z- face of the block + BLOCK_FACE_ZP = 3, // Interacting with the Z+ face of the block // Synonyms using the (deprecated) world directions: BLOCK_FACE_BOTTOM = BLOCK_FACE_YM, // Interacting with the bottom face of the block BLOCK_FACE_TOP = BLOCK_FACE_YP, // Interacting with the top face of the block - BLOCK_FACE_NORTH = BLOCK_FACE_ZP, // Interacting with the northern face of the block - BLOCK_FACE_SOUTH = BLOCK_FACE_ZM, // Interacting with the southern face of the block - BLOCK_FACE_WEST = BLOCK_FACE_XP, // Interacting with the western face of the block - BLOCK_FACE_EAST = BLOCK_FACE_XM, // Interacting with the eastern face of the block + BLOCK_FACE_NORTH = BLOCK_FACE_ZM, // Interacting with the northern face of the block + BLOCK_FACE_SOUTH = BLOCK_FACE_ZP, // Interacting with the southern face of the block + BLOCK_FACE_WEST = BLOCK_FACE_XM, // Interacting with the western face of the block + BLOCK_FACE_EAST = BLOCK_FACE_XP, // Interacting with the eastern face of the block } ; @@ -305,12 +305,12 @@ inline void AddFaceDirection(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cha { switch (a_BlockFace) { - case BLOCK_FACE_BOTTOM: a_BlockY--; break; - case BLOCK_FACE_TOP: a_BlockY++; break; - case BLOCK_FACE_EAST: a_BlockX++; break; - case BLOCK_FACE_WEST: a_BlockX--; break; - case BLOCK_FACE_NORTH: a_BlockZ--; break; - case BLOCK_FACE_SOUTH: a_BlockZ++; break; + case BLOCK_FACE_YP: a_BlockY++; break; + case BLOCK_FACE_YM: a_BlockY--; break; + case BLOCK_FACE_ZM: a_BlockZ--; break; + case BLOCK_FACE_ZP: a_BlockZ++; break; + case BLOCK_FACE_XP: a_BlockX++; break; + case BLOCK_FACE_XM: a_BlockX--; break; default: { LOGWARNING("%s: Unknown face: %d", __FUNCTION__, a_BlockFace); @@ -323,12 +323,12 @@ inline void AddFaceDirection(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cha { switch (a_BlockFace) { - case BLOCK_FACE_BOTTOM: a_BlockY++; break; - case BLOCK_FACE_TOP: a_BlockY--; break; - case BLOCK_FACE_EAST: a_BlockX--; break; - case BLOCK_FACE_WEST: a_BlockX++; break; - case BLOCK_FACE_NORTH: a_BlockZ++; break; - case BLOCK_FACE_SOUTH: a_BlockZ--; break; + case BLOCK_FACE_YP: a_BlockY--; break; + case BLOCK_FACE_YM: a_BlockY++; break; + case BLOCK_FACE_ZM: a_BlockZ++; break; + case BLOCK_FACE_ZP: a_BlockZ--; break; + case BLOCK_FACE_XP: a_BlockX--; break; + case BLOCK_FACE_XM: a_BlockX++; break; default: { LOGWARNING("%s: Unknown inv face: %d", __FUNCTION__, a_BlockFace); diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 9d927e39b..fb25aea35 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -230,6 +230,8 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkFirework: return new cFireworkEntity (a_Creator, a_X, a_Y, a_Z ); // TODO: the rest } @@ -446,29 +448,19 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { + if (a_HitFace == BLOCK_FACE_NONE) { return; } + super::OnHitSolidBlock(a_HitPos, a_HitFace); int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; - - // Projectiles mistakenly think a face faces the direction a player faces when looking directly at said face - // This therefore breaks YP & YM of AddFaceDirection - see #350 for more details + switch (a_HitFace) { - case BLOCK_FACE_NONE: break; // Block tracer sometimes returns this, in this case, the coords will be correct - case BLOCK_FACE_YP: - { - a_Y--; - break; - } + case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed case BLOCK_FACE_YM: { - a_Y++; - break; - } - default: - { - AddFaceDirection(a_X, a_Y, a_Z, a_HitFace); break; } + default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true); } m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); @@ -672,6 +664,104 @@ void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_Hi +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cBottleOEnchantingEntity : + +cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : +super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + // TODO: Spawn experience orbs + + Destroy(); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFireworkEntity : + +cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z) : +super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ +} + + + + + +void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + if ((a_HitFace != BLOCK_FACE_BOTTOM) && (a_HitFace != BLOCK_FACE_NONE)) + { + return; + } + + SetSpeed(0, 0, 0); + SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ()); + + std::cout << a_HitPos.x << " " << a_HitPos.y << " " << a_HitPos.z << std::endl; + + m_IsInGround = true; + + BroadcastMovementUpdate(); +} + + + + + +void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) +{ + if (m_IsInGround) + { + if (a_Chunk.GetBlock((int)GetPosX(), (int)GetPosY() + 1, (int)GetPosZ()) == E_BLOCK_AIR) + { + m_IsInGround = false; + } + else + { + return; + } + } + + Vector3d PerTickSpeed = GetSpeed() / 20; + Vector3d Pos = GetPosition(); + + // Trace the tick's worth of movement as a line: + Vector3d NextPos = Pos + PerTickSpeed; + cProjectileTracerCallback TracerCallback(this); + if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos)) + { + // Something has been hit, abort all other processing + return; + } + // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff + + // Update the position: + SetPosition(NextPos); + + // Add slowdown and gravity effect to the speed: + Vector3d NewSpeed(GetSpeed()); + NewSpeed.y += 2; + NewSpeed *= TracerCallback.GetSlowdownCoeff(); + SetSpeed(NewSpeed); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cGhastFireballEntity : diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index f62b53a42..959e81ae5 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -34,6 +34,7 @@ public: pkEnderPearl = 65, pkExpBottle = 75, pkSplashPotion = 73, + pkFirework = 76, pkWitherSkull = 66, pkFishingFloat = 90, } ; @@ -159,6 +160,7 @@ protected: /// Timer for pickup collection animation or five minute timeout float m_Timer; + /// Timer for client arrow position confirmation via TeleportEntity float m_HitGroundTimer; /// If true, the arrow is in the process of being collected - don't go to anyone else @@ -262,6 +264,59 @@ protected: +class cExpBottleEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cExpBottleEntity); + + cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + + // tolua_begin + +}; + + + + + +class cFireworkEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cFireworkEntity); + + cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; + + // tolua_begin + +}; + + + + + class cGhastFireballEntity : public cProjectileEntity { diff --git a/source/Items/ItemHandler.cpp b/source/Items/ItemHandler.cpp index 13f5293b9..92ba94999 100644 --- a/source/Items/ItemHandler.cpp +++ b/source/Items/ItemHandler.cpp @@ -90,6 +90,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType); case E_ITEM_BED: return new cItemBedHandler(a_ItemType); case E_ITEM_BOAT: return new cItemBoatHandler(a_ItemType); + case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler(); case E_ITEM_BOW: return new cItemBowHandler; case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType); case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType); @@ -97,6 +98,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType); case E_ITEM_EGG: return new cItemEggHandler(); case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler(); + case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler(); case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType); diff --git a/source/Items/ItemThrowable.h b/source/Items/ItemThrowable.h index 85579daf2..fc24e775a 100644 --- a/source/Items/ItemThrowable.h +++ b/source/Items/ItemThrowable.h @@ -94,3 +94,47 @@ public: + +class cItemBottleOEnchantingHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; +public: + cItemBottleOEnchantingHandler(void) : + super(E_ITEM_BOTTLE_O_ENCHANTING, cProjectileEntity::pkExpBottle, 10) + { + } +}; + + + + + +class cItemFireworkHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; +public: + cItemFireworkHandler(void) : + super(E_ITEM_FIREWORK_ROCKET, cProjectileEntity::pkFirework, 0) + { + } + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override + { + if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + return false; + } + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + + a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, 0); + + return true; + } + +}; \ No newline at end of file -- cgit v1.2.3 From 165934fc262762377e7f01921ce3e484c57e7b8d Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Sun, 17 Nov 2013 09:43:26 +1100 Subject: fix *.sdf? --- VC2013/MCServer.sdf | Bin 0 -> 61997056 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 VC2013/MCServer.sdf diff --git a/VC2013/MCServer.sdf b/VC2013/MCServer.sdf new file mode 100644 index 000000000..f0501bef6 Binary files /dev/null and b/VC2013/MCServer.sdf differ -- cgit v1.2.3 From 416292a82456a850692fcbf67373d8124f503d5e Mon Sep 17 00:00:00 2001 From: nesco Date: Sun, 17 Nov 2013 17:41:58 +0100 Subject: Blank Line added --- source/Mobs/Giant.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/Mobs/Giant.cpp b/source/Mobs/Giant.cpp index 44ee58e92..66e5bbb01 100644 --- a/source/Mobs/Giant.cpp +++ b/source/Mobs/Giant.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Giant.h" -- cgit v1.2.3 From 9bc79722c7b8665f18a5be70c751f8383e9b0815 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 17 Nov 2013 23:01:23 +0100 Subject: APIDump: Documented Vector3f. --- MCServer/Plugins/APIDump/APIDesc.lua | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index cccc05ce2..210ddc1ae 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2707,13 +2707,43 @@ end Vector3f = { - Desc = [[A Vector3f object uses floating point values to describe a point in space. Vector3f is part of the {{vector3|vector3}} family. -]], + Desc = [[ + A Vector3f object uses floating point values to describe a point in space.

+

+ See also {{Vector3d}} for double-precision floating point 3D coords and {{Vector3i}} for integer + point 3D coords. + ]], Functions = { + constructor = + { + { Params = "", Return = "Vector3f", Notes = "Creates a new Vector3f object with zero coords" }, + { Params = "x, y, z", Return = "Vector3f", Notes = "Creates a new Vector3f object with the specified coords" }, + { Params = "Vector3f", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified vector" }, + { Params = "{{Vector3d}}", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified {{Vector3d}}" }, + { Params = "{{Vector3i}}", Return = "Vector3f", Notes = "Creates a new Vector3f object as a copy of the specified {{Vector3i}}" }, + }, + operator_mul = + { + { Params = "number", Return = "Vector3f", Notes = "Returns a new Vector3f object that has each of its coords multiplied by the specified number" }, + { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that has each of its coords multiplied by the respective coord of the specified vector." }, + }, + operator_plus = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the vector sum of this vector and the specified vector." }, + operator_sub = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the vector differrence between this vector and the specified vector." }, + Cross = { Params = "Vector3f", Return = "Vector3f", Notes = "Returns a new Vector3f object that holds the cross product of this vector and the specified vector." }, + Dot = { Params = "Vector3f", Return = "number", Notes = "Returns the dot product of this vector and the specified vector." }, + Equals = { Params = "Vector3f", Return = "bool", Notes = "Returns true if the specified vector is exactly equal to this vector." }, + Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector" }, + Normalize = { Params = "", Return = "", Notes = "Normalizes this vector (makes it 1 unit long while keeping the direction). FIXME: Fails for zero vectors." }, + NormalizeCopy = { Params = "", Return = "Vector3f", Notes = "Returns a copy of this vector that is normalized (1 unit long while keeping the same direction). FIXME: Fails for zero vectors." }, + Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once." }, + SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." }, }, - Constants = + Variables = { + x = { Type = "number", Notes = "The X coord of the vector." }, + y = { Type = "number", Notes = "The Y coord of the vector." }, + z = { Type = "number", Notes = "The Z coord of the vector." }, }, }, -- Vector3f -- cgit v1.2.3 From b5821998b4519590f8b512aafe74379dfed1e574 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 17 Nov 2013 23:29:17 +0100 Subject: Mineshafts: silenced a compiler warning. --- source/Generating/MineShafts.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/Generating/MineShafts.cpp b/source/Generating/MineShafts.cpp index 78bb15759..f42240e55 100644 --- a/source/Generating/MineShafts.cpp +++ b/source/Generating/MineShafts.cpp @@ -780,6 +780,7 @@ void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc) case dirZM: case dirZP: + default: { x = m_BoundingBox.p1.x - BlockX; z = m_BoundingBox.p1.z + m_ChestPosition - BlockZ; -- cgit v1.2.3 From 44385fba28d68f9ea416d88b0f14b8d72aa8d2a7 Mon Sep 17 00:00:00 2001 From: nesco Date: Mon, 18 Nov 2013 16:55:30 +0100 Subject: flower=38 --- MCServer/items.ini | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MCServer/items.ini b/MCServer/items.ini index bc19467a7..42ab22fa3 100644 --- a/MCServer/items.ini +++ b/MCServer/items.ini @@ -119,12 +119,10 @@ redwool=35:14 blackwool=35:15 dandelion=37 -; Obsolete, use "dandelion" instead (kept for compatibility, will be removed) -flower=37 - -; Obselete, use a specific flower name instead +; Obselete, use a specific flower name instead (or flower) rose=38 +flower=38 poppy=38 blueorchid=38:1 allium=38:2 -- cgit v1.2.3 From bc1e236d547479833cc4f8d8218064cbdb9dfc0d Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 18 Nov 2013 22:30:34 +0000 Subject: Redstone Megacommit [SEE DESC] + Updated BlockID - look for yourself * Improved button, repeater, lever, and comparator code -> simplification and splitting of some stuff from the redstone simulator file * Fixed buttons not breaking when in an invalid game state * Fixed QueueSetBlock -> improved (AGAIN) piston code + Rewrote redstone simulator Fixes: #57, #58, #205, and part of #131. Fixes FS issues: 281, 116, and 102 --- source/BlockID.cpp | 29 +- source/Blocks/BlockButton.cpp | 21 +- source/Blocks/BlockButton.h | 36 +- source/Blocks/BlockComparator.cpp | 4 +- source/Blocks/BlockLever.cpp | 13 +- source/Blocks/BlockLever.h | 19 +- source/Blocks/BlockRedstoneRepeater.cpp | 3 +- source/Blocks/BlockRedstoneRepeater.h | 27 + source/Chunk.cpp | 14 +- source/Chunk.h | 3 + source/Items/ItemComparator.h | 4 +- source/Items/ItemRedstoneRepeater.h | 4 +- source/Piston.cpp | 21 +- source/Piston.h | 3 - source/Simulator/RedstoneSimulator.cpp | 1631 +++++++++++++++---------------- source/Simulator/RedstoneSimulator.h | 217 +++- 16 files changed, 1047 insertions(+), 1002 deletions(-) diff --git a/source/BlockID.cpp b/source/BlockID.cpp index 4467d7e82..a4a1ab2d8 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -669,13 +669,13 @@ public: g_BlockTransparent[E_BLOCK_FLOWER_POT] = true; g_BlockTransparent[E_BLOCK_GLASS] = true; g_BlockTransparent[E_BLOCK_GLASS_PANE] = true; - g_BlockTransparent[E_BLOCK_STAINED_GLASS] = true; - g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true; + g_BlockTransparent[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true; g_BlockTransparent[E_BLOCK_ICE] = true; g_BlockTransparent[E_BLOCK_IRON_DOOR] = true; g_BlockTransparent[E_BLOCK_LAVA] = true; g_BlockTransparent[E_BLOCK_LEAVES] = true; g_BlockTransparent[E_BLOCK_LEVER] = true; + g_BlockTransparent[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true; g_BlockTransparent[E_BLOCK_MELON_STEM] = true; g_BlockTransparent[E_BLOCK_NETHER_BRICK_FENCE] = true; g_BlockTransparent[E_BLOCK_NEW_LEAVES] = true; @@ -687,6 +687,8 @@ public: g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true; g_BlockTransparent[E_BLOCK_SIGN_POST] = true; g_BlockTransparent[E_BLOCK_SNOW] = true; + g_BlockTransparent[E_BLOCK_STAINED_GLASS] = true; + g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true; g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true; g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true; g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true; @@ -700,7 +702,7 @@ public: // TODO: Any other transparent blocks? - // One hit break blocks + // One hit break blocks: g_BlockOneHitDig[E_BLOCK_ACTIVE_COMPARATOR] = true; g_BlockOneHitDig[E_BLOCK_BIG_FLOWER] = true; g_BlockOneHitDig[E_BLOCK_BROWN_MUSHROOM] = true; @@ -711,7 +713,6 @@ public: g_BlockOneHitDig[E_BLOCK_FLOWER] = true; g_BlockOneHitDig[E_BLOCK_FLOWER_POT] = true; g_BlockOneHitDig[E_BLOCK_INACTIVE_COMPARATOR] = true; - g_BlockOneHitDig[E_BLOCK_LOCKED_CHEST] = true; g_BlockOneHitDig[E_BLOCK_MELON_STEM] = true; g_BlockOneHitDig[E_BLOCK_POTATOES] = true; g_BlockOneHitDig[E_BLOCK_PUMPKIN_STEM] = true; @@ -727,7 +728,7 @@ public: g_BlockOneHitDig[E_BLOCK_TALL_GRASS] = true; g_BlockOneHitDig[E_BLOCK_TORCH] = true; - // Blocks that breaks when pushed by piston + // Blocks that break when pushed by piston: g_BlockPistonBreakable[E_BLOCK_ACTIVE_COMPARATOR] = true; g_BlockPistonBreakable[E_BLOCK_AIR] = true; g_BlockPistonBreakable[E_BLOCK_BED] = true; @@ -765,11 +766,12 @@ public: g_BlockPistonBreakable[E_BLOCK_TORCH] = true; g_BlockPistonBreakable[E_BLOCK_VINES] = true; g_BlockPistonBreakable[E_BLOCK_WATER] = true; + g_BlockPistonBreakable[E_BLOCK_WOODEN_BUTTON] = true; g_BlockPistonBreakable[E_BLOCK_WOODEN_DOOR] = true; g_BlockPistonBreakable[E_BLOCK_WOODEN_PRESSURE_PLATE] = true; - // Blocks that can be snowed over: + // Blocks that cannot be snowed over: g_BlockIsSnowable[E_BLOCK_ACTIVE_COMPARATOR] = false; g_BlockIsSnowable[E_BLOCK_AIR] = false; g_BlockIsSnowable[E_BLOCK_BIG_FLOWER] = false; @@ -785,7 +787,6 @@ public: g_BlockIsSnowable[E_BLOCK_INACTIVE_COMPARATOR] = false; g_BlockIsSnowable[E_BLOCK_LAVA] = false; g_BlockIsSnowable[E_BLOCK_LILY_PAD] = false; - g_BlockIsSnowable[E_BLOCK_LOCKED_CHEST] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_OFF] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_ON] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_OFF] = false; @@ -796,6 +797,8 @@ public: g_BlockIsSnowable[E_BLOCK_SAPLING] = false; g_BlockIsSnowable[E_BLOCK_SIGN_POST] = false; g_BlockIsSnowable[E_BLOCK_SNOW] = false; + g_BlockIsSnowable[E_BLOCK_STAINED_GLASS] = false; + g_BlockIsSnowable[E_BLOCK_STAINED_GLASS_PANE] = false; g_BlockIsSnowable[E_BLOCK_STATIONARY_LAVA] = false; g_BlockIsSnowable[E_BLOCK_STATIONARY_WATER] = false; g_BlockIsSnowable[E_BLOCK_TALL_GRASS] = false; @@ -806,7 +809,7 @@ public: g_BlockIsSnowable[E_BLOCK_WATER] = false; - // Blocks that don't drop without a special tool + // Blocks that don't drop without a special tool: g_BlockRequiresSpecialTool[E_BLOCK_BRICK] = true; g_BlockRequiresSpecialTool[E_BLOCK_CAULDRON] = true; g_BlockRequiresSpecialTool[E_BLOCK_COAL_ORE] = true; @@ -841,7 +844,7 @@ public: g_BlockRequiresSpecialTool[E_BLOCK_STONE_SLAB] = true; g_BlockRequiresSpecialTool[E_BLOCK_VINES] = true; - // Nonsolid Blocks: + // Nonsolid blocks: g_BlockIsSolid[E_BLOCK_ACTIVATOR_RAIL] = false; g_BlockIsSolid[E_BLOCK_AIR] = false; g_BlockIsSolid[E_BLOCK_BIG_FLOWER] = false; @@ -860,11 +863,8 @@ public: g_BlockIsSolid[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = false; g_BlockIsSolid[E_BLOCK_MELON_STEM] = false; g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false; - g_BlockIsSolid[E_BLOCK_PISTON] = false; g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false; g_BlockIsSolid[E_BLOCK_RAIL] = false; - g_BlockIsSolid[E_BLOCK_REDSTONE_REPEATER_OFF] = false; - g_BlockIsSolid[E_BLOCK_REDSTONE_REPEATER_ON] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_WIRE] = false; @@ -887,7 +887,7 @@ public: g_BlockIsSolid[E_BLOCK_WOODEN_PRESSURE_PLATE] = false; g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false; - // Torch placeable + // Torch placeable blocks: g_BlockIsTorchPlaceable[E_BLOCK_BEDROCK] = true; g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_COAL] = true; g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_REDSTONE] = true; @@ -933,7 +933,7 @@ public: g_BlockIsTorchPlaceable[E_BLOCK_NETHER_QUARTZ_ORE] = true; g_BlockIsTorchPlaceable[E_BLOCK_NOTE_BLOCK] = true; g_BlockIsTorchPlaceable[E_BLOCK_OBSIDIAN] = true; - g_BlockIsTorchPlaceable[E_BLOCK_PACKED_ICE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_PACKED_ICE] = true; g_BlockIsTorchPlaceable[E_BLOCK_PLANKS] = true; g_BlockIsTorchPlaceable[E_BLOCK_PUMPKIN] = true; g_BlockIsTorchPlaceable[E_BLOCK_QUARTZ_BLOCK] = true; @@ -955,3 +955,4 @@ public: + diff --git a/source/Blocks/BlockButton.cpp b/source/Blocks/BlockButton.cpp index 1011f9351..19b055b62 100644 --- a/source/Blocks/BlockButton.cpp +++ b/source/Blocks/BlockButton.cpp @@ -17,21 +17,14 @@ cBlockButtonHandler::cBlockButtonHandler(BLOCKTYPE a_BlockType) void cBlockButtonHandler::OnUse(cWorld *a_World, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { - // Flip the ON bit on/off. Using XOR bitwise operation to turn it on/off. + // Flip the ON bit on/off using the XOR bitwise operation NIBBLETYPE Meta = ((a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08) & 0x0f); - a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); - - if (Meta & 0x08) - { - a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); - } - else - { - a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.5f); - } - - // Queue a button reset (unpress), with a GetBlock to prevent duplication of buttons (press, break, wait for reset) - a_World->QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ), ((a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08) & 0x0f), m_BlockType == E_BLOCK_STONE_BUTTON ? 20 : 25); + + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta); + a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); + + // Queue a button reset (unpress) + a_World->QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, ((a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08) & 0x0f), m_BlockType == E_BLOCK_STONE_BUTTON ? 20 : 30); } diff --git a/source/Blocks/BlockButton.h b/source/Blocks/BlockButton.h index e3f655bfa..15649acc0 100644 --- a/source/Blocks/BlockButton.h +++ b/source/Blocks/BlockButton.h @@ -14,11 +14,11 @@ public: virtual void OnUse(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; - + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType == E_BLOCK_WOODEN_BUTTON ? E_BLOCK_WOODEN_BUTTON : E_BLOCK_STONE_BUTTON, 1, 0)); + a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } @@ -51,10 +51,10 @@ public: { switch (a_BlockFace) { - case BLOCK_FACE_ZP: { return 0x4; } - case BLOCK_FACE_ZM: { return 0x3; } - case BLOCK_FACE_XP: { return 0x2; } - case BLOCK_FACE_XM: { return 0x1; } + case BLOCK_FACE_ZM: { return 0x4; } + case BLOCK_FACE_ZP: { return 0x3; } + case BLOCK_FACE_XM: { return 0x2; } + case BLOCK_FACE_XP: { return 0x1; } default: { ASSERT(!"Unhandled block face!"); @@ -62,6 +62,30 @@ public: } } } + + inline static NIBBLETYPE BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) + { + switch (a_Meta & 0x7) + { + case 0x1: return BLOCK_FACE_XP; + case 0x2: return BLOCK_FACE_XM; + case 0x3: return BLOCK_FACE_ZP; + case 0x4: return BLOCK_FACE_ZM; + default: + { + ASSERT(!"Unhandled block meta!"); + return BLOCK_FACE_NONE; + } + } + } + + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + { + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + + AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true); + return (a_RelY > 0) && (g_BlockIsSolid[a_Chunk.GetBlock(a_RelX, a_RelY, a_RelZ)]); + } } ; diff --git a/source/Blocks/BlockComparator.cpp b/source/Blocks/BlockComparator.cpp index b4e5a55d0..8bc0ac5ac 100644 --- a/source/Blocks/BlockComparator.cpp +++ b/source/Blocks/BlockComparator.cpp @@ -1,7 +1,7 @@ #include "Globals.h" #include "BlockComparator.h" -#include "../Simulator/RedstoneSimulator.h" +#include "BlockRedstoneRepeater.h" #include "../Entities/Player.h" @@ -44,7 +44,7 @@ bool cBlockComparatorHandler::GetPlacementBlockTypeMeta( ) { a_BlockType = m_BlockType; - a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); return true; } diff --git a/source/Blocks/BlockLever.cpp b/source/Blocks/BlockLever.cpp index a9bd6c990..2739fa3a9 100644 --- a/source/Blocks/BlockLever.cpp +++ b/source/Blocks/BlockLever.cpp @@ -19,18 +19,11 @@ cBlockLeverHandler::cBlockLeverHandler(BLOCKTYPE a_BlockType) void cBlockLeverHandler::OnUse(cWorld *a_World, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { - // Flip the ON bit on/off. Using XOR bitwise operation to turn it on/off. + // Flip the ON bit on/off using the XOR bitwise operation NIBBLETYPE Meta = ((a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08) & 0x0f); - a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); - if (Meta & 0x08) - { - a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); - } - else - { - a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.5f); - } + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta); + a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); } diff --git a/source/Blocks/BlockLever.h b/source/Blocks/BlockLever.h index 5553170e2..fe7ecdf7e 100644 --- a/source/Blocks/BlockLever.h +++ b/source/Blocks/BlockLever.h @@ -1,7 +1,6 @@ #pragma once #include "BlockHandler.h" -#include "../Simulator/RedstoneSimulator.h" @@ -37,11 +36,27 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = cRedstoneSimulator::LeverDirectionToMetaData(a_BlockFace); + a_BlockMeta = LeverDirectionToMetaData(a_BlockFace); return true; } + inline static NIBBLETYPE LeverDirectionToMetaData(char a_Dir) + { + // Determine lever direction: + switch (a_Dir) + { + case BLOCK_FACE_TOP: return 0x6; + case BLOCK_FACE_EAST: return 0x1; + case BLOCK_FACE_WEST: return 0x2; + case BLOCK_FACE_SOUTH: return 0x3; + case BLOCK_FACE_NORTH: return 0x4; + case BLOCK_FACE_BOTTOM: return 0x0; + default: return 0x6; + } + } + + virtual const char * GetStepSound(void) override { return "step.wood"; diff --git a/source/Blocks/BlockRedstoneRepeater.cpp b/source/Blocks/BlockRedstoneRepeater.cpp index 72ea21012..3ab5bc559 100644 --- a/source/Blocks/BlockRedstoneRepeater.cpp +++ b/source/Blocks/BlockRedstoneRepeater.cpp @@ -1,7 +1,6 @@ #include "Globals.h" #include "BlockRedstoneRepeater.h" -#include "../Simulator/RedstoneSimulator.h" #include "../Entities/Player.h" @@ -42,7 +41,7 @@ bool cBlockRedstoneRepeaterHandler::GetPlacementBlockTypeMeta( ) { a_BlockType = m_BlockType; - a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetRotation()); return true; } diff --git a/source/Blocks/BlockRedstoneRepeater.h b/source/Blocks/BlockRedstoneRepeater.h index 958841a34..a61121d3a 100644 --- a/source/Blocks/BlockRedstoneRepeater.h +++ b/source/Blocks/BlockRedstoneRepeater.h @@ -48,6 +48,33 @@ public: { return "step.wood"; } + + + inline static NIBBLETYPE RepeaterRotationToMetaData(double a_Rotation) + { + a_Rotation += 90 + 45; // So its not aligned with axis + if (a_Rotation > 360) + { + a_Rotation -= 360; + } + + if ((a_Rotation >= 0) && (a_Rotation < 90)) + { + return 0x1; + } + else if ((a_Rotation >= 180) && (a_Rotation < 270)) + { + return 0x3; + } + else if ((a_Rotation >= 90) && (a_Rotation < 180)) + { + return 0x2; + } + else + { + return 0x0; + } + } } ; diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 1c937c894..6e83d32ea 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -682,17 +682,17 @@ void cChunk::ProcessQueuedSetBlocks(void) Int64 CurrTick = m_World->GetWorldAge(); for (sSetBlockQueueVector::iterator itr = m_SetBlockQueue.begin(); itr != m_SetBlockQueue.end();) { - if (itr->m_Tick < CurrTick) + if (itr->m_Tick <= CurrTick) { - // Not yet - ++itr; - continue; + // Current world age is bigger than/equal to target world age - delay time reached + SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); + itr = m_SetBlockQueue.erase(itr); } else { - // Now is the time to set the block - SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); - itr = m_SetBlockQueue.erase(itr); + // Not yet + ++itr; + continue; } } // for itr - m_SetBlockQueue[] } diff --git a/source/Chunk.h b/source/Chunk.h index 63a8f75cd..0d7479347 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -6,6 +6,7 @@ #include "Simulator/FireSimulator.h" #include "Simulator/SandSimulator.h" +#include "Simulator/RedstoneSimulator.h" @@ -338,6 +339,7 @@ public: cFluidSimulatorData * GetWaterSimulatorData(void) { return m_WaterSimulatorData; } cFluidSimulatorData * GetLavaSimulatorData (void) { return m_LavaSimulatorData; } cSandSimulatorChunkData & GetSandSimulatorData (void) { return m_SandSimulatorData; } + cRedstoneSimulatorChunkData & GetRedstoneSimulatorData(void) { return m_RedstoneSimulatorData; } cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); } @@ -407,6 +409,7 @@ private: cFluidSimulatorData * m_WaterSimulatorData; cFluidSimulatorData * m_LavaSimulatorData; cSandSimulatorChunkData m_SandSimulatorData; + cRedstoneSimulatorChunkData m_RedstoneSimulatorData; // pick up a random block of this chunk diff --git a/source/Items/ItemComparator.h b/source/Items/ItemComparator.h index 53dbd020d..3fbb7603d 100644 --- a/source/Items/ItemComparator.h +++ b/source/Items/ItemComparator.h @@ -2,7 +2,7 @@ #pragma once #include "ItemHandler.h" -#include "../Simulator/RedstoneSimulator.h" +#include "../Blocks/BlockRedstoneRepeater.h" @@ -30,7 +30,7 @@ public: ) override { a_BlockType = E_BLOCK_INACTIVE_COMPARATOR; - a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); return true; } } ; diff --git a/source/Items/ItemRedstoneRepeater.h b/source/Items/ItemRedstoneRepeater.h index 459070579..f69f24eb8 100644 --- a/source/Items/ItemRedstoneRepeater.h +++ b/source/Items/ItemRedstoneRepeater.h @@ -2,7 +2,7 @@ #pragma once #include "ItemHandler.h" -#include "../Simulator/RedstoneSimulator.h" +#include "../Blocks/BlockRedstoneRepeater.h" @@ -30,7 +30,7 @@ public: ) override { a_BlockType = E_BLOCK_REDSTONE_REPEATER_OFF; - a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); return true; } } ; diff --git a/source/Piston.cpp b/source/Piston.cpp index 136100922..ed175d3e3 100644 --- a/source/Piston.cpp +++ b/source/Piston.cpp @@ -14,14 +14,8 @@ -extern bool g_BlockPistonBreakable[]; - - - - - /// Number of ticks that the piston extending / retracting waits before setting the block -const int PISTON_TICK_DELAY = 20; +const int PISTON_TICK_DELAY = 6; @@ -120,7 +114,7 @@ void cPiston::ExtendPiston(int pistx, int pisty, int pistz) AddDir(pistx, pisty, pistz, pistonMeta, -1); // "pist" now at piston body, "ext" at future extension - m_World->QueueSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta | 0x8, PISTON_TICK_DELAY); + m_World->SetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta | 0x8); m_World->QueueSetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), PISTON_TICK_DELAY); } @@ -141,7 +135,7 @@ void cPiston::RetractPiston(int pistx, int pisty, int pistz) m_World->BroadcastBlockAction(pistx, pisty, pistz, 1, pistonMeta & ~(8), pistonBlock); m_World->BroadcastSoundEffect("tile.piston.in", pistx * 8, pisty * 8, pistz * 8, 0.5f, 0.7f); - m_World->QueueSetBlock(pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8), PISTON_TICK_DELAY); + m_World->SetBlock(pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8)); // Check the extension: AddDir(pistx, pisty, pistz, pistonMeta, 1); @@ -199,15 +193,6 @@ bool cPiston::IsSticky(BLOCKTYPE a_BlockType) -bool cPiston::IsStickyExtension(NIBBLETYPE a_ExtMeta) -{ - return ((a_ExtMeta & 0x08) != 0); -} - - - - - bool cPiston::CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { switch (a_BlockType) diff --git a/source/Piston.h b/source/Piston.h index cc051e454..92ddf6938 100644 --- a/source/Piston.h +++ b/source/Piston.h @@ -63,9 +63,6 @@ public: /// Returns true if the piston (with the specified meta) is extended static bool IsExtended(NIBBLETYPE a_PistonMeta); - - /// Returns true if the extension (with the specified meta) is sticky - static bool IsStickyExtension(NIBBLETYPE a_ExtMeta); /// Returns true if the specified block can be pushed by a piston (and left intact) static bool CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); diff --git a/source/Simulator/RedstoneSimulator.cpp b/source/Simulator/RedstoneSimulator.cpp index 8526a888e..29f59fa53 100644 --- a/source/Simulator/RedstoneSimulator.cpp +++ b/source/Simulator/RedstoneSimulator.cpp @@ -3,12 +3,10 @@ #include "RedstoneSimulator.h" #include "../BlockEntities/DropSpenserEntity.h" +#include "../Entities/TNTEntity.h" #include "../Blocks/BlockTorch.h" +#include "../Blocks/BlockDoor.h" #include "../Piston.h" -#include "../World.h" -#include "../BlockID.h" -#include "../Chunk.h" -#include "../Entities/TNTEntity.h" @@ -31,1104 +29,1024 @@ cRedstoneSimulator::~cRedstoneSimulator() -void cRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if (a_Chunk == NULL) + if ((a_Chunk == NULL) || !a_Chunk->IsValid()) + { + return; + } + else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height)) { return; } + int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - - // Check if any close neighbor is redstone-related: - int MinY = (a_BlockY > 0) ? -1 : 0; - int MaxY = (a_BlockY < cChunkDef::Height - 1) ? 1 : 0; - for (int y = MinY; y <= MaxY; y++) for (int x = -1; x < 2; x++) for (int z = -1; z < 2; z++) + + if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ))) { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!a_Chunk->UnboundedRelGetBlock(RelX + x, a_BlockY + y, RelZ + z, BlockType, BlockMeta)) + return; + } + + // Check for duplicates: + cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); + for (cRedstoneSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr) + { + if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) { - continue; + return; } - switch (BlockType) - { - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_REDSTONE_LAMP_OFF: - case E_BLOCK_REDSTONE_LAMP_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_LEVER: - case E_BLOCK_STONE_BUTTON: - case E_BLOCK_WOODEN_BUTTON: - case E_BLOCK_TRIPWIRE_HOOK: - { - m_Blocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); - return; - } - } // switch (BlockType) - } // for y, x, z - neighbors + } + + ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ)); } -void cRedstoneSimulator::Simulate(float a_Dt) +void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) { - // Toggle torches on/off - while (!m_RefreshTorchesAround.empty()) + cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); + if (ChunkData.empty()) { - Vector3i pos = m_RefreshTorchesAround.front(); - m_RefreshTorchesAround.pop_front(); - - RefreshTorchesAround(pos); + return; } - // Set repeaters to correct values, and decrement ticks - for (RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end();) + int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; + int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; + + for (cRedstoneSimulatorChunkData::const_iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) { - if (--itr->Ticks > 0) + BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z); + if (!IsAllowedBlock(BlockType)) { - // Not yet, move to next item in the list - ++itr; + dataitr = ChunkData.erase(dataitr); continue; } - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(itr->Position.x, itr->Position.y, itr->Position.z, BlockType, BlockMeta); - if (itr->bPowerOn && (BlockType == E_BLOCK_REDSTONE_REPEATER_OFF)) - { - m_World.FastSetBlock(itr->Position.x, itr->Position.y, itr->Position.z, E_BLOCK_REDSTONE_REPEATER_ON, BlockMeta); - m_Blocks.push_back(itr->Position); - } - else if (!itr->bPowerOn && (BlockType == E_BLOCK_REDSTONE_REPEATER_ON)) + + // Check to see if PoweredBlocks have invalid items (source is air or an unpowered source) + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end();) { - m_World.FastSetBlock(itr->Position.x, itr->Position.y, itr->Position.z, E_BLOCK_REDSTONE_REPEATER_OFF, BlockMeta); - m_Blocks.push_back(itr->Position); + sPoweredBlocks & Change = *itr; + BLOCKTYPE SourceBlockType = m_World.GetBlock(Change.a_SourcePos); + + if (SourceBlockType != Change.a_SourceBlock) + { + itr = m_PoweredBlocks.erase(itr); + } + else if ( + // Changeable sources + ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (m_World.GetBlockMeta(Change.a_SourcePos) == 0)) || + ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(m_World.GetBlockMeta(Change.a_SourcePos))) || + ((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (m_World.GetBlockMeta(Change.a_SourcePos) & 0x08) == 0x08) || + (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(m_World.GetBlockMeta(Change.a_SourcePos)))) + ) + { + itr = m_PoweredBlocks.erase(itr); + } + else + { + itr++; + } } - if (itr->bPowerOffNextTime) + // Check to see if LinkedPoweredBlocks have invalid items: source, block powered through, or power destination block has changed + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end();) { - itr->bPowerOn = false; - itr->bPowerOffNextTime = false; - itr->Ticks = 10; // TODO: Look up actual ticks from block metadata - ++itr; + sLinkedPoweredBlocks & Change = *itr; + BLOCKTYPE SourceBlockType = m_World.GetBlock(Change.a_SourcePos); + BLOCKTYPE MiddleBlockType = m_World.GetBlock(Change.a_MiddlePos); + + if (SourceBlockType != Change.a_SourceBlock) + { + itr = m_LinkedPoweredBlocks.erase(itr); + } + else if (MiddleBlockType != Change.a_MiddleBlock) + { + itr = m_LinkedPoweredBlocks.erase(itr); + } + else if ( + // Things that can send power through a block but which depends on meta + ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (m_World.GetBlockMeta(Change.a_SourcePos) == 0)) || + ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(m_World.GetBlockMeta(Change.a_SourcePos))) || + (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(m_World.GetBlockMeta(Change.a_SourcePos)))) + ) + { + itr = m_LinkedPoweredBlocks.erase(itr); + } + else + { + itr++; + } } - else + + // PoweredBlock list was fine, now to the actual handling + int a_X = BaseX + dataitr->x; + int a_Z = BaseZ + dataitr->z; + switch (BlockType) { - itr = m_SetRepeaters.erase(itr); + case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break; + case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break; + case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; + case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break; + + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + { + HandleRedstoneTorch(a_X, dataitr->y, a_Z, BlockType); + break; + } + case E_BLOCK_STONE_BUTTON: + case E_BLOCK_WOODEN_BUTTON: + { + HandleRedstoneButton(a_X, dataitr->y, a_Z, BlockType); + break; + } + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + { + HandleRedstoneRepeater(a_X, dataitr->y, a_Z, BlockType); + break; + } + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + { + HandlePiston(a_X, dataitr->y, a_Z); + break; + } + case E_BLOCK_REDSTONE_LAMP_OFF: + case E_BLOCK_REDSTONE_LAMP_ON: + { + HandleRedstoneLamp(a_X, dataitr->y, a_Z, BlockType); + break; + } + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: + { + HandleDropSpenser(a_X, dataitr->y, a_Z); + break; + } + case E_BLOCK_WOODEN_DOOR: + case E_BLOCK_IRON_DOOR: + { + HandleDoor(a_X, dataitr->y, a_Z); + break; + } + case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_DETECTOR_RAIL: + case E_BLOCK_POWERED_RAIL: + { + HandleRail(a_X, dataitr->y, a_Z, BlockType); + break; + } } - } - // Handle changed blocks - { - cCSLock Lock(m_CS); - std::swap(m_Blocks, m_BlocksBuffer); - } - for (BlockList::iterator itr = m_BlocksBuffer.begin(); itr != m_BlocksBuffer.end(); ++itr) - { - HandleChange(*itr); + ++dataitr; } - m_BlocksBuffer.clear(); } -void cRedstoneSimulator::RefreshTorchesAround(const Vector3i & a_BlockPos) +void cRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) { - static Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, 0,-1), - Vector3i(0, 0, 1), - Vector3i(0, 1, 0), // Also toggle torch on top - }; - BLOCKTYPE TargetBlockType = E_BLOCK_REDSTONE_TORCH_ON; - BLOCKTYPE TargetRepeaterType = E_BLOCK_REDSTONE_REPEATER_OFF; - if (IsPowered(a_BlockPos, true)) + static const struct // Define which directions the torch can power { - TargetBlockType = E_BLOCK_REDSTONE_TORCH_OFF; - TargetRepeaterType = E_BLOCK_REDSTONE_REPEATER_ON; - //Make TNT Explode when it gets powered. - if (m_World.GetBlock(a_BlockPos) == E_BLOCK_TNT) + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + } ; + + if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON) + { + // Check if the block the torch is on is powered + int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ; + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on + + if (AreCoordsPowered(X, Y, Z)) + { + // There was a match, torch goes off + // FastSetBlock so the server doesn't fail an assert -_- + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); + return; + } + + // Torch still on, make all 4(X, Z) + 1(Y) sides powered + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { - m_World.BroadcastSoundEffect("random.fuse", a_BlockPos.x * 8, a_BlockPos.y * 8, a_BlockPos.z * 8, 0.5f, 0.6f); - m_World.SpawnPrimedTNT(a_BlockPos.x + 0.5, a_BlockPos.y + 0.5, a_BlockPos.z + 0.5, 4); // 4 seconds to boom - m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_AIR, 0); + BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z); + if (i < ARRAYCOUNT(gCrossCoords) - 1) // Sides of torch, not top (top is last) + { + if ( + ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc. + (!Vector3i(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on + ) + { + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + } + } + else + { + // Top side, power whatever is there, including blocks + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + } } - //Turn a redstone lamp on when it gets powered. - if (m_World.GetBlock(a_BlockPos) == E_BLOCK_REDSTONE_LAMP_OFF) + + if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0x5) // Is torch standing on ground? If not (i.e. on wall), power block beneath { - m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_ON, 0); + BLOCKTYPE Type = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + + if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though! + { + SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + } } - //if (m_World.GetBlock(a_BlockPos) == E_BLOCK_DIRT) - //{ - // m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_STONE, 0); - //} } else { - //Turn a redstone lamp off when it gets powered. - if (m_World.GetBlock(a_BlockPos) == E_BLOCK_REDSTONE_LAMP_ON) + // Check if the block the torch is on is powered + int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ; + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on + + // See if off state torch can be turned on again + if (AreCoordsPowered(X, Y, Z)) { - m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_OFF, 0); + return; // Something matches, torch still powered } - //if (m_World.GetBlock(a_BlockPos) == E_BLOCK_STONE) - //{ - // m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_DIRT, 0); - //} + + // Block torch on not powered, can be turned on again! + // FastSetBlock so the server doesn't fail an assert -_- + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); } + return; +} + + + - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + +void cRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + static const struct // Define which directions the redstone block can power { - Vector3i TorchPos = a_BlockPos + Surroundings[i]; - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(TorchPos.x, TorchPos.y, TorchPos.z, BlockType, BlockMeta); - switch (BlockType) - { - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - { - if (BlockType != TargetBlockType) - { - if (cBlockTorchHandler::IsAttachedTo(TorchPos, BlockMeta, a_BlockPos)) - { - m_World.FastSetBlock(TorchPos.x, TorchPos.y, TorchPos.z, TargetBlockType, BlockMeta); - m_Blocks.push_back(TorchPos); - } - } - break; - } - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - { - if ((BlockType != TargetRepeaterType) && IsRepeaterPointingAway(TorchPos, BlockMeta, a_BlockPos)) - { - SetRepeater(TorchPos, 10, (TargetRepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)); - } - break; - } - } // switch (BlockType) - } // for i - Surroundings[] + int x, y, z; + } gCrossCoords[] = + { + { 0, 0, 0}, // Oh, anomalous redstone. Only block that powers itself + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + { 0,-1, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power everything + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); + } + return; } -void cRedstoneSimulator::HandleChange(const Vector3i & a_BlockPos) +void cRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ) { - std::deque< Vector3i > SpreadStack; - - static const Vector3i Surroundings[] = { - Vector3i(1, 0, 0), - Vector3i(1, 1, 0), - Vector3i(1,-1, 0), - Vector3i(-1, 0, 0), - Vector3i(-1, 1, 0), - Vector3i(-1,-1, 0), - Vector3i(0, 0, 1), - Vector3i(0, 1, 1), - Vector3i(0,-1, 1), - Vector3i(0, 0,-1), - Vector3i(0, 1,-1), - Vector3i(0,-1,-1), - Vector3i(0,-1, 0), - }; - - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - - // First check whether torch should be on or off - switch (BlockType) + if (IsLeverOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ))) { - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: + static const struct // Define which directions the redstone lever can power (all sides) { - static const Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, 0,-1), - Vector3i(0, 0, 1), - Vector3i(0,-1, 0), - }; - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) - { - Vector3i pos = a_BlockPos + Surroundings[i]; - BLOCKTYPE OtherBlock = m_World.GetBlock(pos); - if ( - (OtherBlock != E_BLOCK_AIR) && - (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && - (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) - ) - { - RefreshTorchesAround(pos); - } - } - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - break; - } // case "torches" - - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: + int x, y, z; + } gCrossCoords[] = { - // Check if repeater is powered by a 'powered block' (not wires/torch) - Vector3i Direction = GetRepeaterDirection(BlockMeta); - Vector3i pos = a_BlockPos - Direction; // NOTE: It's minus Direction - BLOCKTYPE OtherBlock = m_World.GetBlock(pos); - if ( - (OtherBlock != E_BLOCK_AIR) && - (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && - (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) && - (OtherBlock != E_BLOCK_REDSTONE_WIRE) - ) - { - RefreshTorchesAround(pos); - } - else - { - SetRepeater(a_BlockPos, 10, IsPowered(a_BlockPos, false)); - } - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - break; + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + { 0,-1, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power everything + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER); } - } // switch (BlockType) - BlockList Sources; - switch (BlockType) + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER); + } + return; +} + + + + + +void cRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType) +{ + if (IsButtonOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ))) { - case E_BLOCK_REDSTONE_TORCH_ON: + static const struct // Define which directions the redstone button can power (all sides) { - // If torch is still on, use it as a source - Sources.push_back(a_BlockPos); - break; - } - - case E_BLOCK_REDSTONE_REPEATER_ON: + int x, y, z; + } gCrossCoords[] = { - // Repeater only spreads charge right in front, and up to one block up: - static const Vector3i Surroundings [] = { - Vector3i(0, 0, 0), - Vector3i(0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection(BlockMeta); - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) - { - Vector3i pos = a_BlockPos + Direction + Surroundings[i]; - if (PowerBlock(pos, a_BlockPos, 0xf)) - { - SpreadStack.push_back(pos); - } - } - break; - } // case E_BLOCK_REDSTONE_REPEATER_ON - - case E_BLOCK_LEVER: - { - // Adding lever to the source queue - if (cRedstoneSimulator::IsLeverOn(BlockMeta)) - { - Sources.push_back(a_BlockPos); - } - break; - } // case E_BLOCK_LEVER - } // switch (BlockType) + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + { 0,-1, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power everything + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_BlockType); + } + + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, a_BlockType); + } +} + + + + - // Power all blocks legally connected to the sources - if (BlockType != E_BLOCK_REDSTONE_REPEATER_ON) +void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + static const struct // Define which directions the wire can receive power from + { + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 1, 1, 0}, // From here to end, check for wire placed on sides of blocks + {-1, 1, 0}, + { 0, 1, 1}, + { 0, 1, -1}, + { 1,-1, 0}, + {-1,-1, 0}, + { 0,-1, 1}, + { 0,-1, -1}, + } ; + + // Check to see if directly beside a power source + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power + } + else { - BlockList NewSources = RemoveCurrent(a_BlockPos); - Sources.insert(Sources.end(), NewSources.begin(), NewSources.end()); - while (!Sources.empty()) + NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + int TimesMetaSmaller = 0, TimesFoundAWire = 0; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power { - Vector3i SourcePos = Sources.back(); - Sources.pop_back(); + BLOCKTYPE SurroundType; + NIBBLETYPE SurroundMeta; + m_World.GetBlockTypeMeta(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, SurroundType, SurroundMeta); - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(SourcePos.x, SourcePos.y, SourcePos.z, BlockType, BlockMeta); - switch (BlockType) + if (SurroundType == E_BLOCK_REDSTONE_WIRE) { - case E_BLOCK_LEVER: // Treating lever as a torch - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: + TimesFoundAWire++; + + if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking { - static Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, 0,-1), - Vector3i(0, 0, 1), - }; - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + if (SurroundMeta > MyMeta) // Does surrounding wire have a higher power level than self? { - Vector3i OtherPos = SourcePos + Surroundings[i]; - if (PowerBlock(OtherPos, a_BlockPos, 0xf)) - { - SpreadStack.push_back(OtherPos); // Changed, so add to stack - } + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, SurroundMeta - 1); } - break; } - - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: + + if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's { - static Vector3i Surroundings [] = { - Vector3i(0, 0, 0), - Vector3i(0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection(BlockMeta); - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) - { - Vector3i pos = SourcePos + Direction + Surroundings[i]; - if (PowerBlock(pos, a_BlockPos, 0xf)) - { - SpreadStack.push_back(pos); - } - } - break; + TimesMetaSmaller++; } - } // switch (BlockType) - } // while (Sources[]) - } // if (!repeater_on) - - // Do a floodfill - while (!SpreadStack.empty()) - { - Vector3i pos = SpreadStack.back(); - SpreadStack.pop_back(); - NIBBLETYPE Meta = m_World.GetBlockMeta(pos); + } + } - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + if (TimesMetaSmaller == TimesFoundAWire) { - Vector3i OtherPos = pos + Surroundings[i]; - if (PowerBlock(OtherPos, pos, Meta - 1)) - { - SpreadStack.push_back(OtherPos); // Changed, so add to stack - } - } + // All surrounding metas were smaller - self must have been a wire that was + // transferring power to other wires around. + // However, self not directly powered anymore, so source must have been removed, + // therefore, self must be set to meta zero + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0); + } } - // Only after a redstone area has been completely simulated the redstone entities can react - while (!m_RefreshPistons.empty()) + if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0) // A powered wire { - Vector3i pos = m_RefreshPistons.back(); - m_RefreshPistons.pop_back(); + //SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); // No matter what, block underneath gets powered - BLOCKTYPE BlockType = m_World.GetBlock(pos); - switch (BlockType) + switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ)) { - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: + case REDSTONE_NONE: + { + static const struct // Define which directions the redstone wire can power + { + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, // Power block in front + { 2, 0, 0}, // Power block in front of that (strongly power) + {-1, 0, 0}, + {-2, 0, 0}, + { 0, 0, 1}, + { 0, 0, 2}, + { 0, 0, -1}, + { 0, 0, -2}, + { 0, 1, 0}, + { 0, 2, 0}, + { 0,-1, 0}, + { 0,-2, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power if block is solid, CURRENTLY all mechanisms are solid + if (g_BlockIsSolid[m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z)]) + { + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + } + } + break; + } + case REDSTONE_X_POS: { - if (IsPowered(pos)) + if (m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) != E_BLOCK_REDSTONE_WIRE) { - cPiston Piston(&m_World); - Piston.ExtendPiston(pos.x, pos.y, pos.z); + SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); } - else + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE); + break; + } + case REDSTONE_X_NEG: + { + if (m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) != E_BLOCK_REDSTONE_WIRE) { - cPiston Piston(&m_World); - Piston.RetractPiston(pos.x, pos.y, pos.z); + SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); } + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE); break; } - } // switch (BlockType) - } // while (m_RefreshPistons[]) - - while (!m_RefreshDropSpensers.empty()) - { - Vector3i pos = m_RefreshDropSpensers.back(); - m_RefreshDropSpensers.pop_back(); - - BLOCKTYPE BlockType = m_World.GetBlock(pos); - if ((BlockType == E_BLOCK_DISPENSER) || (BlockType == E_BLOCK_DROPPER)) - { - class cSetPowerToDropSpenser : - public cDropSpenserCallback + case REDSTONE_Z_POS: { - bool m_IsPowered; - public: - cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - - virtual bool Item(cDropSpenserEntity * a_DropSpenser) override + if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) != E_BLOCK_REDSTONE_WIRE) { - a_DropSpenser->SetRedstonePower(m_IsPowered); - return false; + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); } - } DrSpSP(IsPowered(pos)); - m_World.DoWithDropSpenserAt(pos.x, pos.y, pos.z, DrSpSP); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE); + break; + } + case REDSTONE_Z_NEG: + { + if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1) != E_BLOCK_REDSTONE_WIRE) + { + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + } + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE); + break; + } } } + return; } -bool cRedstoneSimulator::PowerBlock(const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power) +void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - switch (BlockType) + NIBBLETYPE a_Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (a_MyState == E_BLOCK_REDSTONE_REPEATER_OFF) { - case E_BLOCK_REDSTONE_WIRE: + if (IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3)) { - if (BlockMeta < a_Power) + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); + switch (a_Meta & 0x3) // We only want the direction (bottom) bits { - m_World.SetBlockMeta(a_BlockPos, a_Power); - return true; + case 0x0: + { + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_REPEATER_ON); + break; + } + case 0x1: + { + SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_REPEATER_ON); + break; + } + case 0x2: + { + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_REPEATER_ON); + break; + } + case 0x3: + { + SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_REPEATER_ON); + break; + } } - break; } - - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: + } + else + { + if (!IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3)) { - m_RefreshPistons.push_back(a_BlockPos); - break; + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); } + } + return; +} - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - { - m_RefreshDropSpensers.push_back(a_BlockPos); - break; - } - - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - { - if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) - { - SetRepeater(a_BlockPos, 10, true); - } - break; - } - - case E_BLOCK_REDSTONE_LAMP_OFF: - { - m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_ON, 0); - break; - } - case E_BLOCK_TNT: - { - m_World.BroadcastSoundEffect("random.fuse", a_BlockPos.x * 8, a_BlockPos.y * 8, a_BlockPos.z * 8, 0.5f, 0.6f); - m_World.SpawnPrimedTNT(a_BlockPos.x + 0.5, a_BlockPos.y + 0.5, a_BlockPos.z + 0.5, 4); // 4 seconds to boom - m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_AIR, 0); - break; - } - default: - { - if ( - (BlockType != E_BLOCK_AIR) && - (BlockType != E_BLOCK_REDSTONE_TORCH_ON) && - (BlockType != E_BLOCK_REDSTONE_TORCH_OFF) && - (BlockType != E_BLOCK_LEVER) // Treating lever as a torch, for refreshing - ) - { - if (IsPowered(a_BlockPos, true)) - { - m_RefreshTorchesAround.push_back(a_BlockPos); - } - } - break; - } - } // switch (BlockType) - return false; + +void cRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + { + cPiston Piston(&m_World); + Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ); + } + else + { + cPiston Piston(&m_World); + Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ); + } + return; } -int cRedstoneSimulator::UnPowerBlock(const Vector3i & a_BlockPos, const Vector3i & a_FromBlock) +void cRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ) { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if ((a_BlockPos.y < 0) || (a_BlockPos.y >= cChunkDef::Height)) - { - return 0; - } - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - switch (BlockType) + class cSetPowerToDropSpenser : + public cDropSpenserCallback { - case E_BLOCK_REDSTONE_WIRE: - { - if (BlockMeta > 0) - { - m_World.SetBlockMeta(a_BlockPos, 0); - return 1; - } - break; - } - - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: + bool m_IsPowered; + public: + cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} + + virtual bool Item(cDropSpenserEntity * a_DropSpenser) override { - m_RefreshPistons.push_back(a_BlockPos); - break; + a_DropSpenser->SetRedstonePower(m_IsPowered); + return false; } + } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + + m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP); + return; +} - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - { - m_RefreshDropSpensers.push_back(a_BlockPos); - break; - } - - case E_BLOCK_REDSTONE_TORCH_ON: - { - return 2; - break; - } - - case E_BLOCK_LEVER: - { - // Check if lever is ON. If it is, report it back as a source - if (cRedstoneSimulator::IsLeverOn(BlockMeta)) - { - return 2; - } - break; - } - - case E_BLOCK_REDSTONE_REPEATER_ON: - { - if ( - IsRepeaterPointingTo(a_BlockPos, BlockMeta, a_FromBlock) || // Repeater is next to wire - IsRepeaterPointingTo(a_BlockPos, BlockMeta, a_FromBlock - Vector3i(0, 1, 0)) // Repeater is below wire - ) - { - return 2; - } - else if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) - { - SetRepeater(a_BlockPos, 10, false); - } - // fall-through: - } - - case E_BLOCK_REDSTONE_REPEATER_OFF: - { - if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) - { - SetRepeater(a_BlockPos, 10, false); - } - break; - } - case E_BLOCK_REDSTONE_LAMP_ON: + + + +void cRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +{ + if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF) + { + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_OFF, 0); - break; + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); } - - default: + } + else + { + if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - if ( - (BlockType != E_BLOCK_AIR) && - (BlockType != E_BLOCK_REDSTONE_TORCH_ON) && - (BlockType != E_BLOCK_REDSTONE_TORCH_OFF) && - (BlockType != E_BLOCK_LEVER) - ) - { - if (!IsPowered(a_BlockPos, true)) - { - m_RefreshTorchesAround.push_back(a_BlockPos); - } - } - break; + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); } - } // switch (BlockType) - - return 0; + } + return; } -// Removes current from all powered redstone wires until it reaches an energy source. -// Also returns all energy sources it encountered -cRedstoneSimulator::BlockList cRedstoneSimulator::RemoveCurrent(const Vector3i & a_BlockPos) +void cRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ) { + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + { + m_World.BroadcastSoundEffect("random.fuse", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); + m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + } + return; +} + + + - std::deque< Vector3i > SpreadStack; - std::deque< Vector3i > FoundSources; - - Vector3i Surroundings[] = { - Vector3i(1, 0, 0), - Vector3i(1, 1, 0), - Vector3i(1,-1, 0), - Vector3i(-1, 0, 0), - Vector3i(-1, 1, 0), - Vector3i(-1,-1, 0), - Vector3i(0, 0, 1), - Vector3i(0, 1, 1), - Vector3i(0,-1, 1), - Vector3i(0, 0,-1), - Vector3i(0, 1,-1), - Vector3i(0,-1,-1), - Vector3i(0,-1, 0), - }; - - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - switch (BlockType) +void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08) { - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: + // Block position is located at top half of door + // Is Y - 1 both within world boundaries, a door block, and the bottom half of a door? + // The bottom half stores the open/closed information + if ( + (a_BlockY - 1 >= 0) && + ((m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_DOOR) || (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_IRON_DOOR)) && + (m_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ & 0x08) == 0) + ) { - // Repeaters only spread to their front front and 0 or 1 block up - static Vector3i Surroundings [] = { - Vector3i(0, 0, 0), - Vector3i(0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection(BlockMeta); - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + if ((m_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ) & 0x04) == 0) // Closed door? { - Vector3i pos = a_BlockPos + Direction + Surroundings[i]; - int RetVal = UnPowerBlock(pos, a_BlockPos); - if (RetVal == 1) - { - // Changed, so add to stack - SpreadStack.push_back(pos); - } - else if (RetVal == 2) + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Powered? If so, toggle open { - FoundSources.push_back(pos); + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); } } - break; - } - - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_LEVER: - { - static Vector3i Surroundings [] = { // Torches only spread on the same level - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, 0,-1), - Vector3i(0, 0, 1), - }; - - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + else // Opened door { - Vector3i pos = Vector3i(a_BlockPos) + Surroundings[i]; - int RetVal = UnPowerBlock(pos, a_BlockPos); - if (RetVal == 1) - { - SpreadStack.push_back(pos); // Changed, so add to stack - } - else if (RetVal == 2) + if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Unpowered? Close if so { - FoundSources.push_back(pos); + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); } } - break; - } - - default: - { - SpreadStack.push_back(a_BlockPos); - break; } - } // switch (BlockType) - - - while (!SpreadStack.empty()) + } + else { - Vector3i pos = SpreadStack.back(); - SpreadStack.pop_back(); - - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x04) == 0) // Closed door? { - Vector3i OtherPos = pos + Surroundings[i]; - int RetVal = UnPowerBlock(OtherPos, pos); - if (RetVal == 1) + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Powered? If so, toggle open { - SpreadStack.push_back(OtherPos); // Changed, so add to stack + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); } - else if (RetVal == 2) + } + else // Opened door + { + if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Unpowered? Close if so { - FoundSources.push_back(OtherPos); + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); } } } - - return FoundSources; + return; } -bool cRedstoneSimulator::IsPowering(const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire) +void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) { - BLOCKTYPE PowerBlock; - NIBBLETYPE PowerMeta; - m_World.GetBlockTypeMeta(a_PowerPos.x, a_PowerPos.y, a_PowerPos.z, PowerBlock, PowerMeta); - - // Filter out powering blocks for a_bOnlyByWire - if ( - !a_bOnlyByWire && ( - (PowerBlock == E_BLOCK_REDSTONE_TORCH_ON) || - (PowerBlock == E_BLOCK_LEVER) - ) - ) + switch (a_MyType) { - return true; - } - - switch (PowerBlock) - { - case E_BLOCK_REDSTONE_REPEATER_ON: - { - // A repeater pointing towards block is regarded as wire - if (IsRepeaterPointingTo(a_PowerPos, PowerMeta, a_BlockPos)) - { - return true; - } - break; - } - - case E_BLOCK_REDSTONE_WIRE: + case E_BLOCK_DETECTOR_RAIL: { - if (PowerMeta > 0) + if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08) { - if (GetWireDirection(a_PowerPos) == a_WireDirection) + static const struct // Define which directions the rail can power (all sides) { - return true; + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + { 0,-1, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power everything + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_MyType); } } break; } - } // switch (PowerBlock) - - return false; -} - - - - - -bool cRedstoneSimulator::IsPowered(const Vector3i & a_BlockPos, bool a_bOnlyByWire /* = false */) -{ - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - if ((BlockType == E_BLOCK_REDSTONE_REPEATER_OFF) || (BlockType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - Vector3i Behind = a_BlockPos - GetRepeaterDirection(BlockMeta); - BLOCKTYPE BehindBlock; - NIBBLETYPE BehindMeta; - m_World.GetBlockTypeMeta(Behind.x, Behind.y, Behind.z, BehindBlock, BehindMeta); - switch (BehindBlock) + case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_POWERED_RAIL: { - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_LEVER: - { - // _X: TODO: Shouldn't a lever be checked if it is switched on? - return true; - } - case E_BLOCK_REDSTONE_WIRE: + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - return (BehindMeta > 0); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x08); } - case E_BLOCK_REDSTONE_REPEATER_ON: + else { - return IsRepeaterPointingTo(Behind, BehindMeta, a_BlockPos); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07); } - } // switch (BehindBlock) - return false; - } - - if (IsPowering(Vector3i(a_BlockPos.x - 1, a_BlockPos.y, a_BlockPos.z), a_BlockPos, REDSTONE_X_POS, a_bOnlyByWire)) - { - return true; - } - if (IsPowering(Vector3i(a_BlockPos.x + 1, a_BlockPos.y, a_BlockPos.z), a_BlockPos, REDSTONE_X_NEG, a_bOnlyByWire)) - { - return true; - } - if (IsPowering(Vector3i(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z - 1), a_BlockPos, REDSTONE_Z_POS, a_bOnlyByWire)) - { - return true; - } - if (IsPowering(Vector3i(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z + 1), a_BlockPos, REDSTONE_Z_NEG, a_bOnlyByWire)) - { - return true; - } - - // Only wires can power the bottom block - BLOCKTYPE PosYType; - NIBBLETYPE PosYMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y + 1, a_BlockPos.z, PosYType, PosYMeta); - if (PosYType == E_BLOCK_REDSTONE_WIRE) - { - return (PosYMeta > 0); + break; + } } - - return false; } -// Believe me, it works!! TODO: Add repeaters and low/high wires -cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - int Dir = REDSTONE_NONE; - BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); - if ( - (NegX == E_BLOCK_REDSTONE_WIRE) || - (NegX == E_BLOCK_REDSTONE_TORCH_ON) || - (NegX == E_BLOCK_LEVER) - ) - { - Dir |= (REDSTONE_X_POS); - } - - BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); - if ( - (PosX == E_BLOCK_REDSTONE_WIRE) || - (PosX == E_BLOCK_REDSTONE_TORCH_ON) || - (PosX == E_BLOCK_LEVER) - ) - { - Dir |= (REDSTONE_X_NEG); - } - - BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); - if ( - (NegZ == E_BLOCK_REDSTONE_WIRE) || - (NegZ == E_BLOCK_REDSTONE_TORCH_ON) || - (NegZ == E_BLOCK_LEVER) - ) +bool cRedstoneSimulator::AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + sPoweredBlocks & Change = *itr; + + if (Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; + return true; } - Dir |= REDSTONE_Z_POS; } - - BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); - if ( - (PosZ == E_BLOCK_REDSTONE_WIRE) || - (PosZ == E_BLOCK_REDSTONE_TORCH_ON) || - (PosZ == E_BLOCK_LEVER) - ) + + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + sLinkedPoweredBlocks & Change = *itr; + + if (Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; + return true; } - Dir |= REDSTONE_Z_NEG; } - - return (eRedstoneDirection)Dir; + return false; } -bool cRedstoneSimulator::IsRepeaterPointingTo(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos) +bool cRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) { - switch (a_MetaData & 0x3) + // Check through powered blocks list + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) { - case 0x0: + sPoweredBlocks & Change = *itr; + + switch (a_Meta) { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0, 1))) + case 0x0: { - return true; + // Flip the coords to check the back of the repeater + if (Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + break; } - break; - } - - case 0x1: - { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(-1, 0, 0))) + case 0x1: { - return true; + if (Change.a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + break; } - break; - } - - case 0x2: - { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0,-1))) + case 0x2: + { + if (Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + break; + } + case 0x3: { - return true; + if (Change.a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + break; } - break; } - - case 0x3: + } + + // Check linked powered list, 'middle' blocks + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + { + sLinkedPoweredBlocks & Change = *itr; + + switch (a_Meta) { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(1, 0, 0))) + case 0x0: { - return true; + if (Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + break; + } + case 0x1: + { + if (Change.a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + break; + } + case 0x2: + { + if (Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + break; + } + case 0x3: + { + if (Change.a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + break; } - break; } } - return false; + return false; // Couldn't find power source behind repeater } -bool cRedstoneSimulator::IsRepeaterPointingAway(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos) +void cRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType) { - switch (a_MetaData & 0x3) + switch (a_Direction) { - case 0x0: + case BLOCK_FACE_XM: { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0,-1))) - { - return true; - } + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); break; } - - case 0x1: + case BLOCK_FACE_XP: { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(1, 0, 0))) - { - return true; - } + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); break; } - - case 0x2: + case BLOCK_FACE_YM: { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0, 1))) - { - return true; - } + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); break; } - - case 0x3: + case BLOCK_FACE_YP: { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(-1, 0, 0))) - { - return true; - } + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + break; + } + case BLOCK_FACE_ZM: + { + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + break; + } + case BLOCK_FACE_ZP: + { + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + break; + } + default: + { + ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); break; } } - return false; + return; } -NIBBLETYPE cRedstoneSimulator::RepeaterRotationToMetaData(double a_Rotation) +void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock) { - a_Rotation += 90 + 45; // So its not aligned with axis - if (a_Rotation > 360) - { - a_Rotation -= 360; - } - - if ((a_Rotation >= 0) && (a_Rotation < 90)) - { - return 0x1; - } - else if ((a_Rotation >= 180) && (a_Rotation < 270)) - { - return 0x3; - } - else if ((a_Rotation >= 90) && (a_Rotation < 180)) - { - return 0x2; - } - else - { - return 0x0; - } + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { return; } // Check for duplicates + + sPoweredBlocks RC; + RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_SourceBlock = a_SourceBlock; + m_PoweredBlocks.push_back(RC); + return; } -Vector3i cRedstoneSimulator::GetRepeaterDirection(NIBBLETYPE a_MetaData) +void cRedstoneSimulator::SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, + int a_MiddleX, int a_MiddleY, int a_MiddleZ, + int a_SourceX, int a_SourceY, int a_SourceZ, + BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock + ) { - switch (a_MetaData & 0x3) - { - case 0x0: return Vector3i(0, 0,-1); - case 0x1: return Vector3i(1, 0, 0); - case 0x2: return Vector3i(0, 0, 1); - case 0x3: return Vector3i(-1, 0, 0); - } - return Vector3i(); + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { return; } // Check for duplicates + + sLinkedPoweredBlocks RC; + RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ); + RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_SourceBlock = a_SourceBlock; + RC.a_MiddleBlock = a_MiddleBlock; + m_LinkedPoweredBlocks.push_back(RC); + return; } -NIBBLETYPE cRedstoneSimulator::LeverDirectionToMetaData(char a_Dir) +cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ) { - // Determine lever direction: - switch (a_Dir) + int Dir = REDSTONE_NONE; + + BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); + if (IsPotentialSource(NegX)) { - case BLOCK_FACE_TOP: return 0x6; - case BLOCK_FACE_EAST: return 0x1; - case BLOCK_FACE_WEST: return 0x2; - case BLOCK_FACE_SOUTH: return 0x3; - case BLOCK_FACE_NORTH: return 0x4; - case BLOCK_FACE_BOTTOM: return 0x0; - default: return 0x6; + Dir |= (REDSTONE_X_POS); } -} - - - - - -bool cRedstoneSimulator::IsLeverOn(cWorld * a_World, const Vector3i & a_BlockPos) -{ - // Extract the metadata and ask the lower level: - return IsLeverOn(a_World->GetBlockMeta(a_BlockPos)); + + BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); + if (IsPotentialSource(PosX)) + { + Dir |= (REDSTONE_X_NEG); + } + + BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); + if (IsPotentialSource(NegZ)) + { + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_POS; + } + + BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); + if (IsPotentialSource(PosZ)) + { + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_NEG; + } + return (eRedstoneDirection)Dir; } @@ -1145,32 +1063,9 @@ bool cRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta) -void cRedstoneSimulator::SetRepeater(const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn) +bool cRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta) { - for (RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end(); ++itr) - { - sRepeaterChange & Change = *itr; - if (Change.Position.Equals(a_Position)) - { - if (Change.bPowerOn && !a_bPowerOn) - { - Change.bPowerOffNextTime = true; - } - if (a_bPowerOn) - { - Change.bPowerOffNextTime = false; - } - Change.bPowerOn |= a_bPowerOn; - return; - } - } - - sRepeaterChange RC; - RC.Position = a_Position; - RC.Ticks = a_Ticks; - RC.bPowerOn = a_bPowerOn; - RC.bPowerOffNextTime = false; - m_SetRepeaters.push_back(RC); + return IsLeverOn(a_BlockMeta); } diff --git a/source/Simulator/RedstoneSimulator.h b/source/Simulator/RedstoneSimulator.h index c0d5795c7..d68c6daeb 100644 --- a/source/Simulator/RedstoneSimulator.h +++ b/source/Simulator/RedstoneSimulator.h @@ -3,6 +3,9 @@ #include "Simulator.h" +/// Per-chunk data for the simulator, specified individual chunks to simulate; 'Data' is not used +typedef cCoordWithIntList cRedstoneSimulatorChunkData; + @@ -12,13 +15,13 @@ class cRedstoneSimulator : { typedef cSimulator super; public: + cRedstoneSimulator(cWorld & a_World); ~cRedstoneSimulator(); - virtual void Simulate( float a_Dt ) override; - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return true; } - - virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void Simulate(float a_Dt) override {}; // Not used in this simulator + virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; + virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return IsRedstone(a_BlockType); } enum eRedstoneDirection { @@ -31,56 +34,166 @@ public: eRedstoneDirection GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ); eRedstoneDirection GetWireDirection(const Vector3i & a_Pos) { return GetWireDirection(a_Pos.x, a_Pos.y, a_Pos.z); } - static bool IsRepeaterPointingTo (const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos); - static bool IsRepeaterPointingAway(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos); - static NIBBLETYPE RepeaterRotationToMetaData(double a_Rotation); - static Vector3i GetRepeaterDirection(NIBBLETYPE a_MetaData); - static NIBBLETYPE LeverDirectionToMetaData(char a_Dir); - static bool IsLeverOn(cWorld * a_World, const Vector3i & a_BlockPos); - static bool IsLeverOn(NIBBLETYPE a_BlockMeta); - - private: - struct sRepeaterChange + + struct sPoweredBlocks // Define structure of the directly powered blocks list { - Vector3i Position; - int Ticks; - bool bPowerOn; - bool bPowerOffNextTime; + Vector3i a_BlockPos; // Position of powered block + Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos + BLOCKTYPE a_SourceBlock; // The source block type (for pistons pushing away sources and replacing with non source etc.) }; - typedef std::deque BlockList; - - typedef std::deque< sRepeaterChange > RepeaterList; - RepeaterList m_SetRepeaters; - - void SetRepeater(const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn); - - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override {} - - void HandleChange( const Vector3i & a_BlockPos ); - BlockList RemoveCurrent( const Vector3i & a_BlockPos ); - - bool PowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power ); - int UnPowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock ); - - bool IsPowered( const Vector3i & a_BlockPos, bool a_bOnlyByWire = false ); - bool IsPowering( const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire ); - - BlockList m_Blocks; - BlockList m_BlocksBuffer; - - BlockList m_RefreshPistons; - BlockList m_RefreshDropSpensers; - - BlockList m_RefreshTorchesAround; + struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side) + { + Vector3i a_BlockPos; + Vector3i a_MiddlePos; + Vector3i a_SourcePos; + BLOCKTYPE a_SourceBlock; + BLOCKTYPE a_MiddleBlock; + }; - void RefreshTorchesAround( const Vector3i & a_BlockPos ); - - // TODO: The entire simulator is synchronized, no need to lock data structures; remove this - cCriticalSection m_CS; -}; - - - - + typedef std::vector PoweredBlocksList; + typedef std::vector LinkedBlocksList; + + PoweredBlocksList m_PoweredBlocks; + LinkedBlocksList m_LinkedPoweredBlocks; + + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + + // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly + // In addition to being non-performant, it would stop the player from actually breaking said device + + /* ====== SOURCES ====== */ + ///

Handles the redstone torch + void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + ///Handles the redstone block + void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + ///Handles levers + void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ); + ///Handles buttons + void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); + /* ==================== */ + + /* ====== CARRIERS ====== */ + ///Handles redstone wire + void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ); + ///Handles repeaters + void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + /* ====================== */ + + /* ====== DEVICES ====== */ + ///Handles pistons + void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ); + ///Handles dispensers and droppers + void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ); + ///Handles TNT (exploding) + void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ); + ///Handles redstone lamps + void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + ///Handles doords + void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ); + ///Handles activator, detector, and powered rails + void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); + /* ===================== */ + + /* ====== Helper functions ====== */ + void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock); + void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock); + void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType); + + bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ); + bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); + + bool IsLeverOn(NIBBLETYPE a_BlockMeta); + bool IsButtonOn(NIBBLETYPE a_BlockMeta); + /* ============================== */ + + inline static bool IsMechanism(BLOCKTYPE Block) + { + switch (Block) + { + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: + case E_BLOCK_TNT: + case E_BLOCK_REDSTONE_LAMP_OFF: + case E_BLOCK_REDSTONE_LAMP_ON: + case E_BLOCK_WOODEN_DOOR: + case E_BLOCK_IRON_DOOR: + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_POWERED_RAIL: + { + return true; + } + default: return false; + } + } + + inline static bool IsPotentialSource(BLOCKTYPE Block) + { + switch (Block) + { + case E_BLOCK_WOODEN_BUTTON: + case E_BLOCK_STONE_BUTTON: + case E_BLOCK_REDSTONE_WIRE: + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_LEVER: + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_ACTIVE_COMPARATOR: + case E_BLOCK_INACTIVE_COMPARATOR: + { + return true; + } + default: return false; + } + } + + inline static bool IsRedstone(BLOCKTYPE Block) + { + switch (Block) + { + // All redstone devices, please alpha sort + case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_ACTIVE_COMPARATOR: + case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_DETECTOR_RAIL: + case E_BLOCK_DISPENSER: + case E_BLOCK_DAYLIGHT_SENSOR: + case E_BLOCK_DROPPER: + case E_BLOCK_FENCE_GATE: + case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: + case E_BLOCK_HOPPER: + case E_BLOCK_INACTIVE_COMPARATOR: + case E_BLOCK_IRON_DOOR: + case E_BLOCK_LEVER: + case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: + case E_BLOCK_NOTE_BLOCK: + case E_BLOCK_REDSTONE_LAMP_OFF: + case E_BLOCK_REDSTONE_LAMP_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_WIRE: + case E_BLOCK_STICKY_PISTON: + case E_BLOCK_STONE_BUTTON: + case E_BLOCK_STONE_PRESSURE_PLATE: + case E_BLOCK_TNT: + case E_BLOCK_TRAPDOOR: + case E_BLOCK_TRIPWIRE_HOOK: + case E_BLOCK_WOODEN_BUTTON: + case E_BLOCK_WOODEN_DOOR: + case E_BLOCK_WOODEN_PRESSURE_PLATE: + case E_BLOCK_PISTON: + { + return true; + } + default: return false; + } + } +}; \ No newline at end of file -- cgit v1.2.3 From 4844422e06da2c2982d96e2f0df2824f5c732845 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 19 Nov 2013 06:49:21 +0100 Subject: APIDump: Documented Vector3i. --- MCServer/Plugins/APIDump/APIDesc.lua | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 210ddc1ae..450bc9f28 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2666,7 +2666,10 @@ end Vector3d = { Desc = [[ - A Vector3d object uses double precision floating point values to describe a point in 3D space. + A Vector3d object uses double precision floating point values to describe a point in 3D space.

+

+ See also {{Vector3f}} for single-precision floating point 3D coords and {{Vector3i}} for integer + 3D coords. ]], Functions = { @@ -2711,7 +2714,7 @@ end A Vector3f object uses floating point values to describe a point in space.

See also {{Vector3d}} for double-precision floating point 3D coords and {{Vector3i}} for integer - point 3D coords. + 3D coords. ]], Functions = { @@ -2749,13 +2752,30 @@ end Vector3i = { - Desc = [[A Vector3i object uses integer values to describe a point in space. Vector3i is part of the {{vector3|vector3}} family. -]], + Desc = [[ + A Vector3i object uses integer values to describe a point in space.

+

+ See also {{Vector3d}} for double-precision floating point 3D coords and {{Vector3f}} for + single-precision floating point 3D coords. + ]], Functions = { + constructor = + { + { Params = "", Return = "Vector3i", Notes = "Creates a new Vector3i object with zero coords." }, + { Params = "x, y, z", Return = "Vector3i", Notes = "Creates a new Vector3i object with the specified coords." }, + { Params = "{{Vector3d}}", Return = "Vector3i", Notes = "Creates a new Vector3i object with coords copied and floor()-ed from the specified {{Vector3d}}." }, + }, + Equals = { Params = "Vector3i", Return = "bool", Notes = "Returns true if this vector is exactly the same as the specified vector." }, + Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector." }, + Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once" }, + SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." }, }, - Constants = + Variables = { + x = { Type = "number", Notes = "The X coord of the vector." }, + y = { Type = "number", Notes = "The Y coord of the vector." }, + z = { Type = "number", Notes = "The Z coord of the vector." }, }, }, -- Vector3i -- cgit v1.2.3 From f06d686f63ea564ea4a6ad9eadacf575d1e2c336 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 19 Nov 2013 07:49:02 +0000 Subject: Possible compile fix Also removed unneeded variables. --- source/Blocks/BlockTorch.h | 2 -- source/Simulator/RedstoneSimulator.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/source/Blocks/BlockTorch.h b/source/Blocks/BlockTorch.h index 36383a524..72a313126 100644 --- a/source/Blocks/BlockTorch.h +++ b/source/Blocks/BlockTorch.h @@ -169,8 +169,6 @@ public: virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { char Face = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true); BLOCKTYPE BlockInQuestion; diff --git a/source/Simulator/RedstoneSimulator.cpp b/source/Simulator/RedstoneSimulator.cpp index 29f59fa53..906961490 100644 --- a/source/Simulator/RedstoneSimulator.cpp +++ b/source/Simulator/RedstoneSimulator.cpp @@ -76,7 +76,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; - for (cRedstoneSimulatorChunkData::const_iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) + for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) { BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z); if (!IsAllowedBlock(BlockType)) -- cgit v1.2.3 From e2ea6b59f52d4b513b5537c33dae543f67c729a8 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 19 Nov 2013 09:56:36 +0100 Subject: APIDump: Slight performance improvement. Strings don't need concatenation when using write(). --- MCServer/Plugins/APIDump/main.lua | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/MCServer/Plugins/APIDump/main.lua b/MCServer/Plugins/APIDump/main.lua index ab154dc45..fa9d29423 100644 --- a/MCServer/Plugins/APIDump/main.lua +++ b/MCServer/Plugins/APIDump/main.lua @@ -740,14 +740,14 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) end if (a_InheritedName ~= nil) then - cf:write("

Functions inherited from " .. a_InheritedName .. "

\n"); + cf:write("

Functions inherited from ", a_InheritedName, "

\n"); end cf:write(" \n \n \n \n \n \n \n"); for i, func in ipairs(a_Functions) do cf:write(" \n \n"); - cf:write(" \n"); - cf:write(" \n"); - cf:write(" \n \n"); + cf:write(" \n"); + cf:write(" \n"); + cf:write(" \n \n"); end cf:write("
NameParametersReturn valueNotes
" .. func.Name .. "" .. LinkifyString(func.Params or "", (a_InheritedName or a_ClassAPI.Name)).. "" .. LinkifyString(func.Return or "", (a_InheritedName or a_ClassAPI.Name)).. "" .. LinkifyString(func.Notes or "(undocumented)", (a_InheritedName or a_ClassAPI.Name)) .. "
", LinkifyString(func.Params or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Return or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Notes or "(undocumented)", (a_InheritedName or a_ClassAPI.Name)), "
\n\n"); end @@ -758,14 +758,14 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) end if (a_InheritedName ~= nil) then - cf:write("

Constants inherited from " .. a_InheritedName .. "

\n"); + cf:write("

Constants inherited from ", a_InheritedName, "

\n"); end cf:write(" \n \n \n \n \n \n"); for i, cons in ipairs(a_Constants) do - cf:write(" \n \n"); - cf:write(" \n"); - cf:write(" \n \n"); + cf:write(" \n \n"); + cf:write(" \n"); + cf:write(" \n \n"); end cf:write("
NameValueNotes
" .. cons.Name .. "" .. cons.Value .. "" .. LinkifyString(cons.Notes or "", a_InheritedName or a_ClassAPI.Name) .. "
", cons.Name, "", cons.Value, "", LinkifyString(cons.Notes or "", a_InheritedName or a_ClassAPI.Name), "
\n\n"); end @@ -776,14 +776,14 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) end if (a_InheritedName ~= nil) then - cf:write("

Member variables inherited from " .. a_InheritedName .. "

\n"); + cf:write("

Member variables inherited from ", a_InheritedName, "

\n"); end cf:write(" \n \n \n \n \n \n"); for i, var in ipairs(a_Variables) do - cf:write(" \n \n"); - cf:write(" \n"); - cf:write(" \n \n"); + cf:write(" \n \n"); + cf:write(" \n"); + cf:write(" \n \n"); end cf:write("
NameTypeNotes
" .. var.Name .. "" .. LinkifyString(var.Type or "(undocumented)", a_InheritedName or a_ClassAPI.Name) .. "" .. LinkifyString(var.Notes or "", a_InheritedName or a_ClassAPI.Name) .. "
", var.Name, "", LinkifyString(var.Type or "(undocumented)", a_InheritedName or a_ClassAPI.Name), "", LinkifyString(var.Notes or "", a_InheritedName or a_ClassAPI.Name), "
\n\n"); end @@ -794,7 +794,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) end cf:write("
    "); for i, desc in ipairs(a_Descendants) do - cf:write("
  • " .. desc.Name .. ""); + cf:write("
  • ", desc.Name, ""); WriteDescendants(desc.Descendants); cf:write("
  • \n"); end @@ -814,7 +814,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) cf:write([[ - MCServer API - ]] .. a_ClassAPI.Name .. [[ Class + MCServer API - ]], a_ClassAPI.Name, [[ Class @@ -823,7 +823,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI)
    -

    ]] .. a_ClassAPI.Name .. [[

    +

    ]], a_ClassAPI.Name, [[


    Contents

    @@ -857,7 +857,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) end if (a_ClassAPI.AdditionalInfo ~= nil) then for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do - cf:write("
  • " .. (additional.Header or "(No header)").. "
  • \n"); + cf:write("
  • ", (additional.Header or "(No header)"), "
  • \n"); end end cf:write("
\n\n"); @@ -920,7 +920,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) -- Write the additional infos: if (a_ClassAPI.AdditionalInfo ~= nil) then for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do - cf:write("

" .. additional.Header .. "

\n"); + cf:write("

", additional.Header, "

\n"); cf:write(LinkifyString(additional.Contents, ClassName)); end end -- cgit v1.2.3 From 78f45e0bd1576a38b05b8d1083df9494a41ed644 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 19 Nov 2013 20:40:07 +0000 Subject: Fixed piston sound effect (when unable to extend) --- source/Piston.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/Piston.cpp b/source/Piston.cpp index ed175d3e3..048cc355d 100644 --- a/source/Piston.cpp +++ b/source/Piston.cpp @@ -71,9 +71,6 @@ void cPiston::ExtendPiston(int pistx, int pisty, int pistz) return; } - m_World->BroadcastBlockAction(pistx, pisty, pistz, 0, pistonMeta, pistonBlock); - m_World->BroadcastSoundEffect("tile.piston.out", pistx * 8, pisty * 8, pistz * 8, 0.5f, 0.7f); - int dist = FirstPassthroughBlock(pistx, pisty, pistz, pistonMeta); if (dist < 0) { @@ -81,6 +78,9 @@ void cPiston::ExtendPiston(int pistx, int pisty, int pistz) return; } + m_World->BroadcastBlockAction(pistx, pisty, pistz, 0, pistonMeta, pistonBlock); + m_World->BroadcastSoundEffect("tile.piston.out", pistx * 8, pisty * 8, pistz * 8, 0.5f, 0.7f); + // Drop the breakable block in the line, if appropriate: AddDir(pistx, pisty, pistz, pistonMeta, dist + 1); // "pist" now at the breakable / empty block BLOCKTYPE currBlock; -- cgit v1.2.3 From ba438ccd8a807f8c04b070edb17b2bd14f9ad9ef Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 20 Nov 2013 21:09:01 +0100 Subject: Removed the bloody sdf file. --- VC2013/MCServer.sdf | Bin 61997056 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 VC2013/MCServer.sdf diff --git a/VC2013/MCServer.sdf b/VC2013/MCServer.sdf deleted file mode 100644 index f0501bef6..000000000 Binary files a/VC2013/MCServer.sdf and /dev/null differ -- cgit v1.2.3 From 1797b5b8fe512aa8f8137027c1a155e218e42aad Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 20 Nov 2013 21:11:07 +0100 Subject: Ignoring SDF files. --- VC2013/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/VC2013/.gitignore b/VC2013/.gitignore index d958abab6..9d46443bd 100644 --- a/VC2013/.gitignore +++ b/VC2013/.gitignore @@ -7,3 +7,4 @@ ipch/** *.ncb *.suo *.obj +*.sdf -- cgit v1.2.3 From a5c2d639c612031331a668a483339f3025c7041f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 20 Nov 2013 21:53:29 +0100 Subject: Added cWorld:ForEachBlockEntityInChunk() and cWorld:DoWithBlockEntityAt() functions. Also exported them to the Lua API. --- source/BlockEntities/BlockEntity.h | 5 +++++ source/Chunk.cpp | 44 ++++++++++++++++++++++++++++++++++++++ source/Chunk.h | 6 ++++++ source/ChunkMap.cpp | 33 ++++++++++++++++++++++++++++ source/ChunkMap.h | 11 ++++++++-- source/ManualBindings.cpp | 42 +++++++++++++++++++----------------- source/World.cpp | 18 ++++++++++++++++ source/World.h | 10 +++++++-- 8 files changed, 145 insertions(+), 24 deletions(-) diff --git a/source/BlockEntities/BlockEntity.h b/source/BlockEntities/BlockEntity.h index a2de3160a..0d358b556 100644 --- a/source/BlockEntities/BlockEntity.h +++ b/source/BlockEntities/BlockEntity.h @@ -52,6 +52,11 @@ public: /// Returns NULL for unknown block types static cBlockEntity * CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World = NULL); + static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates + { + return "cBlockEntity"; + } + // tolua_begin // Position, in absolute block coordinates: diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 6e83d32ea..7e71e9ea7 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -1840,6 +1840,24 @@ bool cChunk::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool +bool cChunk::ForEachBlockEntity(cBlockEntityCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (a_Callback.Item(*itr)) + { + return false; + } + } // for itr - m_BlockEntitites[] + return true; +} + + + + + bool cChunk::ForEachChest(cChestCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS @@ -1958,6 +1976,32 @@ bool cChunk::ForEachFurnace(cFurnaceCallback & a_Callback) +bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ)) + { + continue; + } + + if (a_Callback.Item(*itr)) + { + return false; + } + return true; + } // for itr - m_BlockEntitites[] + + // Not found: + return false; +} + + + + + bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/source/Chunk.h b/source/Chunk.h index 0d7479347..895b407a3 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -207,6 +207,9 @@ public: /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible + /// Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true + bool ForEachBlockEntity(cBlockEntityCallback & a_Callback); // Lua-accessible + /// Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true bool ForEachChest(cChestCallback & a_Callback); // Lua-accessible @@ -222,6 +225,9 @@ public: /// Calls the callback for each furnace; returns true if all furnaces processed, false if the callback aborted by returning true bool ForEachFurnace(cFurnaceCallback & a_Callback); // Lua-accessible + /// Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found + bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible + /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index 73a16dbb4..9d55917e5 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -1702,6 +1702,21 @@ bool cChunkMap::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) +bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + if ((Chunk == NULL) && !Chunk->IsValid()) + { + return false; + } + return Chunk->ForEachBlockEntity(a_Callback); +} + + + + + bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback) { cCSLock Lock(m_CSLayers); @@ -1777,6 +1792,24 @@ bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallba +bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) +{ + int ChunkX, ChunkZ; + int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; + cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if ((Chunk == NULL) && !Chunk->IsValid()) + { + return false; + } + return Chunk->DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { int ChunkX, ChunkZ; diff --git a/source/ChunkMap.h b/source/ChunkMap.h index f68cb6472..2a1d78ff8 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -32,6 +32,7 @@ class cMobSpawner; typedef std::list cClientHandleList; typedef cChunk * cChunkPtr; typedef cItemCallback cEntityCallback; +typedef cItemCallback cBlockEntityCallback; typedef cItemCallback cChestCallback; typedef cItemCallback cDispenserCallback; typedef cItemCallback cDropperCallback; @@ -191,8 +192,11 @@ public: /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Lua-accessible + /// Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true + bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Lua-accessible + /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true - bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible + bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); @@ -206,8 +210,11 @@ public: /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Lua-accessible + /// Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found + bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible + /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found - bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible + bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Lua-accessible diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index f98e25880..59bd0657c 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -2128,26 +2128,28 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWorld"); - tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ); - tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ); - tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ); - tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ); - tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); - tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ); - tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); - tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk); - tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); - tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk); - tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk); - tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); - tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); - tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); - tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines); - tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask); - tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); - tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); - tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines); + tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ); + tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ); + tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ); + tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ); + tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ); + tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); + tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ); + tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk); + tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk); + tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); + tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk); + tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk); + tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); + tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); + tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); + tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines); + tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask); + tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); + tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); + tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlugin"); diff --git a/source/World.cpp b/source/World.cpp index 0f9df8a62..531952e37 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -922,6 +922,15 @@ void cWorld::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinB +bool cWorld::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback) +{ + return m_ChunkMap->ForEachBlockEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback); +} + + + + + bool cWorld::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback) { return m_ChunkMap->ForEachChestInChunk(a_ChunkX, a_ChunkZ, a_Callback); @@ -1010,6 +1019,15 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo +bool cWorld::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) +{ + return m_ChunkMap->DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { return m_ChunkMap->DoWithChestAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); diff --git a/source/World.h b/source/World.h index ee4a23b14..d10aa3b78 100644 --- a/source/World.h +++ b/source/World.h @@ -385,8 +385,11 @@ public: inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; } inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; } + /// Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true + bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp + /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true - bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp + bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); @@ -415,8 +418,11 @@ public: */ void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export + /// Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found + bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp + /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found - bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp + bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp -- cgit v1.2.3 From fed37bca4d12579741be97e7994f1d4b8df4bbfd Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 20 Nov 2013 21:54:37 +0100 Subject: Debuggers: Test harness for cWorld:ForEachBlockEntityInChunk(). The fill command will fill all empty slots in block entities with containment with gold nuggets, one per slot. --- MCServer/Plugins/Debuggers/Debuggers.lua | 78 ++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 9350606cc..c4811b91a 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -28,25 +28,26 @@ function Initialize(Plugin) cPluginManager.AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick); cPluginManager.AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated); - PluginManager = cRoot:Get():GetPluginManager(); - PluginManager:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities"); - PluginManager:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities"); - PluginManager:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool"); - PluginManager:BindCommand("/testwnd", "debuggers", HandleTestWndCmd, "- Opens up a window using plugin API"); - PluginManager:BindCommand("/gc", "debuggers", HandleGCCmd, "- Activates the Lua garbage collector"); - PluginManager:BindCommand("/fast", "debuggers", HandleFastCmd, "- Switches between fast and normal movement speed"); - PluginManager:BindCommand("/dash", "debuggers", HandleDashCmd, "- Switches between fast and normal sprinting speed"); - PluginManager:BindCommand("/hunger", "debuggers", HandleHungerCmd, "- Lists the current hunger-related variables"); - PluginManager:BindCommand("/poison", "debuggers", HandlePoisonCmd, "- Sets food-poisoning for 15 seconds"); - PluginManager:BindCommand("/starve", "debuggers", HandleStarveCmd, "- Sets the food level to zero"); - PluginManager:BindCommand("/fl", "debuggers", HandleFoodLevelCmd, "- Sets the food level to the given value"); - PluginManager:BindCommand("/spidey", "debuggers", HandleSpideyCmd, "- Shoots a line of web blocks until it hits non-air"); - PluginManager:BindCommand("/ench", "debuggers", HandleEnchCmd, "- Provides an instant dummy enchantment window"); - PluginManager:BindCommand("/fs", "debuggers", HandleFoodStatsCmd, "- Turns regular foodstats message on or off"); - PluginManager:BindCommand("/arr", "debuggers", HandleArrowCmd, "- Creates an arrow going away from the player"); - PluginManager:BindCommand("/fb", "debuggers", HandleFireballCmd, "- Creates a ghast fireball as if shot by the player"); - PluginManager:BindCommand("/xpa", "debuggers", HandleAddExperience, "- Adds 200 experience to the player"); - PluginManager:BindCommand("/xpr", "debuggers", HandleRemoveXp, "- Remove all xp"); + PM = cRoot:Get():GetPluginManager(); + PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities"); + PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities"); + PM:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool"); + PM:BindCommand("/testwnd", "debuggers", HandleTestWndCmd, "- Opens up a window using plugin API"); + PM:BindCommand("/gc", "debuggers", HandleGCCmd, "- Activates the Lua garbage collector"); + PM:BindCommand("/fast", "debuggers", HandleFastCmd, "- Switches between fast and normal movement speed"); + PM:BindCommand("/dash", "debuggers", HandleDashCmd, "- Switches between fast and normal sprinting speed"); + PM:BindCommand("/hunger", "debuggers", HandleHungerCmd, "- Lists the current hunger-related variables"); + PM:BindCommand("/poison", "debuggers", HandlePoisonCmd, "- Sets food-poisoning for 15 seconds"); + PM:BindCommand("/starve", "debuggers", HandleStarveCmd, "- Sets the food level to zero"); + PM:BindCommand("/fl", "debuggers", HandleFoodLevelCmd, "- Sets the food level to the given value"); + PM:BindCommand("/spidey", "debuggers", HandleSpideyCmd, "- Shoots a line of web blocks until it hits non-air"); + PM:BindCommand("/ench", "debuggers", HandleEnchCmd, "- Provides an instant dummy enchantment window"); + PM:BindCommand("/fs", "debuggers", HandleFoodStatsCmd, "- Turns regular foodstats message on or off"); + PM:BindCommand("/arr", "debuggers", HandleArrowCmd, "- Creates an arrow going away from the player"); + PM:BindCommand("/fb", "debuggers", HandleFireballCmd, "- Creates a ghast fireball as if shot by the player"); + PM:BindCommand("/xpa", "debuggers", HandleAddExperience, "- Adds 200 experience to the player"); + PM:BindCommand("/xpr", "debuggers", HandleRemoveXp, "- Remove all xp"); + PM:BindCommand("/fill", "debuggers", HandleFill, "- Fills all block entities in current chunk with junk"); -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); @@ -863,3 +864,42 @@ function HandleRemoveXp(a_Split, a_Player) return true; end + + + + + +function HandleFill(a_Split, a_Player) + local World = a_Player:GetWorld(); + local ChunkX = a_Player:GetChunkX(); + local ChunkZ = a_Player:GetChunkZ(); + World:ForEachBlockEntityInChunk(ChunkX, ChunkZ, + function(a_BlockEntity) + local BlockType = a_BlockEntity:GetBlockType(); + if ( + (BlockType == E_BLOCK_CHEST) or + (BlockType == E_BLOCK_DISPENSER) or + (BlockType == E_BLOCK_DROPPER) or + (BlockType == E_BLOCK_FURNACE) or + (BlockType == E_BLOCK_HOPPER) + ) then + -- This block entity has items (inherits from cBlockEntityWithItems), fill it: + -- Note that we're not touching lit furnaces, don't wanna mess them up + local EntityWithItems = tolua.cast(a_BlockEntity, "cBlockEntityWithItems"); + local ItemGrid = EntityWithItems:GetContents(); + local NumSlots = ItemGrid:GetNumSlots(); + local ItemToSet = cItem(E_ITEM_GOLD_NUGGET); + for i = 0, NumSlots - 1 do + if (ItemGrid:GetSlot(i):IsEmpty()) then + ItemGrid:SetSlot(i, ItemToSet); + end + end + end + end + ); + return true; +end + + + + -- cgit v1.2.3 From e9a8b964795af23e2dc9681444d7c9944b12ef6f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 20 Nov 2013 22:04:16 +0100 Subject: APIDump: Documented cWorld:ForEachBlockEntityInChunk() and cWorld:DoWithBlockEntityAt(). --- MCServer/Plugins/APIDump/APIDesc.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 450bc9f28..f263d83f4 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2240,6 +2240,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); CreateProjectile = { Params = "X, Y, Z, {{cProjectileEntity|ProjectileKind}}, {{cEntity|Creator}}, [{{Vector3d|Speed}}]", Return = "", Notes = "Creates a new projectile of the specified kind at the specified coords. The projectile's creator is set to Creator (may be nil). Optional speed indicates the initial speed for the projectile." }, DigBlock = { Params = "X, Y, Z", Return = "", Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors." }, DoExplosionAt = { Params = "Force, X, Y, Z, CanCauseFire, Source, SourceData", Return = "", Notes = "Creates an explosion of the specified relative force in the specified position. If CanCauseFire is set, the explosion will set blocks on fire, too. The Source parameter specifies the source of the explosion, one of the esXXX constants. The SourceData parameter is specific to each source type, usually it provides more info about the source." }, + DoWithBlockEntityAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a block entity at the specified coords, calls the CallbackFunction with the {{cBlockEntity}} parameter representing the block entity. The CallbackFunction has the following signature:
function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])
The function returns false if there is no block entity, or if there is, it returns the bool value that the callback has returned. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." }, DoWithChestAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a chest at the specified coords, calls the CallbackFunction with the {{cChestEntity}} parameter representing the chest. The CallbackFunction has the following signature:
function Callback({{cChestEntity|ChestEntity}}, [CallbackData])
The function returns false if there is no chest, or if there is, it returns the bool value that the callback has returned." }, DoWithDispenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dispenser at the specified coords, calls the CallbackFunction with the {{cDispenserEntity}} parameter representing the dispenser. The CallbackFunction has the following signature:
function Callback({{cDispenserEntity|DispenserEntity}}, [CallbackData])
The function returns false if there is no dispenser, or if there is, it returns the bool value that the callback has returned." }, DoWithDropSpenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper or a dispenser at the specified coords, calls the CallbackFunction with the {{cDropSpenserEntity}} parameter representing the dropper or dispenser. The CallbackFunction has the following signature:
function Callback({{cDropSpenserEntity|DropSpenserEntity}}, [CallbackData])
Note that this can be used to access both dispensers and droppers in a similar way. The function returns false if there is neither dispenser nor dropper, or if there is, it returns the bool value that the callback has returned." }, @@ -2253,6 +2254,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); { Params = "{{Vector3i|BlockCoords}}, BlockType, BlockMeta", Return = "", Notes = "Sets the block at the specified coords, without waking up the simulators or replacing the block entities for the previous block type. Do not use if the block being replaced has a block entity tied to it!" }, }, FindAndDoWithPlayer = { Params = "PlayerNameHint, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of a name similar to the specified name (weighted-match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature:
function Callback({{cPlayer|Player}}, [CallbackData])
The function returns false if the player was not found, or whatever bool value the callback returned if the player was found. Note that the name matching is very loose, so it is a good idea to check the player name in the callback function." }, + ForEachBlockEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each block entity in the chunk. Returns true if all block entities in the chunk have been processed (including when there are zero block entities), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature:
function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])
The callback should return false or no value to continue with the next block entity, or true to abort the enumeration. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." }, ForEachChestInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each chest in the chunk. Returns true if all chests in the chunk have been processed (including when there are zero chests), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature:
function Callback({{cChestEntity|ChestEntity}}, [CallbackData])
The callback should return false or no value to continue with the next chest, or true to abort the enumeration." }, ForEachEntity = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the loaded world. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature:
function Callback({{cEntity|Entity}}, [CallbackData])
The callback should return false or no value to continue with the next entity, or true to abort the enumeration." }, ForEachEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the specified chunk. Returns true if all the entities have been processed (including when there are zero entities), or false if the chunk is not loaded or the callback function has aborted the enumeration by returning true. The callback function has the following signature:
function Callback({{cEntity|Entity}}, [CallbackData])
The callback should return false or no value to continue with the next entity, or true to abort the enumeration." }, -- cgit v1.2.3 From f92512ebdf9b163a8e830055d7887b7afe554699 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 21 Nov 2013 22:09:11 +0100 Subject: Exported static XP calculation to Lua API. --- source/Bindings.cpp | 108 +++++++++++++++++++++++++++++++++++++-------- source/Bindings.h | 2 +- source/Entities/Player.cpp | 15 +++---- source/Entities/Player.h | 18 ++++---- 4 files changed, 105 insertions(+), 38 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 9fdd28383..3e261b121 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/16/13 21:58:48. +** Generated automatically by tolua++-1.0.92 on 11/21/13 22:02:55. */ #ifndef __cplusplus @@ -190,7 +190,7 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cThrownEnderPearlEntity"); tolua_usertype(tolua_S,"cFurnaceEntity"); tolua_usertype(tolua_S,"cEntity"); - tolua_usertype(tolua_S,"cCuboid"); + tolua_usertype(tolua_S,"cExpBottleEntity"); tolua_usertype(tolua_S,"cEnchantments"); tolua_usertype(tolua_S,"cMonster"); tolua_usertype(tolua_S,"cPluginLua"); @@ -212,49 +212,51 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cLineBlockTracer"); tolua_usertype(tolua_S,"cListeners"); tolua_usertype(tolua_S,"cThrownSnowballEntity"); - tolua_usertype(tolua_S,"Vector3d"); + tolua_usertype(tolua_S,"cFireworkEntity"); tolua_usertype(tolua_S,"TakeDamageInfo"); tolua_usertype(tolua_S,"cCraftingRecipe"); tolua_usertype(tolua_S,"cPlugin"); tolua_usertype(tolua_S,"cItemGrid"); tolua_usertype(tolua_S,"cHTTPServer::cCallbacks"); tolua_usertype(tolua_S,"cLuaWindow"); - tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"cServer"); tolua_usertype(tolua_S,"cHopperEntity"); tolua_usertype(tolua_S,"std::vector"); tolua_usertype(tolua_S,"cBlockEntityWithItems"); tolua_usertype(tolua_S,"cWindow"); tolua_usertype(tolua_S,"cCraftingGrid"); - tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"cBlockArea"); - tolua_usertype(tolua_S,"cArrowEntity"); - tolua_usertype(tolua_S,"cDropSpenserEntity"); tolua_usertype(tolua_S,"cGroup"); + tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"cTracer"); + tolua_usertype(tolua_S,"cArrowEntity"); + tolua_usertype(tolua_S,"cDropSpenserEntity"); tolua_usertype(tolua_S,"cBoundingBox"); - tolua_usertype(tolua_S,"cNoteEntity"); + tolua_usertype(tolua_S,"cCuboid"); tolua_usertype(tolua_S,"Vector3i"); + tolua_usertype(tolua_S,"cNoteEntity"); + tolua_usertype(tolua_S,"Vector3d"); tolua_usertype(tolua_S,"cBlockEntity"); tolua_usertype(tolua_S,"cCriticalSection"); tolua_usertype(tolua_S,"HTTPTemplateRequest"); - tolua_usertype(tolua_S,"cPlayer"); - tolua_usertype(tolua_S,"cServer"); - tolua_usertype(tolua_S,"cSignEntity"); + tolua_usertype(tolua_S,"cWebPlugin"); tolua_usertype(tolua_S,"cFile"); tolua_usertype(tolua_S,"cItems"); tolua_usertype(tolua_S,"cClientHandle"); - tolua_usertype(tolua_S,"cIniFile"); - tolua_usertype(tolua_S,"cWebPlugin"); - tolua_usertype(tolua_S,"cChatColor"); - tolua_usertype(tolua_S,"cPawn"); - tolua_usertype(tolua_S,"cThrownEggEntity"); - tolua_usertype(tolua_S,"cGroupManager"); tolua_usertype(tolua_S,"cWebAdmin"); + tolua_usertype(tolua_S,"cChatColor"); + tolua_usertype(tolua_S,"cIniFile"); tolua_usertype(tolua_S,"HTTPRequest"); - tolua_usertype(tolua_S,"cProjectileEntity"); tolua_usertype(tolua_S,"HTTPFormData"); + tolua_usertype(tolua_S,"cPawn"); + tolua_usertype(tolua_S,"cPlayer"); + tolua_usertype(tolua_S,"cGroupManager"); + tolua_usertype(tolua_S,"cSignEntity"); tolua_usertype(tolua_S,"cItemGrid::cListener"); + tolua_usertype(tolua_S,"cProjectileEntity"); tolua_usertype(tolua_S,"cDropperEntity"); + tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"cThrownEggEntity"); } /* method: new of class cIniFile */ @@ -7846,6 +7848,66 @@ static int tolua_AllToLua_cPlayer_GetXpPercentage00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: XpForLevel of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_XpForLevel00 +static int tolua_AllToLua_cPlayer_XpForLevel00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cPlayer",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + short int a_Level = ((short int) tolua_tonumber(tolua_S,2,0)); + { + short tolua_ret = (short) cPlayer::XpForLevel(a_Level); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'XpForLevel'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: CalcLevelFromXp of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_CalcLevelFromXp00 +static int tolua_AllToLua_cPlayer_CalcLevelFromXp00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cPlayer",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + short int a_CurrentXp = ((short int) tolua_tonumber(tolua_S,2,0)); + { + short tolua_ret = (short) cPlayer::CalcLevelFromXp(a_CurrentXp); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'CalcLevelFromXp'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetEyeHeight of class cPlayer */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetEyeHeight00 static int tolua_AllToLua_cPlayer_GetEyeHeight00(lua_State* tolua_S) @@ -30449,13 +30511,14 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"EATING_TICKS",cPlayer::EATING_TICKS); tolua_constant(tolua_S,"MAX_AIR_LEVEL",cPlayer::MAX_AIR_LEVEL); tolua_constant(tolua_S,"DROWNING_TICKS",cPlayer::DROWNING_TICKS); - tolua_constant(tolua_S,"MIN_EXPERIENCE",cPlayer::MIN_EXPERIENCE); tolua_function(tolua_S,"SetCurrentExperience",tolua_AllToLua_cPlayer_SetCurrentExperience00); tolua_function(tolua_S,"DeltaExperience",tolua_AllToLua_cPlayer_DeltaExperience00); tolua_function(tolua_S,"GetXpLifetimeTotal",tolua_AllToLua_cPlayer_GetXpLifetimeTotal00); tolua_function(tolua_S,"GetCurrentXp",tolua_AllToLua_cPlayer_GetCurrentXp00); tolua_function(tolua_S,"GetXpLevel",tolua_AllToLua_cPlayer_GetXpLevel00); tolua_function(tolua_S,"GetXpPercentage",tolua_AllToLua_cPlayer_GetXpPercentage00); + tolua_function(tolua_S,"XpForLevel",tolua_AllToLua_cPlayer_XpForLevel00); + tolua_function(tolua_S,"CalcLevelFromXp",tolua_AllToLua_cPlayer_CalcLevelFromXp00); tolua_function(tolua_S,"GetEyeHeight",tolua_AllToLua_cPlayer_GetEyeHeight00); tolua_function(tolua_S,"GetEyePosition",tolua_AllToLua_cPlayer_GetEyePosition00); tolua_function(tolua_S,"IsOnGround",tolua_AllToLua_cPlayer_IsOnGround00); @@ -30543,6 +30606,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"pkEnderPearl",cProjectileEntity::pkEnderPearl); tolua_constant(tolua_S,"pkExpBottle",cProjectileEntity::pkExpBottle); tolua_constant(tolua_S,"pkSplashPotion",cProjectileEntity::pkSplashPotion); + tolua_constant(tolua_S,"pkFirework",cProjectileEntity::pkFirework); tolua_constant(tolua_S,"pkWitherSkull",cProjectileEntity::pkWitherSkull); tolua_constant(tolua_S,"pkFishingFloat",cProjectileEntity::pkFishingFloat); tolua_function(tolua_S,"GetProjectileKind",tolua_AllToLua_cProjectileEntity_GetProjectileKind00); @@ -30572,6 +30636,12 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_cclass(tolua_S,"cThrownSnowballEntity","cThrownSnowballEntity","cProjectileEntity",NULL); tolua_beginmodule(tolua_S,"cThrownSnowballEntity"); tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cExpBottleEntity","cExpBottleEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cExpBottleEntity"); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cFireworkEntity","cFireworkEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cFireworkEntity"); + tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cGhastFireballEntity","cGhastFireballEntity","cProjectileEntity",NULL); tolua_beginmodule(tolua_S,"cGhastFireballEntity"); tolua_endmodule(tolua_S); diff --git a/source/Bindings.h b/source/Bindings.h index 996207055..9c5cdeb23 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/16/13 21:58:48. +** Generated automatically by tolua++-1.0.92 on 11/21/13 22:02:55. */ /* Exported function */ diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 436ae0cfc..f37a23f22 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -358,11 +358,10 @@ bool cPlayer::SetCurrentExperience(short int a_CurrentXp) short cPlayer::DeltaExperience(short a_Xp_delta) { - //ToDo: figure out a better name?... - if(a_Xp_delta > (SHRT_MAX - m_LifetimeTotalXp)) + if (a_Xp_delta > (SHRT_MAX - m_CurrentXp)) { // Value was bad, abort and report - LOGWARNING("Attempt was made to increment Xp by %d, which was bad", + LOGWARNING("Attempt was made to increment Xp by %d, which overflowed the short datatype. Ignoring.", a_Xp_delta); return -1; // Should we instead just return the current Xp? } @@ -370,13 +369,13 @@ short cPlayer::DeltaExperience(short a_Xp_delta) m_CurrentXp += a_Xp_delta; // Make sure they didn't subtract too much - if(m_CurrentXp < MIN_EXPERIENCE) + if (m_CurrentXp < 0) { - m_CurrentXp = MIN_EXPERIENCE; + m_CurrentXp = 0; } // Update total for score calculation - if(a_Xp_delta > 0) + if (a_Xp_delta > 0) { m_LifetimeTotalXp += a_Xp_delta; } @@ -803,8 +802,8 @@ void cPlayer::Respawn(void) m_FoodSaturationLevel = 5; // Reset Experience - m_CurrentXp = MIN_EXPERIENCE; - m_LifetimeTotalXp = MIN_EXPERIENCE; + m_CurrentXp = 0; + m_LifetimeTotalXp = 0; // ToDo: send score to client? How? m_ClientHandle->SendRespawn(); diff --git a/source/Entities/Player.h b/source/Entities/Player.h index bda25715d..44cab7d74 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -32,7 +32,6 @@ public: EATING_TICKS = 30, ///< Number of ticks it takes to eat an item MAX_AIR_LEVEL = 300, DROWNING_TICKS = 10, //number of ticks per heart of damage - MIN_EXPERIENCE = 0, } ; // tolua_end @@ -92,6 +91,12 @@ public: /// Gets the experience bar percentage - XpP float GetXpPercentage(void); + /// Caculates the amount of XP needed for a given level, ref: http://minecraft.gamepedia.com/XP + static short XpForLevel(short int a_Level); + + /// inverse of XpForLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations + static short CalcLevelFromXp(short int a_CurrentXp); + // tolua_end /// Starts charging the equipped bow @@ -326,9 +331,7 @@ public: virtual bool IsCrouched (void) const { return m_IsCrouched; } virtual bool IsSprinting(void) const { return m_IsSprinting; } virtual bool IsRclking (void) const { return IsEating(); } - - - + protected: typedef std::map< std::string, bool > PermissionMap; PermissionMap m_ResolvedPermissions; @@ -426,15 +429,10 @@ protected: // flag saying we need to send a xp update to client bool m_bDirtyExperience; - /// Caculates the Xp needed for a given level, ref: http://minecraft.gamepedia.com/XP - static short XpForLevel(short int a_Level); - - /// inverse of XpAtLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations - static short CalcLevelFromXp(short int a_CurrentXp); - bool m_IsChargingBow; int m_BowCharge; + virtual void Destroyed(void); /// Filters out damage for creative mode -- cgit v1.2.3 From 98be3ca0e4e93eae5deafff86a27827a3ce79e6f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 21 Nov 2013 22:12:52 +0100 Subject: APIDump: Documented cPlayer XP-related functions. --- MCServer/Plugins/APIDump/APIDesc.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index f263d83f4..f8fab9afc 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1784,14 +1784,17 @@ a_Player:OpenWindow(Window); { AddFoodExhaustion = { Params = "Exhaustion", Return = "", Notes = "Adds the specified number to the food exhaustion. Only positive numbers expected." }, AddToGroup = { Params = "GroupName", Return = "", Notes = "Temporarily adds the player to the specified group. The assignment is lost when the player disconnects." }, + CalcLevelFromXp = { Params = "XPAmount", Return = "number", Notes = "Returns the level which is reached with the specified amount of XP. Inverse of XpForLevel()." }, CanUseCommand = { Params = "Command", Return = "bool", Notes = "Returns true if the player is allowed to use the specified command." }, CloseWindow = { Params = "[CanRefuse]", Return = "", Notes = "Closes the currently open UI window. If CanRefuse is true (default), the window may refuse the closing." }, CloseWindowIfID = { Params = "WindowID, [CanRefuse]", Return = "", Notes = "Closes the currently open UI window if its ID matches the given ID. If CanRefuse is true (default), the window may refuse the closing." }, + DeltaExperience = { Params = "DeltaXP", Return = "", Notes = "Adds or removes XP from the current XP amount. Won't allow XP to go negative. Returns the new experience, -1 on error (XP overflow)." }, Feed = { Params = "AddFood, AddSaturation", Return = "bool", Notes = "Tries to add the specified amounts to food level and food saturation level (only positive amounts expected). Returns true if player was hungry and the food was consumed, false if too satiated." }, FoodPoison = { Params = "NumTicks", Return = "", Notes = "Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two" }, GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left)." }, GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." }, GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player (based on the first group). Prefix player messages with this code." }, + GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" }, GetEffectiveGameMode = { Params = "", Return = "{{eGameMode|GameMode}}", Notes = "Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions." }, GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." }, GetEyeHeight = { Return = "number", Notes = "Returns the height of the player's eyes, in absolute coords" }, @@ -1814,6 +1817,9 @@ a_Player:OpenWindow(Window); GetThrowSpeed = { Params = "SpeedCoeff", Return = "{{Vector3d}}", Notes = "Returns the speed vector for an object thrown with the specified speed coeff. Basically returns the normalized look vector multiplied by the coeff, with a slight random variation." }, GetThrowStartPos = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the position where the projectiles should start when thrown by this player." }, GetWindow = { Params = "", Return = "{{cWindow}}", Notes = "Returns the currently open UI window. If the player doesn't have any UI window open, returns the inventory window." }, + GetXpLevel = { Params = "", Return = "number", Notes = "Returns the current XP level (based on current XP amount)." }, + GetXpLifetimeTotal = { Params = "", Return = "number", Notes = "Returns the amount of XP that has been accumulated throughout the player's lifetime." }, + GetXpPercentage = { Params = "", Return = "number", Notes = "Returns the percentage of the experience bar - the amount of XP towards the next XP level. Between 0 and 1." }, HasPermission = { Params = "PermissionString", Return = "bool", Notes = "Returns true if the player has the specified permission" }, Heal = { Params = "HitPoints", Return = "", Notes = "Heals the player by the specified amount of HPs. Only positive amounts are expected. Sends a health update to the client." }, IsEating = { Params = "", Return = "bool", Notes = "Returns true if the player is currently eating the item in their hand." }, @@ -1834,6 +1840,7 @@ a_Player:OpenWindow(Window); Respawn = { Params = "", Return = "", Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet." }, SendMessage = { Params = "MessageString", Return = "", Notes = "Sends the specified message to the player." }, SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." }, + SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." }, SetFoodExhaustionLevel = { Params = "ExhaustionLevel", Return = "", Notes = "Sets the food exhaustion to the specified level." }, SetFoodLevel = { Params = "FoodLevel", Return = "", Notes = "Sets the food level (number of half-drumsticks on-screen)" }, SetFoodPoisonedTicksRemaining = { Params = "FoodPoisonedTicksRemaining", Return = "", Notes = "Sets the number of ticks remaining for food poisoning. Doesn't send foodpoisoning effect to the client, use FoodPoison() for that." }, @@ -1846,6 +1853,7 @@ a_Player:OpenWindow(Window); SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed (as reported by the 1.6.1+ protocols)" }, SetVisible = { Params = "IsVisible", Return = "", Notes = "Sets the player visibility to other players" }, TossItem = { Params = "DraggedItem, [Amount], [CreateType], [CreateDamage]", Return = "", Notes = "FIXME: This function will be rewritten, avoid it. It tosses an item, either from the inventory, dragged in hand (while in UI window) or a newly created one." }, + XpForLevel = { Params = "XPLevel", Return = "number", Notes = "Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." }, }, Constants = { -- cgit v1.2.3 From 3de6f6357f3e4c2b0b696e2a0b6cdbdaecdf4136 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 22 Nov 2013 12:26:06 +0100 Subject: Changed cRoot:GetFurnaceRecipe() Lua binding signature. Fix #364. --- source/Bindings.cpp | 50 ++++++++--------------------------------------- source/Bindings.h | 2 +- source/ManualBindings.cpp | 40 +++++++++++++++++++++++++++++++++++++ source/Root.h | 2 +- 4 files changed, 50 insertions(+), 44 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 3e261b121..da9c86b6b 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/21/13 22:02:55. +** Generated automatically by tolua++-1.0.92 on 11/22/13 11:58:39. */ #ifndef __cplusplus @@ -199,9 +199,8 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cPickup"); tolua_usertype(tolua_S,"sWebAdminPage"); tolua_usertype(tolua_S,"cFireChargeEntity"); - tolua_usertype(tolua_S,"cWorld"); + tolua_usertype(tolua_S,"cClientHandle"); tolua_usertype(tolua_S,"cChunkDesc"); - tolua_usertype(tolua_S,"cFurnaceRecipe"); tolua_usertype(tolua_S,"cPluginManager"); tolua_usertype(tolua_S,"Vector3f"); tolua_usertype(tolua_S,"cCraftingRecipes"); @@ -225,24 +224,24 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cBlockEntityWithItems"); tolua_usertype(tolua_S,"cWindow"); tolua_usertype(tolua_S,"cCraftingGrid"); + tolua_usertype(tolua_S,"cWorld"); tolua_usertype(tolua_S,"cBlockArea"); - tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"cItem"); - tolua_usertype(tolua_S,"cTracer"); + tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"cArrowEntity"); tolua_usertype(tolua_S,"cDropSpenserEntity"); + tolua_usertype(tolua_S,"cTracer"); tolua_usertype(tolua_S,"cBoundingBox"); tolua_usertype(tolua_S,"cCuboid"); - tolua_usertype(tolua_S,"Vector3i"); tolua_usertype(tolua_S,"cNoteEntity"); - tolua_usertype(tolua_S,"Vector3d"); + tolua_usertype(tolua_S,"Vector3i"); tolua_usertype(tolua_S,"cBlockEntity"); tolua_usertype(tolua_S,"cCriticalSection"); tolua_usertype(tolua_S,"HTTPTemplateRequest"); - tolua_usertype(tolua_S,"cWebPlugin"); + tolua_usertype(tolua_S,"Vector3d"); tolua_usertype(tolua_S,"cFile"); tolua_usertype(tolua_S,"cItems"); - tolua_usertype(tolua_S,"cClientHandle"); + tolua_usertype(tolua_S,"cWebPlugin"); tolua_usertype(tolua_S,"cWebAdmin"); tolua_usertype(tolua_S,"cChatColor"); tolua_usertype(tolua_S,"cIniFile"); @@ -19715,38 +19714,6 @@ static int tolua_AllToLua_cRoot_GetCraftingRecipes00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: GetFurnaceRecipe of class cRoot */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_GetFurnaceRecipe00 -static int tolua_AllToLua_cRoot_GetFurnaceRecipe00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cRoot",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cRoot* self = (cRoot*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetFurnaceRecipe'", NULL); -#endif - { - cFurnaceRecipe* tolua_ret = (cFurnaceRecipe*) self->GetFurnaceRecipe(); - tolua_pushusertype(tolua_S,(void*)tolua_ret,"cFurnaceRecipe"); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetFurnaceRecipe'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetWebAdmin of class cRoot */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_GetWebAdmin00 static int tolua_AllToLua_cRoot_GetWebAdmin00(lua_State* tolua_S) @@ -31126,7 +31093,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SetPrimaryServerVersion",tolua_AllToLua_cRoot_SetPrimaryServerVersion00); tolua_function(tolua_S,"GetGroupManager",tolua_AllToLua_cRoot_GetGroupManager00); tolua_function(tolua_S,"GetCraftingRecipes",tolua_AllToLua_cRoot_GetCraftingRecipes00); - tolua_function(tolua_S,"GetFurnaceRecipe",tolua_AllToLua_cRoot_GetFurnaceRecipe00); tolua_function(tolua_S,"GetWebAdmin",tolua_AllToLua_cRoot_GetWebAdmin00); tolua_function(tolua_S,"GetPluginManager",tolua_AllToLua_cRoot_GetPluginManager00); tolua_function(tolua_S,"QueueExecuteConsoleCommand",tolua_AllToLua_cRoot_QueueExecuteConsoleCommand00); diff --git a/source/Bindings.h b/source/Bindings.h index 9c5cdeb23..090386bee 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/21/13 22:02:55. +** Generated automatically by tolua++-1.0.92 on 11/22/13 11:58:39. */ /* Exported function */ diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 59bd0657c..418819910 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -2063,6 +2063,45 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S) +static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "const cItem") || + !L.CheckParamEnd (2) + ) + { + return 0; + } + + // Check the input param: + cItem * Input = (cItem *)tolua_tousertype(L, 1, NULL); + if (Input == NULL) + { + LOGWARNING("cRoot:GetFurnaceRecipe: the Input parameter is nil or missing."); + return 0; + } + + // Get the recipe for the input + cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe(); + const cFurnaceRecipe::Recipe * Recipe = FR->GetRecipeFrom(*Input); + if (Recipe == NULL) + { + // There is no such furnace recipe for this input, return no value + return 0; + } + + // Push the output, number of ticks and input as the three return values: + tolua_pushusertype(L, Recipe->Out, "const cItem"); + tolua_pushnumber (L, (lua_Number)(Recipe->CookTime)); + tolua_pushusertype(L, Recipe->In, "const cItem"); + return 3; +} + + + + + static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S) { // function cHopperEntity::GetOutputBlockPos() @@ -2125,6 +2164,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith ); tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach); tolua_function(tolua_S, "ForEachWorld", tolua_ForEach); + tolua_function(tolua_S, "GetFurnaceRecipe", tolua_cRoot_GetFurnaceRecipe); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWorld"); diff --git a/source/Root.h b/source/Root.h index 175084c53..36643a3ba 100644 --- a/source/Root.h +++ b/source/Root.h @@ -56,7 +56,7 @@ public: cGroupManager * GetGroupManager (void) { return m_GroupManager; } // tolua_export cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export - cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // tolua_export + cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // Exported in ManualBindings.cpp with quite a different signature cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export cAuthenticator & GetAuthenticator (void) { return m_Authenticator; } -- cgit v1.2.3 From 07a1de8ebb58f61f2cd37db0e3382f0df9a784f0 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 22 Nov 2013 12:26:39 +0100 Subject: Debuggers: Added a test harness for cRoot:GetFurnaceRecipe(). The "/fr" command lists the furnace recipe for the currently held item. --- MCServer/Plugins/Debuggers/Debuggers.lua | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index c4811b91a..e4c601da3 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -48,6 +48,7 @@ function Initialize(Plugin) PM:BindCommand("/xpa", "debuggers", HandleAddExperience, "- Adds 200 experience to the player"); PM:BindCommand("/xpr", "debuggers", HandleRemoveXp, "- Remove all xp"); PM:BindCommand("/fill", "debuggers", HandleFill, "- Fills all block entities in current chunk with junk"); + PM:BindCommand("/fr", "debuggers", HandleFurnaceRecipe, "- Shows the furnace recipe for the currently held item"); -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); @@ -903,3 +904,23 @@ end + +function HandleFurnaceRecipe(a_Split, a_Player) + local HeldItem = a_Player:GetEquippedItem(); + local Out, NumTicks, In = cRoot.GetFurnaceRecipe(HeldItem); + if (Out ~= nil) then + a_Player:SendMessage( + "Furnace turns " .. ItemToFullString(In) .. + " to " .. ItemToFullString(Out) .. + " in " .. NumTicks .. " ticks (" .. + tostring(NumTicks / 20) .. " seconds)." + ); + else + a_Player:SendMessage("There is no furnace recipe that would smelt " .. ItemToString(HeldItem)); + end + return true; +end + + + + -- cgit v1.2.3 From 7fd3fda5d3c0274e47c20ed5f05346e30f1d11e2 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 22 Nov 2013 12:37:55 +0100 Subject: APIDump: Documented new cRoot:GetFurnaceRecipe(). --- MCServer/Plugins/APIDump/APIDesc.lua | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index f8fab9afc..f91d46f52 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2046,7 +2046,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature:
function Callback({{cWorld|cWorld}})
" }, GetCraftingRecipes = { Params = "", Return = "{{cCraftingRecipe|cCraftingRecipe}}", Notes = "Returns the CraftingRecipes object" }, GetDefaultWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world object from the default world." }, - GetFurnaceRecipe = { Params = "", Return = "{{cFurnaceRecipe|cFurnaceRecipe}}", Notes = "Returns the cFurnaceRecipes object." }, + GetFurnaceRecipe = { Params = "{{cItem|InItem}}", Return = "{{cItem|OutItem}}, NumTicks, {{cItem|InItem}}", Notes = "(STATIC) Returns the furnace recipe for smelting the specified input. If a recipe is found, returns the smelted result, the number of ticks required for the smelting operation, and the input consumed (note that MCServer supports smelting M items into N items and different smelting rates). If no recipe is found, returns no value." }, GetGroupManager = { Params = "", Return = "{{cGroupManager|cGroupManager}}", Notes = "Returns the cGroupManager object." }, GetPhysicalRAMUsage = { Params = "", Return = "number", Notes = "Returns the amount of physical RAM that the entire MCServer process is using, in KiB. Negative if the OS doesn't support this query." }, GetPluginManager = { Params = "", Return = "{{cPluginManager|cPluginManager}}", Notes = "Returns the cPluginManager object." }, @@ -2064,7 +2064,32 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); Constants = { }, - }, + AdditionalInfo = + { + { + Header = "Querying a furnace recipe", + Contents = [[ + To find the furnace recipe for an item, use the following code (adapted from the Debuggers plugin's /fr command): +
+local HeldItem = a_Player:GetEquippedItem();
+local Out, NumTicks, In = cRoot.GetFurnaceRecipe(HeldItem);  -- Note STATIC call - using the dot operator instead of a colon
+if (Out ~= nil) then
+	-- There is a recipe, list it:
+	a_Player:SendMessage(
+		"Furnace turns " .. ItemToFullString(In) ..
+		" to " .. ItemToFullString(Out) ..
+		" in " .. NumTicks .. " ticks (" ..
+		tostring(NumTicks / 20) .. " seconds)."
+	);
+else
+	-- No recipe found
+	a_Player:SendMessage("There is no furnace recipe that would smelt " .. ItemToString(HeldItem));
+end
+
+ ]], + }, + }, + }, -- cRoot cServer = { -- cgit v1.2.3 From 14569885e55c7f3def2b0f56765c742a162c0fe1 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 22 Nov 2013 16:49:38 +0100 Subject: Fixed cRoot:GetFurnaceRecipe() Lua binding. --- source/LuaState.cpp | 33 +++++++++++++++++++++++++++++++++ source/LuaState.h | 5 ++++- source/ManualBindings.cpp | 7 ++++--- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/source/LuaState.cpp b/source/LuaState.cpp index 8d2fa8eca..ba60ed67d 100644 --- a/source/LuaState.cpp +++ b/source/LuaState.cpp @@ -739,6 +739,39 @@ bool cLuaState::CallFunction(int a_NumResults) +bool cLuaState::CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + tolua_Error tolua_err; + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (tolua_isusertable(m_LuaState, i, a_UserTable, 0, &tolua_err)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + bool cLuaState::CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam) { ASSERT(IsValid()); diff --git a/source/LuaState.h b/source/LuaState.h index caba2484d..8586a251b 100644 --- a/source/LuaState.h +++ b/source/LuaState.h @@ -764,7 +764,10 @@ public: */ bool CallFunction(int a_NumReturnValues); - /// Returns true if the specified parameters on the stack are of the specified usertype; also logs warning if not + /// Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions + bool CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam = -1); + + /// Returns true if the specified parameters on the stack are of the specified usertype; also logs warning if not. Used for regular functions bool CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam = -1); /// Returns true if the specified parameters on the stack are a table; also logs warning if not diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 418819910..f3325f25c 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -2067,15 +2067,16 @@ static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S) { cLuaState L(tolua_S); if ( - !L.CheckParamUserType(1, "const cItem") || - !L.CheckParamEnd (2) + !L.CheckParamUserTable(1, "cRoot") || + !L.CheckParamUserType (2, "const cItem") || + !L.CheckParamEnd (3) ) { return 0; } // Check the input param: - cItem * Input = (cItem *)tolua_tousertype(L, 1, NULL); + cItem * Input = (cItem *)tolua_tousertype(L, 2, NULL); if (Input == NULL) { LOGWARNING("cRoot:GetFurnaceRecipe: the Input parameter is nil or missing."); -- cgit v1.2.3 From 281bf8f90bbd295bb81ec09889bcaeefa689e6b2 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 22 Nov 2013 16:50:03 +0100 Subject: Added cRoot:GetFurnaceFuelBurnTime() to Lua API. --- MCServer/Plugins/Debuggers/Debuggers.lua | 21 +++++++++++++++++++- source/Bindings.cpp | 33 +++++++++++++++++++++++++++++++- source/Bindings.h | 2 +- source/Root.cpp | 10 ++++++++++ source/Root.h | 4 ++++ 5 files changed, 67 insertions(+), 3 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index e4c601da3..682a54676 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -49,6 +49,7 @@ function Initialize(Plugin) PM:BindCommand("/xpr", "debuggers", HandleRemoveXp, "- Remove all xp"); PM:BindCommand("/fill", "debuggers", HandleFill, "- Fills all block entities in current chunk with junk"); PM:BindCommand("/fr", "debuggers", HandleFurnaceRecipe, "- Shows the furnace recipe for the currently held item"); + PM:BindCommand("/ff", "debuggers", HandleFurnaceFuel, "- Shows how long the currently held item would burn in a furnace"); -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); @@ -907,7 +908,7 @@ end function HandleFurnaceRecipe(a_Split, a_Player) local HeldItem = a_Player:GetEquippedItem(); - local Out, NumTicks, In = cRoot.GetFurnaceRecipe(HeldItem); + local Out, NumTicks, In = cRoot:GetFurnaceRecipe(HeldItem); if (Out ~= nil) then a_Player:SendMessage( "Furnace turns " .. ItemToFullString(In) .. @@ -924,3 +925,21 @@ end + +function HandleFurnaceFuel(a_Split, a_Player) + local HeldItem = a_Player:GetEquippedItem(); + local NumTicks = cRoot:GetFurnaceFuelBurnTime(HeldItem); + if (NumTicks > 0) then + a_Player:SendMessage( + ItemToFullString(HeldItem) .. " would power a furnace for " .. NumTicks .. + " ticks (" .. tostring(NumTicks / 20) .. " seconds)." + ); + else + a_Player:SendMessage(ItemToString(HeldItem) .. " will not power furnaces."); + end + return true; +end + + + + diff --git a/source/Bindings.cpp b/source/Bindings.cpp index da9c86b6b..65c154b78 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/22/13 11:58:39. +** Generated automatically by tolua++-1.0.92 on 11/22/13 16:24:50. */ #ifndef __cplusplus @@ -19714,6 +19714,36 @@ static int tolua_AllToLua_cRoot_GetCraftingRecipes00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: GetFurnaceFuelBurnTime of class cRoot */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_GetFurnaceFuelBurnTime00 +static int tolua_AllToLua_cRoot_GetFurnaceFuelBurnTime00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cRoot",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cItem",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cItem* a_Fuel = ((const cItem*) tolua_tousertype(tolua_S,2,0)); + { + int tolua_ret = (int) cRoot::GetFurnaceFuelBurnTime(*a_Fuel); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetFurnaceFuelBurnTime'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetWebAdmin of class cRoot */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_GetWebAdmin00 static int tolua_AllToLua_cRoot_GetWebAdmin00(lua_State* tolua_S) @@ -31093,6 +31123,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SetPrimaryServerVersion",tolua_AllToLua_cRoot_SetPrimaryServerVersion00); tolua_function(tolua_S,"GetGroupManager",tolua_AllToLua_cRoot_GetGroupManager00); tolua_function(tolua_S,"GetCraftingRecipes",tolua_AllToLua_cRoot_GetCraftingRecipes00); + tolua_function(tolua_S,"GetFurnaceFuelBurnTime",tolua_AllToLua_cRoot_GetFurnaceFuelBurnTime00); tolua_function(tolua_S,"GetWebAdmin",tolua_AllToLua_cRoot_GetWebAdmin00); tolua_function(tolua_S,"GetPluginManager",tolua_AllToLua_cRoot_GetPluginManager00); tolua_function(tolua_S,"QueueExecuteConsoleCommand",tolua_AllToLua_cRoot_QueueExecuteConsoleCommand00); diff --git a/source/Bindings.h b/source/Bindings.h index 090386bee..7d4999505 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/22/13 11:58:39. +** Generated automatically by tolua++-1.0.92 on 11/22/13 16:24:51. */ /* Exported function */ diff --git a/source/Root.cpp b/source/Root.cpp index be5a0553c..5bb04abfb 100644 --- a/source/Root.cpp +++ b/source/Root.cpp @@ -742,3 +742,13 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output) + +int cRoot::GetFurnaceFuelBurnTime(const cItem & a_Fuel) +{ + cFurnaceRecipe * FR = Get()->GetFurnaceRecipe(); + return FR->GetBurnTime(a_Fuel); +} + + + + diff --git a/source/Root.h b/source/Root.h index 36643a3ba..4e38dd17f 100644 --- a/source/Root.h +++ b/source/Root.h @@ -57,6 +57,10 @@ public: cGroupManager * GetGroupManager (void) { return m_GroupManager; } // tolua_export cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // Exported in ManualBindings.cpp with quite a different signature + + /// Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel + static int GetFurnaceFuelBurnTime(const cItem & a_Fuel); // tolua_export + cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export cAuthenticator & GetAuthenticator (void) { return m_Authenticator; } -- cgit v1.2.3 From 4fbfe59ea01d7e622531b7cb3009cd36e595708f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 22 Nov 2013 16:52:09 +0100 Subject: APIDump: Fixed cRoot's furnace query API. --- MCServer/Plugins/APIDump/APIDesc.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index f91d46f52..11b0aeff7 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2046,6 +2046,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature:
function Callback({{cWorld|cWorld}})
" }, GetCraftingRecipes = { Params = "", Return = "{{cCraftingRecipe|cCraftingRecipe}}", Notes = "Returns the CraftingRecipes object" }, GetDefaultWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world object from the default world." }, + GetFurnaceFuelBurnTime = { Params = "{{cItem|Fuel}}", Return = "number", Notes = "(STATIC) Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel." }, GetFurnaceRecipe = { Params = "{{cItem|InItem}}", Return = "{{cItem|OutItem}}, NumTicks, {{cItem|InItem}}", Notes = "(STATIC) Returns the furnace recipe for smelting the specified input. If a recipe is found, returns the smelted result, the number of ticks required for the smelting operation, and the input consumed (note that MCServer supports smelting M items into N items and different smelting rates). If no recipe is found, returns no value." }, GetGroupManager = { Params = "", Return = "{{cGroupManager|cGroupManager}}", Notes = "Returns the cGroupManager object." }, GetPhysicalRAMUsage = { Params = "", Return = "number", Notes = "Returns the amount of physical RAM that the entire MCServer process is using, in KiB. Negative if the OS doesn't support this query." }, @@ -2072,7 +2073,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); To find the furnace recipe for an item, use the following code (adapted from the Debuggers plugin's /fr command):
 local HeldItem = a_Player:GetEquippedItem();
-local Out, NumTicks, In = cRoot.GetFurnaceRecipe(HeldItem);  -- Note STATIC call - using the dot operator instead of a colon
+local Out, NumTicks, In = cRoot:GetFurnaceRecipe(HeldItem);  -- Note STATIC call - no need for a Get()
 if (Out ~= nil) then
 	-- There is a recipe, list it:
 	a_Player:SendMessage(
@@ -4317,6 +4318,7 @@ end
 		"Globals.assert",
 		"Globals.collectgarbage",
 		"Globals.xpcall",
+		"Globals.decoda_output",  -- When running under Decoda, this function gets added to the global namespace
 		"%a+\.__%a+",        -- AnyClass.__Anything
 		"%a+\.\.collector",  -- AnyClass..collector
 		"%a+\.new",          -- AnyClass.new
-- 
cgit v1.2.3


From 63753c5e8405837931510b8da648dc75d4970fe1 Mon Sep 17 00:00:00 2001
From: madmaxoft 
Date: Fri, 22 Nov 2013 20:11:24 +0100
Subject: Added cFile:GetFolderContents().

Fix 162.
---
 MCServer/Plugins/APIDump/APIDesc.lua     | 21 +++++------
 MCServer/Plugins/Debuggers/Debuggers.lua | 11 ++++++
 source/LuaState.cpp                      | 33 ++++++++++++++++++
 source/LuaState.h                        |  7 ++--
 source/ManualBindings.cpp                | 27 ++++++++++++++
 source/OSSupport/File.cpp                | 60 ++++++++++++++++++++++++++++++++
 source/OSSupport/File.h                  |  3 ++
 source/PluginLua.cpp                     |  6 ++--
 source/PluginManager.cpp                 |  4 +--
 source/StringUtils.cpp                   | 49 --------------------------
 source/StringUtils.h                     |  3 --
 11 files changed, 155 insertions(+), 69 deletions(-)

diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 11b0aeff7..8591d9aa4 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -927,22 +927,23 @@ end
 		cFile =
 		{
 			Desc = [[
-				Provides helper functions for manipulating and querying the filesystem. Most functions are called
-				directly on the cFile class itself:
+				Provides helper functions for manipulating and querying the filesystem. Most functions are static,
+				so they should be called directly on the cFile class itself:
 
 cFile:Delete("/usr/bin/virus.exe");
 

]], Functions = { - Copy = { Params = "SrcFileName, DstFileName", Return = "bool", Notes = "Copies a single file to a new destination. Returns true if successful. Fails if the destination already exists." }, - CreateFolder = { Params = "FolderName", Return = "bool", Notes = "Creates a new folder. Returns true if successful." }, - Delete = { Params = "FileName", Return = "bool", Notes = "Deletes the specified file. Returns true if successful." }, - Exists = { Params = "FileName", Return = "bool", Notes = "Returns true if the specified file exists." }, - GetSize = { Params = "FileName", Return = "number", Notes = "Returns the size of the file, or -1 on failure." }, - IsFile = { Params = "Path", Return = "bool", Notes = "Returns true if the specified path points to an existing file." }, - IsFolder = { Params = "Path", Return = "bool", Notes = "Returns true if the specified path points to an existing folder." }, - Rename = { Params = "OrigPath, NewPath", Return = "bool", Notes = "Renames a file or a folder. Returns true if successful. Undefined result if NewPath already exists." }, + Copy = { Params = "SrcFileName, DstFileName", Return = "bool", Notes = "(STATIC) Copies a single file to a new destination. Returns true if successful. Fails if the destination already exists." }, + CreateFolder = { Params = "FolderName", Return = "bool", Notes = "(STATIC) Creates a new folder. Returns true if successful." }, + Delete = { Params = "FileName", Return = "bool", Notes = "(STATIC) Deletes the specified file. Returns true if successful." }, + Exists = { Params = "FileName", Return = "bool", Notes = "(STATIC) Returns true if the specified file exists." }, + GetFolderContents = { Params = "FolderName", Return = "array table of strings", Notes = "(STATIC) Returns the contents of the specified folder, as an array table of strings. Each filesystem object is listed. Use the IsFile() and IsFolder() functions to determine the object type." }, + GetSize = { Params = "FileName", Return = "number", Notes = "(STATIC) Returns the size of the file, or -1 on failure." }, + IsFile = { Params = "Path", Return = "bool", Notes = "(STATIC) Returns true if the specified path points to an existing file." }, + IsFolder = { Params = "Path", Return = "bool", Notes = "(STATIC) Returns true if the specified path points to an existing folder." }, + Rename = { Params = "OrigPath, NewPath", Return = "bool", Notes = "(STATIC) Renames a file or a folder. Returns true if successful. Undefined result if NewPath already exists." }, }, }, -- cFile diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 682a54676..c9a610f71 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -51,6 +51,8 @@ function Initialize(Plugin) PM:BindCommand("/fr", "debuggers", HandleFurnaceRecipe, "- Shows the furnace recipe for the currently held item"); PM:BindCommand("/ff", "debuggers", HandleFurnaceFuel, "- Shows how long the currently held item would burn in a furnace"); + Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers); + -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); @@ -943,3 +945,12 @@ end + +function HandleRequest_Debuggers(a_Request) + local FolderContents = cFile:GetFolderContents("./"); + return "

The following objects have been returned by cFile:GetFolderContents():

  • " .. table.concat(FolderContents, "
  • ") .. "

"; +end + + + + diff --git a/source/LuaState.cpp b/source/LuaState.cpp index ba60ed67d..644f4972c 100644 --- a/source/LuaState.cpp +++ b/source/LuaState.cpp @@ -871,6 +871,39 @@ bool cLuaState::CheckParamNumber(int a_StartParam, int a_EndParam) +bool cLuaState::CheckParamString(int a_StartParam, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + tolua_Error tolua_err; + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (tolua_isstring(m_LuaState, i, 0, &tolua_err)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + bool cLuaState::CheckParamEnd(int a_Param) { tolua_Error tolua_err; diff --git a/source/LuaState.h b/source/LuaState.h index 8586a251b..aa71ee226 100644 --- a/source/LuaState.h +++ b/source/LuaState.h @@ -770,12 +770,15 @@ public: /// Returns true if the specified parameters on the stack are of the specified usertype; also logs warning if not. Used for regular functions bool CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam = -1); - /// Returns true if the specified parameters on the stack are a table; also logs warning if not + /// Returns true if the specified parameters on the stack are tables; also logs warning if not bool CheckParamTable(int a_StartParam, int a_EndParam = -1); - /// Returns true if the specified parameters on the stack are a number; also logs warning if not + /// Returns true if the specified parameters on the stack are numbers; also logs warning if not bool CheckParamNumber(int a_StartParam, int a_EndParam = -1); + /// Returns true if the specified parameters on the stack are strings; also logs warning if not + bool CheckParamString(int a_StartParam, int a_EndParam = -1); + /// Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) bool CheckParamEnd(int a_Param); diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index f3325f25c..967b03ee7 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -171,6 +171,29 @@ cPluginLua * GetLuaPlugin(lua_State * L) +static int tolua_cFile_GetFolderContents(lua_State * tolua_S) +{ + cLuaState LuaState(tolua_S); + if ( + !LuaState.CheckParamUserTable(1, "cFile") || + !LuaState.CheckParamString (2) || + !LuaState.CheckParamEnd (3) + ) + { + return 0; + } + + AString Folder = (AString)tolua_tocppstring(LuaState, 1, 0); + + AStringVector Contents = cFile::GetFolderContents(Folder); + LuaState.Push(Contents); + return 1; +} + + + + + template< class Ty1, class Ty2, @@ -2153,6 +2176,10 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); + tolua_beginmodule(tolua_S, "cFile"); + tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cHopperEntity"); tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos); tolua_endmodule(tolua_S); diff --git a/source/OSSupport/File.cpp b/source/OSSupport/File.cpp index d2eea498a..86276bd79 100644 --- a/source/OSSupport/File.cpp +++ b/source/OSSupport/File.cpp @@ -360,6 +360,66 @@ bool cFile::CreateFolder(const AString & a_FolderPath) +AStringVector cFile::GetFolderContents(const AString & a_Folder) +{ + AStringVector AllFiles; + + #ifdef _WIN32 + + // If the folder name doesn't contain the terminating slash / backslash, add it: + AString FileFilter = a_Folder; + if ( + !FileFilter.empty() && + (FileFilter[FileFilter.length() - 1] != '\\') && + (FileFilter[FileFilter.length() - 1] != '/') + ) + { + FileFilter.push_back('\\'); + } + + // Find all files / folders: + FileFilter.append("*.*"); + HANDLE hFind; + WIN32_FIND_DATA FindFileData; + if ((hFind = FindFirstFile(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) + { + do + { + AllFiles.push_back(FindFileData.cFileName); + } while (FindNextFile(hFind, &FindFileData)); + FindClose(hFind); + } + + #else // _WIN32 + + DIR * dp; + struct dirent *dirp; + if (*a_Directory == 0) + { + a_Directory = "."; + } + if ((dp = opendir(a_Directory)) == NULL) + { + LOGERROR("Error (%i) opening directory \"%s\"\n", errno, a_Directory ); + } + else + { + while ((dirp = readdir(dp)) != NULL) + { + AllFiles.push_back(dirp->d_name); + } + closedir(dp); + } + + #endif // else _WIN32 + + return AllFiles; +} + + + + + int cFile::Printf(const char * a_Fmt, ...) { AString buf; diff --git a/source/OSSupport/File.h b/source/OSSupport/File.h index cfb3a2019..70f81c8d2 100644 --- a/source/OSSupport/File.h +++ b/source/OSSupport/File.h @@ -123,6 +123,9 @@ public: // tolua_end + /// Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). + static AStringVector GetFolderContents(const AString & a_Folder); // Exported in ManualBindings.cpp + int Printf(const char * a_Fmt, ...); private: diff --git a/source/PluginLua.cpp b/source/PluginLua.cpp index 03aefb098..23d079b05 100644 --- a/source/PluginLua.cpp +++ b/source/PluginLua.cpp @@ -86,11 +86,11 @@ bool cPluginLua::Initialize(void) lua_setglobal(m_LuaState, "g_Plugin"); } - std::string PluginPath = FILE_IO_PREFIX + GetLocalDirectory() + "/"; + std::string PluginPath = FILE_IO_PREFIX + GetLocalFolder() + "/"; // Load all files for this plugin, and execute them - AStringList Files = GetDirectoryContents(PluginPath.c_str()); - for (AStringList::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) + AStringVector Files = cFile::GetFolderContents(PluginPath.c_str()); + for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) { if (itr->rfind(".lua") == AString::npos) { diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp index 0a9f5b9d3..e08ebe503 100644 --- a/source/PluginManager.cpp +++ b/source/PluginManager.cpp @@ -72,8 +72,8 @@ void cPluginManager::FindPlugins(void) ++itr; } - AStringList Files = GetDirectoryContents(PluginsPath.c_str()); - for (AStringList::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) + AStringVector Files = cFile::GetFolderContents(PluginsPath.c_str()); + for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) { if ((*itr == ".") || (*itr == "..") || (!cFile::IsFolder(PluginsPath + *itr))) { diff --git a/source/StringUtils.cpp b/source/StringUtils.cpp index d52b1323f..f7aeeed26 100644 --- a/source/StringUtils.cpp +++ b/source/StringUtils.cpp @@ -270,55 +270,6 @@ void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & -AStringList GetDirectoryContents(const char * a_Directory) -{ - AStringList AllFiles; - - #ifdef _WIN32 - - AString FileFilter = AString(a_Directory) + "*.*"; - HANDLE hFind; - WIN32_FIND_DATA FindFileData; - - if ((hFind = FindFirstFile(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) - { - do - { - AllFiles.push_back(FindFileData.cFileName); - } while (FindNextFile(hFind, &FindFileData)); - FindClose(hFind); - } - - #else // _WIN32 - - DIR * dp; - struct dirent *dirp; - if (*a_Directory == 0) - { - a_Directory = "."; - } - if ((dp = opendir(a_Directory)) == NULL) - { - LOGERROR("Error (%i) opening directory \"%s\"\n", errno, a_Directory ); - } - else - { - while ((dirp = readdir(dp)) != NULL) - { - AllFiles.push_back(dirp->d_name); - } - closedir(dp); - } - - #endif // else _WIN32 - - return AllFiles; -} - - - - - // Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8) { diff --git a/source/StringUtils.h b/source/StringUtils.h index ec9ba96ce..3917cc4ec 100644 --- a/source/StringUtils.h +++ b/source/StringUtils.h @@ -57,9 +57,6 @@ extern unsigned int RateCompareString(const AString & s1, const AString & s2 ); /// Replaces *each* occurence of iNeedle in iHayStack with iReplaceWith extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith); // tolua_export -/// Returns the list of all items in the specified directory (files, folders, nix pipes, whatever's there) -extern AStringList GetDirectoryContents(const char * a_Directory); - /// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 extern AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8); -- cgit v1.2.3 From 7a2170f6b323c4ff1a974699ae3d2e43601d94ad Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 22 Nov 2013 21:46:06 +0100 Subject: APIDump: Implemented constant groups. Fix #289. --- MCServer/Plugins/APIDump/APIDesc.lua | 62 +- MCServer/Plugins/APIDump/main.lua | 1247 --------------------------- MCServer/Plugins/APIDump/main_APIDump.lua | 1315 +++++++++++++++++++++++++++++ 3 files changed, 1375 insertions(+), 1249 deletions(-) delete mode 100644 MCServer/Plugins/APIDump/main.lua create mode 100644 MCServer/Plugins/APIDump/main_APIDump.lua diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 8591d9aa4..5489650ad 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -30,6 +30,17 @@ g_APIDesc = { ConstantName = { Notes = "Notes about the constant" }, } , + + ConstantGroups = + { + GroupName1 = -- GroupName1 is used as the HTML anchor name + { + Include = {"constant1", "constant2", "const_.*"}, -- Constants to include in this group, array of identifiers, accepts wildcards + TextBefore = "This text will be written in front of the constant list", + TextAfter = "This text will be written after the constant list", + ShowInDescendants = false, -- If false, descendant classes won't list these constants + } + }, Variables = { @@ -75,6 +86,18 @@ g_APIDesc = psInSurvivalOrCreative = { Notes = "The arrow can be picked up by players in survival or creative gamemode" }, psNoPickup = { Notes = "The arrow cannot be picked up at all" }, }, + + ConstantGroups = + { + PickupState = + { + Include = "ps.*", + TextBefore = [[ + The following constants are used to signalize whether the arrow, once it lands, can be picked by + players: + ]], + }, + }, Inherits = "cProjectileEntity", }, @@ -182,7 +205,25 @@ g_APIDesc = msImprint = { Notes = "Src overwrites Dst anywhere where Dst has non-air blocks" }, msLake = { Notes = "Special mode for merging lake images" }, }, - + ConstantGroups = + { + BATypes = + { + Include = "ba.*", + TextBefore = [[ + The following constants are used to signalize the datatype to read or write: + ]], + }, + MergeStrategies = + { + Include = "ms.*", + TextBefore = [[ + The Merge() function can use different strategies to combine the source and destination blocks. + The following constants are used: + ]], + TextAfter = "See below for a detailed explanation of the individual merge strategies.", + }, + }, AdditionalInfo = { { @@ -817,7 +858,7 @@ end GetChunkZ = { Params = "", Return = "number", Notes = "Returns the Z-coord of the chunk in which the entity is placed" }, GetClass = { Params = "", Return = "string", Notes = "Returns the classname of the entity, such as \"cSpider\" or \"cPickup\"" }, GetClassStatic = { Params = "", Return = "string", Notes = "Returns the entity classname that this class implements. Each descendant overrides this function. Is static" }, - GetEntityType = { Params = "", Return = "eEntityType", Notes = "Returns the type of the entity, one of the etXXX constants. Note that to check specific entity type, you should use one of the IsXXX functions instead of comparing the value returned by this call." }, + GetEntityType = { Params = "", Return = "{{cEntity#EntityType|EntityType}}", Notes = "Returns the type of the entity, one of the {{cEntity#EntityType|etXXX}} constants. Note that to check specific entity type, you should use one of the IsXXX functions instead of comparing the value returned by this call." }, GetEquippedBoots = { Params = "", Return = "{{cItem}}", Notes = "Returns the boots that the entity has equipped. Returns an empty cItem if no boots equipped or not applicable." }, GetEquippedChestplate = { Params = "", Return = "{{cItem}}", Notes = "Returns the chestplate that the entity has equipped. Returns an empty cItem if no chestplate equipped or not applicable." }, GetEquippedHelmet = { Params = "", Return = "{{cItem}}", Notes = "Returns the helmet that the entity has equipped. Returns an empty cItem if no helmet equipped or not applicable." }, @@ -922,6 +963,14 @@ end etProjectile = { Notes = "The entity is a {{cProjectileEntity}} descendant" }, etTNT = { Notes = "The entity is a {{cTNTEntity}}" }, }, + ConstantGroups = + { + EntityType = + { + Include = "et.*", + TextBefore = "The following constants are used to distinguish between different entity types:", + }, + }, }, cFile = @@ -2018,12 +2067,21 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); pkEnderPearl = { Notes = "The projectile is a {{cThrownEnderPearlEntity|thrown enderpearl}}" }, pkExpBottle = { Notes = "The projectile is a thrown exp bottle (NYI)" }, pkFireCharge = { Notes = "The projectile is a {{cFireChargeEntity|fire charge}}" }, + pkFirework = { Notes = "The projectile is a (flying) firework (NYI)" }, pkFishingFloat = { Notes = "The projectile is a fishing float (NYI)" }, pkGhastFireball = { Notes = "The projectile is a {{cGhastFireballEntity|ghast fireball}}" }, pkSnowball = { Notes = "The projectile is a {{cThrownSnowballEntity|thrown snowball}}" }, pkSplashPotion = { Notes = "The projectile is a thrown splash potion (NYI)" }, pkWitherSkull = { Notes = "The projectile is a wither skull (NYI)" }, }, + ConstantGroups = + { + ProjectileKind = + { + Include = "pk.*", + TextBefore = "The following constants are used to distinguish between the different projectile kinds:", + }, + }, Inherits = "cEntity", }, diff --git a/MCServer/Plugins/APIDump/main.lua b/MCServer/Plugins/APIDump/main.lua deleted file mode 100644 index fa9d29423..000000000 --- a/MCServer/Plugins/APIDump/main.lua +++ /dev/null @@ -1,1247 +0,0 @@ - --- main.lua - --- Implements the plugin entrypoint (in this case the entire plugin) - - - - - --- Global variables: -g_Plugin = nil; -g_PluginFolder = ""; -g_TrackedPages = {}; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames. -g_Stats = -- Statistics about the documentation -{ - NumTotalClasses = 0, - NumUndocumentedClasses = 0, - NumTotalFunctions = 0, - NumUndocumentedFunctions = 0, - NumTotalConstants = 0, - NumUndocumentedConstants = 0, - NumTotalVariables = 0, - NumUndocumentedVariables = 0, - NumTotalHooks = 0, - NumUndocumentedHooks = 0, - NumTrackedLinks = 0, - NumInvalidLinks = 0, -} - - - - - - -function Initialize(Plugin) - g_Plugin = Plugin; - - Plugin:SetName("APIDump"); - Plugin:SetVersion(1); - - LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) - - g_PluginFolder = Plugin:GetLocalFolder(); - - -- dump all available API functions and objects: - -- DumpAPITxt(); - - -- Dump all available API object in HTML format into a subfolder: - DumpAPIHtml(); - - return true -end - - - - - -function DumpAPITxt() - LOG("Dumping all available functions to API.txt..."); - function dump (prefix, a, Output) - for i, v in pairs (a) do - if (type(v) == "table") then - if (GetChar(i, 1) ~= ".") then - if (v == _G) then - -- LOG(prefix .. i .. " == _G, CYCLE, ignoring"); - elseif (v == _G.package) then - -- LOG(prefix .. i .. " == _G.package, ignoring"); - else - dump(prefix .. i .. ".", v, Output) - end - end - elseif (type(v) == "function") then - if (string.sub(i, 1, 2) ~= "__") then - table.insert(Output, prefix .. i .. "()"); - end - end - end - end - - local Output = {}; - dump("", _G, Output); - - table.sort(Output); - local f = io.open("API.txt", "w"); - for i, n in ipairs(Output) do - f:write(n, "\n"); - end - f:close(); - LOG("API.txt written."); -end - - - - - -function CreateAPITables() - --[[ - We want an API table of the following shape: - local API = { - { - Name = "cCuboid", - Functions = { - {Name = "Sort"}, - {Name = "IsInside"} - }, - Constants = { - }, - Variables = { - }, - Descendants = {}, -- Will be filled by ReadDescriptions(), array of class APIs (references to other member in the tree) - }}, - { - Name = "cBlockArea", - Functions = { - {Name = "Clear"}, - {Name = "CopyFrom"}, - ... - }, - Constants = { - {Name = "baTypes", Value = 0}, - {Name = "baMetas", Value = 1}, - ... - }, - Variables = { - }, - ... - }} - }; - local Globals = { - Functions = { - ... - }, - Constants = { - ... - } - }; - --]] - - local Globals = {Functions = {}, Constants = {}, Variables = {}, Descendants = {}}; - local API = {}; - - local function Add(a_APIContainer, a_ObjName, a_ObjValue) - if (type(a_ObjValue) == "function") then - table.insert(a_APIContainer.Functions, {Name = a_ObjName}); - elseif ( - (type(a_ObjValue) == "number") or - (type(a_ObjValue) == "string") - ) then - table.insert(a_APIContainer.Constants, {Name = a_ObjName, Value = a_ObjValue}); - end - end - - local function ParseClass(a_ClassName, a_ClassObj) - local res = {Name = a_ClassName, Functions = {}, Constants = {}, Variables = {}, Descendants = {}}; - -- Add functions and constants: - for i, v in pairs(a_ClassObj) do - Add(res, i, v); - end - - -- Member variables: - local SetField = a_ClassObj[".set"] or {}; - if ((a_ClassObj[".get"] ~= nil) and (type(a_ClassObj[".get"]) == "table")) then - for k, v in pairs(a_ClassObj[".get"]) do - if (SetField[k] == nil) then - -- It is a read-only variable, add it as a constant: - table.insert(res.Constants, {Name = k, Value = ""}); - else - -- It is a read-write variable, add it as a variable: - table.insert(res.Variables, { Name = k }); - end - end - end - return res; - end - - for i, v in pairs(_G) do - if ( - (v ~= _G) and -- don't want the global namespace - (v ~= _G.packages) and -- don't want any packages - (v ~= _G[".get"]) and - (v ~= g_APIDesc) - ) then - if (type(v) == "table") then - table.insert(API, ParseClass(i, v)); - else - Add(Globals, i, v); - end - end - end - - return API, Globals; -end - - - - - -function DumpAPIHtml() - LOG("Dumping all available functions and constants to API subfolder..."); - - LOG("Creating API tables..."); - local API, Globals = CreateAPITables(); - local Hooks = {}; - local UndocumentedHooks = {}; - - -- Sort the classes by name: - LOG("Sorting..."); - table.sort(API, - function (c1, c2) - return (string.lower(c1.Name) < string.lower(c2.Name)); - end - ); - - g_Stats.NumTotalClasses = #API; - - -- Add Globals into the API: - Globals.Name = "Globals"; - table.insert(API, Globals); - - -- Extract hook constants: - for name, obj in pairs(cPluginManager) do - if ( - (type(obj) == "number") and - name:match("HOOK_.*") and - (name ~= "HOOK_MAX") and - (name ~= "HOOK_NUM_HOOKS") - ) then - table.insert(Hooks, { Name = name }); - end - end - table.sort(Hooks, - function(Hook1, Hook2) - return (Hook1.Name < Hook2.Name); - end - ); - - -- Read in the descriptions: - LOG("Reading descriptions..."); - ReadDescriptions(API); - ReadHooks(Hooks); - - -- Create the output folder - if not(cFile:IsFolder("API")) then - cFile:CreateFolder("API"); - end - - -- Create a "class index" file, write each class as a link to that file, - -- then dump class contents into class-specific file - LOG("Writing HTML files..."); - local f = io.open("API/index.html", "w"); - if (f == nil) then - LOGINFO("Cannot output HTML API: " .. err); - return; - end - - f:write([[ - - - MCServer API - Index - - - -
-
-

MCServer API - Index

-
-
-

The API reference is divided into the following sections:

- - - -
-

Class index

-

The following classes are available in the MCServer Lua scripting language:

- -
    -]]); - for i, cls in ipairs(API) do - f:write("
  • " .. cls.Name .. "
  • \n"); - WriteHtmlClass(cls, API); - end - f:write([[
- -
-

Hooks

- -

A plugin can register to be called whenever an "interesting event" occurs. It does so by calling cPluginManager's AddHook() function and implementing a callback function to handle the event.

-

A plugin can decide whether it will let the event pass through to the rest of the plugins, or hide it from them. This is determined by the return value from the hook callback function. If the function returns false or no value, the event is propagated further. If the function returns true, the processing is stopped, no other plugin receives the notification (and possibly MCServer disables the default behavior for the event). See each hook's details to see the exact behavior.

- - - - - - -]]); - for i, hook in ipairs(Hooks) do - if (hook.DefaultFnName == nil) then - -- The hook is not documented yet - f:write(" \n \n \n \n"); - table.insert(UndocumentedHooks, hook.Name); - else - f:write(" \n \n \n \n"); - WriteHtmlHook(hook); - end - end - f:write([[
Hook nameCalled when
" .. hook.Name .. "(No documentation yet)
" .. hook.Name .. "" .. LinkifyString(hook.CalledWhen, hook.Name) .. "
- -
-

Extra pages

- -

The following pages provide various extra information

- -
    -]]); - for i, extra in ipairs(g_APIDesc.ExtraPages) do - local SrcFileName = g_PluginFolder .. "/" .. extra.FileName; - if (cFile:Exists(SrcFileName)) then - local DstFileName = "API/" .. extra.FileName; - if (cFile:Exists(DstFileName)) then - cFile:Delete(DstFileName); - end - cFile:Copy(SrcFileName, DstFileName); - f:write("
  • " .. extra.Title .. "
  • \n"); - else - f:write("
  • " .. extra.Title .. " (file is missing)
  • \n"); - end - end - f:write("
"); - - -- Copy the static files to the output folder (overwrite any existing): - cFile:Copy(g_Plugin:GetLocalFolder() .. "/main.css", "API/main.css"); - cFile:Copy(g_Plugin:GetLocalFolder() .. "/prettify.js", "API/prettify.js"); - cFile:Copy(g_Plugin:GetLocalFolder() .. "/prettify.css", "API/prettify.css"); - cFile:Copy(g_Plugin:GetLocalFolder() .. "/lang-lua.js", "API/lang-lua.js"); - - -- List the documentation problems: - LOG("Listing leftovers..."); - ListUndocumentedObjects(API, UndocumentedHooks); - ListUnexportedObjects(); - ListMissingPages(); - - WriteStats(f); - - f:write([[ -
- -]]); - f:close(); - - LOG("API subfolder written"); -end - - - - - -function ReadDescriptions(a_API) - -- Returns true if the class of the specified name is to be ignored - local function IsClassIgnored(a_ClsName) - if (g_APIDesc.IgnoreClasses == nil) then - return false; - end - for i, name in ipairs(g_APIDesc.IgnoreClasses) do - if (a_ClsName:match(name)) then - return true; - end - end - return false; - end - - -- Returns true if the function is to be ignored - local function IsFunctionIgnored(a_ClassName, a_FnName) - if (g_APIDesc.IgnoreFunctions == nil) then - return false; - end - if (((g_APIDesc.Classes[a_ClassName] or {}).Functions or {})[a_FnName] ~= nil) then - -- The function is documented, don't ignore - return false; - end - local FnName = a_ClassName .. "." .. a_FnName; - for i, name in ipairs(g_APIDesc.IgnoreFunctions) do - if (FnName:match(name)) then - return true; - end - end - return false; - end - - -- Returns true if the constant (specified by its fully qualified name) is to be ignored - local function IsConstantIgnored(a_CnName) - if (g_APIDesc.IgnoreConstants == nil) then - return false; - end; - for i, name in ipairs(g_APIDesc.IgnoreConstants) do - if (a_CnName:match(name)) then - return true; - end - end - return false; - end - - -- Returns true if the member variable (specified by its fully qualified name) is to be ignored - local function IsVariableIgnored(a_VarName) - if (g_APIDesc.IgnoreVariables == nil) then - return false; - end; - for i, name in ipairs(g_APIDesc.IgnoreVariables) do - if (a_VarName:match(name)) then - return true; - end - end - return false; - end - - -- Remove ignored classes from a_API: - local APICopy = {}; - for i, cls in ipairs(a_API) do - if not(IsClassIgnored(cls.Name)) then - table.insert(APICopy, cls); - end - end - for i = 1, #a_API do - a_API[i] = APICopy[i]; - end; - - -- Process the documentation for each class: - for i, cls in ipairs(a_API) do - -- Rename special functions: - for j, fn in ipairs(cls.Functions) do - if (fn.Name == ".call") then - fn.DocID = "constructor"; - fn.Name = "() (constructor)"; - elseif (fn.Name == ".add") then - fn.DocID = "operator_plus"; - fn.Name = "operator +"; - elseif (fn.Name == ".div") then - fn.DocID = "operator_div"; - fn.Name = "operator /"; - elseif (fn.Name == ".mul") then - fn.DocID = "operator_mul"; - fn.Name = "operator *"; - elseif (fn.Name == ".sub") then - fn.DocID = "operator_sub"; - fn.Name = "operator -"; - elseif (fn.Name == ".eq") then - fn.DocID = "operator_eq"; - fn.Name = "operator =="; - end - end - - local APIDesc = g_APIDesc.Classes[cls.Name]; - if (APIDesc ~= nil) then - APIDesc.IsExported = true; - cls.Desc = APIDesc.Desc; - cls.AdditionalInfo = APIDesc.AdditionalInfo; - - -- Process inheritance: - if (APIDesc.Inherits ~= nil) then - for j, icls in ipairs(a_API) do - if (icls.Name == APIDesc.Inherits) then - table.insert(icls.Descendants, cls); - cls.Inherits = icls; - end - end - end - - cls.UndocumentedFunctions = {}; -- This will contain names of all the functions that are not documented - cls.UndocumentedConstants = {}; -- This will contain names of all the constants that are not documented - cls.UndocumentedVariables = {}; -- This will contain names of all the variables that are not documented - - local DoxyFunctions = {}; -- This will contain all the API functions together with their documentation - - local function AddFunction(a_Name, a_Params, a_Return, a_Notes) - table.insert(DoxyFunctions, {Name = a_Name, Params = a_Params, Return = a_Return, Notes = a_Notes}); - end - - if (APIDesc.Functions ~= nil) then - -- Assign function descriptions: - for j, func in ipairs(cls.Functions) do - local FnName = func.DocID or func.Name; - local FnDesc = APIDesc.Functions[FnName]; - if (FnDesc == nil) then - -- No description for this API function - AddFunction(func.Name); - if not(IsFunctionIgnored(cls.Name, FnName)) then - table.insert(cls.UndocumentedFunctions, FnName); - end - else - -- Description is available - if (FnDesc[1] == nil) then - -- Single function definition - AddFunction(func.Name, FnDesc.Params, FnDesc.Return, FnDesc.Notes); - else - -- Multiple function overloads - for k, desc in ipairs(FnDesc) do - AddFunction(func.Name, desc.Params, desc.Return, desc.Notes); - end -- for k, desc - FnDesc[] - end - FnDesc.IsExported = true; - end - end -- for j, func - - -- Replace functions with their described and overload-expanded versions: - cls.Functions = DoxyFunctions; - else -- if (APIDesc.Functions ~= nil) - for j, func in ipairs(cls.Functions) do - local FnName = func.DocID or func.Name; - if not(IsFunctionIgnored(cls.Name, FnName)) then - table.insert(cls.UndocumentedFunctions, FnName); - end - end - end -- if (APIDesc.Functions ~= nil) - - if (APIDesc.Constants ~= nil) then - -- Assign constant descriptions: - for j, cons in ipairs(cls.Constants) do - local CnDesc = APIDesc.Constants[cons.Name]; - if (CnDesc == nil) then - -- Not documented - if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then - table.insert(cls.UndocumentedConstants, cons.Name); - end - else - cons.Notes = CnDesc.Notes; - CnDesc.IsExported = true; - end - end -- for j, cons - else -- if (APIDesc.Constants ~= nil) - for j, cons in ipairs(cls.Constants) do - if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then - table.insert(cls.UndocumentedConstants, cons.Name); - end - end - end -- else if (APIDesc.Constants ~= nil) - - -- Assign member variables' descriptions: - if (APIDesc.Variables ~= nil) then - for j, var in ipairs(cls.Variables) do - local VarDesc = APIDesc.Variables[var.Name]; - if (VarDesc == nil) then - -- Not documented - if not(IsVariableIgnored(cls.Name .. "." .. var.Name)) then - table.insert(cls.UndocumentedVariables, var.Name); - end - else - -- Copy all documentation: - for k, v in pairs(VarDesc) do - var[k] = v - end - end - end -- for j, var - else -- if (APIDesc.Variables ~= nil) - for j, var in ipairs(cls.Variables) do - if not(IsVariableIgnored(cls.Name .. "." .. var.Name)) then - table.insert(cls.UndocumentedVariables, var.Name); - end - end - end -- else if (APIDesc.Variables ~= nil) - - else -- if (APIDesc ~= nil) - - -- Class is not documented at all, add all its members to Undocumented lists: - cls.UndocumentedFunctions = {}; - cls.UndocumentedConstants = {}; - cls.UndocumentedVariables = {}; - cls.Variables = cls.Variables or {}; - g_Stats.NumUndocumentedClasses = g_Stats.NumUndocumentedClasses + 1; - for j, func in ipairs(cls.Functions) do - local FnName = func.DocID or func.Name; - if not(IsFunctionIgnored(cls.Name, FnName)) then - table.insert(cls.UndocumentedFunctions, FnName); - end - end -- for j, func - cls.Functions[] - for j, cons in ipairs(cls.Constants) do - if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then - table.insert(cls.UndocumentedConstants, cons.Name); - end - end -- for j, cons - cls.Constants[] - for j, var in ipairs(cls.Variables) do - if not(IsConstantIgnored(cls.Name .. "." .. var.Name)) then - table.insert(cls.UndocumentedVariables, var.Name); - end - end -- for j, var - cls.Variables[] - end -- else if (APIDesc ~= nil) - - -- Remove ignored functions: - local NewFunctions = {}; - for j, fn in ipairs(cls.Functions) do - if (not(IsFunctionIgnored(cls.Name, fn.Name))) then - table.insert(NewFunctions, fn); - end - end -- for j, fn - cls.Functions = NewFunctions; - - -- Sort the functions (they may have been renamed): - table.sort(cls.Functions, - function(f1, f2) - if (f1.Name == f2.Name) then - -- Same name, either comparing the same function to itself, or two overloads, in which case compare the params - if ((f1.Params == nil) or (f2.Params == nil)) then - return 0; - end - return (f1.Params < f2.Params); - end - return (f1.Name < f2.Name); - end - ); - - -- Sort the constants: - table.sort(cls.Constants, - function(c1, c2) - return (c1.Name < c2.Name); - end - ); - - -- Remove ignored functions: - local NewVariables = {}; - for j, var in ipairs(cls.Variables) do - if (not(IsVariableIgnored(cls.Name .. "." .. var.Name))) then - table.insert(NewVariables, var); - end - end -- for j, var - cls.Variables = NewVariables; - - -- Sort the member variables: - table.sort(cls.Variables, - function(v1, v2) - return (v1.Name < v2.Name); - end - ); - end -- for i, cls - - -- Sort the descendants lists: - for i, cls in ipairs(a_API) do - table.sort(cls.Descendants, - function(c1, c2) - return (c1.Name < c2.Name); - end - ); - end -- for i, cls -end - - - - - -function ReadHooks(a_Hooks) - --[[ - a_Hooks = { - { Name = "HOOK_1"}, - { Name = "HOOK_2"}, - ... - }; - We want to add hook descriptions to each hook in this array - --]] - for i, hook in ipairs(a_Hooks) do - local HookDesc = g_APIDesc.Hooks[hook.Name]; - if (HookDesc ~= nil) then - for key, val in pairs(HookDesc) do - hook[key] = val; - end - end - end -- for i, hook - a_Hooks[] - g_Stats.NumTotalHooks = #a_Hooks; -end - - - - - --- Make a link out of anything with the special linkifying syntax {{link|title}} -function LinkifyString(a_String, a_Referrer) - assert(a_Referrer ~= nil); - assert(a_Referrer ~= ""); - - --- Adds a page to the list of tracked pages (to be checked for existence at the end) - local function AddTrackedPage(a_PageName) - local Pg = (g_TrackedPages[a_PageName] or {}); - table.insert(Pg, a_Referrer); - g_TrackedPages[a_PageName] = Pg; - end - - --- Creates the HTML for the specified link and title - local function CreateLink(Link, Title) - if (Link:sub(1, 7) == "http://") then - -- The link is a full absolute URL, do not modify, do not track: - return "" .. Title .. ""; - end - local idxHash = Link:find("#"); - if (idxHash ~= nil) then - -- The link contains an anchor: - if (idxHash == 1) then - -- Anchor in the current page, no need to track: - return "" .. Title .. ""; - end - -- Anchor in another page: - local PageName = Link:sub(1, idxHash - 1); - AddTrackedPage(PageName); - return "" .. Title .. ""; - end - -- Link without anchor: - AddTrackedPage(Link); - return "" .. Title .. ""; - end - - -- Linkify the strings using the CreateLink() function: - local txt = a_String:gsub("{{([^|}]*)|([^}]*)}}", CreateLink) -- {{link|title}} - txt = txt:gsub("{{([^|}]*)}}", -- {{LinkAndTitle}} - function(LinkAndTitle) - local idxHash = LinkAndTitle:find("#"); - if (idxHash ~= nil) then - -- The LinkAndTitle contains a hash, remove the hashed part from the title: - return CreateLink(LinkAndTitle, LinkAndTitle:sub(1, idxHash - 1)); - end - return CreateLink(LinkAndTitle, LinkAndTitle); - end - ); - return txt; -end - - - - - -function WriteHtmlClass(a_ClassAPI, a_AllAPI) - local cf, err = io.open("API/" .. a_ClassAPI.Name .. ".html", "w"); - if (cf == nil) then - return; - end - - -- Writes a table containing all functions in the specified list, with an optional "inherited from" header when a_InheritedName is valid - local function WriteFunctions(a_Functions, a_InheritedName) - if (#a_Functions == 0) then - return; - end - - if (a_InheritedName ~= nil) then - cf:write("

Functions inherited from ", a_InheritedName, "

\n"); - end - cf:write(" \n \n \n \n \n \n \n"); - for i, func in ipairs(a_Functions) do - cf:write(" \n \n"); - cf:write(" \n"); - cf:write(" \n"); - cf:write(" \n \n"); - end - cf:write("
NameParametersReturn valueNotes
" .. func.Name .. "", LinkifyString(func.Params or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Return or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Notes or "(undocumented)", (a_InheritedName or a_ClassAPI.Name)), "
\n\n"); - end - - local function WriteConstants(a_Constants, a_InheritedName) - if (#a_Constants == 0) then - return; - end - - if (a_InheritedName ~= nil) then - cf:write("

Constants inherited from ", a_InheritedName, "

\n"); - end - - cf:write(" \n \n \n \n \n \n"); - for i, cons in ipairs(a_Constants) do - cf:write(" \n \n"); - cf:write(" \n"); - cf:write(" \n \n"); - end - cf:write("
NameValueNotes
", cons.Name, "", cons.Value, "", LinkifyString(cons.Notes or "", a_InheritedName or a_ClassAPI.Name), "
\n\n"); - end - - local function WriteVariables(a_Variables, a_InheritedName) - if (#a_Variables == 0) then - return; - end - - if (a_InheritedName ~= nil) then - cf:write("

Member variables inherited from ", a_InheritedName, "

\n"); - end - - cf:write(" \n \n \n \n \n \n"); - for i, var in ipairs(a_Variables) do - cf:write(" \n \n"); - cf:write(" \n"); - cf:write(" \n \n"); - end - cf:write("
NameTypeNotes
", var.Name, "", LinkifyString(var.Type or "(undocumented)", a_InheritedName or a_ClassAPI.Name), "", LinkifyString(var.Notes or "", a_InheritedName or a_ClassAPI.Name), "
\n\n"); - end - - local function WriteDescendants(a_Descendants) - if (#a_Descendants == 0) then - return; - end - cf:write("
    "); - for i, desc in ipairs(a_Descendants) do - cf:write("
  • ", desc.Name, ""); - WriteDescendants(desc.Descendants); - cf:write("
  • \n"); - end - cf:write("
\n"); - end - - local ClassName = a_ClassAPI.Name; - - -- Build an array of inherited classes chain: - local InheritanceChain = {}; - local CurrInheritance = a_ClassAPI.Inherits; - while (CurrInheritance ~= nil) do - table.insert(InheritanceChain, CurrInheritance); - CurrInheritance = CurrInheritance.Inherits; - end - - cf:write([[ - - - MCServer API - ]], a_ClassAPI.Name, [[ Class - - - - - - -
-
-

]], a_ClassAPI.Name, [[

-
-
-

Contents

- -
    -]]); - - local HasInheritance = ((#a_ClassAPI.Descendants > 0) or (a_ClassAPI.Inherits ~= nil)); - - local HasConstants = (#a_ClassAPI.Constants > 0); - local HasFunctions = (#a_ClassAPI.Functions > 0); - local HasVariables = (#a_ClassAPI.Variables > 0); - for idx, cls in ipairs(InheritanceChain) do - HasConstants = HasConstants or (#cls.Constants > 0); - HasFunctions = HasFunctions or (#cls.Functions > 0); - HasVariables = HasVariables or (#cls.Variables > 0); - end - - -- Write the table of contents: - if (HasInheritance) then - cf:write("
  • Inheritance
  • \n"); - end - if (HasConstants) then - cf:write("
  • Constants
  • \n"); - end - if (HasVariables) then - cf:write("
  • Member variables
  • \n"); - end - if (HasFunctions) then - cf:write("
  • Functions
  • \n"); - end - if (a_ClassAPI.AdditionalInfo ~= nil) then - for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do - cf:write("
  • ", (additional.Header or "(No header)"), "
  • \n"); - end - end - cf:write("
\n\n"); - - -- Write the class description: - cf:write("

" .. ClassName .. " class

\n"); - if (a_ClassAPI.Desc ~= nil) then - cf:write("

"); - cf:write(LinkifyString(a_ClassAPI.Desc, ClassName)); - cf:write("

\n\n"); - end; - - -- Write the inheritance, if available: - if (HasInheritance) then - cf:write(" \n

Inheritance

\n"); - if (#InheritanceChain > 0) then - cf:write("

This class inherits from the following parent classes:

\n\n
    \n"); - for i, cls in ipairs(InheritanceChain) do - cf:write("
  • " .. cls.Name .. "
  • \n"); - end - cf:write("
\n\n"); - end - if (#a_ClassAPI.Descendants > 0) then - cf:write("

This class has the following descendants:\n"); - WriteDescendants(a_ClassAPI.Descendants); - cf:write("

\n\n"); - end - end - - -- Write the constants: - if (HasConstants) then - cf:write("

Constants

\n"); - WriteConstants(a_ClassAPI.Constants, nil); - g_Stats.NumTotalConstants = g_Stats.NumTotalConstants + #a_ClassAPI.Constants; - for i, cls in ipairs(InheritanceChain) do - WriteConstants(cls.Constants, cls.Name); - end; - end; - - -- Write the member variables: - if (HasVariables) then - cf:write("

Member variables

\n"); - WriteVariables(a_ClassAPI.Variables, nil); - g_Stats.NumTotalVariables = g_Stats.NumTotalVariables + #a_ClassAPI.Variables; - for i, cls in ipairs(InheritanceChain) do - WriteVariables(cls.Variables, cls.Name); - end; - end - - -- Write the functions, including the inherited ones: - if (HasFunctions) then - cf:write("

Functions

\n"); - WriteFunctions(a_ClassAPI.Functions, nil); - g_Stats.NumTotalFunctions = g_Stats.NumTotalFunctions + #a_ClassAPI.Functions; - for i, cls in ipairs(InheritanceChain) do - WriteFunctions(cls.Functions, cls.Name); - end - end - - -- Write the additional infos: - if (a_ClassAPI.AdditionalInfo ~= nil) then - for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do - cf:write("

", additional.Header, "

\n"); - cf:write(LinkifyString(additional.Contents, ClassName)); - end - end - - cf:write([[ -
- - - - ]]); - cf:close(); -end - - - - - -function WriteHtmlHook(a_Hook) - local fnam = "API/" .. a_Hook.DefaultFnName .. ".html"; - local f, error = io.open(fnam, "w"); - if (f == nil) then - LOG("Cannot write \"" .. fnam .. "\": \"" .. error .. "\"."); - return; - end - local HookName = a_Hook.DefaultFnName; - - f:write([[ - - - MCServer API - ]] .. HookName .. [[ Hook - - - - - - -
-
-

]] .. a_Hook.Name .. [[

-
-
-

-]]); - f:write(LinkifyString(a_Hook.Desc, HookName)); - f:write("

\n

Callback function

\n

The default name for the callback function is "); - f:write(a_Hook.DefaultFnName .. ". It has the following signature:\n\n"); - f:write("

function " .. HookName .. "(");
-	if (a_Hook.Params == nil) then
-		a_Hook.Params = {};
-	end
-	for i, param in ipairs(a_Hook.Params) do
-		if (i > 1) then
-			f:write(", ");
-		end
-		f:write(param.Name);
-	end
-	f:write(")
\n\n

Parameters:

\n\n \n \n \n \n \n \n"); - for i, param in ipairs(a_Hook.Params) do - f:write(" \n \n \n \n \n"); - end - f:write("
NameTypeNotes
" .. param.Name .. "" .. LinkifyString(param.Type, HookName) .. "" .. LinkifyString(param.Notes, HookName) .. "
\n\n

" .. (a_Hook.Returns or "") .. "

\n\n"); - f:write([[

Code examples

-

Registering the callback

- -]]); - f:write("
\n");
-	f:write([[cPluginManager.AddHook(cPluginManager.]] .. a_Hook.Name .. ", My" .. a_Hook.DefaultFnName .. [[);]]);
-	f:write("
\n\n"); - local Examples = a_Hook.CodeExamples or {}; - for i, example in ipairs(Examples) do - f:write("

" .. (example.Title or "missing Title") .. "

\n"); - f:write("

" .. (example.Desc or "missing Desc") .. "

\n\n"); - f:write("
" .. (example.Code or "missing Code") .. "\n			
\n\n"); - end - f:write([[
- - -]]); - f:close(); -end - - - - - ---- Writes a list of undocumented objects into a file -function ListUndocumentedObjects(API, UndocumentedHooks) - f = io.open("API/_undocumented.lua", "w"); - if (f ~= nil) then - f:write("\n-- This is the list of undocumented API objects, automatically generated by APIDump\n\n"); - f:write("g_APIDesc =\n{\n\tClasses =\n\t{\n"); - for i, cls in ipairs(API) do - local HasFunctions = ((cls.UndocumentedFunctions ~= nil) and (#cls.UndocumentedFunctions > 0)); - local HasConstants = ((cls.UndocumentedConstants ~= nil) and (#cls.UndocumentedConstants > 0)); - local HasVariables = ((cls.UndocumentedVariables ~= nil) and (#cls.UndocumentedVariables > 0)); - g_Stats.NumUndocumentedFunctions = g_Stats.NumUndocumentedFunctions + #cls.UndocumentedFunctions; - g_Stats.NumUndocumentedConstants = g_Stats.NumUndocumentedConstants + #cls.UndocumentedConstants; - g_Stats.NumUndocumentedVariables = g_Stats.NumUndocumentedVariables + #cls.UndocumentedVariables; - if (HasFunctions or HasConstants or HasVariables) then - f:write("\t\t" .. cls.Name .. " =\n\t\t{\n"); - if ((cls.Desc == nil) or (cls.Desc == "")) then - f:write("\t\t\tDesc = \"\"\n"); - end - end - - if (HasFunctions) then - f:write("\t\t\tFunctions =\n\t\t\t{\n"); - table.sort(cls.UndocumentedFunctions); - for j, fn in ipairs(cls.UndocumentedFunctions) do - f:write("\t\t\t\t" .. fn .. " = { Params = \"\", Return = \"\", Notes = \"\" },\n"); - end -- for j, fn - cls.UndocumentedFunctions[] - f:write("\t\t\t},\n\n"); - end - - if (HasConstants) then - f:write("\t\t\tConstants =\n\t\t\t{\n"); - table.sort(cls.UndocumentedConstants); - for j, cn in ipairs(cls.UndocumentedConstants) do - f:write("\t\t\t\t" .. cn .. " = { Notes = \"\" },\n"); - end -- for j, fn - cls.UndocumentedConstants[] - f:write("\t\t\t},\n\n"); - end - - if (HasVariables) then - f:write("\t\t\tVariables =\n\t\t\t{\n"); - table.sort(cls.UndocumentedVariables); - for j, vn in ipairs(cls.UndocumentedVariables) do - f:write("\t\t\t\t" .. vn .. " = { Type = \"\", Notes = \"\" },\n"); - end -- for j, fn - cls.UndocumentedVariables[] - f:write("\t\t\t},\n\n"); - end - - if (HasFunctions or HasConstants or HasVariables) then - f:write("\t\t},\n\n"); - end - end -- for i, cls - API[] - f:write("\t},\n"); - - if (#UndocumentedHooks > 0) then - f:write("\n\tHooks =\n\t{\n"); - for i, hook in ipairs(UndocumentedHooks) do - if (i > 1) then - f:write("\n"); - end - f:write("\t\t" .. hook .. " =\n\t\t{\n"); - f:write("\t\t\tCalledWhen = \"\",\n"); - f:write("\t\t\tDefaultFnName = \"On\", -- also used as pagename\n"); - f:write("\t\t\tDesc = [[\n\t\t\t\t\n\t\t\t]],\n"); - f:write("\t\t\tParams =\n\t\t\t{\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); - f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); - f:write("\t\t\t},\n"); - f:write("\t\t\tReturns = [[\n\t\t\t\t\n\t\t\t]],\n"); - f:write("\t\t}, -- " .. hook .. "\n"); - end - f:write("\t},\n"); - end - f:write("}\n\n\n\n"); - f:close(); - end - g_Stats.NumUndocumentedHooks = #UndocumentedHooks; -end - - - - - ---- Lists the API objects that are documented but not available in the API: -function ListUnexportedObjects() - f = io.open("API/_unexported-documented.txt", "w"); - if (f ~= nil) then - for clsname, cls in pairs(g_APIDesc.Classes) do - if not(cls.IsExported) then - -- The whole class is not exported - f:write("class\t" .. clsname .. "\n"); - else - if (cls.Functions ~= nil) then - for fnname, fnapi in pairs(cls.Functions) do - if not(fnapi.IsExported) then - f:write("func\t" .. clsname .. "." .. fnname .. "\n"); - end - end -- for j, fn - cls.Functions[] - end - if (cls.Constants ~= nil) then - for cnname, cnapi in pairs(cls.Constants) do - if not(cnapi.IsExported) then - f:write("const\t" .. clsname .. "." .. cnname .. "\n"); - end - end -- for j, fn - cls.Functions[] - end - end - end -- for i, cls - g_APIDesc.Classes[] - f:close(); - end -end - - - - - -function ListMissingPages() - local MissingPages = {}; - local NumLinks = 0; - for PageName, Referrers in pairs(g_TrackedPages) do - NumLinks = NumLinks + 1; - if not(cFile:Exists("API/" .. PageName .. ".html")) then - table.insert(MissingPages, {Name = PageName, Refs = Referrers} ); - end - end; - g_Stats.NumTrackedLinks = NumLinks; - g_TrackedPages = {}; - - if (#MissingPages == 0) then - -- No missing pages, congratulations! - return; - end - - -- Sort the pages by name: - table.sort(MissingPages, - function (Page1, Page2) - return (Page1.Name < Page2.Name); - end - ); - - -- Output the pages: - local f, err = io.open("API/_missingPages.txt", "w"); - if (f == nil) then - LOGWARNING("Cannot open _missingPages.txt for writing: '" .. err .. "'. There are " .. #MissingPages .. " pages missing."); - return; - end - for idx, pg in ipairs(MissingPages) do - f:write(pg.Name .. ":\n"); - -- Sort and output the referrers: - table.sort(pg.Refs); - f:write("\t" .. table.concat(pg.Refs, "\n\t")); - f:write("\n\n"); - end - f:close(); - g_Stats.NumInvalidLinks = #MissingPages; -end - - - - - ---- Writes the documentation statistics (in g_Stats) into the given HTML file -function WriteStats(f) - local function ExportMeter(a_Percent) - local Color; - if (a_Percent > 95) then - Color = "green"; - elseif (a_Percent > 50) then - Color = "orange"; - else - Color = "red"; - end - - local meter = { - "\n", - "
\n", - "
\n", - string.format("%.2f", a_Percent), - " %", - }; - return table.concat(meter, ""); - end - - f:write([[ -

Documentation statistics

- - ]]); - f:write("\n"); - - f:write("\n"); - - f:write("\n"); - - f:write("\n"); - - f:write("\n"); - - f:write([[ -
ObjectTotalDocumentedUndocumentedDocumented %
Classes", g_Stats.NumTotalClasses); - f:write("", g_Stats.NumTotalClasses - g_Stats.NumUndocumentedClasses); - f:write("", g_Stats.NumUndocumentedClasses); - f:write("", ExportMeter(100 * (g_Stats.NumTotalClasses - g_Stats.NumUndocumentedClasses) / g_Stats.NumTotalClasses)); - f:write("
Functions", g_Stats.NumTotalFunctions); - f:write("", g_Stats.NumTotalFunctions - g_Stats.NumUndocumentedFunctions); - f:write("", g_Stats.NumUndocumentedFunctions); - f:write("", ExportMeter(100 * (g_Stats.NumTotalFunctions - g_Stats.NumUndocumentedFunctions) / g_Stats.NumTotalFunctions)); - f:write("
Member variables", g_Stats.NumTotalVariables); - f:write("", g_Stats.NumTotalVariables - g_Stats.NumUndocumentedVariables); - f:write("", g_Stats.NumUndocumentedVariables); - f:write("", ExportMeter(100 * (g_Stats.NumTotalVariables - g_Stats.NumUndocumentedVariables) / g_Stats.NumTotalVariables)); - f:write("
Constants", g_Stats.NumTotalConstants); - f:write("", g_Stats.NumTotalConstants - g_Stats.NumUndocumentedConstants); - f:write("", g_Stats.NumUndocumentedConstants); - f:write("", ExportMeter(100 * (g_Stats.NumTotalConstants - g_Stats.NumUndocumentedConstants) / g_Stats.NumTotalConstants)); - f:write("
Hooks", g_Stats.NumTotalHooks); - f:write("", g_Stats.NumTotalHooks - g_Stats.NumUndocumentedHooks); - f:write("", g_Stats.NumUndocumentedHooks); - f:write("", ExportMeter(100 * (g_Stats.NumTotalHooks - g_Stats.NumUndocumentedHooks) / g_Stats.NumTotalHooks)); - f:write("
-

There are ]], g_Stats.NumTrackedLinks, " internal links, ", g_Stats.NumInvalidLinks, " of them are invalid.

" - ); -end - - - - diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua new file mode 100644 index 000000000..4dcedc06e --- /dev/null +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -0,0 +1,1315 @@ + +-- main.lua + +-- Implements the plugin entrypoint (in this case the entire plugin) + + + + + +-- Global variables: +g_Plugin = nil; +g_PluginFolder = ""; +g_TrackedPages = {}; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames. +g_Stats = -- Statistics about the documentation +{ + NumTotalClasses = 0, + NumUndocumentedClasses = 0, + NumTotalFunctions = 0, + NumUndocumentedFunctions = 0, + NumTotalConstants = 0, + NumUndocumentedConstants = 0, + NumTotalVariables = 0, + NumUndocumentedVariables = 0, + NumTotalHooks = 0, + NumUndocumentedHooks = 0, + NumTrackedLinks = 0, + NumInvalidLinks = 0, +} + + + + + + +function Initialize(Plugin) + g_Plugin = Plugin; + + Plugin:SetName("APIDump"); + Plugin:SetVersion(1); + + LOG("Initialising " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) + + g_PluginFolder = Plugin:GetLocalFolder(); + + -- dump all available API functions and objects: + -- DumpAPITxt(); + + -- Dump all available API object in HTML format into a subfolder: + DumpAPIHtml(); + + LOG("APIDump finished"); + + return true +end + + + + + +function DumpAPITxt() + LOG("Dumping all available functions to API.txt..."); + function dump (prefix, a, Output) + for i, v in pairs (a) do + if (type(v) == "table") then + if (GetChar(i, 1) ~= ".") then + if (v == _G) then + -- LOG(prefix .. i .. " == _G, CYCLE, ignoring"); + elseif (v == _G.package) then + -- LOG(prefix .. i .. " == _G.package, ignoring"); + else + dump(prefix .. i .. ".", v, Output) + end + end + elseif (type(v) == "function") then + if (string.sub(i, 1, 2) ~= "__") then + table.insert(Output, prefix .. i .. "()"); + end + end + end + end + + local Output = {}; + dump("", _G, Output); + + table.sort(Output); + local f = io.open("API.txt", "w"); + for i, n in ipairs(Output) do + f:write(n, "\n"); + end + f:close(); + LOG("API.txt written."); +end + + + + + +function CreateAPITables() + --[[ + We want an API table of the following shape: + local API = { + { + Name = "cCuboid", + Functions = { + {Name = "Sort"}, + {Name = "IsInside"} + }, + Constants = { + }, + Variables = { + }, + Descendants = {}, -- Will be filled by ReadDescriptions(), array of class APIs (references to other member in the tree) + }}, + { + Name = "cBlockArea", + Functions = { + {Name = "Clear"}, + {Name = "CopyFrom"}, + ... + }, + Constants = { + {Name = "baTypes", Value = 0}, + {Name = "baMetas", Value = 1}, + ... + }, + Variables = { + }, + ... + }} + }; + local Globals = { + Functions = { + ... + }, + Constants = { + ... + } + }; + --]] + + local Globals = {Functions = {}, Constants = {}, Variables = {}, Descendants = {}}; + local API = {}; + + local function Add(a_APIContainer, a_ObjName, a_ObjValue) + if (type(a_ObjValue) == "function") then + table.insert(a_APIContainer.Functions, {Name = a_ObjName}); + elseif ( + (type(a_ObjValue) == "number") or + (type(a_ObjValue) == "string") + ) then + table.insert(a_APIContainer.Constants, {Name = a_ObjName, Value = a_ObjValue}); + end + end + + local function ParseClass(a_ClassName, a_ClassObj) + local res = {Name = a_ClassName, Functions = {}, Constants = {}, Variables = {}, Descendants = {}}; + -- Add functions and constants: + for i, v in pairs(a_ClassObj) do + Add(res, i, v); + end + + -- Member variables: + local SetField = a_ClassObj[".set"] or {}; + if ((a_ClassObj[".get"] ~= nil) and (type(a_ClassObj[".get"]) == "table")) then + for k, v in pairs(a_ClassObj[".get"]) do + if (SetField[k] == nil) then + -- It is a read-only variable, add it as a constant: + table.insert(res.Constants, {Name = k, Value = ""}); + else + -- It is a read-write variable, add it as a variable: + table.insert(res.Variables, { Name = k }); + end + end + end + return res; + end + + for i, v in pairs(_G) do + if ( + (v ~= _G) and -- don't want the global namespace + (v ~= _G.packages) and -- don't want any packages + (v ~= _G[".get"]) and + (v ~= g_APIDesc) + ) then + if (type(v) == "table") then + table.insert(API, ParseClass(i, v)); + else + Add(Globals, i, v); + end + end + end + + return API, Globals; +end + + + + + +function DumpAPIHtml() + LOG("Dumping all available functions and constants to API subfolder..."); + + LOG("Creating API tables..."); + local API, Globals = CreateAPITables(); + local Hooks = {}; + local UndocumentedHooks = {}; + + -- Sort the classes by name: + LOG("Sorting..."); + table.sort(API, + function (c1, c2) + return (string.lower(c1.Name) < string.lower(c2.Name)); + end + ); + + g_Stats.NumTotalClasses = #API; + + -- Add Globals into the API: + Globals.Name = "Globals"; + table.insert(API, Globals); + + -- Extract hook constants: + for name, obj in pairs(cPluginManager) do + if ( + (type(obj) == "number") and + name:match("HOOK_.*") and + (name ~= "HOOK_MAX") and + (name ~= "HOOK_NUM_HOOKS") + ) then + table.insert(Hooks, { Name = name }); + end + end + table.sort(Hooks, + function(Hook1, Hook2) + return (Hook1.Name < Hook2.Name); + end + ); + + -- Read in the descriptions: + LOG("Reading descriptions..."); + ReadDescriptions(API); + ReadHooks(Hooks); + + -- Create the output folder + if not(cFile:IsFolder("API")) then + cFile:CreateFolder("API"); + end + + -- Create a "class index" file, write each class as a link to that file, + -- then dump class contents into class-specific file + LOG("Writing HTML files..."); + local f = io.open("API/index.html", "w"); + if (f == nil) then + LOGINFO("Cannot output HTML API: " .. err); + return; + end + + f:write([[ + + + MCServer API - Index + + + +
+
+

MCServer API - Index

+
+
+

The API reference is divided into the following sections:

+ + + +
+

Class index

+

The following classes are available in the MCServer Lua scripting language:

+ +
    +]]); + for i, cls in ipairs(API) do + f:write("
  • " .. cls.Name .. "
  • \n"); + WriteHtmlClass(cls, API); + end + f:write([[
+ +
+

Hooks

+ +

A plugin can register to be called whenever an "interesting event" occurs. It does so by calling cPluginManager's AddHook() function and implementing a callback function to handle the event.

+

A plugin can decide whether it will let the event pass through to the rest of the plugins, or hide it from them. This is determined by the return value from the hook callback function. If the function returns false or no value, the event is propagated further. If the function returns true, the processing is stopped, no other plugin receives the notification (and possibly MCServer disables the default behavior for the event). See each hook's details to see the exact behavior.

+ + + + + + +]]); + for i, hook in ipairs(Hooks) do + if (hook.DefaultFnName == nil) then + -- The hook is not documented yet + f:write(" \n \n \n \n"); + table.insert(UndocumentedHooks, hook.Name); + else + f:write(" \n \n \n \n"); + WriteHtmlHook(hook); + end + end + f:write([[
Hook nameCalled when
" .. hook.Name .. "(No documentation yet)
" .. hook.Name .. "" .. LinkifyString(hook.CalledWhen, hook.Name) .. "
+ +
+

Extra pages

+ +

The following pages provide various extra information

+ +
    +]]); + for i, extra in ipairs(g_APIDesc.ExtraPages) do + local SrcFileName = g_PluginFolder .. "/" .. extra.FileName; + if (cFile:Exists(SrcFileName)) then + local DstFileName = "API/" .. extra.FileName; + if (cFile:Exists(DstFileName)) then + cFile:Delete(DstFileName); + end + cFile:Copy(SrcFileName, DstFileName); + f:write("
  • " .. extra.Title .. "
  • \n"); + else + f:write("
  • " .. extra.Title .. " (file is missing)
  • \n"); + end + end + f:write("
"); + + -- Copy the static files to the output folder (overwrite any existing): + cFile:Copy(g_Plugin:GetLocalFolder() .. "/main.css", "API/main.css"); + cFile:Copy(g_Plugin:GetLocalFolder() .. "/prettify.js", "API/prettify.js"); + cFile:Copy(g_Plugin:GetLocalFolder() .. "/prettify.css", "API/prettify.css"); + cFile:Copy(g_Plugin:GetLocalFolder() .. "/lang-lua.js", "API/lang-lua.js"); + + -- List the documentation problems: + LOG("Listing leftovers..."); + ListUndocumentedObjects(API, UndocumentedHooks); + ListUnexportedObjects(); + ListMissingPages(); + + WriteStats(f); + + f:write([[ +
+ +]]); + f:close(); + + LOG("API subfolder written"); +end + + + + + +function ReadDescriptions(a_API) + -- Returns true if the class of the specified name is to be ignored + local function IsClassIgnored(a_ClsName) + if (g_APIDesc.IgnoreClasses == nil) then + return false; + end + for i, name in ipairs(g_APIDesc.IgnoreClasses) do + if (a_ClsName:match(name)) then + return true; + end + end + return false; + end + + -- Returns true if the function is to be ignored + local function IsFunctionIgnored(a_ClassName, a_FnName) + if (g_APIDesc.IgnoreFunctions == nil) then + return false; + end + if (((g_APIDesc.Classes[a_ClassName] or {}).Functions or {})[a_FnName] ~= nil) then + -- The function is documented, don't ignore + return false; + end + local FnName = a_ClassName .. "." .. a_FnName; + for i, name in ipairs(g_APIDesc.IgnoreFunctions) do + if (FnName:match(name)) then + return true; + end + end + return false; + end + + -- Returns true if the constant (specified by its fully qualified name) is to be ignored + local function IsConstantIgnored(a_CnName) + if (g_APIDesc.IgnoreConstants == nil) then + return false; + end; + for i, name in ipairs(g_APIDesc.IgnoreConstants) do + if (a_CnName:match(name)) then + return true; + end + end + return false; + end + + -- Returns true if the member variable (specified by its fully qualified name) is to be ignored + local function IsVariableIgnored(a_VarName) + if (g_APIDesc.IgnoreVariables == nil) then + return false; + end; + for i, name in ipairs(g_APIDesc.IgnoreVariables) do + if (a_VarName:match(name)) then + return true; + end + end + return false; + end + + -- Remove ignored classes from a_API: + local APICopy = {}; + for i, cls in ipairs(a_API) do + if not(IsClassIgnored(cls.Name)) then + table.insert(APICopy, cls); + end + end + for i = 1, #a_API do + a_API[i] = APICopy[i]; + end; + + -- Process the documentation for each class: + for i, cls in ipairs(a_API) do + -- Initialize default values for each class: + cls.ConstantGroups = {}; + cls.NumConstantsInGroups = 0; + cls.NumConstantsInGroupsForDescendants = 0; + + -- Rename special functions: + for j, fn in ipairs(cls.Functions) do + if (fn.Name == ".call") then + fn.DocID = "constructor"; + fn.Name = "() (constructor)"; + elseif (fn.Name == ".add") then + fn.DocID = "operator_plus"; + fn.Name = "operator +"; + elseif (fn.Name == ".div") then + fn.DocID = "operator_div"; + fn.Name = "operator /"; + elseif (fn.Name == ".mul") then + fn.DocID = "operator_mul"; + fn.Name = "operator *"; + elseif (fn.Name == ".sub") then + fn.DocID = "operator_sub"; + fn.Name = "operator -"; + elseif (fn.Name == ".eq") then + fn.DocID = "operator_eq"; + fn.Name = "operator =="; + end + end + + local APIDesc = g_APIDesc.Classes[cls.Name]; + if (APIDesc ~= nil) then + APIDesc.IsExported = true; + cls.Desc = APIDesc.Desc; + cls.AdditionalInfo = APIDesc.AdditionalInfo; + + -- Process inheritance: + if (APIDesc.Inherits ~= nil) then + for j, icls in ipairs(a_API) do + if (icls.Name == APIDesc.Inherits) then + table.insert(icls.Descendants, cls); + cls.Inherits = icls; + end + end + end + + cls.UndocumentedFunctions = {}; -- This will contain names of all the functions that are not documented + cls.UndocumentedConstants = {}; -- This will contain names of all the constants that are not documented + cls.UndocumentedVariables = {}; -- This will contain names of all the variables that are not documented + + local DoxyFunctions = {}; -- This will contain all the API functions together with their documentation + + local function AddFunction(a_Name, a_Params, a_Return, a_Notes) + table.insert(DoxyFunctions, {Name = a_Name, Params = a_Params, Return = a_Return, Notes = a_Notes}); + end + + if (APIDesc.Functions ~= nil) then + -- Assign function descriptions: + for j, func in ipairs(cls.Functions) do + local FnName = func.DocID or func.Name; + local FnDesc = APIDesc.Functions[FnName]; + if (FnDesc == nil) then + -- No description for this API function + AddFunction(func.Name); + if not(IsFunctionIgnored(cls.Name, FnName)) then + table.insert(cls.UndocumentedFunctions, FnName); + end + else + -- Description is available + if (FnDesc[1] == nil) then + -- Single function definition + AddFunction(func.Name, FnDesc.Params, FnDesc.Return, FnDesc.Notes); + else + -- Multiple function overloads + for k, desc in ipairs(FnDesc) do + AddFunction(func.Name, desc.Params, desc.Return, desc.Notes); + end -- for k, desc - FnDesc[] + end + FnDesc.IsExported = true; + end + end -- for j, func + + -- Replace functions with their described and overload-expanded versions: + cls.Functions = DoxyFunctions; + else -- if (APIDesc.Functions ~= nil) + for j, func in ipairs(cls.Functions) do + local FnName = func.DocID or func.Name; + if not(IsFunctionIgnored(cls.Name, FnName)) then + table.insert(cls.UndocumentedFunctions, FnName); + end + end + end -- if (APIDesc.Functions ~= nil) + + if (APIDesc.Constants ~= nil) then + -- Assign constant descriptions: + for j, cons in ipairs(cls.Constants) do + local CnDesc = APIDesc.Constants[cons.Name]; + if (CnDesc == nil) then + -- Not documented + if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then + table.insert(cls.UndocumentedConstants, cons.Name); + end + else + cons.Notes = CnDesc.Notes; + CnDesc.IsExported = true; + end + end -- for j, cons + else -- if (APIDesc.Constants ~= nil) + for j, cons in ipairs(cls.Constants) do + if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then + table.insert(cls.UndocumentedConstants, cons.Name); + end + end + end -- else if (APIDesc.Constants ~= nil) + + -- Assign member variables' descriptions: + if (APIDesc.Variables ~= nil) then + for j, var in ipairs(cls.Variables) do + local VarDesc = APIDesc.Variables[var.Name]; + if (VarDesc == nil) then + -- Not documented + if not(IsVariableIgnored(cls.Name .. "." .. var.Name)) then + table.insert(cls.UndocumentedVariables, var.Name); + end + else + -- Copy all documentation: + for k, v in pairs(VarDesc) do + var[k] = v + end + end + end -- for j, var + else -- if (APIDesc.Variables ~= nil) + for j, var in ipairs(cls.Variables) do + if not(IsVariableIgnored(cls.Name .. "." .. var.Name)) then + table.insert(cls.UndocumentedVariables, var.Name); + end + end + end -- else if (APIDesc.Variables ~= nil) + + if (APIDesc.ConstantGroups ~= nil) then + -- Create links between the constants and the groups: + local NumInGroups = 0; + local NumInDescendantGroups = 0; + for j, group in pairs(APIDesc.ConstantGroups) do + group.Name = j; + group.Constants = {}; + if (type(group.Include == "string")) then + group.Include = { group.Include }; + end + local NumInGroup = 0; + for idx, incl in ipairs(group.Include or {}) do + for cidx, cons in ipairs(cls.Constants) do + if ((cons.Group == nil) and cons.Name:match(incl)) then + cons.Group = group; + table.insert(group.Constants, cons); + NumInGroup = NumInGroup + 1; + end + end -- for cidx - cls.Constants[] + end -- for idx - group.Include[] + NumInGroups = NumInGroups + NumInGroup; + if (group.ShowInDescendants) then + NumInDescendantGroups = NumInDescendantGroups + NumInGroup; + end + + -- Sort the constants: + table.sort(group.Constants, + function(c1, c2) + return (c1.Name < c2.Name); + end + ); + end -- for j - APIDesc.ConstantGroups[] + cls.ConstantGroups = APIDesc.ConstantGroups; + cls.NumConstantsInGroups = NumInGroups; + cls.NumConstantsInGroupsForDescendants = NumInDescendantGroups; + + -- Remove grouped constants from the normal list: + local NewConstants = {}; + for idx, cons in ipairs(cls.Constants) do + if (cons.Group == nil) then + table.insert(NewConstants, cons); + end + end + cls.Constants = NewConstants; + end -- if (ConstantGroups ~= nil) + + else -- if (APIDesc ~= nil) + + -- Class is not documented at all, add all its members to Undocumented lists: + cls.UndocumentedFunctions = {}; + cls.UndocumentedConstants = {}; + cls.UndocumentedVariables = {}; + cls.Variables = cls.Variables or {}; + g_Stats.NumUndocumentedClasses = g_Stats.NumUndocumentedClasses + 1; + for j, func in ipairs(cls.Functions) do + local FnName = func.DocID or func.Name; + if not(IsFunctionIgnored(cls.Name, FnName)) then + table.insert(cls.UndocumentedFunctions, FnName); + end + end -- for j, func - cls.Functions[] + for j, cons in ipairs(cls.Constants) do + if not(IsConstantIgnored(cls.Name .. "." .. cons.Name)) then + table.insert(cls.UndocumentedConstants, cons.Name); + end + end -- for j, cons - cls.Constants[] + for j, var in ipairs(cls.Variables) do + if not(IsConstantIgnored(cls.Name .. "." .. var.Name)) then + table.insert(cls.UndocumentedVariables, var.Name); + end + end -- for j, var - cls.Variables[] + end -- else if (APIDesc ~= nil) + + -- Remove ignored functions: + local NewFunctions = {}; + for j, fn in ipairs(cls.Functions) do + if (not(IsFunctionIgnored(cls.Name, fn.Name))) then + table.insert(NewFunctions, fn); + end + end -- for j, fn + cls.Functions = NewFunctions; + + -- Sort the functions (they may have been renamed): + table.sort(cls.Functions, + function(f1, f2) + if (f1.Name == f2.Name) then + -- Same name, either comparing the same function to itself, or two overloads, in which case compare the params + if ((f1.Params == nil) or (f2.Params == nil)) then + return 0; + end + return (f1.Params < f2.Params); + end + return (f1.Name < f2.Name); + end + ); + + -- Sort the constants: + table.sort(cls.Constants, + function(c1, c2) + return (c1.Name < c2.Name); + end + ); + + -- Remove ignored functions: + local NewVariables = {}; + for j, var in ipairs(cls.Variables) do + if (not(IsVariableIgnored(cls.Name .. "." .. var.Name))) then + table.insert(NewVariables, var); + end + end -- for j, var + cls.Variables = NewVariables; + + -- Sort the member variables: + table.sort(cls.Variables, + function(v1, v2) + return (v1.Name < v2.Name); + end + ); + end -- for i, cls + + -- Sort the descendants lists: + for i, cls in ipairs(a_API) do + table.sort(cls.Descendants, + function(c1, c2) + return (c1.Name < c2.Name); + end + ); + end -- for i, cls +end + + + + + +function ReadHooks(a_Hooks) + --[[ + a_Hooks = { + { Name = "HOOK_1"}, + { Name = "HOOK_2"}, + ... + }; + We want to add hook descriptions to each hook in this array + --]] + for i, hook in ipairs(a_Hooks) do + local HookDesc = g_APIDesc.Hooks[hook.Name]; + if (HookDesc ~= nil) then + for key, val in pairs(HookDesc) do + hook[key] = val; + end + end + end -- for i, hook - a_Hooks[] + g_Stats.NumTotalHooks = #a_Hooks; +end + + + + + +-- Make a link out of anything with the special linkifying syntax {{link|title}} +function LinkifyString(a_String, a_Referrer) + assert(a_Referrer ~= nil); + assert(a_Referrer ~= ""); + + --- Adds a page to the list of tracked pages (to be checked for existence at the end) + local function AddTrackedPage(a_PageName) + local Pg = (g_TrackedPages[a_PageName] or {}); + table.insert(Pg, a_Referrer); + g_TrackedPages[a_PageName] = Pg; + end + + --- Creates the HTML for the specified link and title + local function CreateLink(Link, Title) + if (Link:sub(1, 7) == "http://") then + -- The link is a full absolute URL, do not modify, do not track: + return "" .. Title .. ""; + end + local idxHash = Link:find("#"); + if (idxHash ~= nil) then + -- The link contains an anchor: + if (idxHash == 1) then + -- Anchor in the current page, no need to track: + return "" .. Title .. ""; + end + -- Anchor in another page: + local PageName = Link:sub(1, idxHash - 1); + AddTrackedPage(PageName); + return "" .. Title .. ""; + end + -- Link without anchor: + AddTrackedPage(Link); + return "" .. Title .. ""; + end + + -- Linkify the strings using the CreateLink() function: + local txt = a_String:gsub("{{([^|}]*)|([^}]*)}}", CreateLink) -- {{link|title}} + txt = txt:gsub("{{([^|}]*)}}", -- {{LinkAndTitle}} + function(LinkAndTitle) + local idxHash = LinkAndTitle:find("#"); + if (idxHash ~= nil) then + -- The LinkAndTitle contains a hash, remove the hashed part from the title: + return CreateLink(LinkAndTitle, LinkAndTitle:sub(1, idxHash - 1)); + end + return CreateLink(LinkAndTitle, LinkAndTitle); + end + ); + return txt; +end + + + + + +function WriteHtmlClass(a_ClassAPI, a_AllAPI) + local cf, err = io.open("API/" .. a_ClassAPI.Name .. ".html", "w"); + if (cf == nil) then + return; + end + + -- Writes a table containing all functions in the specified list, with an optional "inherited from" header when a_InheritedName is valid + local function WriteFunctions(a_Functions, a_InheritedName) + if (#a_Functions == 0) then + return; + end + + if (a_InheritedName ~= nil) then + cf:write("

Functions inherited from ", a_InheritedName, "

\n"); + end + cf:write(" \n \n \n \n \n \n \n"); + for i, func in ipairs(a_Functions) do + cf:write(" \n \n"); + cf:write(" \n"); + cf:write(" \n"); + cf:write(" \n \n"); + end + cf:write("
NameParametersReturn valueNotes
" .. func.Name .. "", LinkifyString(func.Params or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Return or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Notes or "(undocumented)", (a_InheritedName or a_ClassAPI.Name)), "
\n\n"); + end + + local function WriteConstantTable(a_Constants, a_Source) + cf:write("\n\n"); + for i, cons in ipairs(a_Constants) do + cf:write("\n"); + cf:write("\n"); + cf:write("\n"); + end + cf:write("
NameValueNotes
", cons.Name, "", cons.Value, "", LinkifyString(cons.Notes or "", a_Source), "
\n\n"); + end + + local function WriteConstants(a_Constants, a_ConstantGroups, a_NumConstantGroups, a_InheritedName) + if ((#a_Constants == 0) and (a_NumConstantGroups == 0)) then + return; + end + + if (a_InheritedName ~= nil) then + cf:write("

Constants inherited from ", a_InheritedName, "

\n"); + end + + if (#a_Constants > 0) then + WriteConstantTable(a_Constants, a_InheritedName or a_ClassAPI.Name); + end + + for k, group in pairs(a_ConstantGroups) do + if ((a_InheritedName == nil) or group.ShowInDescendants) then + cf:write("

"); + cf:write(group.TextBefore or ""); + WriteConstantTable(group.Constants, a_InheritedName or a_ClassAPI.Name); + cf:write(group.TextAfter or "", "

"); + end + end + end + + local function WriteVariables(a_Variables, a_InheritedName) + if (#a_Variables == 0) then + return; + end + + if (a_InheritedName ~= nil) then + cf:write("

Member variables inherited from ", a_InheritedName, "

\n"); + end + + cf:write(" \n \n \n \n \n \n"); + for i, var in ipairs(a_Variables) do + cf:write(" \n \n"); + cf:write(" \n"); + cf:write(" \n \n"); + end + cf:write("
NameTypeNotes
", var.Name, "", LinkifyString(var.Type or "(undocumented)", a_InheritedName or a_ClassAPI.Name), "", LinkifyString(var.Notes or "", a_InheritedName or a_ClassAPI.Name), "
\n\n"); + end + + local function WriteDescendants(a_Descendants) + if (#a_Descendants == 0) then + return; + end + cf:write("
    "); + for i, desc in ipairs(a_Descendants) do + cf:write("
  • ", desc.Name, ""); + WriteDescendants(desc.Descendants); + cf:write("
  • \n"); + end + cf:write("
\n"); + end + + local ClassName = a_ClassAPI.Name; + + -- Build an array of inherited classes chain: + local InheritanceChain = {}; + local CurrInheritance = a_ClassAPI.Inherits; + while (CurrInheritance ~= nil) do + table.insert(InheritanceChain, CurrInheritance); + CurrInheritance = CurrInheritance.Inherits; + end + + cf:write([[ + + + MCServer API - ]], a_ClassAPI.Name, [[ Class + + + + + + +
+
+

]], a_ClassAPI.Name, [[

+
+
+

Contents

+ +
    +]]); + + local HasInheritance = ((#a_ClassAPI.Descendants > 0) or (a_ClassAPI.Inherits ~= nil)); + + local HasConstants = (#a_ClassAPI.Constants > 0) or (a_ClassAPI.NumConstantsInGroups > 0); + local HasFunctions = (#a_ClassAPI.Functions > 0); + local HasVariables = (#a_ClassAPI.Variables > 0); + for idx, cls in ipairs(InheritanceChain) do + HasConstants = HasConstants or (#cls.Constants > 0) or (cls.NumConstantsInGroupsForDescendants > 0); + HasFunctions = HasFunctions or (#cls.Functions > 0); + HasVariables = HasVariables or (#cls.Variables > 0); + end + + -- Write the table of contents: + if (HasInheritance) then + cf:write("
  • Inheritance
  • \n"); + end + if (HasConstants) then + cf:write("
  • Constants
  • \n"); + end + if (HasVariables) then + cf:write("
  • Member variables
  • \n"); + end + if (HasFunctions) then + cf:write("
  • Functions
  • \n"); + end + if (a_ClassAPI.AdditionalInfo ~= nil) then + for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do + cf:write("
  • ", (additional.Header or "(No header)"), "
  • \n"); + end + end + cf:write("
\n\n"); + + -- Write the class description: + cf:write("

" .. ClassName .. " class

\n"); + if (a_ClassAPI.Desc ~= nil) then + cf:write("

"); + cf:write(LinkifyString(a_ClassAPI.Desc, ClassName)); + cf:write("

\n\n"); + end; + + -- Write the inheritance, if available: + if (HasInheritance) then + cf:write(" \n

Inheritance

\n"); + if (#InheritanceChain > 0) then + cf:write("

This class inherits from the following parent classes:

\n\n
    \n"); + for i, cls in ipairs(InheritanceChain) do + cf:write("
  • " .. cls.Name .. "
  • \n"); + end + cf:write("
\n\n"); + end + if (#a_ClassAPI.Descendants > 0) then + cf:write("

This class has the following descendants:\n"); + WriteDescendants(a_ClassAPI.Descendants); + cf:write("

\n\n"); + end + end + + -- Write the constants: + if (HasConstants) then + cf:write("

Constants

\n"); + WriteConstants(a_ClassAPI.Constants, a_ClassAPI.ConstantGroups, a_ClassAPI.NumConstantsInGroups, nil); + g_Stats.NumTotalConstants = g_Stats.NumTotalConstants + #a_ClassAPI.Constants + (a_ClassAPI.NumConstantsInGroups or 0); + for i, cls in ipairs(InheritanceChain) do + WriteConstants(cls.Constants, cls.ConstantGroups, cls.NumConstantsInGroupsForDescendants, cls.Name); + end; + end; + + -- Write the member variables: + if (HasVariables) then + cf:write("

Member variables

\n"); + WriteVariables(a_ClassAPI.Variables, nil); + g_Stats.NumTotalVariables = g_Stats.NumTotalVariables + #a_ClassAPI.Variables; + for i, cls in ipairs(InheritanceChain) do + WriteVariables(cls.Variables, cls.Name); + end; + end + + -- Write the functions, including the inherited ones: + if (HasFunctions) then + cf:write("

Functions

\n"); + WriteFunctions(a_ClassAPI.Functions, nil); + g_Stats.NumTotalFunctions = g_Stats.NumTotalFunctions + #a_ClassAPI.Functions; + for i, cls in ipairs(InheritanceChain) do + WriteFunctions(cls.Functions, cls.Name); + end + end + + -- Write the additional infos: + if (a_ClassAPI.AdditionalInfo ~= nil) then + for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do + cf:write("

", additional.Header, "

\n"); + cf:write(LinkifyString(additional.Contents, ClassName)); + end + end + + cf:write([[ +
+ + + + ]]); + cf:close(); +end + + + + + +function WriteHtmlHook(a_Hook) + local fnam = "API/" .. a_Hook.DefaultFnName .. ".html"; + local f, error = io.open(fnam, "w"); + if (f == nil) then + LOG("Cannot write \"" .. fnam .. "\": \"" .. error .. "\"."); + return; + end + local HookName = a_Hook.DefaultFnName; + + f:write([[ + + + MCServer API - ]] .. HookName .. [[ Hook + + + + + + +
+
+

]] .. a_Hook.Name .. [[

+
+
+

+]]); + f:write(LinkifyString(a_Hook.Desc, HookName)); + f:write("

\n

Callback function

\n

The default name for the callback function is "); + f:write(a_Hook.DefaultFnName .. ". It has the following signature:\n\n"); + f:write("

function " .. HookName .. "(");
+	if (a_Hook.Params == nil) then
+		a_Hook.Params = {};
+	end
+	for i, param in ipairs(a_Hook.Params) do
+		if (i > 1) then
+			f:write(", ");
+		end
+		f:write(param.Name);
+	end
+	f:write(")
\n\n

Parameters:

\n\n \n \n \n \n \n \n"); + for i, param in ipairs(a_Hook.Params) do + f:write(" \n \n \n \n \n"); + end + f:write("
NameTypeNotes
" .. param.Name .. "" .. LinkifyString(param.Type, HookName) .. "" .. LinkifyString(param.Notes, HookName) .. "
\n\n

" .. (a_Hook.Returns or "") .. "

\n\n"); + f:write([[

Code examples

+

Registering the callback

+ +]]); + f:write("
\n");
+	f:write([[cPluginManager.AddHook(cPluginManager.]] .. a_Hook.Name .. ", My" .. a_Hook.DefaultFnName .. [[);]]);
+	f:write("
\n\n"); + local Examples = a_Hook.CodeExamples or {}; + for i, example in ipairs(Examples) do + f:write("

" .. (example.Title or "missing Title") .. "

\n"); + f:write("

" .. (example.Desc or "missing Desc") .. "

\n\n"); + f:write("
" .. (example.Code or "missing Code") .. "\n			
\n\n"); + end + f:write([[
+ + +]]); + f:close(); +end + + + + + +--- Writes a list of undocumented objects into a file +function ListUndocumentedObjects(API, UndocumentedHooks) + f = io.open("API/_undocumented.lua", "w"); + if (f ~= nil) then + f:write("\n-- This is the list of undocumented API objects, automatically generated by APIDump\n\n"); + f:write("g_APIDesc =\n{\n\tClasses =\n\t{\n"); + for i, cls in ipairs(API) do + local HasFunctions = ((cls.UndocumentedFunctions ~= nil) and (#cls.UndocumentedFunctions > 0)); + local HasConstants = ((cls.UndocumentedConstants ~= nil) and (#cls.UndocumentedConstants > 0)); + local HasVariables = ((cls.UndocumentedVariables ~= nil) and (#cls.UndocumentedVariables > 0)); + g_Stats.NumUndocumentedFunctions = g_Stats.NumUndocumentedFunctions + #cls.UndocumentedFunctions; + g_Stats.NumUndocumentedConstants = g_Stats.NumUndocumentedConstants + #cls.UndocumentedConstants; + g_Stats.NumUndocumentedVariables = g_Stats.NumUndocumentedVariables + #cls.UndocumentedVariables; + if (HasFunctions or HasConstants or HasVariables) then + f:write("\t\t" .. cls.Name .. " =\n\t\t{\n"); + if ((cls.Desc == nil) or (cls.Desc == "")) then + f:write("\t\t\tDesc = \"\"\n"); + end + end + + if (HasFunctions) then + f:write("\t\t\tFunctions =\n\t\t\t{\n"); + table.sort(cls.UndocumentedFunctions); + for j, fn in ipairs(cls.UndocumentedFunctions) do + f:write("\t\t\t\t" .. fn .. " = { Params = \"\", Return = \"\", Notes = \"\" },\n"); + end -- for j, fn - cls.UndocumentedFunctions[] + f:write("\t\t\t},\n\n"); + end + + if (HasConstants) then + f:write("\t\t\tConstants =\n\t\t\t{\n"); + table.sort(cls.UndocumentedConstants); + for j, cn in ipairs(cls.UndocumentedConstants) do + f:write("\t\t\t\t" .. cn .. " = { Notes = \"\" },\n"); + end -- for j, fn - cls.UndocumentedConstants[] + f:write("\t\t\t},\n\n"); + end + + if (HasVariables) then + f:write("\t\t\tVariables =\n\t\t\t{\n"); + table.sort(cls.UndocumentedVariables); + for j, vn in ipairs(cls.UndocumentedVariables) do + f:write("\t\t\t\t" .. vn .. " = { Type = \"\", Notes = \"\" },\n"); + end -- for j, fn - cls.UndocumentedVariables[] + f:write("\t\t\t},\n\n"); + end + + if (HasFunctions or HasConstants or HasVariables) then + f:write("\t\t},\n\n"); + end + end -- for i, cls - API[] + f:write("\t},\n"); + + if (#UndocumentedHooks > 0) then + f:write("\n\tHooks =\n\t{\n"); + for i, hook in ipairs(UndocumentedHooks) do + if (i > 1) then + f:write("\n"); + end + f:write("\t\t" .. hook .. " =\n\t\t{\n"); + f:write("\t\t\tCalledWhen = \"\",\n"); + f:write("\t\t\tDefaultFnName = \"On\", -- also used as pagename\n"); + f:write("\t\t\tDesc = [[\n\t\t\t\t\n\t\t\t]],\n"); + f:write("\t\t\tParams =\n\t\t\t{\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t\t{ Name = \"\", Type = \"\", Notes = \"\" },\n"); + f:write("\t\t\t},\n"); + f:write("\t\t\tReturns = [[\n\t\t\t\t\n\t\t\t]],\n"); + f:write("\t\t}, -- " .. hook .. "\n"); + end + f:write("\t},\n"); + end + f:write("}\n\n\n\n"); + f:close(); + end + g_Stats.NumUndocumentedHooks = #UndocumentedHooks; +end + + + + + +--- Lists the API objects that are documented but not available in the API: +function ListUnexportedObjects() + f = io.open("API/_unexported-documented.txt", "w"); + if (f ~= nil) then + for clsname, cls in pairs(g_APIDesc.Classes) do + if not(cls.IsExported) then + -- The whole class is not exported + f:write("class\t" .. clsname .. "\n"); + else + if (cls.Functions ~= nil) then + for fnname, fnapi in pairs(cls.Functions) do + if not(fnapi.IsExported) then + f:write("func\t" .. clsname .. "." .. fnname .. "\n"); + end + end -- for j, fn - cls.Functions[] + end + if (cls.Constants ~= nil) then + for cnname, cnapi in pairs(cls.Constants) do + if not(cnapi.IsExported) then + f:write("const\t" .. clsname .. "." .. cnname .. "\n"); + end + end -- for j, fn - cls.Functions[] + end + end + end -- for i, cls - g_APIDesc.Classes[] + f:close(); + end +end + + + + + +function ListMissingPages() + local MissingPages = {}; + local NumLinks = 0; + for PageName, Referrers in pairs(g_TrackedPages) do + NumLinks = NumLinks + 1; + if not(cFile:Exists("API/" .. PageName .. ".html")) then + table.insert(MissingPages, {Name = PageName, Refs = Referrers} ); + end + end; + g_Stats.NumTrackedLinks = NumLinks; + g_TrackedPages = {}; + + if (#MissingPages == 0) then + -- No missing pages, congratulations! + return; + end + + -- Sort the pages by name: + table.sort(MissingPages, + function (Page1, Page2) + return (Page1.Name < Page2.Name); + end + ); + + -- Output the pages: + local f, err = io.open("API/_missingPages.txt", "w"); + if (f == nil) then + LOGWARNING("Cannot open _missingPages.txt for writing: '" .. err .. "'. There are " .. #MissingPages .. " pages missing."); + return; + end + for idx, pg in ipairs(MissingPages) do + f:write(pg.Name .. ":\n"); + -- Sort and output the referrers: + table.sort(pg.Refs); + f:write("\t" .. table.concat(pg.Refs, "\n\t")); + f:write("\n\n"); + end + f:close(); + g_Stats.NumInvalidLinks = #MissingPages; +end + + + + + +--- Writes the documentation statistics (in g_Stats) into the given HTML file +function WriteStats(f) + local function ExportMeter(a_Percent) + local Color; + if (a_Percent > 99) then + Color = "green"; + elseif (a_Percent > 50) then + Color = "orange"; + else + Color = "red"; + end + + local meter = { + "\n", + "
\n", + "
\n", + string.format("%.2f", a_Percent), + " %", + }; + return table.concat(meter, ""); + end + + f:write([[ +

Documentation statistics

+ + ]]); + f:write("\n"); + + f:write("\n"); + + f:write("\n"); + + f:write("\n"); + + f:write("\n"); + + f:write([[ +
ObjectTotalDocumentedUndocumentedDocumented %
Classes", g_Stats.NumTotalClasses); + f:write("", g_Stats.NumTotalClasses - g_Stats.NumUndocumentedClasses); + f:write("", g_Stats.NumUndocumentedClasses); + f:write("", ExportMeter(100 * (g_Stats.NumTotalClasses - g_Stats.NumUndocumentedClasses) / g_Stats.NumTotalClasses)); + f:write("
Functions", g_Stats.NumTotalFunctions); + f:write("", g_Stats.NumTotalFunctions - g_Stats.NumUndocumentedFunctions); + f:write("", g_Stats.NumUndocumentedFunctions); + f:write("", ExportMeter(100 * (g_Stats.NumTotalFunctions - g_Stats.NumUndocumentedFunctions) / g_Stats.NumTotalFunctions)); + f:write("
Member variables", g_Stats.NumTotalVariables); + f:write("", g_Stats.NumTotalVariables - g_Stats.NumUndocumentedVariables); + f:write("", g_Stats.NumUndocumentedVariables); + f:write("", ExportMeter(100 * (g_Stats.NumTotalVariables - g_Stats.NumUndocumentedVariables) / g_Stats.NumTotalVariables)); + f:write("
Constants", g_Stats.NumTotalConstants); + f:write("", g_Stats.NumTotalConstants - g_Stats.NumUndocumentedConstants); + f:write("", g_Stats.NumUndocumentedConstants); + f:write("", ExportMeter(100 * (g_Stats.NumTotalConstants - g_Stats.NumUndocumentedConstants) / g_Stats.NumTotalConstants)); + f:write("
Hooks", g_Stats.NumTotalHooks); + f:write("", g_Stats.NumTotalHooks - g_Stats.NumUndocumentedHooks); + f:write("", g_Stats.NumUndocumentedHooks); + f:write("", ExportMeter(100 * (g_Stats.NumTotalHooks - g_Stats.NumUndocumentedHooks) / g_Stats.NumTotalHooks)); + f:write("
+

There are ]], g_Stats.NumTrackedLinks, " internal links, ", g_Stats.NumInvalidLinks, " of them are invalid.

" + ); +end + + + + -- cgit v1.2.3 From b8aaf13a1270a1ffb998a63888c457f53178653d Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 22 Nov 2013 22:12:46 +0100 Subject: APIDump: Added a few constant groups to the descriptions. --- MCServer/Plugins/APIDump/APIDesc.lua | 170 ++++++++++++++++------------------- 1 file changed, 78 insertions(+), 92 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 5489650ad..28ed9b9d4 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -322,9 +322,6 @@ g_APIDesc = GetRelZ = { Params = "", Return = "number", Notes = "Returns the relative Z coord of the block entity's block within the chunk" }, GetWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world to which the block entity belongs" }, }, - Constants = - { - }, }, cBlockEntityWithItems = @@ -353,9 +350,6 @@ g_APIDesc = { Params = "X, Y, {{cItem|cItem}}", Return = "", Notes = "Sets the cItem for the specified slot coords. Ignored if invalid slot coords" }, }, }, - Constants = - { - }, }, cBoundingBox = @@ -395,7 +389,6 @@ g_APIDesc = }, Union = { Params = "OtherBoundingBox", Return = "cBoundingBox", Notes = "Returns the smallest bounding box that contains both OtherBoundingBox and this bounding box. Note that unlike the strict geometrical meaning of \"union\", this operation actually returns a cBoundingBox." }, }, - Constants = {}, }, cChatColor = @@ -535,9 +528,6 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(), SetUseDefaultStructures = { Params = "bool", Return = "", Notes = "Sets the chunk to use default structures or not" }, WriteBlockArea = { Params = "{{cBlockArea|BlockArea}}, MinRelX, MinRelY, MinRelZ", Return = "", Notes = "Writes data from the block area into the chunk" }, }, - Constants = - { - }, AdditionalInfo = { { @@ -600,7 +590,7 @@ end MAX_VIEW_DISTANCE = { Notes = "The maximum value of the view distance" }, MIN_VIEW_DISTANCE = { Notes = "The minimum value of the view distance" }, }, - }, + }, -- cClientHandle cCraftingGrid = { @@ -630,10 +620,7 @@ end { Params = "x, y, ItemType, ItemCount, ItemDamage", Return = "", Notes = "Sets the item at the specified coords" }, }, }, - Constants = - { - }, - }, + }, -- cCraftingGrid cCraftingRecipe = { @@ -662,10 +649,7 @@ end { Params = "ItemType, ItemCount, ItemDamage", Return = "", Notes = "Sets the result item" }, }, }, - Constants = - { - }, - }, + }, -- cCraftingRecipe cCuboid = { @@ -707,7 +691,7 @@ end p1 = { Type = "{{Vector3i}}", Notes = "The first corner. Usually the lesser of the two coords in each set" }, p2 = { Type = "{{Vector3i}}", Notes = "The second corner. Usually the larger of the two coords in each set" }, }, - }, + }, -- cCuboid cDispenserEntity = { @@ -1000,14 +984,15 @@ cFile:Delete("/usr/bin/virus.exe"); { Desc = "", Functions = {}, - Constants = {}, Inherits = "cProjectileEntity", } , cFurnaceEntity = { Desc = [[ - This class represents a furnace block entity in the world. + This class represents a furnace block entity in the world.

+

+ See also {{cRoot}}'s GetFurnaceRecipe() and GetFurnaceFuelBurnTime() functions ]], Functions = { @@ -1024,27 +1009,36 @@ cFile:Delete("/usr/bin/virus.exe"); }, Constants = { - fsInput = { Notes = "Index of the input slot, when using the GetSlot() / SetSlot() functions" }, - fsFuel = { Notes = "Index of the fuel slot, when using the GetSlot() / SetSlot() functions" }, - fsOutput = { Notes = "Index of the output slot, when using the GetSlot() / SetSlot() functions" }, + fsInput = { Notes = "Index of the input slot" }, + fsFuel = { Notes = "Index of the fuel slot" }, + fsOutput = { Notes = "Index of the output slot" }, ContentsWidth = { Notes = "Width (X) of the {{cItemGrid|cItemGrid}} representing the contents" }, ContentsHeight = { Notes = "Height (Y) of the {{cItemGrid|cItemGrid}} representing the contents" }, }, + ConstantGroups = + { + SlotIndices = + { + Include = "fs.*", + TextBefore = "When using the GetSlot() or SetSlot() function, use these constants for slot index:", + }, + }, Inherits = "cBlockEntityWithItems" - }, + }, -- cFurnaceEntity cGhastFireballEntity = { Desc = "", Functions = {}, - Constants = {}, Inherits = "cProjectileEntity", - } , + }, -- cGhastFireballEntity cGroup = { - Desc = [[cGroup is a group {{cPlayer|cPlayer}}'s can be in. Groups define the permissions players have, and optionally the color of their name in the chat. -]], + Desc = [[ + This class represents a group {{cPlayer|players}} can be in. Groups define the permissions players + have, and optionally the color of their name in the chat. + ]], Functions = { SetName = { Return = "" }, @@ -1056,10 +1050,7 @@ cFile:Delete("/usr/bin/virus.exe"); AddPermission = { Return = "" }, InheritFrom = { Return = "" }, }, - Constants = - { - }, - }, + }, -- cGroup cHopperEntity = { @@ -1077,7 +1068,7 @@ cFile:Delete("/usr/bin/virus.exe"); TICKS_PER_TRANSFER = { Notes = "Number of ticks between when the hopper transfers items." }, }, Inherits = "cBlockEntityWithItems", - }, + }, -- cHopperEntity cIniFile = { @@ -1287,6 +1278,16 @@ These ItemGrids are available in the API and can be manipulated by the plugins, invHotbarOffset = { Notes = "Starting slot number of the Hotbar part" }, invNumSlots = { Notes = "Total number of slots in a cInventory" }, }, + ConstantGroups = + { + SlotIndices = + { + Include = "inv.*", + TextBefore = [[ + Rather than hardcoding numbers, use the following constants for slot indices and counts: + ]], + }, + }, }, -- cInventory cItem = @@ -1448,9 +1449,6 @@ local Item5 = cItem(E_ITEM_DIAMOND_CHESTPLATE, 1, 0, "thorns=1;unbreaking=3"); { Params = "X, Y, {{cItem|cItem}}", Return = "", Notes = "Sets the specified slot to the specified item" }, }, }, - Constants = - { - }, AdditionalInfo = { { @@ -1512,9 +1510,6 @@ end }, Size = { Params = "", Return = "number", Notes = "Returns the number of items in the collection" }, }, - Constants = - { - }, }, -- cItems cJukeboxEntity = @@ -1641,9 +1636,6 @@ end SetOnClosing = { Params = "OnClosingCallback", Return = "", Notes = "Sets the function that the window will call when it is about to be closed by a player" }, SetOnSlotChanged = { Params = "OnSlotChangedCallback", Return = "", Notes = "Sets the function that the window will call when a slot is changed by a player" }, }, - Constants = - { - }, AdditionalInfo = { { @@ -1718,12 +1710,12 @@ a_Player:OpenWindow(Window); ]], Functions = { - FamilyFromType = { Params = "MobType", Return = "MobFamily", Notes = "(STATIC) Returns the mob family (mfXXX constants) based on the mob type (mtXXX constants)" }, - GetMobFamily = { Params = "", Return = "MobFamily", Notes = "Returns this mob's family (mfXXX constant)" }, - GetMobType = { Params = "", Return = "MobType", Notes = "Returns the type of this mob (mtXXX constant)" }, - GetSpawnDelay = { Params = "MobFamily", Return = "number", Notes = "(STATIC) Returns the spawn delay - the number of game ticks between spawn attempts - for the specified mob family." }, - MobTypeToString = { Params = "MobType", Return = "string", Notes = "(STATIC) Returns the string representing the given mob type (mtXXX constant), or empty string if unknown type." }, - StringToMobType = { Params = "string", Return = "MobType", Notes = "(STATIC) Returns the mob type (mtXXX constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." }, + FamilyFromType = { Params = "{{cMonster#MobType|MobType}}", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "(STATIC) Returns the mob family ({{cMonster#MobFamily|mfXXX}} constants) based on the mob type ({{cMonster#MobType|mtXXX}} constants)" }, + GetMobFamily = { Params = "", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "Returns this mob's family ({{cMonster#MobFamily|mfXXX}} constant)" }, + GetMobType = { Params = "", Return = "{{cMonster#MobType|MobType}}", Notes = "Returns the type of this mob ({{cMonster#MobType|mtXXX}} constant)" }, + GetSpawnDelay = { Params = "{{cMonster#MobFamily|MobFamily}}", Return = "number", Notes = "(STATIC) Returns the spawn delay - the number of game ticks between spawn attempts - for the specified mob family." }, + MobTypeToString = { Params = "{{cMonster#MobType|MobType}}", Return = "string", Notes = "(STATIC) Returns the string representing the given mob type ({{cMonster#MobType|mtXXX}} constant), or empty string if unknown type." }, + StringToMobType = { Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "(STATIC) Returns the mob type ({{cMonster#MobType|mtXXX}} constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." }, }, Constants = { @@ -1763,6 +1755,23 @@ a_Player:OpenWindow(Window); mtZombie = { Notes = "" }, mtZombiePigman = { Notes = "" }, }, + ConstantGroups = + { + MobFamily = + { + Include = "mf.*", + TextBefore = [[ + Mobs are divided into families. The following constants are used for individual family types: + ]], + }, + MobType = + { + Include = "mt.*", + TextBefore = [[ + The following constants are used for distinguishing between the individual mob types: + ]], + }, + }, Inherits = "cPawn", }, -- cMonster @@ -1798,11 +1807,8 @@ a_Player:OpenWindow(Window); KilledBy = { Return = "" }, GetHealth = { Return = "number" }, }, - Constants = - { - }, Inherits = "cEntity", - }, + }, -- cPawn cPickup = { @@ -1914,7 +1920,7 @@ a_Player:OpenWindow(Window); MAX_HEALTH = { Notes = "The maximum health value" }, }, Inherits = "cPawn", - }, + }, -- cPlayer cPlugin = { @@ -1933,18 +1939,14 @@ a_Player:OpenWindow(Window); GetFileName = { Return = "string" }, CreateWebPlugin = { Notes = "{{cWebPlugin|cWebPlugin}}" }, }, - Constants = - { - }, - }, + }, -- cPlugin cPluginLua = { Desc = "", Functions = {}, - Constants = {}, Inherits = "cPlugin", - }, + }, -- cPluginLua cPluginManager = { @@ -2121,9 +2123,6 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); SaveAllChunks = { Params = "", Return = "", Notes = "Saves all the chunks in all the worlds. Note that the saving is queued on each world's tick thread and this functions returns before the chunks are actually saved." }, SetPrimaryServerVersion = { Params = "Protocol Version", Return = "", Notes = "Sets the servers PrimaryServerVersion to the given protocol number." } }, - Constants = - { - }, AdditionalInfo = { { @@ -2169,9 +2168,6 @@ end GetServerID = { Return = "string", Notes = "Returns the ID of the server?" }, IsHardcore = { Params = "", Return = "bool", Notes = "Returns true if the server is hardcore (players get banned on death)." }, }, - Constants = - { - }, }, -- cServer cSignEntity = @@ -2193,39 +2189,37 @@ end { Desc = "", Functions = {}, - Constants = {}, Inherits = "cProjectileEntity", - }, + }, -- cThrownEggEntity cThrownEnderPearlEntity = { Desc = "", Functions = {}, - Constants = {}, Inherits = "cProjectileEntity", - }, + }, -- cThrownEnderPearlEntity cThrownSnowballEntity = { Desc = "", Functions = {}, - Constants = {}, Inherits = "cProjectileEntity", - }, + }, -- cThrownSnowballEntity cTracer = { - Desc = [[A cTracer object is used to trace lines in the world. One thing you can use the cTracer for, is tracing what block a player is looking at, but you can do more with it if you want. -

-

The cTracer is still a work in progress -]], + Desc = [[ + A cTracer object is used to trace lines in the world. One thing you can use the cTracer for, is + tracing what block a player is looking at, but you can do more with it if you want.

+

+ The cTracer is still a work in progress.

+

+ See also the {{cLineBlockTracer}} class for an alternative approach using callbacks. + ]], Functions = { }, - Constants = - { - }, - }, + }, -- cTracer cWebAdmin = { @@ -2234,15 +2228,13 @@ end { GetHTMLEscapedString = { Params = "string", Return = "string", Notes = "Gets the HTML escaped representation of a requested string. This is useful for user input and game data that is not guaranteed to be escaped already." }, }, - Constants = {}, - }, + }, -- cWebAdmin cWebPlugin = { Desc = "", Functions = {}, - Constants = {}, - }, + }, -- cWebPlugin cWindow = { @@ -2437,9 +2429,6 @@ end WakeUpSimulators = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Wakes up the simulators for the specified block." }, WakeUpSimulatorsInArea = { Params = "MinBlockX, MaxBlockX, MinBlockY, MaxBlockY, MinBlockZ, MaxBlockZ", Return = "", Notes = "Wakes up the simulators for all the blocks in the specified area (edges inclusive)." }, }, - Constants = - { - }, AdditionalInfo = { { @@ -2908,10 +2897,7 @@ end TrimString = {Params = "string", Return = "string", Notes = "Trime whitespace at both ends of the string"}, md5 = {Params = "string", Return = "string", Notes = "converts a string to an md5 hash"}, }, - Constants = - { - }, - }, + }, -- Globals }, -- cgit v1.2.3 From 520088fc7c71818bb0988063a19e45b3577541d5 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 23 Nov 2013 19:40:35 +0100 Subject: APIDump: Added more constant groups. Also fixed the parsing of the Include data in the constant groups, and added linkification to group texts. --- MCServer/Plugins/APIDump/APIDesc.lua | 131 ++++++++++++++++++++++++++---- MCServer/Plugins/APIDump/main_APIDump.lua | 10 ++- 2 files changed, 121 insertions(+), 20 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 28ed9b9d4..bdbea2351 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2865,38 +2865,137 @@ end Globals = { - Desc = [[These functions are available directly, without a class instance. Any plugin cal call them at any time.]], + Desc = [[ + These functions are available directly, without a class instance. Any plugin cal call them at any + time. + ]], Functions = { - AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, Inverse", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified face"}, + AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFace|face}}"}, BlockStringToType = {Params = "BlockTypeString", Return = "BLOCKTYPE", Notes = "Returns the block type parsed from the given string"}, - ClickActionToString = {Params = "ClickAction", Return = "string", Notes = "Returns a string description of the ClickAction enumerated value"}, - DamageTypeToString = {Params = "{{TakeDamageInfo|eDamageType}}", Return = "string", Notes = "Converts a damage type enumerated value to a string representation "}, + ClickActionToString = {Params = "{{Globals#ClickAction|ClickAction}}", Return = "string", Notes = "Returns a string description of the ClickAction enumerated value"}, + DamageTypeToString = {Params = "{{Globals#DamageType|DamageType}}", Return = "string", Notes = "Converts the {{Globals#DamageType|DamageType}} enumerated value to a string representation "}, EscapeString = {Params = "string", Return = "string", Notes = "Returns a copy of the string with all quotes and backslashes escaped by a backslash"}, GetChar = {Params = "String, Pos", Return = "string", Notes = "Returns one character from the string, specified by position "}, GetTime = {Return = "number", Notes = "Returns the current OS time, as a unix time stamp (number of seconds since Jan 1, 1970)"}, IsValidBlock = {Params = "BlockType", Return = "bool", Notes = "Returns true if BlockType is a known block type"}, IsValidItem = {Params = "ItemType", Return = "bool", Notes = "Returns true if ItemType is a known item type"}, - ItemToFullString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item, in the format “ItemTypeText:ItemDamage * Count”"}, + ItemToFullString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item, in the format 'ItemTypeText:ItemDamage * Count'"}, ItemToString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item type"}, ItemTypeToString = {Params = "ItemType", Return = "string", Notes = "Returns the string representation of ItemType "}, - LOG = {Params = "string", Notes = "Logs a text into the server console using “normal” severity (gray text) "}, - LOGERROR = {Params = "string", Notes = "Logs a text into the server console using “error” severity (black text on red background)"}, - LOGINFO = {Params = "string", Notes = "Logs a text into the server console using “info” severity (yellow text)"}, - LOGWARN = {Params = "string", Notes = "Logs a text into the server console using “warning” severity (red text); OBSOLETE"}, - LOGWARNING = {Params = "string", Notes = "Logs a text into the server console using “warning” severity (red text)"}, + LOG = {Params = "string", Notes = "Logs a text into the server console using 'normal' severity (gray text) "}, + LOGERROR = {Params = "string", Notes = "Logs a text into the server console using 'error' severity (black text on red background)"}, + LOGINFO = {Params = "string", Notes = "Logs a text into the server console using 'info' severity (yellow text)"}, + LOGWARN = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"}, + LOGWARNING = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text)"}, NoCaseCompare = {Params = "string, string", Return = "number", Notes = "Case-insensitive string comparison; returns 0 if the strings are the same"}, ReplaceString = {Params = "full-string, to-be-replaced-string, to-replace-string", Notes = "Replaces *each* occurence of to-be-replaced-string in full-string with to-replace-string"}, - StringSplit = {Params = "string, Seperator", Return = "list", Notes = "Seperates string into multiple by splitting every time Seperator is encountered."}, - StringToBiome = {Params = "string", Return = "EMCSBiome", Notes = "Converts a string representation to a biome enumerated value"}, - StringToDamageType = {Params = "string", Return = "{{TakeDamageInfo|eDamageType}}", Notes = "Converts a string representation to an {{TakeDamageInfo|eDamageType}} enumerated value "}, - StringToDimension = {Params = "string", Return = "eDimension", Notes = "Converts a string representation to an eDimension enumerated value"}, + StringSplit = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered."}, + StringSplitAndTrim = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered. Each of the separate strings is trimmed (whitespace removed from the beginning and end of the string)"}, + StringToBiome = {Params = "string", Return = "{{Globals#BiomeTypes|BiomeType}}", Notes = "Converts a string representation to a {{Globals#BiomeTypes|BiomeType}} enumerated value"}, + StringToDamageType = {Params = "string", Return = "{{Globals#DamageType|DamageType}}", Notes = "Converts a string representation to a {{Globals#DamageType|DamageType}} enumerated value."}, + StringToDimension = {Params = "string", Return = "{{Globals#WorldDimension|Dimension}}", Notes = "Converts a string representation to a {{Globals#WorldDimension|Dimension}} enumerated value"}, StringToItem = {Params = "string, {{cItem|cItem}}", Return = "bool", Notes = "Parses the given string and sets the item; returns true if successful"}, - StringToMobType = {Params = "string", Return = "number", Notes = "Converts a string representation to a mob enumerated value"}, + StringToMobType = {Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "Converts a string representation to a {{cMonster#MobType|MobType}} enumerated value"}, StripColorCodes = {Params = "string", Return = "string", Notes = "Removes all control codes used by MC for colors and styles"}, - TrimString = {Params = "string", Return = "string", Notes = "Trime whitespace at both ends of the string"}, + TrimString = {Params = "string", Return = "string", Notes = "Trims whitespace at both ends of the string"}, md5 = {Params = "string", Return = "string", Notes = "converts a string to an md5 hash"}, }, + ConstantGroups = + { + BlockTypes = + { + Include = "^E_BLOCK_.*", + TextBefore = [[ + These constants are used for block types. They correspond directly with MineCraft's data values + for blocks. + ]], + }, + ItemTypes = + { + Include = "^E_ITEM_.*", + TextBefore = [[ + These constants are used for item types. They correspond directly with MineCraft's data values + for items. + ]], + }, + MetaValues = + { + Include = "^E_META_.*", + }, + BiomeTypes = + { + Include = "^bi.*", + TextBefore = [[ + These constants represent the biomes that the server understands. Note that there is a global + StringToBiome() function that can convert a string into one of these constants. + ]], + }, + BlockFaces = + { + Include = "^BLOCK_FACE_.*", + TextBefore = [[ + These constants are used to describe individual faces of the block. They are used when the + client is interacting with a block, or when the {{cLineBlockTracer}} hits a block, etc. + ]], + }, + ClickAction = + { + Include = "^ca.*", + TextBefore = [[ + These constants are used to signalize various interactions that the user can do with the + {{cWindow|UI windows}}. The server translates the protocol events into these constants. Note + that there is a global ClickActionToString() function that can translate these constants into + their textual representation. + ]], + }, + WorldDimension = + { + Include = "^dim.*", + TextBefore = [[ + These constants represent dimension of a world. In MCServer, the dimension is only reflected in + the world's overall tint - overworld gets sky-like colors and dark shades, the nether gets + reddish haze and the end gets dark haze. World generator is not directly affected by the + dimension, same as fluid simulators; those only default to the expected values if not set + specifically otherwise in the world.ini file. + ]], + }, + DamageType = + { + Include = "^dt.*", + TextBefore = [[ + These constants are used for specifying the cause of damage to entities. They are used in the + {{TakeDamageInfo}} structure, as well as in {{cEntity}}'s damage-related API functions. + ]], + }, + GameMode = + { + Include = { "^gm.*", "^eGameMode_.*" }, + TextBefore = [[ + The following constants are used for the gamemode - survival, creative or adventure. Use the + gmXXX constants, the eGameMode_ constants are deprecated and will be removed from the API. + ]], + }, + Weather = + { + Include = { "^eWeather_.*", "wSunny", "wRain", "wStorm", "wThunderstorm" }, + TextBefore = [[ + These constants represent the weather in the world. Note that unlike vanilla, MCServer allows + different weathers even in non-overworld {{Globals#WorldDimension|dimensions}}. + ]], + }, + ExplosionSource = + { + Include = "^es.*", + TextBefore = [[ + These constants are used to differentiate the various sources of explosions. They are used in + the {{OnExploded|HOOK_EXPLODED}} hook, {{OnExploding|HOOK_EXPLODING}} hook and in the + {{cWorld}}:DoExplosionAt() function. These constants also dictate the type of the additional + data provided with the explosions, such as the exploding {{cCreeper|creeper}} entity or the + {{Vector3i|coords}} of the exploding bed. + ]], + } + }, }, -- Globals }, diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index 4dcedc06e..9c4fb17f8 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -576,7 +576,7 @@ function ReadDescriptions(a_API) for j, group in pairs(APIDesc.ConstantGroups) do group.Name = j; group.Constants = {}; - if (type(group.Include == "string")) then + if (type(group.Include) == "string") then group.Include = { group.Include }; end local NumInGroup = 0; @@ -820,20 +820,22 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) return; end + local Source = a_ClassAPI.Name if (a_InheritedName ~= nil) then cf:write("

Constants inherited from ", a_InheritedName, "

\n"); + Source = a_InheritedName; end if (#a_Constants > 0) then - WriteConstantTable(a_Constants, a_InheritedName or a_ClassAPI.Name); + WriteConstantTable(a_Constants, Source); end for k, group in pairs(a_ConstantGroups) do if ((a_InheritedName == nil) or group.ShowInDescendants) then cf:write("

"); - cf:write(group.TextBefore or ""); + cf:write(LinkifyString(group.TextBefore or "", Source)); WriteConstantTable(group.Constants, a_InheritedName or a_ClassAPI.Name); - cf:write(group.TextAfter or "", "

"); + cf:write(LinkifyString(group.TextAfter or "", Source), "

"); end end end -- cgit v1.2.3 From 94e14e1ace16a265b8e58a186c308609c504d288 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 23 Nov 2013 20:26:00 +0100 Subject: Added cFile:ReadWholeFile() to Lua API. --- source/Bindings.cpp | 34 +++++++++++++++++++++++++++++++++- source/Bindings.h | 2 +- source/OSSupport/File.cpp | 16 ++++++++++++++++ source/OSSupport/File.h | 3 +++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 65c154b78..ad3ad8423 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/22/13 16:24:50. +** Generated automatically by tolua++-1.0.92 on 11/23/13 19:57:30. */ #ifndef __cplusplus @@ -2303,6 +2303,37 @@ static int tolua_AllToLua_cFile_CreateFolder00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: ReadWholeFile of class cFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cFile_ReadWholeFile00 +static int tolua_AllToLua_cFile_ReadWholeFile00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cFile",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const AString a_FileName = ((const AString) tolua_tocppstring(tolua_S,2,0)); + { + AString tolua_ret = (AString) cFile::ReadWholeFile(a_FileName); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_FileName); + } + } + return 2; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'ReadWholeFile'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* function: BlockStringToType */ #ifndef TOLUA_DISABLE_tolua_AllToLua_BlockStringToType00 static int tolua_AllToLua_BlockStringToType00(lua_State* tolua_S) @@ -29538,6 +29569,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"IsFile",tolua_AllToLua_cFile_IsFile00); tolua_function(tolua_S,"GetSize",tolua_AllToLua_cFile_GetSize00); tolua_function(tolua_S,"CreateFolder",tolua_AllToLua_cFile_CreateFolder00); + tolua_function(tolua_S,"ReadWholeFile",tolua_AllToLua_cFile_ReadWholeFile00); tolua_endmodule(tolua_S); tolua_constant(tolua_S,"E_BLOCK_AIR",E_BLOCK_AIR); tolua_constant(tolua_S,"E_BLOCK_STONE",E_BLOCK_STONE); diff --git a/source/Bindings.h b/source/Bindings.h index 7d4999505..bc8589293 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/22/13 16:24:51. +** Generated automatically by tolua++-1.0.92 on 11/23/13 19:57:31. */ /* Exported function */ diff --git a/source/OSSupport/File.cpp b/source/OSSupport/File.cpp index 86276bd79..274aa52da 100644 --- a/source/OSSupport/File.cpp +++ b/source/OSSupport/File.cpp @@ -420,6 +420,22 @@ AStringVector cFile::GetFolderContents(const AString & a_Folder) +AString cFile::ReadWholeFile(const AString & a_FileName) +{ + cFile f; + if (!f.Open(a_FileName, fmRead)) + { + return ""; + } + AString Contents; + f.ReadRestOfFile(Contents); + return Contents; +} + + + + + int cFile::Printf(const char * a_Fmt, ...) { AString buf; diff --git a/source/OSSupport/File.h b/source/OSSupport/File.h index 70f81c8d2..01663a229 100644 --- a/source/OSSupport/File.h +++ b/source/OSSupport/File.h @@ -121,6 +121,9 @@ public: /// Creates a new folder with the specified name. Returns true if successful. Path may be relative or absolute static bool CreateFolder(const AString & a_FolderPath); + /// Returns the entire contents of the specified file as a string. Returns empty string on error. + static AString ReadWholeFile(const AString & a_FileName); + // tolua_end /// Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). -- cgit v1.2.3 From e662a3109466011514d154373ba9f39066e4a80e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 23 Nov 2013 20:26:23 +0100 Subject: Fixed Lua bindings for cFile:GetFolderContents(). --- source/ManualBindings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 967b03ee7..02b3347f6 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -183,7 +183,7 @@ static int tolua_cFile_GetFolderContents(lua_State * tolua_S) return 0; } - AString Folder = (AString)tolua_tocppstring(LuaState, 1, 0); + AString Folder = (AString)tolua_tocppstring(LuaState, 2, 0); AStringVector Contents = cFile::GetFolderContents(Folder); LuaState.Push(Contents); -- cgit v1.2.3 From cc77ffd0698ed9a533d8e06de53bab9380b45b80 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Sat, 23 Nov 2013 21:13:55 +0100 Subject: Documented sqlite functions. Used: http://lua.sqlite.org/index.cgi/doc/tip/doc/lsqlite3.wiki#sqlite3_functions --- MCServer/Plugins/APIDump/APIDesc.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index bdbea2351..82ba5ba45 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2668,6 +2668,24 @@ Parser:close(); }, -- AdditionalInfo }, -- lxp + sqlite3 = + { + Desc = [[ + ]], + + Functions = + { + complete = { Params = "string", Return = "bool", Notes = "Returns true if the string sql comprises one or more complete SQL statements and false otherwise." }, + open = { Params = "string", Return = "Userdata", Notes = [[Opens (or creates if it does not exist) an SQLite database with name filename and returns its handle as userdata (the returned object should be used for all further method calls in connection with this specific database, see {{http://lua.sqlite.org/index.cgi/doc/tip/doc/lsqlite3.wiki#database_methods|Database methods}}). Example:
myDB=sqlite3.open('MyDatabase.sqlite3')  -- open
+-- do some database calls...
+myDB:close()  -- close
+TakeDamageInfo =
]], }, + open_memory = { Return = "userdata", Notes = "Opens an SQLite database in memory and returns its handle as userdata. In case of an error, the function returns nil, an error code and an error message. (In-memory databases are volatile as they are never stored on disk.)" }, + temp_directory = { Params = "string", Notes = "Opens an SQLite database in memory and returns its handle as userdata. In case of an error, the function returns nil, an error code and an error message. (In-memory databases are volatile as they are never stored on disk.)" }, + version = { Return = "string", Notes = "Returns a string with SQLite version information, in the form 'x.y[.z]'." }, + }, + }, + TakeDamageInfo = { Desc = [[ -- cgit v1.2.3 From d9dc241e6fe669585d7c0b13d55818a22e1c76bc Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 23 Nov 2013 21:26:24 +0100 Subject: APIDump: The descriptions are read from multiple files. All the files in the Classes subfolder are read for class descriptions, and in the Hooks subfolder for the hook descriptions. --- MCServer/Plugins/APIDump/APIDesc.lua | 1729 +------------------- MCServer/Plugins/APIDump/Classes/BlockEntities.lua | 243 +++ .../Plugins/APIDump/Hooks/OnBlockToPickups.lua | 62 + MCServer/Plugins/APIDump/Hooks/OnChat.lua | 29 + .../Plugins/APIDump/Hooks/OnChunkAvailable.lua | 27 + .../Plugins/APIDump/Hooks/OnChunkGenerated.lua | 67 + .../Plugins/APIDump/Hooks/OnChunkGenerating.lua | 35 + MCServer/Plugins/APIDump/Hooks/OnChunkUnloaded.lua | 28 + .../Plugins/APIDump/Hooks/OnChunkUnloading.lua | 30 + .../Plugins/APIDump/Hooks/OnCollectingPickup.lua | 32 + .../Plugins/APIDump/Hooks/OnCraftingNoRecipe.lua | 32 + MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua | 32 + .../Plugins/APIDump/Hooks/OnExecuteCommand.lua | 31 + MCServer/Plugins/APIDump/Hooks/OnExploded.lua | 49 + MCServer/Plugins/APIDump/Hooks/OnExploding.lua | 50 + MCServer/Plugins/APIDump/Hooks/OnHandshake.lua | 29 + .../Plugins/APIDump/Hooks/OnHopperPullingItem.lua | 30 + .../Plugins/APIDump/Hooks/OnHopperPushingItem.lua | 30 + MCServer/Plugins/APIDump/Hooks/OnKilling.lua | 33 + MCServer/Plugins/APIDump/Hooks/OnLogin.lua | 31 + .../Plugins/APIDump/Hooks/OnPlayerAnimation.lua | 28 + .../APIDump/Hooks/OnPlayerBreakingBlock.lua | 36 + .../Plugins/APIDump/Hooks/OnPlayerBrokenBlock.lua | 36 + MCServer/Plugins/APIDump/Hooks/OnPlayerEating.lua | 27 + MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua | 29 + .../Plugins/APIDump/Hooks/OnPlayerLeftClick.lua | 47 + MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua | 27 + .../Plugins/APIDump/Hooks/OnPlayerPlacedBlock.lua | 40 + .../Plugins/APIDump/Hooks/OnPlayerPlacingBlock.lua | 45 + .../Plugins/APIDump/Hooks/OnPlayerRightClick.lua | 37 + .../APIDump/Hooks/OnPlayerRightClickingEntity.lua | 27 + .../Plugins/APIDump/Hooks/OnPlayerShooting.lua | 32 + MCServer/Plugins/APIDump/Hooks/OnPlayerSpawned.lua | 32 + .../Plugins/APIDump/Hooks/OnPlayerTossingItem.lua | 30 + .../Plugins/APIDump/Hooks/OnPlayerUsedBlock.lua | 46 + .../Plugins/APIDump/Hooks/OnPlayerUsedItem.lua | 46 + .../Plugins/APIDump/Hooks/OnPlayerUsingBlock.lua | 46 + .../Plugins/APIDump/Hooks/OnPlayerUsingItem.lua | 47 + MCServer/Plugins/APIDump/Hooks/OnPostCrafting.lua | 36 + MCServer/Plugins/APIDump/Hooks/OnPreCrafting.lua | 37 + MCServer/Plugins/APIDump/Hooks/OnSpawnedEntity.lua | 31 + .../Plugins/APIDump/Hooks/OnSpawnedMonster.lua | 30 + .../Plugins/APIDump/Hooks/OnSpawningEntity.lua | 32 + .../Plugins/APIDump/Hooks/OnSpawningMonster.lua | 33 + MCServer/Plugins/APIDump/Hooks/OnTakeDamage.lua | 31 + MCServer/Plugins/APIDump/Hooks/OnTick.lua | 29 + MCServer/Plugins/APIDump/Hooks/OnUpdatedSign.lua | 38 + MCServer/Plugins/APIDump/Hooks/OnUpdatingSign.lua | 58 + .../Plugins/APIDump/Hooks/OnWeatherChanged.lua | 28 + .../Plugins/APIDump/Hooks/OnWeatherChanging.lua | 32 + MCServer/Plugins/APIDump/Hooks/OnWorldTick.lua | 29 + MCServer/Plugins/APIDump/main_APIDump.lua | 33 + 52 files changed, 2059 insertions(+), 1705 deletions(-) create mode 100644 MCServer/Plugins/APIDump/Classes/BlockEntities.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnBlockToPickups.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnChat.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnChunkAvailable.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnChunkGenerated.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnChunkGenerating.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnChunkUnloaded.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnChunkUnloading.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnCollectingPickup.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnCraftingNoRecipe.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnExecuteCommand.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnExploded.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnExploding.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnHandshake.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnHopperPullingItem.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnHopperPushingItem.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnKilling.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnLogin.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerAnimation.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerBreakingBlock.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerBrokenBlock.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerEating.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerLeftClick.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerPlacedBlock.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerPlacingBlock.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerRightClick.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerRightClickingEntity.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerShooting.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerSpawned.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerUsedBlock.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerUsedItem.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerUsingBlock.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPlayerUsingItem.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPostCrafting.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnPreCrafting.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnSpawnedEntity.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnSpawnedMonster.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnSpawningEntity.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnSpawningMonster.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnTakeDamage.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnTick.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnUpdatedSign.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnUpdatingSign.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnWeatherChanged.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnWeatherChanging.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnWorldTick.lua diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 82ba5ba45..1ad5bf5e4 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -302,56 +302,6 @@ g_APIDesc = }, -- AdditionalInfo }, -- cBlockArea - cBlockEntity = - { - Desc = [[ - Block entities are simply blocks in the world that have persistent data, such as the text for a sign - or contents of a chest. All block entities are also saved in the chunk data of the chunk they reside in. - The cBlockEntity class acts as a common ancestor for all the individual block entities. - ]], - - Functions = - { - GetBlockType = { Params = "", Return = "BLOCKTYPE", Notes = "Returns the blocktype which is represented by this blockentity. This is the primary means of type-identification" }, - GetChunkX = { Params = "", Return = "number", Notes = "Returns the chunk X-coord of the block entity's chunk" }, - GetChunkZ = { Params = "", Return = "number", Notes = "Returns the chunk Z-coord of the block entity's chunk" }, - GetPosX = { Params = "", Return = "number", Notes = "Returns the block X-coord of the block entity's block" }, - GetPosY = { Params = "", Return = "number", Notes = "Returns the block Y-coord of the block entity's block" }, - GetPosZ = { Params = "", Return = "number", Notes = "Returns the block Z-coord of the block entity's block" }, - GetRelX = { Params = "", Return = "number", Notes = "Returns the relative X coord of the block entity's block within the chunk" }, - GetRelZ = { Params = "", Return = "number", Notes = "Returns the relative Z coord of the block entity's block within the chunk" }, - GetWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world to which the block entity belongs" }, - }, - }, - - cBlockEntityWithItems = - { - Desc = [[ - This class is a common ancestor for all {{cBlockEntity|block entities}} that provide item storage. - Internally, the object has a {{cItemGrid|cItemGrid}} object for storing the items; this ItemGrid is - accessible through the API. The storage is a grid of items, items in it can be addressed either by a slot - number, or by XY coords within the grid. If a UI window is opened for this block entity, the item storage - is monitored for changes and the changes are immediately sent to clients of the UI window. - ]], - - Inherits = "cBlockEntity", - - Functions = - { - GetContents = { Params = "", Return = "{{cItemGrid|cItemGrid}}", Notes = "Returns the cItemGrid object representing the items stored within this block entity" }, - GetSlot = - { - { Params = "SlotNum", Return = "{{cItem|cItem}}", Notes = "Returns the cItem for the specified slot number. Returns nil for invalid slot numbers" }, - { Params = "X, Y", Return = "{{cItem|cItem}}", Notes = "Returns the cItem for the specified slot coords. Returns nil for invalid slot coords" }, - }, - SetSlot = - { - { Params = "SlotNum, {{cItem|cItem}}", Return = "", Notes = "Sets the cItem for the specified slot number. Ignored if invalid slot number" }, - { Params = "X, Y, {{cItem|cItem}}", Return = "", Notes = "Sets the cItem for the specified slot coords. Ignored if invalid slot coords" }, - }, - }, - }, - cBoundingBox = { Desc = [[ @@ -430,45 +380,6 @@ g_APIDesc = }, }, - cChestEntity = - { - Desc = [[ - A chest entity is a {{cBlockEntityWithItems|cBlockEntityWithItems}} descendant that represents a chest - in the world. Note that doublechests consist of two separate cChestEntity objects, they do not collaborate - in any way.

-

- To manipulate a chest already in the game, you need to use {{cWorld}}'s callback mechanism with - either DoWithChestAt() or ForEachChestInChunk() function. See the code example below - ]], - - Inherits = "cBlockEntityWithItems", - - Constants = - { - ContentsHeight = { Notes = "Height of the contents' {{cItemGrid|ItemGrid}}, as required by the parent class, {{cBlockEntityWithItems}}" }, - ContentsWidth = { Notes = "Width of the contents' {{cItemGrid|ItemGrid}}, as required by the parent class, {{cBlockEntityWithItems}}" }, - }, - AdditionalInfo = - { - { - Header = "Code example", - Contents = [[ - The following example code sets the top-left item of each chest in the same chunk as Player to - 64 * diamond: -

--- Player is a {{cPlayer}} object instance
-local World = Player:GetWorld();
-World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
-	function (ChestEntity)
-		ChestEntity:SetSlot(0, 0, cItem(E_ITEM_DIAMOND, 64));
-	end
-);
-
- ]], - }, - }, -- AdditionalInfo - }, - cChunkDesc = { Desc = [[ @@ -693,47 +604,6 @@ end }, }, -- cCuboid - cDispenserEntity = - { - Desc = [[ - This class represents a dispenser block entity in the world. Most of this block entity's - functionality is implemented in the {{cDropSpenserEntity|cDropSpenserEntity}} class that represents - the behavior common with a {{cDropperEntity|dropper}} entity. - ]], - Inherits = "cDropSpenserEntity", - }, - - cDropperEntity = - { - Desc = [[ - This class represents a dropper block entity in the world. Most of this block entity's functionality - is implemented in the {{cDropSpenserEntity|cDropSpenserEntity}} class that represents the behavior - common with the {{cDispenserEntity|dispenser}} entity.

-

- An object of this class can be created from scratch when generating chunks ({{OnChunkGenerated|OnChunkGenerated}} and {{OnChunkGenerating|OnChunkGenerating}} hooks). - ]], - Inherits = "cDropSpenserEntity", - }, -- cDropperEntity - - cDropSpenserEntity = - { - Desc = [[ - This is a class that implements behavior common to both {{cDispenserEntity|dispensers}} and {{cDropperEntity|droppers}}. - ]], - Functions = - { - Activate = { Params = "", Return = "", Notes = "Sets the block entity to dropspense an item in the next tick" }, - AddDropSpenserDir = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "BlockX, BlockY, BlockZ", Notes = "Adjusts the block coords to where the dropspenser items materialize" }, - SetRedstonePower = { Params = "IsPowered", Return = "", Notes = "Sets the redstone status of the dropspenser. If the redstone power goes from off to on, the dropspenser will be activated" }, - }, - Constants = - { - ContentsWidth = { Notes = "Width (X) of the {{cItemGrid}} representing the contents" }, - ContentsHeight = { Notes = "Height (Y) of the {{cItemGrid}} representing the contents" }, - }, - Inherits = "cBlockEntityWithItems"; - }, -- cDropSpenserEntity - cEnchantments = { Desc = [[ @@ -987,45 +857,6 @@ cFile:Delete("/usr/bin/virus.exe"); Inherits = "cProjectileEntity", } , - cFurnaceEntity = - { - Desc = [[ - This class represents a furnace block entity in the world.

-

- See also {{cRoot}}'s GetFurnaceRecipe() and GetFurnaceFuelBurnTime() functions - ]], - Functions = - { - GetCookTimeLeft = { Params = "", Return = "number", Notes = "Returns the time until the current item finishes cooking, in ticks" }, - GetFuelBurnTimeLeft = { Params = "", Return = "number", Notes = "Returns the time until the current fuel is depleted, in ticks" }, - GetFuelSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the fuel slot" }, - GetInputSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the input slot" }, - GetOutputSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the output slot" }, - GetTimeCooked = { Params = "", Return = "number", Notes = "Returns the time that the current item has been cooking, in ticks" }, - HasFuelTimeLeft = { Params = "", Return = "bool", Notes = "Returns true if there's time before the current fuel is depleted" }, - SetFuelSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the fuel slot" }, - SetInputSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the input slot" }, - SetOutputSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the output slot" }, - }, - Constants = - { - fsInput = { Notes = "Index of the input slot" }, - fsFuel = { Notes = "Index of the fuel slot" }, - fsOutput = { Notes = "Index of the output slot" }, - ContentsWidth = { Notes = "Width (X) of the {{cItemGrid|cItemGrid}} representing the contents" }, - ContentsHeight = { Notes = "Height (Y) of the {{cItemGrid|cItemGrid}} representing the contents" }, - }, - ConstantGroups = - { - SlotIndices = - { - Include = "fs.*", - TextBefore = "When using the GetSlot() or SetSlot() function, use these constants for slot index:", - }, - }, - Inherits = "cBlockEntityWithItems" - }, -- cFurnaceEntity - cGhastFireballEntity = { Desc = "", @@ -1052,24 +883,6 @@ cFile:Delete("/usr/bin/virus.exe"); }, }, -- cGroup - cHopperEntity = - { - Desc = [[ - This class represents a hopper block entity in the world. - ]], - Functions = - { - GetOutputBlockPos = { Params = "BlockMeta", Return = "bool, BlockX, BlockY, BlockZ", Notes = "Returns whether the hopper is attached, and if so, the block coords of the block receiving the output items, based on the given meta." }, - }, - Constants = - { - ContentsHeight = { Notes = "Height (Y) of the internal {{cItemGrid}} representing the hopper contents." }, - ContentsWidth = { Notes = "Width (X) of the internal {{cItemGrid}} representing the hopper contents." }, - TICKS_PER_TRANSFER = { Notes = "Number of ticks between when the hopper transfers items." }, - }, - Inherits = "cBlockEntityWithItems", - }, -- cHopperEntity - cIniFile = { Desc = [[ @@ -1512,22 +1325,6 @@ end }, }, -- cItems - cJukeboxEntity = - { - Desc = [[ - This class represents a jukebox in the world. It can play the records, either when the - {{cPlayer|player}} uses the record on the jukebox, or when a plugin instructs it to play. - ]], - Inherits = "cBlockEntity", - Functions = - { - EjectRecord = { Params = "", Return = "", Notes = "Ejects the current record as a {{cPickup|pickup}}. No action if there's no current record. To remove record without generating the pickup, use SetRecord(0)" }, - GetRecord = { Params = "", Return = "number", Notes = "Returns the record currently present. Zero for no record, E_ITEM_*_DISC for records." }, - PlayRecord = { Params = "", Return = "", Notes = "Plays the currently present record. No action if there's no current record." }, - SetRecord = { Params = "number", Return = "", Notes = "Sets the currently present record. Use zero for no record, or E_ITEM_*_DISC for records." }, - }, - }, -- cJukeboxEntity - cLineBlockTracer = { Desc = [[Objects of this class provide an easy-to-use interface to tracing lines through individual @@ -1775,25 +1572,6 @@ a_Player:OpenWindow(Window); Inherits = "cPawn", }, -- cMonster - cNoteEntity = - { - Desc = [[ - This class represents a note block entity in the world. It takes care of the note block's pitch, - and also can play the sound, either when the {{cPlayer|player}} right-clicks it, redstone activates - it, or upon a plugin's request.

-

- The pitch is stored as an integer between 0 and 24. - ]], - Functions = - { - GetPitch = { Params = "", Return = "number", Notes = "Returns the current pitch set for the block" }, - IncrementPitch = { Params = "", Return = "", Notes = "Adds 1 to the current pitch. Wraps around to 0 when the pitch cannot go any higher." }, - MakeSound = { Params = "", Return = "", Notes = "Plays the sound for all {{cClientHandle|clients}} near this block." }, - SetPitch = { Params = "Pitch", Return = "", Notes = "Sets a new pitch for the block." }, - }, - Inherits = "cBlockEntity", - }, -- cNoteEntity - cPawn = { Desc = [[cPawn is a controllable pawn object, controlled by either AI or a player. cPawn inherits all functions and members of {{cEntity}} @@ -2170,21 +1948,6 @@ end }, }, -- cServer - cSignEntity = - { - Desc = [[ - A sign entity represents a sign in the world. This class is only used when generating chunks, so - that the plugins may generate signs within new chunks. See the code example in {{cChunkDesc}}. - ]], - Functions = - { - GetLine = { Params = "LineIndex", Return = "string", Notes = "Returns the specified line. LineIndex is expected between 0 and 3. Returns empty string and logs to server console when LineIndex is invalid." }, - SetLine = { Params = "LineIndex, LineText", Return = "", Notes = "Sets the specified line. LineIndex is expected between 0 and 3. Logs to server console when LineIndex is invalid." }, - SetLines = { Params = "Line1, Line2, Line3, Line4", Return = "", Notes = "Sets all the sign's lines at once." }, - }, - Inherits = "cBlockEntity"; - }, -- cSignEntity - cThrownEggEntity = { Desc = "", @@ -2708,7 +2471,7 @@ TakeDamageInfo =

]], }, The TDI is passed as the second parameter in the HOOK_TAKE_DAMAGE hook, and can be used to modify the damage before it is applied to the receiver:
-function Plugin:OnTakeDamage(Receiver, TDI)
+function OnTakeDamage(Receiver, TDI)
 	LOG("Damage: Raw ".. TDI.RawDamage .. ", Final:" .. TDI.FinalDamage);
 
 	-- If the attacker is a spider, make it deal 999 points of damage (insta-death spiders):
@@ -3018,1474 +2781,31 @@ end
 	},
 
 
-	Hooks =
+	IgnoreClasses =
 	{
-		HOOK_BLOCK_TO_PICKUPS =
-		{
-			CalledWhen = "A block is about to be dug ({{cPlayer|player}}, {{cEntity|entity}} or natural reason), plugins may override what pickups that will produce.",
-			DefaultFnName = "OnBlockToPickups",  -- also used as pagename
-			Desc = [[
-				This callback gets called whenever a block is about to be dug. This includes {{cPlayer|players}}
-				digging blocks, entities causing blocks to disappear ({{cTNTEntity|TNT}}, Endermen) and natural
-				causes (water washing away a block). Plugins may override the amount and kinds of pickups this
-				action produces.
-			]],
-			Params =
-			{
-				{ Name = "World", Type = "{{cWorld}}", Notes = "The world in which the block resides" },
-				{ Name = "Digger", Type = "{{cEntity}} descendant", Notes = "The entitycausing the digging. May be a {{cPlayer}}, {{cTNTEntity}} or even nil (natural causes)" },
-				{ Name = "BlockX", Type = "number", Notes = "X-coord of the block" },
-				{ Name = "BlockY", Type = "number", Notes = "Y-coord of the block" },
-				{ Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" },
-				{ Name = "BlockType", Type = "BLOCKTYPE", Notes = "Block type of the block" },
-				{ Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "Block meta of the block" },
-				{ Name = "Pickups", Type = "{{cItems}}", Notes = "Items that will be spawned as pickups" },
-			},
-			Returns = [[
-				If the function returns false or no value, the next callback in the hook chain will be called. If
-				the function returns true, no other callbacks in the chain will be called.

-

- Either way, the server will then spawn pickups specified in the Pickups parameter, so to disable - pickups, you need to Clear the object first, then return true. - ]], - CodeExamples = - { - { - Title = "Modify pickups", - Desc = "This example callback function makes tall grass drop diamonds when digged by natural causes (washed away by water).", - Code = [[ -function OnBlockToPickups(a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups) - if (a_Digger ~= nil) then - -- Not a natural cause - return false; - end - if (a_BlockType ~= E_BLOCK_TALL_GRASS) then - -- Not a tall grass being washed away - return false; - end - - -- Remove all pickups suggested by MCServer: - a_Pickups:Clear(); - - -- Drop a diamond: - a_Pickups:Add(cItem(E_ITEM_DIAMOND)); - return true; -end; - ]], - }, - } , -- CodeExamples - }, -- HOOK_BLOCK_TO_PICKUPS - - HOOK_CHAT = - { - CalledWhen = "Player sends a chat message", - DefaultFnName = "OnChat", -- also used as pagename - Desc = [[ - A plugin may implement an OnChat() function and register it as a Hook to process chat messages from - the players. The function is then called for every in-game message sent from any player. Note that - commands are handled separately using a command framework API. - ]], - Params = { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who sent the message" }, - { Name = "Message", Type = "string", Notes = "The message" }, - }, - Returns = [[ - The plugin may return 2 values. The first is a boolean specifying whether the hook handling is to be - stopped or not. If it is false, the message is broadcast to all players in the world. If it is true, - no message is broadcast and no further action is taken.

-

- The second value is specifies the message to broadcast. This way, plugins may modify the message. If - the second value is not provided, the original message is used. - ]], - }, -- HOOK_CHAT - - HOOK_CHUNK_AVAILABLE = - { - CalledWhen = "A chunk has just been added to world, either generated or loaded. ", - DefaultFnName = "OnChunkAvailable", -- also used as pagename - Desc = [[ - This hook is called after a chunk is either generated or loaded from the disk. The chunk is - already available for manipulation using the {{cWorld}} API. This is a notification-only callback, - there is no behavior that plugins could override. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk belongs" }, - { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, - { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event. - ]], - }, -- HOOK_CHUNK_AVAILABLE - - HOOK_CHUNK_GENERATED = - { - CalledWhen = "After a chunk was generated. Notification only.", - DefaultFnName = "OnChunkGenerated", -- also used as pagename - Desc = [[ - This hook is called when world generator finished its work on a chunk. The chunk data has already - been generated and is about to be stored in the {{cWorld|world}}. A plugin may provide some - last-minute finishing touches to the generated data. Note that the chunk is not yet stored in the - world, so regular {{cWorld}} block API will not work! Instead, use the {{cChunkDesc}} object - received as the parameter.

-

- See also the {{OnChunkGenerating|HOOK_CHUNK_GENERATING}} hook. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk will be added" }, - { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, - { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, - { Name = "ChunkDesc", Type = "{{cChunkDesc}}", Notes = "Generated chunk data. Plugins may still modify the chunk data contained." }, - }, - Returns = [[ - If the plugin returns false or no value, MCServer will call other plugins' callbacks for this event. - If a plugin returns true, no other callback is called for this event.

-

- In either case, MCServer will then store the data from ChunkDesc as the chunk's contents in the world. - ]], - CodeExamples = - { - { - Title = "Generate emerald ore", - Desc = "This example callback function generates one block of emerald ore in each chunk, under the condition that the randomly chosen location is in an ExtremeHills biome.", - Code = [[ -function OnChunkGenerated(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc) - -- Generate a psaudorandom value that is always the same for the same X/Z pair, but is otherwise random enough: - -- This is actually similar to how MCServer does its noise functions - local PseudoRandom = (a_ChunkX * 57 + a_ChunkZ) * 57 + 19785486 - PseudoRandom = PseudoRandom * 8192 + PseudoRandom; - PseudoRandom = ((PseudoRandom * (PseudoRandom * PseudoRandom * 15731 + 789221) + 1376312589) % 0x7fffffff; - PseudoRandom = PseudoRandom / 7; - - -- Based on the PseudoRandom value, choose a location for the ore: - local OreX = PseudoRandom % 16; - local OreY = 2 + ((PseudoRandom / 16) % 20); - local OreZ = (PseudoRandom / 320) % 16; - - -- Check if the location is in ExtremeHills: - if (a_ChunkDesc:GetBiome(OreX, OreZ) ~= biExtremeHills) then - return false; - end - - -- Only replace allowed blocks with the ore: - local CurrBlock = a_ChunDesc:GetBlockType(OreX, OreY, OreZ); - if ( - (CurrBlock == E_BLOCK_STONE) or - (CurrBlock == E_BLOCK_DIRT) or - (CurrBlock == E_BLOCK_GRAVEL) - ) then - a_ChunkDesc:SetBlockTypeMeta(OreX, OreY, OreZ, E_BLOCK_EMERALD_ORE, 0); - end -end; - ]], - }, - } , -- CodeExamples - }, -- HOOK_CHUNK_GENERATED - - HOOK_CHUNK_GENERATING = - { - CalledWhen = "A chunk is about to be generated. Plugin can override the built-in generator.", - DefaultFnName = "OnChunkGenerating", -- also used as pagename - Desc = [[ - This hook is called before the world generator starts generating a chunk. The plugin may provide - some or all parts of the generation, by-passing the built-in generator. The function is given access - to the {{cChunkDesc|ChunkDesc}} object representing the contents of the chunk. It may override parts - of the built-in generator by using the object's SetUseDefaultXXX(false) functions. After all - the callbacks for a chunk have been processed, the server will generate the chunk based on the - {{cChunkDesc|ChunkDesc}} description - those parts that are set for generating (by default - everything) are generated, the rest are read from the ChunkDesc object.

-

- See also the {{OnChunkGenerated|HOOK_CHUNK_GENERATED}} hook. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk will be added" }, - { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, - { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, - { Name = "ChunkDesc", Type = "{{cChunkDesc}}", Notes = "Generated chunk data." }, - }, - Returns = [[ - If this function returns true, the server will not call any other plugin with the same chunk. If - this function returns false, the server will call the rest of the plugins with the same chunk, - possibly overwriting the ChunkDesc's contents. - ]], - }, -- HOOK_CHUNK_GENERATING - - HOOK_CHUNK_UNLOADED = - { - CalledWhen = "A chunk has been unloaded from the memory.", - DefaultFnName = "OnChunkUnloaded", -- also used as pagename - Desc = [[ - This hook is called when a chunk is unloaded from the memory. Though technically still in memory, - the plugin should behave as if the chunk was already not present. In particular, {{cWorld}} block - API should not be used in the area of the specified chunk. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world from which the chunk is unloading" }, - { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, - { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event. There is no behavior that plugins could - override. - ]], - }, -- HOOK_CHUNK_UNLOADED - - HOOK_CHUNK_UNLOADING = - { - CalledWhen = " A chunk is about to be unloaded from the memory. Plugins may refuse the unload.", - DefaultFnName = "OnChunkUnloading", -- also used as pagename - Desc = [[ - MCServer calls this function when a chunk is about to be unloaded from the memory. A plugin may - force MCServer to keep the chunk in memory by returning true.

-

- FIXME: The return value should be used only for event propagation stopping, not for the actual - decision whether to unload. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world from which the chunk is unloading" }, - { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, - { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called and finally MCServer - unloads the chunk. If the function returns true, no other callback is called for this event and the - chunk is left in the memory. - ]], - }, -- HOOK_CHUNK_UNLOADING - - HOOK_COLLECTING_PICKUP = - { - CalledWhen = "Player is about to collect a pickup. Plugin can refuse / override behavior. ", - DefaultFnName = "OnCollectingPickup", -- also used as pagename - Desc = [[ - This hook is called when a player is about to collect a pickup. Plugins may refuse the action.

-

- Pickup collection happens within the world tick, so if the collecting is refused, it will be tried - again in the next world tick, as long as the player is within reach of the pickup.

-

- FIXME: There is no OnCollectedPickup() callback.

-

- FIXME: This callback is called even if the pickup doesn't fit into the player's inventory.

- ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who's collecting the pickup" }, - { Name = "Pickup", Type = "{{cPickup}}", Notes = "The pickup being collected" }, - }, - Returns = [[ - If the function returns false or no value, MCServer calls other plugins' callbacks and finally the - pickup is collected. If the function returns true, no other plugins are called for this event and - the pickup is not collected. - ]], - }, -- HOOK_COLLECTING_PICKUP - - HOOK_CRAFTING_NO_RECIPE = - { - CalledWhen = " No built-in crafting recipe is found. Plugin may provide a recipe.", - DefaultFnName = "OnCraftingNoRecipe", -- also used as pagename - Desc = [[ - This callback is called when a player places items in their {{cCraftingGrid|crafting grid}} and - MCServer cannot find a built-in {{cCraftingRecipe|recipe}} for the combination. Plugins may provide - a recipe for the ingredients given. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose crafting is reported in this hook" }, - { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "Contents of the player's crafting grid" }, - { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that will be used (can be filled by plugins)" }, - }, - Returns = [[ - If the function returns false or no value, no recipe will be used. If the function returns true, no - other plugin will have their callback called for this event and MCServer will use the crafting - recipe in Recipe.

-

- FIXME: To allow plugins give suggestions and overwrite other plugins' suggestions, we should change - the behavior with returning false, so that the recipe will still be used, but fill the recipe with - empty values by default. - ]], - }, -- HOOK_CRAFTING_NO_RECIPE - - HOOK_DISCONNECT = - { - CalledWhen = "A player has explicitly disconnected.", - DefaultFnName = "OnDisconnect", -- also used as pagename - Desc = [[ - This hook is called when a client sends the disconnect packet and is about to be disconnected from - the server.

-

- Note that this callback is not called if the client drops the connection or is kicked by the - server.

-

- FIXME: There is no callback for "client destroying" that would be called in all circumstances.

- ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has disconnected" }, - { Name = "Reason", Type = "string", Notes = "The reason that the client has sent in the disconnect packet" }, - }, - Returns = [[ - If the function returns false or no value, MCServer calls other plugins' callbacks for this event - and finally broadcasts a disconnect message to the player's world. If the function returns true, no - other plugins are called for this event and the disconnect message is not broadcast. In either case, - the player is disconnected. - ]], - }, -- HOOK_DISCONNECT - - HOOK_EXECUTE_COMMAND = - { - CalledWhen = "A player executes an in-game command, or the admin issues a console command. Note that built-in console commands are exempt to this hook - they are always performed and the hook is not called.", - DefaultFnName = "OnExecuteCommand", -- also used as pagename - Desc = [[ - A plugin may implement a callback for this hook to intercept both in-game commands executed by the - players and console commands executed by the server admin. The function is called for every in-game - command sent from any player and for those server console commands that are not built in in the - server.

-

- If the command is in-game, the first parameter to the hook function is the {{cPlayer|player}} who's - executing the command. If the command comes from the server console, the first parameter is nil. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "For in-game commands, the player who has sent the message. For console commands, nil" }, - { Name = "Command", Type = "table of strings", Notes = "The command and its parameters, broken into a table by spaces" }, - }, - Returns = [[ - If the plugin returns true, the command will be blocked and none of the remaining hook handlers will - be called. If the plugin returns false, MCServer calls all the remaining hook handlers and finally - the command will be executed. - ]], - }, -- HOOK_EXECUTE_COMMAND + "coroutine", + "debug", + "io", + "math", + "package", + "os", + "string", + "table", + "g_TrackedPages", + "g_Stats", + }, - HOOK_EXPLODED = - { - CalledWhen = "An explosion has happened", - DefaultFnName = "OnExploded", -- also used as pagename - Desc = [[ - This hook is called after an explosion has been processed in a world.

-

- See also {{OnExploding|HOOK_EXPLODING}} for a similar hook called before the explosion.

-

- The explosion carries with it the type of its source - whether it's a creeper exploding, or TNT, - etc. It also carries the identification of the actual source. The exact type of the identification - depends on the source kind: - - - - - - - - - - - - -
SourceSourceData TypeNotes
esPrimedTNT{{cTNTEntity}}An exploding primed TNT entity
esCreeper{{cCreeper}}An exploding creeper or charged creeper
esBed{{Vector3i}}A bed exploding in the Nether or in the End. The bed coords are given.
esEnderCrystal{{Vector3i}}An ender crystal exploding upon hit. The block coords are given.
esGhastFireball{{cGhastFireballEntity}}A ghast fireball hitting ground or an {{cEntity|entity}}.
esWitherSkullBlackTBDA black wither skull hitting ground or an {{cEntity|entity}}.
esWitherSkullBlueTBDA blue wither skull hitting ground or an {{cEntity|entity}}.
esWitherBirthTBDA wither boss being created
esOtherTBDAny other previously unspecified type.
esPluginobjectAn explosion created by a plugin. The plugin may specify any kind of data.

- ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world where the explosion happened" }, - { Name = "ExplosionSize", Type = "number", Notes = "The relative explosion size" }, - { Name = "CanCauseFire", Type = "bool", Notes = "True if the explosion has turned random air blocks to fire (such as a ghast fireball)" }, - { Name = "X", Type = "number", Notes = "X-coord of the explosion center" }, - { Name = "Y", Type = "number", Notes = "Y-coord of the explosion center" }, - { Name = "Z", Type = "number", Notes = "Z-coord of the explosion center" }, - { Name = "Source", Type = "eExplosionSource", Notes = "Source of the explosion. See the table above." }, - { Name = "SourceData", Type = "varies", Notes = "Additional data for the source. The exact type varies by the source. See the table above." }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event. There is no overridable behaviour. - ]], - }, -- HOOK_EXPLODED - - HOOK_EXPLODING = - { - CalledWhen = "An explosion is about to be processed", - DefaultFnName = "OnExploding", -- also used as pagename - Desc = [[ - This hook is called before an explosion has been processed in a world.

-

- See also {{OnExploded|HOOK_EXPLODED}} for a similar hook called after the explosion.

-

- The explosion carries with it the type of its source - whether it's a creeper exploding, or TNT, - etc. It also carries the identification of the actual source. The exact type of the identification - depends on the source kind: - - - - - - - - - - - - -
SourceSourceData TypeNotes
esPrimedTNT{{cTNTEntity}}An exploding primed TNT entity
esCreeper{{cCreeper}}An exploding creeper or charged creeper
esBed{{Vector3i}}A bed exploding in the Nether or in the End. The bed coords are given.
esEnderCrystal{{Vector3i}}An ender crystal exploding upon hit. The block coords are given.
esGhastFireball{{cGhastFireballEntity}}A ghast fireball hitting ground or an {{cEntity|entity}}.
esWitherSkullBlackTBDA black wither skull hitting ground or an {{cEntity|entity}}.
esWitherSkullBlueTBDA blue wither skull hitting ground or an {{cEntity|entity}}.
esWitherBirthTBDA wither boss being created
esOtherTBDAny other previously unspecified type.
esPluginobjectAn explosion created by a plugin. The plugin may specify any kind of data.

- ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world where the explosion happens" }, - { Name = "ExplosionSize", Type = "number", Notes = "The relative explosion size" }, - { Name = "CanCauseFire", Type = "bool", Notes = "True if the explosion will turn random air blocks to fire (such as a ghast fireball)" }, - { Name = "X", Type = "number", Notes = "X-coord of the explosion center" }, - { Name = "Y", Type = "number", Notes = "Y-coord of the explosion center" }, - { Name = "Z", Type = "number", Notes = "Z-coord of the explosion center" }, - { Name = "Source", Type = "eExplosionSource", Notes = "Source of the explosion. See the table above." }, - { Name = "SourceData", Type = "varies", Notes = "Additional data for the source. The exact type varies by the source. See the table above." }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called, and finally - MCServer will process the explosion - destroy blocks and push + hurt entities. If the function - returns true, no other callback is called for this event and the explosion will not occur. - ]], - }, -- HOOK_EXPLODING - - HOOK_HANDSHAKE = - { - CalledWhen = "A client is connecting.", - DefaultFnName = "OnHandshake", -- also used as pagename - Desc = [[ - This hook is called when a client sends the Handshake packet. At this stage, only the client IP and - (unverified) username are known. Plugins may refuse access to the server based on this - information.

-

- Note that the username is not authenticated - the authentication takes place only after this hook is - processed. - ]], - Params = - { - { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client handle representing the connection. Note that there's no {{cPlayer}} object for this client yet." }, - { Name = "UserName", Type = "string", Notes = "The username presented in the packet. Note that this username is unverified." }, - }, - Returns = [[ - If the function returns false, the user is let in to the server. If the function returns true, no - other plugin's callback is called, the user is kicked and the connection is closed. - ]], - }, -- HOOK_HANDSHAKE - - HOOK_HOPPER_PULLING_ITEM = - { - CalledWhen = "A hopper is pulling an item from another block entity.", - DefaultFnName = "OnHopperPullingItem", -- also used as pagename - Desc = [[ - This callback is called whenever a {{cHopperEntity|hopper}} transfers an {{cItem|item}} from another - block entity into its own internal storage. A plugin may decide to disallow the move by returning - true. Note that in such a case, the hook may be called again for the same hopper, with different - slot numbers. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "World where the hopper resides" }, - { Name = "Hopper", Type = "{{cHopperEntity}}", Notes = "The hopper that is pulling the item" }, - { Name = "DstSlot", Type = "number", Notes = "The destination slot in the hopper's {{cItemGrid|internal storage}}" }, - { Name = "SrcBlockEntity", Type = "{{cBlockEntityWithItems}}", Notes = "The block entity that is losing the item" }, - { Name = "SrcSlot", Type = "number", Notes = "Slot in SrcBlockEntity from which the item will be pulled" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event and the hopper will not pull the item. - ]], - }, -- HOOK_HOPPER_PULLING_ITEM - - HOOK_HOPPER_PUSHING_ITEM = - { - CalledWhen = "A hopper is pushing an item into another block entity. ", - DefaultFnName = "OnHopperPushingItem", -- also used as pagename - Desc = [[ - This hook is called whenever a {{cHopperEntity|hopper}} transfers an {{cItem|item}} from its own - internal storage into another block entity. A plugin may decide to disallow the move by returning - true. Note that in such a case, the hook may be called again for the same hopper and block, with - different slot numbers. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "World where the hopper resides" }, - { Name = "Hopper", Type = "{{cHopperEntity}}", Notes = "The hopper that is pushing the item" }, - { Name = "SrcSlot", Type = "number", Notes = "Slot in the hopper that will lose the item" }, - { Name = "DstBlockEntity", Type = "{{cBlockEntityWithItems}}", Notes = " The block entity that will receive the item" }, - { Name = "DstSlot", Type = "number", Notes = " Slot in DstBlockEntity's internal storage where the item will be stored" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event and the hopper will not push the item. - ]], - }, -- HOOK_HOPPER_PUSHING_ITEM - - HOOK_KILLING = - { - CalledWhen = "A player or a mob is dying.", - DefaultFnName = "OnKilling", -- also used as pagename - Desc = [[ - This hook is called whenever a {{cPawn|pawn}}'s (a player's or a mob's) health reaches zero. This - means that the pawn is about to be killed, unless a plugin "revives" them by setting their health - back to a positive value.

-

- FIXME: There is no HOOK_KILLED notification hook yet; this is deliberate because HOOK_KILLED has - been recently renamed to HOOK_KILLING, and plugins need to be updated. Once updated, the HOOK_KILLED - notification will be implemented. - ]], - Params = - { - { Name = "Victim", Type = "{{cPawn}}", Notes = "The player or mob that is about to be killed" }, - { Name = "Killer", Type = "{{cEntity}}", Notes = "The entity that has caused the victim to lose the last point of health. May be nil for environment damage" }, - }, - Returns = [[ - If the function returns false or no value, MCServer calls other plugins with this event. If the - function returns true, no other plugin is called for this event.

-

- In either case, the victim's health is then re-checked and if it is greater than zero, the victim is - "revived" with that health amount. If the health is less or equal to zero, the victim is killed. - ]], - }, -- HOOK_KILLING - - HOOK_LOGIN = - { - CalledWhen = "Right before player authentication. If auth is disabled, right after the player sends their name.", - DefaultFnName = "OnLogin", -- also used as pagename - Desc = [[ - This hook is called whenever a client logs in. It is called right before the client's name is sent - to be authenticated. Plugins may refuse the client from accessing the server. Note that when this - callback is called, the {{cPlayer}} object for this client doesn't exist yet - the client has no - representation in any world. To process new players when their world is known, use a later callback, - such as {{OnPlayerJoined|HOOK_PLAYER_JOINED}} or {{OnPlayerSpawned|HOOK_PLAYER_SPAWNED}}. - ]], - Params = - { - { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client handle representing the connection" }, - { Name = "ProtocolVersion", Type = "number", Notes = "Versio of the protocol that the client is talking" }, - { Name = "UserName", Type = "string", Notes = "The name that the client has presented for authentication. This name will be given to the {{cPlayer}} object when it is created for this client." }, - }, - Returns = [[ - If the function returns true, no other plugins are called for this event and the client is kicked. - If the function returns false or no value, MCServer calls other plugins' callbacks and finally - sends an authentication request for the client's username to the auth server. If the auth server - is disabled in the server settings, the player object is immediately created. - ]], - }, -- HOOK_LOGIN - - HOOK_PLAYER_ANIMATION = - { - CalledWhen = "A client has sent an Animation packet (0x12)", - DefaultFnName = "OnPlayerAnimation", -- also used as pagename - Desc = [[ - This hook is called when the server receives an Animation packet (0x12) from the client.

-

- For the list of animations that are sent by the client, see the - Protocol wiki. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player from whom the packet was received" }, - { Name = "Animation", Type = "number", Notes = "The kind of animation" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. Afterwards, the - server broadcasts the animation packet to all nearby clients. If the function returns true, no other - callback is called for this event and the packet is not broadcasted. - ]], - }, -- HOOK_PLAYER_ANIMATION - - HOOK_PLAYER_BREAKING_BLOCK = - { - CalledWhen = "Just before a player breaks a block. Plugin may override / refuse. ", - DefaultFnName = "OnPlayerBreakingBlock", -- also used as pagename - Desc = [[ - This hook is called when a {{cPlayer|player}} breaks a block, before the block is actually broken in - the {{cWorld|World}}. Plugins may refuse the breaking.

-

- See also the {{OnPlayerBrokenBlock|HOOK_PLAYER_BROKEN_BLOCK}} hook for a similar hook called after - the block is broken. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is digging the block" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player is acting. One of the BLOCK_FACE_ constants" }, - { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block being broken" }, - { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block being broken " }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called, and then the block - is broken. If the function returns true, no other plugin's callback is called and the block breaking - is cancelled. The server re-sends the block back to the player to replace it (the player's client - already thinks the block was broken). - ]], - }, -- HOOK_PLAYER_BREAKING_BLOCK - - HOOK_PLAYER_BROKEN_BLOCK = - { - CalledWhen = "After a player has broken a block. Notification only.", - DefaultFnName = "OnPlayerBrokenBlock", -- also used as pagename - Desc = [[ - This function is called after a {{cPlayer|player}} breaks a block. The block is already removed - from the {{cWorld|world}} and {{cPickup|pickups}} have been spawned. To get the world in which the - block has been dug, use the {{cPlayer}}:GetWorld() function.

-

- See also the {{OnPlayerBreakingBlock|HOOK_PLAYER_BREAKING_BLOCK}} hook for a similar hook called - before the block is broken. To intercept the creation of pickups, see the - {{OnBlockToPickups|HOOK_BLOCK_TO_PICKUPS}} hook. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who broke the block" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, - { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, - { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event. - ]], - }, -- HOOK_PLAYER_BROKEN_BLOCK - - HOOK_PLAYER_EATING = - { - CalledWhen = "When the player starts eating", - DefaultFnName = "OnPlayerEating", -- also used as pagename - Desc = [[ - This hook gets called when the {{cPlayer|player}} starts eating, after the server checks that the - player can indeed eat (is not satiated and is holding food). Plugins may still refuse the eating by - returning true. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who started eating" }, - }, - Returns = [[ - If the function returns false or no value, the server calls the next plugin handler, and finally - lets the player eat. If the function returns true, the server doesn't call any more callbacks for - this event and aborts the eating. A "disallow" packet is sent to the client. - ]], - }, -- HOOK_PLAYER_EATING - - HOOK_PLAYER_JOINED = - { - CalledWhen = "After Login and before Spawned, before being added to world. ", - DefaultFnName = "OnPlayerJoined", -- also used as pagename - Desc = [[ - This hook is called whenever a {{cPlayer|player}} has completely logged in. If authentication is - enabled, this function is called after their name has been authenticated. It is called after - {{OnLogin|HOOK_LOGIN}} and before {{OnPlayerSpawned|HOOK_PLAYER_SPAWNED}}, right after the player's - entity is created, but not added to the world yet. The player is not yet visible to other players. - This is a notification-only event, plugins wishing to refuse player's entry should kick the player - using the {{cPlayer}}:Kick() function. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has joined the game" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called. If the function - returns true, no other callbacks are called for this event. Either way the player is let in. - ]], - }, -- HOOK_PLAYER_JOINED - - HOOK_PLAYER_LEFT_CLICK = - { - CalledWhen = "A left-click packet is received from the client. Plugin may override / refuse.", - DefaultFnName = "OnPlayerLeftClick", -- also used as pagename - Desc = [[ - This hook is called when MCServer receives a left-click packet from the {{cClientHandle|client}}. It - is called before any processing whatsoever is performed on the packet, meaning that hacked / - malicious clients may be trigerring this event very often and with unchecked parameters. Therefore - plugin authors are advised to use extreme caution with this callback.

-

- Plugins may refuse the default processing for the packet, causing MCServer to behave as if the - packet has never arrived. This may, however, create inconsistencies in the client - the client may - think that they broke a block, while the server didn't process the breaking, etc. For this reason, - if a plugin refuses the processing, MCServer sends the block specified in the packet back to the - client (as if placed anew), if the status code specified a block-break action. For other actions, - plugins must rectify the situation on their own.

-

- The client sends the left-click packet for several other occasions, such as dropping the held item - (Q keypress) or shooting an arrow. This is reflected in the Status code. Consult the - protocol documentation for details on the actions. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose client sent the packet" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, - { Name = "Action", Type = "number", Notes = "Action to be performed on the block (\"status\" in the protocol docs)" }, - }, - Returns = [[ - If the function returns false or no value, MCServer calls other plugins' callbacks and finally sends - the packet for further processing.

-

- If the function returns true, no other plugins are called, processing is halted. If the action was a - block dig, MCServer sends the block specified in the coords back to the client. The packet is - dropped. - ]], - }, -- HOOK_PLAYER_LEFT_CLICK - - HOOK_PLAYER_MOVING = - { - CalledWhen = "Player tried to move in the tick being currently processed. Plugin may refuse movement.", - DefaultFnName = "OnPlayerMoving", -- also used as pagename - Desc = [[ - This function is called in each server tick for each {{cPlayer|player}} that has sent any of the - player-move packets. Plugins may refuse the movement. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has moved. The object already has the new position stored in it." }, - }, - Returns = [[ - If the function returns true, movement is prohibited. FIXME: The player's client is not informed.

-

- If the function returns false or no value, other plugins' callbacks are called and finally the new - position is permanently stored in the cPlayer object.

- ]], - }, -- HOOK_PLAYER_MOVING - - HOOK_PLAYER_PLACED_BLOCK = - { - CalledWhen = "After a player has placed a block. Notification only.", - DefaultFnName = "OnPlayerPlacedBlock", -- also used as pagename - Desc = [[ - This hook is called after a {{cPlayer|player}} has placed a block in the {{cWorld|world}}. The block - is already added to the world and the corresponding item removed from player's - {{cInventory|inventory}}.

-

- Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.

-

- See also the {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}} hook for a similar hook called - before the placement. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who placed the block" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of the existing block upon which the player interacted. One of the BLOCK_FACE_ constants" }, - { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor within the block face (0 .. 15)" }, - { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor within the block face (0 .. 15)" }, - { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor within the block face (0 .. 15)" }, - { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, - { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, - }, - Returns = [[ - If this function returns false or no value, MCServer calls other plugins with the same event. If - this function returns true, no other plugin is called for this event. - ]], - }, -- HOOK_PLAYER_PLACED_BLOCK - - HOOK_PLAYER_PLACING_BLOCK = - { - CalledWhen = "Just before a player places a block. Plugin may override / refuse.", - DefaultFnName = "OnPlayerPlacingBlock", -- also used as pagename - Desc = [[ - This hook is called just before a {{cPlayer|player}} places a block in the {{cWorld|world}}. The - block is not yet placed, plugins may choose to override the default behavior or refuse the placement - at all.

-

- Note that the client already expects that the block has been placed. For that reason, if a plugin - refuses the placement, MCServer sends the old block at the provided coords to the client.

-

- Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.

-

- See also the {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}} hook for a similar hook called after - the placement. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is placing the block" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of the existing block upon which the player is interacting. One of the BLOCK_FACE_ constants" }, - { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor within the block face (0 .. 15)" }, - { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor within the block face (0 .. 15)" }, - { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor within the block face (0 .. 15)" }, - { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, - { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, - }, - Returns = [[ - If this function returns false or no value, MCServer calls other plugins with the same event and - finally places the block and removes the corresponding item from player's inventory. If this - function returns true, no other plugin is called for this event, MCServer sends the old block at - the specified coords to the client and drops the packet. - ]], - }, -- HOOK_PLAYER_PLACING_BLOCK - - HOOK_PLAYER_RIGHT_CLICK = - { - CalledWhen = "A right-click packet is received from the client. Plugin may override / refuse.", - DefaultFnName = "OnPlayerRightClick", -- also used as pagename - Desc = [[ - This hook is called when MCServer receives a right-click packet from the {{cClientHandle|client}}. It - is called before any processing whatsoever is performed on the packet, meaning that hacked / - malicious clients may be trigerring this event very often and with unchecked parameters. Therefore - plugin authors are advised to use extreme caution with this callback.

-

- Plugins may refuse the default processing for the packet, causing MCServer to behave as if the - packet has never arrived. This may, however, create inconsistencies in the client - the client may - think that they placed a block, while the server didn't process the placing, etc. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose client sent the packet" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, - }, - Returns = [[ - If the function returns false or no value, MCServer calls other plugins' callbacks and finally sends - the packet for further processing.

-

- If the function returns true, no other plugins are called, processing is halted. - ]], - }, -- HOOK_PLAYER_RIGHT_CLICK - - HOOK_PLAYER_RIGHT_CLICKING_ENTITY = - { - CalledWhen = "A player has right-clicked an entity. Plugins may override / refuse.", - DefaultFnName = "OnPlayerRightClickingEntity", -- also used as pagename - Desc = [[ - This hook is called when the {{cPlayer|player}} right-clicks an {{cEntity|entity}}. Plugins may - override the default behavior or even cancel the default processing. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has right-clicked the entity" }, - { Name = "Entity", Type = "{{cEntity}} descendant", Notes = "The entity that has been right-clicked" }, - }, - Returns = [[ - If the functino returns false or no value, MCServer calls other plugins' callbacks and finally does - the default processing for the right-click. If the function returns true, no other callbacks are - called and the default processing is skipped. - ]], - }, -- HOOK_PLAYER_RIGHT_CLICKING_ENTITY - - HOOK_PLAYER_SHOOTING = - { - CalledWhen = "When the player releases the bow, shooting an arrow (other projectiles: unknown)", - DefaultFnName = "OnPlayerShooting", -- also used as pagename - Desc = [[ - This hook is called when the {{cPlayer|player}} shoots their bow. It is called for the actual - release of the {{cArrowEntity|arrow}}. FIXME: It is currently unknown whether other - {{cProjectileEntity|projectiles}} (snowballs, eggs) trigger this hook.

-

- To get the player's position and direction, use the {{cPlayer}}:GetEyePosition() and - cPlayer:GetLookVector() functions. Note that for shooting a bow, the position for the arrow creation - is not at the eye pos, some adjustments are required. FIXME: Export the {{cPlayer}} function for - this adjustment. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player shooting" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called, and finally - MCServer creates the projectile. If the functino returns true, no other callback is called and no - projectile is created. - ]], - }, -- HOOK_PLAYER_SHOOTING - - HOOK_PLAYER_SPAWNED = - { - CalledWhen = "After a player (re)spawns in the world to which they belong to.", - DefaultFnName = "OnPlayerSpawned", -- also used as pagename - Desc = [[ - This hook is called after a {{cPlayer|player}} has spawned in the world. It is called after - {{OnLogin|HOOK_LOGIN}} and {{OnPlayerJoined|HOOK_PLAYER_JOINED}}, after the player name has been - authenticated, the initial worldtime, inventory and health have been sent to the player and the - player spawn packet has been broadcast to all players near enough to the player spawn place. This is - a notification-only event, plugins wishing to refuse player's entry should kick the player using the - {{cPlayer}}:Kick() function.

-

- This hook is also called when the player respawns after death (and a respawn packet is received from - the client, meaning the player has already clicked the Respawn button). - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has (re)spawned" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called. If the function - returns true, no other callbacks are called for this event. There is no overridable behavior. - ]], - }, -- HOOK_PLAYER_SPAWNED - - HOOK_PLAYER_TOSSING_ITEM = - { - CalledWhen = "A player is tossing an item. Plugin may override / refuse.", - DefaultFnName = "OnPlayerTossingItem", -- also used as pagename - Desc = [[ - This hook is called when a {{cPlayer|player}} has tossed an item (Q keypress). The - {{cPickup|pickup}} has not been spawned yet. Plugins may disallow the tossing, but in that case they - need to clean up - the player's client already thinks the item has been tossed so the - {{cInventory|inventory}} needs to be re-sent to the player.

-

- To get the item that is about to be tossed, call the {{cPlayer}}:GetEquippedItem() function. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player tossing an item" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called and finally MCServer - creates the pickup for the item and tosses it, using {{cPlayer}}:TossItem. If the function returns - true, no other callbacks are called for this event and MCServer doesn't toss the item. - ]], - }, -- HOOK_PLAYER_TOSSING_ITEM - - HOOK_PLAYER_USED_BLOCK = - { - CalledWhen = "A player has just used a block (chest, furnace). Notification only.", - DefaultFnName = "OnPlayerUsedBlock", -- also used as pagename - Desc = [[ - This hook is called after a {{cPlayer|player}} has right-clicked a block that can be used, such as a - {{cChestEntity|chest}} or a lever. It is called after MCServer processes the usage (sends the UI - handling packets / toggles redstone). Note that for UI-related blocks, the player is most likely - still using the UI. This is a notification-only event.

-

- Note that the block coords given in this callback are for the (solid) block that is being clicked, - not the air block between it and the player.

-

- To get the world at which the right-click occurred, use the {{cPlayer}}:GetWorld() function.

-

- See also the {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}} for a similar hook called before the - use, the {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} and {{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}} - for similar hooks called when a player interacts with any block with a usable item in hand, such as - a bucket. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who used the block" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the clicked block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the clicked block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the clicked block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of clicked block which has been clicked. One of the BLOCK_FACE_ constants" }, - { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor crosshair on the block being clicked" }, - { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor crosshair on the block being clicked" }, - { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor crosshair on the block being clicked" }, - { Name = "BlockType", Type = "number", Notes = "Block type of the clicked block" }, - { Name = "BlockMeta", Type = "number", Notes = "Block meta of the clicked block" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called. If the function - returns true, no other callbacks are called for this event. - ]], - }, -- HOOK_PLAYER_USED_BLOCK - - HOOK_PLAYER_USED_ITEM = - { - CalledWhen = "A player has used an item in hand (bucket...)", - DefaultFnName = "OnPlayerUsedItem", -- also used as pagename - Desc = [[ - This hook is called after a {{cPlayer|player}} has right-clicked a block with an {{cItem|item}} that - can be used (is not placeable, is not food and clicked block is not use-able), such as a bucket or a - hoe. It is called after MCServer processes the usage (places fluid / turns dirt to farmland). - This is an information-only hook, there is no way to cancel the event anymore.

-

- Note that the block coords given in this callback are for the (solid) block that is being clicked, - not the air block between it and the player.

-

- To get the world at which the right-click occurred, use the {{cPlayer}}:GetWorld() function. To get - the item that the player is using, use the {{cPlayer}}:GetEquippedItem() function.

-

- See also the {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} for a similar hook called before the use, - the {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}} and {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}} - for similar hooks called when a player interacts with a block, such as a chest. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who used the item" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the clicked block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the clicked block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the clicked block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of clicked block which has been clicked. One of the BLOCK_FACE_ constants" }, - { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor crosshair on the block being clicked" }, - { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor crosshair on the block being clicked" }, - { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor crosshair on the block being clicked" }, - { Name = "BlockType", Type = "number", Notes = "Block type of the clicked block" }, - { Name = "BlockMeta", Type = "number", Notes = "Block meta of the clicked block" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called. If the function - returns true, no other callbacks are called for this event. - ]], - }, -- HOOK_PLAYER_USED_ITEM - - HOOK_PLAYER_USING_BLOCK = - { - CalledWhen = "Just before a player uses a block (chest, furnace...). Plugin may override / refuse.", - DefaultFnName = "OnPlayerUsingBlock", -- also used as pagename - Desc = [[ - This hook is called when a {{cPlayer|player}} has right-clicked a block that can be used, such as a - {{cChestEntity|chest}} or a lever. It is called before MCServer processes the usage (sends the UI - handling packets / toggles redstone). Plugins may refuse the interaction by returning true.

-

- Note that the block coords given in this callback are for the (solid) block that is being clicked, - not the air block between it and the player.

-

- To get the world at which the right-click occurred, use the {{cPlayer}}:GetWorld() function.

-

- See also the {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}} for a similar hook called after the use, the - {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} and {{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}} for - similar hooks called when a player interacts with any block with a usable item in hand, such as a - bucket. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is using the block" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the clicked block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the clicked block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the clicked block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of clicked block which has been clicked. One of the BLOCK_FACE_ constants" }, - { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor crosshair on the block being clicked" }, - { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor crosshair on the block being clicked" }, - { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor crosshair on the block being clicked" }, - { Name = "BlockType", Type = "number", Notes = "Block type of the clicked block" }, - { Name = "BlockMeta", Type = "number", Notes = "Block meta of the clicked block" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called and then MCServer - processes the interaction. If the function returns true, no other callbacks are called for this - event and the interaction is silently dropped. - ]], - }, -- HOOK_PLAYER_USING_BLOCK - - HOOK_PLAYER_USING_ITEM = - { - CalledWhen = "Just before a player uses an item in hand (bucket...). Plugin may override / refuse.", - DefaultFnName = "OnPlayerUsingItem", -- also used as pagename - Desc = [[ - This hook is called when a {{cPlayer|player}} has right-clicked a block with an {{cItem|item}} that - can be used (is not placeable, is not food and clicked block is not use-able), such as a bucket or a - hoe. It is called before MCServer processes the usage (places fluid / turns dirt to farmland). - Plugins may refuse the interaction by returning true.

-

- Note that the block coords given in this callback are for the (solid) block that is being clicked, - not the air block between it and the player.

-

- To get the world at which the right-click occurred, use the {{cPlayer}}:GetWorld() function. To get - the item that the player is using, use the {{cPlayer}}:GetEquippedItem() function.

-

- See also the {{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}} for a similar hook called after the use, the - {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}} and {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}} for - similar hooks called when a player interacts with a block, such as a chest. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is using the item" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the clicked block" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the clicked block" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the clicked block" }, - { Name = "BlockFace", Type = "number", Notes = "Face of clicked block which has been clicked. One of the BLOCK_FACE_ constants" }, - { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor crosshair on the block being clicked" }, - { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor crosshair on the block being clicked" }, - { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor crosshair on the block being clicked" }, - { Name = "BlockType", Type = "number", Notes = "Block type of the clicked block" }, - { Name = "BlockMeta", Type = "number", Notes = "Block meta of the clicked block" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called and then MCServer - processes the interaction. If the function returns true, no other callbacks are called for this - event and the interaction is silently dropped. - ]], - }, -- HOOK_PLAYER_USING_ITEM - - HOOK_POST_CRAFTING = - { - CalledWhen = "After the built-in recipes are checked and a recipe was found.", - DefaultFnName = "OnPostCrafting", -- also used as pagename - Desc = [[ - This hook is called when a {{cPlayer|player}} changes contents of their - {{cCraftingGrid|crafting grid}}, after the recipe has been established by MCServer. Plugins may use - this to modify the resulting recipe or provide an alternate recipe.

-

- If a plugin implements custom recipes, it should do so using the {{OnPreCrafting|HOOK_PRE_CRAFTING}} - hook, because that will save the server from going through the built-in recipes. The - HOOK_POST_CRAFTING hook is intended as a notification, with a chance to tweak the result.

-

- Note that this hook is not called if a built-in recipe is not found; - {{OnCraftingNoRecipe|HOOK_CRAFTING_NO_RECIPE}} is called instead in such a case. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has changed their crafting grid contents" }, - { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "The new crafting grid contents" }, - { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that MCServer has decided to use (can be tweaked by plugins)" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called. If the function - returns true, no other callbacks are called for this event. In either case, MCServer uses the value - of Recipe as the recipe to be presented to the player. - ]], - }, -- HOOK_POST_CRAFTING - - HOOK_PRE_CRAFTING = - { - CalledWhen = "Before the built-in recipes are checked.", - DefaultFnName = "OnPreCrafting", -- also used as pagename - Desc = [[ - This hook is called when a {{cPlayer|player}} changes contents of their - {{cCraftingGrid|crafting grid}}, before the built-in recipes are searched for a match by MCServer. - Plugins may use this hook to provide a custom recipe.

-

- If you intend to tweak built-in recipes, use the {{OnPostCrafting|HOOK_POST_CRAFTING}} hook, because - that will be called once the built-in recipe is matched.

-

- Also note a third hook, {{OnCraftingNoRecipe|HOOK_CRAFTING_NO_RECIPE}}, that is called when MCServer - cannot find any built-in recipe for the given ingredients. - ]], - Params = - { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has changed their crafting grid contents" }, - { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "The new crafting grid contents" }, - { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that MCServer will use. Modify this object to change the recipe" }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called and then MCServer - searches the built-in recipes. The Recipe output parameter is ignored in this case.

-

- If the function returns true, no other callbacks are called for this event and MCServer uses the - recipe stored in the Recipe output parameter. - ]], - }, -- HOOK_PRE_CRAFTING - - HOOK_SPAWNED_ENTITY = - { - CalledWhen = "After an entity is spawned in the world.", - DefaultFnName = "OnSpawnedEntity", -- also used as pagename - Desc = [[ - This hook is called after the server spawns an {{cEntity|entity}}. This is an information-only - callback, the entity is already spawned by the time it is called. If the entity spawned is a - {{cMonster|monster}}, the {{OnSpawnedMonster|HOOK_SPAWNED_MONSTER}} hook is called before this - hook.

-

- See also the {{OnSpawningEntity|HOOK_SPAWNING_ENTITY}} hook for a similar hook called before the - entity is spawned. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity has spawned" }, - { Name = "Entity", Type = "{{cEntity}} descentant", Notes = "The entity that has spawned" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event. - ]], - }, -- HOOK_SPAWNED_ENTITY - - HOOK_SPAWNED_MONSTER = - { - CalledWhen = "After a monster is spawned in the world", - DefaultFnName = "OnSpawnedMonster", -- also used as pagename - Desc = [[ - This hook is called after the server spawns a {{cMonster|monster}}. This is an information-only - callback, the monster is already spawned by the time it is called. After this hook is called, the - {{OnSpawnedEntity|HOOK_SPAWNED_ENTITY}} is called for the monster entity.

-

- See also the {{OnSpawningMonster|HOOK_SPAWNING_MONSTER}} hook for a similar hook called before the - monster is spawned. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the monster has spawned" }, - { Name = "Monster", Type = "{{cMonster}} descendant", Notes = "The monster that has spawned" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event. - ]], - }, -- HOOK_SPAWNED_MONSTER - - HOOK_SPAWNING_ENTITY = - { - CalledWhen = "Before an entity is spawned in the world.", - DefaultFnName = "OnSpawningEntity", -- also used as pagename - Desc = [[ - This hook is called before the server spawns an {{cEntity|entity}}. The plugin can either modify the - entity before it is spawned, or disable the spawning altogether. If the entity spawning is a - monster, the {{OnSpawningMonster|HOOK_SPAWNING_MONSTER}} hook is called before this hook.

-

- See also the {{OnSpawnedEntity|HOOK_SPAWNED_ENTITY}} hook for a similar hook called after the - entity is spawned. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity will spawn" }, - { Name = "Entity", Type = "{{cEntity}} descentant", Notes = "The entity that will spawn" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. Finally, the server - spawns the entity with whatever parameters have been set on the {{cEntity}} object by the callbacks. - If the function returns true, no other callback is called for this event and the entity is not - spawned. - ]], - }, -- HOOK_SPAWNING_ENTITY - - HOOK_SPAWNING_MONSTER = - { - CalledWhen = "Before a monster is spawned in the world.", - DefaultFnName = "OnSpawningMonster", -- also used as pagename - Desc = [[ - This hook is called before the server spawns a {{cMonster|monster}}. The plugins may modify the - monster's parameters in the {{cMonster}} class, or disallow the spawning altogether. This hook is - called before the {{OnSpawningEntity|HOOK_SPAWNING_ENTITY}} is called for the monster entity.

-

- See also the {{OnSpawnedMonster|HOOK_SPAWNED_MONSTER}} hook for a similar hook called after the - monster is spawned. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity will spawn" }, - { Name = "Monster", Type = "{{cMonster}} descentant", Notes = "The monster that will spawn" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. Finally, the server - spawns the monster with whatever parameters the plugins set in the cMonster parameter.

-

- If the function returns true, no other callback is called for this event and the monster won't - spawn. - ]], - }, -- HOOK_SPAWNING_MONSTER - - HOOK_TAKE_DAMAGE = - { - CalledWhen = "An {{cEntity|entity}} is taking any kind of damage", - DefaultFnName = "OnTakeDamage", -- also used as pagename - Desc = [[ - This hook is called when any {{cEntity}} descendant, such as a {{cPlayer|player}} or a - {{cMonster|mob}}, takes any kind of damage. The plugins may modify the amount of damage or effects - with this hook by editting the {{TakeDamageInfo}} object passed.

-

- This hook is called after the final damage is calculated, including all the possible weapon - {{cEnchantments|enchantments}}, armor protection and potion effects. - ]], - Params = - { - { Name = "Receiver", Type = "{{cEntity}} descendant", Notes = "The entity taking damage" }, - { Name = "TDI", Type = "{{TakeDamageInfo}}", Notes = "The damage type, cause and effects. Plugins may modify this object to alter the final damage applied." }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called and then the server - applies the final values from the TDI object to Receiver. If the function returns true, no other - callbacks are called, and no damage nor effects are applied. - ]], - }, -- HOOK_TAKE_DAMAGE - - HOOK_TICK = - { - CalledWhen = "Every server tick (approximately 20 times per second)", - DefaultFnName = "OnTick", -- also used as pagename - Desc = [[ - This hook is called every game tick (50 msec, or 20 times a second). If the server is overloaded, - the interval is larger, which is indicated by the TimeDelta parameter.

-

- This hook is called in the context of the server-tick thread, that is, the thread that takes care of - {{cClientHandle|client connections}} before they're assigned to {{cPlayer|player entities}}, and - processing console commands. - ]], - Params = - { - { Name = "TimeDelta", Type = "number", Notes = "The number of milliseconds elapsed since the last server tick. Will not be less than 50 msec." }, - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called. If the function - returns true, no other callbacks are called. There is no overridable behavior. - ]], - }, -- HOOK_TICK - - HOOK_UPDATED_SIGN = - { - CalledWhen = "After the sign text is updated. Notification only.", - DefaultFnName = "OnUpdatedSign", -- also used as pagename - Desc = [[ - This hook is called after a sign has had its text updated. The text is already updated at this - point.

-

The update may have been caused either by a {{cPlayer|player}} directly updating the sign, or by - a plugin changing the sign text using the API.

-

- See also the {{OnUpdatingSign|HOOK_UPDATING_SIGN}} hook for a similar hook called before the update, - with a chance to modify the text. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the sign resides" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the sign" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the sign" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the sign" }, - { Name = "Line1", Type = "string", Notes = "1st line of the new text" }, - { Name = "Line2", Type = "string", Notes = "2nd line of the new text" }, - { Name = "Line3", Type = "string", Notes = "3rd line of the new text" }, - { Name = "Line4", Type = "string", Notes = "4th line of the new text" }, - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is changing the text. May be nil for non-player updates." } - }, - Returns = [[ - If the function returns false or no value, other plugins' callbacks are called. If the function - returns true, no other callbacks are called. There is no overridable behavior. - ]], - }, -- HOOK_UPDATED_SIGN - HOOK_UPDATING_SIGN = - { - CalledWhen = "Before the sign text is updated. Plugin may modify the text / refuse.", - DefaultFnName = "OnUpdatingSign", -- also used as pagename - Desc = [[ - This hook is called when a sign text is about to be updated, either as a result of player's - manipulation or any other event, such as a plugin setting the sign text. Plugins may modify the text - or refuse the update altogether.

-

- See also the {{OnUpdatedSign|HOOK_UPDATED_SIGN}} hook for a similar hook called after the update. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the sign resides" }, - { Name = "BlockX", Type = "number", Notes = "X-coord of the sign" }, - { Name = "BlockY", Type = "number", Notes = "Y-coord of the sign" }, - { Name = "BlockZ", Type = "number", Notes = "Z-coord of the sign" }, - { Name = "Line1", Type = "string", Notes = "1st line of the new text" }, - { Name = "Line2", Type = "string", Notes = "2nd line of the new text" }, - { Name = "Line3", Type = "string", Notes = "3rd line of the new text" }, - { Name = "Line4", Type = "string", Notes = "4th line of the new text" }, - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is changing the text. May be nil for non-player updates." } - }, - Returns = [[ - The function may return up to five values. If the function returns true as the first value, no other - callbacks are called for this event and the sign is not updated. If the function returns no value or - false as its first value, other plugins' callbacks are called.

-

- The other up to four values returned are used to update the sign text, line by line, respectively. - Note that other plugins may again update the texts (if the first value returned is false). - ]], - CodeExamples = - { - { - Title = "Add player signature", - Desc = "The following example appends a player signature to the last line, if the sign is updated by a player:", - Code = [[ -function OnUpdatingSign(World, BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4, Player) - if (Player == nil) then - -- Not changed by a player - return false; - end - - -- Sign with playername, allow other plugins to interfere: - return false, Line1, Line2, Line3, Line4 .. Player:GetName(); -end - ]], - } - } , - }, -- HOOK_UPDATING_SIGN - - HOOK_WEATHER_CHANGED = - { - CalledWhen = "The weather has changed", - DefaultFnName = "OnWeatherChanged", -- also used as pagename - Desc = [[ - This hook is called after the weather has changed in a {{cWorld|world}}. The new weather has already - been sent to the clients.

-

- See also the {{OnWeatherChanging|HOOK_WEATHER_CHANGING}} hook for a similar hook called before the - change. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "World for which the weather has changed" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event. There is no overridable behavior. - ]], - }, -- HOOK_WEATHER_CHANGED - - HOOK_WEATHER_CHANGING = - { - CalledWhen = "The weather is about to change", - DefaultFnName = "OnWeatherChanging", -- also used as pagename - Desc = [[ - This hook is called when the current weather has expired and a new weather is selected. Plugins may - override the new weather setting.

-

- The new weather setting is sent to the clients only after this hook has been processed.

-

- See also the {{OnWeatherChanged|HOOK_WEATHER_CHANGED}} hook for a similar hook called after the - change. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "World for which the weather is changing" }, - { Name = "Weather", Type = "number", Notes = "The newly selected weather. One of wSunny, wRain, wStorm" }, - }, - Returns = [[ - If the function returns false or no value, the server calls other plugins' callbacks and finally - sets the weather. If the function returns true, the server takes the second returned value (wSunny - by default) and sets it as the new weather. No other plugins' callbacks are called in this case. - ]], - }, -- HOOK_WEATHER_CHANGING - - HOOK_WORLD_TICK = - { - CalledWhen = "Every world tick (about 20 times per second), separately for each world", - DefaultFnName = "OnWorldTick", -- also used as pagename - Desc = [[ - This hook is called for each {{cWorld|world}} every tick (50 msec, or 20 times a second). If the - world is overloaded, the interval is larger, which is indicated by the TimeDelta parameter.

-

- This hook is called in the world's tick thread context and thus has access to all world data - guaranteed without blocking. - ]], - Params = - { - { Name = "World", Type = "{{cWorld}}", Notes = "World that is ticking" }, - { Name = "TimeDelta", Type = "number", Notes = "The number of milliseconds since the previous game tick. Will not be less than 50 msec" }, - }, - Returns = [[ - If the function returns false or no value, the next plugin's callback is called. If the function - returns true, no other callback is called for this event. There is no overridable behavior. - ]], - }, -- HOOK_WORLD_TICK - - }, -- Hooks[] - - - IgnoreClasses = - { - "coroutine", - "debug", - "io", - "math", - "package", - "os", - "string", - "table", - "g_TrackedPages", - "g_Stats", - }, - - IgnoreFunctions = - { - "Globals.assert", - "Globals.collectgarbage", - "Globals.xpcall", - "Globals.decoda_output", -- When running under Decoda, this function gets added to the global namespace - "%a+\.__%a+", -- AnyClass.__Anything - "%a+\.\.collector", -- AnyClass..collector - "%a+\.new", -- AnyClass.new - "%a+.new_local", -- AnyClass.new_local - "%a+.delete", -- AnyClass.delete + IgnoreFunctions = + { + "Globals.assert", + "Globals.collectgarbage", + "Globals.xpcall", + "Globals.decoda_output", -- When running under Decoda, this function gets added to the global namespace + "%a+\.__%a+", -- AnyClass.__Anything + "%a+\.\.collector", -- AnyClass..collector + "%a+\.new", -- AnyClass.new + "%a+.new_local", -- AnyClass.new_local + "%a+.delete", -- AnyClass.delete -- Functions global in the APIDump plugin: "CreateAPITables", @@ -4518,4 +2838,3 @@ end - diff --git a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua new file mode 100644 index 000000000..cf258160c --- /dev/null +++ b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua @@ -0,0 +1,243 @@ +return +{ + cBlockEntity = + { + Desc = [[ + Block entities are simply blocks in the world that have persistent data, such as the text for a sign + or contents of a chest. All block entities are also saved in the chunk data of the chunk they reside in. + The cBlockEntity class acts as a common ancestor for all the individual block entities. + ]], + + Functions = + { + GetBlockType = { Params = "", Return = "BLOCKTYPE", Notes = "Returns the blocktype which is represented by this blockentity. This is the primary means of type-identification" }, + GetChunkX = { Params = "", Return = "number", Notes = "Returns the chunk X-coord of the block entity's chunk" }, + GetChunkZ = { Params = "", Return = "number", Notes = "Returns the chunk Z-coord of the block entity's chunk" }, + GetPosX = { Params = "", Return = "number", Notes = "Returns the block X-coord of the block entity's block" }, + GetPosY = { Params = "", Return = "number", Notes = "Returns the block Y-coord of the block entity's block" }, + GetPosZ = { Params = "", Return = "number", Notes = "Returns the block Z-coord of the block entity's block" }, + GetRelX = { Params = "", Return = "number", Notes = "Returns the relative X coord of the block entity's block within the chunk" }, + GetRelZ = { Params = "", Return = "number", Notes = "Returns the relative Z coord of the block entity's block within the chunk" }, + GetWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world to which the block entity belongs" }, + }, + }, + + cBlockEntityWithItems = + { + Desc = [[ + This class is a common ancestor for all {{cBlockEntity|block entities}} that provide item storage. + Internally, the object has a {{cItemGrid|cItemGrid}} object for storing the items; this ItemGrid is + accessible through the API. The storage is a grid of items, items in it can be addressed either by a slot + number, or by XY coords within the grid. If a UI window is opened for this block entity, the item storage + is monitored for changes and the changes are immediately sent to clients of the UI window. + ]], + + Inherits = "cBlockEntity", + + Functions = + { + GetContents = { Params = "", Return = "{{cItemGrid|cItemGrid}}", Notes = "Returns the cItemGrid object representing the items stored within this block entity" }, + GetSlot = + { + { Params = "SlotNum", Return = "{{cItem|cItem}}", Notes = "Returns the cItem for the specified slot number. Returns nil for invalid slot numbers" }, + { Params = "X, Y", Return = "{{cItem|cItem}}", Notes = "Returns the cItem for the specified slot coords. Returns nil for invalid slot coords" }, + }, + SetSlot = + { + { Params = "SlotNum, {{cItem|cItem}}", Return = "", Notes = "Sets the cItem for the specified slot number. Ignored if invalid slot number" }, + { Params = "X, Y, {{cItem|cItem}}", Return = "", Notes = "Sets the cItem for the specified slot coords. Ignored if invalid slot coords" }, + }, + }, + }, + + cChestEntity = + { + Desc = [[ + A chest entity is a {{cBlockEntityWithItems|cBlockEntityWithItems}} descendant that represents a chest + in the world. Note that doublechests consist of two separate cChestEntity objects, they do not collaborate + in any way.

+

+ To manipulate a chest already in the game, you need to use {{cWorld}}'s callback mechanism with + either DoWithChestAt() or ForEachChestInChunk() function. See the code example below + ]], + + Inherits = "cBlockEntityWithItems", + + Constants = + { + ContentsHeight = { Notes = "Height of the contents' {{cItemGrid|ItemGrid}}, as required by the parent class, {{cBlockEntityWithItems}}" }, + ContentsWidth = { Notes = "Width of the contents' {{cItemGrid|ItemGrid}}, as required by the parent class, {{cBlockEntityWithItems}}" }, + }, + AdditionalInfo = + { + { + Header = "Code example", + Contents = [[ + The following example code sets the top-left item of each chest in the same chunk as Player to + 64 * diamond: +

+-- Player is a {{cPlayer}} object instance
+local World = Player:GetWorld();
+World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
+	function (ChestEntity)
+		ChestEntity:SetSlot(0, 0, cItem(E_ITEM_DIAMOND, 64));
+	end
+);
+
+ ]], + }, + }, -- AdditionalInfo + }, + + cDispenserEntity = + { + Desc = [[ + This class represents a dispenser block entity in the world. Most of this block entity's + functionality is implemented in the {{cDropSpenserEntity|cDropSpenserEntity}} class that represents + the behavior common with a {{cDropperEntity|dropper}} entity. + ]], + Inherits = "cDropSpenserEntity", + }, + + cDropperEntity = + { + Desc = [[ + This class represents a dropper block entity in the world. Most of this block entity's functionality + is implemented in the {{cDropSpenserEntity|cDropSpenserEntity}} class that represents the behavior + common with the {{cDispenserEntity|dispenser}} entity.

+

+ An object of this class can be created from scratch when generating chunks ({{OnChunkGenerated|OnChunkGenerated}} and {{OnChunkGenerating|OnChunkGenerating}} hooks). + ]], + Inherits = "cDropSpenserEntity", + }, -- cDropperEntity + + cDropSpenserEntity = + { + Desc = [[ + This is a class that implements behavior common to both {{cDispenserEntity|dispensers}} and {{cDropperEntity|droppers}}. + ]], + Functions = + { + Activate = { Params = "", Return = "", Notes = "Sets the block entity to dropspense an item in the next tick" }, + AddDropSpenserDir = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "BlockX, BlockY, BlockZ", Notes = "Adjusts the block coords to where the dropspenser items materialize" }, + SetRedstonePower = { Params = "IsPowered", Return = "", Notes = "Sets the redstone status of the dropspenser. If the redstone power goes from off to on, the dropspenser will be activated" }, + }, + Constants = + { + ContentsWidth = { Notes = "Width (X) of the {{cItemGrid}} representing the contents" }, + ContentsHeight = { Notes = "Height (Y) of the {{cItemGrid}} representing the contents" }, + }, + Inherits = "cBlockEntityWithItems"; + }, -- cDropSpenserEntity + + cFurnaceEntity = + { + Desc = [[ + This class represents a furnace block entity in the world.

+

+ See also {{cRoot}}'s GetFurnaceRecipe() and GetFurnaceFuelBurnTime() functions + ]], + Functions = + { + GetCookTimeLeft = { Params = "", Return = "number", Notes = "Returns the time until the current item finishes cooking, in ticks" }, + GetFuelBurnTimeLeft = { Params = "", Return = "number", Notes = "Returns the time until the current fuel is depleted, in ticks" }, + GetFuelSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the fuel slot" }, + GetInputSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the input slot" }, + GetOutputSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the output slot" }, + GetTimeCooked = { Params = "", Return = "number", Notes = "Returns the time that the current item has been cooking, in ticks" }, + HasFuelTimeLeft = { Params = "", Return = "bool", Notes = "Returns true if there's time before the current fuel is depleted" }, + SetFuelSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the fuel slot" }, + SetInputSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the input slot" }, + SetOutputSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the output slot" }, + }, + Constants = + { + fsInput = { Notes = "Index of the input slot" }, + fsFuel = { Notes = "Index of the fuel slot" }, + fsOutput = { Notes = "Index of the output slot" }, + ContentsWidth = { Notes = "Width (X) of the {{cItemGrid|cItemGrid}} representing the contents" }, + ContentsHeight = { Notes = "Height (Y) of the {{cItemGrid|cItemGrid}} representing the contents" }, + }, + ConstantGroups = + { + SlotIndices = + { + Include = "fs.*", + TextBefore = "When using the GetSlot() or SetSlot() function, use these constants for slot index:", + }, + }, + Inherits = "cBlockEntityWithItems" + }, -- cFurnaceEntity + + cHopperEntity = + { + Desc = [[ + This class represents a hopper block entity in the world. + ]], + Functions = + { + GetOutputBlockPos = { Params = "BlockMeta", Return = "bool, BlockX, BlockY, BlockZ", Notes = "Returns whether the hopper is attached, and if so, the block coords of the block receiving the output items, based on the given meta." }, + }, + Constants = + { + ContentsHeight = { Notes = "Height (Y) of the internal {{cItemGrid}} representing the hopper contents." }, + ContentsWidth = { Notes = "Width (X) of the internal {{cItemGrid}} representing the hopper contents." }, + TICKS_PER_TRANSFER = { Notes = "Number of ticks between when the hopper transfers items." }, + }, + Inherits = "cBlockEntityWithItems", + }, -- cHopperEntity + + cJukeboxEntity = + { + Desc = [[ + This class represents a jukebox in the world. It can play the records, either when the + {{cPlayer|player}} uses the record on the jukebox, or when a plugin instructs it to play. + ]], + Inherits = "cBlockEntity", + Functions = + { + EjectRecord = { Params = "", Return = "", Notes = "Ejects the current record as a {{cPickup|pickup}}. No action if there's no current record. To remove record without generating the pickup, use SetRecord(0)" }, + GetRecord = { Params = "", Return = "number", Notes = "Returns the record currently present. Zero for no record, E_ITEM_*_DISC for records." }, + PlayRecord = { Params = "", Return = "", Notes = "Plays the currently present record. No action if there's no current record." }, + SetRecord = { Params = "number", Return = "", Notes = "Sets the currently present record. Use zero for no record, or E_ITEM_*_DISC for records." }, + }, + }, -- cJukeboxEntity + + cNoteEntity = + { + Desc = [[ + This class represents a note block entity in the world. It takes care of the note block's pitch, + and also can play the sound, either when the {{cPlayer|player}} right-clicks it, redstone activates + it, or upon a plugin's request.

+

+ The pitch is stored as an integer between 0 and 24. + ]], + Functions = + { + GetPitch = { Params = "", Return = "number", Notes = "Returns the current pitch set for the block" }, + IncrementPitch = { Params = "", Return = "", Notes = "Adds 1 to the current pitch. Wraps around to 0 when the pitch cannot go any higher." }, + MakeSound = { Params = "", Return = "", Notes = "Plays the sound for all {{cClientHandle|clients}} near this block." }, + SetPitch = { Params = "Pitch", Return = "", Notes = "Sets a new pitch for the block." }, + }, + Inherits = "cBlockEntity", + }, -- cNoteEntity + + cSignEntity = + { + Desc = [[ + A sign entity represents a sign in the world. This class is only used when generating chunks, so + that the plugins may generate signs within new chunks. See the code example in {{cChunkDesc}}. + ]], + Functions = + { + GetLine = { Params = "LineIndex", Return = "string", Notes = "Returns the specified line. LineIndex is expected between 0 and 3. Returns empty string and logs to server console when LineIndex is invalid." }, + SetLine = { Params = "LineIndex, LineText", Return = "", Notes = "Sets the specified line. LineIndex is expected between 0 and 3. Logs to server console when LineIndex is invalid." }, + SetLines = { Params = "Line1, Line2, Line3, Line4", Return = "", Notes = "Sets all the sign's lines at once." }, + }, + Inherits = "cBlockEntity"; + }, -- cSignEntity +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnBlockToPickups.lua b/MCServer/Plugins/APIDump/Hooks/OnBlockToPickups.lua new file mode 100644 index 000000000..e6f115f37 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnBlockToPickups.lua @@ -0,0 +1,62 @@ +return +{ + HOOK_BLOCK_TO_PICKUPS = + { + CalledWhen = "A block is about to be dug ({{cPlayer|player}}, {{cEntity|entity}} or natural reason), plugins may override what pickups that will produce.", + DefaultFnName = "OnBlockToPickups", -- also used as pagename + Desc = [[ + This callback gets called whenever a block is about to be dug. This includes {{cPlayer|players}} + digging blocks, entities causing blocks to disappear ({{cTNTEntity|TNT}}, Endermen) and natural + causes (water washing away a block). Plugins may override the amount and kinds of pickups this + action produces. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the block resides" }, + { Name = "Digger", Type = "{{cEntity}} descendant", Notes = "The entity causing the digging. May be a {{cPlayer}}, {{cTNTEntity}} or even nil (natural causes)" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "Block type of the block" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "Block meta of the block" }, + { Name = "Pickups", Type = "{{cItems}}", Notes = "Items that will be spawned as pickups" }, + }, + Returns = [[ + If the function returns false or no value, the next callback in the hook chain will be called. If + the function returns true, no other callbacks in the chain will be called.

+

+ Either way, the server will then spawn pickups specified in the Pickups parameter, so to disable + pickups, you need to Clear the object first, then return true. + ]], + CodeExamples = + { + { + Title = "Modify pickups", + Desc = "This example callback function makes tall grass drop diamonds when digged by natural causes (washed away by water).", + Code = [[ +function OnBlockToPickups(a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups) + if (a_Digger ~= nil) then + -- Not a natural cause + return false; + end + if (a_BlockType ~= E_BLOCK_TALL_GRASS) then + -- Not a tall grass being washed away + return false; + end + + -- Remove all pickups suggested by MCServer: + a_Pickups:Clear(); + + -- Drop a diamond: + a_Pickups:Add(cItem(E_ITEM_DIAMOND)); + return true; +end; + ]], + }, + } , -- CodeExamples + }, -- HOOK_BLOCK_TO_PICKUPS +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnChat.lua b/MCServer/Plugins/APIDump/Hooks/OnChat.lua new file mode 100644 index 000000000..d98df008a --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnChat.lua @@ -0,0 +1,29 @@ +return +{ + HOOK_CHAT = + { + CalledWhen = "Player sends a chat message", + DefaultFnName = "OnChat", -- also used as pagename + Desc = [[ + A plugin may implement an OnChat() function and register it as a Hook to process chat messages from + the players. The function is then called for every in-game message sent from any player. Note that + commands are handled separately using a command framework API. + ]], + Params = { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who sent the message" }, + { Name = "Message", Type = "string", Notes = "The message" }, + }, + Returns = [[ + The plugin may return 2 values. The first is a boolean specifying whether the hook handling is to be + stopped or not. If it is false, the message is broadcast to all players in the world. If it is true, + no message is broadcast and no further action is taken.

+

+ The second value is specifies the message to broadcast. This way, plugins may modify the message. If + the second value is not provided, the original message is used. + ]], + }, -- HOOK_CHAT +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnChunkAvailable.lua b/MCServer/Plugins/APIDump/Hooks/OnChunkAvailable.lua new file mode 100644 index 000000000..61c191c57 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnChunkAvailable.lua @@ -0,0 +1,27 @@ +return +{ + HOOK_CHUNK_AVAILABLE = + { + CalledWhen = "A chunk has just been added to world, either generated or loaded. ", + DefaultFnName = "OnChunkAvailable", -- also used as pagename + Desc = [[ + This hook is called after a chunk is either generated or loaded from the disk. The chunk is + already available for manipulation using the {{cWorld}} API. This is a notification-only callback, + there is no behavior that plugins could override. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk belongs" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_CHUNK_AVAILABLE +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnChunkGenerated.lua b/MCServer/Plugins/APIDump/Hooks/OnChunkGenerated.lua new file mode 100644 index 000000000..b10dc36f5 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnChunkGenerated.lua @@ -0,0 +1,67 @@ +return +{ + HOOK_CHUNK_GENERATED = + { + CalledWhen = "After a chunk was generated. Notification only.", + DefaultFnName = "OnChunkGenerated", -- also used as pagename + Desc = [[ + This hook is called when world generator finished its work on a chunk. The chunk data has already + been generated and is about to be stored in the {{cWorld|world}}. A plugin may provide some + last-minute finishing touches to the generated data. Note that the chunk is not yet stored in the + world, so regular {{cWorld}} block API will not work! Instead, use the {{cChunkDesc}} object + received as the parameter.

+

+ See also the {{OnChunkGenerating|HOOK_CHUNK_GENERATING}} hook. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk will be added" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + { Name = "ChunkDesc", Type = "{{cChunkDesc}}", Notes = "Generated chunk data. Plugins may still modify the chunk data contained." }, + }, + Returns = [[ + If the plugin returns false or no value, MCServer will call other plugins' callbacks for this event. + If a plugin returns true, no other callback is called for this event.

+

+ In either case, MCServer will then store the data from ChunkDesc as the chunk's contents in the world. + ]], + CodeExamples = + { + { + Title = "Generate emerald ore", + Desc = "This example callback function generates one block of emerald ore in each chunk, under the condition that the randomly chosen location is in an ExtremeHills biome.", + Code = [[ +function OnChunkGenerated(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc) + -- Generate a psaudorandom value that is always the same for the same X/Z pair, but is otherwise random enough: + -- This is actually similar to how MCServer does its noise functions + local PseudoRandom = (a_ChunkX * 57 + a_ChunkZ) * 57 + 19785486 + PseudoRandom = PseudoRandom * 8192 + PseudoRandom; + PseudoRandom = ((PseudoRandom * (PseudoRandom * PseudoRandom * 15731 + 789221) + 1376312589) % 0x7fffffff; + PseudoRandom = PseudoRandom / 7; + + -- Based on the PseudoRandom value, choose a location for the ore: + local OreX = PseudoRandom % 16; + local OreY = 2 + ((PseudoRandom / 16) % 20); + local OreZ = (PseudoRandom / 320) % 16; + + -- Check if the location is in ExtremeHills: + if (a_ChunkDesc:GetBiome(OreX, OreZ) ~= biExtremeHills) then + return false; + end + + -- Only replace allowed blocks with the ore: + local CurrBlock = a_ChunDesc:GetBlockType(OreX, OreY, OreZ); + if ( + (CurrBlock == E_BLOCK_STONE) or + (CurrBlock == E_BLOCK_DIRT) or + (CurrBlock == E_BLOCK_GRAVEL) + ) then + a_ChunkDesc:SetBlockTypeMeta(OreX, OreY, OreZ, E_BLOCK_EMERALD_ORE, 0); + end +end; + ]], + }, + } , -- CodeExamples + }, -- HOOK_CHUNK_GENERATED +} \ No newline at end of file diff --git a/MCServer/Plugins/APIDump/Hooks/OnChunkGenerating.lua b/MCServer/Plugins/APIDump/Hooks/OnChunkGenerating.lua new file mode 100644 index 000000000..0db0e2727 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnChunkGenerating.lua @@ -0,0 +1,35 @@ +return +{ + HOOK_CHUNK_GENERATING = + { + CalledWhen = "A chunk is about to be generated. Plugin can override the built-in generator.", + DefaultFnName = "OnChunkGenerating", -- also used as pagename + Desc = [[ + This hook is called before the world generator starts generating a chunk. The plugin may provide + some or all parts of the generation, by-passing the built-in generator. The function is given access + to the {{cChunkDesc|ChunkDesc}} object representing the contents of the chunk. It may override parts + of the built-in generator by using the object's SetUseDefaultXXX(false) functions. After all + the callbacks for a chunk have been processed, the server will generate the chunk based on the + {{cChunkDesc|ChunkDesc}} description - those parts that are set for generating (by default + everything) are generated, the rest are read from the ChunkDesc object.

+

+ See also the {{OnChunkGenerated|HOOK_CHUNK_GENERATED}} hook. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the chunk will be added" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + { Name = "ChunkDesc", Type = "{{cChunkDesc}}", Notes = "Generated chunk data." }, + }, + Returns = [[ + If this function returns true, the server will not call any other plugin with the same chunk. If + this function returns false, the server will call the rest of the plugins with the same chunk, + possibly overwriting the ChunkDesc's contents. + ]], + }, -- HOOK_CHUNK_GENERATING +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnChunkUnloaded.lua b/MCServer/Plugins/APIDump/Hooks/OnChunkUnloaded.lua new file mode 100644 index 000000000..a67d5d461 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnChunkUnloaded.lua @@ -0,0 +1,28 @@ +return +{ + HOOK_CHUNK_UNLOADED = + { + CalledWhen = "A chunk has been unloaded from the memory.", + DefaultFnName = "OnChunkUnloaded", -- also used as pagename + Desc = [[ + This hook is called when a chunk is unloaded from the memory. Though technically still in memory, + the plugin should behave as if the chunk was already not present. In particular, {{cWorld}} block + API should not be used in the area of the specified chunk. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world from which the chunk is unloading" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. There is no behavior that plugins could + override. + ]], + }, -- HOOK_CHUNK_UNLOADED +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnChunkUnloading.lua b/MCServer/Plugins/APIDump/Hooks/OnChunkUnloading.lua new file mode 100644 index 000000000..cd79e2a13 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnChunkUnloading.lua @@ -0,0 +1,30 @@ +return +{ + HOOK_CHUNK_UNLOADING = + { + CalledWhen = " A chunk is about to be unloaded from the memory. Plugins may refuse the unload.", + DefaultFnName = "OnChunkUnloading", -- also used as pagename + Desc = [[ + MCServer calls this function when a chunk is about to be unloaded from the memory. A plugin may + force MCServer to keep the chunk in memory by returning true.

+

+ FIXME: The return value should be used only for event propagation stopping, not for the actual + decision whether to unload. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world from which the chunk is unloading" }, + { Name = "ChunkX", Type = "number", Notes = "X-coord of the chunk" }, + { Name = "ChunkZ", Type = "number", Notes = "Z-coord of the chunk" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called and finally MCServer + unloads the chunk. If the function returns true, no other callback is called for this event and the + chunk is left in the memory. + ]], + }, -- HOOK_CHUNK_UNLOADING +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnCollectingPickup.lua b/MCServer/Plugins/APIDump/Hooks/OnCollectingPickup.lua new file mode 100644 index 000000000..0a56df2c9 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnCollectingPickup.lua @@ -0,0 +1,32 @@ +return +{ + HOOK_COLLECTING_PICKUP = + { + CalledWhen = "Player is about to collect a pickup. Plugin can refuse / override behavior. ", + DefaultFnName = "OnCollectingPickup", -- also used as pagename + Desc = [[ + This hook is called when a player is about to collect a pickup. Plugins may refuse the action.

+

+ Pickup collection happens within the world tick, so if the collecting is refused, it will be tried + again in the next world tick, as long as the player is within reach of the pickup.

+

+ FIXME: There is no OnCollectedPickup() callback.

+

+ FIXME: This callback is called even if the pickup doesn't fit into the player's inventory.

+ ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who's collecting the pickup" }, + { Name = "Pickup", Type = "{{cPickup}}", Notes = "The pickup being collected" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins' callbacks and finally the + pickup is collected. If the function returns true, no other plugins are called for this event and + the pickup is not collected. + ]], + }, -- HOOK_COLLECTING_PICKUP +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnCraftingNoRecipe.lua b/MCServer/Plugins/APIDump/Hooks/OnCraftingNoRecipe.lua new file mode 100644 index 000000000..5137bbb25 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnCraftingNoRecipe.lua @@ -0,0 +1,32 @@ +return +{ + HOOK_CRAFTING_NO_RECIPE = + { + CalledWhen = " No built-in crafting recipe is found. Plugin may provide a recipe.", + DefaultFnName = "OnCraftingNoRecipe", -- also used as pagename + Desc = [[ + This callback is called when a player places items in their {{cCraftingGrid|crafting grid}} and + MCServer cannot find a built-in {{cCraftingRecipe|recipe}} for the combination. Plugins may provide + a recipe for the ingredients given. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose crafting is reported in this hook" }, + { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "Contents of the player's crafting grid" }, + { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that will be used (can be filled by plugins)" }, + }, + Returns = [[ + If the function returns false or no value, no recipe will be used. If the function returns true, no + other plugin will have their callback called for this event and MCServer will use the crafting + recipe in Recipe.

+

+ FIXME: To allow plugins give suggestions and overwrite other plugins' suggestions, we should change + the behavior with returning false, so that the recipe will still be used, but fill the recipe with + empty values by default. + ]], + }, -- HOOK_CRAFTING_NO_RECIPE +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua b/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua new file mode 100644 index 000000000..496e0d751 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua @@ -0,0 +1,32 @@ +return +{ + HOOK_DISCONNECT = + { + CalledWhen = "A player has explicitly disconnected.", + DefaultFnName = "OnDisconnect", -- also used as pagename + Desc = [[ + This hook is called when a client sends the disconnect packet and is about to be disconnected from + the server.

+

+ Note that this callback is not called if the client drops the connection or is kicked by the + server.

+

+ FIXME: There is no callback for "client destroying" that would be called in all circumstances.

+ ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has disconnected" }, + { Name = "Reason", Type = "string", Notes = "The reason that the client has sent in the disconnect packet" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins' callbacks for this event + and finally broadcasts a disconnect message to the player's world. If the function returns true, no + other plugins are called for this event and the disconnect message is not broadcast. In either case, + the player is disconnected. + ]], + }, -- HOOK_DISCONNECT +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnExecuteCommand.lua b/MCServer/Plugins/APIDump/Hooks/OnExecuteCommand.lua new file mode 100644 index 000000000..dadc4e94f --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnExecuteCommand.lua @@ -0,0 +1,31 @@ +return +{ + HOOK_EXECUTE_COMMAND = + { + CalledWhen = "A player executes an in-game command, or the admin issues a console command. Note that built-in console commands are exempt to this hook - they are always performed and the hook is not called.", + DefaultFnName = "OnExecuteCommand", -- also used as pagename + Desc = [[ + A plugin may implement a callback for this hook to intercept both in-game commands executed by the + players and console commands executed by the server admin. The function is called for every in-game + command sent from any player and for those server console commands that are not built in in the + server.

+

+ If the command is in-game, the first parameter to the hook function is the {{cPlayer|player}} who's + executing the command. If the command comes from the server console, the first parameter is nil. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "For in-game commands, the player who has sent the message. For console commands, nil" }, + { Name = "Command", Type = "table of strings", Notes = "The command and its parameters, broken into a table by spaces" }, + }, + Returns = [[ + If the plugin returns true, the command will be blocked and none of the remaining hook handlers will + be called. If the plugin returns false, MCServer calls all the remaining hook handlers and finally + the command will be executed. + ]], + }, -- HOOK_EXECUTE_COMMAND +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnExploded.lua b/MCServer/Plugins/APIDump/Hooks/OnExploded.lua new file mode 100644 index 000000000..6a01542ab --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnExploded.lua @@ -0,0 +1,49 @@ +return +{ + HOOK_EXPLODED = + { + CalledWhen = "An explosion has happened", + DefaultFnName = "OnExploded", -- also used as pagename + Desc = [[ + This hook is called after an explosion has been processed in a world.

+

+ See also {{OnExploding|HOOK_EXPLODING}} for a similar hook called before the explosion.

+

+ The explosion carries with it the type of its source - whether it's a creeper exploding, or TNT, + etc. It also carries the identification of the actual source. The exact type of the identification + depends on the source kind: + + + + + + + + + + + + +
SourceSourceData TypeNotes
esPrimedTNT{{cTNTEntity}}An exploding primed TNT entity
esCreeper{{cCreeper}}An exploding creeper or charged creeper
esBed{{Vector3i}}A bed exploding in the Nether or in the End. The bed coords are given.
esEnderCrystal{{Vector3i}}An ender crystal exploding upon hit. The block coords are given.
esGhastFireball{{cGhastFireballEntity}}A ghast fireball hitting ground or an {{cEntity|entity}}.
esWitherSkullBlackTBDA black wither skull hitting ground or an {{cEntity|entity}}.
esWitherSkullBlueTBDA blue wither skull hitting ground or an {{cEntity|entity}}.
esWitherBirthTBDA wither boss being created
esOtherTBDAny other previously unspecified type.
esPluginobjectAn explosion created by a plugin. The plugin may specify any kind of data.

+ ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world where the explosion happened" }, + { Name = "ExplosionSize", Type = "number", Notes = "The relative explosion size" }, + { Name = "CanCauseFire", Type = "bool", Notes = "True if the explosion has turned random air blocks to fire (such as a ghast fireball)" }, + { Name = "X", Type = "number", Notes = "X-coord of the explosion center" }, + { Name = "Y", Type = "number", Notes = "Y-coord of the explosion center" }, + { Name = "Z", Type = "number", Notes = "Z-coord of the explosion center" }, + { Name = "Source", Type = "eExplosionSource", Notes = "Source of the explosion. See the table above." }, + { Name = "SourceData", Type = "varies", Notes = "Additional data for the source. The exact type varies by the source. See the table above." }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. There is no overridable behaviour. + ]], + }, -- HOOK_EXPLODED +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnExploding.lua b/MCServer/Plugins/APIDump/Hooks/OnExploding.lua new file mode 100644 index 000000000..729f2e162 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnExploding.lua @@ -0,0 +1,50 @@ +return +{ + HOOK_EXPLODING = + { + CalledWhen = "An explosion is about to be processed", + DefaultFnName = "OnExploding", -- also used as pagename + Desc = [[ + This hook is called before an explosion has been processed in a world.

+

+ See also {{OnExploded|HOOK_EXPLODED}} for a similar hook called after the explosion.

+

+ The explosion carries with it the type of its source - whether it's a creeper exploding, or TNT, + etc. It also carries the identification of the actual source. The exact type of the identification + depends on the source kind: + + + + + + + + + + + + +
SourceSourceData TypeNotes
esPrimedTNT{{cTNTEntity}}An exploding primed TNT entity
esCreeper{{cCreeper}}An exploding creeper or charged creeper
esBed{{Vector3i}}A bed exploding in the Nether or in the End. The bed coords are given.
esEnderCrystal{{Vector3i}}An ender crystal exploding upon hit. The block coords are given.
esGhastFireball{{cGhastFireballEntity}}A ghast fireball hitting ground or an {{cEntity|entity}}.
esWitherSkullBlackTBDA black wither skull hitting ground or an {{cEntity|entity}}.
esWitherSkullBlueTBDA blue wither skull hitting ground or an {{cEntity|entity}}.
esWitherBirthTBDA wither boss being created
esOtherTBDAny other previously unspecified type.
esPluginobjectAn explosion created by a plugin. The plugin may specify any kind of data.

+ ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world where the explosion happens" }, + { Name = "ExplosionSize", Type = "number", Notes = "The relative explosion size" }, + { Name = "CanCauseFire", Type = "bool", Notes = "True if the explosion will turn random air blocks to fire (such as a ghast fireball)" }, + { Name = "X", Type = "number", Notes = "X-coord of the explosion center" }, + { Name = "Y", Type = "number", Notes = "Y-coord of the explosion center" }, + { Name = "Z", Type = "number", Notes = "Z-coord of the explosion center" }, + { Name = "Source", Type = "eExplosionSource", Notes = "Source of the explosion. See the table above." }, + { Name = "SourceData", Type = "varies", Notes = "Additional data for the source. The exact type varies by the source. See the table above." }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called, and finally + MCServer will process the explosion - destroy blocks and push + hurt entities. If the function + returns true, no other callback is called for this event and the explosion will not occur. + ]], + }, -- HOOK_EXPLODING +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnHandshake.lua b/MCServer/Plugins/APIDump/Hooks/OnHandshake.lua new file mode 100644 index 000000000..6183cc506 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnHandshake.lua @@ -0,0 +1,29 @@ +return +{ + HOOK_HANDSHAKE = + { + CalledWhen = "A client is connecting.", + DefaultFnName = "OnHandshake", -- also used as pagename + Desc = [[ + This hook is called when a client sends the Handshake packet. At this stage, only the client IP and + (unverified) username are known. Plugins may refuse access to the server based on this + information.

+

+ Note that the username is not authenticated - the authentication takes place only after this hook is + processed. + ]], + Params = + { + { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client handle representing the connection. Note that there's no {{cPlayer}} object for this client yet." }, + { Name = "UserName", Type = "string", Notes = "The username presented in the packet. Note that this username is unverified." }, + }, + Returns = [[ + If the function returns false, the user is let in to the server. If the function returns true, no + other plugin's callback is called, the user is kicked and the connection is closed. + ]], + }, -- HOOK_HANDSHAKE +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnHopperPullingItem.lua b/MCServer/Plugins/APIDump/Hooks/OnHopperPullingItem.lua new file mode 100644 index 000000000..b268a76be --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnHopperPullingItem.lua @@ -0,0 +1,30 @@ +return +{ + HOOK_HOPPER_PULLING_ITEM = + { + CalledWhen = "A hopper is pulling an item from another block entity.", + DefaultFnName = "OnHopperPullingItem", -- also used as pagename + Desc = [[ + This callback is called whenever a {{cHopperEntity|hopper}} transfers an {{cItem|item}} from another + block entity into its own internal storage. A plugin may decide to disallow the move by returning + true. Note that in such a case, the hook may be called again for the same hopper, with different + slot numbers. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "World where the hopper resides" }, + { Name = "Hopper", Type = "{{cHopperEntity}}", Notes = "The hopper that is pulling the item" }, + { Name = "DstSlot", Type = "number", Notes = "The destination slot in the hopper's {{cItemGrid|internal storage}}" }, + { Name = "SrcBlockEntity", Type = "{{cBlockEntityWithItems}}", Notes = "The block entity that is losing the item" }, + { Name = "SrcSlot", Type = "number", Notes = "Slot in SrcBlockEntity from which the item will be pulled" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event and the hopper will not pull the item. + ]], + }, -- HOOK_HOPPER_PULLING_ITEM +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnHopperPushingItem.lua b/MCServer/Plugins/APIDump/Hooks/OnHopperPushingItem.lua new file mode 100644 index 000000000..bd5702518 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnHopperPushingItem.lua @@ -0,0 +1,30 @@ +return +{ + HOOK_HOPPER_PUSHING_ITEM = + { + CalledWhen = "A hopper is pushing an item into another block entity. ", + DefaultFnName = "OnHopperPushingItem", -- also used as pagename + Desc = [[ + This hook is called whenever a {{cHopperEntity|hopper}} transfers an {{cItem|item}} from its own + internal storage into another block entity. A plugin may decide to disallow the move by returning + true. Note that in such a case, the hook may be called again for the same hopper and block, with + different slot numbers. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "World where the hopper resides" }, + { Name = "Hopper", Type = "{{cHopperEntity}}", Notes = "The hopper that is pushing the item" }, + { Name = "SrcSlot", Type = "number", Notes = "Slot in the hopper that will lose the item" }, + { Name = "DstBlockEntity", Type = "{{cBlockEntityWithItems}}", Notes = " The block entity that will receive the item" }, + { Name = "DstSlot", Type = "number", Notes = " Slot in DstBlockEntity's internal storage where the item will be stored" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event and the hopper will not push the item. + ]], + }, -- HOOK_HOPPER_PUSHING_ITEM +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnKilling.lua b/MCServer/Plugins/APIDump/Hooks/OnKilling.lua new file mode 100644 index 000000000..8ec1cfe2e --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnKilling.lua @@ -0,0 +1,33 @@ +return +{ + HOOK_KILLING = + { + CalledWhen = "A player or a mob is dying.", + DefaultFnName = "OnKilling", -- also used as pagename + Desc = [[ + This hook is called whenever a {{cPawn|pawn}}'s (a player's or a mob's) health reaches zero. This + means that the pawn is about to be killed, unless a plugin "revives" them by setting their health + back to a positive value.

+

+ FIXME: There is no HOOK_KILLED notification hook yet; this is deliberate because HOOK_KILLED has + been recently renamed to HOOK_KILLING, and plugins need to be updated. Once updated, the HOOK_KILLED + notification will be implemented. + ]], + Params = + { + { Name = "Victim", Type = "{{cPawn}}", Notes = "The player or mob that is about to be killed" }, + { Name = "Killer", Type = "{{cEntity}}", Notes = "The entity that has caused the victim to lose the last point of health. May be nil for environment damage" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins with this event. If the + function returns true, no other plugin is called for this event.

+

+ In either case, the victim's health is then re-checked and if it is greater than zero, the victim is + "revived" with that health amount. If the health is less or equal to zero, the victim is killed. + ]], + }, -- HOOK_KILLING +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnLogin.lua b/MCServer/Plugins/APIDump/Hooks/OnLogin.lua new file mode 100644 index 000000000..6859f9d11 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnLogin.lua @@ -0,0 +1,31 @@ +return +{ + HOOK_LOGIN = + { + CalledWhen = "Right before player authentication. If auth is disabled, right after the player sends their name.", + DefaultFnName = "OnLogin", -- also used as pagename + Desc = [[ + This hook is called whenever a client logs in. It is called right before the client's name is sent + to be authenticated. Plugins may refuse the client from accessing the server. Note that when this + callback is called, the {{cPlayer}} object for this client doesn't exist yet - the client has no + representation in any world. To process new players when their world is known, use a later callback, + such as {{OnPlayerJoined|HOOK_PLAYER_JOINED}} or {{OnPlayerSpawned|HOOK_PLAYER_SPAWNED}}. + ]], + Params = + { + { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client handle representing the connection" }, + { Name = "ProtocolVersion", Type = "number", Notes = "Versio of the protocol that the client is talking" }, + { Name = "UserName", Type = "string", Notes = "The name that the client has presented for authentication. This name will be given to the {{cPlayer}} object when it is created for this client." }, + }, + Returns = [[ + If the function returns true, no other plugins are called for this event and the client is kicked. + If the function returns false or no value, MCServer calls other plugins' callbacks and finally + sends an authentication request for the client's username to the auth server. If the auth server + is disabled in the server settings, the player object is immediately created. + ]], + }, -- HOOK_LOGIN +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerAnimation.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerAnimation.lua new file mode 100644 index 000000000..baf99834e --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerAnimation.lua @@ -0,0 +1,28 @@ +return +{ + HOOK_PLAYER_ANIMATION = + { + CalledWhen = "A client has sent an Animation packet (0x12)", + DefaultFnName = "OnPlayerAnimation", -- also used as pagename + Desc = [[ + This hook is called when the server receives an Animation packet (0x12) from the client.

+

+ For the list of animations that are sent by the client, see the + Protocol wiki. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player from whom the packet was received" }, + { Name = "Animation", Type = "number", Notes = "The kind of animation" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. Afterwards, the + server broadcasts the animation packet to all nearby clients. If the function returns true, no other + callback is called for this event and the packet is not broadcasted. + ]], + }, -- HOOK_PLAYER_ANIMATION +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerBreakingBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerBreakingBlock.lua new file mode 100644 index 000000000..18f19f247 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerBreakingBlock.lua @@ -0,0 +1,36 @@ +return +{ + HOOK_PLAYER_BREAKING_BLOCK = + { + CalledWhen = "Just before a player breaks a block. Plugin may override / refuse. ", + DefaultFnName = "OnPlayerBreakingBlock", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} breaks a block, before the block is actually broken in + the {{cWorld|World}}. Plugins may refuse the breaking.

+

+ See also the {{OnPlayerBrokenBlock|HOOK_PLAYER_BROKEN_BLOCK}} hook for a similar hook called after + the block is broken. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is digging the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player is acting. One of the BLOCK_FACE_ constants" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block being broken" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block being broken " }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called, and then the block + is broken. If the function returns true, no other plugin's callback is called and the block breaking + is cancelled. The server re-sends the block back to the player to replace it (the player's client + already thinks the block was broken). + ]], + }, -- HOOK_PLAYER_BREAKING_BLOCK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerBrokenBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerBrokenBlock.lua new file mode 100644 index 000000000..e718c5d97 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerBrokenBlock.lua @@ -0,0 +1,36 @@ +return +{ + HOOK_PLAYER_BROKEN_BLOCK = + { + CalledWhen = "After a player has broken a block. Notification only.", + DefaultFnName = "OnPlayerBrokenBlock", -- also used as pagename + Desc = [[ + This function is called after a {{cPlayer|player}} breaks a block. The block is already removed + from the {{cWorld|world}} and {{cPickup|pickups}} have been spawned. To get the world in which the + block has been dug, use the {{cPlayer}}:GetWorld() function.

+

+ See also the {{OnPlayerBreakingBlock|HOOK_PLAYER_BREAKING_BLOCK}} hook for a similar hook called + before the block is broken. To intercept the creation of pickups, see the + {{OnBlockToPickups|HOOK_BLOCK_TO_PICKUPS}} hook. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who broke the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_PLAYER_BROKEN_BLOCK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerEating.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerEating.lua new file mode 100644 index 000000000..e77d02a96 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerEating.lua @@ -0,0 +1,27 @@ +return +{ + HOOK_PLAYER_EATING = + { + CalledWhen = "When the player starts eating", + DefaultFnName = "OnPlayerEating", -- also used as pagename + Desc = [[ + This hook gets called when the {{cPlayer|player}} starts eating, after the server checks that the + player can indeed eat (is not satiated and is holding food). Plugins may still refuse the eating by + returning true. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who started eating" }, + }, + Returns = [[ + If the function returns false or no value, the server calls the next plugin handler, and finally + lets the player eat. If the function returns true, the server doesn't call any more callbacks for + this event and aborts the eating. A "disallow" packet is sent to the client. + ]], + }, -- HOOK_PLAYER_EATING +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua new file mode 100644 index 000000000..00805af7e --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerJoined.lua @@ -0,0 +1,29 @@ +return +{ + HOOK_PLAYER_JOINED = + { + CalledWhen = "After Login and before Spawned, before being added to world. ", + DefaultFnName = "OnPlayerJoined", -- also used as pagename + Desc = [[ + This hook is called whenever a {{cPlayer|player}} has completely logged in. If authentication is + enabled, this function is called after their name has been authenticated. It is called after + {{OnLogin|HOOK_LOGIN}} and before {{OnPlayerSpawned|HOOK_PLAYER_SPAWNED}}, right after the player's + entity is created, but not added to the world yet. The player is not yet visible to other players. + This is a notification-only event, plugins wishing to refuse player's entry should kick the player + using the {{cPlayer}}:Kick() function. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has joined the game" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called for this event. Either way the player is let in. + ]], + }, -- HOOK_PLAYER_JOINED +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerLeftClick.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerLeftClick.lua new file mode 100644 index 000000000..1d9585c55 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerLeftClick.lua @@ -0,0 +1,47 @@ +return +{ + HOOK_PLAYER_LEFT_CLICK = + { + CalledWhen = "A left-click packet is received from the client. Plugin may override / refuse.", + DefaultFnName = "OnPlayerLeftClick", -- also used as pagename + Desc = [[ + This hook is called when MCServer receives a left-click packet from the {{cClientHandle|client}}. It + is called before any processing whatsoever is performed on the packet, meaning that hacked / + malicious clients may be trigerring this event very often and with unchecked parameters. Therefore + plugin authors are advised to use extreme caution with this callback.

+

+ Plugins may refuse the default processing for the packet, causing MCServer to behave as if the + packet has never arrived. This may, however, create inconsistencies in the client - the client may + think that they broke a block, while the server didn't process the breaking, etc. For this reason, + if a plugin refuses the processing, MCServer sends the block specified in the packet back to the + client (as if placed anew), if the status code specified a block-break action. For other actions, + plugins must rectify the situation on their own.

+

+ The client sends the left-click packet for several other occasions, such as dropping the held item + (Q keypress) or shooting an arrow. This is reflected in the Status code. Consult the + protocol documentation for details on the actions. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose client sent the packet" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, + { Name = "Action", Type = "number", Notes = "Action to be performed on the block (\"status\" in the protocol docs)" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins' callbacks and finally sends + the packet for further processing.

+

+ If the function returns true, no other plugins are called, processing is halted. If the action was a + block dig, MCServer sends the block specified in the coords back to the client. The packet is + dropped. + ]], + }, -- HOOK_PLAYER_LEFT_CLICK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua new file mode 100644 index 000000000..2756529ef --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua @@ -0,0 +1,27 @@ +return +{ + HOOK_PLAYER_MOVING = + { + CalledWhen = "Player tried to move in the tick being currently processed. Plugin may refuse movement.", + DefaultFnName = "OnPlayerMoving", -- also used as pagename + Desc = [[ + This function is called in each server tick for each {{cPlayer|player}} that has sent any of the + player-move packets. Plugins may refuse the movement. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has moved. The object already has the new position stored in it." }, + }, + Returns = [[ + If the function returns true, movement is prohibited. FIXME: The player's client is not informed.

+

+ If the function returns false or no value, other plugins' callbacks are called and finally the new + position is permanently stored in the cPlayer object.

+ ]], + }, -- HOOK_PLAYER_MOVING +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerPlacedBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerPlacedBlock.lua new file mode 100644 index 000000000..54888a6db --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerPlacedBlock.lua @@ -0,0 +1,40 @@ +return +{ + HOOK_PLAYER_PLACED_BLOCK = + { + CalledWhen = "After a player has placed a block. Notification only.", + DefaultFnName = "OnPlayerPlacedBlock", -- also used as pagename + Desc = [[ + This hook is called after a {{cPlayer|player}} has placed a block in the {{cWorld|world}}. The block + is already added to the world and the corresponding item removed from player's + {{cInventory|inventory}}.

+

+ Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.

+

+ See also the {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}} hook for a similar hook called + before the placement. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who placed the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the existing block upon which the player interacted. One of the BLOCK_FACE_ constants" }, + { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor within the block face (0 .. 15)" }, + { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor within the block face (0 .. 15)" }, + { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor within the block face (0 .. 15)" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, + }, + Returns = [[ + If this function returns false or no value, MCServer calls other plugins with the same event. If + this function returns true, no other plugin is called for this event. + ]], + }, -- HOOK_PLAYER_PLACED_BLOCK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerPlacingBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerPlacingBlock.lua new file mode 100644 index 000000000..2a928390b --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerPlacingBlock.lua @@ -0,0 +1,45 @@ +return +{ + HOOK_PLAYER_PLACING_BLOCK = + { + CalledWhen = "Just before a player places a block. Plugin may override / refuse.", + DefaultFnName = "OnPlayerPlacingBlock", -- also used as pagename + Desc = [[ + This hook is called just before a {{cPlayer|player}} places a block in the {{cWorld|world}}. The + block is not yet placed, plugins may choose to override the default behavior or refuse the placement + at all.

+

+ Note that the client already expects that the block has been placed. For that reason, if a plugin + refuses the placement, MCServer sends the old block at the provided coords to the client.

+

+ Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.

+

+ See also the {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}} hook for a similar hook called after + the placement. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is placing the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the existing block upon which the player is interacting. One of the BLOCK_FACE_ constants" }, + { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor within the block face (0 .. 15)" }, + { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor within the block face (0 .. 15)" }, + { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor within the block face (0 .. 15)" }, + { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, + { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, + }, + Returns = [[ + If this function returns false or no value, MCServer calls other plugins with the same event and + finally places the block and removes the corresponding item from player's inventory. If this + function returns true, no other plugin is called for this event, MCServer sends the old block at + the specified coords to the client and drops the packet. + ]], + }, -- HOOK_PLAYER_PLACING_BLOCK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerRightClick.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerRightClick.lua new file mode 100644 index 000000000..d767b449d --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerRightClick.lua @@ -0,0 +1,37 @@ +return +{ + HOOK_PLAYER_RIGHT_CLICK = + { + CalledWhen = "A right-click packet is received from the client. Plugin may override / refuse.", + DefaultFnName = "OnPlayerRightClick", -- also used as pagename + Desc = [[ + This hook is called when MCServer receives a right-click packet from the {{cClientHandle|client}}. It + is called before any processing whatsoever is performed on the packet, meaning that hacked / + malicious clients may be trigerring this event very often and with unchecked parameters. Therefore + plugin authors are advised to use extreme caution with this callback.

+

+ Plugins may refuse the default processing for the packet, causing MCServer to behave as if the + packet has never arrived. This may, however, create inconsistencies in the client - the client may + think that they placed a block, while the server didn't process the placing, etc. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player whose client sent the packet" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of the block upon which the player interacted. One of the BLOCK_FACE_ constants" }, + }, + Returns = [[ + If the function returns false or no value, MCServer calls other plugins' callbacks and finally sends + the packet for further processing.

+

+ If the function returns true, no other plugins are called, processing is halted. + ]], + }, -- HOOK_PLAYER_RIGHT_CLICK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerRightClickingEntity.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerRightClickingEntity.lua new file mode 100644 index 000000000..796622307 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerRightClickingEntity.lua @@ -0,0 +1,27 @@ +return +{ + HOOK_PLAYER_RIGHT_CLICKING_ENTITY = + { + CalledWhen = "A player has right-clicked an entity. Plugins may override / refuse.", + DefaultFnName = "OnPlayerRightClickingEntity", -- also used as pagename + Desc = [[ + This hook is called when the {{cPlayer|player}} right-clicks an {{cEntity|entity}}. Plugins may + override the default behavior or even cancel the default processing. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has right-clicked the entity" }, + { Name = "Entity", Type = "{{cEntity}} descendant", Notes = "The entity that has been right-clicked" }, + }, + Returns = [[ + If the functino returns false or no value, MCServer calls other plugins' callbacks and finally does + the default processing for the right-click. If the function returns true, no other callbacks are + called and the default processing is skipped. + ]], + }, -- HOOK_PLAYER_RIGHT_CLICKING_ENTITY +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerShooting.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerShooting.lua new file mode 100644 index 000000000..aefae2c2f --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerShooting.lua @@ -0,0 +1,32 @@ +return +{ + HOOK_PLAYER_SHOOTING = + { + CalledWhen = "When the player releases the bow, shooting an arrow (other projectiles: unknown)", + DefaultFnName = "OnPlayerShooting", -- also used as pagename + Desc = [[ + This hook is called when the {{cPlayer|player}} shoots their bow. It is called for the actual + release of the {{cArrowEntity|arrow}}. FIXME: It is currently unknown whether other + {{cProjectileEntity|projectiles}} (snowballs, eggs) trigger this hook.

+

+ To get the player's position and direction, use the {{cPlayer}}:GetEyePosition() and + cPlayer:GetLookVector() functions. Note that for shooting a bow, the position for the arrow creation + is not at the eye pos, some adjustments are required. FIXME: Export the {{cPlayer}} function for + this adjustment. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player shooting" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called, and finally + MCServer creates the projectile. If the functino returns true, no other callback is called and no + projectile is created. + ]], + }, -- HOOK_PLAYER_SHOOTING +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerSpawned.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerSpawned.lua new file mode 100644 index 000000000..190909ee5 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerSpawned.lua @@ -0,0 +1,32 @@ +return +{ + HOOK_PLAYER_SPAWNED = + { + CalledWhen = "After a player (re)spawns in the world to which they belong to.", + DefaultFnName = "OnPlayerSpawned", -- also used as pagename + Desc = [[ + This hook is called after a {{cPlayer|player}} has spawned in the world. It is called after + {{OnLogin|HOOK_LOGIN}} and {{OnPlayerJoined|HOOK_PLAYER_JOINED}}, after the player name has been + authenticated, the initial worldtime, inventory and health have been sent to the player and the + player spawn packet has been broadcast to all players near enough to the player spawn place. This is + a notification-only event, plugins wishing to refuse player's entry should kick the player using the + {{cPlayer}}:Kick() function.

+

+ This hook is also called when the player respawns after death (and a respawn packet is received from + the client, meaning the player has already clicked the Respawn button). + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has (re)spawned" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called for this event. There is no overridable behavior. + ]], + }, -- HOOK_PLAYER_SPAWNED +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua new file mode 100644 index 000000000..85c943721 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerTossingItem.lua @@ -0,0 +1,30 @@ +return +{ + HOOK_PLAYER_TOSSING_ITEM = + { + CalledWhen = "A player is tossing an item. Plugin may override / refuse.", + DefaultFnName = "OnPlayerTossingItem", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} has tossed an item (Q keypress). The + {{cPickup|pickup}} has not been spawned yet. Plugins may disallow the tossing, but in that case they + need to clean up - the player's client already thinks the item has been tossed so the + {{cInventory|inventory}} needs to be re-sent to the player.

+

+ To get the item that is about to be tossed, call the {{cPlayer}}:GetEquippedItem() function. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player tossing an item" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called and finally MCServer + creates the pickup for the item and tosses it, using {{cPlayer}}:TossItem. If the function returns + true, no other callbacks are called for this event and MCServer doesn't toss the item. + ]], + }, -- HOOK_PLAYER_TOSSING_ITEM +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerUsedBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerUsedBlock.lua new file mode 100644 index 000000000..4c91ea89e --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerUsedBlock.lua @@ -0,0 +1,46 @@ +return +{ + HOOK_PLAYER_USED_BLOCK = + { + CalledWhen = "A player has just used a block (chest, furnace). Notification only.", + DefaultFnName = "OnPlayerUsedBlock", -- also used as pagename + Desc = [[ + This hook is called after a {{cPlayer|player}} has right-clicked a block that can be used, such as a + {{cChestEntity|chest}} or a lever. It is called after MCServer processes the usage (sends the UI + handling packets / toggles redstone). Note that for UI-related blocks, the player is most likely + still using the UI. This is a notification-only event.

+

+ Note that the block coords given in this callback are for the (solid) block that is being clicked, + not the air block between it and the player.

+

+ To get the world at which the right-click occurred, use the {{cPlayer}}:GetWorld() function.

+

+ See also the {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}} for a similar hook called before the + use, the {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} and {{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}} + for similar hooks called when a player interacts with any block with a usable item in hand, such as + a bucket. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who used the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the clicked block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the clicked block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the clicked block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of clicked block which has been clicked. One of the BLOCK_FACE_ constants" }, + { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor crosshair on the block being clicked" }, + { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor crosshair on the block being clicked" }, + { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor crosshair on the block being clicked" }, + { Name = "BlockType", Type = "number", Notes = "Block type of the clicked block" }, + { Name = "BlockMeta", Type = "number", Notes = "Block meta of the clicked block" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called for this event. + ]], + }, -- HOOK_PLAYER_USED_BLOCK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerUsedItem.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerUsedItem.lua new file mode 100644 index 000000000..998058c35 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerUsedItem.lua @@ -0,0 +1,46 @@ +return +{ + HOOK_PLAYER_USED_ITEM = + { + CalledWhen = "A player has used an item in hand (bucket...)", + DefaultFnName = "OnPlayerUsedItem", -- also used as pagename + Desc = [[ + This hook is called after a {{cPlayer|player}} has right-clicked a block with an {{cItem|item}} that + can be used (is not placeable, is not food and clicked block is not use-able), such as a bucket or a + hoe. It is called after MCServer processes the usage (places fluid / turns dirt to farmland). + This is an information-only hook, there is no way to cancel the event anymore.

+

+ Note that the block coords given in this callback are for the (solid) block that is being clicked, + not the air block between it and the player.

+

+ To get the world at which the right-click occurred, use the {{cPlayer}}:GetWorld() function. To get + the item that the player is using, use the {{cPlayer}}:GetEquippedItem() function.

+

+ See also the {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} for a similar hook called before the use, + the {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}} and {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}} + for similar hooks called when a player interacts with a block, such as a chest. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who used the item" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the clicked block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the clicked block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the clicked block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of clicked block which has been clicked. One of the BLOCK_FACE_ constants" }, + { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor crosshair on the block being clicked" }, + { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor crosshair on the block being clicked" }, + { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor crosshair on the block being clicked" }, + { Name = "BlockType", Type = "number", Notes = "Block type of the clicked block" }, + { Name = "BlockMeta", Type = "number", Notes = "Block meta of the clicked block" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called for this event. + ]], + }, -- HOOK_PLAYER_USED_ITEM +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerUsingBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerUsingBlock.lua new file mode 100644 index 000000000..8acc84b5f --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerUsingBlock.lua @@ -0,0 +1,46 @@ +return +{ + HOOK_PLAYER_USING_BLOCK = + { + CalledWhen = "Just before a player uses a block (chest, furnace...). Plugin may override / refuse.", + DefaultFnName = "OnPlayerUsingBlock", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} has right-clicked a block that can be used, such as a + {{cChestEntity|chest}} or a lever. It is called before MCServer processes the usage (sends the UI + handling packets / toggles redstone). Plugins may refuse the interaction by returning true.

+

+ Note that the block coords given in this callback are for the (solid) block that is being clicked, + not the air block between it and the player.

+

+ To get the world at which the right-click occurred, use the {{cPlayer}}:GetWorld() function.

+

+ See also the {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}} for a similar hook called after the use, the + {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} and {{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}} for + similar hooks called when a player interacts with any block with a usable item in hand, such as a + bucket. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is using the block" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the clicked block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the clicked block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the clicked block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of clicked block which has been clicked. One of the BLOCK_FACE_ constants" }, + { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor crosshair on the block being clicked" }, + { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor crosshair on the block being clicked" }, + { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor crosshair on the block being clicked" }, + { Name = "BlockType", Type = "number", Notes = "Block type of the clicked block" }, + { Name = "BlockMeta", Type = "number", Notes = "Block meta of the clicked block" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called and then MCServer + processes the interaction. If the function returns true, no other callbacks are called for this + event and the interaction is silently dropped. + ]], + }, -- HOOK_PLAYER_USING_BLOCK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerUsingItem.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerUsingItem.lua new file mode 100644 index 000000000..09674606d --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerUsingItem.lua @@ -0,0 +1,47 @@ +return +{ + HOOK_PLAYER_USING_ITEM = + { + CalledWhen = "Just before a player uses an item in hand (bucket...). Plugin may override / refuse.", + DefaultFnName = "OnPlayerUsingItem", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} has right-clicked a block with an {{cItem|item}} that + can be used (is not placeable, is not food and clicked block is not use-able), such as a bucket or a + hoe. It is called before MCServer processes the usage (places fluid / turns dirt to farmland). + Plugins may refuse the interaction by returning true.

+

+ Note that the block coords given in this callback are for the (solid) block that is being clicked, + not the air block between it and the player.

+

+ To get the world at which the right-click occurred, use the {{cPlayer}}:GetWorld() function. To get + the item that the player is using, use the {{cPlayer}}:GetEquippedItem() function.

+

+ See also the {{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}} for a similar hook called after the use, the + {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}} and {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}} for + similar hooks called when a player interacts with a block, such as a chest. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is using the item" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the clicked block" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the clicked block" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the clicked block" }, + { Name = "BlockFace", Type = "number", Notes = "Face of clicked block which has been clicked. One of the BLOCK_FACE_ constants" }, + { Name = "CursorX", Type = "number", Notes = "X-coord of the cursor crosshair on the block being clicked" }, + { Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor crosshair on the block being clicked" }, + { Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor crosshair on the block being clicked" }, + { Name = "BlockType", Type = "number", Notes = "Block type of the clicked block" }, + { Name = "BlockMeta", Type = "number", Notes = "Block meta of the clicked block" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called and then MCServer + processes the interaction. If the function returns true, no other callbacks are called for this + event and the interaction is silently dropped. + ]], + }, -- HOOK_PLAYER_USING_ITEM +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPostCrafting.lua b/MCServer/Plugins/APIDump/Hooks/OnPostCrafting.lua new file mode 100644 index 000000000..8af78ba62 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPostCrafting.lua @@ -0,0 +1,36 @@ +return +{ + HOOK_POST_CRAFTING = + { + CalledWhen = "After the built-in recipes are checked and a recipe was found.", + DefaultFnName = "OnPostCrafting", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} changes contents of their + {{cCraftingGrid|crafting grid}}, after the recipe has been established by MCServer. Plugins may use + this to modify the resulting recipe or provide an alternate recipe.

+

+ If a plugin implements custom recipes, it should do so using the {{OnPreCrafting|HOOK_PRE_CRAFTING}} + hook, because that will save the server from going through the built-in recipes. The + HOOK_POST_CRAFTING hook is intended as a notification, with a chance to tweak the result.

+

+ Note that this hook is not called if a built-in recipe is not found; + {{OnCraftingNoRecipe|HOOK_CRAFTING_NO_RECIPE}} is called instead in such a case. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has changed their crafting grid contents" }, + { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "The new crafting grid contents" }, + { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that MCServer has decided to use (can be tweaked by plugins)" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called for this event. In either case, MCServer uses the value + of Recipe as the recipe to be presented to the player. + ]], + }, -- HOOK_POST_CRAFTING +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPreCrafting.lua b/MCServer/Plugins/APIDump/Hooks/OnPreCrafting.lua new file mode 100644 index 000000000..b404e0e73 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPreCrafting.lua @@ -0,0 +1,37 @@ +return +{ + HOOK_PRE_CRAFTING = + { + CalledWhen = "Before the built-in recipes are checked.", + DefaultFnName = "OnPreCrafting", -- also used as pagename + Desc = [[ + This hook is called when a {{cPlayer|player}} changes contents of their + {{cCraftingGrid|crafting grid}}, before the built-in recipes are searched for a match by MCServer. + Plugins may use this hook to provide a custom recipe.

+

+ If you intend to tweak built-in recipes, use the {{OnPostCrafting|HOOK_POST_CRAFTING}} hook, because + that will be called once the built-in recipe is matched.

+

+ Also note a third hook, {{OnCraftingNoRecipe|HOOK_CRAFTING_NO_RECIPE}}, that is called when MCServer + cannot find any built-in recipe for the given ingredients. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has changed their crafting grid contents" }, + { Name = "Grid", Type = "{{cCraftingGrid}}", Notes = "The new crafting grid contents" }, + { Name = "Recipe", Type = "{{cCraftingRecipe}}", Notes = "The recipe that MCServer will use. Modify this object to change the recipe" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called and then MCServer + searches the built-in recipes. The Recipe output parameter is ignored in this case.

+

+ If the function returns true, no other callbacks are called for this event and MCServer uses the + recipe stored in the Recipe output parameter. + ]], + }, -- HOOK_PRE_CRAFTING +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnSpawnedEntity.lua b/MCServer/Plugins/APIDump/Hooks/OnSpawnedEntity.lua new file mode 100644 index 000000000..037a90f1c --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnSpawnedEntity.lua @@ -0,0 +1,31 @@ +return +{ + HOOK_SPAWNED_ENTITY = + { + CalledWhen = "After an entity is spawned in the world.", + DefaultFnName = "OnSpawnedEntity", -- also used as pagename + Desc = [[ + This hook is called after the server spawns an {{cEntity|entity}}. This is an information-only + callback, the entity is already spawned by the time it is called. If the entity spawned is a + {{cMonster|monster}}, the {{OnSpawnedMonster|HOOK_SPAWNED_MONSTER}} hook is called before this + hook.

+

+ See also the {{OnSpawningEntity|HOOK_SPAWNING_ENTITY}} hook for a similar hook called before the + entity is spawned. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity has spawned" }, + { Name = "Entity", Type = "{{cEntity}} descentant", Notes = "The entity that has spawned" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_SPAWNED_ENTITY +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnSpawnedMonster.lua b/MCServer/Plugins/APIDump/Hooks/OnSpawnedMonster.lua new file mode 100644 index 000000000..c319a77ea --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnSpawnedMonster.lua @@ -0,0 +1,30 @@ +return +{ + HOOK_SPAWNED_MONSTER = + { + CalledWhen = "After a monster is spawned in the world", + DefaultFnName = "OnSpawnedMonster", -- also used as pagename + Desc = [[ + This hook is called after the server spawns a {{cMonster|monster}}. This is an information-only + callback, the monster is already spawned by the time it is called. After this hook is called, the + {{OnSpawnedEntity|HOOK_SPAWNED_ENTITY}} is called for the monster entity.

+

+ See also the {{OnSpawningMonster|HOOK_SPAWNING_MONSTER}} hook for a similar hook called before the + monster is spawned. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the monster has spawned" }, + { Name = "Monster", Type = "{{cMonster}} descendant", Notes = "The monster that has spawned" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_SPAWNED_MONSTER +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnSpawningEntity.lua b/MCServer/Plugins/APIDump/Hooks/OnSpawningEntity.lua new file mode 100644 index 000000000..c4bff3916 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnSpawningEntity.lua @@ -0,0 +1,32 @@ +return +{ + HOOK_SPAWNING_ENTITY = + { + CalledWhen = "Before an entity is spawned in the world.", + DefaultFnName = "OnSpawningEntity", -- also used as pagename + Desc = [[ + This hook is called before the server spawns an {{cEntity|entity}}. The plugin can either modify the + entity before it is spawned, or disable the spawning altogether. If the entity spawning is a + monster, the {{OnSpawningMonster|HOOK_SPAWNING_MONSTER}} hook is called before this hook.

+

+ See also the {{OnSpawnedEntity|HOOK_SPAWNED_ENTITY}} hook for a similar hook called after the + entity is spawned. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity will spawn" }, + { Name = "Entity", Type = "{{cEntity}} descentant", Notes = "The entity that will spawn" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. Finally, the server + spawns the entity with whatever parameters have been set on the {{cEntity}} object by the callbacks. + If the function returns true, no other callback is called for this event and the entity is not + spawned. + ]], + }, -- HOOK_SPAWNING_ENTITY +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnSpawningMonster.lua b/MCServer/Plugins/APIDump/Hooks/OnSpawningMonster.lua new file mode 100644 index 000000000..4c0519e27 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnSpawningMonster.lua @@ -0,0 +1,33 @@ +return +{ + HOOK_SPAWNING_MONSTER = + { + CalledWhen = "Before a monster is spawned in the world.", + DefaultFnName = "OnSpawningMonster", -- also used as pagename + Desc = [[ + This hook is called before the server spawns a {{cMonster|monster}}. The plugins may modify the + monster's parameters in the {{cMonster}} class, or disallow the spawning altogether. This hook is + called before the {{OnSpawningEntity|HOOK_SPAWNING_ENTITY}} is called for the monster entity.

+

+ See also the {{OnSpawnedMonster|HOOK_SPAWNED_MONSTER}} hook for a similar hook called after the + monster is spawned. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the entity will spawn" }, + { Name = "Monster", Type = "{{cMonster}} descentant", Notes = "The monster that will spawn" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. Finally, the server + spawns the monster with whatever parameters the plugins set in the cMonster parameter.

+

+ If the function returns true, no other callback is called for this event and the monster won't + spawn. + ]], + }, -- HOOK_SPAWNING_MONSTER +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnTakeDamage.lua b/MCServer/Plugins/APIDump/Hooks/OnTakeDamage.lua new file mode 100644 index 000000000..608126f2b --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnTakeDamage.lua @@ -0,0 +1,31 @@ +return +{ + HOOK_TAKE_DAMAGE = + { + CalledWhen = "An {{cEntity|entity}} is taking any kind of damage", + DefaultFnName = "OnTakeDamage", -- also used as pagename + Desc = [[ + This hook is called when any {{cEntity}} descendant, such as a {{cPlayer|player}} or a + {{cMonster|mob}}, takes any kind of damage. The plugins may modify the amount of damage or effects + with this hook by editting the {{TakeDamageInfo}} object passed.

+

+ This hook is called after the final damage is calculated, including all the possible weapon + {{cEnchantments|enchantments}}, armor protection and potion effects. + ]], + Params = + { + { Name = "Receiver", Type = "{{cEntity}} descendant", Notes = "The entity taking damage" }, + { Name = "TDI", Type = "{{TakeDamageInfo}}", Notes = "The damage type, cause and effects. Plugins may modify this object to alter the final damage applied." }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called and then the server + applies the final values from the TDI object to Receiver. If the function returns true, no other + callbacks are called, and no damage nor effects are applied. + ]], + }, -- HOOK_TAKE_DAMAGE +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnTick.lua b/MCServer/Plugins/APIDump/Hooks/OnTick.lua new file mode 100644 index 000000000..d8c329253 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnTick.lua @@ -0,0 +1,29 @@ +return +{ + HOOK_TICK = + { + CalledWhen = "Every server tick (approximately 20 times per second)", + DefaultFnName = "OnTick", -- also used as pagename + Desc = [[ + This hook is called every game tick (50 msec, or 20 times a second). If the server is overloaded, + the interval is larger, which is indicated by the TimeDelta parameter.

+

+ This hook is called in the context of the server-tick thread, that is, the thread that takes care of + {{cClientHandle|client connections}} before they're assigned to {{cPlayer|player entities}}, and + processing console commands. + ]], + Params = + { + { Name = "TimeDelta", Type = "number", Notes = "The number of milliseconds elapsed since the last server tick. Will not be less than 50 msec." }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called. There is no overridable behavior. + ]], + }, -- HOOK_TICK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnUpdatedSign.lua b/MCServer/Plugins/APIDump/Hooks/OnUpdatedSign.lua new file mode 100644 index 000000000..937e6b981 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnUpdatedSign.lua @@ -0,0 +1,38 @@ +return +{ + HOOK_UPDATED_SIGN = + { + CalledWhen = "After the sign text is updated. Notification only.", + DefaultFnName = "OnUpdatedSign", -- also used as pagename + Desc = [[ + This hook is called after a sign has had its text updated. The text is already updated at this + point.

+

The update may have been caused either by a {{cPlayer|player}} directly updating the sign, or by + a plugin changing the sign text using the API.

+

+ See also the {{OnUpdatingSign|HOOK_UPDATING_SIGN}} hook for a similar hook called before the update, + with a chance to modify the text. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the sign resides" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the sign" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the sign" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the sign" }, + { Name = "Line1", Type = "string", Notes = "1st line of the new text" }, + { Name = "Line2", Type = "string", Notes = "2nd line of the new text" }, + { Name = "Line3", Type = "string", Notes = "3rd line of the new text" }, + { Name = "Line4", Type = "string", Notes = "4th line of the new text" }, + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is changing the text. May be nil for non-player updates." } + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called. There is no overridable behavior. + ]], + }, -- HOOK_UPDATED_SIGN +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnUpdatingSign.lua b/MCServer/Plugins/APIDump/Hooks/OnUpdatingSign.lua new file mode 100644 index 000000000..d74458182 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnUpdatingSign.lua @@ -0,0 +1,58 @@ +return +{ + HOOK_UPDATING_SIGN = + { + CalledWhen = "Before the sign text is updated. Plugin may modify the text / refuse.", + DefaultFnName = "OnUpdatingSign", -- also used as pagename + Desc = [[ + This hook is called when a sign text is about to be updated, either as a result of player's + manipulation or any other event, such as a plugin setting the sign text. Plugins may modify the text + or refuse the update altogether.

+

+ See also the {{OnUpdatedSign|HOOK_UPDATED_SIGN}} hook for a similar hook called after the update. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the sign resides" }, + { Name = "BlockX", Type = "number", Notes = "X-coord of the sign" }, + { Name = "BlockY", Type = "number", Notes = "Y-coord of the sign" }, + { Name = "BlockZ", Type = "number", Notes = "Z-coord of the sign" }, + { Name = "Line1", Type = "string", Notes = "1st line of the new text" }, + { Name = "Line2", Type = "string", Notes = "2nd line of the new text" }, + { Name = "Line3", Type = "string", Notes = "3rd line of the new text" }, + { Name = "Line4", Type = "string", Notes = "4th line of the new text" }, + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is changing the text. May be nil for non-player updates." } + }, + Returns = [[ + The function may return up to five values. If the function returns true as the first value, no other + callbacks are called for this event and the sign is not updated. If the function returns no value or + false as its first value, other plugins' callbacks are called.

+

+ The other up to four values returned are used to update the sign text, line by line, respectively. + Note that other plugins may again update the texts (if the first value returned is false). + ]], + CodeExamples = + { + { + Title = "Add player signature", + Desc = "The following example appends a player signature to the last line, if the sign is updated by a player:", + Code = [[ +function OnUpdatingSign(World, BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4, Player) + if (Player == nil) then + -- Not changed by a player + return false; + end + + -- Sign with playername, allow other plugins to interfere: + return false, Line1, Line2, Line3, Line4 .. Player:GetName(); +end + ]], + } + } , + }, -- HOOK_UPDATING_SIGN +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnWeatherChanged.lua b/MCServer/Plugins/APIDump/Hooks/OnWeatherChanged.lua new file mode 100644 index 000000000..2a3bbe92b --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnWeatherChanged.lua @@ -0,0 +1,28 @@ +return +{ + HOOK_WEATHER_CHANGED = + { + CalledWhen = "The weather has changed", + DefaultFnName = "OnWeatherChanged", -- also used as pagename + Desc = [[ + This hook is called after the weather has changed in a {{cWorld|world}}. The new weather has already + been sent to the clients.

+

+ See also the {{OnWeatherChanging|HOOK_WEATHER_CHANGING}} hook for a similar hook called before the + change. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "World for which the weather has changed" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. There is no overridable behavior. + ]], + }, -- HOOK_WEATHER_CHANGED +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnWeatherChanging.lua b/MCServer/Plugins/APIDump/Hooks/OnWeatherChanging.lua new file mode 100644 index 000000000..d36164e8e --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnWeatherChanging.lua @@ -0,0 +1,32 @@ +return +{ + HOOK_WEATHER_CHANGING = + { + CalledWhen = "The weather is about to change", + DefaultFnName = "OnWeatherChanging", -- also used as pagename + Desc = [[ + This hook is called when the current weather has expired and a new weather is selected. Plugins may + override the new weather setting.

+

+ The new weather setting is sent to the clients only after this hook has been processed.

+

+ See also the {{OnWeatherChanged|HOOK_WEATHER_CHANGED}} hook for a similar hook called after the + change. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "World for which the weather is changing" }, + { Name = "Weather", Type = "number", Notes = "The newly selected weather. One of wSunny, wRain, wStorm" }, + }, + Returns = [[ + If the function returns false or no value, the server calls other plugins' callbacks and finally + sets the weather. If the function returns true, the server takes the second returned value (wSunny + by default) and sets it as the new weather. No other plugins' callbacks are called in this case. + ]], + }, -- HOOK_WEATHER_CHANGING +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnWorldTick.lua b/MCServer/Plugins/APIDump/Hooks/OnWorldTick.lua new file mode 100644 index 000000000..657716d9e --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnWorldTick.lua @@ -0,0 +1,29 @@ +return +{ + HOOK_WORLD_TICK = + { + CalledWhen = "Every world tick (about 20 times per second), separately for each world", + DefaultFnName = "OnWorldTick", -- also used as pagename + Desc = [[ + This hook is called for each {{cWorld|world}} every tick (50 msec, or 20 times a second). If the + world is overloaded, the interval is larger, which is indicated by the TimeDelta parameter.

+

+ This hook is called in the world's tick thread context and thus has access to all world data + guaranteed without blocking. + ]], + Params = + { + { Name = "World", Type = "{{cWorld}}", Notes = "World that is ticking" }, + { Name = "TimeDelta", Type = "number", Notes = "The number of milliseconds since the previous game tick. Will not be less than 50 msec" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. There is no overridable behavior. + ]], + }, -- HOOK_WORLD_TICK +} + + + + + diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index 9c4fb17f8..f77409f91 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -41,6 +41,16 @@ function Initialize(Plugin) LOG("Initialising " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) g_PluginFolder = Plugin:GetLocalFolder(); + + -- Load the API descriptions from the Classes and Hooks subfolders: + if (g_APIDesc.Classes == nil) then + g_APIDesc.Classes = {}; + end + if (g_APIDesc.Hooks == nil) then + g_APIDesc.Hooks = {}; + end + LoadAPIFiles("/Classes/", g_APIDesc.Classes); + LoadAPIFiles("/Hooks/", g_APIDesc.Hooks); -- dump all available API functions and objects: -- DumpAPITxt(); @@ -57,6 +67,29 @@ end +function LoadAPIFiles(a_Folder, a_DstTable) + local Folder = g_PluginFolder .. a_Folder; + for idx, fnam in ipairs(cFile:GetFolderContents(Folder)) do + local FileName = Folder .. fnam; + -- We only want .lua files from the folder: + if (cFile:IsFile(FileName) and fnam:match(".*%.lua$")) then + local TablesFn, Err = loadfile(FileName); + if (TablesFn == nil) then + LOGWARNING("Cannot load API descriptions from " .. FileName .. ", Lua error '" .. Err .. "'."); + else + local Tables = TablesFn(); + for k, cls in pairs(Tables) do + a_DstTable[k] = cls; + end + end -- if (TablesFn) + end -- if (is lua file) + end -- for fnam - Folder[] +end + + + + + function DumpAPITxt() LOG("Dumping all available functions to API.txt..."); function dump (prefix, a, Output) -- cgit v1.2.3 From 3ef7f2008f87d2ea1f99a1dc008a4688d9b13c7b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 23 Nov 2013 21:32:18 +0100 Subject: APIDump: Reformatted the sqlite docs. --- MCServer/Plugins/APIDump/APIDesc.lua | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 1ad5bf5e4..8778727e1 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2439,11 +2439,23 @@ Parser:close(); Functions = { complete = { Params = "string", Return = "bool", Notes = "Returns true if the string sql comprises one or more complete SQL statements and false otherwise." }, - open = { Params = "string", Return = "Userdata", Notes = [[Opens (or creates if it does not exist) an SQLite database with name filename and returns its handle as userdata (the returned object should be used for all further method calls in connection with this specific database, see {{http://lua.sqlite.org/index.cgi/doc/tip/doc/lsqlite3.wiki#database_methods|Database methods}}). Example:

myDB=sqlite3.open('MyDatabase.sqlite3')  -- open
+				open = { Params = "FileName", Return = "DBClass", Notes = [[
+					Opens (or creates if it does not exist) an SQLite database with name filename and returns its
+					handle as userdata (the returned object should be used for all further method calls in connection
+					with this specific database, see
+					{{http://lua.sqlite.org/index.cgi/doc/tip/doc/lsqlite3.wiki#database_methods|Database methods}}).
+					Example:
+
+-- open the database:
+myDB = sqlite3.open('MyDatabaseFile.sqlite3')
+
 -- do some database calls...
-myDB:close()  -- close
-TakeDamageInfo =
]], }, - open_memory = { Return = "userdata", Notes = "Opens an SQLite database in memory and returns its handle as userdata. In case of an error, the function returns nil, an error code and an error message. (In-memory databases are volatile as they are never stored on disk.)" }, + +-- Close the database: +myDB:close() +
+ ]], }, + open_memory = { Return = "DBClass", Notes = "Opens an SQLite database in memory and returns its handle as userdata. In case of an error, the function returns nil, an error code and an error message. (In-memory databases are volatile as they are never stored on disk.)" }, temp_directory = { Params = "string", Notes = "Opens an SQLite database in memory and returns its handle as userdata. In case of an error, the function returns nil, an error code and an error message. (In-memory databases are volatile as they are never stored on disk.)" }, version = { Return = "string", Notes = "Returns a string with SQLite version information, in the form 'x.y[.z]'." }, }, -- cgit v1.2.3 From 38fe16d8b6bfc41f077cb700a3bc5a537cf28959 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 23 Nov 2013 21:43:38 +0100 Subject: APIDump: Removed unwanted functions. --- 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 8778727e1..afe002784 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2456,7 +2456,6 @@ myDB:close()
]], }, open_memory = { Return = "DBClass", Notes = "Opens an SQLite database in memory and returns its handle as userdata. In case of an error, the function returns nil, an error code and an error message. (In-memory databases are volatile as they are never stored on disk.)" }, - temp_directory = { Params = "string", Notes = "Opens an SQLite database in memory and returns its handle as userdata. In case of an error, the function returns nil, an error code and an error message. (In-memory databases are volatile as they are never stored on disk.)" }, version = { Return = "string", Notes = "Returns a string with SQLite version information, in the form 'x.y[.z]'." }, }, }, @@ -2813,6 +2812,7 @@ end "Globals.collectgarbage", "Globals.xpcall", "Globals.decoda_output", -- When running under Decoda, this function gets added to the global namespace + "sqlite3.__newindex", "%a+\.__%a+", -- AnyClass.__Anything "%a+\.\.collector", -- AnyClass..collector "%a+\.new", -- AnyClass.new @@ -2828,6 +2828,7 @@ end "ListMissingPages", "ListUndocumentedObjects", "ListUnexportedObjects", + "LoadAPIFiles", "ReadDescriptions", "ReadHooks", "WriteHtmlClass", -- cgit v1.2.3 From 51b02854f9f9dc597d095f14c1b05150edf604e4 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 24 Nov 2013 10:03:02 +0100 Subject: APIDump: Removed needless whitespace output. --- MCServer/Plugins/APIDump/main_APIDump.lua | 231 ++++++++++++++---------------- 1 file changed, 108 insertions(+), 123 deletions(-) diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index f77409f91..de4239f7e 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -289,50 +289,53 @@ function DumpAPIHtml() end f:write([[ - - + + MCServer API - Index - - + +
-
-

MCServer API - Index

-
-
-

The API reference is divided into the following sections:

- - - -
-

Class index

-

The following classes are available in the MCServer Lua scripting language:

- -
    -]]); +
    +

    MCServer API - Index

    +
    +
    +

    The API reference is divided into the following sections:

    + +
    +

    Class index

    +

    The following classes are available in the MCServer Lua scripting language: +

    - -
    -

    Hooks

    - -

    A plugin can register to be called whenever an "interesting event" occurs. It does so by calling cPluginManager's AddHook() function and implementing a callback function to handle the event.

    -

    A plugin can decide whether it will let the event pass through to the rest of the plugins, or hide it from them. This is determined by the return value from the hook callback function. If the function returns false or no value, the event is propagated further. If the function returns true, the processing is stopped, no other plugin receives the notification (and possibly MCServer disables the default behavior for the event). See each hook's details to see the exact behavior.

    - - - - - - -]]); + f:write([[ +

    +
    +

    Hooks

    +

    + A plugin can register to be called whenever an "interesting event" occurs. It does so by calling + cPluginManager's AddHook() function and implementing a callback + function to handle the event.

    +

    + A plugin can decide whether it will let the event pass through to the rest of the plugins, or hide it + from them. This is determined by the return value from the hook callback function. If the function + returns false or no value, the event is propagated further. If the function returns true, the processing + is stopped, no other plugin receives the notification (and possibly MCServer disables the default + behavior for the event). See each hook's details to see the exact behavior.

    +
    Hook nameCalled when
    + + + + + ]]); for i, hook in ipairs(Hooks) do if (hook.DefaultFnName == nil) then -- The hook is not documented yet @@ -826,16 +829,16 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) end if (a_InheritedName ~= nil) then - cf:write("

    Functions inherited from ", a_InheritedName, "

    \n"); + cf:write("

    Functions inherited from ", a_InheritedName, "

    \n"); end - cf:write("
    Hook nameCalled when
    \n \n \n \n \n \n \n"); + cf:write("
    NameParametersReturn valueNotes
    \n\n"); for i, func in ipairs(a_Functions) do - cf:write(" \n \n"); - cf:write(" \n"); - cf:write(" \n"); - cf:write(" \n \n"); + cf:write("\n"); + cf:write("\n"); + cf:write("\n"); + cf:write("\n"); end - cf:write("
    NameParametersReturn valueNotes
    " .. func.Name .. "", LinkifyString(func.Params or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Return or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Notes or "(undocumented)", (a_InheritedName or a_ClassAPI.Name)), "
    ", func.Name, "", LinkifyString(func.Params or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Return or "", (a_InheritedName or a_ClassAPI.Name)), "", LinkifyString(func.Notes or "(undocumented)", (a_InheritedName or a_ClassAPI.Name)), "
    \n\n"); + cf:write("\n"); end local function WriteConstantTable(a_Constants, a_Source) @@ -879,16 +882,16 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) end if (a_InheritedName ~= nil) then - cf:write("

    Member variables inherited from ", a_InheritedName, "

    \n"); + cf:write("

    Member variables inherited from ", a_InheritedName, "

    \n"); end - cf:write(" \n \n \n \n \n \n"); + cf:write("
    NameTypeNotes
    \n"); for i, var in ipairs(a_Variables) do - cf:write(" \n \n"); - cf:write(" \n"); - cf:write(" \n \n"); + cf:write("\n"); + cf:write("\n"); + cf:write("\n \n"); end - cf:write("
    NameTypeNotes
    ", var.Name, "", LinkifyString(var.Type or "(undocumented)", a_InheritedName or a_ClassAPI.Name), "", LinkifyString(var.Notes or "", a_InheritedName or a_ClassAPI.Name), "
    ", var.Name, "", LinkifyString(var.Type or "(undocumented)", a_InheritedName or a_ClassAPI.Name), "", LinkifyString(var.Notes or "", a_InheritedName or a_ClassAPI.Name), "
    \n\n"); + cf:write("\n\n"); end local function WriteDescendants(a_Descendants) @@ -914,25 +917,23 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) CurrInheritance = CurrInheritance.Inherits; end - cf:write([[ - - + cf:write([[ + MCServer API - ]], a_ClassAPI.Name, [[ Class - - + +
    -
    -

    ]], a_ClassAPI.Name, [[

    -
    -
    -

    Contents

    - -

    \n"); -- Write the class description: - cf:write("

    " .. ClassName .. " class

    \n"); + cf:write("

    ", ClassName, " class

    \n"); if (a_ClassAPI.Desc ~= nil) then - cf:write("

    "); + cf:write("

    "); cf:write(LinkifyString(a_ClassAPI.Desc, ClassName)); - cf:write("

    \n\n"); + cf:write("

    \n\n"); end; -- Write the inheritance, if available: if (HasInheritance) then - cf:write(" \n

    Inheritance

    \n"); + cf:write("

    Inheritance

    \n"); if (#InheritanceChain > 0) then - cf:write("

    This class inherits from the following parent classes:

    \n\n
      \n"); + cf:write("

      This class inherits from the following parent classes:

      \n\n"); + cf:write("

    \n"); end if (#a_ClassAPI.Descendants > 0) then - cf:write("

    This class has the following descendants:\n"); + cf:write("

    This class has the following descendants:\n"); WriteDescendants(a_ClassAPI.Descendants); - cf:write("

    \n\n"); + cf:write("

    \n\n"); end end -- Write the constants: if (HasConstants) then - cf:write("

    Constants

    \n"); + cf:write("

    Constants

    \n"); WriteConstants(a_ClassAPI.Constants, a_ClassAPI.ConstantGroups, a_ClassAPI.NumConstantsInGroups, nil); g_Stats.NumTotalConstants = g_Stats.NumTotalConstants + #a_ClassAPI.Constants + (a_ClassAPI.NumConstantsInGroups or 0); for i, cls in ipairs(InheritanceChain) do @@ -1002,7 +1003,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) -- Write the member variables: if (HasVariables) then - cf:write("

    Member variables

    \n"); + cf:write("

    Member variables

    \n"); WriteVariables(a_ClassAPI.Variables, nil); g_Stats.NumTotalVariables = g_Stats.NumTotalVariables + #a_ClassAPI.Variables; for i, cls in ipairs(InheritanceChain) do @@ -1012,7 +1013,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) -- Write the functions, including the inherited ones: if (HasFunctions) then - cf:write("

    Functions

    \n"); + cf:write("

    Functions

    \n"); WriteFunctions(a_ClassAPI.Functions, nil); g_Stats.NumTotalFunctions = g_Stats.NumTotalFunctions + #a_ClassAPI.Functions; for i, cls in ipairs(InheritanceChain) do @@ -1023,19 +1024,12 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI) -- Write the additional infos: if (a_ClassAPI.AdditionalInfo ~= nil) then for i, additional in ipairs(a_ClassAPI.AdditionalInfo) do - cf:write("

    ", additional.Header, "

    \n"); + cf:write("

    ", additional.Header, "

    \n"); cf:write(LinkifyString(additional.Contents, ClassName)); end end - cf:write([[ -
    - - - - ]]); + cf:write([[
]]); cf:close(); end @@ -1052,27 +1046,26 @@ function WriteHtmlHook(a_Hook) end local HookName = a_Hook.DefaultFnName; - f:write([[ - - - MCServer API - ]] .. HookName .. [[ Hook + f:write([[ + + MCServer API - ]], HookName, [[ Hook - - + +
-
-

]] .. a_Hook.Name .. [[

-
-
-

-]]); +

+

]], a_Hook.Name, [[

+
+
+

+ ]]); f:write(LinkifyString(a_Hook.Desc, HookName)); - f:write("

\n

Callback function

\n

The default name for the callback function is "); - f:write(a_Hook.DefaultFnName .. ". It has the following signature:\n\n"); - f:write("

function " .. HookName .. "(");
+	f:write("

\n

Callback function

\n

The default name for the callback function is "); + f:write(a_Hook.DefaultFnName, ". It has the following signature:\n"); + f:write("

function ", HookName, "(");
 	if (a_Hook.Params == nil) then
 		a_Hook.Params = {};
 	end
@@ -1082,30 +1075,22 @@ function WriteHtmlHook(a_Hook)
 		end
 		f:write(param.Name);
 	end
-	f:write(")
\n\n

Parameters:

\n\n \n \n \n \n \n \n"); + f:write(")\n

Parameters:

\n
NameTypeNotes
\n"); for i, param in ipairs(a_Hook.Params) do - f:write(" \n \n \n \n \n"); + f:write("\n"); end - f:write("
NameTypeNotes
" .. param.Name .. "" .. LinkifyString(param.Type, HookName) .. "" .. LinkifyString(param.Notes, HookName) .. "
", param.Name, "", LinkifyString(param.Type, HookName), "", LinkifyString(param.Notes, HookName), "
\n\n

" .. (a_Hook.Returns or "") .. "

\n\n"); - f:write([[

Code examples

-

Registering the callback

- -]]); - f:write("
\n");
+	f:write("\n

" .. (a_Hook.Returns or "") .. "

\n\n"); + f:write([[

Code examples

Registering the callback

]]); + f:write("
\n");
 	f:write([[cPluginManager.AddHook(cPluginManager.]] .. a_Hook.Name .. ", My" .. a_Hook.DefaultFnName .. [[);]]);
 	f:write("
\n\n"); local Examples = a_Hook.CodeExamples or {}; for i, example in ipairs(Examples) do - f:write("

" .. (example.Title or "missing Title") .. "

\n"); - f:write("

" .. (example.Desc or "missing Desc") .. "

\n\n"); - f:write("
" .. (example.Code or "missing Code") .. "\n			
\n\n"); + f:write("

", (example.Title or "missing Title"), "

\n"); + f:write("

", (example.Desc or "missing Desc"), "

\n"); + f:write("
", (example.Code or "missing Code"), "\n
\n\n"); end - f:write([[
- - -]]); + f:write([[]]); f:close(); end -- cgit v1.2.3 From e683c54b49f88e989efaef0225de996293f7444c Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 24 Nov 2013 10:08:04 +0100 Subject: APIDump: Moved projectiles' documentation to a separate file. --- MCServer/Plugins/APIDump/APIDesc.lua | 111 +---------------------- MCServer/Plugins/APIDump/Classes/Projectiles.lua | 111 +++++++++++++++++++++++ 2 files changed, 112 insertions(+), 110 deletions(-) create mode 100644 MCServer/Plugins/APIDump/Classes/Projectiles.lua diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index afe002784..44e4bb35f 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -63,45 +63,6 @@ g_APIDesc = }, ]]-- - cArrowEntity = - { - Desc = [[ - Represents the arrow when it is shot from the bow. A subclass of the {{cProjectileEntity}}. - ]], - - Functions = - { - CanPickup = { Params = "{{cPlayer|Player}}", Return = "bool", Notes = "Returns true if the specified player can pick the arrow when it's on the ground" }, - GetDamageCoeff = { Params = "", Return = "number", Notes = "Returns the damage coefficient stored within the arrow. The damage dealt by this arrow is multiplied by this coeff" }, - GetPickupState = { Params = "", Return = "PickupState", Notes = "Returns the pickup state (one of the psXXX constants, above)" }, - IsCritical = { Params = "", Return = "bool", Notes = "Returns true if the arrow should deal critical damage. Based on the bow charge when the arrow was shot." }, - SetDamageCoeff = { Params = "number", Return = "", Notes = "Sets the damage coefficient. The damage dealt by this arrow is multiplied by this coeff" }, - SetIsCritical = { Params = "bool", Return = "", Notes = "Sets the IsCritical flag on the arrow. Critical arrow deal additional damage" }, - SetPickupState = { Params = "PickupState", Return = "", Notes = "Sets the pickup state (one of the psXXX constants, above)" }, - }, - - Constants = - { - psInCreative = { Notes = "The arrow can be picked up only by players in creative gamemode" }, - psInSurvivalOrCreative = { Notes = "The arrow can be picked up by players in survival or creative gamemode" }, - psNoPickup = { Notes = "The arrow cannot be picked up at all" }, - }, - - ConstantGroups = - { - PickupState = - { - Include = "ps.*", - TextBefore = [[ - The following constants are used to signalize whether the arrow, once it lands, can be picked by - players: - ]], - }, - }, - - Inherits = "cProjectileEntity", - }, - cBlockArea = { Desc = [[ @@ -850,20 +811,6 @@ cFile:Delete("/usr/bin/virus.exe"); }, }, -- cFile - cFireChargeEntity = - { - Desc = "", - Functions = {}, - Inherits = "cProjectileEntity", - } , - - cGhastFireballEntity = - { - Desc = "", - Functions = {}, - Inherits = "cProjectileEntity", - }, -- cGhastFireballEntity - cGroup = { Desc = [[ @@ -1828,42 +1775,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); HOOK_WEATHER_CHANGING = { Notes = "Called just before the weather changes" }, HOOK_WORLD_TICK = { Notes = "Called in each world's tick thread when the game logic is about to tick (20 times a second)." }, }, - }, - - cProjectileEntity = - { - Desc = "", - Functions = - { - GetCreator = { Params = "", Return = "{{cEntity}} descendant", Notes = "Returns the entity who created this projectile. May return nil." }, - GetMCAClassName = { Params = "", Return = "string", Notes = "Returns the string that identifies the projectile type (class name) in MCA files" }, - GetProjectileKind = { Params = "", Return = "ProjectileKind", Notes = "Returns the kind of this projectile (pkXXX constant)" }, - IsInGround = { Params = "", Return = "bool", Notes = "Returns true if this projectile has hit the ground." }, - }, - Constants = - { - pkArrow = { Notes = "The projectile is an {{cArrowEntity|arrow}}" }, - pkEgg = { Notes = "The projectile is a {{cThrownEggEntity|thrown egg}}" }, - pkEnderPearl = { Notes = "The projectile is a {{cThrownEnderPearlEntity|thrown enderpearl}}" }, - pkExpBottle = { Notes = "The projectile is a thrown exp bottle (NYI)" }, - pkFireCharge = { Notes = "The projectile is a {{cFireChargeEntity|fire charge}}" }, - pkFirework = { Notes = "The projectile is a (flying) firework (NYI)" }, - pkFishingFloat = { Notes = "The projectile is a fishing float (NYI)" }, - pkGhastFireball = { Notes = "The projectile is a {{cGhastFireballEntity|ghast fireball}}" }, - pkSnowball = { Notes = "The projectile is a {{cThrownSnowballEntity|thrown snowball}}" }, - pkSplashPotion = { Notes = "The projectile is a thrown splash potion (NYI)" }, - pkWitherSkull = { Notes = "The projectile is a wither skull (NYI)" }, - }, - ConstantGroups = - { - ProjectileKind = - { - Include = "pk.*", - TextBefore = "The following constants are used to distinguish between the different projectile kinds:", - }, - }, - Inherits = "cEntity", - }, + }, -- cPluginManager cRoot = { @@ -1948,27 +1860,6 @@ end }, }, -- cServer - cThrownEggEntity = - { - Desc = "", - Functions = {}, - Inherits = "cProjectileEntity", - }, -- cThrownEggEntity - - cThrownEnderPearlEntity = - { - Desc = "", - Functions = {}, - Inherits = "cProjectileEntity", - }, -- cThrownEnderPearlEntity - - cThrownSnowballEntity = - { - Desc = "", - Functions = {}, - Inherits = "cProjectileEntity", - }, -- cThrownSnowballEntity - cTracer = { Desc = [[ diff --git a/MCServer/Plugins/APIDump/Classes/Projectiles.lua b/MCServer/Plugins/APIDump/Classes/Projectiles.lua new file mode 100644 index 000000000..08c981e5d --- /dev/null +++ b/MCServer/Plugins/APIDump/Classes/Projectiles.lua @@ -0,0 +1,111 @@ +return +{ + cArrowEntity = + { + Desc = [[ + Represents the arrow when it is shot from the bow. A subclass of the {{cProjectileEntity}}. + ]], + Functions = + { + CanPickup = { Params = "{{cPlayer|Player}}", Return = "bool", Notes = "Returns true if the specified player can pick the arrow when it's on the ground" }, + GetDamageCoeff = { Params = "", Return = "number", Notes = "Returns the damage coefficient stored within the arrow. The damage dealt by this arrow is multiplied by this coeff" }, + GetPickupState = { Params = "", Return = "PickupState", Notes = "Returns the pickup state (one of the psXXX constants, above)" }, + IsCritical = { Params = "", Return = "bool", Notes = "Returns true if the arrow should deal critical damage. Based on the bow charge when the arrow was shot." }, + SetDamageCoeff = { Params = "number", Return = "", Notes = "Sets the damage coefficient. The damage dealt by this arrow is multiplied by this coeff" }, + SetIsCritical = { Params = "bool", Return = "", Notes = "Sets the IsCritical flag on the arrow. Critical arrow deal additional damage" }, + SetPickupState = { Params = "PickupState", Return = "", Notes = "Sets the pickup state (one of the psXXX constants, above)" }, + }, + Constants = + { + psInCreative = { Notes = "The arrow can be picked up only by players in creative gamemode" }, + psInSurvivalOrCreative = { Notes = "The arrow can be picked up by players in survival or creative gamemode" }, + psNoPickup = { Notes = "The arrow cannot be picked up at all" }, + }, + ConstantGroups = + { + PickupState = + { + Include = "ps.*", + TextBefore = [[ + The following constants are used to signalize whether the arrow, once it lands, can be picked by + players: + ]], + }, + }, + Inherits = "cProjectileEntity", + }, -- cArrowEntity + + cFireChargeEntity = + { + Desc = "", + Functions = {}, + Inherits = "cProjectileEntity", + }, -- cFireChargeEntity + + cGhastFireballEntity = + { + Desc = "", + Functions = {}, + Inherits = "cProjectileEntity", + }, -- cGhastFireballEntity + + cProjectileEntity = + { + Desc = "", + Functions = + { + GetCreator = { Params = "", Return = "{{cEntity}} descendant", Notes = "Returns the entity who created this projectile. May return nil." }, + GetMCAClassName = { Params = "", Return = "string", Notes = "Returns the string that identifies the projectile type (class name) in MCA files" }, + GetProjectileKind = { Params = "", Return = "ProjectileKind", Notes = "Returns the kind of this projectile (pkXXX constant)" }, + IsInGround = { Params = "", Return = "bool", Notes = "Returns true if this projectile has hit the ground." }, + }, + Constants = + { + pkArrow = { Notes = "The projectile is an {{cArrowEntity|arrow}}" }, + pkEgg = { Notes = "The projectile is a {{cThrownEggEntity|thrown egg}}" }, + pkEnderPearl = { Notes = "The projectile is a {{cThrownEnderPearlEntity|thrown enderpearl}}" }, + pkExpBottle = { Notes = "The projectile is a thrown exp bottle (NYI)" }, + pkFireCharge = { Notes = "The projectile is a {{cFireChargeEntity|fire charge}}" }, + pkFirework = { Notes = "The projectile is a (flying) firework (NYI)" }, + pkFishingFloat = { Notes = "The projectile is a fishing float (NYI)" }, + pkGhastFireball = { Notes = "The projectile is a {{cGhastFireballEntity|ghast fireball}}" }, + pkSnowball = { Notes = "The projectile is a {{cThrownSnowballEntity|thrown snowball}}" }, + pkSplashPotion = { Notes = "The projectile is a thrown splash potion (NYI)" }, + pkWitherSkull = { Notes = "The projectile is a wither skull (NYI)" }, + }, + ConstantGroups = + { + ProjectileKind = + { + Include = "pk.*", + TextBefore = "The following constants are used to distinguish between the different projectile kinds:", + }, + }, + Inherits = "cEntity", + }, -- cProjectileEntity + + cThrownEggEntity = + { + Desc = "", + Functions = {}, + Inherits = "cProjectileEntity", + }, -- cThrownEggEntity + + cThrownEnderPearlEntity = + { + Desc = "", + Functions = {}, + Inherits = "cProjectileEntity", + }, -- cThrownEnderPearlEntity + + cThrownSnowballEntity = + { + Desc = "", + Functions = {}, + Inherits = "cProjectileEntity", + }, -- cThrownSnowballEntity +} + + + + -- cgit v1.2.3 From 1f8399fae528f44e0543d1baca7d6ccbc2dd5f8b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 24 Nov 2013 14:28:51 +0100 Subject: Fixed socket connection startup. --- source/OSSupport/Socket.cpp | 14 +++++++------- source/OSSupport/Socket.h | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/source/OSSupport/Socket.cpp b/source/OSSupport/Socket.cpp index 48b5d704d..c461d38a4 100644 --- a/source/OSSupport/Socket.cpp +++ b/source/OSSupport/Socket.cpp @@ -169,7 +169,7 @@ bool cSocket::SetReuseAddress(void) -int cSocket::WSAStartup() +int cSocket::WSAStartup(void) { #ifdef _WIN32 WSADATA wsaData; @@ -336,23 +336,23 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por { // First try IP Address string to hostent conversion, because it's faster unsigned long addr = inet_addr(a_HostNameOrAddr.c_str()); - hostent * hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET); - if (hp == NULL) + if (addr == INADDR_NONE) { // It is not an IP Address string, but rather a regular hostname, resolve: - hp = gethostbyname(a_HostNameOrAddr.c_str()); + hostent * hp = gethostbyname(a_HostNameOrAddr.c_str()); if (hp == NULL) { - LOGWARN("cTCPLink: Could not resolve hostname \"%s\"", a_HostNameOrAddr.c_str()); + LOGWARNING("%s: Could not resolve hostname \"%s\"", __FUNCTION__, a_HostNameOrAddr.c_str()); CloseSocket(); return false; } + addr = *((unsigned long*)hp->h_addr); } sockaddr_in server; - server.sin_addr.s_addr = *((unsigned long*)hp->h_addr); + server.sin_addr.s_addr = addr; server.sin_family = AF_INET; - server.sin_port = htons( (unsigned short)a_Port ); + server.sin_port = htons((unsigned short)a_Port); return (connect(m_Socket, (sockaddr *)&server, sizeof(server)) == 0); } diff --git a/source/OSSupport/Socket.h b/source/OSSupport/Socket.h index 34f09cc74..81bfd28fc 100644 --- a/source/OSSupport/Socket.h +++ b/source/OSSupport/Socket.h @@ -38,6 +38,7 @@ public: /// Sets the address-reuse socket flag; returns true on success bool SetReuseAddress(void); + /// Initializes the network stack. Returns 0 on success, or another number as an error code. static int WSAStartup(void); static AString GetErrorString(int a_ErrNo); -- cgit v1.2.3 From c10daa853085a4b4abf0cc202ea6070a2a110ace Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 24 Nov 2013 14:29:15 +0100 Subject: RCON server: Login failure gets sent to the client. --- source/RCONServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/RCONServer.cpp b/source/RCONServer.cpp index 93f2ccdd3..3f86a7ca2 100644 --- a/source/RCONServer.cpp +++ b/source/RCONServer.cpp @@ -241,6 +241,7 @@ bool cRCONServer::cConnection::ProcessPacket(int a_RequestID, int a_PacketType, if (strncmp(a_Payload, m_RCONServer.m_Password.c_str(), a_PayloadLength) != 0) { LOGINFO("RCON: Invalid password from client %s, dropping connection.", m_IPAddress.c_str()); + SendResponse(-1, RCON_PACKET_RESPONSE, 0, NULL); return false; } m_IsAuthenticated = true; -- cgit v1.2.3 From dbb76ef9fefa90a1e24acc42ba0421980df89379 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 24 Nov 2013 14:35:35 +0100 Subject: RCONClient: Initial implementation. Fix #79. --- Tools/RCONClient/.gitignore | 7 + Tools/RCONClient/Globals.cpp | 10 ++ Tools/RCONClient/Globals.h | 208 +++++++++++++++++++++++ Tools/RCONClient/RCONClient.cpp | 332 +++++++++++++++++++++++++++++++++++++ Tools/RCONClient/RCONClient.sln | 20 +++ Tools/RCONClient/RCONClient.vcproj | 287 ++++++++++++++++++++++++++++++++ source/ByteBuffer.cpp | 54 ++++++ source/ByteBuffer.h | 2 + 8 files changed, 920 insertions(+) create mode 100644 Tools/RCONClient/.gitignore create mode 100644 Tools/RCONClient/Globals.cpp create mode 100644 Tools/RCONClient/Globals.h create mode 100644 Tools/RCONClient/RCONClient.cpp create mode 100644 Tools/RCONClient/RCONClient.sln create mode 100644 Tools/RCONClient/RCONClient.vcproj diff --git a/Tools/RCONClient/.gitignore b/Tools/RCONClient/.gitignore new file mode 100644 index 000000000..e124797c5 --- /dev/null +++ b/Tools/RCONClient/.gitignore @@ -0,0 +1,7 @@ +Debug/ +logs/ +Release/ +*.suo +*.user +*.ncb +*.sdf diff --git a/Tools/RCONClient/Globals.cpp b/Tools/RCONClient/Globals.cpp new file mode 100644 index 000000000..13c6ae709 --- /dev/null +++ b/Tools/RCONClient/Globals.cpp @@ -0,0 +1,10 @@ + +// Globals.cpp + +// This file is used for precompiled header generation in MSVC environments + +#include "Globals.h" + + + + diff --git a/Tools/RCONClient/Globals.h b/Tools/RCONClient/Globals.h new file mode 100644 index 000000000..a3a2f2846 --- /dev/null +++ b/Tools/RCONClient/Globals.h @@ -0,0 +1,208 @@ + +// Globals.h + +// This file gets included from every module in the project, so that global symbols may be introduced easily +// Also used for precompiled header generation in MSVC environments + + + + + +// Compiler-dependent stuff: +#if defined(_MSC_VER) + // MSVC produces warning C4481 on the override keyword usage, so disable the warning altogether + #pragma warning(disable:4481) + + // Disable some warnings that we don't care about: + #pragma warning(disable:4100) + + #define OBSOLETE __declspec(deprecated) + + // No alignment needed in MSVC + #define ALIGN_8 + #define ALIGN_16 + +#elif defined(__GNUC__) + + // TODO: Can GCC explicitly mark classes as abstract (no instances can be created)? + #define abstract + + // TODO: Can GCC mark virtual methods as overriding (forcing them to have a virtual function of the same signature in the base class) + #define override + + #define OBSOLETE __attribute__((deprecated)) + + #define ALIGN_8 __attribute__((aligned(8))) + #define ALIGN_16 __attribute__((aligned(16))) + + // Some portability macros :) + #define stricmp strcasecmp + +#else + + #error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler" + + /* + // Copy and uncomment this into another #elif section based on your compiler identification + + // Explicitly mark classes as abstract (no instances can be created) + #define abstract + + // Mark virtual methods as overriding (forcing them to have a virtual function of the same signature in the base class) + #define override + + // Mark functions as obsolete, so that their usage results in a compile-time warning + #define OBSOLETE + + // Mark types / variables for alignment. Do the platforms need it? + #define ALIGN_8 + #define ALIGN_16 + */ + +#endif + + + + + +// Integral types with predefined sizes: +typedef long long Int64; +typedef int Int32; +typedef short Int16; + +typedef unsigned long long UInt64; +typedef unsigned int UInt32; +typedef unsigned short UInt16; + + + + + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for any class that shouldn't allow copying itself +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName &); \ + void operator=(const TypeName &) + +// A macro that is used to mark unused function parameters, to avoid pedantic warnings in gcc +#define UNUSED(X) (void)(X) + + + + +// OS-dependent stuff: +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + + #define _WIN32_WINNT 0x501 // We want to target WinXP and higher + + #include + #include + #include // IPv6 stuff + + // Windows SDK defines min and max macros, messing up with our std::min and std::max usage + #undef min + #undef max + + // Windows SDK defines GetFreeSpace as a constant, probably a Win16 API remnant + #ifdef GetFreeSpace + #undef GetFreeSpace + #endif // GetFreeSpace +#else + #include + #include // for mkdir + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + #include +#if !defined(ANDROID_NDK) + #include +#endif +#endif + +#if !defined(ANDROID_NDK) + #define USE_SQUIRREL +#endif + +#if defined(ANDROID_NDK) + #define FILE_IO_PREFIX "/sdcard/mcserver/" +#else + #define FILE_IO_PREFIX "" +#endif + + + + + +// CRT stuff: +#include +#include +#include +#include +#include +#include + + + + + +// STL stuff: +#include +#include +#include +#include +#include +#include +#include + + + + + +// Common headers (part 1, without macros): +#include "StringUtils.h" +#include "OSSupport/CriticalSection.h" +#include "OSSupport/File.h" +#include "MCLogger.h" + + + + + +// Common definitions: + +/// Evaluates to the number of elements in an array (compile-time!) +#define ARRAYCOUNT(X) (sizeof(X) / sizeof(*(X))) + +/// Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it, "(32 KiB)" ) +#define KiB * 1024 + +/// Faster than (int)floorf((float)x / (float)div) +#define FAST_FLOOR_DIV( x, div ) ( (x) < 0 ? (((int)x / div) - 1) : ((int)x / div) ) + +// Own version of assert() that writes failed assertions to the log for review +#ifdef NDEBUG + #define ASSERT(x) ((void)0) +#else + #define ASSERT assert +#endif + +// Pretty much the same as ASSERT() but stays in Release builds +#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) ) + + + + + diff --git a/Tools/RCONClient/RCONClient.cpp b/Tools/RCONClient/RCONClient.cpp new file mode 100644 index 000000000..288363a66 --- /dev/null +++ b/Tools/RCONClient/RCONClient.cpp @@ -0,0 +1,332 @@ + +// RCONClient.cpp + +// Implements the main app entrypoint + +#include "Globals.h" +#include "OSSupport/Socket.h" +#include "ByteBuffer.h" + + + + + +// If set to true, verbose messages are output to stderr. Use the "-v" or "--verbose" param to turn on +bool g_IsVerbose = false; + + + + + +/// This class can read and write RCON packets to / from a connected socket +class cRCONPacketizer +{ +public: + enum + { + ptCommand = 2, + ptLogin = 3, + } ; + + cRCONPacketizer(cSocket & a_Socket); + + /// Sends the packet to the socket and waits until the response is received. + /// Returns true if response successfully received, false if the client disconnected or protocol error. + /// Dumps the reply payload to stdout. + bool SendPacket(int a_PacketType, const AString & a_PacketPayload); + +protected: + /// The socket to use for reading incoming data and writing outgoing data: + cSocket & m_Socket; + + /// The RequestID of the packet that is being sent. Incremented when the reply is received + int m_RequestID; + + /// Receives the full response and dumps its payload to stdout. + /// Returns true if successful, false if the client disconnected or protocol error. + bool ReceiveResponse(void); + + /// Parses the received response packet and dumps its payload to stdout. + /// Returns true if successful, false on protocol error + /// Assumes that the packet length has already been read from the packet + /// If the packet is successfully parsed, increments m_RequestID + bool ParsePacket(cByteBuffer & a_Buffer, int a_PacketLength); +} ; + + + + + +cRCONPacketizer::cRCONPacketizer(cSocket & a_Socket) : + m_Socket(a_Socket), + m_RequestID(0) +{ +} + + + + + +bool cRCONPacketizer::SendPacket(int a_PacketType, const AString & a_PacketPayload) +{ + // Send the packet: + cByteBuffer bb(a_PacketPayload.size() + 30); + bb.WriteLEInt(m_RequestID); + bb.WriteLEInt(a_PacketType); + bb.WriteBuf(a_PacketPayload.data(), a_PacketPayload.size()); + bb.WriteBEShort(0); // Padding + AString Packet; + bb.ReadAll(Packet); + size_t Length = Packet.size(); + if (!m_Socket.Send((const char *)&Length, 4)) + { + fprintf(stderr, "Network error while sending packet: %d (%s). Aborting.", + cSocket::GetLastError(), cSocket::GetLastErrorString().c_str() + ); + return false; + } + if (!m_Socket.Send(Packet.data(), Packet.size())) + { + fprintf(stderr, "Network error while sending packet: %d (%s). Aborting.", + cSocket::GetLastError(), cSocket::GetLastErrorString().c_str() + ); + return false; + } + + return ReceiveResponse(); +} + + + + + +bool cRCONPacketizer::ReceiveResponse(void) +{ + // Receive the response: + cByteBuffer Buffer(64 KiB); + while (true) + { + char buf[1024]; + int NumReceived = m_Socket.Receive(buf, sizeof(buf), 0); + if (NumReceived == 0) + { + fprintf(stderr, "The remote end closed the connection. Aborting."); + return false; + } + if (NumReceived < 0) + { + fprintf(stderr, "Network error while receiving response: %d, %d (%s). Aborting.", + NumReceived, cSocket::GetLastError(), cSocket::GetLastErrorString().c_str() + ); + return false; + } + Buffer.Write(buf, NumReceived); + Buffer.ResetRead(); + + // Check if the buffer contains the full packet: + if (!Buffer.CanReadBytes(14)) + { + // 14 is the minimum packet size for RCON + continue; + } + int PacketSize; + VERIFY(Buffer.ReadLEInt(PacketSize)); + if (!Buffer.CanReadBytes(PacketSize)) + { + // The packet is not complete yet + continue; + } + + // Parse the packet + return ParsePacket(Buffer, PacketSize); + } +} + + + + + +bool cRCONPacketizer::ParsePacket(cByteBuffer & a_Buffer, int a_PacketLength) +{ + // Check that the request ID is equal + bool IsValid = true; + int RequestID = 0; + VERIFY(a_Buffer.ReadLEInt(RequestID)); + if (RequestID != m_RequestID) + { + if ((RequestID == -1) && (m_RequestID == 0)) + { + fprintf(stderr, "Login failed. Aborting."); + IsValid = false; + // Continue, so that the payload is printed before the program aborts. + } + else + { + fprintf(stderr, "The server returned an invalid request ID, got %d, exp. %d. Aborting.", RequestID, m_RequestID); + return false; + } + } + + // Check the packet type: + int PacketType = 0; + VERIFY(a_Buffer.ReadLEInt(PacketType)); + if (PacketType != ptCommand) + { + fprintf(stderr, "The server returned an unknown packet type: %d. Aborting.", PacketType); + IsValid = false; + // Continue, so that the payload is printed before the program aborts. + } + + AString Payload; + VERIFY(a_Buffer.ReadString(Payload, a_PacketLength - 10)); + + // Dump the payload to stdout, in a binary mode + fwrite(Payload.data(), Payload.size(), 1, stdout); + + if (IsValid) + { + m_RequestID++; + return true; + } + return false; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// main: + +int RealMain(int argc, char * argv[]) +{ + new cMCLogger; // Create a new logger + + // Parse the cmdline params for server IP, port, password and the commands to send: + AString ServerAddress, Password; + int ServerPort = -1; + AStringVector Commands; + for (int i = 1; i < argc; i++) + { + if (((NoCaseCompare(argv[i], "-s") == 0) || (NoCaseCompare(argv[i], "--server") == 0)) && (i < argc - 1)) + { + ServerAddress = argv[i + 1]; + i++; + continue; + } + if (((NoCaseCompare(argv[i], "-p") == 0) || (NoCaseCompare(argv[i], "--port") == 0)) && (i < argc - 1)) + { + ServerPort = atoi(argv[i + 1]); + i++; + continue; + } + if (((NoCaseCompare(argv[i], "-w") == 0) || (NoCaseCompare(argv[i], "--password") == 0)) && (i < argc - 1)) + { + Password = argv[i + 1]; + i++; + continue; + } + if (((NoCaseCompare(argv[i], "-c") == 0) || (NoCaseCompare(argv[i], "--cmd") == 0) || (NoCaseCompare(argv[i], "--command") == 0)) && (i < argc - 1)) + { + Commands.push_back(argv[i + 1]); + i++; + continue; + } + if (((NoCaseCompare(argv[i], "-f") == 0) || (NoCaseCompare(argv[i], "--file") == 0)) && (i < argc - 1)) + { + i++; + cFile f(argv[i], cFile::fmRead); + if (!f.IsOpen()) + { + fprintf(stderr, "Cannot read commands from file \"%s\", aborting.", argv[i]); + return 2; + } + AString cmd; + f.ReadRestOfFile(cmd); + Commands.push_back(cmd); + continue; + } + if ((NoCaseCompare(argv[i], "-v") == 0) || (NoCaseCompare(argv[i], "--verbose") == 0)) + { + fprintf(stderr, "Verbose output enabled\n"); + g_IsVerbose = true; + continue; + } + fprintf(stderr, "Unknown parameter: \"%s\". Aborting.", argv[i]); + return 1; + } // for i - argv[] + + if (ServerAddress.empty() || (ServerPort < 0)) + { + fprintf(stderr, "Server address or port not set. Use the --server and --port parameters to set them. Aborting."); + return 1; + } + + // Connect: + if (cSocket::WSAStartup() != 0) + { + fprintf(stderr, "Cannot initialize network stack. Aborting\n"); + return 6; + } + if (g_IsVerbose) + { + fprintf(stderr, "Connecting to \"%s:%d\"...\n", ServerAddress.c_str(), ServerPort); + } + cSocket s = cSocket::CreateSocket(cSocket::IPv4); + if (!s.ConnectIPv4(ServerAddress, (unsigned short)ServerPort)) + { + fprintf(stderr, "Cannot connect to \"%s:%d\": %s\n", ServerAddress.c_str(), ServerPort, cSocket::GetLastErrorString().c_str()); + return 3; + } + cRCONPacketizer Packetizer(s); + + // Authenticate using the provided password: + if (!Password.empty()) + { + if (g_IsVerbose) + { + fprintf(stderr, "Sending the login packet...\n"); + } + if (!Packetizer.SendPacket(cRCONPacketizer::ptLogin, Password)) + { + // Error message has already been printed, bail out + return 4; + } + } + else + { + if (g_IsVerbose) + { + fprintf(stderr, "No password provided, not sending a login packet.\n"); + } + } + + for (AStringVector::const_iterator itr = Commands.begin(), end = Commands.end(); itr != end; ++itr) + { + if (g_IsVerbose) + { + fprintf(stderr, "Sending command \"%s\"...\n", itr->c_str()); + } + if (!Packetizer.SendPacket(cRCONPacketizer::ptCommand, *itr)) + { + return 5; + } + } + + return 0; +} + + + + + +int main(int argc, char * argv[]) +{ + // This redirection function is only so that debugging the program is easier in MSVC - when RealMain exits, it's still possible to place a breakpoint + int res = RealMain(argc, argv); + return res; +} + + + + diff --git a/Tools/RCONClient/RCONClient.sln b/Tools/RCONClient/RCONClient.sln new file mode 100644 index 000000000..0a8596e43 --- /dev/null +++ b/Tools/RCONClient/RCONClient.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RCONClient", "RCONClient.vcproj", "{1A48B032-07D0-4DDD-8362-66C0FC7F7849}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1A48B032-07D0-4DDD-8362-66C0FC7F7849}.Debug|Win32.ActiveCfg = Debug|Win32 + {1A48B032-07D0-4DDD-8362-66C0FC7F7849}.Debug|Win32.Build.0 = Debug|Win32 + {1A48B032-07D0-4DDD-8362-66C0FC7F7849}.Release|Win32.ActiveCfg = Release|Win32 + {1A48B032-07D0-4DDD-8362-66C0FC7F7849}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Tools/RCONClient/RCONClient.vcproj b/Tools/RCONClient/RCONClient.vcproj new file mode 100644 index 000000000..59d0b3b74 --- /dev/null +++ b/Tools/RCONClient/RCONClient.vcproj @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/ByteBuffer.cpp b/source/ByteBuffer.cpp index 1cdd2f430..8f2b76c1f 100644 --- a/source/ByteBuffer.cpp +++ b/source/ByteBuffer.cpp @@ -13,6 +13,25 @@ +// Try to determine endianness: +#if ( \ + defined(__i386__) || defined(__alpha__) || \ + defined(__ia64) || defined(__ia64__) || \ + defined(_M_IX86) || defined(_M_IA64) || \ + defined(_M_ALPHA) || defined(__amd64) || \ + defined(__amd64__) || defined(_M_AMD64) || \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(_M_X64) || defined(__bfin__) || \ + defined(__ARMEL__) || \ + (defined(_WIN32) && defined(__ARM__) && defined(_MSC_VER)) \ +) + #define IS_LITTLE_ENDIAN +#elif defined (__ARMEB__) + #define IS_BIG_ENDIAN +#else + #error Cannot determine endianness of this platform +#endif + // If a string sent over the protocol is larger than this, a warning is emitted to the console #define MAX_STRING_SIZE (512 KiB) @@ -416,6 +435,25 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value) +bool cByteBuffer::ReadLEInt(int & a_Value) +{ + CHECK_THREAD; + CheckValid(); + NEEDBYTES(4); + ReadBuf(&a_Value, 4); + + #ifdef IS_BIG_ENDIAN + // Convert: + a_Value = ((a_Value >> 24) & 0xff) | ((a_Value >> 16) & 0xff00) | ((a_Value >> 8) & 0xff0000) | (a_Value & 0xff000000); + #endif + + return true; +} + + + + + bool cByteBuffer::WriteChar(char a_Value) { CHECK_THREAD; @@ -572,6 +610,22 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) +bool cByteBuffer::WriteLEInt(int a_Value) +{ + CHECK_THREAD; + CheckValid(); + #ifdef IS_LITTLE_ENDIAN + return WriteBuf((const char *)&a_Value, 4); + #else + int Value = ((a_Value >> 24) & 0xff) | ((a_Value >> 16) & 0xff00) | ((a_Value >> 8) & 0xff0000) | (a_Value & 0xff000000); + return WriteBuf((const char *)&Value, 4); + #endif +} + + + + + bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count) { CHECK_THREAD; diff --git a/source/ByteBuffer.h b/source/ByteBuffer.h index 21abb0377..a9dd7f5ea 100644 --- a/source/ByteBuffer.h +++ b/source/ByteBuffer.h @@ -60,6 +60,7 @@ public: bool ReadBEUTF16String16(AString & a_Value); // string length as BE short, then string as UTF-16BE bool ReadVarInt (UInt32 & a_Value); bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8 + bool ReadLEInt (int & a_Value); /// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) template bool ReadVarInt(T & a_Value) @@ -85,6 +86,7 @@ public: bool WriteBEUTF16String16(const AString & a_Value); // string length as BE short, then string as UTF-16BE bool WriteVarInt (UInt32 a_Value); bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8 + bool WriteLEInt (int a_Value); /// Reads a_Count bytes into a_Buffer; returns true if successful bool ReadBuf(void * a_Buffer, int a_Count); -- cgit v1.2.3