summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/PluginLua.cpp249
-rw-r--r--src/BiomeDef.cpp7
-rw-r--r--src/BlockID.cpp29
-rw-r--r--src/Blocks/BlockButton.h6
-rw-r--r--src/Entities/Player.cpp6
-rw-r--r--src/OSSupport/File.cpp102
-rw-r--r--src/OSSupport/File.h16
-rw-r--r--src/Root.cpp28
-rw-r--r--src/Root.h3
-rw-r--r--src/Vector3.h9
-rw-r--r--src/main.cpp233
11 files changed, 638 insertions, 50 deletions
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 0a2a8411d..9bbac92b0 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -208,6 +208,10 @@ void cPluginLua::OnDisable(void)
void cPluginLua::Tick(float a_Dt)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return;
+ }
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TICK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
@@ -222,6 +226,10 @@ void cPluginLua::Tick(float a_Dt)
bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -242,6 +250,10 @@ bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int
bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_TO_PICKUPS];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -262,6 +274,10 @@ bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_Bl
bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -282,6 +298,10 @@ bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_AVAILABLE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -302,6 +322,10 @@ bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -322,6 +346,10 @@ bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ,
bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -342,6 +370,10 @@ bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ,
bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -362,6 +394,10 @@ bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -382,6 +418,10 @@ bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_COLLECTING_PICKUP];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -402,6 +442,10 @@ bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CRAFTING_NO_RECIPE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -422,6 +466,10 @@ bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid,
bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -442,6 +490,10 @@ bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason
bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_ADD_EFFECT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -462,6 +514,10 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E
bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -482,6 +538,10 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp
bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -519,6 +579,10 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can
bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -556,6 +620,10 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool &
bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Username)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HANDSHAKE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -576,8 +644,11 @@ bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Usernam
bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
-
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PULLING_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
@@ -597,6 +668,10 @@ bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper,
bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PUSHING_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -617,6 +692,10 @@ bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper,
bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -637,6 +716,10 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInf
bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_LOGIN];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -657,6 +740,10 @@ bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const
bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_ANIMATION];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -677,6 +764,10 @@ bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation)
bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BREAKING_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -697,6 +788,10 @@ bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_B
bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BROKEN_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -717,6 +812,10 @@ bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_Blo
bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_DESTROYED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -737,6 +836,10 @@ bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player)
bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_EATING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -757,6 +860,10 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FOOD_LEVEL_CHANGE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -777,6 +884,10 @@ bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -797,6 +908,10 @@ bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -817,6 +932,10 @@ bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward)
bool cPluginLua::OnPlayerJoined(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_JOINED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -837,6 +956,10 @@ bool cPluginLua::OnPlayerJoined(cPlayer & a_Player)
bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_LEFT_CLICK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -857,6 +980,10 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block
bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_MOVING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -877,6 +1004,10 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPositi
bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_TELEPORT];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -897,6 +1028,10 @@ bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosi
bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -922,6 +1057,10 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_Blo
bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -947,6 +1086,10 @@ bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_Bl
bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -967,6 +1110,10 @@ bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_Bloc
bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -987,6 +1134,10 @@ bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Ent
bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SHOOTING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1007,6 +1158,10 @@ bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SPAWNED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1027,6 +1182,10 @@ bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_TOSSING_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1047,6 +1206,10 @@ bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player)
bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1067,6 +1230,10 @@ bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_Block
bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1087,6 +1254,10 @@ bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY
bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1107,6 +1278,10 @@ bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_Bloc
bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_ITEM];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1127,6 +1302,10 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block
bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1147,6 +1326,10 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha
bool cPluginLua::OnPluginsLoaded(void)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1165,6 +1348,10 @@ bool cPluginLua::OnPluginsLoaded(void)
bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_POST_CRAFTING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1185,6 +1372,10 @@ bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCra
bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PRE_CRAFTING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1205,6 +1396,10 @@ bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraf
bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1225,6 +1420,10 @@ bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_Bl
bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1245,6 +1444,10 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity
bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1265,6 +1468,10 @@ bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Server
bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1285,6 +1492,10 @@ bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_MONSTER];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1305,6 +1516,10 @@ bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_ENTITY];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1325,6 +1540,10 @@ bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_MONSTER];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1345,6 +1564,10 @@ bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TAKE_DAMAGE];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1370,6 +1593,10 @@ bool cPluginLua::OnUpdatedSign(
)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATED_SIGN];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1395,6 +1622,10 @@ bool cPluginLua::OnUpdatingSign(
)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1415,6 +1646,10 @@ bool cPluginLua::OnUpdatingSign(
bool cPluginLua::OnWeatherChanged(cWorld & a_World)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1435,6 +1670,10 @@ bool cPluginLua::OnWeatherChanged(cWorld & a_World)
bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
@@ -1455,6 +1694,10 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
bool cPluginLua::OnWorldStarted(cWorld & a_World)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_STARTED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
@@ -1470,6 +1713,10 @@ bool cPluginLua::OnWorldStarted(cWorld & a_World)
bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
{
cCSLock Lock(m_CriticalSection);
+ if (!m_LuaState.IsValid())
+ {
+ return false;
+ }
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp
index 3e34ebdbe..a2a06f10c 100644
--- a/src/BiomeDef.cpp
+++ b/src/BiomeDef.cpp
@@ -338,6 +338,13 @@ int GetSnowStartHeight(EMCSBiome a_Biome)
// These biomes don't actualy have any downfall.
return 1000;
}
+
+ case biNether:
+ case biEnd:
+ {
+ // These shouldn't get any snow at all.
+ return 9999;
+ }
default:
{
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index 06f4232d3..7f0db3cfc 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -26,8 +26,18 @@ class cBlockIDMap
typedef std::map<AString, std::pair<short, short>, Comparator> ItemMap;
public:
+ static bool m_bHasRunInit;
+
cBlockIDMap(void)
{
+ // Dont load items.ini on construct, this will search the wrong path when running as a service.
+ }
+
+
+ void init()
+ {
+ m_bHasRunInit = true;
+
cIniFile Ini;
if (!Ini.ReadFile("items.ini"))
{
@@ -174,7 +184,7 @@ protected:
-
+bool cBlockIDMap::m_bHasRunInit = false;
static cBlockIDMap gsBlockIDMap;
@@ -209,6 +219,10 @@ int BlockStringToType(const AString & a_BlockTypeString)
return res;
}
+ if (!gsBlockIDMap.m_bHasRunInit)
+ {
+ gsBlockIDMap.init();
+ }
return gsBlockIDMap.Resolve(TrimString(a_BlockTypeString));
}
@@ -222,6 +236,11 @@ bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item)
{
ItemName = ItemName.substr(10);
}
+
+ if (!gsBlockIDMap.m_bHasRunInit)
+ {
+ gsBlockIDMap.init();
+ }
return gsBlockIDMap.ResolveItem(ItemName, a_Item);
}
@@ -231,6 +250,10 @@ bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item)
AString ItemToString(const cItem & a_Item)
{
+ if (!gsBlockIDMap.m_bHasRunInit)
+ {
+ gsBlockIDMap.init();
+ }
return gsBlockIDMap.Desolve(a_Item.m_ItemType, a_Item.m_ItemDamage);
}
@@ -240,6 +263,10 @@ AString ItemToString(const cItem & a_Item)
AString ItemTypeToString(short a_ItemType)
{
+ if (!gsBlockIDMap.m_bHasRunInit)
+ {
+ gsBlockIDMap.init();
+ }
return gsBlockIDMap.Desolve(a_ItemType, -1);
}
diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h
index 8e4f04740..d24c7d952 100644
--- a/src/Blocks/BlockButton.h
+++ b/src/Blocks/BlockButton.h
@@ -61,14 +61,16 @@ public:
{
switch (a_BlockFace)
{
+ case BLOCK_FACE_YP: return 0x5;
case BLOCK_FACE_ZM: return 0x4;
case BLOCK_FACE_ZP: return 0x3;
case BLOCK_FACE_XM: return 0x2;
case BLOCK_FACE_XP: return 0x1;
+ case BLOCK_FACE_YM: return 0x0;
default:
{
ASSERT(!"Unhandled block face!");
- return 0x0; // No idea, give a special meta (button in centre of block)
+ return 0x0;
}
}
}
@@ -77,10 +79,12 @@ public:
{
switch (a_Meta & 0x7)
{
+ case 0x0: return BLOCK_FACE_YM;
case 0x1: return BLOCK_FACE_XP;
case 0x2: return BLOCK_FACE_XM;
case 0x3: return BLOCK_FACE_ZP;
case 0x4: return BLOCK_FACE_ZM;
+ case 0x5: return BLOCK_FACE_YP;
default:
{
ASSERT(!"Unhandled block meta!");
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index c89e7b87c..2549a8481 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1603,6 +1603,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
m_ClientHandle->SendRespawn(a_World->GetDimension());
}
+ // Broadcast for other people that the player is gone.
+ GetWorld()->BroadcastDestroyEntity(*this);
+
// Remove player from the old world
SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal
GetWorld()->RemovePlayer(this, false);
@@ -1619,6 +1622,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
{
m_ClientHandle->SendWeather(a_World->GetWeather());
}
+
+ // Broadcast the player into the new world.
+ a_World->BroadcastSpawnEntity(*this);
return true;
}
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 8957dfaef..43105b230 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -453,6 +453,108 @@ AString cFile::ReadWholeFile(const AString & a_FileName)
+AString cFile::ChangeFileExt(const AString & a_FileName, const AString & a_NewExt)
+{
+ auto res = a_FileName;
+
+ // If the path separator is the last character of the string, return the string unmodified (refers to a folder):
+ #if defined(_MSC_VER)
+ // Find either path separator - MSVC CRT accepts slashes as separators, too
+ auto LastPathSep = res.find_last_of("/\\");
+ #elif defined(_WIN32)
+ // Windows with different CRTs support only the backslash separator
+ auto LastPathSep = res.rfind('\\');
+ #else
+ // Linux supports only the slash separator
+ auto LastPathSep = res.rfind('/');
+ #endif
+ if ((LastPathSep != AString::npos) && (LastPathSep + 1 == res.size()))
+ {
+ return res;
+ }
+
+ // Append or replace the extension:
+ auto DotPos = res.rfind('.');
+ if (
+ (DotPos == AString::npos) || // No dot found
+ ((LastPathSep != AString::npos) && (LastPathSep > DotPos)) // Last dot is before the last path separator (-> in folder name)
+ )
+ {
+ // No extension, just append the new one:
+ if (!a_NewExt.empty() && (a_NewExt[0] != '.'))
+ {
+ // a_NewExt doesn't start with a dot, insert one:
+ res.push_back('.');
+ }
+ res.append(a_NewExt);
+ }
+ else
+ {
+ // Replace existing extension:
+ if (!a_NewExt.empty() && (a_NewExt[0] != '.'))
+ {
+ // a_NewExt doesn't start with a dot, keep the current one:
+ res.erase(DotPos + 1, AString::npos);
+ }
+ else
+ {
+ res.erase(DotPos, AString::npos);
+ }
+ res.append(a_NewExt);
+ }
+ return res;
+}
+
+
+
+
+
+unsigned cFile::GetLastModificationTime(const AString & a_FileName)
+{
+ struct stat st;
+ if (stat(a_FileName.c_str(), &st) < 0)
+ {
+ return 0;
+ }
+ #ifdef _WIN32
+ // Windows returns times in local time already
+ return static_cast<unsigned>(st.st_mtime);
+ #else
+ // Linux returns UTC time, convert to local timezone:
+ return static_cast<unsigned>(mktime(localtime(&st.st_mtime)));
+ #endif
+}
+
+
+
+
+
+AString cFile::GetPathSeparator(void)
+{
+ #ifdef _WIN32
+ return "\\";
+ #else
+ return "/";
+ #endif
+}
+
+
+
+
+
+AString cFile::GetExecutableExt(void)
+{
+ #ifdef _WIN32
+ return ".exe";
+ #else
+ return "";
+ #endif
+}
+
+
+
+
+
int cFile::Printf(const char * a_Fmt, ...)
{
AString buf;
diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h
index ac6d1ab21..6ee080480 100644
--- a/src/OSSupport/File.h
+++ b/src/OSSupport/File.h
@@ -127,6 +127,22 @@ public:
/** Returns the entire contents of the specified file as a string. Returns empty string on error. */
static AString ReadWholeFile(const AString & a_FileName);
+ /** Returns a_FileName with its extension changed to a_NewExt.
+ a_FileName may contain path specification. */
+ static AString ChangeFileExt(const AString & a_FileName, const AString & a_NewExt);
+
+ /** Returns the last modification time (in current timezone) of the specified file.
+ The value returned is in the same units as the value returned by time() function.
+ If the file is not found / accessible, zero is returned. */
+ static unsigned GetLastModificationTime(const AString & a_FileName);
+
+ /** Returns the path separator used by the current platform.
+ Note that the platform / CRT may support additional path separators (such as slashes on Windows), these don't get reported. */
+ static AString GetPathSeparator(void);
+
+ /** Returns the customary executable extension used by the current platform. */
+ static AString GetExecutableExt(void);
+
// tolua_end
/** Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). */
diff --git a/src/Root.cpp b/src/Root.cpp
index 27d87c717..690bd7357 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -33,7 +33,8 @@
-cRoot* cRoot::s_Root = nullptr;
+cRoot * cRoot::s_Root = nullptr;
+bool cRoot::m_ShouldStop = false;
@@ -48,7 +49,6 @@ cRoot::cRoot(void) :
m_WebAdmin(nullptr),
m_PluginManager(nullptr),
m_MojangAPI(nullptr),
- m_bStop(false),
m_bRestart(false)
{
s_Root = this;
@@ -71,7 +71,7 @@ void cRoot::InputThread(cRoot & a_Params)
{
cLogCommandOutputCallback Output;
- while (!a_Params.m_bStop && !a_Params.m_bRestart && !m_TerminateEventRaised && std::cin.good())
+ while (!cRoot::m_ShouldStop && !a_Params.m_bRestart && !m_TerminateEventRaised && std::cin.good())
{
AString Command;
std::getline(std::cin, Command);
@@ -83,8 +83,12 @@ void cRoot::InputThread(cRoot & a_Params)
if (m_TerminateEventRaised || !std::cin.good())
{
- // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running; stop the server:
- a_Params.m_bStop = true;
+ // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running
+ // Stop the server:
+ if (!m_RunAsService) // Dont kill if running as a service
+ {
+ a_Params.m_ShouldStop = true;
+ }
}
}
@@ -114,8 +118,8 @@ void cRoot::Start(void)
cDeadlockDetect dd;
- m_bStop = false;
- while (!m_bStop)
+ m_ShouldStop = false;
+ while (!m_ShouldStop)
{
auto BeginTime = std::chrono::steady_clock::now();
m_bRestart = false;
@@ -203,14 +207,14 @@ void cRoot::Start(void)
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
#endif
- while (!m_bStop && !m_bRestart && !m_TerminateEventRaised) // These are modified by external threads
+ while (!m_ShouldStop && !m_bRestart && !m_TerminateEventRaised) // These are modified by external threads
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
if (m_TerminateEventRaised)
{
- m_bStop = true;
+ m_ShouldStop = true;
}
// Stop the server:
@@ -221,7 +225,7 @@ void cRoot::Start(void)
} // if (m_Server->Start())
else
{
- m_bStop = true;
+ m_ShouldStop = true;
}
delete m_MojangAPI; m_MojangAPI = nullptr;
@@ -456,7 +460,7 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCall
// Some commands are built-in:
if (a_Cmd == "stop")
{
- m_bStop = true;
+ m_ShouldStop = true;
}
else if (a_Cmd == "restart")
{
@@ -488,7 +492,7 @@ void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback
// cRoot handles stopping and restarting due to our access to controlling variables
if (a_Cmd == "stop")
{
- m_bStop = true;
+ m_ShouldStop = true;
return;
}
else if (a_Cmd == "restart")
diff --git a/src/Root.h b/src/Root.h
index fdaf444bd..2f9d1eb2c 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -46,6 +46,8 @@ public:
// tolua_end
static bool m_TerminateEventRaised;
+ static bool m_RunAsService;
+ static bool m_ShouldStop;
cRoot(void);
@@ -197,7 +199,6 @@ private:
cHTTPServer m_HTTPServer;
- bool m_bStop;
bool m_bRestart;
void LoadGlobalSettings();
diff --git a/src/Vector3.h b/src/Vector3.h
index 1f3f6b955..36f277ba4 100644
--- a/src/Vector3.h
+++ b/src/Vector3.h
@@ -244,6 +244,15 @@ public:
);
}
+ inline Vector3<T> operator / (const Vector3<T> & a_Rhs)
+ {
+ return Vector3<T>(
+ x / a_Rhs.x,
+ y / a_Rhs.y,
+ z / a_Rhs.z
+ );
+ }
+
inline Vector3<T> operator * (T a_v) const
{
return Vector3<T>(
diff --git a/src/main.cpp b/src/main.cpp
index 428e89e93..2e7e107f7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -29,11 +29,24 @@ bool g_ShouldLogCommIn;
/** If set to true, the protocols will log each player's outgoing (S->C) communication to a per-connection logfile */
bool g_ShouldLogCommOut;
+/** If set to true, binary will attempt to run as a service on Windows */
+bool cRoot::m_RunAsService = false;
-/// If defined, a thorough leak finder will be used (debug MSVC only); leaks will be output to the Output window
+
+#if defined(_WIN32)
+ SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
+ HANDLE g_ServiceThread = INVALID_HANDLE_VALUE;
+ #define SERVICE_NAME "MCServerService"
+#endif
+
+
+
+
+
+/** If defined, a thorough leak finder will be used (debug MSVC only); leaks will be output to the Output window */
// _X 2014_02_20: Disabled for canon repo, it makes the debug version too slow in MSVC2013
// and we haven't had a memory leak for over a year anyway.
// #define ENABLE_LEAK_FINDER
@@ -160,6 +173,7 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except
+
#ifdef _WIN32
// Handle CTRL events in windows, including console window close
BOOL CtrlHandler(DWORD fdwCtrlType)
@@ -181,6 +195,167 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
////////////////////////////////////////////////////////////////////////////////
+// universalMain - Main startup logic for both standard running and as a service
+
+void universalMain()
+{
+ #ifdef _WIN32
+ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE))
+ {
+ LOGERROR("Could not install the Windows CTRL handler!");
+ }
+ #endif
+
+ // Initialize logging subsystem:
+ cLogger::InitiateMultithreading();
+
+ // Initialize LibEvent:
+ cNetworkSingleton::Get();
+
+ #if !defined(ANDROID_NDK)
+ try
+ #endif
+ {
+ cRoot Root;
+ Root.Start();
+ }
+ #if !defined(ANDROID_NDK)
+ catch (std::exception & e)
+ {
+ LOGERROR("Standard exception: %s", e.what());
+ }
+ catch (...)
+ {
+ LOGERROR("Unknown exception!");
+ }
+ #endif
+
+ g_ServerTerminated = true;
+
+ // Shutdown all of LibEvent:
+ cNetworkSingleton::Get().Terminate();
+}
+
+
+
+
+#if defined(_WIN32)
+////////////////////////////////////////////////////////////////////////////////
+// serviceWorkerThread: Keep the service alive
+
+DWORD WINAPI serviceWorkerThread(LPVOID lpParam)
+{
+ UNREFERENCED_PARAMETER(lpParam);
+
+ // Do the normal startup
+ universalMain();
+
+ return ERROR_SUCCESS;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// serviceSetState: Set the internal status of the service
+
+void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode)
+{
+ SERVICE_STATUS serviceStatus;
+ ZeroMemory(&serviceStatus, sizeof(SERVICE_STATUS));
+ serviceStatus.dwCheckPoint = 0;
+ serviceStatus.dwControlsAccepted = acceptedControls;
+ serviceStatus.dwCurrentState = newState;
+ serviceStatus.dwServiceSpecificExitCode = 0;
+ serviceStatus.dwServiceType = SERVICE_WIN32;
+ serviceStatus.dwWaitHint = 0;
+ serviceStatus.dwWin32ExitCode = exitCode;
+
+ if (SetServiceStatus(g_StatusHandle, &serviceStatus) == FALSE)
+ {
+ LOGERROR("SetServiceStatus() failed\n");
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// serviceCtrlHandler: Handle stop events from the Service Control Manager
+
+void WINAPI serviceCtrlHandler(DWORD CtrlCode)
+{
+ switch (CtrlCode)
+ {
+ case SERVICE_CONTROL_STOP:
+ {
+ cRoot::m_ShouldStop = true;
+ serviceSetState(0, SERVICE_STOP_PENDING, 0);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// serviceMain: Startup logic for running as a service
+
+void WINAPI serviceMain(DWORD argc, TCHAR *argv[])
+{
+ #if defined(_DEBUG) && defined(DEBUG_SERVICE_STARTUP)
+ Sleep(10000);
+ #endif
+
+ char applicationFilename[MAX_PATH];
+ char applicationDirectory[MAX_PATH];
+
+ GetModuleFileName(NULL, applicationFilename, sizeof(applicationFilename)); // This binary's file path.
+
+ // Strip off the filename, keep only the path:
+ strncpy_s(applicationDirectory, sizeof(applicationDirectory), applicationFilename, (strrchr(applicationFilename, '\\') - applicationFilename));
+ applicationDirectory[strlen(applicationDirectory)] = '\0'; // Make sure new path is null terminated
+
+ // Services are run by the SCM, and inherit its working directory - usually System32.
+ // Set the working directory to the same location as the binary.
+ SetCurrentDirectory(applicationDirectory);
+
+ g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, serviceCtrlHandler);
+
+ if (g_StatusHandle == NULL)
+ {
+ OutputDebugStringA("RegisterServiceCtrlHandler() failed\n");
+ serviceSetState(0, SERVICE_STOPPED, GetLastError());
+ return;
+ }
+
+ serviceSetState(SERVICE_ACCEPT_STOP, SERVICE_RUNNING, 0);
+
+ g_ServiceThread = CreateThread(NULL, 0, serviceWorkerThread, NULL, 0, NULL);
+ if (g_ServiceThread == NULL)
+ {
+ OutputDebugStringA("CreateThread() failed\n");
+ serviceSetState(0, SERVICE_STOPPED, GetLastError());
+ return;
+ }
+ WaitForSingleObject(g_ServiceThread, INFINITE); // Wait here for a stop signal.
+
+ CloseHandle(g_ServiceThread);
+
+ serviceSetState(0, SERVICE_STOPPED, 0);
+}
+#endif
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
// main:
int main( int argc, char **argv)
@@ -219,13 +394,6 @@ int main( int argc, char **argv)
#endif // _WIN32 && !_WIN64
// End of dump-file magic
- #ifdef _WIN32
- if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE))
- {
- LOGERROR("Could not install the Windows CTRL handler!");
- }
- #endif
-
#if defined(_DEBUG) && defined(_MSC_VER)
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
@@ -280,42 +448,39 @@ int main( int argc, char **argv)
{
setvbuf(stdout, nullptr, _IONBF, 0);
}
+ else if (NoCaseCompare(Arg, "/service") == 0)
+ {
+ cRoot::m_RunAsService = true;
+ }
} // for i - argv[]
-
- // Initialize logging subsystem:
- cLogger::InitiateMultithreading();
-
- // Initialize LibEvent:
- cNetworkSingleton::Get();
-
- #if !defined(ANDROID_NDK)
- try
- #endif
- {
- cRoot Root;
- Root.Start();
- }
- #if !defined(ANDROID_NDK)
- catch (std::exception & e)
+
+ #if defined(_WIN32)
+ // Attempt to run as a service
+ if (cRoot::m_RunAsService)
{
- LOGERROR("Standard exception: %s", e.what());
+ SERVICE_TABLE_ENTRY ServiceTable[] =
+ {
+ { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain },
+ { NULL, NULL }
+ };
+
+ if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
+ {
+ LOGERROR("Attempted, but failed, service startup.");
+ return GetLastError();
+ }
}
- catch (...)
+ else
+ #endif
{
- LOGERROR("Unknown exception!");
+ // Not running as a service, do normal startup
+ universalMain();
}
- #endif
-
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
DeinitLeakFinder();
#endif
- g_ServerTerminated = true;
-
- // Shutdown all of LibEvent:
- cNetworkSingleton::Get().Terminate();
-
return EXIT_SUCCESS;
}