From a60721d1675398e16dcdfd788d62d929e2b6b66c Mon Sep 17 00:00:00 2001 From: Ace Lite <47698279+Ace-Lite@users.noreply.github.com> Date: Sat, 30 Mar 2024 14:51:43 +0100 Subject: [PATCH 1/2] Initial Commit - Custom Cvar Menu --- src/command.h | 1 + src/deh_tables.c | 1 + src/lua_consolelib.c | 61 ++++++++++++++++++++++++++++------- src/m_menu.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ src/m_menu.h | 1 + 5 files changed, 129 insertions(+), 11 deletions(-) diff --git a/src/command.h b/src/command.h index f0dc62418..deb30e28b 100644 --- a/src/command.h +++ b/src/command.h @@ -121,6 +121,7 @@ typedef enum // used on menus CV_CHEAT = 2048, // Don't let this be used in multiplayer unless cheats are on. CV_ALLOWLUA = 4096,/* Let this be called from Lua */ + CV_NOMENU = 8192, // Lua exclusive flag, to give choice to modders regarding custom options menu. } cvflags_t; typedef struct CV_PossibleValue_s diff --git a/src/deh_tables.c b/src/deh_tables.c index ed401d68a..9631a57f2 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5617,6 +5617,7 @@ struct int_const_s const INT_CONST[] = { {"CV_HIDDEN",CV_HIDEN}, {"CV_CHEAT",CV_CHEAT}, {"CV_ALLOWLUA",CV_ALLOWLUA}, + {"CV_NOMENU",CV_NOMENU}, // v_video flags {"V_NOSCALEPATCH",V_NOSCALEPATCH}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index aaa676526..00e8d036d 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -22,6 +22,11 @@ #include "lua_libs.h" #include "lua_hud.h" // hud_running errors +// Included for the custom options menu +#include "netcode/d_netfil.h" +#include "m_menu.h" +#include "w_wad.h" + // for functions not allowed in hud.add hooks #define NOHUD if (hud_running)\ return luaL_error(L, "HUD rendering code should not call this function!"); @@ -335,6 +340,9 @@ static int lib_cvRegisterVar(lua_State *L) cvar = ZZ_Calloc(sizeof(consvar_t)); LUA_PushUserdata(L, cvar, META_CVAR); + const char* category = NULL; + const char* menu_name = NULL; + #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("CV_RegisterVar") " (%s)", e); #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) @@ -382,7 +390,7 @@ static int lib_cvRegisterVar(lua_State *L) { if (lua_islightuserdata(L, 4)) { - CV_PossibleValue_t *pv = lua_touserdata(L, 4); + CV_PossibleValue_t* pv = lua_touserdata(L, 4); if (pv == CV_OnOff || pv == CV_YesNo || pv == CV_Unsigned || pv == CV_Natural || pv == CV_TrueFalse) cvar->PossibleValue = pv; else @@ -397,9 +405,9 @@ static int lib_cvRegisterVar(lua_State *L) // being used for multiple cvars will be converted and stored multiple times. // So maybe instead it should be a seperate function which must be run beforehand or something. size_t count = 0; - CV_PossibleValue_t *cvpv; + CV_PossibleValue_t* cvpv; - const char * const MINMAX[2] = {"MIN", "MAX"}; + const char* const MINMAX[2] = { "MIN", "MAX" }; int minmax_unset = 3; lua_pushnil(L); @@ -412,7 +420,7 @@ static int lib_cvRegisterVar(lua_State *L) lua_getfield(L, LUA_REGISTRYINDEX, "CV_PossibleValue"); I_Assert(lua_istable(L, 5)); lua_pushlightuserdata(L, cvar); - cvpv = lua_newuserdata(L, sizeof(CV_PossibleValue_t) * (count+1)); + cvpv = lua_newuserdata(L, sizeof(CV_PossibleValue_t) * (count + 1)); lua_rawset(L, 5); lua_pop(L, 1); // pop CV_PossibleValue registry table @@ -421,25 +429,25 @@ static int lib_cvRegisterVar(lua_State *L) while (lua_next(L, 4)) { INT32 n; - const char * strval; + const char* strval; // stack: [...] PossibleValue table, index, value // 4 5 6 if (lua_type(L, 5) != LUA_TSTRING - || lua_type(L, 6) != LUA_TNUMBER) + || lua_type(L, 6) != LUA_TNUMBER) FIELDERROR("PossibleValue", "custom PossibleValue table requires a format of string=integer, i.e. {MIN=0, MAX=9999}"); strval = lua_tostring(L, 5); if ( - stricmp(strval, MINMAX[n=0]) == 0 || - stricmp(strval, MINMAX[n=1]) == 0 - ){ + stricmp(strval, MINMAX[n = 0]) == 0 || + stricmp(strval, MINMAX[n = 1]) == 0 + ) { /* need to shift forward */ if (minmax_unset == 3) { memmove(&cvpv[2], &cvpv[0], - i * sizeof *cvpv); + i * sizeof * cvpv); i += 2; } cvpv[n].strvalue = MINMAX[n]; @@ -482,7 +490,7 @@ static int lib_cvRegisterVar(lua_State *L) lua_pop(L, 1); cvar->func = Lua_OnChange; } - else if (cvar->flags & CV_CALL && (k && fasticmp(k, "can_change"))) + else if (cvar->flags & CV_CALL && (i == 6 || (k && fasticmp(k, "can_change")))) { if (!lua_isfunction(L, 4)) { @@ -496,6 +504,19 @@ static int lib_cvRegisterVar(lua_State *L) lua_pop(L, 1); cvar->can_change = Lua_CanChange; } + else if (((i == 5 && !(cvar->flags & CV_CALL)) + || (cvar->flags & CV_CALL && i == 7)) + || (k && fasticmp(k, "category"))) + { + category = lua_isnoneornil(L, 4) ? NULL : lua_tostring(L, 4); + } + else if (((i == 6 && !(cvar->flags & CV_CALL)) + || (cvar->flags & CV_CALL && i == 8)) + || (k && fasticmp(k, "displayname"))) + { + menu_name = lua_isnoneornil(L, 4) ? NULL : lua_tostring(L, 4); + } + lua_pop(L, 1); } @@ -532,6 +553,24 @@ static int lib_cvRegisterVar(lua_State *L) return luaL_error(L, "failed to register cvar (probable conflict with internal variable/command names)"); } + if (!((cvar->flags & CV_NOMENU) + || (cvar->flags & CV_HIDEN)) + || (cvar->flags & CV_NOSHOWHELP)) + { + if (!category) + { + char* temp = strdup(wadfiles[numwadfiles - 1]->filename); + nameonly(temp); + + category = temp; + } + + if (menu_name && menu_name[0] != '\0') + M_FreeslotIntoCustomMenu(cvar, category, menu_name); + else + M_FreeslotIntoCustomMenu(cvar, category, cvar->name); + } + // return cvar userdata return 1; } diff --git a/src/m_menu.c b/src/m_menu.c index 500113475..cf484f07f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -48,6 +48,7 @@ #include "p_setup.h" #include "f_finale.h" #include "lua_hook.h" +#include "lua_libs.h" #ifdef HWRENDER #include "hardware/hw_main.h" @@ -316,6 +317,7 @@ menu_t OP_P1ControlsDef, OP_P2ControlsDef, OP_MouseOptionsDef; menu_t OP_Mouse2OptionsDef, OP_Joystick1Def, OP_Joystick2Def; menu_t OP_CameraOptionsDef, OP_Camera2OptionsDef; menu_t OP_PlaystyleDef; +menu_t OP_AddonCustomOptionsDef; static void M_VideoModeMenu(INT32 choice); static void M_Setup1PControlsMenu(INT32 choice); static void M_Setup2PControlsMenu(INT32 choice); @@ -349,6 +351,7 @@ static void M_EraseData(INT32 choice); static void M_Addons(INT32 choice); static void M_AddonsOptions(INT32 choice); +static void M_AddonsCvarOptions(INT32 choice); static patch_t *addonsp[NUM_EXT+5]; #define addonmenusize 9 // number of items actually displayed in the addons menu view, formerly (2*numaddonsshown + 1) @@ -1037,6 +1040,7 @@ static menuitem_t OP_MainMenu[] = {IT_CALL | IT_STRING, NULL, "Server Options...", M_ServerOptions, 80}, {IT_SUBMENU | IT_STRING, NULL, "Data Options...", &OP_DataOptionsDef, 100}, + {IT_CALL | IT_STRING, NULL, "Custom Options...", M_AddonsCvarOptions,110}, }; static menuitem_t OP_P1ControlsMenu[] = @@ -1648,6 +1652,9 @@ static menuitem_t OP_MonitorToggleMenu[] = {IT_STRING|IT_CVAR|IT_CV_INVISSLIDER, NULL, "Eggman Box", &cv_eggmanbox, 140}, }; +#define MAXADDONOPTIONS 999 +menuitem_t OP_AddonOptionsSlots[MAXADDONOPTIONS]; + // ========================================================================== // ALL MENU DEFINITIONS GO HERE // ========================================================================== @@ -2218,6 +2225,23 @@ menu_t OP_ScreenshotOptionsDef = NULL }; +INT16 addoncvarpos = 0; + +static void M_AddonsCvarOptions(INT32 choice) +{ + (void)choice; + + if (addoncvarpos) + M_SetupNextMenu(&OP_AddonCustomOptionsDef); + else + M_StartMessage(M_GetText("No Custom Option was found.\nTry to load any Addon!\n(Press a key)\n"), NULL, MM_NOTHING); +} + +menu_t OP_AddonCustomOptionsDef = DEFAULTSCROLLMENUSTYLE( + MTREE3(MN_OP_MAIN, MN_OP_DATA, MN_OP_ADDONS), + "M_ADDONS", OP_AddonOptionsSlots, &OP_MainDef, 30, 30); + + menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE( MTREE3(MN_OP_MAIN, MN_OP_DATA, MN_OP_ADDONS), "M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30); @@ -6915,6 +6939,58 @@ static void M_SelectableClearMenus(INT32 choice) M_ClearMenus(true); } +#define CCVHEIGHT 5 +#define CCVHEIGHTHEADER 1 +#define CCVHEIGHTHEADERAFTER 6 + +UINT16 addonvaralphakey = 4; +INT16 addonlastheaderpos = 0; + +INT32 CVARSETUP; + +void M_FreeslotIntoCustomMenu(consvar_t* cvar, const char* category, const char* name) +{ + if (addoncvarpos == INT16_MAX) + return; + + if (addoncvarpos >= MAXADDONOPTIONS - 2) + { + CONS_Printf("Failed to register the console variable '%s' into the menu. Custom Options menu most likely reached the hard limit.\n", name); + addoncvarpos = INT16_MAX; + return; + } + + if (!CVARSETUP) + { + CONS_Printf("Custom Options menu initiation.\n"); + for (CVARSETUP = 0; CVARSETUP < MAXADDONOPTIONS; ++CVARSETUP) + OP_AddonOptionsSlots[CVARSETUP] = (menuitem_t){ IT_DISABLED, NULL, "", 0, INT16_MAX }; + } + + if (category && ((addoncvarpos == 0 && category[0] != '\0') || !fasticmp(category, OP_AddonOptionsSlots[addonlastheaderpos].text))) + { + addonlastheaderpos = addoncvarpos; + addonvaralphakey += CCVHEIGHTHEADER; + + OP_AddonOptionsSlots[addoncvarpos] = (menuitem_t){ IT_HEADER, NULL, Z_StrDup(category), NULL, addonvaralphakey }; + addonvaralphakey += CCVHEIGHTHEADERAFTER; + + + ++addoncvarpos; + } + + if (cvar->PossibleValue && fasticmp(cvar->PossibleValue[0].strvalue, "MIN")) + OP_AddonOptionsSlots[addoncvarpos] = (menuitem_t){ IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, Z_StrDup(name), cvar, addonvaralphakey }; + else if (cvar->flags & CV_FLOAT) + OP_AddonOptionsSlots[addoncvarpos] = (menuitem_t){ IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, Z_StrDup(name), cvar, addonvaralphakey }; + else + OP_AddonOptionsSlots[addoncvarpos] = (menuitem_t){ IT_STRING | IT_CVAR, NULL, Z_StrDup(name), cvar, addonvaralphakey }; + + addonvaralphakey += CCVHEIGHT; + ++addoncvarpos; +} + + // ====== // CHEATS // ====== diff --git a/src/m_menu.h b/src/m_menu.h index 99a5b6de4..8e34ae063 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -485,6 +485,7 @@ UINT16 M_GetColorIndex(UINT16 color); menucolor_t* M_GetColorFromIndex(UINT16 index); void M_InitPlayerSetupColors(void); void M_FreePlayerSetupColors(void); +void M_FreeslotIntoCustomMenu(consvar_t* cvar, const char* category, const char* name); // These defines make it a little easier to make menus #define DEFAULTMENUSTYLE(id, header, source, prev, x, y)\ From e6d51750bd277f93780e3556b6528b38ec655750 Mon Sep 17 00:00:00 2001 From: Skydusk Date: Fri, 21 Feb 2025 22:41:21 +0000 Subject: [PATCH 2/2] Get the filename with pointer arithmetic instead. -- Lactozilla's change --- src/lua_consolelib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 51ade0463..34f1affc5 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -585,8 +585,8 @@ static int lib_cvRegisterVar(lua_State *L) { if (!category) { - char* temp = strdup(wadfiles[numwadfiles - 1]->filename); - nameonly(temp); + char* temp = wadfiles[numwadfiles - 1]->filename; + temp += strlen(temp) - nameonlylength(temp); category = temp; }