diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 82a23e2be..2c02ea8b0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -554,6 +554,7 @@ file( GLOB HEADER_FILES intermission/*.h maploader/*.h menu/*.h + commandlets/*.h sound/*.h sound/backend/*.h* posix/*.h @@ -816,6 +817,8 @@ set (PCH_SOURCES playsim/p_user.cpp rendering/r_utility.cpp rendering/r_sky.cpp + commandlets/commandlet.cpp + commandlets/lightmapcmd.cpp sound/s_advsound.cpp sound/s_sndseq.cpp sound/s_doomsound.cpp @@ -1472,6 +1475,7 @@ install(TARGETS ztool DESTINATION ${INSTALL_PATH} COMPONENT "Tool executable") +source_group("Commandlets" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/commandlets/.+") source_group("Audio Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/.+") source_group("Game Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/.+") source_group("Game Data\\Fonts" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/fonts/.+") diff --git a/src/commandlets/commandlet.cpp b/src/commandlets/commandlet.cpp new file mode 100644 index 000000000..c41a4cd45 --- /dev/null +++ b/src/commandlets/commandlet.cpp @@ -0,0 +1,123 @@ + +#include "commandlet.h" +#include "lightmapcmd.h" +#include "version.h" + +void CommandletGroup::AddGroup(std::unique_ptr group) +{ + Groups.Push(std::move(group)); +} + +void CommandletGroup::AddCommand(std::unique_ptr command) +{ + Commands.Push(std::move(command)); +} + +///////////////////////////////////////////////////////////////////////////// + +RootCommandlet::RootCommandlet() +{ + AddGroup(); +} + +void RootCommandlet::RunCommand() +{ + FArgs args = *Args; + args.RemoveArg(0); + + if (args.NumArgs() > 0 && stricmp(args.GetArg(0), "help") == 0) + { + args.RemoveArg(0); + PrintDetailHelp(this, args); + } + else + { + RunCommand(this, args, {}); + } +} + +void RootCommandlet::RunCommand(CommandletGroup* group, FArgs args, const FString prefix) +{ + if (args.NumArgs() > 0 && args.GetArg(0)[0] != '-') + { + const char* arg = args.GetArg(0); + for (auto& cmd : group->Commands) + { + if (stricmp(arg, cmd->GetLongFormName().GetChars()) == 0) + { + args.RemoveArg(0); + cmd->OnCommand(args); + return; + } + } + for (auto& subgroup : group->Groups) + { + if (stricmp(arg, subgroup->GetLongFormName().GetChars()) == 0) + { + args.RemoveArg(0); + RunCommand(subgroup.get(), args, prefix + arg + " "); + return; + } + } + Printf("Unknown command " TEXTCOLOR_ORANGE "%s\n", arg); + } + else + { + Printf("Syntax: " TOOLNAMELOWERCASE TEXTCOLOR_ORANGE " " TEXTCOLOR_CYAN "[options]" TEXTCOLOR_NORMAL " - Run command\n"); + Printf("Syntax: " TOOLNAMELOWERCASE " help " TEXTCOLOR_CYAN "[options]" TEXTCOLOR_NORMAL " - Get help list of commands\n"); + Printf("Syntax: " TOOLNAMELOWERCASE " help " TEXTCOLOR_ORANGE " " TEXTCOLOR_CYAN "[options]" TEXTCOLOR_NORMAL " - Get help about a specific command\n"); + } +} + +void RootCommandlet::PrintDetailHelp(CommandletGroup* group, FArgs args) +{ + if (args.NumArgs() > 0 && args.GetArg(0)[0] != '-') + { + const char* arg = args.GetArg(0); + for (auto& cmd : group->Commands) + { + if (stricmp(arg, cmd->GetLongFormName().GetChars()) == 0) + { + cmd->OnPrintHelp(); + return; + } + } + for (auto& subgroup : group->Groups) + { + if (stricmp(arg, subgroup->GetLongFormName().GetChars()) == 0) + { + args.RemoveArg(0); + PrintDetailHelp(subgroup.get(), args); + return; + } + } + Printf("Unknown command " TEXTCOLOR_ORANGE "%s\n", arg); + } + else + { + PrintCommandList(this, {}); + } +} + +void RootCommandlet::PrintCommandList(CommandletGroup* group, const FString prefix) +{ + if (group != this) + { + FString description = group->GetShortDescription(); + Printf("%s:\n", description.GetChars()); + } + + for (auto& cmdlet : group->Commands) + { + FString longname = prefix + cmdlet->GetLongFormName(); + FString description = cmdlet->GetShortDescription(); + while (longname.Len() < 20) + longname.AppendCharacter(' '); + Printf(TEXTCOLOR_ORANGE "%s " TEXTCOLOR_NORMAL "%s\n", longname.GetChars(), description.GetChars()); + } + + for (auto& subgroup : group->Groups) + { + PrintCommandList(subgroup.get(), prefix + subgroup->GetLongFormName() + " "); + } +} diff --git a/src/commandlets/commandlet.h b/src/commandlets/commandlet.h new file mode 100644 index 000000000..cee0cdb0f --- /dev/null +++ b/src/commandlets/commandlet.h @@ -0,0 +1,69 @@ + +#pragma once + +#include +#include "templates.h" +#include "zstring.h" +#include "printf.h" +#include "m_argv.h" + +class Commandlet +{ +public: + virtual ~Commandlet() = default; + + virtual void OnCommand(FArgs args) = 0; + virtual void OnPrintHelp() = 0; + + const FString& GetLongFormName() const { return LongFormName; } + const FString& GetShortDescription() const { return ShortDescription; } + +protected: + void SetLongFormName(FString name) { LongFormName = std::move(name); } + void SetShortDescription(FString desc) { ShortDescription = std::move(desc); } + +private: + FString LongFormName; + FString ShortDescription; +}; + +class CommandletGroup +{ +public: + void AddGroup(std::unique_ptr group); + void AddCommand(std::unique_ptr command); + + template + void AddGroup() { AddGroup(std::make_unique()); } + + template + void AddCommand() { AddCommand(std::make_unique()); } + + const FString& GetLongFormName() const { return LongFormName; } + const FString& GetShortDescription() const { return ShortDescription; } + +protected: + void SetLongFormName(FString name) { LongFormName = std::move(name); } + void SetShortDescription(FString desc) { ShortDescription = std::move(desc); } + +private: + FString LongFormName; + FString ShortDescription; + + TArray> Groups; + TArray> Commands; + + friend class RootCommandlet; +}; + +class RootCommandlet : public CommandletGroup +{ +public: + RootCommandlet(); + void RunCommand(); + +private: + void RunCommand(CommandletGroup* group, FArgs args, const FString prefix); + void PrintCommandList(CommandletGroup* group, const FString prefix); + void PrintDetailHelp(CommandletGroup* group, FArgs args); +}; diff --git a/src/commandlets/lightmapcmd.cpp b/src/commandlets/lightmapcmd.cpp new file mode 100644 index 000000000..70561f89b --- /dev/null +++ b/src/commandlets/lightmapcmd.cpp @@ -0,0 +1,47 @@ + +#include "lightmapcmd.h" + +LightmapCmdletGroup::LightmapCmdletGroup() +{ + SetLongFormName("lightmap"); + SetShortDescription("Lightmapper commands"); + + AddCommand(); + AddCommand(); +} + +///////////////////////////////////////////////////////////////////////////// + +LightmapBuildCmdlet::LightmapBuildCmdlet() +{ + SetLongFormName("build"); + SetShortDescription("Build lightmap lump"); +} + +void LightmapBuildCmdlet::OnCommand(FArgs args) +{ + Printf("Baking LIGHTMAP lump!\n"); +} + +void LightmapBuildCmdlet::OnPrintHelp() +{ + Printf(TEXTCOLOR_ORANGE "lightmap build " TEXTCOLOR_CYAN "[map name]" TEXTCOLOR_NORMAL " - Bakes all the lightmap lights and stores the result in a LIGHTMAP lump\n"); +} + +///////////////////////////////////////////////////////////////////////////// + +LightmapDeleteCmdlet::LightmapDeleteCmdlet() +{ + SetLongFormName("delete"); + SetShortDescription("Delete lightmap lump"); +} + +void LightmapDeleteCmdlet::OnCommand(FArgs args) +{ + Printf("Deleting LIGHTMAP lump!\n"); +} + +void LightmapDeleteCmdlet::OnPrintHelp() +{ + Printf(TEXTCOLOR_ORANGE "lightmap delete " TEXTCOLOR_CYAN "[map name]" TEXTCOLOR_NORMAL " - Deletes the LIGHTMAP lump\n"); +} diff --git a/src/commandlets/lightmapcmd.h b/src/commandlets/lightmapcmd.h new file mode 100644 index 000000000..20468de98 --- /dev/null +++ b/src/commandlets/lightmapcmd.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "commandlet.h" + +class LightmapCmdletGroup : public CommandletGroup +{ +public: + LightmapCmdletGroup(); +}; + +class LightmapBuildCmdlet : public Commandlet +{ +public: + LightmapBuildCmdlet(); + void OnCommand(FArgs args) override; + void OnPrintHelp() override; +}; + +class LightmapDeleteCmdlet : public Commandlet +{ +public: + LightmapDeleteCmdlet(); + void OnCommand(FArgs args) override; + void OnPrintHelp() override; +}; diff --git a/src/common/utility/m_argv.cpp b/src/common/utility/m_argv.cpp index 0e8946058..be44ab8c5 100644 --- a/src/common/utility/m_argv.cpp +++ b/src/common/utility/m_argv.cpp @@ -36,6 +36,8 @@ #include "m_argv.h" #include "zstring.h" +extern bool RunningAsTool; + //=========================================================================== // // FArgs Default Constructor @@ -489,29 +491,32 @@ void FArgs::CollectFiles(const char *finalname, const char **param, const char * unsigned int i; size_t extlen = extension == nullptr ? 0 : strlen(extension); - // Step 1: Find suitable arguments before the first switch. i = 1; - while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+') + if (!RunningAsTool) // Arguments before the first switch belong to the commandlet { - bool useit; + // Step 1: Find suitable arguments before the first switch. + while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+') + { + bool useit; - if (extlen > 0) - { // Argument's extension must match. - size_t len = Argv[i].Len(); - useit = (len >= extlen && stricmp(&Argv[i][len - extlen], extension) == 0); - } - else - { // Anything will do so long as it's before the first switch. - useit = true; - } - if (useit) - { - work.Push(Argv[i]); - Argv.Delete(i); - } - else - { - i++; + if (extlen > 0) + { // Argument's extension must match. + size_t len = Argv[i].Len(); + useit = (len >= extlen && stricmp(&Argv[i][len - extlen], extension) == 0); + } + else + { // Anything will do so long as it's before the first switch. + useit = true; + } + if (useit) + { + work.Push(Argv[i]); + Argv.Delete(i); + } + else + { + i++; + } } } diff --git a/src/d_main.cpp b/src/d_main.cpp index f7269fb14..3997cc436 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -121,6 +121,7 @@ #include "startscreen.h" #include "shiftstate.h" #include "common/widgets/errorwindow.h" +#include "commandlets/commandlet.h" #ifdef __unix__ #include "i_system.h" // for SHARE_DIR @@ -3851,10 +3852,9 @@ static int D_DoomMain_Internal (void) if (RunningAsTool) { - // To do: We got a game loaded and can now process commandlets - Printf("\n"); - Printf("Specify " TEXTCOLOR_ORANGE "--help" TEXTCOLOR_NORMAL " for a list of commands\n"); + RootCommandlet commands; + commands.RunCommand(); return 0; } diff --git a/src/version.h b/src/version.h index 4feeb2db1..afce5a1bb 100644 --- a/src/version.h +++ b/src/version.h @@ -108,6 +108,7 @@ const char *GetVersionString(); #define GAMENAME "VKDoom" #define WGAMENAME L"VKDoom" #define GAMENAMELOWERCASE "vkdoom" +#define TOOLNAMELOWERCASE "vktool" #define QUERYIWADDEFAULT true //#define FORUM_URL "http://forum.zdoom.org/" //#define BUGS_FORUM_URL "http://forum.zdoom.org/viewforum.php?f=2"