diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 1e9a1c954..3304b7e49 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -5381,4 +5381,4 @@ int Minecraft::MustSignInReturnedPSN(void* pParam, int iPad, return 0; } -#endif +#endif \ No newline at end of file diff --git a/Minecraft.Client/MinecraftServer.cpp b/Minecraft.Client/MinecraftServer.cpp index a08f48ac9..fc6bc761e 100644 --- a/Minecraft.Client/MinecraftServer.cpp +++ b/Minecraft.Client/MinecraftServer.cpp @@ -1993,4 +1993,4 @@ bool MinecraftServer::flagEntitiesToBeRemoved(unsigned int* flags) { } } return removedFound; -} +} \ No newline at end of file diff --git a/Minecraft.Client/MinecraftServer.h b/Minecraft.Client/MinecraftServer.h index 6b2b5a809..7b7793775 100644 --- a/Minecraft.Client/MinecraftServer.h +++ b/Minecraft.Client/MinecraftServer.h @@ -317,4 +317,4 @@ public: // 4J Stu - A load of functions were all added in 1.0.1 in the // ServerInterface, but I don't think we need any of them -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Network/ClientConnection.cpp b/Minecraft.Client/Network/ClientConnection.cpp index 8494759de..835968f9e 100644 --- a/Minecraft.Client/Network/ClientConnection.cpp +++ b/Minecraft.Client/Network/ClientConnection.cpp @@ -4106,4 +4106,4 @@ ClientConnection::DeferredEntityLinkPacket::DeferredEntityLinkPacket( std::shared_ptr packet) { m_recievedTick = GetTickCount(); m_packet = packet; -} +} \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.h b/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.h index 9a174a4ba..9763c201a 100644 --- a/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.h +++ b/Minecraft.Client/Platform/Common/Audio/Consoles_SoundEngine.h @@ -2,30 +2,11 @@ #include "../../Minecraft.World/Util/SoundTypes.h" -#ifdef _XBOX - -#elif defined(__PS3__) -#undef __in -#undef __out -#include "../../Minecraft.Client/Platform/PS3/Miles/include/mss.h" -#elif defined(__PSVITA__) -#include "../../PSVITA/Miles/include/mss.h" -#elif defined _DURANGO -// 4J Stu - Temp define to get Miles to link, can likely be removed when we get -// a new version of Miles -#define _SEKRIT -#include "../../Minecraft.Client/Platform/Durango/Miles/include/mss.h" -#elif defined _WINDOWS64 +#ifdef _WINDOWS64 #include "../../windows64/Miles/include/mss.h" -#elif defined(__linux__) -// (DecalOverdose)HACK + TODO: Find native Linux headers and libs for this, but -// for now I'm using Win64 ones +#else +// Linux currently uses the Windows64 Miles headers as the compatible host SDK. #include "../../Minecraft.Client/Platform/Windows64/Miles/include/mss.h" -#else // PS4 -// 4J Stu - Temp define to get Miles to link, can likely be removed when we get -// a new version of Miles -#define _SEKRIT2 -#include "../../Minecraft.Client/Platform/Orbis/Miles/include/mss.h" #endif typedef struct { @@ -46,7 +27,8 @@ public: : m_bIsPlayingStreamingCDMusic(false), m_bIsPlayingStreamingGameMusic(false), m_bIsPlayingEndMusic(false), - m_bIsPlayingNetherMusic(false) {}; + m_bIsPlayingNetherMusic(false) {} + virtual void tick(std::shared_ptr* players, float a) = 0; virtual void destroy() = 0; virtual void play(int iSound, float x, float y, float z, float volume, @@ -74,6 +56,7 @@ public: virtual bool GetIsPlayingNetherMusic(); virtual void SetIsPlayingEndMusic(bool bVal); virtual void SetIsPlayingNetherMusic(bool bVal); + static const WCHAR* wchSoundNames[eSoundType_MAX]; static const WCHAR* wchUISoundNames[eSFX_MAX]; @@ -97,9 +80,6 @@ private: std::vector scheduledSounds; -private: - // platform specific functions - virtual int initAudioHardware(int iMinSpeakers) = 0; bool m_bIsPlayingStreamingCDMusic; @@ -107,3 +87,5 @@ private: bool m_bIsPlayingEndMusic; bool m_bIsPlayingNetherMusic; }; + + diff --git a/Minecraft.Client/Platform/Common/Audio/SoundEngine.h b/Minecraft.Client/Platform/Common/Audio/SoundEngine.h index ceb474353..2b843288f 100644 --- a/Minecraft.Client/Platform/Common/Audio/SoundEngine.h +++ b/Minecraft.Client/Platform/Common/Audio/SoundEngine.h @@ -180,4 +180,4 @@ private: #ifdef __ORBIS__ int32_t m_hBGMAudio; #endif -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/Consoles_App.h b/Minecraft.Client/Platform/Common/Consoles_App.h index 1077172df..cd84011ad 100644 --- a/Minecraft.Client/Platform/Common/Consoles_App.h +++ b/Minecraft.Client/Platform/Common/Consoles_App.h @@ -1158,4 +1158,4 @@ private: }; // singleton -// extern CMinecraftApp app; +// extern CMinecraftApp app; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Platform/Common/Network/GameNetworkManager.cpp index a26addc80..946d567e1 100644 --- a/Minecraft.Client/Platform/Common/Network/GameNetworkManager.cpp +++ b/Minecraft.Client/Platform/Common/Network/GameNetworkManager.cpp @@ -2213,4 +2213,4 @@ void CGameNetworkManager::startAdhocMatching() { ->startAdhocMatching(); } -#endif +#endif \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/Network/GameNetworkManager.h b/Minecraft.Client/Platform/Common/Network/GameNetworkManager.h index 2abdb4ba9..325c380c0 100644 --- a/Minecraft.Client/Platform/Common/Network/GameNetworkManager.h +++ b/Minecraft.Client/Platform/Common/Network/GameNetworkManager.h @@ -263,4 +263,4 @@ extern CGameNetworkManager g_NetworkManager; #ifdef __PS3__ #undef __in #define __out -#endif +#endif \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/ShutdownManager.h b/Minecraft.Client/Platform/Common/ShutdownManager.h new file mode 100644 index 000000000..e6c0f8b4f --- /dev/null +++ b/Minecraft.Client/Platform/Common/ShutdownManager.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "../../../Minecraft.World/Util/C4JThread.h" + +class ShutdownManager { + public: + enum EThreadId { + eMainThread, + eLeaderboardThread, + eCommerceThread, + ePostProcessThread, + eRunUpdateThread, + eRenderChunkUpdateThread, + eServerThread, + eStorageManagerThreads, + eConnectionReadThreads, + eConnectionWriteThreads, + eEventQueueThreads, + + eThreadIdCount + }; + + static void Initialise(); + static void StartShutdown(); + static void MainThreadHandleShutdown(); + + static void HasStarted(EThreadId threadId); + static void HasStarted(EThreadId threadId, + C4JThread::EventArray* eventArray); + static bool ShouldRun(EThreadId threadId); + static void HasFinished(EThreadId threadId); + + private: + struct GroupState { + std::size_t started = 0; + std::size_t running = 0; + }; + + struct State { + std::mutex mutex; + std::condition_variable condition; + std::array groups{}; + std::atomic shutdownRequested{false}; + }; + + static State& GetState(); +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/IUIScene_PauseMenu.cpp b/Minecraft.Client/Platform/Common/UI/IUIScene_PauseMenu.cpp index 65d52d39a..635c0414d 100644 --- a/Minecraft.Client/Platform/Common/UI/IUIScene_PauseMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/IUIScene_PauseMenu.cpp @@ -749,4 +749,4 @@ int IUIScene_PauseMenu::DisableAutosaveDialogReturned( app.SetAction(iPad, eAppAction_SaveGame); } return 0; -} +} \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIController.h b/Minecraft.Client/Platform/Common/UI/UIController.h index eb24f0f1a..5f01d17e8 100644 --- a/Minecraft.Client/Platform/Common/UI/UIController.h +++ b/Minecraft.Client/Platform/Common/UI/UIController.h @@ -457,4 +457,4 @@ public: public: char *m_defaultBuffer, *m_tempBuffer; void setFontCachingCalculationBuffer(int length); -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_ControlsMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_ControlsMenu.cpp index 070c34e36..1939d20e6 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_ControlsMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_ControlsMenu.cpp @@ -341,4 +341,4 @@ void UIScene_ControlsMenu::PositionTextDirect(int iPad, int iTextID, m_labelsPad[iControlDetailsIndex].setLabel(text); m_controlLines[iControlDetailsIndex].setVisible(bShow); -} +} \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_CreateWorldMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_CreateWorldMenu.cpp index 43dbade82..d8556dedc 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_CreateWorldMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_CreateWorldMenu.cpp @@ -1506,4 +1506,4 @@ int UIScene_CreateWorldMenu::MustSignInReturnedPSN( void UIScene_CreateWorldMenu::handleTouchBoxRebuild() { m_bRebuildTouchBoxes = true; -} +} \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_DLCMainMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_DLCMainMenu.cpp index 6ac19847d..21a743982 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_DLCMainMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_DLCMainMenu.cpp @@ -234,4 +234,4 @@ void UIScene_DLCMainMenu::tick() { } } #endif -} +} \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_DLCMainMenu.h b/Minecraft.Client/Platform/Common/UI/UIScene_DLCMainMenu.h index 2c8ee1668..66c747dad 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_DLCMainMenu.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_DLCMainMenu.h @@ -46,4 +46,4 @@ public: virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool& handled); virtual void handlePress(F64 controlId, F64 childId); -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_DLCOffersMenu.h b/Minecraft.Client/Platform/Common/UI/UIScene_DLCOffersMenu.h index c2aa14549..65a0b14ae 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_DLCOffersMenu.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_DLCOffersMenu.h @@ -90,4 +90,4 @@ private: #if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) std::vector* m_pvProductInfo; #endif -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_EnchantingMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_EnchantingMenu.cpp index 78fca71e5..e13edeb67 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_EnchantingMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_EnchantingMenu.cpp @@ -4,9 +4,6 @@ #include "../../Minecraft.World/Headers/net.minecraft.world.inventory.h" #include "../../Minecraft.Client/Minecraft.h" #include "UIScene_EnchantingMenu.h" - -#include - UIScene_EnchantingMenu::UIScene_EnchantingMenu(int iPad, void* _initData, UILayer* parentLayer) : UIScene_AbstractContainerMenu(iPad, parentLayer) { @@ -291,3 +288,4 @@ void UIScene_EnchantingMenu::customDraw(IggyCustomDrawCallbackRegion* region) { } } } + diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_LoadMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_LoadMenu.cpp index 1425a32bb..1f752e059 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_LoadMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_LoadMenu.cpp @@ -1934,4 +1934,4 @@ int UIScene_LoadMenu::MustSignInReturnedPSN(void* pParam, int iPad, // pClass->m_bIgnoreInput=false; // return 0; // } -#endif +#endif \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_LoadMenu.h b/Minecraft.Client/Platform/Common/UI/UIScene_LoadMenu.h index ba04e9f9f..ef993b73d 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_LoadMenu.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_LoadMenu.h @@ -139,4 +139,4 @@ public: std::uint8_t* pbThumbnail, unsigned int thumbnailBytes); static int StartGame_SignInReturned(void* pParam, bool, int); -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_LoadOrJoinMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_LoadOrJoinMenu.cpp index 563124002..0cd5dd009 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_LoadOrJoinMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_LoadOrJoinMenu.cpp @@ -3842,4 +3842,4 @@ int UIScene_LoadOrJoinMenu::CopySaveErrorDialogFinishedCallback( return 0; } -#endif // _XBOX_ONE +#endif // _XBOX_ONE \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_LoadOrJoinMenu.h b/Minecraft.Client/Platform/Common/UI/UIScene_LoadOrJoinMenu.h index 740907387..51703d9af 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_LoadOrJoinMenu.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_LoadOrJoinMenu.h @@ -328,4 +328,4 @@ private: static int CopySaveErrorDialogFinishedCallback( void* pParam, int iPad, C4JStorage::EMessageResult result); #endif -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp index 29fa2b306..fc920dc4c 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.cpp @@ -2220,4 +2220,4 @@ int UIScene_MainMenu::SelectNetworkModeReturned( pClass->updateTooltips(); return 0; } -#endif //__PSVITA__ +#endif //__PSVITA__ \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.h b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.h index ba8425c62..7abc35f9c 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_MainMenu.h @@ -209,4 +209,4 @@ private: int32_t m_errorCode; bool m_bErrorDialogRunning; #endif -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_PauseMenu.h b/Minecraft.Client/Platform/Common/UI/UIScene_PauseMenu.h index 23c6025b9..c6171a41f 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_PauseMenu.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_PauseMenu.h @@ -118,4 +118,4 @@ protected: #ifdef __ORBIS__ bool CheckForPatch(); #endif -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/UIScene_SkinSelectMenu.h b/Minecraft.Client/Platform/Common/UI/UIScene_SkinSelectMenu.h index 5f013be82..40feb631b 100644 --- a/Minecraft.Client/Platform/Common/UI/UIScene_SkinSelectMenu.h +++ b/Minecraft.Client/Platform/Common/UI/UIScene_SkinSelectMenu.h @@ -199,4 +199,4 @@ private: CRITICAL_SECTION m_DLCInstallCS; // to prevent a race condition between the // install and the mounted callback #endif -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Platform/Linux/Linux_ShutdownManager.cpp b/Minecraft.Client/Platform/Linux/Linux_ShutdownManager.cpp index 1077d1921..a2137cefb 100644 --- a/Minecraft.Client/Platform/Linux/Linux_ShutdownManager.cpp +++ b/Minecraft.Client/Platform/Linux/Linux_ShutdownManager.cpp @@ -1,7 +1,7 @@ // Linux stub implementations for ShutdownManager // The PS3/PSVita versions have full implementations; on Linux these are no-ops. #include "../../Platform/stdafx.h" -#include "../PS3/PS3Extras/ShutdownManager.h" +#include "../Common/ShutdownManager.h" void ShutdownManager::Initialise() {} void ShutdownManager::StartShutdown() {} diff --git a/Minecraft.Client/Platform/stdafx.h b/Minecraft.Client/Platform/stdafx.h index aa113c2c0..c6d17eb4e 100644 --- a/Minecraft.Client/Platform/stdafx.h +++ b/Minecraft.Client/Platform/stdafx.h @@ -14,47 +14,6 @@ // use - #pragma message(__LOC__"Need to do something here") -// #ifndef _XBOX -// #ifdef _CONTENT_PACKAGE -// #define TO_BE_IMPLEMENTED -// #endif -// #endif - -#ifdef __PS3__ - -#include "../Platform/PS3/PS3Extras/Ps3Types.h" -#include "../Platform/PS3/PS3Extras/Ps3Stubs.h" -#include "../Platform/PS3/PS3Extras/PS3Maths.h" - -#elif defined __ORBIS__ -#define AUTO_VAR(_var, _val) auto _var = _val -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../Platform/Orbis/OrbisExtras/OrbisTypes.h" -#include "../Platform/Orbis/OrbisExtras/OrbisStubs.h" -#include "../Platform/Orbis/OrbisExtras/OrbisMaths.h" -#define HRESULT_SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) -#elif defined __PSVITA__ -#include -#include -#include -#include -#include -#include -#include -#include -#include "../Platform/PSVita/PSVitaExtras/PSVitaTypes.h" -#include "../Platform/PSVita/PSVitaExtras/PSVitaStubs.h" -#include "../Platform/PSVita/PSVitaExtras/PSVitaMaths.h" -#elif defined __linux__ #define AUTO_VAR(_var, _val) auto _var = _val #include #include @@ -62,81 +21,25 @@ #include #include +#ifdef __linux__ #include "../Platform/Linux/Stubs/LinuxStubs.h" #else -#define AUTO_VAR(_var, _val) auto _var = _val -#include -#include -#include typedef unsigned __int64 __uint64; #endif -#ifdef _WINDOWS64 -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -// Windows Header Files: +#ifdef _WINDOWS64 +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include #include -// TODO: reference additional headers your program requires here #include #include -using namespace DirectX; +using namespace DirectX; -#define HRESULT_SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) - -#endif - - - -#ifdef _DURANGO -#include -#include -#include -#include -#include -#include -using namespace DirectX; -#include -#include "../Platform/Durango/DurangoExtras/DurangoStubs.h" #define HRESULT_SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) #endif - - -#ifdef _XBOX -#include -#include -#include -#include -#include -#include -typedef XINVITE_INFO INVITE_INFO; -typedef XUID PlayerUID; -typedef XNKID SessionID; -typedef XUID GameSessionUID; -#define HRESULT_SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) - -#include "../Minecraft.Client/xbox/network/extra.h" -#else #include "../../Minecraft.World/Platform/x64headers/extraX64.h" -#endif - -#ifdef __PS3__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - -// C RunTime Header Files -#include #include @@ -152,11 +55,6 @@ typedef XUID GameSessionUID; #include -#ifdef _XBOX -#include -#include -#endif - #include "../../Minecraft.World/Util/Definitions.h" #include "../../Minecraft.World/Util/Class.h" #include "../../Minecraft.World/Util/ArrayWithLength.h" @@ -165,43 +63,16 @@ typedef XUID GameSessionUID; #include "../../Minecraft.World/IO/Streams/Compression.h" #include "../../Minecraft.World/Util/PerformanceTimer.h" -#ifdef _XBOX - #include "xbox/4JLibs/inc/4J_Input.h" - #include "xbox/4JLibs/inc/4J_Profile.h" - #include "xbox/4JLibs/inc/4J_Render.h" - #include "xbox/4JLibs/inc/4J_XTMS.h" - #include "xbox/4JLibs/inc/4J_Storage.h" -#elif defined (__PS3__) - - #include "../Platform/PS3/4JLibs/inc/4J_Input.h" - #include "../Platform/PS3/4JLibs/inc/4J_Profile.h" - #include "../Platform/PS3/4JLibs/inc/4J_Render.h" - #include "../Platform/PS3/4JLibs/inc/4J_Storage.h" -#elif defined _DURANGO - #include "../Platform/Durango/4JLibs/inc/4J_Input.h" - #include "../Platform/Durango/4JLibs/inc/4J_Profile.h" - #include "../Platform/Durango/4JLibs/inc/4J_Render.h" - #include "../Platform/Durango/4JLibs/inc/4J_Storage.h" -#elif defined _WINDOWS64 - #include "../Platform/Windows64/4JLibs/inc/4J_Input.h" - #include "../Platform/Windows64/4JLibs/inc/4J_Profile.h" - #include "../Platform/Windows64/4JLibs/inc/4J_Render.h" - #include "../Platform/Windows64/4JLibs/inc/4J_Storage.h" -#elif defined __linux__ - #include "4J_Input.h" - #include "4J_Profile.h" - #include "4J_Render.h" - #include "4J_Storage.h" -#elif defined __PSVITA__ - #include "../Platform/PSVita/4JLibs/inc/4J_Input.h" - #include "../Platform/PSVita/4JLibs/inc/4J_Profile.h" - #include "../Platform/PSVita/4JLibs/inc/4J_Render.h" - #include "../Platform/PSVita/4JLibs/inc/4J_Storage.h" +#ifdef _WINDOWS64 +#include "../Platform/Windows64/4JLibs/inc/4J_Input.h" +#include "../Platform/Windows64/4JLibs/inc/4J_Profile.h" +#include "../Platform/Windows64/4JLibs/inc/4J_Render.h" +#include "../Platform/Windows64/4JLibs/inc/4J_Storage.h" #else - #include "../Platform/Orbis/4JLibs/inc/4J_Input.h" - #include "../Platform/Orbis/4JLibs/inc/4J_Profile.h" - #include "../Platform/Orbis/4JLibs/inc/4J_Render.h" - #include "../Platform/Orbis/4JLibs/inc/4J_Storage.h" +#include "4J_Input.h" +#include "4J_Profile.h" +#include "4J_Render.h" +#include "4J_Storage.h" #endif #include "../Textures/Textures.h" @@ -217,19 +88,12 @@ typedef XUID GameSessionUID; #include "../Platform/Common/Network/GameNetworkManager.h" -#ifdef _XBOX -#include "../Platform/Common/XUI/XUI_Helper.h" -#include "../Platform/Common/XUI/XUI_Scene_Base.h" -#endif - #include "../Platform/Common/UI/UIEnums.h" #include "../Platform/Common/UI/UIStructs.h" -// #ifdef _XBOX #include "../Platform/Common/App_Defines.h" #include "../Platform/Common/App_enums.h" #include "../Platform/Common/Tutorial/TutorialEnum.h" #include "../Platform/Common/App_structs.h" -//#endif #include "../Platform/Common/Consoles_App.h" #include "../Platform/Common/Minecraft_Macros.h" @@ -238,110 +102,31 @@ typedef XUID GameSessionUID; // This is generated at build time via scripts/pack_loc.py #include "strings.h" -// This is generated at build time via scripts/pack_loc.py -#include "strings.h" - -#ifdef _XBOX - #include "../Platform/Xbox/Xbox_App.h" - #include "../Platform/Xbox/Sentient/MinecraftTelemetry.h" - #include "../Platform/Xbox/Sentient/DynamicConfigurations.h" - #include "../Platform/Xbox/Sentient/SentientTelemetryCommon.h" - #include "../Platform/Xbox/Sentient/Include/SenClientStats.h" - #include "../Platform/Xbox/GameConfig/Minecraft.spa.h" - #include "../../Minecraft.Assets/XboxMedia/4J_strings.h" - #include "../Platform/Xbox/XML/ATGXmlParser.h" - #include "../Platform/Xbox/Leaderboards/XboxLeaderboardManager.h" - #include "../Platform/Xbox/Social/SocialManager.h" - #include "../Platform/Xbox/Audio/SoundEngine.h" - #include "../Platform/Xbox/Xbox_UIController.h" - -#elif defined (__PS3__) - #include "extraX64client.h" - #include "../Platform/PS3/Sentient/MinecraftTelemetry.h" - #include "../Platform/PS3/Sentient/DynamicConfigurations.h" - #include "../Platform/PS3/Sentient/SentientTelemetryCommon.h" - #include "../Platform/PS3/PS3_App.h" - #include "../Platform/PS3/GameConfig/Minecraft.spa.h" - #include "../../Minecraft.Assets/PS3Media/4J_strings.h" - #include "../Platform/PS3/XML/ATGXmlParser.h" - #include "../Platform/PS3/Social/SocialManager.h" - #include "../Platform/Common/Audio/SoundEngine.h" - #include "../Platform/PS3/Iggy/include/iggy.h" - #include "../Platform/PS3/Iggy/gdraw/gdraw_ps3gcm.h" - #include "../Platform/PS3/PS3_UIController.h" -#elif defined _DURANGO - #include "../Platform/Durango/Sentient/MinecraftTelemetry.h" - #include "../Platform/Durango/Durango_App.h" - #include "../Platform/Durango/Sentient/DynamicConfigurations.h" - #include "../Platform/Durango/Sentient/TelemetryEnum.h" - #include "../Platform/Durango/Sentient/SentientTelemetryCommon.h" - #include "../Platform/Durango/PresenceIds.h" - #include "../../Minecraft.Assets/DurangoMedia/4J_strings.h" - #include "../Platform/Durango/XML/ATGXmlParser.h" - #include "../Platform/Durango/Social/SocialManager.h" - #include "../Platform/Common/Audio/SoundEngine.h" - #include "../Platform/Durango/Iggy/include/iggy.h" - #include "../Platform/Durango/Iggy/gdraw/gdraw_d3d11.h" - #include "../Platform/Durango/Durango_UIController.h" -#elif defined _WINDOWS64 - #include "../Platform/Windows64/Sentient/MinecraftTelemetry.h" - #include "../Platform/Windows64/Windows64_App.h" - #include "../Platform/Windows64/Sentient/DynamicConfigurations.h" - #include "../Platform/Windows64/Sentient/SentientTelemetryCommon.h" - #include "../Platform/Windows64/GameConfig/Minecraft.spa.h" - #include "../Platform/Windows64/XML/ATGXmlParser.h" - #include "../Platform/Windows64/Social/SocialManager.h" - #include "../Platform/Common/Audio/SoundEngine.h" - #include "../Platform/Windows64/Iggy/include/iggy.h" - #include "../Platform/Windows64/Iggy/gdraw/gdraw_d3d11.h" - #include "../Platform/Windows64/Windows64_UIController.h" -#elif defined __linux__ - // Linux build: avoid pulling in Windows64 platform headers (they cause - // symbol/class redefinitions). Use Orbis-compatible stubs and Linux controller. - #include "../Platform/Linux/Linux_App.h" - #include "../Platform/Linux/Iggy/include/iggy.h" - #include "../Platform/Linux/Sentient/SentientTelemetryCommon.h" - #include "../Platform/Linux/Sentient/DynamicConfigurations.h" - #include "../Platform/Orbis/GameConfig/Minecraft.spa.h" - #include "../Platform/Common/Audio/SoundEngine.h" - #include "../Platform/Linux/Linux_UIController.h" - #include "../Platform/Linux/Social/SocialManager.h" -#elif defined __PSVITA__ - #include "../Platform/PSVita/PSVita_App.h" - #include "../Platform/PSVita/Sentient/SentientManager.h" - #include "../Platform/PSVita/Sentient/MinecraftTelemetry.h" - #include "../Platform/PSVita/Sentient/DynamicConfigurations.h" - #include "../Platform/PSVita/GameConfig/Minecraft.spa.h" - #include "../Platform/PSVita/XML/ATGXmlParser.h" - #include "../Platform/PSVita/Social/SocialManager.h" - #include "../Platform/Common/Audio/SoundEngine.h" - #include "../Platform/PSVita/Iggy/include/iggy.h" - #include "../Platform/PSVita/Iggy/gdraw/gdraw_psp2.h" - #include "../Platform/PSVita/PSVita_UIController.h" +#ifdef _WINDOWS64 +#include "../Platform/Windows64/Sentient/MinecraftTelemetry.h" +#include "../Platform/Windows64/Windows64_App.h" +#include "../Platform/Windows64/Sentient/DynamicConfigurations.h" +#include "../Platform/Windows64/Sentient/SentientTelemetryCommon.h" +#include "../Platform/Windows64/GameConfig/Minecraft.spa.h" +#include "../Platform/Windows64/XML/ATGXmlParser.h" +#include "../Platform/Windows64/Social/SocialManager.h" +#include "../Platform/Common/Audio/SoundEngine.h" +#include "../Platform/Windows64/Iggy/include/iggy.h" +#include "../Platform/Windows64/Iggy/gdraw/gdraw_d3d11.h" +#include "../Platform/Windows64/Windows64_UIController.h" #else - #include "../Platform/Orbis/Sentient/MinecraftTelemetry.h" - #include "../Platform/Orbis/Orbis_App.h" - #include "../Platform/Orbis/Sentient/SentientTelemetryCommon.h" - #include "../Platform/Orbis/Sentient/DynamicConfigurations.h" - #include "../Platform/Orbis/GameConfig/Minecraft.spa.h" - #include "../../Minecraft.Assets/OrbisMedia/4J_strings.h" - #include "../Platform/Orbis/XML/ATGXmlParser.h" - #include "../Platform/Windows64/Social/SocialManager.h" - #include "../Platform/Common/Audio/SoundEngine.h" - #include "../Platform/Orbis/Iggy/include/iggy.h" - #include "../Platform/Orbis/Iggy/gdraw/gdraw_orbis.h" - #include "../Platform/Orbis/Orbis_UIController.h" +// Linux build: keep the Linux runtime/controller path and use the supported +// Linux/Windows64 metadata headers only. +#include "../Platform/Linux/Linux_App.h" +#include "../Platform/Linux/Iggy/include/iggy.h" +#include "../Platform/Linux/Sentient/SentientTelemetryCommon.h" +#include "../Platform/Linux/Sentient/DynamicConfigurations.h" +#include "../Platform/Windows64/GameConfig/Minecraft.spa.h" +#include "../Platform/Common/Audio/SoundEngine.h" +#include "../Platform/Linux/Linux_UIController.h" +#include "../Platform/Linux/Social/SocialManager.h" #endif -#ifdef _XBOX -#include "../Platform/Common/XUI/XUI_CustomMessages.h" -#include "../Platform/Common/XUI/XUI_Scene_Inventory_Creative.h" -#include "../Platform/Common/XUI/XUI_FullscreenProgress.h" -#include "../Platform/Common/XUI/XUI_ConnectingProgress.h" -#include "../Platform/Common/XUI/XUI_Scene_CraftingPanel.h" -#include "../Platform/Common/XUI/XUI_TutorialPopup.h" -#include "../Platform/Common/XUI/XUI_PauseMenu.h" -#endif #include "../Platform/Common/ConsoleGameMode.h" #include "../Platform/Common/Console_Debug_enum.h" #include "../Platform/Common/Console_Awards_enum.h" @@ -357,13 +142,7 @@ typedef XUID GameSessionUID; #include "../Platform/Common/DLC/DLCPack.h" #include "../Platform/Common/Telemetry/TelemetryManager.h" -#ifdef _XBOX -//#include "../Platform/Xbox/Xbox_App.h" -#elif !defined(__PS3__) #include "extraX64client.h" -#endif - - #ifdef _FINAL_BUILD #define printf BREAKTHECOMPILE diff --git a/Minecraft.Client/Rendering/LevelRenderer.cpp b/Minecraft.Client/Rendering/LevelRenderer.cpp index 2554b3532..a54d377d8 100644 --- a/Minecraft.Client/Rendering/LevelRenderer.cpp +++ b/Minecraft.Client/Rendering/LevelRenderer.cpp @@ -4103,4 +4103,4 @@ int LevelRenderer::checkAllPresentChunks(bool* faultFound) { } } return presentCount; -} +} \ No newline at end of file diff --git a/Minecraft.Client/Rendering/LevelRenderer.h b/Minecraft.Client/Rendering/LevelRenderer.h index 1275ee4e8..8bb1b2d8d 100644 --- a/Minecraft.Client/Rendering/LevelRenderer.h +++ b/Minecraft.Client/Rendering/LevelRenderer.h @@ -347,4 +347,4 @@ public: void nonStackDirtyChunksAdded(); int checkAllPresentChunks(bool* faultFound); // 4J - added for testing -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Rendering/Tesselator.cpp b/Minecraft.Client/Rendering/Tesselator.cpp index 49e6f5669..8642b3d04 100644 --- a/Minecraft.Client/Rendering/Tesselator.cpp +++ b/Minecraft.Client/Rendering/Tesselator.cpp @@ -1129,4 +1129,4 @@ bool Tesselator::hasMaxVertices() { #else return false; #endif -} +} \ No newline at end of file diff --git a/Minecraft.Client/Rendering/Tesselator.h b/Minecraft.Client/Rendering/Tesselator.h index 8738c165a..0e8d7e577 100644 --- a/Minecraft.Client/Rendering/Tesselator.h +++ b/Minecraft.Client/Rendering/Tesselator.h @@ -174,4 +174,4 @@ public: float x4, float y4, float z4, float u4, float v4, float r1, float g1, float b1, float a1); #endif -}; +}; \ No newline at end of file diff --git a/Minecraft.World/IO/Files/ConsoleSaveFileOriginal.cpp b/Minecraft.World/IO/Files/ConsoleSaveFileOriginal.cpp index bc54c3e07..9f4378f02 100644 --- a/Minecraft.World/IO/Files/ConsoleSaveFileOriginal.cpp +++ b/Minecraft.World/IO/Files/ConsoleSaveFileOriginal.cpp @@ -3,6 +3,8 @@ #include "../../Util/PortableFileIO.h" #include "ConsoleSaveFileOriginal.h" #include "File.h" +#include +#include #include #include "../Streams/Compression.h" #include "../../../Minecraft.Client/Minecraft.h" @@ -13,13 +15,8 @@ #include "../../../Minecraft.Client/Platform/Common/GameRules/LevelGenerationOptions.h" #include "../../Headers/net.minecraft.world.level.chunk.storage.h" -#ifdef _XBOX -#define RESERVE_ALLOCATION MEM_RESERVE | MEM_LARGE_PAGES -#define COMMIT_ALLOCATION MEM_COMMIT | MEM_LARGE_PAGES -#else #define RESERVE_ALLOCATION MEM_RESERVE #define COMMIT_ALLOCATION MEM_COMMIT -#endif unsigned int ConsoleSaveFileOriginal::pagesCommitted = 0; void* ConsoleSaveFileOriginal::pvHeap = NULL; @@ -28,8 +25,6 @@ ConsoleSaveFileOriginal::ConsoleSaveFileOriginal( const std::wstring& fileName, void* pvSaveData /*= NULL*/, unsigned int initialFileSize /*= 0*/, bool forceCleanSave /*= false*/, ESavePlatform plat /*= SAVE_FILE_PLATFORM_LOCAL*/) { - InitializeCriticalSectionAndSpinCount(&m_lock, 5120); - // One time initialise of static stuff required for our storage if (pvHeap == NULL) { // Reserve a chunk of 64MB of virtual address space for our saves, using @@ -93,117 +88,66 @@ ConsoleSaveFileOriginal::ConsoleSaveFileOriginal( pagesCommitted = pagesRequired; if (fileSize > 0) { - bool AllocData = false; if (pvSaveData != NULL) { -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualCopyTo(pvSaveMem, pvSaveData, fileSize); -#else memcpy(pvSaveMem, pvSaveData, fileSize); if (bLevelGenBaseSave) { levelGen->deleteBaseSaveData(); } -#endif } else { unsigned int storageLength; -#ifdef __PSVITA__ - // create a buffer to hold the compressed data - pvSaveData = malloc(fileSize); - AllocData = true; - StorageManager.GetSaveData(pvSaveData, &storageLength); -#else StorageManager.GetSaveData(pvSaveMem, &storageLength); -#endif -#ifdef __PS3__ - StorageManager.FreeSaveData(); -#endif app.DebugPrintf("Filesize - %d, Adjusted size - %d\n", fileSize, storageLength); fileSize = storageLength; } + void* pvSourceData = pvSaveMem; + int compressed = *(int*)pvSourceData; + if (compressed == 0) { + unsigned int decompSize = *((int*)pvSourceData + 1); + if (isLocalEndianDifferent(plat)) System::ReverseULONG(&decompSize); -#ifdef __PSVITA__ - if (plat == SAVE_FILE_PLATFORM_PSVITA) { - // AP - decompress via the access function. This uses a special RLE - // format - VirtualDecompress((unsigned char*)pvSaveData + 8, fileSize - 8); - if (AllocData) { - // free the compressed data buffer if required - free(pvSaveData); - } else if (bLevelGenBaseSave) { - levelGen->deleteBaseSaveData(); - } - } else -#endif - { -#ifdef __PSVITA__ - void* pvSourceData = pvSaveData; -#else - void* pvSourceData = pvSaveMem; -#endif - int compressed = *(int*)pvSourceData; - if (compressed == 0) { - unsigned int decompSize = *((int*)pvSourceData + 1); - if (isLocalEndianDifferent(plat)) - System::ReverseULONG(&decompSize); + // An invalid save, so clear the memory and start from scratch + if (decompSize == 0) { + // 4J Stu - Saves created between 2/12/2011 and 7/12/2011 + // will have this problem + app.DebugPrintf("Invalid save data format\n"); + std::memset(pvSourceData, 0, fileSize); + // Clear the first 8 bytes that reference the header + header.WriteHeader(pvSourceData); + } else { + unsigned char* buf = new unsigned char[decompSize]; + Compression::getCompression()->SetDecompressionType( + plat); // if this save is from another platform, set the + // correct decompression type + Compression::getCompression()->Decompress( + buf, &decompSize, (unsigned char*)pvSourceData + 8, + fileSize - 8); + Compression::getCompression()->SetDecompressionType( + SAVE_FILE_PLATFORM_LOCAL); // and then set the + // decompression back to the + // local machine's standard type - // An invalid save, so clear the memory and start from scratch - if (decompSize == 0) { - // 4J Stu - Saves created between 2/12/2011 and 7/12/2011 - // will have this problem - app.DebugPrintf("Invalid save data format\n"); - ZeroMemory(pvSourceData, fileSize); - // Clear the first 8 bytes that reference the header - header.WriteHeader(pvSourceData); - } else { - unsigned char* buf = new unsigned char[decompSize]; -#ifndef _XBOX - if (plat == SAVE_FILE_PLATFORM_PSVITA) { - Compression::VitaVirtualDecompress( - buf, &decompSize, (unsigned char*)pvSourceData + 8, - fileSize - 8); - } else -#endif - { - Compression::getCompression()->SetDecompressionType( - plat); // if this save is from another platform, - // set the correct decompression type - Compression::getCompression()->Decompress( - buf, &decompSize, (unsigned char*)pvSourceData + 8, - fileSize - 8); - Compression::getCompression()->SetDecompressionType( - SAVE_FILE_PLATFORM_LOCAL); // and then set the - // decompression back to - // the local machine's - // standard type + // Only ReAlloc if we need to (we might already have enough) + // and align to 512 byte boundaries + unsigned int currentHeapSize = pagesCommitted * CSF_PAGE_SIZE; + + unsigned int desiredSize = decompSize; + + if (desiredSize > currentHeapSize) { + unsigned int pagesRequired = + (desiredSize + (CSF_PAGE_SIZE - 1)) / CSF_PAGE_SIZE; + void* pvRet = VirtualAlloc(pvHeap, + pagesRequired * CSF_PAGE_SIZE, + COMMIT_ALLOCATION, + PAGE_READWRITE); + if (pvRet == NULL) { + // Out of physical memory + __debugbreak(); } - - // Only ReAlloc if we need to (we might already have enough) - // and align to 512 byte boundaries - unsigned int currentHeapSize = - pagesCommitted * CSF_PAGE_SIZE; - - unsigned int desiredSize = decompSize; - - if (desiredSize > currentHeapSize) { - unsigned int pagesRequired = - (desiredSize + (CSF_PAGE_SIZE - 1)) / CSF_PAGE_SIZE; - void* pvRet = - VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, - COMMIT_ALLOCATION, PAGE_READWRITE); - if (pvRet == NULL) { - // Out of physical memory - __debugbreak(); - } - pagesCommitted = pagesRequired; - } -#ifdef __PSVITA__ - VirtualCopyTo(pvSaveMem, buf, decompSize); -#else - memcpy(pvSaveMem, buf, decompSize); -#endif - delete[] buf; + pagesCommitted = pagesRequired; } + memcpy(pvSaveMem, buf, decompSize); + delete[] buf; } } @@ -218,15 +162,6 @@ ConsoleSaveFileOriginal::ConsoleSaveFileOriginal( ConsoleSaveFileOriginal::~ConsoleSaveFileOriginal() { VirtualFree(pvHeap, MAX_PAGE_COUNT * CSF_PAGE_SIZE, MEM_DECOMMIT); pagesCommitted = 0; - // Make sure we don't have any thumbnail data still waiting round - we can't - // need it now we've destroyed the save file anyway -#if defined _XBOX - app.GetSaveThumbnail(NULL, NULL); -#elif defined __PS3__ - app.GetSaveThumbnail(NULL, NULL, NULL, NULL); -#endif - - DeleteCriticalSection(&m_lock); } // Add the file to our table of internal files if not already there @@ -271,24 +206,14 @@ void ConsoleSaveFileOriginal::deleteFile(FileEntry* file) { if (amountToRead == 0) break; -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualCopyFrom(buffer, readStartOffset, amountToRead); -#else memcpy(buffer, readStartOffset, amountToRead); -#endif numberOfBytesRead = amountToRead; bufferDataSize = amountToRead; readStartOffset += numberOfBytesRead; // Write buffer to file -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualCopyTo((void*)writeStartOffset, buffer, bufferDataSize); -#else memcpy((void*)writeStartOffset, buffer, bufferDataSize); -#endif numberOfBytesWritten = bufferDataSize; writeStartOffset += numberOfBytesWritten; @@ -364,13 +289,7 @@ bool ConsoleSaveFileOriginal::writeFile(FileEntry* file, const void* lpBuffer, // writeStartOffset = %0xd\n", pvSaveMem, file->currentFilePointer, // writeStartOffset); -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualCopyTo((void*)writeStartOffset, (void*)lpBuffer, - nNumberOfBytesToWrite); -#else memcpy((void*)writeStartOffset, lpBuffer, nNumberOfBytesToWrite); -#endif *lpNumberOfBytesWritten = nNumberOfBytesToWrite; if (file->data.length < 0) file->data.length = 0; @@ -404,12 +323,7 @@ bool ConsoleSaveFileOriginal::zeroFile(FileEntry* file, // writeStartOffset = %0xd\n", pvSaveMem, file->currentFilePointer, // writeStartOffset); -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualMemset((void*)writeStartOffset, 0, nNumberOfBytesToWrite); -#else memset((void*)writeStartOffset, 0, nNumberOfBytesToWrite); -#endif *lpNumberOfBytesWritten = nNumberOfBytesToWrite; if (file->data.length < 0) file->data.length = 0; @@ -450,12 +364,7 @@ bool ConsoleSaveFileOriginal::readFile(FileEntry* file, void* lpBuffer, file->currentFilePointer; } -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualCopyFrom(lpBuffer, readStartOffset, actualBytesToRead); -#else memcpy(lpBuffer, readStartOffset, actualBytesToRead); -#endif *lpNumberOfBytesRead = actualBytesToRead; @@ -575,14 +484,8 @@ void ConsoleSaveFileOriginal::MoveDataBeyond( // Needs to be clamped to the end of our region uiCopyEnd = uiFromEnd; } -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualMove((void*)(uiCopyStart + nNumberOfBytesToWrite), - (void*)uiCopyStart, uiCopyEnd - uiCopyStart); -#else XMemCpy((void*)(uiCopyStart + nNumberOfBytesToWrite), (void*)uiCopyStart, uiCopyEnd - uiCopyStart); -#endif } } } else { @@ -605,12 +508,7 @@ void ConsoleSaveFileOriginal::MoveDataBeyond( // printf("About to read %u from %d\n", amountToRead, // readStartOffset - (char *)pvSaveMem ); -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualCopyFrom(buffer1, readStartOffset, amountToRead); -#else memcpy(buffer1, readStartOffset, amountToRead); -#endif numberOfBytesRead = amountToRead; buffer1Size = amountToRead; @@ -623,12 +521,7 @@ void ConsoleSaveFileOriginal::MoveDataBeyond( if ((writeStartOffset + buffer2Size) <= finishEndOfDataOffset) { // printf("About to write %u to %d\n", buffer2Size, // writeStartOffset - (char *)pvSaveMem ); -#ifdef __PSVITA__ - // AP - use this to access the virtual memory - VirtualCopyTo((void*)writeStartOffset, buffer2, buffer2Size); -#else memcpy((void*)writeStartOffset, buffer2, buffer2Size); -#endif numberOfBytesWritten = buffer2Size; } else { assert((writeStartOffset + buffer2Size) <= @@ -659,22 +552,9 @@ bool ConsoleSaveFileOriginal::doesFileExist(ConsoleSavePath file) { void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail) { LockSaveAccess(); -#ifdef __PSVITA__ - // On Vita we've had problems with saves being corrupted on rapid - // save/save-exiting so seems prudent to wait for idle - while (StorageManager.GetSaveState() != C4JStorage::ESaveGame_Idle) { - app.DebugPrintf("Flush wait\n"); - Sleep(10); - } -#endif - finalizeWrite(); - // Get the frequency of the timer - LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime; float fElapsedTime = 0.0f; - QueryPerformanceFrequency(&qwTicksPerSec); - float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart; unsigned int fileSize = header.GetFileSize(); @@ -686,25 +566,11 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail) { // 4J Stu - Added TU-1 interim -#ifdef __PS3__ - // On PS3, don't compress the data as we can't really afford the extra - // memory this requires for the output buffer. Instead we'll be writing - // directly from the save data. - StorageManager.SetSaveData(pvSaveMem, fileSize); - std::uint8_t* compData = (std::uint8_t*)pvSaveMem; -#else // Attempt to allocate the required memory // We do not own this, it belongs to the StorageManager std::uint8_t* compData = (std::uint8_t*)StorageManager.AllocateSaveData(compLength); -#ifdef __PSVITA__ - // AP - make sure we always allocate just what is needed so it will only - // SAVE what is needed. If we don't do this the StorageManager will save a - // file of uncompressed size unnecessarily. - compData = NULL; -#endif - // If we failed to allocate then compData will be NULL // Pre-calculate the compressed data size so that we can attempt to allocate // a smaller buffer @@ -716,19 +582,13 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail) { // Pre-calculate the buffer size required for the compressed data PIXBeginNamedEvent(0, "Pre-calc save compression"); // Save the start time - QueryPerformanceCounter(&qwTime); -#ifdef __PSVITA__ - // AP - get the compressed size via the access function. This uses a - // special RLE format - VirtualCompress(NULL, &compLength, pvSaveMem, fileSize); -#else + const auto startTime = std::chrono::steady_clock::now(); Compression::getCompression()->Compress(NULL, &compLength, pvSaveMem, fileSize); -#endif - QueryPerformanceCounter(&qwNewTime); - - qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; - fElapsedTime = fSecsPerTick * static_cast(qwDeltaTime.QuadPart); + fElapsedTime = + std::chrono::duration(std::chrono::steady_clock::now() - + startTime) + .count(); app.DebugPrintf("Check buffer size: Elapsed time %f\n", fElapsedTime); PIXEndNamedEvent(); @@ -740,38 +600,29 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail) { // Attempt to allocate the required memory compData = (std::uint8_t*)StorageManager.AllocateSaveData(compLength); } -#endif if (compData != NULL) { - // No compression on PS3 - see comment above -#ifndef __PS3__ // Re-compress all save data before we save it to disk PIXBeginNamedEvent(0, "Actual save compression"); // Save the start time - QueryPerformanceCounter(&qwTime); -#ifdef __PSVITA__ - // AP - compress via the access function. This uses a special RLE format - VirtualCompress(compData + 8, &compLength, pvSaveMem, fileSize); -#else + const auto startTime = std::chrono::steady_clock::now(); Compression::getCompression()->Compress(compData + 8, &compLength, pvSaveMem, fileSize); -#endif - QueryPerformanceCounter(&qwNewTime); - - qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; - fElapsedTime = fSecsPerTick * static_cast(qwDeltaTime.QuadPart); + fElapsedTime = + std::chrono::duration(std::chrono::steady_clock::now() - + startTime) + .count(); app.DebugPrintf("Compress: Elapsed time %f\n", fElapsedTime); PIXEndNamedEvent(); - ZeroMemory(compData, 8); + std::fill_n(compData, 8, std::uint8_t{0}); int saveVer = 0; memcpy(compData, &saveVer, sizeof(int)); memcpy(compData + 4, &fileSize, sizeof(int)); app.DebugPrintf("Save data compressed from %d to %d\n", fileSize, compLength); -#endif std::uint8_t* pbThumbnailData = NULL; unsigned int dwThumbnailDataSize = 0; @@ -779,17 +630,14 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail) { std::uint8_t* pbDataSaveImage = NULL; unsigned int dwDataSizeSaveImage = 0; -#if (defined _XBOX || defined _DURANGO) - app.GetSaveThumbnail(&pbThumbnailData, &dwThumbnailDataSize); -#elif (defined __PS3__ || defined __ORBIS__ || defined __PSVITA__) +#ifdef _WINDOWS64 app.GetSaveThumbnail(&pbThumbnailData, &dwThumbnailDataSize, &pbDataSaveImage, &dwDataSizeSaveImage); #endif - std::uint8_t bTextMetadata[88]; - ZeroMemory(bTextMetadata, 88); + std::uint8_t bTextMetadata[88] = {}; - int64_t seed = 0; + __int64 seed = 0; bool hasSeed = false; if (MinecraftServer::getInstance() != NULL && MinecraftServer::getInstance()->levels[0] != NULL) { @@ -810,27 +658,7 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail) { StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); TelemetryManager->RecordLevelSaveOrCheckpoint( ProfileManager.GetPrimaryPad(), saveOrCheckpointId, compLength + 8); - -#ifdef _XBOX - StorageManager.SaveSaveData(compLength + 8, pbThumbnailData, - dwThumbnailDataSize, bTextMetadata, - iTextMetadataBytes); - delete[] pbThumbnailData; -#ifndef _CONTENT_PACKAGE - if (app.DebugSettingsOn()) { - if (app.GetWriteSavesToFolderEnabled()) { - DebugFlushToFile(compData, compLength + 8); - } - } -#endif - } else { - // We have failed to allocate the memory required to save this file. Now - // what? - } - - ReleaseSaveAccess(); -#elif (defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ || \ - defined _DURANGO || defined _WINDOWS64) +#ifdef _WINDOWS64 // set the icon and save image StorageManager.SetSaveImages(pbThumbnailData, dwThumbnailDataSize, pbDataSaveImage, dwDataSizeSaveImage, @@ -848,15 +676,17 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail) { } #endif ReleaseSaveAccess(); - } #else - } - ReleaseSaveAccess(); + ReleaseSaveAccess(); #endif + } else { + // We have failed to allocate the memory required to save this file. Now + // what? + ReleaseSaveAccess(); + } } -#if (defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ || \ - defined _DURANGO || defined _WINDOWS64) +#ifdef _WINDOWS64 int ConsoleSaveFileOriginal::SaveSaveDataCallback(void* lpParam, bool bRes) { ConsoleSaveFile* pClass = (ConsoleSaveFile*)lpParam; @@ -876,18 +706,14 @@ void ConsoleSaveFileOriginal::DebugFlushToFile( unsigned int fileSize = header.GetFileSize(); unsigned int numberOfBytesWritten = 0; -#ifdef _XBOX - File targetFileDir(L"GAME:\\Saves"); -#else File targetFileDir(L"Saves"); -#endif // _XBOX if (!targetFileDir.exists()) targetFileDir.mkdir(); wchar_t* fileName = new wchar_t[XCONTENT_MAX_FILENAME_LENGTH + 1]; - SYSTEMTIME t; - GetSystemTime(&t); + std::time_t now = std::time(NULL); + std::tm t = *std::gmtime(&now); // 14 chars for the digits // 11 chars for the separators + suffix @@ -898,36 +724,22 @@ void ConsoleSaveFileOriginal::DebugFlushToFile( } swprintf(fileName, XCONTENT_MAX_FILENAME_LENGTH + 1, L"\\v%04d-%ls%02d.%02d.%02d.%02d.%02d.mcs", VER_PRODUCTBUILD, - cutFileName.c_str(), t.wMonth, t.wDay, t.wHour, t.wMinute, - t.wSecond); + cutFileName.c_str(), t.tm_mon + 1, t.tm_mday, t.tm_hour, + t.tm_min, t.tm_sec); const std::wstring outputPath = targetFileDir.getPath() + std::wstring(fileName); -#ifndef __PSVITA__ bool writeSucceeded = false; -#endif if (compressedData != NULL && compressedDataSize > 0) { -#ifdef __PSVITA__ - // AP - Use the access function to save - VirtualWriteFile(outputPath.c_str(), compressedData, compressedDataSize, - &numberOfBytesWritten, NULL); -#else writeSucceeded = PortableFileIO::WriteBinaryFile( outputPath, compressedData, compressedDataSize); numberOfBytesWritten = writeSucceeded ? compressedDataSize : 0; -#endif assert(numberOfBytesWritten == compressedDataSize); } else { -#ifdef __PSVITA__ - // AP - Use the access function to save - VirtualWriteFile(outputPath.c_str(), compressedData, compressedDataSize, - &numberOfBytesWritten, NULL); -#else writeSucceeded = PortableFileIO::WriteBinaryFile(outputPath, pvSaveMem, fileSize); numberOfBytesWritten = writeSucceeded ? fileSize : 0; -#endif assert(numberOfBytesWritten == fileSize); } @@ -953,20 +765,6 @@ std::vector* ConsoleSaveFileOriginal::getRegionFilesByDimension( return NULL; } -#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) -std::wstring ConsoleSaveFileOriginal::getPlayerDataFilenameForLoad( - const PlayerUID& pUID) { - return header.getPlayerDataFilenameForLoad(pUID); -} -std::wstring ConsoleSaveFileOriginal::getPlayerDataFilenameForSave( - const PlayerUID& pUID) { - return header.getPlayerDataFilenameForSave(pUID); -} -std::vector* ConsoleSaveFileOriginal::getValidPlayerDatFiles() { - return header.getValidPlayerDatFiles(); -} -#endif - int ConsoleSaveFileOriginal::getSaveVersion() { return header.getSaveVersion(); } diff --git a/Minecraft.World/IO/Files/File.cpp b/Minecraft.World/IO/Files/File.cpp index fb09c1a4f..2b8f95c8d 100644 --- a/Minecraft.World/IO/Files/File.cpp +++ b/Minecraft.World/IO/Files/File.cpp @@ -3,29 +3,14 @@ #include "../../Level/Storage/McRegionLevelStorageSource.h" #include "File.h" -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) #include #include -#endif - -#ifdef __PS3__ -#include -#endif -#ifdef __PSVITA__ -#include -#endif const wchar_t File::pathSeparator = L'/'; -#ifdef _XBOX -const std::wstring File::pathRoot = - L"GAME:"; // Path root after pathSeparator has been removed -#else const std::wstring File::pathRoot = L""; // Path root after pathSeparator has been removed -#endif -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) namespace { namespace fs = std::filesystem; @@ -39,15 +24,14 @@ std::wstring ToFilename(const fs::path& path) { return filenametowstring(filename.c_str()); } -int64_t ToEpochMilliseconds(const fs::file_time_type& fileTime) { +__int64 ToEpochMilliseconds(const fs::file_time_type& fileTime) { using namespace std::chrono; const auto systemTime = time_point_cast( fileTime - fs::file_time_type::clock::now() + system_clock::now()); - return static_cast(systemTime.time_since_epoch().count()); + return static_cast<__int64>(systemTime.time_since_epoch().count()); } } // namespace -#endif // Creates a new File instance from a parent abstract pathname and a child // pathname string. @@ -74,11 +58,6 @@ File::File(const std::wstring& pathname) //: parent( NULL ) std::string finalPath = StorageManager.GetMountedPath(path.c_str()); if (finalPath.size() == 0) finalPath = path; m_abstractPathName = convStringToWstring(finalPath); -#elif defined(_DURANGO) - std::wstring finalPath = - StorageManager.GetMountedPath(m_abstractPathName.c_str()); - if (finalPath.size() == 0) finalPath = m_abstractPathName; - m_abstractPathName = finalPath; #endif /* std::vector path = stringSplit( pathname, pathSeparator ); @@ -133,10 +112,8 @@ this->parent = NULL; // deleted. Returns: true if and only if the file or directory is successfully // deleted; false otherwise bool File::_delete() { -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) std::error_code error; const bool result = fs::remove(ToFilesystemPath(getPath()), error); -#if defined _UNICODE if (!result || error) { #ifndef _CONTENT_PACKAGE printf("File::_delete - Error code %d (%#0.8X)\n", error.value(), @@ -145,58 +122,14 @@ bool File::_delete() { return false; } return true; -#elif defined(__linux__) - if (!result || error) { - printf("Unable to delete file :("); - return false; - } - return true; -#else - if (!result || error) { -#ifndef _CONTENT_PACKAGE - printf("File::_delete - Error code %d (%#0.8X)\n", error.value(), - error.value()); -#endif - return false; - } - return true; -#endif -#elif defined _UNICODE - const bool result = DeleteFile(getPath().c_str()) != 0; -#elif defined(__linux__) - // FIXME - const bool result = false; -#else - const bool result = DeleteFile(wstringtofilename(getPath())) != 0; -#endif - if (!result) { -#if !defined(__linux__) - const unsigned int error = GetLastError(); -#ifndef _CONTENT_PACKAGE - printf("File::_delete - Error code %d (%#0.8X)\n", error, error); -#endif -#else - printf("Unable to delete file :("); -#endif - return false; - } else - return true; } // Creates the directory named by this abstract pathname. // Returns: // true if and only if the directory was created; false otherwise bool File::mkdir() const { -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) std::error_code error; return fs::create_directory(ToFilesystemPath(getPath()), error); -#elif defined(_UNICODE) - return CreateDirectory(getPath().c_str(), NULL) != 0; -#elif defined(__linux__) - return ::mkdir(wstringtofilename(getPath()), 0777) == 0; -#else - return CreateDirectory(wstringtofilename(getPath()), NULL) != 0; -#endif } // Creates the directory named by this abstract pathname, including any @@ -219,7 +152,6 @@ bool File::mkdir() const { // parent directories to be created // bool File::mkdirs() const { -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) std::error_code error; const fs::path path = ToFilesystemPath(getPath()); @@ -232,55 +164,6 @@ bool File::mkdirs() const { } return fs::create_directories(path, error); -#else - std::vector path = - stringSplit(m_abstractPathName, pathSeparator); - - std::wstring pathToHere = L""; - AUTO_VAR(itEnd, path.end()); - for (AUTO_VAR(it, path.begin()); it != itEnd; it++) { - // If this member of the vector is the root then just skip to the next - if (pathRoot.compare(*it) == 0) { - pathToHere = *it; - continue; - } - - pathToHere = pathToHere + pathSeparator + *it; - - // if not exists -#ifdef _UNICODE - if (GetFileAttributes(pathToHere.c_str()) == -1) { - const bool result = CreateDirectory(pathToHere.c_str(), NULL) != 0; - if (!result) { - // Failed to create - return false; - } - } -#elif defined(__linux__) - const char* mkpath = wstringtofilename(getPath()); - struct stat info; - if (stat(mkpath, &info) != 0 || !(info.st_mode & S_IFDIR)) { - if (::mkdir(mkpath, 0777) != 0) { - return false; - } - } -#else - if (GetFileAttributes(wstringtofilename(pathToHere)) == -1) { - const bool result = - CreateDirectory(wstringtofilename(pathToHere), NULL) != 0; - if (!result) { - // Failed to create - return false; - } - } -#endif - } - - // We should now exist - assert(exists()); - - return true; -#endif } /* @@ -297,17 +180,8 @@ return (File *) parent; bool File::exists() const { // TODO 4J Stu - Possible we could get an error result from something other // than the file not existing? -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) std::error_code error; return fs::exists(ToFilesystemPath(getPath()), error); -#elif defined(_UNICODE) - return GetFileAttributes(getPath().c_str()) != -1; -#elif defined(__linux__) - // BAD DOBBY BAD DOBBY - return access(wstringtofilename(getPath()), F_OK) != -1; -#else - return GetFileAttributes(wstringtofilename(getPath())) != -1; -#endif } // Tests whether the file denoted by this abstract pathname is a normal file. A @@ -328,7 +202,6 @@ bool File::isFile() const { return exists() && !isDirectory(); } // Returns: // true if and only if the renaming succeeded; false otherwise bool File::renameTo(File dest) { -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) std::error_code error; fs::rename(ToFilesystemPath(getPath()), ToFilesystemPath(dest.getPath()), error); @@ -337,19 +210,6 @@ bool File::renameTo(File dest) { return false; } return true; -#else - std::string sourcePath = wstringtofilename(getPath()); - std::string destPath = wstringtofilename(dest.getPath()); - - int result = rename(sourcePath.c_str(), destPath.c_str()); - - if (result != 0) { - perror("File::renameTo - Error renaming file"); - return false; - } else { - return true; - } -#endif } // Returns an array of abstract pathnames denoting the files in the directory @@ -378,132 +238,11 @@ std::vector* File::listFiles() const { // TODO 4J Stu - Also need to check for I/O errors? if (!isDirectory()) return vOutput; -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) std::error_code error; for (fs::directory_iterator it(ToFilesystemPath(getPath()), error); !error && it != fs::directory_iterator(); it.increment(error)) { vOutput->push_back(new File(*this, ToFilename(it->path()))); } -#else -#ifdef __PS3__ - const char* lpFileName = wstringtofilename(getPath()); - char filePath[256]; - - std::string mountedPath = StorageManager.GetMountedPath(lpFileName); - if (mountedPath.length() > 0) { - strcpy(filePath, mountedPath.c_str()); - } else if (lpFileName[0] == '/') // already fully qualified path - strcpy(filePath, lpFileName); - else - sprintf(filePath, "%s/%s", getUsrDirPath(), lpFileName); - int fd; - CellFsErrno err = cellFsOpendir(filePath, &fd); - - CellFsDirectoryEntry de; - std::uint32_t count = 0; - err = cellFsGetDirectoryEntries(fd, &de, sizeof(CellFsDirectoryEntry), - &count); - if (count != 0) { - do { - if (de.attribute.st_mode & CELL_FS_S_IFREG) - vOutput->push_back( - new File(*this, filenametowstring(de.entry_name.d_name))); - err = cellFsGetDirectoryEntries( - fd, &de, sizeof(CellFsDirectoryEntry), &count); - } while (count); - } - err = cellFsClose(fd); -#elif defined __ORBIS__ || defined __PSVITA__ - const char* lpFileName = wstringtofilename(getPath()); - char filePath[256]; - - std::string mountedPath = StorageManager.GetMountedPath(lpFileName); - if (mountedPath.length() > 0) { - strcpy(filePath, mountedPath.c_str()); - } else if (lpFileName[0] == '/') // already fully qualified path - strcpy(filePath, lpFileName); - else - sprintf(filePath, "%s/%s", getUsrDirPath(), lpFileName); - - bool exists = sceFiosDirectoryExistsSync(NULL, filePath); - if (!exists) { - app.DebugPrintf( - "\nsceFiosDirectoryExistsSync - Directory doesn't exist\n"); - } - - // CD - Vita note: sceFiosDHOpenSync returns SCE_FIOS_ERROR_UNIMPLEMENTED - // CD - The Handle also returns as 0 [dh], sceFiosDHOpen could also be - // failing CD - Hence, this fails stating 0 files in directory - - SceFiosDH dh = SCE_FIOS_DH_INVALID; - SceFiosBuffer buf; - buf.length = 0; - SceFiosOp op = sceFiosDHOpen(NULL, &dh, filePath, buf); - - int err = sceFiosOpWait(op); - if (err != SCE_FIOS_OK) { - app.DebugPrintf("\nsceFiosOpWait = 0x%x\n", err); - } - SceFiosSize size = sceFiosOpGetActualCount(op); - char* pBuf = new char[size]; - buf.set(pBuf, (size_t)size); - - sceFiosOpDelete(op); - sceFiosDHClose(NULL, dh); - - err = sceFiosDHOpenSync(NULL, &dh, filePath, buf); - if (err != SCE_FIOS_OK) { - app.DebugPrintf("\nsceFiosDHOpenSync = 0x%x\n", err); - } - SceFiosDirEntry entry; - ZeroMemory(&entry, sizeof(SceFiosDirEntry)); - err = sceFiosDHReadSync(NULL, dh, &entry); - while (err == SCE_FIOS_OK) { - vOutput->push_back(new File( - *this, filenametowstring(entry.fullPath + entry.offsetToName))); - ZeroMemory(&entry, sizeof(SceFiosDirEntry)); - err = sceFiosDHReadSync(NULL, dh, &entry); - }; - - sceFiosDHClose(NULL, dh); - delete pBuf; -#else - -#if defined(__linux__) - struct stat wfd; -#else // _WIN32 - WIN32_FIND_DATA wfd; -#endif // __linux__ - -#ifdef _UNICODE - WCHAR path[MAX_PATH]; - swprintf(path, L"%ls\\*", getPath().c_str()); - HANDLE hFind = FindFirstFile(path, &wfd); - if (hFind != INVALID_HANDLE_VALUE) { - int count = 0; - do { - vOutput->push_back(new File(*this, wfd.cFileName)); - } while (FindNextFile(hFind, &wfd)); - FindClose(hFind); - } -#elif defined(__linux__) - char path[MAX_PATH]; - ::listFiles(path); -#else - char path[MAX_PATH]; - sprintf(path, "%s\\*", wstringtofilename(getPath())); - HANDLE hFind = FindFirstFile(path, &wfd); - if (hFind != INVALID_HANDLE_VALUE) { - // int count = 0; - do { - vOutput->push_back( - new File(*this, filenametowstring(wfd.cFileName))); - } while (FindNextFile(hFind, &wfd)); - FindClose(hFind); - } -#endif -#endif -#endif return vOutput; } @@ -525,7 +264,6 @@ std::vector* File::listFiles(FileFilter* filter) const { std::vector* vOutput = new std::vector(); -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) std::error_code error; for (fs::directory_iterator it(ToFilesystemPath(getPath()), error); !error && it != fs::directory_iterator(); it.increment(error)) { @@ -534,82 +272,6 @@ std::vector* File::listFiles(FileFilter* filter) const { vOutput->push_back(new File(thisFile)); } } -#else -#ifdef __PS3__ - const char* lpFileName = wstringtofilename(getPath()); - char filePath[256]; - - std::string mountedPath = StorageManager.GetMountedPath(lpFileName); - if (mountedPath.length() > 0) { - strcpy(filePath, mountedPath.c_str()); - } else if (lpFileName[0] == '/') // already fully qualified path - strcpy(filePath, lpFileName); - else - sprintf(filePath, "%s/%s", getUsrDirPath(), lpFileName); - int fd; - CellFsErrno err = cellFsOpendir(filePath, &fd); - - CellFsDirectoryEntry de; - std::uint32_t count = 0; - err = cellFsGetDirectoryEntries(fd, &de, sizeof(CellFsDirectoryEntry), - &count); - if (count != 0) { - do { - File thisFile = - File(*this, filenametowstring(de.entry_name.d_name)); - if (filter->accept(&thisFile)) { - File storageFile = thisFile; - if (de.attribute.st_mode & CELL_FS_S_IFREG) - vOutput->push_back(&storageFile); - } - err = cellFsGetDirectoryEntries( - fd, &de, sizeof(CellFsDirectoryEntry), &count); - } while (count); - } - err = cellFsClose(fd); -#else - -#ifdef _UNICODE - - WCHAR path[MAX_PATH]; - WIN32_FIND_DATA wfd; - - swprintf(path, L"%ls\\*", getPath().c_str()); - HANDLE hFind = FindFirstFile(path, &wfd); - if (hFind != INVALID_HANDLE_VALUE) { - int count = 0; - do { - File thisFile = File(*this, wfd.cFileName); - if (filter->accept(&thisFile)) { - File storageFile = thisFile; - vOutput->push_back(&storageFile); - } - } while (FindNextFile(hFind, &wfd)); - FindClose(hFind); - } -#elif defined(__linux__) - char path[MAX_PATH]; - ::listFiles(path); -#else - char path[MAX_PATH]; - WIN32_FIND_DATA wfd; - - sprintf(path, "%s\\*", wstringtofilename(getPath())); - HANDLE hFind = FindFirstFile(path, &wfd); - if (hFind != INVALID_HANDLE_VALUE) { - // int count = 0; - do { - File thisFile = File(*this, filenametowstring(wfd.cFileName)); - if (filter->accept(&thisFile)) { - File storageFile = thisFile; - vOutput->push_back(&storageFile); - } - } while (FindNextFile(hFind, &wfd)); - FindClose(hFind); - } -#endif -#endif -#endif return vOutput; } @@ -618,132 +280,33 @@ std::vector* File::listFiles(FileFilter* filter) const { // true if and only if the file denoted by this abstract pathname exists and is // a directory; false otherwise bool File::isDirectory() const { -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) std::error_code error; return fs::is_directory(ToFilesystemPath(getPath()), error); -#elif defined(_UNICODE) - return exists() && (GetFileAttributes(getPath().c_str()) & - FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; -#elif defined(__linux__) - const char* dirpath = wstringtofilename(getPath()); - struct stat st; - return stat(dirpath, &st) == 0 && S_ISDIR(st.st_mode); -#else - return exists() && (GetFileAttributes(wstringtofilename(getPath())) & - FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; -#endif } // Returns the length of the file denoted by this abstract pathname. The return // value is unspecified if this pathname denotes a directory. Returns: The // length, in bytes, of the file denoted by this abstract pathname, or 0L if the // file does not exist -int64_t File::length() { -#ifdef __PS3__ - // extern const char* getPS3HomePath(); - CellFsErrno err = 0; - const char* lpFileName = wstringtofilename(getPath()); - char filePath[256]; - - std::string mountedPath = StorageManager.GetMountedPath(lpFileName); - if (mountedPath.length() > 0) { - strcpy(filePath, mountedPath.c_str()); - } else if (lpFileName[0] == '/') // already fully qualified path - strcpy(filePath, lpFileName); - else - sprintf(filePath, "%s/%s", getUsrDirPath(), lpFileName); - -#ifndef _CONTENT_PACKAGE - // printf("+++File::length - %s\n",filePath); -#endif - // check if the file exists first - CellFsStat statData; - err = cellFsStat(filePath, &statData); - - if (err != CELL_FS_SUCCEEDED) { - // printf("+++File::length FAILED with %d\n",err); - return 0; - } - if (statData.st_mode == CELL_FS_S_IFDIR) { - // printf("+++File::length FAILED with %d\n",err); - return 0; - } - - // printf("+++File::length - %ll\n",statData.st_size); - - return statData.st_size; -#elif defined __ORBIS__ || defined __PSVITA__ - - char filePath[256]; - const char* lpFileName = wstringtofilename(getPath()); - - std::string mountedPath = StorageManager.GetMountedPath(lpFileName); - if (mountedPath.length() > 0) { - strcpy(filePath, mountedPath.c_str()); - } else if (lpFileName[0] == '/') // already fully qualified path - strcpy(filePath, lpFileName); - else - sprintf(filePath, "%s/%s", getUsrDirPath(), lpFileName); - - // check if the file exists first - SceFiosStat statData; - if (sceFiosStatSync(NULL, filePath, &statData) != SCE_FIOS_OK) { - return 0; - } - if (statData.statFlags & SCE_FIOS_STATUS_DIRECTORY) { - return 0; - } - return statData.fileSize; -#elif !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) +__int64 File::length() { std::error_code error; const fs::path path = ToFilesystemPath(getPath()); if (fs::is_regular_file(path, error)) { const auto size = fs::file_size(path, error); if (!error) { - return static_cast(size); + return static_cast<__int64>(size); } } return 0; -#else - WIN32_FILE_ATTRIBUTE_DATA fileInfoBuffer; -#ifdef _UNICODE - const bool result = - GetFileAttributesEx(getPath().c_str(), // file or directory name - GetFileExInfoStandard, // attribute - &fileInfoBuffer // attribute information - ) != 0; -#else - const bool result = - GetFileAttributesEx( - wstringtofilename(getPath()), // file or directory name - GetFileExInfoStandard, // attribute - &fileInfoBuffer // attribute information - ) != 0; -#endif - - if (result && !((fileInfoBuffer.dwFileAttributes & - FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) { - // Success - LARGE_INTEGER liFileSize; - liFileSize.HighPart = fileInfoBuffer.nFileSizeHigh; - liFileSize.LowPart = fileInfoBuffer.nFileSizeLow; - - return liFileSize.QuadPart; - } else { - // Fail or a Directory - return 0l; - } -#endif } // Returns the time that the file denoted by this abstract pathname was last // modified. Returns: A long value representing the time the file was last // modified, measured in milliseconds since the epoch (00:00:00 GMT, January 1, // 1970), or 0L if the file does not exist or if an I/O error occurs -int64_t File::lastModified() { -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) +__int64 File::lastModified() { std::error_code error; const fs::path path = ToFilesystemPath(getPath()); @@ -756,44 +319,6 @@ int64_t File::lastModified() { } return 0l; -#elif !defined(__linux__) - WIN32_FILE_ATTRIBUTE_DATA fileInfoBuffer; -#ifdef _UNICODE - const bool result = - GetFileAttributesEx(getPath().c_str(), // file or directory name - GetFileExInfoStandard, // attribute - &fileInfoBuffer // attribute information - ) != 0; -#else - const bool result = - GetFileAttributesEx( - wstringtofilename(getPath()), // file or directory name - GetFileExInfoStandard, // attribute - &fileInfoBuffer // attribute information - ) != 0; -#endif - - if (result && !((fileInfoBuffer.dwFileAttributes & - FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) { - // Success - LARGE_INTEGER liLastModified; - liLastModified.HighPart = fileInfoBuffer.ftLastWriteTime.dwHighDateTime; - liLastModified.LowPart = fileInfoBuffer.ftLastWriteTime.dwLowDateTime; - - return liLastModified.QuadPart; - } else { - // Fail or a Directory - return 0l; - } -#else - struct stat fileStat; - if (stat(wstringtofilename(getPath()), &fileStat) == 0 && - !S_ISDIR(fileStat.st_mode)) { - return static_cast(fileStat.st_mtime); - } else { - return 0l; - } -#endif } const std::wstring File::getPath() const { @@ -834,4 +359,4 @@ int File::hash_fnct(const File& k) { } return (int)hashCode; -} +} \ No newline at end of file diff --git a/Minecraft.World/IO/Files/FileHeader.cpp b/Minecraft.World/IO/Files/FileHeader.cpp index c3d080c4d..dccee366b 100644 --- a/Minecraft.World/IO/Files/FileHeader.cpp +++ b/Minecraft.World/IO/Files/FileHeader.cpp @@ -643,4 +643,4 @@ ByteOrder FileHeader::getEndian(ESavePlatform plat) { break; } return LITTLEENDIAN; -} +} \ No newline at end of file diff --git a/Minecraft.World/IO/Files/FileHeader.h b/Minecraft.World/IO/Files/FileHeader.h index 2e3e23854..94f14cf57 100644 --- a/Minecraft.World/IO/Files/FileHeader.h +++ b/Minecraft.World/IO/Files/FileHeader.h @@ -225,4 +225,4 @@ protected: bool isLocalEndianDifferent(ESavePlatform plat) { return m_localEndian != getEndian(plat); } -}; +}; \ No newline at end of file diff --git a/Minecraft.World/Level/Storage/McRegionChunkStorage.cpp b/Minecraft.World/Level/Storage/McRegionChunkStorage.cpp index cef015625..0e267e0e7 100644 --- a/Minecraft.World/Level/Storage/McRegionChunkStorage.cpp +++ b/Minecraft.World/Level/Storage/McRegionChunkStorage.cpp @@ -1,6 +1,7 @@ #include "../../Platform/stdafx.h" #include "../../Headers/net.minecraft.world.level.h" #include "../../IO/Files/ConsoleSaveFileIO.h" +#include "../../Util/ThreadName.h" #include "../LevelData.h" #include "McRegionChunkStorage.h" @@ -452,3 +453,4 @@ void McRegionChunkStorage::WaitForSaves() { } } } + diff --git a/Minecraft.World/Platform/stdafx.h b/Minecraft.World/Platform/stdafx.h index 44cf96ff5..254beb01f 100644 --- a/Minecraft.World/Platform/stdafx.h +++ b/Minecraft.World/Platform/stdafx.h @@ -4,103 +4,31 @@ // #pragma once -#ifdef __PS3__ -#else #define AUTO_VAR(_var, _val) auto _var = _val -#endif -#if (defined _XBOX || defined _WINDOWS64 || defined _DURANGO) -typedef unsigned int64_t uint64_t; +#ifdef _WINDOWS64 +typedef unsigned __int64 __uint64; #endif #ifdef _WINDOWS64 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -// Windows Header Files: #include #include #include -// TODO: reference additional headers your program requires here #include #endif -#ifdef _DURANGO -#include -#include -#include -#include -using namespace DirectX; -#include -#include "../../Minecraft.Client/Platform/Durango/DurangoExtras/DurangoStubs.h" -#endif - -#if (defined __PS3__ || defined _XBOX) -// C RunTime Header Files -#include -#endif - -#ifdef __ORBIS__ -#include -#include -#include -#include -#include -#include -#include -#endif - -#ifdef _XBOX -#include -#include -#include -#include -typedef XINVITE_INFO INVITE_INFO; -typedef XUID PlayerUID; -typedef XNKID SessionID; -typedef XUID GameSessionUID; -#endif - -#ifdef __PS3__ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../Minecraft.Client/Platform/PS3/PS3Extras/Ps3Types.h" -#include "../../Minecraft.Client/Platform/PS3/PS3Extras/Ps3Stubs.h" -#include "../../Minecraft.Client/Platform/PS3/PS3Extras/PS3Maths.h" - -#elif defined __ORBIS__ +#ifdef __linux__ #include #include #include -#include "../../Minecraft.Client/Platform/Orbis/OrbisExtras/OrbisTypes.h" -#include "../../Minecraft.Client/Platform/Orbis/OrbisExtras/OrbisStubs.h" -#include "../../Minecraft.Client/Platform/Orbis/OrbisExtras/OrbisMaths.h" -#elif defined __PSVITA__ -#include -#include -#include -#include -#include "../../Minecraft.Client/Platform/PSVita/PSVitaExtras/PSVitaTypes.h" -#include "../../Minecraft.Client/Platform/PSVita/PSVitaExtras/PSVitaStubs.h" -#include "../../Minecraft.Client/Platform/PSVita/PSVitaExtras/PSVitaMaths.h" -#elif defined(__linux__) -#include -#include -#include - #include "../../Minecraft.Client/Platform/Linux/Stubs/LinuxStubs.h" #else #include #include #include #include -#endif //__PS3__ +#endif #include @@ -119,10 +47,7 @@ typedef XUID GameSessionUID; #include #include -#ifndef __PS3__ // the PS3 lib assert is rubbish, and aborts the code, we - // define our own in PS3Types.h #include -#endif #include "../Util/Definitions.h" #include "../Util/Class.h" @@ -147,58 +72,26 @@ typedef XUID GameSessionUID; void MemSect(int sect); -#ifdef _XBOX -#include "../Minecraft.Client/xbox/4JLibs/inc/4J_Profile.h" -#include "../Minecraft.Client/xbox/4JLibs/inc/4J_Render.h" -#include "../Minecraft.Client/xbox/4JLibs/inc/4J_XTMS.h" -#include "../Minecraft.Client/xbox/4JLibs/inc/4J_Storage.h" -#include "../Minecraft.Client/xbox/4JLibs/inc/4J_Input.h" -#elif defined(__PS3__) -#include "../../Minecraft.Client/Platform/PS3/4JLibs/inc/4J_Profile.h" -#include "../../Minecraft.Client/Platform/PS3/4JLibs/inc/4J_Render.h" -#include "../../Minecraft.Client/Platform/PS3/4JLibs/inc/4J_Storage.h" -#include "../../Minecraft.Client/Platform/PS3/4JLibs/inc/4J_Input.h" -#elif defined _DURANGO -#include "../../Minecraft.Client/Platform/Durango/4JLibs/inc/4J_Profile.h" -#include "../../Minecraft.Client/Platform/Durango/4JLibs/inc/4J_Render.h" -#include "../../Minecraft.Client/Platform/Durango/4JLibs/inc/4J_Storage.h" -#include "../../Minecraft.Client/Platform/Durango/4JLibs/inc/4J_Input.h" -#elif defined _WINDOWS64 +#ifdef _WINDOWS64 #include "../../Minecraft.Client/Platform/Windows64/4JLibs/inc/4J_Profile.h" #include "../../Minecraft.Client/Platform/Windows64/4JLibs/inc/4J_Render.h" #include "../../Minecraft.Client/Platform/Windows64/4JLibs/inc/4J_Storage.h" #include "../../Minecraft.Client/Platform/Windows64/4JLibs/inc/4J_Input.h" -#elif defined __PSVITA__ -#include "../../Minecraft.Client/Platform/PSVita/4JLibs/inc/4J_Profile.h" -#include "../../Minecraft.Client/Platform/PSVita/4JLibs/inc/4J_Render.h" -#include "../../Minecraft.Client/Platform/PSVita/4JLibs/inc/4J_Storage.h" -#include "../../Minecraft.Client/Platform/PSVita/4JLibs/inc/4J_Input.h" -#elif defined __linux__ +#else #include "4J_Profile.h" #include "4J_Render.h" #include "4J_Storage.h" #include "4J_Input.h" -#else -#include "../../Minecraft.Client/Platform/Orbis/4JLibs/inc/4J_Profile.h" -#include "../../Minecraft.Client/Platform/Orbis/4JLibs/inc/4J_Render.h" -#include "../../Minecraft.Client/Platform/Orbis/4JLibs/inc/4J_Storage.h" -#include "../../Minecraft.Client/Platform/Orbis/4JLibs/inc/4J_Input.h" #endif #include "../../Minecraft.Client/Platform/Common/Network/GameNetworkManager.h" -// #ifdef _XBOX #include "../../Minecraft.Client/Platform/Common/UI/UIEnums.h" #include "../../Minecraft.Client/Platform/Common/App_Defines.h" #include "../../Minecraft.Client/Platform/Common/App_enums.h" #include "../../Minecraft.Client/Platform/Common/Tutorial/TutorialEnum.h" #include "../../Minecraft.Client/Platform/Common/App_structs.h" -// #endif -#ifdef _XBOX -#include "../../Minecraft.Client/Platform/Common/XUI/XUI_Helper.h" -#include "../../Minecraft.Client/Platform/Common/XUI/XUI_Scene_Base.h" -#endif #include "../../Minecraft.Client/Platform/Common/Consoles_App.h" #include "../../Minecraft.Client/Platform/Common/Minecraft_Macros.h" #include "../../Minecraft.Client/Platform/Common/Colours/ColourTable.h" @@ -208,50 +101,16 @@ void MemSect(int sect); // This is generated at build time via scripts/pack_loc.py #include "strings.h" -// This is generated at build time via scripts/pack_loc.py -#include "strings.h" - -#ifdef _XBOX -#include "../../Minecraft.Client/Platform/Xbox/Xbox_App.h" -#include "../../Minecraft.Client/Platform/Xbox/Sentient/SentientTelemetryCommon.h" -#include "../../Minecraft.Client/Platform/Xbox/Sentient/MinecraftTelemetry.h" - -#elif defined(__PS3__) -#include "../../Minecraft.Client/Platform/PS3/PS3_App.h" -#include "../../Minecraft.Client/Platform/PS3/Sentient/SentientTelemetryCommon.h" -#include "../../Minecraft.Client/Platform/PS3/Sentient/MinecraftTelemetry.h" - -#elif defined _DURANGO -#include "../../Minecraft.Client/Platform/Durango/Durango_App.h" -// #include "../../Minecraft.Client/Platform/Durango/Sentient/SentientManager.h" -#include "../../Minecraft.Client/Platform/Durango/Sentient/SentientTelemetryCommon.h" -#include "../../Minecraft.Client/Platform/Durango/Sentient/MinecraftTelemetry.h" -#include "../../Minecraft.Client/Platform/Durango/Sentient/TelemetryEnum.h" - -#elif defined _WINDOWS64 +#ifdef _WINDOWS64 #include "../../Minecraft.Client/Platform/Windows64/Windows64_App.h" #include "../../Minecraft.Client/Platform/Windows64/Sentient/SentientTelemetryCommon.h" #include "../../Minecraft.Client/Platform/Windows64/Sentient/MinecraftTelemetry.h" - -#elif defined __PSVITA__ -#include "../../Minecraft.Client/Platform/PSVita/PSVita_App.h" -#include "../../Minecraft.Client/Platform/PSVita/Sentient/SentientManager.h" -#include "../../Minecraft.Client/Platform/PSVita/Sentient/MinecraftTelemetry.h" -#elif defined(__linux__) -// Use Orbis-compatible headers on Linux (same as -// Minecraft.Client/Platform/stdafx.h). All Orbis Sentient headers have #pragma -// once, preventing double-inclusion when DLC/other Common files also pull in -// Minecraft.Client stdafx.h. +#else +// Use the Linux runtime path with supported metadata/config headers only. #include "../../Minecraft.Client/Platform/Linux/Linux_App.h" #include "../../Minecraft.Client/Platform/Linux/Sentient/SentientTelemetryCommon.h" #include "../../Minecraft.Client/Platform/Linux/Sentient/DynamicConfigurations.h" -#include "../../Minecraft.Client/Platform/Orbis/GameConfig/Minecraft.spa.h" -// #include -// "../../Minecraft.Client/Platform/Windows64/Sentient/MinecraftTelemetry.h" -#else -#include "../../Minecraft.Client/Platform/Orbis/Orbis_App.h" -#include "../../Minecraft.Client/Platform/Orbis/Sentient/SentientTelemetryCommon.h" -#include "../../Minecraft.Client/Platform/Orbis/Sentient/MinecraftTelemetry.h" +#include "../../Minecraft.Client/Platform/Windows64/GameConfig/Minecraft.spa.h" #endif #include "../../Minecraft.Client/Platform/Common/DLC/DLCSkinFile.h" diff --git a/Minecraft.World/Platform/x64headers/extraX64.h b/Minecraft.World/Platform/x64headers/extraX64.h index b7115bc77..7b6fadc9a 100644 --- a/Minecraft.World/Platform/x64headers/extraX64.h +++ b/Minecraft.World/Platform/x64headers/extraX64.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "4J_Compat.h" #include "../../../Minecraft.Client/Rendering/Models/SkinBox.h" @@ -14,107 +15,46 @@ #define MULTITHREAD_ENABLE typedef unsigned char byte; - -#ifdef __PSVITA__ -constexpr int MINECRAFT_NET_MAX_PLAYERS = 4; -#else constexpr int MINECRAFT_NET_MAX_PLAYERS = 8; -#endif static_assert( MINECRAFT_NET_MAX_PLAYERS <= std::numeric_limits::max(), "MINECRAFT_NET_MAX_PLAYERS must fit in the 8-bit network protocol"); -#ifdef __ORBIS__ -#include -#include -#include -#include "../../../Minecraft.Client/Platform/Orbis/Orbis_PlayerUID.h" -#include "../../../Minecraft.Client/Platform/Orbis/Network/SQRNetworkManager_Orbis.h" -typedef SQRNetworkManager_Orbis::SessionID SessionID; -typedef SQRNetworkManager_Orbis::PresenceSyncInfo INVITE_INFO; - -#elif defined __PS3__ // defined in the profile lib -#include -#include -#include -#include -#include -#include "../../../Minecraft.Client/Platform/PS3/PS3_PlayerUID.h" -#include "../../../Minecraft.Client/Platform/PS3/Network/SQRNetworkManager_PS3.h" -typedef SQRNetworkManager::SessionID SessionID; -typedef SQRNetworkManager::PresenceSyncInfo INVITE_INFO; - -#elif defined __PSVITA__ -#include -#include -#include -#include "../../../Minecraft.Client/Platform/PSVita/PSVita_PlayerUID.h" -#include "../../../Minecraft.Client/Platform/PSVita/Network/SQRNetworkManager_Vita.h" -#include "../../../Minecraft.Client/Platform/PSVita/Network/SQRNetworkManager_AdHoc_Vita.h" -typedef SQRNetworkManager_Vita::SessionID SessionID; -typedef SQRNetworkManager_Vita::PresenceSyncInfo INVITE_INFO; - -#elif defined _DURANGO -#include "../../../Minecraft.Client/Platform/Durango/4JLibs/inc/4J_Profile.h" -#include "../../../Minecraft.Client/Platform/Durango/Network/DQRNetworkManager.h" -typedef ULONGLONG SessionID; -typedef ULONGLONG GameSessionUID; -typedef DQRNetworkManager::SessionInfo INVITE_INFO; -#else typedef ULONGLONG SessionID; typedef PlayerUID GameSessionUID; class INVITE_INFO; -#endif // __PS3__ - typedef struct _XUIOBJ* HXUIOBJ; typedef struct _XUICLASS* HXUICLASS; typedef struct _XUIBRUSH* HXUIBRUSH; typedef struct _XUIDC* HXUIDC; -// #ifdef _DURANGO -// void GetLocalTime(SYSTEMTIME *time); -// #endif - bool IsEqualXUID(PlayerUID a, PlayerUID b); -// Temporary implementation of lock free stack with quite a bit more locking -// than you might expect template class XLockFreeStack { std::vector intStack; + std::mutex m_cs; public: - XLockFreeStack() { -#ifdef __ORBIS__ - OrbisInit(); // For PS4, we need to make sure Ult is set up for the - // critical sections to be able to initialise -#endif - InitializeCriticalSectionAndSpinCount(&m_cs, 5120); - } - ~XLockFreeStack() { DeleteCriticalSection(&m_cs); } + XLockFreeStack() = default; + ~XLockFreeStack() = default; void Initialize() {} void Push(T* data) { - EnterCriticalSection(&m_cs); + std::lock_guard lock(m_cs); intStack.push_back(data); - LeaveCriticalSection(&m_cs); } T* Pop() { - EnterCriticalSection(&m_cs); + std::lock_guard lock(m_cs); if (intStack.size()) { T* ret = intStack.back(); intStack.pop_back(); - LeaveCriticalSection(&m_cs); return ret; - } else { - LeaveCriticalSection(&m_cs); - return NULL; } - } -private: - CRITICAL_SECTION m_cs; + return NULL; + } }; void XMemCpy(void* a, const void* b, size_t s); @@ -124,8 +64,6 @@ void* XPhysicalAlloc(SIZE_T a, ULONG_PTR b, ULONG_PTR c, DWORD d); void XPhysicalFree(void* a); class DLCManager; - -// class LevelGenerationOptions; class LevelRuleset; class ModelPart; class LevelChunk; @@ -142,10 +80,6 @@ const int XN_SYS_INPUTDEVICESCHANGED = 1; const int XN_LIVE_CONTENT_INSTALLED = 2; const int XN_SYS_STORAGEDEVICESCHANGED = 3; -// -// Codes returned for the gamepad input -// - #define VK_PAD_A 0x5800 #define VK_PAD_B 0x5801 #define VK_PAD_X 0x5802 @@ -257,11 +191,9 @@ typedef struct _XONLINE_FRIEND { SessionID xnkidInvite; FILETIME gameinviteTime; DWORD cchRichPresence; - // WCHAR wszRichPresence[MAX_RICHPRESENCE_SIZE]; } XONLINE_FRIEND, *PXONLINE_FRIEND; class IQNetCallbacks {}; - class IQNetGameSearch {}; typedef enum _QNET_STATE { @@ -297,80 +229,16 @@ public: static IQNetPlayer m_player[4]; }; -#ifdef _DURANGO -// 4J Stu - We don't want to be doing string conversions at runtime for timing -// instrumentation, so do this instead -#define PIXBeginNamedEvent(a, b, ...) PIXBeginEvent(a, L##b, __VA_ARGS__) -#define PIXEndNamedEvent() PIXEndEvent() -#define PIXSetMarkerDeprecated(a, b, ...) PIXSetMarker(a, L##b, __VA_ARGS__) -#define PIXAddNamedCounter(a, b) PIXReportCounter(L##b, a) -#else void PIXAddNamedCounter(int a, const char* b, ...); void PIXBeginNamedEvent(int a, const char* b, ...); void PIXEndNamedEvent(); void PIXSetMarkerDeprecated(int a, const char* b, ...); -#endif void XSetThreadProcessor(HANDLE a, int b); -// BOOL XCloseHandle(HANDLE a); const int QNET_SENDDATA_LOW_PRIORITY = 0; const int QNET_SENDDATA_SECONDARY = 0; -#if defined(__PS3__) || defined(__ORBIS__) || defined(_DURANGO) || \ - defined(__PSVITA__) -#define INVALID_XUID PlayerUID() -#else -const int INVALID_XUID = 0; -#endif -// const int MOJANG_DATA = 0; - -// typedef struct _STRING_VERIFY_RESPONSE -// { -// WORD wNumStrings; -// HRESULT *pStringResult; -// } STRING_VERIFY_RESPONSE; - -#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(_DURANGO) && \ - !defined(__PSVITA__) && !defined(FOURJ_COMMON_XCONTENT_DATA_DEFINED) -typedef int XCONTENTDEVICEID; -#endif //__PS3__ - -#if !defined(_DURANGO) && !defined(FOURJ_COMMON_XMARKETPLACE_DEFINED) -typedef struct _XMARKETPLACE_CONTENTOFFER_INFO { - ULONGLONG qwOfferID; - ULONGLONG qwPreviewOfferID; - DWORD dwOfferNameLength; - WCHAR* wszOfferName; - DWORD dwOfferType; - BYTE contentId[XMARKETPLACE_CONTENT_ID_LEN]; - BOOL fIsUnrestrictedLicense; - DWORD dwLicenseMask; - DWORD dwTitleID; - DWORD dwContentCategory; - DWORD dwTitleNameLength; - WCHAR* wszTitleName; - BOOL fUserHasPurchased; - DWORD dwPackageSize; - DWORD dwInstallSize; - DWORD dwSellTextLength; - WCHAR* wszSellText; - DWORD dwAssetID; - DWORD dwPurchaseQuantity; - DWORD dwPointsPrice; -} XMARKETPLACE_CONTENTOFFER_INFO, *PXMARKETPLACE_CONTENTOFFER_INFO; - -typedef enum { - XMARKETPLACE_OFFERING_TYPE_CONTENT = 0x00000002, - XMARKETPLACE_OFFERING_TYPE_GAME_DEMO = 0x00000020, - XMARKETPLACE_OFFERING_TYPE_GAME_TRAILER = 0x00000040, - XMARKETPLACE_OFFERING_TYPE_THEME = 0x00000080, - XMARKETPLACE_OFFERING_TYPE_TILE = 0x00000800, - XMARKETPLACE_OFFERING_TYPE_ARCADE = 0x00002000, - XMARKETPLACE_OFFERING_TYPE_VIDEO = 0x00004000, - XMARKETPLACE_OFFERING_TYPE_CONSUMABLE = 0x00010000, - XMARKETPLACE_OFFERING_TYPE_AVATARITEM = 0x00100000 -} XMARKETPLACE_OFFERING_TYPE; -#endif // _DURANGO +constexpr PlayerUID INVALID_XUID = 0; const int QNET_SENDDATA_RELIABLE = 0; const int QNET_SENDDATA_SEQUENTIAL = 0; @@ -403,7 +271,6 @@ public: HRESULT Load(LPCWSTR szId); }; -#if !defined(__ORBIS__) && !defined(_XBOX_ONE) typedef VOID* XMEMDECOMPRESSION_CONTEXT; typedef VOID* XMEMCOMPRESSION_CONTEXT; @@ -434,7 +301,6 @@ typedef struct _XMEMCODEC_PARAMETERS_LZX { void XMemDestroyCompressionContext(XMEMCOMPRESSION_CONTEXT Context); void XMemDestroyDecompressionContext(XMEMDECOMPRESSION_CONTEXT Context); -#endif typedef struct { BYTE type; @@ -460,36 +326,6 @@ typedef struct { XUSER_DATA value; } XUSER_PROPERTY, *PXUSER_PROPERTY; -// these need to match apwstrLocaleCode -// const int XC_LANGUAGE_ENGLISH =1; -// const int XC_LANGUAGE_JAPANESE =2; -// const int XC_LANGUAGE_GERMAN =3; -// const int XC_LANGUAGE_FRENCH =4; -// const int XC_LANGUAGE_SPANISH =5; -// const int XC_LANGUAGE_ITALIAN =6; -// const int XC_LANGUAGE_KOREAN =7; -// const int XC_LANGUAGE_TCHINESE =8; -// const int XC_LANGUAGE_PORTUGUESE =9; -// const int XC_LANGUAGE_BRAZILIAN =10; -// #if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ -// const int XC_LANGUAGE_RUSSIAN =11; -// // more PS3 -// const int XC_LANGUAGE_DUTCH =12; -// const int XC_LANGUAGE_FINISH =13; -// const int XC_LANGUAGE_SWEDISH =14; -// const int XC_LANGUAGE_DANISH =15; -// const int XC_LANGUAGE_NORWEGIAN =16; -// const int XC_LANGUAGE_POLISH =17; -// const int XC_LANGUAGE_TURKISH =18; -// const int XC_LANGUAGE_LATINAMERICANSPANISH =19; -// -// const int XC_LANGUAGE_GREEK =20; -// #else -// const int XC_LANGUAGE_UKENGLISH =11; -// const int XC_LANGUAGE_MEXICANSPANISH=12; -// #endif - -// matching Xbox 360 const int XC_LANGUAGE_ENGLISH = 0x01; const int XC_LANGUAGE_JAPANESE = 0x02; const int XC_LANGUAGE_GERMAN = 0x03; @@ -507,13 +343,10 @@ const int XC_LANGUAGE_BNORWEGIAN = 0x0F; const int XC_LANGUAGE_DUTCH = 0x10; const int XC_LANGUAGE_SCHINESE = 0x11; -// for Sony const int XC_LANGUAGE_LATINAMERICANSPANISH = 0xF0; const int XC_LANGUAGE_FINISH = 0xF1; const int XC_LANGUAGE_GREEK = 0xF2; const int XC_LANGUAGE_DANISH = 0xF3; - -// for Xbox One const int XC_LANGUAGE_CZECH = 0xF4; const int XC_LANGUAGE_SLOVAK = 0xF5; @@ -560,16 +393,11 @@ const int XC_LOCALE_ARGENTINA = 40; const int XC_LOCALE_SAUDI_ARABIA = 41; const int XC_LOCALE_ISRAEL = 42; const int XC_LOCALE_UNITED_ARAB_EMIRATES = 43; - -// for Sony const int XC_LOCALE_LATIN_AMERICA = 240; -#if !(defined _DURANGO || defined __PS3__ || defined __ORBIS__ || \ - defined __PSVITA__) DWORD XGetLanguage(); DWORD XGetLocale(); DWORD XEnableGuestSignin(BOOL fEnable); -#endif class D3DXVECTOR3 { public: diff --git a/Minecraft.World/Util/C4JThread.cpp b/Minecraft.World/Util/C4JThread.cpp index ace672d19..ad3ab8cfb 100644 --- a/Minecraft.World/Util/C4JThread.cpp +++ b/Minecraft.World/Util/C4JThread.cpp @@ -1,1065 +1,904 @@ #include "../Platform/stdafx.h" #include "C4JThread.h" -#ifdef __PSVITA__ -#include "../../Minecraft.Client/Platform/PSVita/PSVitaExtras/ShutdownManager.h" -#include "../../Minecraft.Client/Platform/PSVita/PSVitaExtras/PSVitaTLSStorage.h" -// AP - this comes from the low level user_malloc.c file used to overide the -// default memory functions. These must be called when a thread is -// started/stopped -extern "C" { -extern void user_registerthread(); -extern void user_removethread(); +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#endif + +#if defined(__linux__) +#include +#include +#include +#include +#include +#include +#endif + +#include "../../Minecraft.Client/Platform/Common/ShutdownManager.h" + +#if !defined(INFINITE) +#define INFINITE 0xFFFFFFFFu +#endif + +#if !defined(WAIT_OBJECT_0) +#define WAIT_OBJECT_0 0u +#endif + +#if !defined(WAIT_TIMEOUT) +#define WAIT_TIMEOUT 258u +#endif + +#if !defined(STILL_ACTIVE) +#define STILL_ACTIVE 259 +#endif + +#if !defined(THREAD_PRIORITY_IDLE) +#define THREAD_PRIORITY_IDLE (-15) +#endif + +#if !defined(THREAD_PRIORITY_LOWEST) +#define THREAD_PRIORITY_LOWEST (-2) +#endif + +#if !defined(THREAD_PRIORITY_BELOW_NORMAL) +#define THREAD_PRIORITY_BELOW_NORMAL (-1) +#endif + +#if !defined(THREAD_PRIORITY_NORMAL) +#define THREAD_PRIORITY_NORMAL 0 +#endif + +#if !defined(THREAD_PRIORITY_ABOVE_NORMAL) +#define THREAD_PRIORITY_ABOVE_NORMAL 1 +#endif + +#if !defined(THREAD_PRIORITY_HIGHEST) +#define THREAD_PRIORITY_HIGHEST 2 +#endif + +#if !defined(THREAD_PRIORITY_TIME_CRITICAL) +#define THREAD_PRIORITY_TIME_CRITICAL 15 +#endif + +thread_local C4JThread* C4JThread::ms_currentThread = nullptr; + +namespace { + +constexpr int kDefaultStackSize = 65536 * 2; +constexpr int kMinimumStackSize = 16384; +constexpr int kUnsetPriority = std::numeric_limits::min(); +constexpr int kEventQueueShutdownPollMs = 100; + +const std::thread::id g_processMainThreadId = std::this_thread::get_id(); + +template +bool WaitForCondition(std::condition_variable& condition, + std::unique_lock& lock, + int timeoutMs, + Predicate predicate) { + if (timeoutMs < 0 || + static_cast(timeoutMs) == + static_cast(INFINITE)) { + condition.wait(lock, predicate); + return true; + } + + return condition.wait_for(lock, std::chrono::milliseconds(timeoutMs), + predicate); } -#else -#include "../../Minecraft.Client/Platform/PS3/PS3Extras/ShutdownManager.h" +std::uint32_t FirstSetBitIndex(std::uint32_t bitMask) { + return static_cast(std::countr_zero(bitMask)); +} + +std::uint32_t BuildMaskForSize(int size) { + assert(size > 0); + assert(size <= 32); + + if (size == 32) { + return 0xFFFFFFFFU; + } + + return (1U << static_cast(size)) - 1U; +} + +void FormatThreadName(std::string& outThreadName, const char* threadName) { + const char* safeName = + (threadName != nullptr && threadName[0] != '\0') ? threadName : "Unnamed"; + + char buffer[64]; + std::snprintf(buffer, sizeof(buffer), "(4J) %s", safeName); + buffer[sizeof(buffer) - 1] = '\0'; + outThreadName = buffer; +} + +const char* GetSafeThreadName(const char* threadName) { + return (threadName != nullptr && threadName[0] != '\0') ? threadName + : "(4J) Unnamed"; +} + +bool IsProcessorIndexPlausible(int proc) { + if (proc < 0) { + return true; + } + + const unsigned int hardwareThreads = std::thread::hardware_concurrency(); + if (hardwareThreads == 0U) { + return true; + } + + return static_cast(proc) < hardwareThreads; +} + +#if defined(__linux__) +std::int64_t GetLinuxThreadId() { + return static_cast(::syscall(SYS_gettid)); +} + +int MapPriorityToNice(int priority) { + switch (priority) { + case THREAD_PRIORITY_TIME_CRITICAL: + return -15; + case THREAD_PRIORITY_HIGHEST: + return -10; + case THREAD_PRIORITY_ABOVE_NORMAL: + return -5; + case THREAD_PRIORITY_NORMAL: + return 0; + case THREAD_PRIORITY_BELOW_NORMAL: + return 5; + case THREAD_PRIORITY_LOWEST: + return 10; + case THREAD_PRIORITY_IDLE: + return 19; + default: + return 0; + } +} #endif -std::vector C4JThread::ms_threadList; -CRITICAL_SECTION C4JThread::ms_threadListCS; - -#ifdef _XBOX_ONE -// 4J Stu - On XboxOne the main thread is not the one that does all the static -// init, so we have to set this up later -C4JThread* C4JThread::m_mainThread = NULL; - -void C4JThread::StaticInit() { m_mainThread = new C4JThread("Main thread"); } -#else -C4JThread C4JThread::m_mainThread("Main thread"); +#if defined(_WIN32) +thread_local std::vector g_affinityMaskStack; +#elif defined(__linux__) +thread_local std::vector g_affinityMaskStack; #endif -#ifdef __ORBIS__ -__thread SceKernelCpumask C4JThread::m_oldAffinityMask; -#endif - -#if __PSVITA__ -static SceInt32 g_DefaultCPU; -static SceInt32 g_DefaultPriority; -#endif +} // namespace C4JThread::C4JThread(C4JThreadStartFunc* startFunc, void* param, - const char* threadName, int stackSize /* = 0*/) { - m_startFunc = startFunc; - m_threadParam = param; - m_stackSize = stackSize; - - // to match XBox, if the stack size is zero, use the default 64k - if (m_stackSize == 0) m_stackSize = 65536 * 2; - // make sure it's at least 16K - if (m_stackSize < 16384) m_stackSize = 16384; - -#ifdef __PS3__ - sprintf(m_threadName, "(4J) %s", threadName); -#else - sprintf_s(m_threadName, 64, "(4J) %s", threadName); -#endif - - m_isRunning = false; - m_hasStarted = false; - - m_exitCode = STILL_ACTIVE; - -#ifdef __PS3__ - m_completionFlag = new Event(Event::e_modeManualClear); - m_threadID = 0; - m_lastSleepTime = 0; - m_priority = 1002; // main thread has priority 1001 -#elif defined __ORBIS__ - m_completionFlag = new Event(Event::e_modeManualClear); - m_threadID = 0; - m_lastSleepTime = 0; - scePthreadAttrInit(&m_threadAttr); - int err = scePthreadAttrSetaffinity( - &m_threadAttr, - 63); // set the thread affinity to all cores to start with - assert(err == SCE_OK); - m_oldAffinityMask = 0; - m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT; -#elif defined __PSVITA__ - m_completionFlag = new Event(Event::e_modeManualClear); - m_threadID = 0; - m_lastSleepTime = 0; - m_priority = g_DefaultPriority; - // m_CPUMask = SCE_KERNEL_CPU_MASK_USER_ALL; - - // AP - I had trouble getting the cpu to change once the thread was created - // so I've hard coded them here The main work division is... 0 - Main 1 - - // Chunk/Tile Update 2 - Server/Audio These three can sometimes consume ALL - // the CPU time so they are set to below average priority so as not to block - // other critical threads - int CPU = SCE_KERNEL_CPU_MASK_USER_ALL; - if (!strcmp(threadName, "Chunk update")) { - CPU = SCE_KERNEL_CPU_MASK_USER_2; - m_priority = g_DefaultPriority + 1; - } - if (!strcmp(threadName, "Server")) { - CPU = SCE_KERNEL_CPU_MASK_USER_1; - m_priority = g_DefaultPriority + 1; - } - // make sure Tile Update doesn't go on cpu 0 because it will hold up the - // main thread. And it can't go on cpu 1 because Chunk Update crashes. - if (!strcmp(threadName, "Tile update")) { - CPU = SCE_KERNEL_CPU_MASK_USER_1; + const char* threadName, int stackSize) + : m_threadParam(param), + m_startFunc(startFunc), + m_stackSize(stackSize == 0 ? kDefaultStackSize : stackSize), + m_threadName(), + m_isRunning(false), + m_hasStarted(false), + m_exitCode(STILL_ACTIVE), + m_threadID(), + m_threadHandle(), + m_completionFlag(std::make_unique(Event::e_modeManualClear)), + m_requestedProcessor(-1), + m_requestedPriority(kUnsetPriority), + m_nativeTid(0) { + if (m_stackSize < kMinimumStackSize) { + m_stackSize = kMinimumStackSize; } - m_threadID = sceKernelCreateThread( - m_threadName, entryPoint, g_DefaultPriority, m_stackSize, 0, CPU, NULL); - app.DebugPrintf( - "***************************** start thread %s " - "**************************\n", - m_threadName); -#else - m_threadID = 0; - m_threadHandle = 0; - DWORD threadID = 0; - m_threadHandle = CreateThread(NULL, m_stackSize, entryPoint, this, - CREATE_SUSPENDED, &threadID); - m_threadID = threadID; -#endif - EnterCriticalSection(&ms_threadListCS); - ms_threadList.push_back(this); - LeaveCriticalSection(&ms_threadListCS); + FormatThreadName(m_threadName, threadName); } -// only used for the main thread -C4JThread::C4JThread(const char* mainThreadName) { -#ifdef __PSVITA__ - user_registerthread(); -#endif - - m_startFunc = NULL; - m_threadParam = NULL; - m_stackSize = 0; - -#ifdef __PS3__ - sprintf(m_threadName, "(4J) %s", mainThreadName); +C4JThread::C4JThread(const char* mainThreadName) + : m_threadParam(nullptr), + m_startFunc(nullptr), + m_stackSize(0), + m_threadName(), + m_isRunning(true), + m_hasStarted(true), + m_exitCode(STILL_ACTIVE), + m_threadID(std::this_thread::get_id()), + m_threadHandle(), + m_completionFlag(std::make_unique(Event::e_modeManualClear)), + m_requestedProcessor(-1), + m_requestedPriority(kUnsetPriority), +#if defined(__linux__) + m_nativeTid(GetLinuxThreadId()) #else - sprintf_s(m_threadName, 64, "(4J) %s", mainThreadName); + m_nativeTid(0) #endif - m_isRunning = true; - m_hasStarted = true; - m_lastSleepTime = System::currentTimeMillis(); - - // should be the first thread to be created, so init the static critical - // section for the threadlist here - InitializeCriticalSection(&ms_threadListCS); - -#ifdef __PS3__ - m_completionFlag = new Event(Event::e_modeManualClear); - sys_ppu_thread_get_id(&m_threadID); -#elif defined __ORBIS__ - m_completionFlag = new Event(Event::e_modeManualClear); - m_threadID = scePthreadSelf(); - m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT; -#elif defined __PSVITA__ - m_completionFlag = new Event(Event::e_modeManualClear); - g_DefaultPriority = sceKernelGetThreadCurrentPriority(); - m_threadID = sceKernelGetThreadId(); - int err = sceKernelChangeThreadCpuAffinityMask(m_threadID, - SCE_KERNEL_CPU_MASK_USER_0); - // sceKernelChangeThreadPriority(m_threadID, g_DefaultPriority + 1); - g_DefaultCPU = - SCE_KERNEL_CPU_MASK_USER_ALL; // sceKernelGetThreadCpuAffinityMask(m_threadID); -#else - m_threadID = GetCurrentThreadId(); - m_threadHandle = GetCurrentThread(); -#endif -#ifdef _XBOX_ONE - SetThreadName(-1, m_threadName); -#endif - EnterCriticalSection(&ms_threadListCS); - ms_threadList.push_back(this); - LeaveCriticalSection(&ms_threadListCS); +{ + FormatThreadName(m_threadName, mainThreadName); + ms_currentThread = this; + SetCurrentThreadName(m_threadName.c_str()); } C4JThread::~C4JThread() { -#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ - delete m_completionFlag; -#endif - -#if defined __ORBIS__ - scePthreadJoin(m_threadID, NULL); -#endif - - EnterCriticalSection(&ms_threadListCS); - - for (AUTO_VAR(it, ms_threadList.begin()); it != ms_threadList.end(); it++) { - if ((*it) == this) { - ms_threadList.erase(it); - LeaveCriticalSection(&ms_threadListCS); - return; + if (m_threadHandle.joinable()) { + if (m_threadHandle.get_id() == std::this_thread::get_id()) { + m_threadHandle.detach(); + } else { + m_threadHandle.join(); } } - LeaveCriticalSection(&ms_threadListCS); + if (ms_currentThread == this) { + ms_currentThread = nullptr; + } } -#ifdef __PS3__ -void C4JThread::entryPoint(uint64_t param) { - C4JThread* pThread = (C4JThread*)param; - pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam); - pThread->m_completionFlag->Set(); - pThread->m_isRunning = false; - sys_ppu_thread_exit(0); +C4JThread& C4JThread::getMainThreadInstance() noexcept { + static C4JThread mainThread("Main thread"); + return mainThread; } -#elif defined __ORBIS__ -void* C4JThread::entryPoint(void* param) { - C4JThread* pThread = (C4JThread*)param; - pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam); - pThread->m_completionFlag->Set(); - pThread->m_isRunning = false; - scePthreadExit(NULL); -} -#elif defined __PSVITA__ -struct StrArg { - C4JThread* Thread; -}; -SceInt32 C4JThread::entryPoint(SceSize argSize, void* pArgBlock) { - StrArg* strArg = (StrArg*)pArgBlock; - C4JThread* pThread = strArg->Thread; - user_registerthread(); - pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam); - app.DebugPrintf( - "***************************** thread exit %s " - "**************************\n", - pThread->m_threadName); - pThread->m_completionFlag->Set(); - pThread->m_isRunning = false; +void C4JThread::entryPoint(C4JThread* pThread) { + ms_currentThread = pThread; + pThread->m_threadID = std::this_thread::get_id(); - // AP - make sure we clean up this thread's storage and memory - PSVitaTLSStorage::RemoveThread(pThread->m_threadID); - user_removethread(); - - sceKernelExitDeleteThread(NULL); - - return pThread->m_exitCode; -} -#else -DWORD WINAPI C4JThread::entryPoint(LPVOID lpParam) { - C4JThread* pThread = (C4JThread*)lpParam; - SetThreadName(-1, pThread->m_threadName); - pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam); - pThread->m_isRunning = false; - return pThread->m_exitCode; -} +#if defined(__linux__) + pThread->m_nativeTid.store(GetLinuxThreadId(), std::memory_order_release); #endif + SetCurrentThreadName(pThread->m_threadName.c_str()); + + const int requestedProcessor = + pThread->m_requestedProcessor.load(std::memory_order_acquire); + if (requestedProcessor >= 0) { + pThread->SetProcessor(requestedProcessor); + } + + const int requestedPriority = + pThread->m_requestedPriority.load(std::memory_order_acquire); + if (requestedPriority != kUnsetPriority) { + pThread->SetPriority(requestedPriority); + } + + int exitCode = 0; + try { + exitCode = + (pThread->m_startFunc != nullptr) + ? (*pThread->m_startFunc)(pThread->m_threadParam) + : 0; + } catch (...) { + exitCode = -1; + } + + pThread->m_exitCode.store(exitCode, std::memory_order_release); + pThread->m_isRunning.store(false, std::memory_order_release); + pThread->m_completionFlag->Set(); +} + void C4JThread::Run() { -#ifdef __PS3__ - // prio specifies the priority value of the PPU thread within the - // range from 0 to 3071 where 0 is the highest. - // One of the following values is set to flags: - // 0 - non-joinable non-interrupt thread - // SYS_PPU_THREAD_CREATE_JOINABLE - Create a joinable thread - // SYS_PPU_THREAD_CREATE_INTERRUPT - Create an interrupt thread - uint64_t flags = 0; - int err = - sys_ppu_thread_create(&m_threadID, entryPoint, (uint64_t)this, - m_priority, m_stackSize, flags, m_threadName); -#elif defined __ORBIS__ - scePthreadAttrSetstacksize(&m_threadAttr, m_stackSize); - scePthreadAttrSetguardsize(&m_threadAttr, 1024); - int ret = scePthreadCreate(&m_threadID, &m_threadAttr, entryPoint, this, - m_threadName); - assert(ret == SCE_OK); - scePthreadSetprio(m_threadID, m_priority); - scePthreadAttrDestroy(&m_threadAttr); -#elif defined __PSVITA__ - StrArg strArg = {this}; - // m_threadID = sceKernelCreateThread(m_threadName, entryPoint, m_priority, - // m_stackSize, 0, m_CPUMask, NULL); - sceKernelStartThread(m_threadID, sizeof(strArg), &strArg); -#else - ResumeThread(m_threadHandle); -#endif - m_lastSleepTime = System::currentTimeMillis(); - m_isRunning = true; - m_hasStarted = true; + bool expected = false; + if (!m_hasStarted.compare_exchange_strong(expected, true, + std::memory_order_acq_rel)) { + return; + } + + m_isRunning.store(true, std::memory_order_release); + m_exitCode.store(STILL_ACTIVE, std::memory_order_release); + m_completionFlag->Clear(); + m_nativeTid.store(0, std::memory_order_release); + + m_threadHandle = std::thread(&C4JThread::entryPoint, this); + m_threadID = m_threadHandle.get_id(); + + const int requestedProcessor = + m_requestedProcessor.load(std::memory_order_acquire); + if (requestedProcessor >= 0) { + SetProcessor(requestedProcessor); + } + + const int requestedPriority = + m_requestedPriority.load(std::memory_order_acquire); + if (requestedPriority != kUnsetPriority) { + SetPriority(requestedPriority); + } } void C4JThread::SetProcessor(int proc) { -#ifdef __PS3__ - // does nothing since we only have the 1 processor -#elif defined __ORBIS__ - scePthreadAttrSetaffinity(&m_threadAttr, 1 << proc); -#elif defined __PSVITA__ - int Proc = - proc >> - 1; // convert from 360's 3 cores * 2 hardware threads to Vita's 3 cores - int Mask = SCE_KERNEL_CPU_MASK_USER_0 << Proc; - // m_CPUMask = Mask; - // int err = sceKernelChangeThreadCpuAffinityMask(m_threadID, Mask); - int Newmask = sceKernelGetThreadCpuAffinityMask(m_threadID); - app.DebugPrintf( - "***************************** set thread proc %s %d %d %d " - "**************************\n", - m_threadName, proc, Mask, Newmask); -#elif defined _DURANGO - SetThreadAffinityMask(m_threadHandle, 1 << proc); + m_requestedProcessor.store(proc, std::memory_order_release); + + if (!IsProcessorIndexPlausible(proc)) { + return; + } + +#if defined(_WIN32) + HANDLE threadHandle = nullptr; + + if (m_threadHandle.joinable()) { + threadHandle = m_threadHandle.native_handle(); + } else if (ms_currentThread == this) { + threadHandle = ::GetCurrentThread(); + } else { + return; + } + + DWORD_PTR affinityMask = 0; + if (proc < 0) { + DWORD_PTR processAffinityMask = 0; + DWORD_PTR systemAffinityMask = 0; + if (!::GetProcessAffinityMask(::GetCurrentProcess(), + &processAffinityMask, + &systemAffinityMask) || + processAffinityMask == 0) { + return; + } + affinityMask = processAffinityMask; + } else { + const unsigned int bitCount = + static_cast(sizeof(DWORD_PTR) * CHAR_BIT); + if (static_cast(proc) >= bitCount) { + return; + } + + affinityMask = + (static_cast(1) << static_cast(proc)); + } + + (void)::SetThreadAffinityMask(threadHandle, affinityMask); + +#elif defined(__linux__) + pthread_t threadHandle; + + if (m_threadHandle.joinable()) { + threadHandle = m_threadHandle.native_handle(); + } else if (ms_currentThread == this) { + threadHandle = ::pthread_self(); + } else { + return; + } + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + + if (proc < 0) { + if (::sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) { + return; + } + } else { + if (proc >= CPU_SETSIZE) { + return; + } + CPU_SET(proc, &cpuset); + } + + (void)::pthread_setaffinity_np(threadHandle, sizeof(cpuset), &cpuset); #else - XSetThreadProcessor(m_threadHandle, proc); + (void)proc; #endif } void C4JThread::SetPriority(int priority) { -#ifdef __PS3__ - switch (priority) { - case THREAD_PRIORITY_LOWEST: - m_priority = 1003; - break; - case THREAD_PRIORITY_BELOW_NORMAL: - m_priority = 1002; - break; - case THREAD_PRIORITY_NORMAL: - m_priority = 1001; - break; // same as main thread - case THREAD_PRIORITY_ABOVE_NORMAL: - m_priority = 1000; - break; - case THREAD_PRIORITY_HIGHEST: - m_priority = 999; - break; - } - if (m_threadID != 0) sys_ppu_thread_set_priority(m_threadID, m_priority); - // int erro = sys_ppu_thread_set_priority(m_threadID, priority); -#elif defined __ORBIS__ + m_requestedPriority.store(priority, std::memory_order_release); - switch (priority) { - case THREAD_PRIORITY_LOWEST: - m_priority = SCE_KERNEL_PRIO_FIFO_LOWEST; - break; - case THREAD_PRIORITY_BELOW_NORMAL: - m_priority = - SCE_KERNEL_PRIO_FIFO_LOWEST + - ((SCE_KERNEL_PRIO_FIFO_DEFAULT - SCE_KERNEL_PRIO_FIFO_LOWEST) / - 2); - break; - case THREAD_PRIORITY_NORMAL: - m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT; - break; // same as main thread - case THREAD_PRIORITY_ABOVE_NORMAL: - m_priority = - SCE_KERNEL_PRIO_FIFO_DEFAULT + - ((SCE_KERNEL_PRIO_FIFO_HIGHEST - SCE_KERNEL_PRIO_FIFO_DEFAULT) / - 2); - break; - case THREAD_PRIORITY_HIGHEST: - m_priority = SCE_KERNEL_PRIO_FIFO_HIGHEST; - break; +#if defined(_WIN32) + HANDLE threadHandle = nullptr; + + if (m_threadHandle.joinable()) { + threadHandle = m_threadHandle.native_handle(); + } else if (ms_currentThread == this) { + threadHandle = ::GetCurrentThread(); + } else { + return; } - if (m_threadID != 0) { - scePthreadSetprio(m_threadID, m_priority); - } -#elif defined __PSVITA__ - int Mid = g_DefaultPriority; //(SCE_KERNEL_LOWEST_PRIORITY_USER + - // SCE_KERNEL_HIGHEST_PRIORITY_USER) / 2; - switch (priority) { - case THREAD_PRIORITY_LOWEST: - m_priority = SCE_KERNEL_LOWEST_PRIORITY_USER; - break; - case THREAD_PRIORITY_BELOW_NORMAL: - m_priority = Mid + 1; - break; - case THREAD_PRIORITY_NORMAL: - m_priority = Mid; - break; // same as main thread - case THREAD_PRIORITY_ABOVE_NORMAL: - m_priority = Mid - 1; - break; - case THREAD_PRIORITY_HIGHEST: - m_priority = SCE_KERNEL_HIGHEST_PRIORITY_USER; - break; + (void)::SetThreadPriority(threadHandle, priority); + +#elif defined(__linux__) + std::int64_t nativeTid = 0; + + if (ms_currentThread == this) { + nativeTid = GetLinuxThreadId(); + m_nativeTid.store(nativeTid, std::memory_order_release); + } else { + nativeTid = m_nativeTid.load(std::memory_order_acquire); } - // sceKernelChangeThreadPriority(m_threadID, m_priority); - app.DebugPrintf( - "***************************** set thread prio %s %d %d " - "**************************\n", - m_threadName, priority, m_priority); + if (nativeTid <= 0) { + return; + } + + const int niceValue = MapPriorityToNice(priority); + + errno = 0; + if (::setpriority(PRIO_PROCESS, static_cast(nativeTid), niceValue) != + 0) { + if ((errno == EACCES || errno == EPERM) && niceValue < 0) { + (void)::setpriority(PRIO_PROCESS, static_cast(nativeTid), 0); + } + } #else - SetThreadPriority(m_threadHandle, priority); -#endif // __PS3__ + (void)priority; +#endif } std::uint32_t C4JThread::WaitForCompletion(int timeoutMs) { -#ifdef __PS3__ - if (timeoutMs == INFINITE) timeoutMs = SYS_NO_TIMEOUT; - return m_completionFlag->WaitForSignal(timeoutMs); -#elif defined __ORBIS__ - return m_completionFlag->WaitForSignal(timeoutMs); -#elif defined __PSVITA__ - return m_completionFlag->WaitForSignal(timeoutMs); -/* SceUInt32 Timeout = timeoutMs * 1000; - SceInt32 err = sceKernelWaitThreadEnd(m_threadID, &m_exitCode, - &Timeout); if( err == 0 ) - { - return m_exitCode; + const std::uint32_t waitResult = m_completionFlag->WaitForSignal(timeoutMs); + if (waitResult == WAIT_OBJECT_0 && m_threadHandle.joinable()) { + if (m_threadHandle.get_id() == std::this_thread::get_id()) { + m_threadHandle.detach(); + } else { + m_threadHandle.join(); } - else - { - if( err == SCE_KERNEL_ERROR_WAIT_TIMEOUT ) - { - return WAIT_TIMEOUT; - } - else - { - // AP - not sure what to do here - return 0; - } - }*/ - -// return m_exitCode; -#else - return WaitForSingleObject(m_threadHandle, timeoutMs); -#endif // __PS3__ + } + return waitResult; } -int C4JThread::GetExitCode() { -#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ - return m_exitCode; -#else - DWORD exitcode = 0; - GetExitCodeThread(m_threadHandle, &exitcode); - - return *((int*)&exitcode); -#endif +int C4JThread::GetExitCode() const noexcept { + return m_isRunning.load(std::memory_order_acquire) + ? STILL_ACTIVE + : m_exitCode.load(std::memory_order_acquire); } void C4JThread::Sleep(int millisecs) { -#ifdef __PS3__ - if (millisecs == 0) { - // https://ps3.scedev.net/forums/thread/116470/ - // "sys_timer_usleep(0) does not yield the CPU." - sys_ppu_thread_yield(); - } else - sys_timer_usleep(millisecs * 1000); -#elif defined __ORBIS__ - sceKernelUsleep(((SceKernelUseconds)millisecs) * 1000); -#elif defined __PSVITA__ - // 4J Stu - 0 is an error, so add a tiny sleep when we just want to yield - sceKernelDelayThread(millisecs * 1000 + 1); -#else - ::Sleep(millisecs); -#endif // __PS3__ + if (millisecs <= 0) { + std::this_thread::yield(); + return; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(millisecs)); } -C4JThread* C4JThread::getCurrentThread() { -#ifdef __PS3__ - sys_ppu_thread_t currThreadID; - sys_ppu_thread_get_id(&currThreadID); -#elif defined __ORBIS__ - ScePthread currThreadID = scePthreadSelf(); -#elif defined __PSVITA__ - SceUID currThreadID = sceKernelGetThreadId(); -#else - std::uint32_t currThreadID = GetCurrentThreadId(); -#endif //__PS3__ - EnterCriticalSection(&ms_threadListCS); +C4JThread* C4JThread::getCurrentThread() noexcept { + if (ms_currentThread != nullptr) { + return ms_currentThread; + } - for (int i = 0; i < ms_threadList.size(); i++) { - if (currThreadID == ms_threadList[i]->m_threadID) { - LeaveCriticalSection(&ms_threadListCS); - return ms_threadList[i]; + if (std::this_thread::get_id() == g_processMainThreadId) { + return &getMainThreadInstance(); + } + + return nullptr; +} + +bool C4JThread::isMainThread() noexcept { + return std::this_thread::get_id() == g_processMainThreadId; +} + +void C4JThread::SetThreadName(std::uint32_t threadId, const char* threadName) { + const char* safeThreadName = GetSafeThreadName(threadName); + +#if defined(_WIN32) + if (threadId == static_cast(-1) || + threadId == ::GetCurrentThreadId()) { + using SetThreadDescriptionFn = HRESULT(WINAPI*)(HANDLE, PCWSTR); + + const HMODULE kernelModule = ::GetModuleHandleW(L"Kernel32.dll"); + if (kernelModule != nullptr) { + const auto setThreadDescription = + reinterpret_cast( + ::GetProcAddress(kernelModule, "SetThreadDescription")); + + if (setThreadDescription != nullptr) { + wchar_t wideName[64]; + const std::size_t converted = + std::mbstowcs(wideName, safeThreadName, + (sizeof(wideName) / sizeof(wideName[0])) - 1); + + if (converted != static_cast(-1)) { + wideName[converted] = L'\0'; + (void)setThreadDescription(::GetCurrentThread(), wideName); + return; + } + } } } - LeaveCriticalSection(&ms_threadListCS); +#pragma pack(push, 8) + struct THREADNAME_INFO { + std::uint32_t dwType; + const char* szName; + std::uint32_t dwThreadID; + std::uint32_t dwFlags; + }; +#pragma pack(pop) - return NULL; -} + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = safeThreadName; + info.dwThreadID = threadId; + info.dwFlags = 0; + + __try { + ::RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), + reinterpret_cast(&info)); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } + +#elif defined(__linux__) + (void)threadId; + + char truncatedName[16]; + std::snprintf(truncatedName, sizeof(truncatedName), "%s", safeThreadName); + truncatedName[sizeof(truncatedName) - 1] = '\0'; + + (void)::pthread_setname_np(::pthread_self(), truncatedName); -bool C4JThread::isMainThread() { -#ifdef _XBOX_ONE - return getCurrentThread() == m_mainThread; #else - return getCurrentThread() == &m_mainThread; + (void)threadId; + (void)safeThreadName; #endif } -C4JThread::Event::Event(EMode mode /* = e_modeAutoClear*/) { - m_mode = mode; -#ifdef __PS3__ - sys_event_flag_attribute_t attr; - // default values taken from sys_event_flag_attribute_initialize - attr.attr_protocol = SYS_SYNC_PRIORITY; - attr.attr_pshared = SYS_SYNC_NOT_PROCESS_SHARED; - attr.key = 0; - attr.flags = 0; - attr.type = SYS_SYNC_WAITER_SINGLE; - attr.name[0] = '\0'; - sys_event_flag_attribute_initialize(attr); - - int err = sys_event_flag_create(&m_event, &attr, 0); - -#elif defined __ORBIS__ - char name[1] = {0}; - sceKernelCreateEventFlag( - &m_event, name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, - 0, NULL); -#elif defined __PSVITA__ - char name[1] = {0}; - m_event = sceKernelCreateEventFlag( - name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL); -#else - m_event = CreateEvent(NULL, (m_mode == e_modeManualClear), FALSE, NULL); -#endif //__PS3__ +void C4JThread::SetCurrentThreadName(const char* threadName) { + SetThreadName(static_cast(-1), threadName); } -C4JThread::Event::~Event() { -#ifdef __PS3__ - sys_event_flag_destroy(m_event); -#elif defined __ORBIS__ - sceKernelDeleteEventFlag(m_event); -#elif defined __PSVITA__ - sceKernelDeleteEventFlag(m_event); -#else - CloseHandle(m_event); -#endif // __PS3__ -} +C4JThread::Event::Event(EMode mode) + : m_mode(mode), m_mutex(), m_condition(), m_signaled(false) {} void C4JThread::Event::Set() { -#ifdef __PS3__ - int err = sys_event_flag_set(m_event, 1); -#elif defined __ORBIS__ - sceKernelSetEventFlag(m_event, 1); -#elif defined __PSVITA__ - sceKernelSetEventFlag(m_event, 1); -#else - SetEvent(m_event); -#endif //__PS3__ + { + std::lock_guard lock(m_mutex); + m_signaled = true; + } + + if (m_mode == e_modeAutoClear) { + m_condition.notify_one(); + } else { + m_condition.notify_all(); + } } void C4JThread::Event::Clear() { -#ifdef __PS3__ - int err = sys_event_flag_clear(m_event, ~(1)); -#elif defined __ORBIS__ - sceKernelClearEventFlag(m_event, ~(1)); -#elif defined __PSVITA__ - sceKernelClearEventFlag(m_event, ~1); -#else - ResetEvent(m_event); -#endif //__PS3__ + std::lock_guard lock(m_mutex); + m_signaled = false; } std::uint32_t C4JThread::Event::WaitForSignal(int timeoutMs) { -#ifdef __PS3__ - if (timeoutMs == INFINITE) timeoutMs = SYS_NO_TIMEOUT; - int timoutMicrosecs = timeoutMs * 1000; - uint32_t mode = SYS_EVENT_FLAG_WAIT_AND; - if (m_mode == e_modeAutoClear) mode |= SYS_EVENT_FLAG_WAIT_CLEAR; - int err = sys_event_flag_wait(m_event, 1, mode, 0, timoutMicrosecs); + std::unique_lock lock(m_mutex); + const bool signaled = + WaitForCondition(m_condition, lock, timeoutMs, + [this] { return m_signaled; }); - switch (err) { - case CELL_OK: - return WAIT_OBJECT_0; - case ETIMEDOUT: - return WAIT_TIMEOUT; - case ECANCELED: - return WAIT_ABANDONED; - default: - return WAIT_FAILED; + if (!signaled) { + return WAIT_TIMEOUT; } -#elif defined __ORBIS__ - SceKernelUseconds timeoutMicrosecs; - SceKernelUseconds* pTimeoutMicrosecs; - if (timeoutMs == INFINITE) { - pTimeoutMicrosecs = NULL; - } else { - timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000; - pTimeoutMicrosecs = &timeoutMicrosecs; - } - uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND; if (m_mode == e_modeAutoClear) { - waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT; + m_signaled = false; } - int err = - sceKernelWaitEventFlag(m_event, 1, waitMode, NULL, pTimeoutMicrosecs); - switch (err) { - case SCE_OK: - return WAIT_OBJECT_0; - case SCE_KERNEL_ERROR_ETIMEDOUT: - return WAIT_TIMEOUT; - case SCE_KERNEL_ERROR_ECANCELED: - return WAIT_ABANDONED; - default: - return WAIT_FAILED; - } -#elif defined __PSVITA__ - SceUInt32 timeoutMicrosecs; - SceUInt32* pTimeoutMicrosecs; - if (timeoutMs == INFINITE) { - pTimeoutMicrosecs = NULL; - } else { - timeoutMicrosecs = ((SceInt32)timeoutMs) * 1000; - pTimeoutMicrosecs = &timeoutMicrosecs; - } - uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND; - if (m_mode == e_modeAutoClear) { - waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL; - } - int err = - sceKernelWaitEventFlag(m_event, 1, waitMode, NULL, pTimeoutMicrosecs); - switch (err) { - case SCE_OK: - return WAIT_OBJECT_0; - case SCE_KERNEL_ERROR_WAIT_TIMEOUT: - return WAIT_TIMEOUT; - case SCE_KERNEL_ERROR_WAIT_CANCEL: - return WAIT_ABANDONED; - default: - return WAIT_FAILED; - } -#else - return WaitForSingleObject(m_event, timeoutMs); -#endif // __PS3__ + + return WAIT_OBJECT_0; } -C4JThread::EventArray::EventArray(int size, EMode mode /* = e_modeAutoClear*/) { - assert(size < 32); - m_size = size; - m_mode = mode; -#ifdef __PS3__ - sys_event_flag_attribute_t attr; - // default values taken from sys_event_flag_attribute_initialize - attr.attr_protocol = SYS_SYNC_PRIORITY; - attr.attr_pshared = SYS_SYNC_NOT_PROCESS_SHARED; - attr.key = 0; - attr.flags = 0; - attr.type = SYS_SYNC_WAITER_SINGLE; - attr.name[0] = '\0'; - sys_event_flag_attribute_initialize(attr); - int err = sys_event_flag_create(&m_events, &attr, 0); - assert(err == CELL_OK); -#elif defined __ORBIS__ - char name[1] = {0}; - sceKernelCreateEventFlag( - &m_events, name, - SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL); -#elif defined __PSVITA__ - char name[1] = {0}; - m_events = sceKernelCreateEventFlag( - name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL); -#else - m_events = new HANDLE[size]; - for (int i = 0; i < size; i++) { - m_events[i] = - CreateEvent(NULL, (m_mode == e_modeManualClear), FALSE, NULL); - } -#endif // __PS3__ +C4JThread::EventArray::EventArray(int size, EMode mode) + : m_size(size), + m_mode(mode), + m_mutex(), + m_condition(), + m_signaledMask(0U) { + assert(m_size > 0); + assert(m_size <= 32); } void C4JThread::EventArray::Set(int index) { -#ifdef __PS3__ - int err = sys_event_flag_set(m_events, 1 << index); - assert(err == CELL_OK); -#elif defined __ORBIS__ - sceKernelSetEventFlag(m_events, 1 << index); -#elif defined __PSVITA__ - sceKernelSetEventFlag(m_events, 1 << index); -#else - SetEvent(m_events[index]); -#endif //__PS3__ + assert(index >= 0); + assert(index < m_size); + + { + std::lock_guard lock(m_mutex); + m_signaledMask |= (1U << static_cast(index)); + } + + m_condition.notify_all(); } void C4JThread::EventArray::Clear(int index) { -#ifdef __PS3__ - int err = sys_event_flag_clear(m_events, ~(1 << index)); - assert(err == CELL_OK); -#elif defined __ORBIS__ - sceKernelClearEventFlag(m_events, ~(1 << index)); -#elif defined __PSVITA__ - sceKernelClearEventFlag(m_events, ~(1 << index)); -#else - ResetEvent(m_events[index]); -#endif //__PS3__ + assert(index >= 0); + assert(index < m_size); + + std::lock_guard lock(m_mutex); + m_signaledMask &= ~(1U << static_cast(index)); } void C4JThread::EventArray::SetAll() { - for (int i = 0; i < m_size; i++) Set(i); + { + std::lock_guard lock(m_mutex); + m_signaledMask |= BuildMaskForSize(m_size); + } + + m_condition.notify_all(); } void C4JThread::EventArray::ClearAll() { - for (int i = 0; i < m_size; i++) Clear(i); + std::lock_guard lock(m_mutex); + m_signaledMask = 0U; } std::uint32_t C4JThread::EventArray::WaitForSingle(int index, int timeoutMs) { - std::uint32_t retVal; -#ifdef __PS3__ - int timeoutMicrosecs; - if (timeoutMs == INFINITE) - timeoutMicrosecs = SYS_NO_TIMEOUT; - else - timeoutMicrosecs = timeoutMs * 1000; - uint32_t mode = SYS_EVENT_FLAG_WAIT_AND; - if (m_mode == e_modeAutoClear) mode |= SYS_EVENT_FLAG_WAIT_CLEAR; + assert(index >= 0); + assert(index < m_size); - int err = - sys_event_flag_wait(m_events, 1 << index, mode, 0, timeoutMicrosecs); + const std::uint32_t bitMask = 1U << static_cast(index); + std::unique_lock lock(m_mutex); - switch (err) { - case CELL_OK: - retVal = WAIT_OBJECT_0; - break; - case ETIMEDOUT: - retVal = WAIT_TIMEOUT; - break; - case ECANCELED: - retVal = WAIT_ABANDONED; - break; - default: - assert(0); - retVal = WAIT_FAILED; - break; + const bool signaled = + WaitForCondition(m_condition, lock, timeoutMs, + [this, bitMask] { + return (m_signaledMask & bitMask) != 0U; + }); + + if (!signaled) { + return WAIT_TIMEOUT; } -#elif defined __ORBIS__ - SceKernelUseconds timeoutMicrosecs; - SceKernelUseconds* pTimeoutMicrosecs; - if (timeoutMs == INFINITE) { - pTimeoutMicrosecs = NULL; - } else { - timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000; - pTimeoutMicrosecs = &timeoutMicrosecs; - } - uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND; + if (m_mode == e_modeAutoClear) { - waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT; + m_signaledMask &= ~bitMask; } - uint64_t resultPat; - int err = sceKernelWaitEventFlag(m_events, 1 << index, waitMode, &resultPat, - pTimeoutMicrosecs); - assert(err != SCE_KERNEL_ERROR_ETIMEDOUT); - switch (err) { - case SCE_OK: - retVal = WAIT_OBJECT_0; - break; - case SCE_KERNEL_ERROR_ETIMEDOUT: - retVal = WAIT_TIMEOUT; - break; - case SCE_KERNEL_ERROR_ECANCELED: - retVal = WAIT_ABANDONED; - break; - default: - retVal = WAIT_FAILED; - break; - } -#elif defined __PSVITA__ - SceUInt32 timeoutMicrosecs; - SceUInt32* pTimeoutMicrosecs; - if (timeoutMs == INFINITE) { - pTimeoutMicrosecs = NULL; - } else { - timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000; - pTimeoutMicrosecs = &timeoutMicrosecs; - } - uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND; - if (m_mode == e_modeAutoClear) { - waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL; - } - int err = sceKernelWaitEventFlag(m_events, 1 << index, waitMode, NULL, - pTimeoutMicrosecs); - switch (err) { - case SCE_OK: - return WAIT_OBJECT_0; - case SCE_KERNEL_ERROR_WAIT_TIMEOUT: - return WAIT_TIMEOUT; - case SCE_KERNEL_ERROR_WAIT_CANCEL: - return WAIT_ABANDONED; - default: - return WAIT_FAILED; - } -#else - retVal = WaitForSingleObject(m_events[index], timeoutMs); -#endif // __PS3__ - return retVal; + return WAIT_OBJECT_0; } std::uint32_t C4JThread::EventArray::WaitForAll(int timeoutMs) { - std::uint32_t retVal; -#ifdef __PS3__ - if (timeoutMs == INFINITE) timeoutMs = SYS_NO_TIMEOUT; - int timoutMicrosecs = timeoutMs * 1000; - unsigned int bitmask = 0; - for (int i = 0; i < m_size; i++) bitmask |= (1 << i); + const std::uint32_t bitMask = BuildMaskForSize(m_size); + std::unique_lock lock(m_mutex); - uint32_t mode = SYS_EVENT_FLAG_WAIT_AND; - if (m_mode == e_modeAutoClear) mode |= SYS_EVENT_FLAG_WAIT_CLEAR; + const bool signaled = + WaitForCondition(m_condition, lock, timeoutMs, + [this, bitMask] { + return (m_signaledMask & bitMask) == bitMask; + }); - int err = sys_event_flag_wait(m_events, bitmask, mode, 0, timoutMicrosecs); - - switch (err) { - case CELL_OK: - retVal = WAIT_OBJECT_0; - break; - case ETIMEDOUT: - retVal = WAIT_TIMEOUT; - break; - case ECANCELED: - retVal = WAIT_ABANDONED; - break; - default: - assert(0); - retVal = WAIT_FAILED; - break; + if (!signaled) { + return WAIT_TIMEOUT; } -#elif defined __ORBIS__ - SceKernelUseconds timeoutMicrosecs; - SceKernelUseconds* pTimeoutMicrosecs; - if (timeoutMs == INFINITE) { - pTimeoutMicrosecs = NULL; - } else { - timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000; - pTimeoutMicrosecs = &timeoutMicrosecs; - } - unsigned int bitmask = 0; - for (int i = 0; i < m_size; i++) bitmask |= (1 << i); - uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND; if (m_mode == e_modeAutoClear) { - waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT; + m_signaledMask &= ~bitMask; } - int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, - pTimeoutMicrosecs); - switch (err) { - case SCE_OK: - retVal = WAIT_OBJECT_0; - break; - case SCE_KERNEL_ERROR_ETIMEDOUT: - retVal = WAIT_TIMEOUT; - break; - case SCE_KERNEL_ERROR_ECANCELED: - retVal = WAIT_ABANDONED; - break; - default: - retVal = WAIT_FAILED; - break; - } -#elif defined __PSVITA__ - SceUInt32 timeoutMicrosecs; - SceUInt32* pTimeoutMicrosecs; - if (timeoutMs == INFINITE) { - pTimeoutMicrosecs = NULL; - } else { - timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000; - pTimeoutMicrosecs = &timeoutMicrosecs; - } - unsigned int bitmask = 0; - for (int i = 0; i < m_size; i++) bitmask |= (1 << i); - uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND; - if (m_mode == e_modeAutoClear) { - waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL; - } - int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, - pTimeoutMicrosecs); - switch (err) { - case SCE_OK: - return WAIT_OBJECT_0; - case SCE_KERNEL_ERROR_WAIT_TIMEOUT: - return WAIT_TIMEOUT; - case SCE_KERNEL_ERROR_WAIT_CANCEL: - return WAIT_ABANDONED; - default: - return WAIT_FAILED; - } -#else - retVal = WaitForMultipleObjects(m_size, m_events, true, timeoutMs); -#endif // __PS3__ - return retVal; + return WAIT_OBJECT_0; } std::uint32_t C4JThread::EventArray::WaitForAny(int timeoutMs) { -#ifdef __PS3__ - if (timeoutMs == INFINITE) timeoutMs = SYS_NO_TIMEOUT; - int timoutMicrosecs = timeoutMs * 1000; - unsigned int bitmask = 0; - for (int i = 0; i < m_size; i++) bitmask |= (1 << i); + const std::uint32_t bitMask = BuildMaskForSize(m_size); + std::unique_lock lock(m_mutex); - uint32_t mode = SYS_EVENT_FLAG_WAIT_OR; - if (m_mode == e_modeAutoClear) mode |= SYS_EVENT_FLAG_WAIT_CLEAR; + const bool signaled = + WaitForCondition(m_condition, lock, timeoutMs, + [this, bitMask] { + return (m_signaledMask & bitMask) != 0U; + }); - int err = sys_event_flag_wait(m_events, bitmask, mode, 0, timoutMicrosecs); - - switch (err) { - case CELL_OK: - return WAIT_OBJECT_0; - case ETIMEDOUT: - return WAIT_TIMEOUT; - case ECANCELED: - return WAIT_ABANDONED; - default: - assert(0); - return WAIT_FAILED; + if (!signaled) { + return WAIT_TIMEOUT; } -#elif defined __ORBIS__ - SceKernelUseconds timeoutMicrosecs; - SceKernelUseconds* pTimeoutMicrosecs; - if (timeoutMs == INFINITE) { - pTimeoutMicrosecs = NULL; - } else { - timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000; - pTimeoutMicrosecs = &timeoutMicrosecs; - } - unsigned int bitmask = 0; - for (int i = 0; i < m_size; i++) bitmask |= (1 << i); - uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_OR; + const std::uint32_t readyMask = m_signaledMask & bitMask; + const std::uint32_t readyIndex = FirstSetBitIndex(readyMask); + if (m_mode == e_modeAutoClear) { - waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT; + m_signaledMask &= ~(1U << readyIndex); } - int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, - pTimeoutMicrosecs); - switch (err) { - case SCE_OK: - return WAIT_OBJECT_0; - case SCE_KERNEL_ERROR_ETIMEDOUT: - return WAIT_TIMEOUT; - case SCE_KERNEL_ERROR_ECANCELED: - return WAIT_ABANDONED; - default: - return WAIT_FAILED; - } -#elif defined __PSVITA__ - SceUInt32 timeoutMicrosecs; - SceUInt32* pTimeoutMicrosecs; - if (timeoutMs == INFINITE) { - pTimeoutMicrosecs = NULL; - } else { - timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000; - pTimeoutMicrosecs = &timeoutMicrosecs; - } - unsigned int bitmask = 0; - for (int i = 0; i < m_size; i++) bitmask |= (1 << i); - uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_OR; - if (m_mode == e_modeAutoClear) { - waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL; - } - int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, - pTimeoutMicrosecs); - switch (err) { - case SCE_OK: - return WAIT_OBJECT_0; - case SCE_KERNEL_ERROR_WAIT_TIMEOUT: - return WAIT_TIMEOUT; - case SCE_KERNEL_ERROR_WAIT_CANCEL: - return WAIT_ABANDONED; - default: - return WAIT_FAILED; - } -#else - return WaitForMultipleObjects(m_size, m_events, false, timeoutMs); -#endif // __PS3__ + + return WAIT_OBJECT_0 + readyIndex; } -#ifdef __PS3__ -void C4JThread::EventArray::Cancel() { sys_event_flag_cancel(m_events, NULL); } -#endif - C4JThread::EventQueue::EventQueue(UpdateFunc* updateFunc, - ThreadInitFunc threadInitFunc, - const char* szThreadName) { - m_updateFunc = updateFunc; - m_threadInitFunc = threadInitFunc; - strcpy(m_threadName, szThreadName); - m_thread = NULL; - m_startEvent = NULL; - m_finishedEvent = NULL; - m_processor = -1; - m_priority = THREAD_PRIORITY_HIGHEST + 1; + ThreadInitFunc* threadInitFunc, + const char* threadName) + : m_thread(), + m_queue(), + m_mutex(), + m_queueCondition(), + m_drainedCondition(), + m_updateFunc(updateFunc), + m_threadInitFunc(threadInitFunc), + m_threadName(threadName != nullptr ? threadName : "Unnamed"), + m_processor(-1), + m_priority(kUnsetPriority), + m_busy(false), + m_initOnce(), + m_stopRequested(false) { + assert(m_updateFunc != nullptr); +} + +C4JThread::EventQueue::~EventQueue() { + m_stopRequested.store(true, std::memory_order_release); + m_queueCondition.notify_all(); + + if (m_thread) { + (void)m_thread->WaitForCompletion(INFINITE); + } +} + +void C4JThread::EventQueue::setProcessor(int proc) { + m_processor = proc; + if (m_thread) { + m_thread->SetProcessor(proc); + } +} + +void C4JThread::EventQueue::setPriority(int priority) { + m_priority = priority; + if (m_thread) { + m_thread->SetPriority(priority); + } } void C4JThread::EventQueue::init() { - m_startEvent = new C4JThread::EventArray(1); - m_finishedEvent = new C4JThread::Event(); - InitializeCriticalSection(&m_critSect); - m_thread = new C4JThread(threadFunc, this, m_threadName); - if (m_processor >= 0) m_thread->SetProcessor(m_processor); - if (m_priority != THREAD_PRIORITY_HIGHEST + 1) - m_thread->SetPriority(m_priority); - m_thread->Run(); + std::call_once(m_initOnce, [this]() { + m_thread = std::make_unique(threadFunc, this, + m_threadName.c_str()); + + if (m_processor >= 0) { + m_thread->SetProcessor(m_processor); + } + + if (m_priority != kUnsetPriority) { + m_thread->SetPriority(m_priority); + } + + m_thread->Run(); + }); } void C4JThread::EventQueue::sendEvent(Level* pLevel) { - if (m_thread == NULL) init(); - EnterCriticalSection(&m_critSect); - m_queue.push(pLevel); - m_startEvent->Set(0); - m_finishedEvent->Clear(); - LeaveCriticalSection(&m_critSect); + init(); + + if (m_stopRequested.load(std::memory_order_acquire)) { + return; + } + + { + std::lock_guard lock(m_mutex); + m_queue.push(pLevel); + } + + m_queueCondition.notify_one(); } void C4JThread::EventQueue::waitForFinish() { - if (m_thread == NULL) init(); - EnterCriticalSection(&m_critSect); - if (m_queue.empty()) { - LeaveCriticalSection((&m_critSect)); - return; - } - LeaveCriticalSection((&m_critSect)); - m_finishedEvent->WaitForSignal(INFINITE); + init(); + + std::unique_lock lock(m_mutex); + m_drainedCondition.wait(lock, [this] { + return m_queue.empty() && !m_busy; + }); } int C4JThread::EventQueue::threadFunc(void* lpParam) { - EventQueue* p = (EventQueue*)lpParam; - p->threadPoll(); + EventQueue* pQueue = static_cast(lpParam); + pQueue->threadPoll(); return 0; } void C4JThread::EventQueue::threadPoll() { - ShutdownManager::HasStarted(ShutdownManager::eEventQueueThreads, - m_startEvent); + ShutdownManager::HasStarted(ShutdownManager::eEventQueueThreads); - if (m_threadInitFunc) m_threadInitFunc(); - - while (ShutdownManager::ShouldRun(ShutdownManager::eEventQueueThreads)) { - std::uint32_t err = m_startEvent->WaitForAny(INFINITE); - if (err == WAIT_OBJECT_0) { - bool bListEmpty = true; - do { - EnterCriticalSection(&m_critSect); - void* updateParam = m_queue.front(); - LeaveCriticalSection(&m_critSect); - - m_updateFunc(updateParam); - - EnterCriticalSection(&m_critSect); - m_queue.pop(); - bListEmpty = m_queue.empty(); - if (bListEmpty) { - m_finishedEvent->Set(); - } - LeaveCriticalSection(&m_critSect); - - } while (!bListEmpty); + if (m_threadInitFunc != nullptr) { + try { + m_threadInitFunc(); + } catch (...) { } - }; + } + + while (!m_stopRequested.load(std::memory_order_acquire) && + ShutdownManager::ShouldRun(ShutdownManager::eEventQueueThreads)) { + void* updateParam = nullptr; + + { + std::unique_lock lock(m_mutex); + m_queueCondition.wait_for(lock, + std::chrono::milliseconds( + kEventQueueShutdownPollMs), + [this] { + return m_stopRequested.load( + std::memory_order_acquire) || + !m_queue.empty(); + }); + + if (m_stopRequested.load(std::memory_order_acquire)) { + break; + } + + if (m_queue.empty()) { + continue; + } + + m_busy = true; + updateParam = m_queue.front(); + m_queue.pop(); + } + + try { + m_updateFunc(updateParam); + } catch (...) { + } + + { + std::lock_guard lock(m_mutex); + m_busy = false; + if (m_queue.empty()) { + m_drainedCondition.notify_all(); + } + } + } + + { + std::lock_guard lock(m_mutex); + m_busy = false; + std::queue emptyQueue; + m_queue.swap(emptyQueue); + } + m_drainedCondition.notify_all(); ShutdownManager::HasFinished(ShutdownManager::eEventQueueThreads); } -#ifdef __ORBIS__ - void C4JThread::PushAffinityAllCores() { - assert(m_oldAffinityMask == 0); - int err; - ScePthread currThreadID = scePthreadSelf(); - err = scePthreadGetaffinity(currThreadID, &m_oldAffinityMask); - assert(err == SCE_OK); - err = scePthreadSetaffinity(currThreadID, 63); - assert(err == SCE_OK); +#if defined(_WIN32) + const HANDLE currentThread = ::GetCurrentThread(); + DWORD_PTR processAffinityMask = 0; + DWORD_PTR systemAffinityMask = 0; + + if (!::GetProcessAffinityMask(::GetCurrentProcess(), + &processAffinityMask, + &systemAffinityMask) || + processAffinityMask == 0) { + return; + } + + const DWORD_PTR previousMask = + ::SetThreadAffinityMask(currentThread, processAffinityMask); + + if (previousMask != 0) { + g_affinityMaskStack.push_back(previousMask); + } + +#elif defined(__linux__) + cpu_set_t previousMask; + if (::pthread_getaffinity_np(::pthread_self(), sizeof(previousMask), + &previousMask) != 0) { + return; + } + + g_affinityMaskStack.push_back(previousMask); + + cpu_set_t allowedMask; + if (::sched_getaffinity(0, sizeof(allowedMask), &allowedMask) != 0) { + g_affinityMaskStack.pop_back(); + return; + } + + (void)::pthread_setaffinity_np(::pthread_self(), sizeof(allowedMask), + &allowedMask); +#endif } void C4JThread::PopAffinity() { - int err; - ScePthread currThreadID = scePthreadSelf(); - err = scePthreadSetaffinity(currThreadID, m_oldAffinityMask); - m_oldAffinityMask = 0; - assert(err == SCE_OK); -} +#if defined(_WIN32) + if (g_affinityMaskStack.empty()) { + return; + } -#endif // __ORBIS__ \ No newline at end of file + const DWORD_PTR previousMask = g_affinityMaskStack.back(); + g_affinityMaskStack.pop_back(); + (void)::SetThreadAffinityMask(::GetCurrentThread(), previousMask); + +#elif defined(__linux__) + if (g_affinityMaskStack.empty()) { + return; + } + + const cpu_set_t previousMask = g_affinityMaskStack.back(); + g_affinityMaskStack.pop_back(); + (void)::pthread_setaffinity_np(::pthread_self(), sizeof(previousMask), + &previousMask); +#endif +} \ No newline at end of file diff --git a/Minecraft.World/Util/C4JThread.h b/Minecraft.World/Util/C4JThread.h index a567696ff..195d86b69 100644 --- a/Minecraft.World/Util/C4JThread.h +++ b/Minecraft.World/Util/C4JThread.h @@ -1,89 +1,65 @@ #pragma once -#include -#include -typedef int(C4JThreadStartFunc)(void* lpThreadParameter); +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using C4JThreadStartFunc = int(void* lpThreadParameter); class Level; -#if defined(_XBOX_ONE) || defined(__ORBIS__) +inline constexpr int CPU_CORE_MAIN_THREAD = 0; -#define CPU_CORE_MAIN_THREAD 0 +inline constexpr int CPU_CORE_CHUNK_REBUILD_A = 1; +inline constexpr int CPU_CORE_SAVE_THREAD_A = 1; +inline constexpr int CPU_CORE_TILE_UPDATE = 1; +inline constexpr int CPU_CORE_CONNECTIONS = 1; -#define CPU_CORE_SERVER 1 +inline constexpr int CPU_CORE_CHUNK_UPDATE = 2; +inline constexpr int CPU_CORE_REMOVE_PLAYER = 2; -#define CPU_CORE_CHUNK_UPDATE 2 -#define CPU_CORE_REMOVE_PLAYER 2 +inline constexpr int CPU_CORE_CHUNK_REBUILD_B = 3; +inline constexpr int CPU_CORE_SAVE_THREAD_B = 3; +inline constexpr int CPU_CORE_UI_SCENE = 3; +inline constexpr int CPU_CORE_POST_PROCESSING = 3; -#define CPU_CORE_CHUNK_REBUILD_A 3 -#define CPU_CORE_SAVE_THREAD_A 3 -#define CPU_CORE_UI_SCENE 3 -#define CPU_CORE_POST_PROCESSING 3 -#define CPU_CORE_DQR_REALTIMESESSION 3 +inline constexpr int CPU_CORE_SERVER = 4; -#define CPU_CORE_CHUNK_REBUILD_B 4 -#define CPU_CORE_SAVE_THREAD_B 4 -#define CPU_CORE_TILE_UPDATE 4 -#define CPU_CORE_CONNECTIONS 4 - -#define CPU_CORE_CHUNK_REBUILD_C 5 -#define CPU_CORE_SAVE_THREAD_C 5 -#define CPU_CORE_LEADERBOARDS 5 // Orbis only - -#else - -#define CPU_CORE_MAIN_THREAD 0 - -#define CPU_CORE_CHUNK_REBUILD_A 1 -#define CPU_CORE_SAVE_THREAD_A 1 -#define CPU_CORE_TILE_UPDATE 1 -#define CPU_CORE_CONNECTIONS 1 - -#define CPU_CORE_CHUNK_UPDATE 2 -#define CPU_CORE_REMOVE_PLAYER 2 - -#define CPU_CORE_CHUNK_REBUILD_B 3 -#define CPU_CORE_SAVE_THREAD_B 3 -#define CPU_CORE_UI_SCENE 3 -#define CPU_CORE_POST_PROCESSING 3 - -#define CPU_CORE_SERVER 4 - -#define CPU_CORE_CHUNK_REBUILD_C 5 -#define CPU_CORE_SAVE_THREAD_C 5 -#define CPU_CORE_LEADERBOARDS 5 // Sony only - -#endif +inline constexpr int CPU_CORE_CHUNK_REBUILD_C = 5; +inline constexpr int CPU_CORE_SAVE_THREAD_C = 5; +inline constexpr int CPU_CORE_LEADERBOARDS = 5; class C4JThread { public: class Event { public: enum EMode { e_modeAutoClear, e_modeManualClear }; - Event(EMode mode = e_modeAutoClear); - ~Event(); + + explicit Event(EMode mode = e_modeAutoClear); + ~Event() = default; + void Set(); void Clear(); std::uint32_t WaitForSignal(int timeoutMs); private: EMode m_mode; -#ifdef __PS3__ - sys_event_flag_t m_event; -#elif defined __ORBIS__ - SceKernelEventFlag m_event; -#elif defined __PSVITA__ - SceUID m_event; -#else - HANDLE m_event; -#endif // __PS3__ + std::mutex m_mutex; + std::condition_variable m_condition; + bool m_signaled; }; class EventArray { public: enum EMode { e_modeAutoClear, e_modeManualClear }; - EventArray(int size, EMode mode = e_modeAutoClear); + explicit EventArray(int size, EMode mode = e_modeAutoClear); void Set(int index); void Clear(int index); @@ -92,128 +68,109 @@ public: std::uint32_t WaitForAll(int timeoutMs); std::uint32_t WaitForAny(int timeoutMs); std::uint32_t WaitForSingle(int index, int timeoutMs); -#ifdef __PS3__ - void Cancel(); -#endif private: int m_size; EMode m_mode; -#ifdef __PS3__ - sys_event_flag_t m_events; -#elif defined __ORBIS__ - SceKernelEventFlag m_events; -#elif defined __PSVITA__ - SceUID m_events; -#else - HANDLE* m_events; -#endif // __PS3__ + std::mutex m_mutex; + std::condition_variable m_condition; + std::uint32_t m_signaledMask; }; class EventQueue { - typedef void(UpdateFunc)(void* lpParameter); - typedef void(ThreadInitFunc)(); + public: + using UpdateFunc = void(void* lpParameter); + using ThreadInitFunc = void(); - C4JThread* m_thread; - std::queue m_queue; - C4JThread::EventArray* m_startEvent; - C4JThread::Event* m_finishedEvent; - CRITICAL_SECTION m_critSect; - UpdateFunc* m_updateFunc; - ThreadInitFunc* m_threadInitFunc; - char m_threadName[64]; - int m_processor; - int m_priority; + EventQueue(UpdateFunc* updateFunc, ThreadInitFunc* threadInitFunc, + const char* threadName); + ~EventQueue(); + + EventQueue(const EventQueue&) = delete; + EventQueue& operator=(const EventQueue&) = delete; + + void setProcessor(int proc); + void setPriority(int priority); + void sendEvent(Level* pLevel); + void waitForFinish(); + + private: void init(); static int threadFunc(void* lpParam); void threadPoll(); - public: - EventQueue(UpdateFunc* updateFunc, ThreadInitFunc threadInitFunc, - const char* szThreadName); - void setProcessor(int proc) { - m_processor = proc; - if (m_thread) m_thread->SetProcessor(proc); - } - void setPriority(int priority) { - m_priority = priority; - if (m_thread) m_thread->SetPriority(priority); - } - void sendEvent(Level* pLevel); - void waitForFinish(); + std::unique_ptr m_thread; + std::queue m_queue; + std::mutex m_mutex; + std::condition_variable m_queueCondition; + std::condition_variable m_drainedCondition; + UpdateFunc* m_updateFunc; + ThreadInitFunc* m_threadInitFunc; + std::string m_threadName; + int m_processor; + int m_priority; + bool m_busy; + std::once_flag m_initOnce; + std::atomic m_stopRequested; }; C4JThread(C4JThreadStartFunc* startFunc, void* param, const char* threadName, int stackSize = 0); - C4JThread(const char* mainThreadName); // only used for the main thread + explicit C4JThread(const char* mainThreadName); ~C4JThread(); + C4JThread(const C4JThread&) = delete; + C4JThread& operator=(const C4JThread&) = delete; + void Run(); - bool isRunning() { return m_isRunning; } - bool hasStarted() { return m_hasStarted; } + + [[nodiscard]] bool isRunning() const noexcept { return m_isRunning.load(); } + [[nodiscard]] bool hasStarted() const noexcept { return m_hasStarted.load(); } + void SetProcessor(int proc); void SetPriority(int priority); + std::uint32_t WaitForCompletion(int timeoutMs); - int GetExitCode(); - char* getName() { return m_threadName; } - static void Sleep(int millisecs); - static C4JThread* getCurrentThread(); - static bool isMainThread(); - static char* getCurrentThreadName() { - return getCurrentThread()->getName(); + [[nodiscard]] int GetExitCode() const noexcept; + + [[nodiscard]] const char* getName() const noexcept { + return m_threadName.c_str(); } -#ifdef __ORBIS__ - static void PushAffinityAllCores(); // PS4 only - static void PopAffinity(); - static __thread SceKernelCpumask m_oldAffinityMask; -#endif // __ORBIS__ + static void Sleep(int millisecs); + static C4JThread* getCurrentThread() noexcept; + static bool isMainThread() noexcept; -#ifdef _XBOX_ONE - static void StaticInit(); -#endif + static const char* getCurrentThreadName() noexcept { + const C4JThread* pThread = getCurrentThread(); + return pThread ? pThread->getName() : "(4J) Unknown thread"; + } + + static void SetThreadName(std::uint32_t threadId, const char* threadName); + static void SetCurrentThreadName(const char* threadName); + + static void PushAffinityAllCores(); + static void PopAffinity(); private: + static void entryPoint(C4JThread* pThread); + static C4JThread& getMainThreadInstance() noexcept; + void* m_threadParam; C4JThreadStartFunc* m_startFunc; int m_stackSize; - char m_threadName[64]; - bool m_isRunning; - bool m_hasStarted; - int m_exitCode; - int64_t m_lastSleepTime; - static std::vector ms_threadList; - static CRITICAL_SECTION ms_threadListCS; + std::string m_threadName; + std::atomic m_isRunning; + std::atomic m_hasStarted; + std::atomic m_exitCode; -#ifdef _XBOX_ONE - // 4J Stu - On XboxOne the main thread is not the one that does all the - // static init, so we have to set this up later - static C4JThread* m_mainThread; -#else - static C4JThread m_mainThread; -#endif + std::thread::id m_threadID; + std::thread m_threadHandle; + std::unique_ptr m_completionFlag; -#ifdef __PS3__ - sys_ppu_thread_t m_threadID; - Event* m_completionFlag; - int m_priority; - static void entryPoint(uint64_t); -#elif defined __ORBIS__ - ScePthreadAttr m_threadAttr; - ScePthread m_threadID; - Event* m_completionFlag; - int m_priority; - static void* entryPoint(void*); -#elif defined __PSVITA__ - SceUID m_threadID; - Event* m_completionFlag; - int m_priority; - static SceInt32 entryPoint(SceSize argSize, void* pArgBlock); -#else - std::uint32_t m_threadID; - HANDLE m_threadHandle; - Event* m_completionFlag; - static DWORD WINAPI entryPoint(LPVOID lpParam); -#endif -}; -void SetThreadName(std::uint32_t threadId, const char* threadName); + std::atomic m_requestedProcessor; + std::atomic m_requestedPriority; + std::atomic m_nativeTid; + + static thread_local C4JThread* ms_currentThread; +}; \ No newline at end of file