1
0

Merge branch 'master' into NetherFortGen

This commit is contained in:
madmaxoft 2014-03-29 23:05:17 +01:00
commit 47a427d3dc
17 changed files with 285 additions and 27 deletions

View File

@ -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 := $(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 %.cpp,../%.cpp,$(LOCAL_SRC_FILES))
LOCAL_SRC_FILES := $(patsubst %.c,../%.c,$(LOCAL_SRC_FILES)) LOCAL_SRC_FILES := $(patsubst %.c,../%.c,$(LOCAL_SRC_FILES))
@ -24,17 +24,17 @@ LOCAL_C_INCLUDES := ../src \
../src/packets \ ../src/packets \
../src/items \ ../src/items \
../src/blocks \ ../src/blocks \
../tolua++/src/lib \ ../lib/tolua++/src/lib \
../lua/src \ ../lib/lua/src \
../zlib-1.2.7 \ ../lib/zlib-1.2.7 \
../iniFile \ ../lib/iniFile \
../tolua++/include \ ../lib/tolua++/include \
../jsoncpp/include \ ../lib/jsoncpp/include \
../jsoncpp/src/lib_json \ ../lib/jsoncpp/src/lib_json \
../expat/ \ ../lib/expat/ \
../md5/ \ ../lib/md5/ \
../sqlite/ \ ../lib/sqlite/ \
../luaexpat/ \ ../lib/luaexpat/ \
.. \ .. \

View File

@ -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
}

View File

@ -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
}

View File

@ -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) void cLuaState::Push(cMonster * a_Monster)
{ {
ASSERT(IsValid()); ASSERT(IsValid());

View File

@ -38,6 +38,7 @@ extern "C"
class cWorld; class cWorld;
class cPlayer; class cPlayer;
class cEntity; class cEntity;
class cProjectileEntity;
class cMonster; class cMonster;
class cItem; class cItem;
class cItems; class cItems;
@ -183,6 +184,7 @@ public:
void Push(cPlayer * a_Player); void Push(cPlayer * a_Player);
void Push(const cPlayer * a_Player); void Push(const cPlayer * a_Player);
void Push(cEntity * a_Entity); void Push(cEntity * a_Entity);
void Push(cProjectileEntity * a_ProjectileEntity);
void Push(cMonster * a_Monster); void Push(cMonster * a_Monster);
void Push(cItem * a_Item); void Push(cItem * a_Item);
void Push(cItems * a_Items); void Push(cItems * a_Items);

View File

@ -90,6 +90,8 @@ public:
virtual bool OnPluginsLoaded (void) = 0; virtual bool OnPluginsLoaded (void) = 0;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 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 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 OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0;
virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0;
virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0;

View File

@ -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) bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{ {
cCSLock Lock(m_CriticalSection); cCSLock Lock(m_CriticalSection);

View File

@ -113,6 +113,8 @@ public:
virtual bool OnPluginsLoaded (void) override; virtual bool OnPluginsLoaded (void) override;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) 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 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 OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override;
virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override;
virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override;

View File

@ -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) bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{ {
HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_ENTITY); HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_ENTITY);

View File

@ -18,6 +18,9 @@ class cChunkDesc;
// fwd: Entities/Entity.h // fwd: Entities/Entity.h
class cEntity; class cEntity;
// fwd: Entities/ProjectileEntity.h
class cProjectileEntity;
// fwd: Mobs/Monster.h // fwd: Mobs/Monster.h
class cMonster; class cMonster;
@ -102,6 +105,8 @@ public: // tolua_export
HOOK_PLUGINS_LOADED, HOOK_PLUGINS_LOADED,
HOOK_POST_CRAFTING, HOOK_POST_CRAFTING,
HOOK_PRE_CRAFTING, HOOK_PRE_CRAFTING,
HOOK_PROJECTILE_HIT_BLOCK,
HOOK_PROJECTILE_HIT_ENTITY,
HOOK_SPAWNED_ENTITY, HOOK_SPAWNED_ENTITY,
HOOK_SPAWNED_MONSTER, HOOK_SPAWNED_MONSTER,
HOOK_SPAWNING_ENTITY, HOOK_SPAWNING_ENTITY,
@ -201,6 +206,8 @@ public: // tolua_export
bool CallHookPluginsLoaded (void); bool CallHookPluginsLoaded (void);
bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); 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 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 CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity);
bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster); bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster);
bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity); bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity);

View File

@ -1606,10 +1606,8 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket)
m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
} // for itr - Chunks[] } // for itr - Chunks[]
// Do NOT stream new chunks, the new world runs its own tick thread and may deadlock // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set
// Instead, the chunks will be streamed when the client is moved to the new world's Tick list, // Meanwhile here, we set last streamed values to bogus ones so everything is resent
// by setting state to csAuthenticated
m_State = csAuthenticated;
m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkX = 0x7fffffff;
m_LastStreamedChunkZ = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff;
m_HasSentPlayerChunk = false; m_HasSentPlayerChunk = false;

View File

@ -1489,6 +1489,7 @@ bool cPlayer::MoveToWorld(const char * a_WorldName)
// Add player to all the necessary parts of the new world // Add player to all the necessary parts of the new world
SetWorld(World); SetWorld(World);
m_ClientHandle->StreamChunks();
World->AddEntity(this); World->AddEntity(this);
World->AddPlayer(this); World->AddPlayer(this);

View File

@ -4,6 +4,7 @@
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types // Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
#include "Globals.h" #include "Globals.h"
#include "../Bindings/PluginManager.h"
#include "ProjectileEntity.h" #include "ProjectileEntity.h"
#include "../ClientHandle.h" #include "../ClientHandle.h"
#include "Player.h" #include "Player.h"
@ -66,6 +67,11 @@ protected:
eBlockFace Face; eBlockFace Face;
if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face)) if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face))
{ {
if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile))
{
return false;
}
Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff; Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff;
m_Projectile->OnHitSolidBlock(Intersection, Face); m_Projectile->OnHitSolidBlock(Intersection, Face);
return true; return true;
@ -147,7 +153,11 @@ public:
} }
// TODO: Some entities don't interact with the projectiles (pickups, falling blocks) // 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) if (LineCoeff < m_MinCoeff)
{ {

View File

@ -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) : cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ), 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), 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: // Initialize the charmap to all-invalid values:
for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++) 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: // Process the lines in the definition:
@ -104,15 +191,15 @@ void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
continue; continue;
} }
unsigned char Src = (unsigned char)CharDef[0][0]; 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; NIBBLETYPE BlockMeta = 0;
if ((NumElements >= 3) && !CharDef[2].empty()) if ((NumElements >= 3) && !CharDef[2].empty())
{ {
BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str()); BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
ASSERT((BlockMeta >= 0) && (BlockMeta <= 15)); ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
} }
ASSERT(a_CharMapOut[Src] == -1); // Any duplicates letter-wise? a_CharMapOut[Src].m_BlockMeta = BlockMeta;
a_CharMapOut[Src] = (BlockType << 4) | BlockMeta;
} // for itr - Lines[] } // 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; 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++) for (int x = 0; x < m_Size.x; x++)
{ {
int MappedValue = a_CharMap[BlockImage[x]]; const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]];
ASSERT(MappedValue != -1); // Using a letter not defined in the CharMap? ASSERT(MappedValue.m_BlockMeta != 16); // Using a letter not defined in the CharMap?
BLOCKTYPE BlockType = MappedValue >> 4; m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta);
NIBBLETYPE BlockMeta = MappedValue & 0x0f;
m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, BlockType, BlockMeta);
} }
} }
} }

View File

@ -53,8 +53,15 @@ public:
bool HasConnectorType(int a_ConnectorType) const; bool HasConnectorType(int a_ConnectorType) const;
protected: 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 */ /** 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. /** The cBlockArea that contains the block definitions for the prefab.

View File

@ -304,6 +304,7 @@ void cRoot::LoadWorlds(cIniFile & IniFile)
{ {
if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld") if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld")
{ {
IniFile.DeleteKeyComment("Worlds", 0);
IniFile.AddKeyComment("Worlds", " World=secondworld"); IniFile.AddKeyComment("Worlds", " World=secondworld");
} }
} }