mirror of
https://forge.banditvault.co.uk/racoon/MinecraftConsoles.git
synced 2026-07-06 03:38:22 +00:00
feat: Implement LCELive username handling and logging for Windows64 client
This commit is contained in:
@@ -48,6 +48,104 @@
|
||||
#include "../DLCTexturePack.h"
|
||||
#include "DLC/DLCPack.h"
|
||||
#include "../StringTable.h"
|
||||
|
||||
#if defined(_WINDOWS64) && !defined(MINECRAFT_SERVER_BUILD)
|
||||
namespace
|
||||
{
|
||||
FILE *g_clientDebugLogFile = nullptr;
|
||||
CRITICAL_SECTION g_clientDebugLogLock;
|
||||
INIT_ONCE g_clientDebugLogOnce = INIT_ONCE_STATIC_INIT;
|
||||
|
||||
static bool BuildExeRelativeLogPath(const char *fileName, char *outPath, size_t outPathSize)
|
||||
{
|
||||
if (fileName == nullptr || outPath == nullptr || outPathSize == 0)
|
||||
return false;
|
||||
|
||||
outPath[0] = 0;
|
||||
|
||||
char exePath[MAX_PATH] = {};
|
||||
DWORD len = GetModuleFileNameA(nullptr, exePath, MAX_PATH);
|
||||
if (len == 0 || len >= MAX_PATH)
|
||||
return false;
|
||||
|
||||
char *lastSlash = strrchr(exePath, '\\');
|
||||
if (lastSlash != nullptr)
|
||||
*(lastSlash + 1) = 0;
|
||||
|
||||
if (strcpy_s(outPath, outPathSize, exePath) != 0)
|
||||
return false;
|
||||
if (strcat_s(outPath, outPathSize, "logs\\") != 0)
|
||||
return false;
|
||||
|
||||
CreateDirectoryA(outPath, nullptr);
|
||||
|
||||
if (strcat_s(outPath, outPathSize, fileName) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool OpenClientDebugLog()
|
||||
{
|
||||
char logPath[MAX_PATH] = {};
|
||||
char previousPath[MAX_PATH] = {};
|
||||
|
||||
if (!BuildExeRelativeLogPath("client.log", logPath, sizeof(logPath)) ||
|
||||
!BuildExeRelativeLogPath("client.previous.log", previousPath, sizeof(previousPath)))
|
||||
{
|
||||
strcpy_s(logPath, sizeof(logPath), "client.log");
|
||||
strcpy_s(previousPath, sizeof(previousPath), "client.previous.log");
|
||||
}
|
||||
|
||||
DeleteFileA(previousPath);
|
||||
MoveFileExA(logPath, previousPath, MOVEFILE_REPLACE_EXISTING);
|
||||
|
||||
if (fopen_s(&g_clientDebugLogFile, logPath, "w") != 0 || g_clientDebugLogFile == nullptr)
|
||||
{
|
||||
if (fopen_s(&g_clientDebugLogFile, "client.log", "w") != 0)
|
||||
g_clientDebugLogFile = nullptr;
|
||||
}
|
||||
|
||||
if (g_clientDebugLogFile == nullptr)
|
||||
return false;
|
||||
|
||||
fprintf(g_clientDebugLogFile, "Minecraft client debug log started. pid=%lu\n",
|
||||
static_cast<unsigned long>(GetCurrentProcessId()));
|
||||
fflush(g_clientDebugLogFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK InitializeClientDebugLog(PINIT_ONCE, PVOID, PVOID *)
|
||||
{
|
||||
InitializeCriticalSection(&g_clientDebugLogLock);
|
||||
OpenClientDebugLog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void WriteClientDebugLogLine(const char *message)
|
||||
{
|
||||
if (message == nullptr || message[0] == 0)
|
||||
return;
|
||||
|
||||
InitOnceExecuteOnce(&g_clientDebugLogOnce, &InitializeClientDebugLog, nullptr, nullptr);
|
||||
if (g_clientDebugLogFile == nullptr)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&g_clientDebugLogLock);
|
||||
fprintf(g_clientDebugLogFile, "[%10llu][T%lu] %s",
|
||||
static_cast<unsigned long long>(GetTickCount64()),
|
||||
static_cast<unsigned long>(GetCurrentThreadId()),
|
||||
message);
|
||||
|
||||
const size_t length = strlen(message);
|
||||
if (length == 0 || (message[length - 1] != '\n' && message[length - 1] != '\r'))
|
||||
fputc('\n', g_clientDebugLogFile);
|
||||
|
||||
fflush(g_clientDebugLogFile);
|
||||
LeaveCriticalSection(&g_clientDebugLogLock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef _XBOX
|
||||
#include "../ArchiveFile.h"
|
||||
#endif
|
||||
@@ -243,6 +341,15 @@ CMinecraftApp::CMinecraftApp()
|
||||
void CMinecraftApp::DebugPrintf(const char *szFormat, ...)
|
||||
{
|
||||
|
||||
#if defined(_WINDOWS64) && !defined(MINECRAFT_SERVER_BUILD)
|
||||
va_list fileAp;
|
||||
va_start(fileAp, szFormat);
|
||||
char fileBuf[1024];
|
||||
vsnprintf(fileBuf, sizeof(fileBuf), szFormat, fileAp);
|
||||
va_end(fileAp);
|
||||
WriteClientDebugLogLine(fileBuf);
|
||||
#endif
|
||||
|
||||
#ifndef _FINAL_BUILD
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
@@ -265,9 +372,22 @@ void CMinecraftApp::DebugPrintf(const char *szFormat, ...)
|
||||
|
||||
void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...)
|
||||
{
|
||||
#ifndef _FINAL_BUILD
|
||||
if(user == USER_NONE)
|
||||
return;
|
||||
|
||||
#if defined(_WINDOWS64) && !defined(MINECRAFT_SERVER_BUILD)
|
||||
va_list fileAp;
|
||||
va_start(fileAp, szFormat);
|
||||
char fileBuf[1024];
|
||||
vsnprintf(fileBuf, sizeof(fileBuf), szFormat, fileAp);
|
||||
va_end(fileAp);
|
||||
|
||||
char taggedFileBuf[1100];
|
||||
_snprintf_s(taggedFileBuf, sizeof(taggedFileBuf), _TRUNCATE, "[user=%d] %s", user, fileBuf);
|
||||
WriteClientDebugLogLine(taggedFileBuf);
|
||||
#endif
|
||||
|
||||
#ifndef _FINAL_BUILD
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
|
||||
@@ -1110,6 +1110,22 @@ namespace Win64LceLive
|
||||
return token;
|
||||
}
|
||||
|
||||
bool GetSignedInUsername(std::wstring *outUsername)
|
||||
{
|
||||
if (outUsername == nullptr)
|
||||
return false;
|
||||
|
||||
EnsureInitialized();
|
||||
|
||||
outUsername->clear();
|
||||
EnterCriticalSection(&g_state.lock);
|
||||
const bool hasUsername = g_state.session.valid && !g_state.session.username.empty();
|
||||
if (hasUsername)
|
||||
*outUsername = Utf8ToWide(g_state.session.username);
|
||||
LeaveCriticalSection(&g_state.lock);
|
||||
return hasUsername;
|
||||
}
|
||||
|
||||
TicketResult RequestJoinTicketSync()
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
@@ -114,6 +114,10 @@ namespace Win64LceLive
|
||||
// Synchronous — reads from cached state, never blocks.
|
||||
std::string GetAccessToken();
|
||||
|
||||
// Returns the signed-in LCELive username if a cached session is active.
|
||||
// Synchronous; reads from cached state, never blocks.
|
||||
bool GetSignedInUsername(std::wstring* outUsername);
|
||||
|
||||
// Requests a short-lived join ticket from the LceLive API.
|
||||
// Synchronous blocking call (~localhost RTT). Call from a non-UI thread.
|
||||
TicketResult RequestJoinTicketSync();
|
||||
|
||||
@@ -205,6 +205,9 @@ static bool g_bResizeReady = false;
|
||||
|
||||
char g_Win64Username[17] = { 0 };
|
||||
wchar_t g_Win64UsernameW[17] = { 0 };
|
||||
static char g_Win64FallbackUsername[17] = { 0 };
|
||||
static const char *g_Win64FallbackUsernameSource = "default";
|
||||
static bool g_Win64NameLockedToLaunchOverride = false;
|
||||
|
||||
// Fullscreen toggle state
|
||||
static bool g_isFullscreen = false;
|
||||
@@ -214,6 +217,7 @@ struct Win64LaunchOptions
|
||||
{
|
||||
int screenMode;
|
||||
bool fullscreen;
|
||||
bool usernameOverride;
|
||||
};
|
||||
|
||||
static void CopyWideArgToAnsi(LPCWSTR source, char* dest, size_t destSize)
|
||||
@@ -229,6 +233,53 @@ static void CopyWideArgToAnsi(LPCWSTR source, char* dest, size_t destSize)
|
||||
dest[destSize - 1] = 0;
|
||||
}
|
||||
|
||||
static void ApplyWin64Username(const char *username, const char *source, bool updateRuntime)
|
||||
{
|
||||
if (username == nullptr || username[0] == 0)
|
||||
return;
|
||||
|
||||
char nextUsername[sizeof(g_Win64Username)] = {};
|
||||
strncpy_s(nextUsername, sizeof(nextUsername), username, _TRUNCATE);
|
||||
if (nextUsername[0] == 0)
|
||||
return;
|
||||
|
||||
const bool changed = strcmp(g_Win64Username, nextUsername) != 0;
|
||||
strncpy_s(g_Win64Username, sizeof(g_Win64Username), nextUsername, _TRUNCATE);
|
||||
MultiByteToWideChar(CP_ACP, 0, g_Win64Username, -1, g_Win64UsernameW, static_cast<int>(_countof(g_Win64UsernameW)));
|
||||
|
||||
if (changed)
|
||||
GameLog("[IDENTITY] Using %s username: %s\n", source != nullptr ? source : "configured", g_Win64Username);
|
||||
|
||||
if (updateRuntime)
|
||||
{
|
||||
wcsncpy_s(IQNet::m_player[0].m_gamertag, 32, g_Win64UsernameW, _TRUNCATE);
|
||||
|
||||
Minecraft *minecraft = Minecraft::GetInstance();
|
||||
if (minecraft != nullptr && minecraft->user != nullptr)
|
||||
minecraft->user->name = g_Win64UsernameW;
|
||||
}
|
||||
}
|
||||
|
||||
static void RefreshWin64UsernameFromIdentity(bool updateRuntime)
|
||||
{
|
||||
if (!g_Win64NameLockedToLaunchOverride)
|
||||
{
|
||||
std::wstring lceLiveUsername;
|
||||
if (Win64LceLive::GetSignedInUsername(&lceLiveUsername) && !lceLiveUsername.empty())
|
||||
{
|
||||
char lceLiveUsernameAnsi[sizeof(g_Win64Username)] = {};
|
||||
CopyWideArgToAnsi(lceLiveUsername.c_str(), lceLiveUsernameAnsi, sizeof(lceLiveUsernameAnsi));
|
||||
if (lceLiveUsernameAnsi[0] != 0)
|
||||
{
|
||||
ApplyWin64Username(lceLiveUsernameAnsi, "LCELive", updateRuntime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApplyWin64Username(g_Win64FallbackUsername, g_Win64FallbackUsernameSource, updateRuntime);
|
||||
}
|
||||
|
||||
// ---------- Persistent options (options.txt next to exe) ----------
|
||||
static void GetOptionsFilePath(char *out, size_t outSize)
|
||||
{
|
||||
@@ -318,6 +369,7 @@ static Win64LaunchOptions ParseLaunchOptions()
|
||||
if (_wcsicmp(argv[i], L"-name") == 0 && (i + 1) < argc)
|
||||
{
|
||||
CopyWideArgToAnsi(argv[++i], g_Win64Username, sizeof(g_Win64Username));
|
||||
options.usernameOverride = g_Win64Username[0] != 0;
|
||||
}
|
||||
else if (_wcsicmp(argv[i], L"-ip") == 0 && (i + 1) < argc)
|
||||
{
|
||||
@@ -1535,6 +1587,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
if (len > 0)
|
||||
{
|
||||
strncpy_s(g_Win64Username, sizeof(g_Win64Username), buf, _TRUNCATE);
|
||||
g_Win64FallbackUsernameSource = "username.txt";
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
@@ -1542,6 +1595,9 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
|
||||
// Load stuff from launch options, including username
|
||||
const Win64LaunchOptions launchOptions = ParseLaunchOptions();
|
||||
g_Win64NameLockedToLaunchOverride = launchOptions.usernameOverride;
|
||||
if (launchOptions.usernameOverride)
|
||||
g_Win64FallbackUsernameSource = "launch argument";
|
||||
ApplyScreenMode(launchOptions.screenMode);
|
||||
|
||||
// Ensure uid.dat exists from startup (before any multiplayer/login path).
|
||||
@@ -1552,9 +1608,11 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
{
|
||||
// Default username will be "Player"
|
||||
strncpy_s(g_Win64Username, sizeof(g_Win64Username), "Player", _TRUNCATE);
|
||||
g_Win64FallbackUsernameSource = "default";
|
||||
}
|
||||
|
||||
MultiByteToWideChar(CP_ACP, 0, g_Win64Username, -1, g_Win64UsernameW, 17);
|
||||
strncpy_s(g_Win64FallbackUsername, sizeof(g_Win64FallbackUsername), g_Win64Username, _TRUNCATE);
|
||||
RefreshWin64UsernameFromIdentity(false);
|
||||
|
||||
// convert servers.txt to servers.db
|
||||
if (GetFileAttributesA("servers.txt") != INVALID_FILE_ATTRIBUTES &&
|
||||
@@ -1855,6 +1913,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
|
||||
// LceLive platform service ticks — keep auth token fresh, drive P2P + signaling.
|
||||
Win64LceLive::Tick();
|
||||
RefreshWin64UsernameFromIdentity(true);
|
||||
Win64LceLiveP2P::P2PTick();
|
||||
Win64LceLiveSignaling::Tick();
|
||||
|
||||
|
||||
@@ -103,6 +103,8 @@ Important: launch from the output directory so relative asset paths resolve corr
|
||||
| `-name <username>` | Override in-game username |
|
||||
| `-fullscreen` | Launch in fullscreen |
|
||||
|
||||
When signed in to LCELive, the Windows64 client uses your LCELive username in game. If you are signed out, it falls back to `username.txt`, then `Player`. The `-name` launch argument still overrides both for local testing.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
@@ -121,10 +123,12 @@ Logs are written next to the executable in `logs`:
|
||||
|
||||
- `logs/game.log`
|
||||
- `logs/game.previous.log`
|
||||
- `logs/client.log`
|
||||
- `logs/client.previous.log`
|
||||
- `logs/lcelive.log`
|
||||
- `logs/lcelive.previous.log`
|
||||
|
||||
If networking fails, inspect `logs/lcelive.log` first.
|
||||
`client.log` is enabled for Windows64 client release builds too. It captures the game-wide `app.DebugPrintf` stream: world, packet, storage, audio, UI, and gameplay diagnostics. If networking fails, inspect `logs/lcelive.log` first.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define VER_PRODUCTBUILD 560
|
||||
#define VER_PRODUCTVERSION_STR_W L"1.1.0.0"
|
||||
#define VER_PRODUCTVERSION_STR_W L"1.2.0.0"
|
||||
#define VER_FILEVERSION_STR_W VER_PRODUCTVERSION_STR_W
|
||||
#define VER_BRANCHVERSION_STR_W L"UNKNOWN BRANCH"
|
||||
#define VER_NETWORK VER_PRODUCTBUILD
|
||||
|
||||
Reference in New Issue
Block a user