MinecraftConsoles/Minecraft.Client/Common/UI/NativeUIRenderer.h
MrTheShy 4f2352361a Add Mojang/Ely.by/offline authentication system
The old Windows64 port had no real player identity — it used hardcoded
fake XUIDs, so anyone could impersonate anyone. This replaces that with
proper auth supporting Mojang, Ely.by, and offline accounts.

MCAuth library (new, MCAuth/):
  Mojang auth via MSA device code flow (XBL, SISU, MC services),
  Ely.by via Yggdrasil with 2FA, offline UUID generation matching
  Java Edition (MD5 v3 from "OfflinePlayer:<name>"). Multi-account
  manager with background token refresh, per-slot sessions, and
  on-disk token persistence. Server-side session verification via
  Mojang/Ely.by hasJoined API. Skin fetching and PNG validation
  from texture servers.

Network protocol (version bumped to 80):
  Three new packets (AuthScheme, AuthResponse, AuthResult) implement
  a server-driven auth handshake before login completes. Player
  identity migrated from 64-bit XUID to 128-bit GameUUID backed by
  two uint64 fields (hi/lo). readPlayerUID/writePlayerUID now
  serialize 16 bytes on the wire. Old and new clients cannot connect
  to each other — version mismatch is rejected at PreLogin.

Save migration:
  Map data mappings auto-migrate from old format: the old 64-bit
  XUID is placed in hi, lo is set to 0 as a sentinel. On first
  access by the real player, the sentinel entry is upgraded in-place
  to the full 128-bit UUID. Format detection is by file size (2080,
  2112, or 4160 bytes). Player .dat filenames inside saveData.ms
  change from decimal XUID to dashed UUID — old saves need manual
  entry renaming in the archive.

UI:
  NativeUIRenderer: immediate-mode drawing system (quads, text,
  9-slice panels, scrollbars, focus lists) for rendering auth
  screens without Flash/Scaleform. UIScene_MSAuth handles device
  code display, Ely.by credential input with 2FA, per-account
  skin head preview, and multi-account add/remove/switch.

Server:
  online-mode and auth-provider (mojang/elyby) in server.properties.
  Whitelist and ban checks validate against the server-verified UUID.
  Incompatible auth scheme logs which provider the server expects
  vs what the client is using.

Also fixes a pre-existing exploit where any client could send a
DebugOptionsPacket to grant themselves CraftAnything and other debug
privileges on any server — now requires OP status server-side.
2026-03-23 01:14:23 +01:00

347 lines
14 KiB
C++

#pragma once
#include <cstdint>
#include <vector>
#include <string>
// NativeUI — Direct D3D11 2D rendering for SWF-free UIScene subclasses.
//
// Renders rectangles, text, and widgets via raw D3D11 draw calls,
// completely independent of the Tesselator/RenderManager pipeline.
//
// Usage:
//
// void MyScene::render(S32 w, S32 h, C4JRender::eViewportType vp)
// {
// if (!m_hasTickedOnce) return;
// NativeUI::BeginFrame();
//
// NativeUI::DrawRect(0, 0, 1280, 720, 0xCC000000u);
// NativeUI::DrawShadowText(640, 300, L"Hello",
// 0xFFFFFFFFu, 22.0f, ALIGN_CENTER_X);
//
// NativeUI::EndFrame();
// }
//
// Coordinate space: 1280 x 720 virtual canvas (resolution-independent).
// Color format: 0xAARRGGBB (alpha 0xFF = opaque).
// Font size: Height in virtual pixels. Bitmap font is 8 units tall;
// system scales to match. Common sizes: 8, 12, 14, 16, 22.
namespace NativeUI
{
// ---- Alignment flags ------------------------------------------
enum : uint32_t
{
ALIGN_LEFT = 0x00u,
ALIGN_RIGHT = 0x01u,
ALIGN_CENTER_X = 0x02u,
ALIGN_CENTER_Y = 0x04u,
ALIGN_BOTTOM = 0x08u,
};
// ---- Lifecycle ------------------------------------------------
void BeginFrame();
void EndFrame();
void Shutdown();
// ---- Input helpers (Windows64) -----------------------------------
// Convert window mouse coords to 1280x720 virtual canvas.
// Returns false if the window handle is invalid or has zero size.
bool GetMouseVirtual(float& outX, float& outY);
// ---- Primitives -----------------------------------------------
// Filled axis-aligned rectangle.
void DrawRect(float x, float y, float w, float h, uint32_t color);
// Fullscreen rectangle that covers the entire backbuffer (ignores 16:9 viewport).
// Use for dim overlays, backgrounds, etc. that must reach into pillarbox/letterbox bands.
void DrawRectFullscreen(uint32_t color);
// Filled rectangle with rounded corners (radius in virtual pixels).
void DrawRoundedRect(float x, float y, float w, float h,
float radius, uint32_t color);
// Rounded border (outline only, no fill).
void DrawRoundedBorder(float x, float y, float w, float h,
float radius, float thickness, uint32_t color);
// Outlined rectangle (border only, no fill).
void DrawBorder(float x, float y, float w, float h,
float thickness, uint32_t color);
// Horizontal line.
void DrawLine(float x, float y, float length, float thickness,
uint32_t color);
// Vertical line.
void DrawLineV(float x, float y, float length, float thickness,
uint32_t color);
// Filled rectangle with gradient (top to bottom).
void DrawGradientRect(float x, float y, float w, float h,
uint32_t topColor, uint32_t bottomColor);
// Rounded rect with gradient (top to bottom).
void DrawGradientRoundedRect(float x, float y, float w, float h,
float radius,
uint32_t topColor, uint32_t bottomColor);
// Drop shadow behind a rectangle (semi-transparent, offset).
void DrawDropShadow(float x, float y, float w, float h,
float offset = 4.0f, float spread = 6.0f,
uint32_t color = 0x60000000u);
// Panel with rounded corners, drop shadow, and optional border.
void DrawPanel(float x, float y, float w, float h,
float radius = 8.0f,
uint32_t bgColor = 0xF0181818u,
uint32_t borderColor = 0xFF333333u,
float borderThick = 1.0f,
bool shadow = true);
// Horizontal divider line with optional fade at edges.
void DrawDivider(float x, float y, float w,
uint32_t color = 0xFF333333u,
float thickness = 1.0f);
// ---- Text -----------------------------------------------------
void DrawText(float x, float y, const wchar_t* text,
uint32_t color, float size = 14.0f,
uint32_t align = ALIGN_LEFT);
void DrawShadowText(float x, float y, const wchar_t* text,
uint32_t color, float size = 14.0f,
uint32_t align = ALIGN_LEFT);
float DrawTextWrapped(float x, float y, const wchar_t* text,
float maxWidth, uint32_t color,
float size = 14.0f, uint32_t align = ALIGN_LEFT);
void MeasureText(const wchar_t* text, float size,
float* outWidth, float* outHeight);
float LineHeight(float size);
// ---- Clipping -------------------------------------------------
void PushClipRect(float x, float y, float w, float h);
void PopClipRect();
// ---- Widgets --------------------------------------------------
void DrawButton(float x, float y, float w, float h,
const wchar_t* label, bool focused,
bool hovered = false, float labelSize = 16.0f);
// Text input box from gui/gui.png (y=46, 20px tall in atlas).
void DrawTextBox(float x, float y, float w, float h,
uint32_t tint = 0xFFFFFFFFu);
// Clickable link text with underline. Opens URL on activation.
void DrawLink(float x, float y, const wchar_t* text,
const char* url, bool focused, bool hovered = false,
float size = 14.0f, uint32_t align = ALIGN_LEFT,
float* outX = nullptr, float* outY = nullptr,
float* outW = nullptr, float* outH = nullptr);
void DrawProgressBar(float x, float y, float w, float h,
float progress,
uint32_t fillColor = 0xFF1A71D1u,
uint32_t trackColor = 0xFF333333u);
void DrawSpinner(float cx, float cy, float radius, int tick,
uint32_t color = 0xFFFFFFFFu);
void DrawCheckbox(float x, float y, float size,
bool checked, bool focused,
bool hovered = false);
void DrawSlider(float x, float y, float w, float h,
float value, bool focused,
bool hovered = false,
uint32_t fillColor = 0xFF1A71D1u,
uint32_t trackColor = 0xFF333333u);
void DrawTooltip(float x, float y, const wchar_t* text,
float size = 12.0f);
// Open a URL in the system default browser (Windows only, no-op elsewhere).
void OpenURL(const char* url);
// ---- Texture drawing ------------------------------------------
// Load a texture from the game's resource pack (e.g. L"/gui/container.png").
// Returns an internal texture ID for use with Draw calls.
// Textures are cached — calling this multiple times with the same path is cheap.
int LoadTexture(const wchar_t* path);
// Load a pre-registered texture by TEXTURE_NAME enum value.
// See Textures.h for the full list (TN_GUI_GUI, TN_TERRAIN, etc.).
int LoadTextureByName(int textureName);
// Load a PNG file and create a D3D11 texture directly (bypasses RenderManager).
// Decodes via WIC, creates DXGI_FORMAT_R8G8B8A8_UNORM texture.
// Use this for externally sourced PNGs (e.g. Mojang skins) where the
// RenderManager's pixel format assumptions may not match.
// Returns texture ID (for use with DrawTexture/DrawTextureUV), or -1 on failure.
// Caches by path. Must be called from the main/render thread.
int LoadTextureFromFileDirect(const char* filePath,
int* outWidth = nullptr, int* outHeight = nullptr);
// Load a texture from an arbitrary filesystem path relative to the EXE dir.
// e.g. "Common/Media/Graphics/PanelsAndTabs/Panel_MM.png"
// Returns texture ID, or -1 on failure. Caches by path.
// Also returns texture dimensions via optional out params.
int LoadTextureFromFile(const char* filePath,
int* outWidth = nullptr, int* outHeight = nullptr);
// 9-slice panel: draws a scalable panel from 9 texture pieces.
// basePath = folder + prefix, e.g. "Common/Media/Graphics/PanelsAndTabs/Panel"
// Auto-detects naming convention:
// Convention A: _TL, _TM, _TR, _ML, _MM, _MR, _BL, _BM, _BR
// Convention B: _Top_L, _Top_M, _Top_R, _Mid_L, _Mid_M, _Mid_R, _Bot_L, _Bot_M, _Bot_R
struct NineSlice
{
int tl, tm, tr; // texture IDs: top-left, top-mid, top-right
int ml, mm, mr; // mid-left, mid-mid, mid-right
int bl, bm, br; // bot-left, bot-mid, bot-right
int cornerW, cornerH; // corner piece dimensions
bool valid;
};
// Load a 9-slice panel set from disk. Caches internally.
// Supports both naming conventions (auto-detected).
NineSlice LoadNineSlice(const char* basePath);
// Draw a 9-slice panel scaled to any size.
void DrawNineSlice(float x, float y, float w, float h,
const NineSlice& ns, uint32_t tint = 0xFFFFFFFFu);
// 3-slice horizontal strip (tabs, bars).
// basePath e.g. "Common/Media/Graphics/PanelsAndTabs/Tab"
// Expects: {basePath}_Left.png, _Middle.png, _Right.png
struct ThreeSlice
{
int left, mid, right; // texture IDs
int capW, capH; // left/right cap dimensions
bool valid;
};
// Load a 3-slice strip from disk. Caches internally.
ThreeSlice LoadThreeSlice(const char* basePath);
// Draw a 3-slice strip scaled horizontally.
void DrawThreeSlice(float x, float y, float w, float h,
const ThreeSlice& ts, uint32_t tint = 0xFFFFFFFFu);
// Draw a texture filling the given rect. tint multiplies the texture color.
// Pass 0xFFFFFFFF for no tint. textureId comes from LoadTexture/LoadTextureByName.
void DrawTexture(float x, float y, float w, float h,
int textureId, uint32_t tint = 0xFFFFFFFFu);
// Draw a sub-region of a texture (UV rect in [0,1] space).
void DrawTextureUV(float x, float y, float w, float h,
int textureId,
float u0, float v0, float u1, float v1,
uint32_t tint = 0xFFFFFFFFu);
// Draw a texture clipped to rounded corners (uses scissor).
void DrawTextureRounded(float x, float y, float w, float h,
int textureId, float radius,
uint32_t tint = 0xFFFFFFFFu);
// Draw a texture scaled to fit (maintaining aspect ratio, centered).
// texW/texH = source texture dimensions in pixels.
void DrawTextureFit(float x, float y, float w, float h,
int textureId, int texW, int texH,
uint32_t tint = 0xFFFFFFFFu);
// ---- Focus list -----------------------------------------------
class FocusList
{
public:
struct Entry { int id; float x, y, w, h; };
void Clear() { m_entries.clear(); m_hoveredId = -1; }
void Add(int id, float x, float y, float w, float h);
int GetFocused() const;
int GetHovered() const { return m_hoveredId; }
bool IsFocused(int id) const { return GetFocused() == id; }
bool IsHovered(int id) const { return m_lastDevice == eDevice_Mouse && m_hoveredId == id; }
bool IsActive(int id) const { return IsFocused(id) || IsHovered(id); }
// For rendering: show highlight based on last-used input device.
// Gamepad last → show focus ring on focused element, ignore mouse hover.
// Mouse last → show hover highlight, suppress gamepad focus ring.
bool ShowFocus(int id) const
{
if (m_lastDevice == eDevice_Mouse)
return m_hoveredId >= 0 && m_hoveredId == id;
// Gamepad or no device: show gamepad focus, ignore hover
return IsFocused(id);
}
void MoveNext();
void MovePrev();
void SetFocus(int id);
bool HitTest(float mx, float my, int& outId) const;
bool UpdateHover(float mx, float my);
void ClearHover() { m_hoveredId = -1; }
int Count() const { return (int)m_entries.size(); }
// Mouse hover — call once per tick from tick().
// Updates hover state, plays hover sound. No click handling.
void TickMouse();
// True while the mouse was used for the last interaction.
bool IsMouseConsumed() const { return m_mouseConsumed; }
// Gamepad/keyboard — standard menu key handling.
// Handles UP/DOWN/LEFT/RIGHT (navigation with sound),
// OK (returns focused id with press sound),
// CANCEL (returns backId with back sound).
//
// backId = the control id to return when CANCEL is pressed.
//
// Returns: >=0 = activated element id (OK or CANCEL)
// -1 = navigation happened (focus moved, no activation)
// -2 = key not handled (scene should set handled=false)
static constexpr int RESULT_NAVIGATED = -1;
static constexpr int RESULT_UNHANDLED = -2;
// panelX/Y/W/H = scene panel bounds. Used to hit-test mouse clicks
// when UIController sends ACTION_MENU_OK from a left-click.
int HandleMenuKey(int key, int backId = 0,
float panelX = 0, float panelY = 0,
float panelW = 0, float panelH = 0);
// Input device tracking — same concept as Iggy's lastUsedDevice.
// When the gamepad navigates, mouse hover is suppressed.
// When the mouse moves, gamepad focus ring is suppressed.
enum ELastDevice { eDevice_None, eDevice_Gamepad, eDevice_Mouse };
ELastDevice GetLastDevice() const { return m_lastDevice; }
private:
std::vector<Entry> m_entries;
int m_focusIdx = 0;
int m_hoveredId = -1;
int m_lastHoveredId = -1; // hover id from previous tick
bool m_mouseConsumed = false; // true = click in progress, don't re-fire
ELastDevice m_lastDevice = eDevice_None;
float m_lastMouseX = -1.0f;
float m_lastMouseY = -1.0f;
};
} // namespace NativeUI