diff options
-rw-r--r-- | Android/jni/Android.mk | 24 | ||||
-rw-r--r-- | MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua | 24 | ||||
-rw-r--r-- | MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua | 25 | ||||
-rw-r--r-- | src/Bindings/LuaState.cpp | 12 | ||||
-rw-r--r-- | src/Bindings/LuaState.h | 2 | ||||
-rw-r--r-- | src/Bindings/Plugin.h | 2 | ||||
-rw-r--r-- | src/Bindings/PluginLua.cpp | 40 | ||||
-rw-r--r-- | src/Bindings/PluginLua.h | 2 | ||||
-rw-r--r-- | src/Bindings/PluginManager.cpp | 42 | ||||
-rw-r--r-- | src/Bindings/PluginManager.h | 7 | ||||
-rw-r--r-- | src/Bindings/lua51.dll (renamed from src/Bindings/lua5.1.dll) | bin | 167424 -> 167424 bytes | |||
-rw-r--r-- | src/ClientHandle.cpp | 6 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 1 | ||||
-rw-r--r-- | src/Entities/ProjectileEntity.cpp | 12 | ||||
-rw-r--r-- | src/Generating/Prefab.cpp | 103 | ||||
-rw-r--r-- | src/Generating/Prefab.h | 9 | ||||
-rw-r--r-- | src/Root.cpp | 1 |
17 files changed, 285 insertions, 27 deletions
diff --git a/Android/jni/Android.mk b/Android/jni/Android.mk index 3542e588b..ce142d446 100644 --- a/Android/jni/Android.mk +++ b/Android/jni/Android.mk @@ -5,7 +5,7 @@ LOCAL_MODULE := mcserver -LOCAL_SRC_FILES := $(shell find ../CryptoPP ../lua ../jsoncpp ../zlib ../src ../tolua++ ../iniFile ../expat ../md5 ../sqlite ../luaexpat '(' -name '*.cpp' -o -name '*.c' ')') +LOCAL_SRC_FILES := $(shell find ../lib/polarssl ../lib/lua ../lib/jsoncpp ../lib/zlib ../src ../lib/tolua++ ../lib/iniFile ../lib/expat ../lib/md5 ../lib/sqlite ../lib/luaexpat '(' -name '*.cpp' -o -name '*.c' ')') LOCAL_SRC_FILES := $(filter-out %SquirrelFunctions.cpp %SquirrelBindings.cpp %cPlugin_Squirrel.cpp %cSquirrelCommandBinder.cpp %minigzip.c %lua.c %tolua.c %toluabind.c %LeakFinder.cpp %StackWalker.cpp %example.c,$(LOCAL_SRC_FILES)) LOCAL_SRC_FILES := $(patsubst %.cpp,../%.cpp,$(LOCAL_SRC_FILES)) LOCAL_SRC_FILES := $(patsubst %.c,../%.c,$(LOCAL_SRC_FILES)) @@ -24,17 +24,17 @@ LOCAL_C_INCLUDES := ../src \ ../src/packets \ ../src/items \ ../src/blocks \ - ../tolua++/src/lib \ - ../lua/src \ - ../zlib-1.2.7 \ - ../iniFile \ - ../tolua++/include \ - ../jsoncpp/include \ - ../jsoncpp/src/lib_json \ - ../expat/ \ - ../md5/ \ - ../sqlite/ \ - ../luaexpat/ \ + ../lib/tolua++/src/lib \ + ../lib/lua/src \ + ../lib/zlib-1.2.7 \ + ../lib/iniFile \ + ../lib/tolua++/include \ + ../lib/jsoncpp/include \ + ../lib/jsoncpp/src/lib_json \ + ../lib/expat/ \ + ../lib/md5/ \ + ../lib/sqlite/ \ + ../lib/luaexpat/ \ .. \ diff --git a/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua new file mode 100644 index 000000000..1588d420c --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua @@ -0,0 +1,24 @@ +return +{ + HOOK_PROJECTILE_HIT_BLOCK = + { + CalledWhen = "A projectile hits a solid block.", + DefaultFnName = "OnProjectileHitBlock", -- also used as pagename + Desc = [[ + This hook is called when a {{cProjectileEntity|projectile}} hits a solid block.. + ]], + Params = + { + { Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." }, + }, + 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 projectile flies through block.. + ]], + }, -- HOOK_PROJECTILE_HIT_BLOCK +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua new file mode 100644 index 000000000..dd949fb46 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua @@ -0,0 +1,25 @@ +return +{ + HOOK_PROJECTILE_HIT_ENTITY = + { + CalledWhen = "A projectile hits another entity.", + DefaultFnName = "OnProjectileHitEntity", -- also used as pagename + Desc = [[ + This hook is called when a {{cProjectileEntity|projectile}} hits another entity. + ]], + Params = + { + { Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." }, + { Name = "Entity", Type = "{{cEntity}}", Notes = "The entity wich was hit." }, + }, + 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 projectile flies through the entity. + ]], + }, -- HOOK_PROJECTILE_HIT_ENTITY +} + + + + + diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 47380b8a7..13eb17f7d 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -479,6 +479,18 @@ void cLuaState::Push(cEntity * a_Entity) +void cLuaState::Push(cProjectileEntity * a_ProjectileEntity) +{ + ASSERT(IsValid()); + + tolua_pushusertype(m_LuaState, a_ProjectileEntity, "cProjectileEntity"); + m_NumCurrentFunctionArgs += 1; +} + + + + + void cLuaState::Push(cMonster * a_Monster) { ASSERT(IsValid()); diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index f0047b362..b9ca2f29b 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -38,6 +38,7 @@ extern "C" class cWorld; class cPlayer; class cEntity; +class cProjectileEntity; class cMonster; class cItem; class cItems; @@ -183,6 +184,7 @@ public: void Push(cPlayer * a_Player); void Push(const cPlayer * a_Player); void Push(cEntity * a_Entity); + void Push(cProjectileEntity * a_ProjectileEntity); void Push(cMonster * a_Monster); void Push(cItem * a_Item); void Push(cItems * a_Items); diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 057fa0304..df0bd4dcc 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -90,6 +90,8 @@ public: virtual bool OnPluginsLoaded (void) = 0; virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; + virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile) = 0; + virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 4f0e13f12..7e69e0f4b 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -1108,6 +1108,46 @@ bool cPluginLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a +bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile) +{ + cCSLock Lock(m_CriticalSection); + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Projectile, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; +} + + + + + +bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity) +{ + cCSLock Lock(m_CriticalSection); + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Projectile, &a_HitEntity, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; +} + + + + + bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index f51056186..59542d23a 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -113,6 +113,8 @@ public: virtual bool OnPluginsLoaded (void) override; virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; + virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile) override; + virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 7d346c522..6a5356c0b 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -1154,6 +1154,48 @@ bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCrafti +bool cPluginManager::CallHookProjectileHitBlock(cProjectileEntity & a_Projectile) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_BLOCK); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnProjectileHitBlock(a_Projectile)) + { + return true; + } + } + return false; +} + + + + + +bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_ENTITY); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnProjectileHitEntity(a_Projectile, a_HitEntity)) + { + return true; + } + } + return false; +} + + + + + bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity) { HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_ENTITY); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 7895be959..512bc1351 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -18,6 +18,9 @@ class cChunkDesc; // fwd: Entities/Entity.h class cEntity; +// fwd: Entities/ProjectileEntity.h +class cProjectileEntity; + // fwd: Mobs/Monster.h class cMonster; @@ -102,6 +105,8 @@ public: // tolua_export HOOK_PLUGINS_LOADED, HOOK_POST_CRAFTING, HOOK_PRE_CRAFTING, + HOOK_PROJECTILE_HIT_BLOCK, + HOOK_PROJECTILE_HIT_ENTITY, HOOK_SPAWNED_ENTITY, HOOK_SPAWNED_MONSTER, HOOK_SPAWNING_ENTITY, @@ -201,6 +206,8 @@ public: // tolua_export bool CallHookPluginsLoaded (void); bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); + bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile); + bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity); bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity); bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster); bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity); diff --git a/src/Bindings/lua5.1.dll b/src/Bindings/lua51.dll Binary files differindex 515cf8b30..515cf8b30 100644 --- a/src/Bindings/lua5.1.dll +++ b/src/Bindings/lua51.dll diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 46c10ae82..eb05ebdb7 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1606,10 +1606,8 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket) m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - Chunks[] - // Do NOT stream new chunks, the new world runs its own tick thread and may deadlock - // Instead, the chunks will be streamed when the client is moved to the new world's Tick list, - // by setting state to csAuthenticated - m_State = csAuthenticated; + // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set + // Meanwhile here, we set last streamed values to bogus ones so everything is resent m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff; m_HasSentPlayerChunk = false; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 863aaa799..646aad50f 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1489,6 +1489,7 @@ bool cPlayer::MoveToWorld(const char * a_WorldName) // Add player to all the necessary parts of the new world SetWorld(World); + m_ClientHandle->StreamChunks(); World->AddEntity(this); World->AddPlayer(this); diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index f4ab825f2..a9735a53c 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -4,6 +4,7 @@ // Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types #include "Globals.h" +#include "../Bindings/PluginManager.h" #include "ProjectileEntity.h" #include "../ClientHandle.h" #include "Player.h" @@ -66,6 +67,11 @@ protected: eBlockFace Face; if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face)) { + if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile)) + { + return false; + } + Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff; m_Projectile->OnHitSolidBlock(Intersection, Face); return true; @@ -147,7 +153,11 @@ public: } // TODO: Some entities don't interact with the projectiles (pickups, falling blocks) - // TODO: Allow plugins to interfere about which entities can be hit + if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity)) + { + // A plugin disagreed. + return false; + } if (LineCoeff < m_MinCoeff) { diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp index 1af1faec1..a9e0a839d 100644 --- a/src/Generating/Prefab.cpp +++ b/src/Generating/Prefab.cpp @@ -15,6 +15,92 @@ uses a prefabricate in a cBlockArea for drawing itself. +#ifdef SELF_TEST + +// Create one static prefab to test the parser: +static const cPrefab::sDef g_TestPrefabDef = +{ + // Size: + 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7 + + // Block definitions: + ".: 0: 0\n" /* 0 */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */, + + // Block data: + // Level 1 + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + + // Level 2 + "aa...aa" + "a.....a" + "......." + "......." + "......." + "a.....a" + "aa...aa" + + // Level 3 + "aa...aa" + "a.....a" + "......." + "......." + "......." + "a.....a" + "aa...aa" + + // Level 4 + "aa...aa" + "a.....a" + "......." + "......." + "......." + "a.....a" + "aa...aa" + + // Level 5 + "aabbbaa" + "a.....a" + "b.....b" + "b.....b" + "b.....b" + "a.....a" + "aabbbaa" + + // Level 6 + "aaaaaaa" + "a.....a" + "a.....a" + "a.....a" + "a.....a" + "a.....a" + "aaaaaaa", + + // Connections: + "0: 0, 3, 2: 4\n" + "0: 2, 3, 0: 2\n", + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotations */ + + // Merge strategy: + cBlockArea::msImprint +}; + +static cPrefab g_TestPrefab(g_TestPrefabDef); +#endif + + + + + cPrefab::cPrefab(const cPrefab::sDef & a_Def) : m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ), m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1), @@ -89,7 +175,8 @@ void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef) // Initialize the charmap to all-invalid values: for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++) { - a_CharMapOut[i] = -1; + a_CharMapOut[i].m_BlockType = 0; + a_CharMapOut[i].m_BlockMeta = 16; // Mark unassigned entries with a meta that is impossible otherwise } // Process the lines in the definition: @@ -104,15 +191,15 @@ void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef) continue; } unsigned char Src = (unsigned char)CharDef[0][0]; - BLOCKTYPE BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str()); + ASSERT(a_CharMapOut[Src].m_BlockMeta == 16); // This letter has not been assigned yet? + a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str()); NIBBLETYPE BlockMeta = 0; if ((NumElements >= 3) && !CharDef[2].empty()) { BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str()); ASSERT((BlockMeta >= 0) && (BlockMeta <= 15)); } - ASSERT(a_CharMapOut[Src] == -1); // Any duplicates letter-wise? - a_CharMapOut[Src] = (BlockType << 4) | BlockMeta; + a_CharMapOut[Src].m_BlockMeta = BlockMeta; } // for itr - Lines[] } @@ -130,11 +217,9 @@ void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockIma const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x; for (int x = 0; x < m_Size.x; x++) { - int MappedValue = a_CharMap[BlockImage[x]]; - ASSERT(MappedValue != -1); // Using a letter not defined in the CharMap? - BLOCKTYPE BlockType = MappedValue >> 4; - NIBBLETYPE BlockMeta = MappedValue & 0x0f; - m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, BlockType, BlockMeta); + const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]]; + ASSERT(MappedValue.m_BlockMeta != 16); // Using a letter not defined in the CharMap? + m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta); } } } diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h index 0b254c03b..04c4f09da 100644 --- a/src/Generating/Prefab.h +++ b/src/Generating/Prefab.h @@ -53,8 +53,15 @@ public: bool HasConnectorType(int a_ConnectorType) const; protected: + /** Packs complete definition of a single block, for per-letter assignment. */ + struct sBlockTypeDef + { + BLOCKTYPE m_BlockType; + NIBBLETYPE m_BlockMeta; + }; + /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */ - typedef int CharMap[256]; + typedef sBlockTypeDef CharMap[256]; /** The cBlockArea that contains the block definitions for the prefab. diff --git a/src/Root.cpp b/src/Root.cpp index 3555afb45..ba4398b35 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -304,6 +304,7 @@ void cRoot::LoadWorlds(cIniFile & IniFile) { if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld") { + IniFile.DeleteKeyComment("Worlds", 0); IniFile.AddKeyComment("Worlds", " World=secondworld"); } } |