diff options
-rw-r--r-- | src/Blocks/BlockRail.h | 34 | ||||
-rw-r--r-- | src/Entities/Entity.cpp | 25 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 23 | ||||
-rw-r--r-- | src/Root.cpp | 34 | ||||
-rw-r--r-- | src/Simulator/RedstoneSimulator.cpp | 175 | ||||
-rw-r--r-- | src/Simulator/RedstoneSimulator.h | 6 | ||||
-rw-r--r-- | src/main.cpp | 64 |
7 files changed, 314 insertions, 47 deletions
diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index 24a101652..55cadfa48 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -43,6 +43,40 @@ public: } + virtual void OnPlaced(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + { + super::OnPlaced(a_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); + + // Alert diagonal rails + OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY + 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY + 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ + 1); + OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ - 1); + + OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY - 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY - 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ + 1); + OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ - 1); + } + + + virtual void OnDestroyed(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + { + super::OnDestroyed(a_World, a_BlockX, a_BlockY, a_BlockZ); + + // Alert diagonal rails + OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY + 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY + 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ + 1); + OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ - 1); + + OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY - 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY - 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ + 1); + OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ - 1); + } + + virtual void OnNeighborChanged(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override { NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 8fcdcc82f..8a74c9da4 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -13,6 +13,7 @@ #include "../Bindings/PluginManager.h" #include "../Tracer.h" #include "Minecart.h" +#include "Player.h" @@ -239,10 +240,14 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R TDI.Attacker = a_Attacker; TDI.RawDamage = a_RawDamage; TDI.FinalDamage = a_FinalDamage; - Vector3d Heading; - Heading.x = sin(GetRotation()); - Heading.y = 0.4; // TODO: adjust the amount of "up" knockback when testing - Heading.z = cos(GetRotation()); + + Vector3d Heading(0, 0, 0); + if (a_Attacker != NULL) + { + Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 10 : 8); + } + Heading.y = 2; + TDI.Knockback = Heading * a_KnockbackAmount; DoTakeDamage(TDI); } @@ -297,6 +302,16 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) return; } + if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) + { + // IsOnGround() only is false if the player is moving downwards + if (!((cPlayer *)a_TDI.Attacker)->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) + { + a_TDI.FinalDamage += 2; + m_World->BroadcastEntityAnimation(*this, 4); // Critical hit + } + } + m_Health -= (short)a_TDI.FinalDamage; // TODO: Apply damage to armor @@ -306,6 +321,8 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_Health = 0; } + AddSpeed(a_TDI.Knockback * 2); + m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT); if (m_Health <= 0) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index b923a094e..0fa8254ce 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -252,6 +252,11 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) m_World->SendPlayerList(this); m_LastPlayerListTime = t1.GetNowTime(); } + + if (IsFlying()) + { + m_LastGroundHeight = (float)GetPosY(); + } } @@ -452,10 +457,16 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) if (m_LastJumpHeight > m_LastGroundHeight) Damage++; m_LastJumpHeight = (float)GetPosY(); - if ((Damage > 0) && (!IsGameModeCreative())) + if (Damage > 0) { - TakeDamage(dtFalling, NULL, Damage, Damage, 0); - } + if (!IsGameModeCreative()) + { + TakeDamage(dtFalling, NULL, Damage, Damage, 0); + } + + // Mojang uses floor() to get X and Z positions, instead of just casting it to an (int) + GetWorld()->BroadcastSoundParticleEffect(2006, (int)floor(GetPosX()), (int)GetPosY() - 1, (int)floor(GetPosZ()), Damage /* Used as particle effect speed modifier */); + } m_LastGroundHeight = (float)GetPosY(); } @@ -979,6 +990,12 @@ void cPlayer::SetGameMode(eGameMode a_GameMode) m_GameMode = a_GameMode; m_ClientHandle->SendGameMode(a_GameMode); + + if (!IsGameModeCreative()) + { + SetFlying(false); + SetCanFly(false); + } } diff --git a/src/Root.cpp b/src/Root.cpp index fffd8fb47..798f965be 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -22,6 +22,7 @@ #include "inifile/iniFile.h" #ifdef _WIN32 + #include "conio.h" #include <psapi.h> #elif defined(__linux__) #include <fstream> @@ -29,6 +30,8 @@ #include <mach/mach.h> #endif +extern bool g_TERMINATE_EVENT_RAISED; + @@ -76,7 +79,7 @@ void cRoot::InputThread(void * a_Params) cLogCommandOutputCallback Output; - while (!(self.m_bStop || self.m_bRestart) && std::cin.good()) + while (!self.m_bStop && !self.m_bRestart && !g_TERMINATE_EVENT_RAISED && std::cin.good()) { AString Command; std::getline(std::cin, Command); @@ -85,10 +88,10 @@ void cRoot::InputThread(void * a_Params) self.ExecuteConsoleCommand(TrimString(Command), Output); } } - - if (!(self.m_bStop || self.m_bRestart)) + + if (g_TERMINATE_EVENT_RAISED || !std::cin.good()) { - // We have come here because the std::cin has received an EOF and the server is still running; stop the server: + // 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: self.m_bStop = true; } } @@ -99,6 +102,12 @@ void cRoot::InputThread(void * a_Params) void cRoot::Start(void) { + #ifdef _WIN32 + HWND hwnd = GetConsoleWindow(); + HMENU hmenu = GetSystemMenu(hwnd, FALSE); + EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling + #endif + cDeadlockDetect dd; delete m_Log; m_Log = new cMCLogger(); @@ -192,12 +201,20 @@ void cRoot::Start(void) finishmseconds -= mseconds; LOG("Startup complete, took %i ms!", finishmseconds); + #ifdef _WIN32 + EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button + #endif - while (!m_bStop && !m_bRestart) // These are modified by external threads + while (!m_bStop && !m_bRestart && !g_TERMINATE_EVENT_RAISED) // These are modified by external threads { cSleep::MilliSleep(1000); } + if (g_TERMINATE_EVENT_RAISED) + { + m_bStop = true; + } + #if !defined(ANDROID_NDK) delete m_InputThread; m_InputThread = NULL; #endif @@ -222,7 +239,7 @@ void cRoot::Start(void) delete m_FurnaceRecipe; m_FurnaceRecipe = NULL; delete m_CraftingRecipes; m_CraftingRecipes = NULL; LOGD("Forgetting groups..."); - delete m_GroupManager; m_GroupManager = 0; + delete m_GroupManager; m_GroupManager = NULL; LOGD("Unloading worlds..."); UnloadWorlds(); @@ -233,12 +250,11 @@ void cRoot::Start(void) cBlockHandler::Deinit(); LOG("Cleaning up..."); - //delete HeartBeat; HeartBeat = 0; - delete m_Server; m_Server = 0; + delete m_Server; m_Server = NULL; LOG("Shutdown successful!"); } - delete m_Log; m_Log = 0; + delete m_Log; m_Log = NULL; } diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index e53c7c172..f65908729 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -8,6 +8,7 @@ #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" #include "../Piston.h" +#include "../Tracer.h" @@ -106,21 +107,47 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) || ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) || ((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) || - (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) + (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) || + (((SourceBlockType == E_BLOCK_STONE_PRESSURE_PLATE) || (SourceBlockType == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (SourceBlockMeta == 0)) ) { LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(itr->a_SourceBlock).c_str()); itr = m_PoweredBlocks.erase(itr); } + else if (SourceBlockType == E_BLOCK_DAYLIGHT_SENSOR) + { + if (!a_Chunk->IsLightValid()) + { + m_World.QueueLightChunk(a_ChunkX, a_ChunkZ); + ++itr; + continue; + } + else + { + NIBBLETYPE SkyLight; + a_Chunk->UnboundedRelGetBlockSkyLight(RelX, itr->a_SourcePos.y + 1, RelZ, SkyLight); + + if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness(); + { + LOGD("cRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level"); + itr = m_PoweredBlocks.erase(itr); + } + else + { + ++itr; + continue; + } + } + } else if ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (DestBlockType == E_BLOCK_REDSTONE_WIRE)) { // It is simply not allowed that a wire powers another wire, presuming that data here is sane and a dest and source are beside each other - LOGD("cRedstoneSimulator: Erased redstone wire from powered blocks list because it's source was also wire"); + LOGD("cRedstoneSimulator: Erased redstone wire from powered blocks list because its source was also wire"); itr = m_PoweredBlocks.erase(itr); } else { - itr++; + ++itr; } } @@ -165,7 +192,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c } else { - itr++; + ++itr; } } @@ -186,7 +213,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c } else { - itr++; + ++itr; } } @@ -206,12 +233,8 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c itr = m_RepeatersDelayList.erase(itr); continue; } - else if (itr->a_ElapsedTicks < itr->a_DelayTicks) - { - itr->a_ElapsedTicks++; - } - itr++; + ++itr; } for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) @@ -285,6 +308,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c HandleRail(a_X, dataitr->y, a_Z, BlockType); break; } + case E_BLOCK_WOODEN_PRESSURE_PLATE: + case E_BLOCK_STONE_PRESSURE_PLATE: + { + HandlePressurePlate(a_X, dataitr->y, a_Z, BlockType); + break; + } } ++dataitr; @@ -601,7 +630,7 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, false); } - for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); itr++) + for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -659,8 +688,14 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int return; } } - - // Tick incrementing handled in SimChunk + else + { + // Apparently, incrementing ticks only works reliably here, and not in SimChunk; + // With a world with lots of redstone, the repeaters simply do not delay + // I am confounded to say why. Perhaps optimisation failure. + LOGD("Incremented a repeater @ %i %i %i | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); + itr->a_ElapsedTicks++; + } } } @@ -897,9 +932,112 @@ void cRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_Block void cRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ) { - if (m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) > 10) + int a_ChunkX, a_ChunkZ; + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ); + + if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ)) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR); + m_World.QueueLightChunk(a_ChunkX, a_ChunkZ); + } + else + { + NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness(); + if (SkyLight > 8) + { + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR); + } + } +} + + + + + +void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) +{ + switch (a_MyType) + { + case E_BLOCK_STONE_PRESSURE_PLATE: + { + // MCS feature - stone pressure plates can only be triggered by players :D + cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f); + + if (a_Player != NULL) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE); + } + else + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); + } + break; + } + case E_BLOCK_WOODEN_PRESSURE_PLATE: + { + class cWoodenPressurePlateCallback : + public cEntityCallback + { + public: + cWoodenPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ), + m_World(a_World), + m_Entity(NULL) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + cTracer LineOfSight(m_World); + + Vector3f EntityPos = a_Entity->GetPosition(); + Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); + float Distance = (EntityPos - BlockPos).Length(); + + if (Distance < 0.5) + { + if (!LineOfSight.Trace(BlockPos, (EntityPos - BlockPos), (int)(EntityPos - BlockPos).Length())) + { + m_Entity = a_Entity; + return true; // Break out, we only need to know for wooden plates that at least one entity is on top + } + } + return false; + } + + bool FoundEntity(void) const + { + return m_Entity != NULL; + } + + protected: + cEntity * m_Entity; + cWorld * m_World; + + int m_X; + int m_Y; + int m_Z; + } ; + + cWoodenPressurePlateCallback WoodenPressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World); + m_World.ForEachEntity(WoodenPressurePlateCallback); + + if (WoodenPressurePlateCallback.FoundEntity()) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WOODEN_PRESSURE_PLATE); + } + else + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); + } + break; + } + default: + LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str()); + break; } } @@ -1308,7 +1446,7 @@ void cRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn) { - for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); itr++) + for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr) { if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -1318,7 +1456,7 @@ void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, in } // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit - itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description + itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; // See below for description itr->a_ElapsedTicks = 0; itr->ShouldPowerOn = ShouldPowerOn; return; @@ -1331,7 +1469,8 @@ void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, in // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.) // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed - RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; + // We don't +1 when powering off because everything seems to already delay a tick when powering off, why? No idea :P + RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; RC.a_ElapsedTicks = 0; diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index 309135497..60c86a3c5 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -89,6 +89,10 @@ private: void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ); /// <summary>Handles buttons</summary> void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); + /// <summary>Handles daylight sensors</summary> + void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ); + /// <summary>Handles pressure plates</summary> + void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); /* ==================== */ /* ====== CARRIERS ====== */ @@ -115,8 +119,6 @@ private: void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ); /// <summary>Handles noteblocks</summary> void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles noteblocks</summary> - void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ); /* ===================== */ /* ====== Helper functions ====== */ diff --git a/src/main.cpp b/src/main.cpp index 1f6aad24f..81c6b41e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,10 @@ #include <dbghelp.h> #endif // _MSC_VER +// Here, we have some ALL CAPS variables, to give the impression that this is deeeep, gritty programming :P +bool g_TERMINATE_EVENT_RAISED = false; // If something has told the server to stop; checked periodically in cRoot +bool g_SERVER_TERMINATED = false; // Set to true when the server terminates, so our CTRL handler can then tell Windows to close the console + @@ -33,14 +37,21 @@ - -void ShowCrashReport(int) +void NonCtrlHandler(int a_Signal) { - std::signal(SIGSEGV, SIG_DFL); + LOGD("Terminate event raised from std::signal"); + g_TERMINATE_EVENT_RAISED = true; - printf("\n\nMCServer has crashed!\n"); - - exit(-1); + switch (a_Signal) + { + case SIGSEGV: + { + std::signal(SIGSEGV, SIG_DFL); + LOGWARN("Segmentation fault; MCServer has crashed :("); + exit(EXIT_FAILURE); + } + default: break; + } } @@ -111,13 +122,33 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except +#ifdef _WIN32 +// Handle CTRL events in windows, including console window close +BOOL CtrlHandler(DWORD fdwCtrlType) +{ + g_TERMINATE_EVENT_RAISED = true; + LOGD("Terminate event raised from the Windows CtrlHandler"); + + if (fdwCtrlType == CTRL_CLOSE_EVENT) // Console window closed via 'x' button, Windows will try to close immediately, therefore... + { + while (!g_SERVER_TERMINATED) { cSleep::MilliSleep(100); } // Delay as much as possible to try to get the server to shut down cleanly + } + + return TRUE; +} +#endif + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // main: int main( int argc, char **argv ) { - (void)argc; - (void)argv; + UNUSED(argc); + UNUSED(argv); #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) InitLeakFinder(); @@ -149,6 +180,13 @@ 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 ); @@ -160,7 +198,9 @@ int main( int argc, char **argv ) #endif // _DEBUG && _MSC_VER #ifndef _DEBUG - std::signal(SIGSEGV, ShowCrashReport); + std::signal(SIGSEGV, NonCtrlHandler); + std::signal(SIGTERM, NonCtrlHandler); + std::signal(SIGINT, NonCtrlHandler); #endif // DEBUG: test the dumpfile creation: @@ -188,8 +228,10 @@ int main( int argc, char **argv ) #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) DeinitLeakFinder(); #endif - - return 0; + + g_SERVER_TERMINATED = true; + + return EXIT_SUCCESS; } |