aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordtentiion <dtentiongit@gmail.com>2026-03-02 23:50:45 +0000
committerGitHub <noreply@github.com>2026-03-03 07:50:45 +0800
commitb8a7f816b52775fdcfb3503f0000accb8cd65765 (patch)
treebcb865733ced35c675843ecb7932b9971be29fb5
parent8b28c20d7adc3824f96fbcc34ad65d778a97a05b (diff)
Win64: configurable username (username.txt) and persistent game settings (settings.dat) (#195)
-rw-r--r--Minecraft.Client/Common/Consoles_App.cpp45
-rw-r--r--Minecraft.Client/Extrax64Stubs.cpp9
-rw-r--r--Minecraft.Client/Windows64/Windows64_App.cpp57
-rw-r--r--Minecraft.Client/Windows64/Windows64_App.h2
-rw-r--r--Minecraft.Client/Windows64/Windows64_Minecraft.cpp27
5 files changed, 132 insertions, 8 deletions
diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp
index 0e02ab40..b476ca90 100644
--- a/Minecraft.Client/Common/Consoles_App.cpp
+++ b/Minecraft.Client/Common/Consoles_App.cpp
@@ -760,6 +760,43 @@ bool CMinecraftApp::LoadBeaconMenu(int iPad ,shared_ptr<Inventory> inventory, sh
//////////////////////////////////////////////
// GAME SETTINGS
//////////////////////////////////////////////
+
+#ifdef _WINDOWS64
+static void Win64_GetSettingsPath(char *outPath, DWORD size)
+{
+ GetModuleFileNameA(NULL, outPath, size);
+ char *lastSlash = strrchr(outPath, '\\');
+ if (lastSlash) *(lastSlash + 1) = '\0';
+ strncat_s(outPath, size, "settings.dat", _TRUNCATE);
+}
+static void Win64_SaveSettings(GAME_SETTINGS *gs)
+{
+ if (!gs) return;
+ char filePath[MAX_PATH] = {};
+ Win64_GetSettingsPath(filePath, MAX_PATH);
+ FILE *f = NULL;
+ if (fopen_s(&f, filePath, "wb") == 0 && f)
+ {
+ fwrite(gs, sizeof(GAME_SETTINGS), 1, f);
+ fclose(f);
+ }
+}
+static void Win64_LoadSettings(GAME_SETTINGS *gs)
+{
+ if (!gs) return;
+ char filePath[MAX_PATH] = {};
+ Win64_GetSettingsPath(filePath, MAX_PATH);
+ FILE *f = NULL;
+ if (fopen_s(&f, filePath, "rb") == 0 && f)
+ {
+ GAME_SETTINGS temp = {};
+ if (fread(&temp, sizeof(GAME_SETTINGS), 1, f) == 1)
+ memcpy(gs, &temp, sizeof(GAME_SETTINGS));
+ fclose(f);
+ }
+}
+#endif
+
void CMinecraftApp::InitGameSettings()
{
for(int i=0;i<XUSER_MAX_COUNT;i++)
@@ -780,6 +817,8 @@ void CMinecraftApp::InitGameSettings()
// clear this for now - it will come from reading the system values
memset(pProfileSettings,0,sizeof(C_4JProfile::PROFILESETTINGS));
SetDefaultOptions(pProfileSettings,i);
+ Win64_LoadSettings(GameSettingsA[i]);
+ ApplyGameSettingsChanged(i);
#elif defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__
C4JStorage::PROFILESETTINGS *pProfileSettings=StorageManager.GetDashboardProfileSettings(i);
// 4J-PB - don't cause an options write to happen here
@@ -2372,6 +2411,9 @@ void CMinecraftApp::CheckGameSettingsChanged(bool bOverride5MinuteTimer, int iPa
StorageManager.WriteToProfile(i,true, bOverride5MinuteTimer);
#else
ProfileManager.WriteToProfile(i,true, bOverride5MinuteTimer);
+#ifdef _WINDOWS64
+ Win64_SaveSettings(GameSettingsA[i]);
+#endif
#endif
GameSettingsA[i]->bSettingsChanged=false;
}
@@ -2385,6 +2427,9 @@ void CMinecraftApp::CheckGameSettingsChanged(bool bOverride5MinuteTimer, int iPa
StorageManager.WriteToProfile(iPad,true, bOverride5MinuteTimer);
#else
ProfileManager.WriteToProfile(iPad,true, bOverride5MinuteTimer);
+#ifdef _WINDOWS64
+ Win64_SaveSettings(GameSettingsA[iPad]);
+#endif
#endif
GameSettingsA[iPad]->bSettingsChanged=false;
}
diff --git a/Minecraft.Client/Extrax64Stubs.cpp b/Minecraft.Client/Extrax64Stubs.cpp
index f368afed..23b2c7f0 100644
--- a/Minecraft.Client/Extrax64Stubs.cpp
+++ b/Minecraft.Client/Extrax64Stubs.cpp
@@ -199,10 +199,11 @@ DWORD IQNetPlayer::GetSendQueueSize(IQNetPlayer * player, DWORD dwFlags) { retur
DWORD IQNetPlayer::GetCurrentRtt() { return 0; }
bool IQNetPlayer::IsHost() { return m_isHostPlayer; }
bool IQNetPlayer::IsGuest() { return false; }
-bool IQNetPlayer::IsLocal() { return !m_isRemote; }
-PlayerUID IQNetPlayer::GetXuid() { return (PlayerUID)(0xe000d45248242f2e + m_smallId); }
-LPCWSTR IQNetPlayer::GetGamertag() { return m_gamertag; }
-int IQNetPlayer::GetSessionIndex() { return m_smallId; }
+bool IQNetPlayer::IsLocal() { return true; }
+PlayerUID IQNetPlayer::GetXuid() { return INVALID_XUID; }
+extern wstring g_playerName;
+LPCWSTR IQNetPlayer::GetGamertag() { return g_playerName.empty() ? L"Windows" : g_playerName.c_str(); }
+int IQNetPlayer::GetSessionIndex() { return 0; }
bool IQNetPlayer::IsTalking() { return false; }
bool IQNetPlayer::IsMutedByLocalUser(DWORD dwUserIndex) { return false; }
bool IQNetPlayer::HasVoice() { return false; }
diff --git a/Minecraft.Client/Windows64/Windows64_App.cpp b/Minecraft.Client/Windows64/Windows64_App.cpp
index dbc1bfc5..461e8c34 100644
--- a/Minecraft.Client/Windows64/Windows64_App.cpp
+++ b/Minecraft.Client/Windows64/Windows64_App.cpp
@@ -10,11 +10,46 @@
#include "..\..\Minecraft.World\BiomeSource.h"
#include "..\..\Minecraft.World\LevelType.h"
+wstring g_playerName;
+
CConsoleMinecraftApp app;
+static void LoadPlayerName()
+{
+ if (!g_playerName.empty()) return;
+ g_playerName = L"Windows";
+
+ char exePath[MAX_PATH] = {};
+ GetModuleFileNameA(NULL, exePath, MAX_PATH);
+ char *lastSlash = strrchr(exePath, '\\');
+ if (lastSlash) *(lastSlash + 1) = '\0';
+ char filePath[MAX_PATH] = {};
+ _snprintf_s(filePath, sizeof(filePath), _TRUNCATE, "%susername.txt", exePath);
+
+ FILE *f = NULL;
+ if (fopen_s(&f, filePath, "r") == 0 && f)
+ {
+ char buf[128] = {};
+ if (fgets(buf, sizeof(buf), f))
+ {
+ int len = (int)strlen(buf);
+ while (len > 0 && (buf[len-1] == '\n' || buf[len-1] == '\r' || buf[len-1] == ' '))
+ buf[--len] = '\0';
+ if (len > 0)
+ {
+ wchar_t wbuf[128] = {};
+ mbstowcs(wbuf, buf, 127);
+ g_playerName = wbuf;
+ }
+ }
+ fclose(f);
+ }
+}
+
CConsoleMinecraftApp::CConsoleMinecraftApp() : CMinecraftApp()
{
m_bShutdown = false;
+ LoadPlayerName();
}
void CConsoleMinecraftApp::SetRichPresenceContext(int iPad, int contextId)
@@ -35,9 +70,27 @@ void CConsoleMinecraftApp::FatalLoadError()
void CConsoleMinecraftApp::CaptureSaveThumbnail()
{
+ RenderManager.CaptureThumbnail(&m_ThumbnailBuffer);
}
void CConsoleMinecraftApp::GetSaveThumbnail(PBYTE *pbData,DWORD *pdwSize)
{
+ // On a save caused by a create world, the thumbnail capture won't have happened
+ if (m_ThumbnailBuffer.Allocated())
+ {
+ if (pbData)
+ {
+ *pbData = new BYTE[m_ThumbnailBuffer.GetBufferSize()];
+ *pdwSize = m_ThumbnailBuffer.GetBufferSize();
+ memcpy(*pbData, m_ThumbnailBuffer.GetBufferPointer(), *pdwSize);
+ }
+ m_ThumbnailBuffer.Release();
+ }
+ else
+ {
+ // No capture happened (e.g. first save on world creation) leave thumbnail as NULL
+ if (pbData) *pbData = NULL;
+ if (pdwSize) *pdwSize = 0;
+ }
}
void CConsoleMinecraftApp::ReleaseSaveThumbnail()
{
@@ -57,8 +110,8 @@ void CConsoleMinecraftApp::TemporaryCreateGameStart()
Minecraft *pMinecraft=Minecraft::GetInstance();
app.ReleaseSaveThumbnail();
ProfileManager.SetLockedProfile(0);
- extern wchar_t g_Win64UsernameW[17];
- pMinecraft->user->name = g_Win64UsernameW;
+ LoadPlayerName();
+ pMinecraft->user->name = g_playerName;
app.ApplyGameSettingsChanged(0);
////////////////////////////////////////////////////////////////////////////////////////////// From CScene_MultiGameJoinLoad::OnInit
diff --git a/Minecraft.Client/Windows64/Windows64_App.h b/Minecraft.Client/Windows64/Windows64_App.h
index de8f6d85..bff916ec 100644
--- a/Minecraft.Client/Windows64/Windows64_App.h
+++ b/Minecraft.Client/Windows64/Windows64_App.h
@@ -1,7 +1,9 @@
#pragma once
+#include "4JLibs\inc\4J_Render.h"
class CConsoleMinecraftApp : public CMinecraftApp
{
+ ImageFileBuffer m_ThumbnailBuffer;
public:
CConsoleMinecraftApp();
diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
index 5bd1a546..a1bdcd0f 100644
--- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
+++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
@@ -827,7 +827,16 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
- dyn_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
+ // 4J-Win64: set CWD to exe dir so asset paths resolve correctly
+ {
+ char szExeDir[MAX_PATH] = {};
+ GetModuleFileNameA(NULL, szExeDir, MAX_PATH);
+ char *pSlash = strrchr(szExeDir, '\\');
+ if (pSlash) { *(pSlash + 1) = '\0'; SetCurrentDirectoryA(szExeDir); }
+ }
+
+ // Declare DPI awareness so GetSystemMetrics returns physical pixels
+ SetProcessDPIAware();
g_iScreenWidth = GetSystemMetrics(SM_CXSCREEN);
g_iScreenHeight = GetSystemMetrics(SM_CYSCREEN);
@@ -1361,7 +1370,21 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
}
- // F11 toggles fullscreen
+ // F3 toggles the debug console overlay, F11 toggles fullscreen
+ if (KMInput.IsKeyPressed(VK_F3))
+ {
+ static bool s_debugConsole = false;
+ s_debugConsole = !s_debugConsole;
+ ui.ShowUIDebugConsole(s_debugConsole);
+ }
+
+#ifdef _DEBUG_MENUS_ENABLED
+ if (KMInput.IsKeyPressed(VK_F4))
+ {
+ ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_DebugOverlay, NULL, eUILayer_Debug);
+ }
+#endif
+
if (KMInput.IsKeyPressed(VK_F11))
{
ToggleFullscreen();