Files
coah80-LegacyVulkEdition/Minecraft.Client/CrossPlatform/NkGameMenus.cpp

489 lines
17 KiB
C++

#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#include "nuklear.h"
#include "NkGameMenus.h"
#include "NkCommon.h"
#include "MenuScreens.h"
#include "NuklearBridge.h"
#include <cstring>
#include <cstdio>
namespace lve { namespace ui {
static const float BASE_W = 1280.0f;
static const float BASE_H = 720.0f;
static const float BUTTON_X = 415.0f;
static const float BUTTON_W = 450.0f;
static const float BUTTON_H = 40.0f;
static const float BUTTON_Y_START = 200.0f;
static const float BUTTON_Y_STEP = 50.0f;
static const float TITLE_Y = 120.0f;
static const float TITLE_H = 50.0f;
static const float CHECKBOX_ROW_H = 40.0f;
static const float LIST_ITEM_H = 40.0f;
static const float FIELD_H = 36.0f;
static const float PANEL_X = 290.0f;
static const float PANEL_W = 700.0f;
static const float PANEL_Y = 80.0f;
static const float SIGN_FIELD_W = 360.0f;
static const float SIGN_FIELD_H = 32.0f;
static const float SIGN_FIELD_GAP = 8.0f;
GameMenuAction renderHostOptions(nk_context *ctx, int winW, int winH,
MenuTextures &tex, HostOptionsState &state)
{
GameMenuAction result = kGameAction_None;
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
pushCleanStyle(ctx);
if (nk_begin(ctx, "HostOptions", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
drawTitle(ctx, "Host Options", winW, winH, TITLE_Y, TITLE_H);
float rowW = BUTTON_W * scaleX;
float rowH = CHECKBOX_ROW_H * scaleY;
float rowX = BUTTON_X * scaleX;
float step = BUTTON_Y_STEP * scaleY;
float baseY = BUTTON_Y_START * scaleY;
int row = 0;
state.fireSpreads = drawCheckbox(ctx, "Fire Spreads",
rowX, baseY + step * (float)row, rowW, rowH,
state.fireSpreads, true, winH, tex);
row++;
state.tntExplodes = drawCheckbox(ctx, "TNT Explodes",
rowX, baseY + step * (float)row, rowW, rowH,
state.tntExplodes, true, winH, tex);
row++;
if (state.showTeleport) {
float btnW = rowW;
float btnH = BUTTON_H * scaleY;
struct nk_rect tpRect = nk_rect(rowX, baseY + step * (float)row, btnW, btnH);
bool tpHover = nk_input_is_mouse_hovering_rect(&ctx->input, tpRect) != 0;
if (drawBtn(ctx, "Teleport to Player", rowX, baseY + step * (float)row, btnW, btnH, tpHover, winH, tex)) {
result = kGameAction_TeleportToPlayer;
}
row++;
struct nk_rect tmRect = nk_rect(rowX, baseY + step * (float)row, btnW, btnH);
bool tmHover = nk_input_is_mouse_hovering_rect(&ctx->input, tmRect) != 0;
if (drawBtn(ctx, "Teleport to Me", rowX, baseY + step * (float)row, btnW, btnH, tmHover, winH, tex)) {
result = kGameAction_TeleportToMe;
}
}
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
return result;
}
GameMenuAction renderPlayerOptions(nk_context *ctx, int winW, int winH,
MenuTextures &tex, PlayerOptionsState &state)
{
GameMenuAction result = kGameAction_None;
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
pushCleanStyle(ctx);
if (nk_begin(ctx, "PlayerOptions", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
drawTitle(ctx, state.gamertag, winW, winH, TITLE_Y, TITLE_H);
float rowW = BUTTON_W * scaleX;
float rowH = CHECKBOX_ROW_H * scaleY;
float rowX = BUTTON_X * scaleX;
float step = BUTTON_Y_STEP * scaleY;
float baseY = BUTTON_Y_START * scaleY;
int row = 0;
if (state.showPermissions) {
state.canBuildAndMine = drawCheckbox(ctx, "Can Build and Mine",
rowX, baseY + step * (float)row, rowW, rowH,
state.canBuildAndMine, true, winH, tex);
row++;
state.canUseDoorsAndSwitches = drawCheckbox(ctx, "Can Use Doors and Switches",
rowX, baseY + step * (float)row, rowW, rowH,
state.canUseDoorsAndSwitches, true, winH, tex);
row++;
state.canOpenContainers = drawCheckbox(ctx, "Can Open Containers",
rowX, baseY + step * (float)row, rowW, rowH,
state.canOpenContainers, true, winH, tex);
row++;
state.canAttackPlayers = drawCheckbox(ctx, "Can Attack Players",
rowX, baseY + step * (float)row, rowW, rowH,
state.canAttackPlayers, true, winH, tex);
row++;
state.canAttackAnimals = drawCheckbox(ctx, "Can Attack Animals",
rowX, baseY + step * (float)row, rowW, rowH,
state.canAttackAnimals, true, winH, tex);
row++;
}
if (state.showModerator) {
state.moderator = drawCheckbox(ctx, "Moderator",
rowX, baseY + step * (float)row, rowW, rowH,
state.moderator, true, winH, tex);
row++;
}
if (state.showCheats) {
state.invisible = drawCheckbox(ctx,
state.editingSelf ? "Invisible" : "Can be Invisible",
rowX, baseY + step * (float)row, rowW, rowH,
state.invisible, true, winH, tex);
row++;
state.canFly = drawCheckbox(ctx, "Can Fly",
rowX, baseY + step * (float)row, rowW, rowH,
state.canFly, true, winH, tex);
row++;
state.disableExhaustion = drawCheckbox(ctx,
state.editingSelf ? "Disable Exhaustion" : "Can Disable Exhaustion",
rowX, baseY + step * (float)row, rowW, rowH,
state.disableExhaustion, true, winH, tex);
row++;
if (!state.editingSelf) {
state.enableTeleport = drawCheckbox(ctx, "Enable Teleport",
rowX, baseY + step * (float)row, rowW, rowH,
state.enableTeleport, true, winH, tex);
row++;
}
}
if (state.showKick) {
float btnW = rowW;
float btnH = BUTTON_H * scaleY;
struct nk_rect kickRect = nk_rect(rowX, baseY + step * (float)row, btnW, btnH);
bool kickHover = nk_input_is_mouse_hovering_rect(&ctx->input, kickRect) != 0;
if (drawBtn(ctx, "Kick Player", rowX, baseY + step * (float)row, btnW, btnH, kickHover, winH, tex)) {
result = kGameAction_KickPlayer;
}
}
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
return result;
}
GameMenuAction renderInGameInfo(nk_context *ctx, int winW, int winH,
MenuTextures &tex, InGameInfoState &state)
{
GameMenuAction result = kGameAction_None;
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
pushCleanStyle(ctx);
if (nk_begin(ctx, "InGameInfo", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
drawTitle(ctx, "Players", winW, winH, TITLE_Y, TITLE_H);
const struct nk_input *input = &ctx->input;
float panelX = PANEL_X * scaleX;
float panelW = PANEL_W * scaleX;
float curY = PANEL_Y * scaleY + 100.0f * scaleY;
float itemH = LIST_ITEM_H * scaleY;
if (state.showHostOptions) {
float btnW = BUTTON_W * scaleX;
float btnH = BUTTON_H * scaleY;
float btnX = BUTTON_X * scaleX;
float btnY = PANEL_Y * scaleY + 60.0f * scaleY;
struct nk_rect hoRect = nk_rect(btnX, btnY, btnW, btnH);
bool hoHover = nk_input_is_mouse_hovering_rect(input, hoRect) != 0;
if (drawBtn(ctx, "Host Options", btnX, btnY, btnW, btnH, hoHover, winH, tex)) {
result = kGameAction_HostOptions;
}
}
int visiblePlayers = 8;
for (int i = 0; i < state.playerCount && i < visiblePlayers; i++) {
float itemY = curY + (float)i * itemH;
bool isSelected = (i == state.selectedIndex);
struct nk_rect itemRect = nk_rect(panelX, itemY, panelW, itemH);
bool itemHover = nk_input_is_mouse_hovering_rect(input, itemRect) != 0;
if (drawListItem(ctx, state.playerNames[i], panelX, itemY, panelW, itemH,
isSelected, itemHover, winH)) {
state.selectedIndex = i;
result = kGameAction_SelectPlayer;
}
}
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
return result;
}
GameMenuAction renderSignEntry(nk_context *ctx, int winW, int winH,
MenuTextures &tex, SignEntryState &state)
{
GameMenuAction result = kGameAction_None;
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
pushCleanStyle(ctx);
if (nk_begin(ctx, "SignEntry", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
drawTitle(ctx, "Edit Sign Message", winW, winH, TITLE_Y, TITLE_H);
float fieldW = SIGN_FIELD_W * scaleX;
float fieldH = SIGN_FIELD_H * scaleY;
float gap = SIGN_FIELD_GAP * scaleY;
float fieldX = ((float)winW - fieldW) * 0.5f;
float startY = BUTTON_Y_START * scaleY;
for (int i = 0; i < 4; i++) {
float fieldY = startY + (float)i * (fieldH + gap);
bool selected = (i == state.editingLine);
if (drawTextInput(ctx, state.lines[i], fieldX, fieldY, fieldW, fieldH, selected, winH)) {
state.editingLine = i;
}
}
float btnW = BUTTON_W * scaleX;
float btnH = BUTTON_H * scaleY;
float btnX = ((float)winW - btnW) * 0.5f;
float btnY = startY + 4.0f * (fieldH + gap) + gap * 2.0f;
struct nk_rect doneRect = nk_rect(btnX, btnY, btnW, btnH);
bool doneHover = nk_input_is_mouse_hovering_rect(&ctx->input, doneRect) != 0;
if (drawBtn(ctx, "Done", btnX, btnY, btnW, btnH, doneHover, winH, tex)) {
state.confirmed = true;
result = kGameAction_SignDone;
}
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
return result;
}
GameMenuAction renderTeleportMenu(nk_context *ctx, int winW, int winH,
MenuTextures &tex, TeleportMenuState &state)
{
GameMenuAction result = kGameAction_None;
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
pushCleanStyle(ctx);
const char *title = state.teleportToPlayer
? "Teleport to Player"
: "Teleport to Me";
if (nk_begin(ctx, "TeleportMenu", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
drawTitle(ctx, title, winW, winH, TITLE_Y, TITLE_H);
const struct nk_input *input = &ctx->input;
float panelX = PANEL_X * scaleX;
float panelW = PANEL_W * scaleX;
float curY = PANEL_Y * scaleY + 100.0f * scaleY;
float itemH = LIST_ITEM_H * scaleY;
int visiblePlayers = 8;
for (int i = 0; i < state.playerCount && i < visiblePlayers; i++) {
float itemY = curY + (float)i * itemH;
bool isSelected = (i == state.selectedIndex);
struct nk_rect itemRect = nk_rect(panelX, itemY, panelW, itemH);
bool itemHover = nk_input_is_mouse_hovering_rect(input, itemRect) != 0;
if (drawListItem(ctx, state.playerNames[i], panelX, itemY, panelW, itemH,
isSelected, itemHover, winH)) {
state.selectedIndex = i;
result = kGameAction_TeleportSelect;
}
}
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
return result;
}
GameMenuAction renderLaunchMoreOptions(nk_context *ctx, int winW, int winH,
MenuTextures &tex, LaunchMoreOptionsState &state)
{
GameMenuAction result = kGameAction_None;
float scaleX = (float)winW / BASE_W;
float scaleY = (float)winH / BASE_H;
pushCleanStyle(ctx);
const char *tabTitle = (state.tabIndex == 0)
? "World Options"
: "Game Options";
if (nk_begin(ctx, "LaunchMoreOptions", nk_rect(0, 0, (float)winW, (float)winH),
NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) {
drawDirtBg(ctx, winW, winH, tex);
drawTitle(ctx, tabTitle, winW, winH, TITLE_Y, TITLE_H);
float rowW = BUTTON_W * scaleX;
float rowH = CHECKBOX_ROW_H * scaleY;
float rowX = BUTTON_X * scaleX;
float step = 44.0f * scaleY;
float baseY = BUTTON_Y_START * scaleY;
if (state.tabIndex == 0) {
int row = 0;
state.onlineGame = drawCheckbox(ctx, "Online Game",
rowX, baseY + step * (float)row, rowW, rowH,
state.onlineGame, true, winH, tex);
row++;
state.inviteOnly = drawCheckbox(ctx, "Invite Only",
rowX, baseY + step * (float)row, rowW, rowH,
state.inviteOnly, state.onlineGame, winH, tex);
row++;
state.allowFriendsOfFriends = drawCheckbox(ctx, "Allow Friends of Friends",
rowX, baseY + step * (float)row, rowW, rowH,
state.allowFriendsOfFriends, state.onlineGame, winH, tex);
row++;
state.pvp = drawCheckbox(ctx, "Player vs Player",
rowX, baseY + step * (float)row, rowW, rowH,
state.pvp, true, winH, tex);
row++;
state.trustPlayers = drawCheckbox(ctx, "Trust Players",
rowX, baseY + step * (float)row, rowW, rowH,
state.trustPlayers, true, winH, tex);
row++;
state.fireSpreads = drawCheckbox(ctx, "Fire Spreads",
rowX, baseY + step * (float)row, rowW, rowH,
state.fireSpreads, true, winH, tex);
row++;
state.tntExplodes = drawCheckbox(ctx, "TNT Explodes",
rowX, baseY + step * (float)row, rowW, rowH,
state.tntExplodes, true, winH, tex);
row++;
state.hostPrivileges = drawCheckbox(ctx, "Host Privileges",
rowX, baseY + step * (float)row, rowW, rowH,
state.hostPrivileges, true, winH, tex);
row++;
state.resetNether = drawCheckbox(ctx, "Reset Nether",
rowX, baseY + step * (float)row, rowW, rowH,
state.resetNether, true, winH, tex);
row++;
state.generateStructures = drawCheckbox(ctx, "Generate Structures",
rowX, baseY + step * (float)row, rowW, rowH,
state.generateStructures, true, winH, tex);
row++;
state.superflatWorld = drawCheckbox(ctx, "Superflat World",
rowX, baseY + step * (float)row, rowW, rowH,
state.superflatWorld, true, winH, tex);
row++;
state.bonusChest = drawCheckbox(ctx, "Bonus Chest",
rowX, baseY + step * (float)row, rowW, rowH,
state.bonusChest, true, winH, tex);
} else {
int row = 0;
float fieldH = FIELD_H * scaleY;
drawLabel(ctx, "Seed for the World Generator", rowX, baseY + step * (float)row, rowW, winH);
row++;
drawTextInput(ctx, state.seed, rowX, baseY + step * (float)row, rowW, fieldH, false, winH);
row++;
char sizeLabel[64];
snprintf(sizeLabel, sizeof(sizeLabel), "World Size: %s", WORLD_SIZE_LABELS[state.worldSize]);
state.worldSize = drawSlider(ctx, sizeLabel,
rowX, baseY + step * (float)row, rowW, BUTTON_H * scaleY,
state.worldSize, 0, 3, winH, tex);
row++;
state.disableSaving = drawCheckbox(ctx, "Disable Saving",
rowX, baseY + step * (float)row, rowW, rowH,
state.disableSaving, true, winH, tex);
}
drawControllerPrompts(ctx, winW, winH, tex);
}
nk_end(ctx);
popCleanStyle(ctx);
return result;
}
}}