From 268e7df992f8cb15029e21bfa67094b550e08de2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Apr 2015 14:09:55 +0200 Subject: [PATCH 1/4] - fixed: We must not allow the engine to start without a default MAPINFO definition. Both 'Adventures of Square' IWADs were missing an entry for base MAPINFO and as a result did not define the common editor numbers. To prevent this, a new mindefaults MAPINFO was added to zdoom.pk3 which now gets loaded if IWADINFO does not specify a game-specific file. This minimum setting sets all gamedefaults to a reasonable base value and defines all other things that are required to be defined. --- src/d_iwad.cpp | 5 +++ wadsrc/static/iwadinfo.txt | 2 + wadsrc/static/mapinfo/mindefaults.txt | 59 +++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 wadsrc/static/mapinfo/mindefaults.txt diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 7574347bc3..3fc365e8c9 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -219,6 +219,11 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize) sc.ScriptError("Unknown keyword '%s'", sc.String); } } + if (iwad->MapInfo.IsEmpty()) + { + // We must at least load the minimum defaults to allow the engine to run. + iwad->MapInfo = "mapinfo/mindefaults.txt"; + } } else if (sc.Compare("NAMES")) { diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index a274a1f2ff..6c958ddfa2 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -6,6 +6,7 @@ IWad Autoname = "square.square" Game = "Doom" Config = "Square" + Mapinfo = "mapinfo/mindefaults.txt" MustContain = "SQU-IWAD", "E1A1" BannerColors = "ff ff ff", "80 00 80" } @@ -16,6 +17,7 @@ IWad Autoname = "square.squareware" Game = "Doom" Config = "Square" + Mapinfo = "mapinfo/mindefaults.txt" MustContain = "SQU-SWE1", "E1A1" BannerColors = "ff ff ff", "80 00 80" } diff --git a/wadsrc/static/mapinfo/mindefaults.txt b/wadsrc/static/mapinfo/mindefaults.txt new file mode 100644 index 0000000000..cbb3fa06b4 --- /dev/null +++ b/wadsrc/static/mapinfo/mindefaults.txt @@ -0,0 +1,59 @@ +// defines the minimum needed entries to let an unknown IWAD run + +gameinfo +{ + titlepage = "-NOFLAT-" + titletime = 999 + infopage = "-NOFLAT-" + titlemusic = "" + advisorytime = 0 + chatsound = "" + finalemusic = "" + finaleflat = "-NOFLAT-" + finalepage = "-NOFLAT-" + quitsound = "" + borderflat = "-NOFLAT-" + border = DoomBorder + telefogheight = 0 + defkickback = 100 + skyflatname = "F_SKY1" + translator = "xlat/doom.txt" + defaultbloodcolor = "68 00 00" + defaultbloodparticlecolor = "ff 00 00" + backpacktype = "Backpack" + armoricons = "AICNA0", 0.75, "AICNC0" + statusbar = "sbarinfo/doom.txt" + intermissionmusic = "" + intermissioncounter = true + dimcolor = "6f 00 6b" + dimamount = 0.8 + definventorymaxamount = 25 + defaultrespawntime = 12 + defaultdropstyle = 1 + endoom = "ENDOOM" + player5start = 4001 + pickupcolor = "c0 c0 c0" + quitmessages = "Do you want to quit?" + + menufontcolor_title = "purple" + menufontcolor_label = "default" + menufontcolor_value = "gray" + menufontcolor_action = "gray" + menufontcolor_header = "blue" + menufontcolor_highlight = "lightblue" + menufontcolor_selection = "purple" + menubackbutton = "M_BACK_D" + playerclasses = "DoomPlayer" + pausesign = "-NOFLAT-" + gibfactor = 1 + cursorpic = "doomcurs" + textscreenx = 10 + textscreeny = 10 + defaultendsequence = "Inter_Cast" + maparrow = "maparrows/arrow.txt", "maparrows/ddtarrow.txt" + statscreen_mapnamefont = "BigFont" + statscreen_finishedpatch = "WIF" + statscreen_enteringpatch = "WIENTER" +} + +include "mapinfo/common.txt" From c5a4221b587bf7d5a9f7cfc42c1a6ead720c2722 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Apr 2015 16:27:57 +0200 Subject: [PATCH 2/4] - fixed handling of args for non-actor mapthings again. As it turns out there was insufficient information in the data to properly decide this case so a new flag was added to make it all more reliable. --- src/g_doomedmap.cpp | 9 ++++++--- src/info.h | 3 ++- src/p_mobj.cpp | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index 131ddd076f..c9deb72565 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -80,7 +80,8 @@ const char *SpecialMapthingNames[] = { struct MapinfoEdMapItem { FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet. - int special; + short special; + bool argsdefined; int args[5]; // These are for error reporting. We must store the file information because it's no longer available when these items get resolved. FString filename; @@ -180,14 +181,15 @@ void FMapInfoParser::ParseDoomEdNums() editem.special = -1; } memset(editem.args, 0, sizeof(editem.args)); + editem.argsdefined = false; int minargs = 0; int maxargs = 5; FString specialname; if (sc.CheckString(",")) { - // todo: parse a special or args - if (editem.special < 0) editem.special = 0; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. + editem.argsdefined = true; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. + if (editem.special < 0) editem.special = 0; if (!sc.CheckNumber()) { sc.MustGetString(); @@ -264,6 +266,7 @@ void InitActorNumsFromMapinfo() FDoomEdEntry ent; ent.Type = cls; ent.Special = pair->Value.special; + ent.ArgsDefined = pair->Value.argsdefined; memcpy(ent.Args, pair->Value.args, sizeof(ent.Args)); DoomEdMap.Insert(pair->Key, ent); } diff --git a/src/info.h b/src/info.h index 8eed93e48d..bdbb69940e 100644 --- a/src/info.h +++ b/src/info.h @@ -282,7 +282,8 @@ struct FActorInfo struct FDoomEdEntry { const PClass *Type; - int Special; + short Special; + bool ArgsDefined; int Args[5]; }; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e3317e1a26..2571413c85 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4617,9 +4617,9 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) } // copy args to mapthing so that we have them in one place for the rest of this function - if (mentry->Type != NULL && mentry->Special >= 0) + if (mentry->ArgsDefined) { - mthing->special = mentry->Special; + if (mentry->Type!= NULL) mthing->special = mentry->Special; memcpy(mthing->args, mentry->Args, sizeof(mthing->args)); } From e4cadc90a5aa9eff55fe4bc4a3b5a0d1d046fb3c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 7 Apr 2015 11:08:28 -0500 Subject: [PATCH 3/4] Fix grammar: then -> than --- src/d_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 1244cc88f1..da901bb68e 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2310,7 +2310,7 @@ void D_DoomMain (void) if (hashfile) { - Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer then usual.\n"); + Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer than usual.\n"); } Printf ("W_Init: Init WADfiles.\n"); From 6428b399d6a931471f3d7bf1620599cb0e4193d1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 7 Apr 2015 12:37:33 -0500 Subject: [PATCH 4/4] Try to sanitize the exec+pullin mess - Old mess: * Execute autoexec files right away. * Execute -exec files right away. * Execute command line commands right away. - If, during any of the above, an unknown command or a set of an unknown variable is encountered, store it for later. - Pullin commands are directly executed and add to the list of files to load. * Do a little setup, including parsing CVARINFOs. * Retry saved commands in case CVARINFO added a cvar they refer to. - New, less messy, mess: * Parse autoexec files into an array. * Parse -exec files. * Parse command line commands. - During all of the above, exec commands are also parsed into the array immediately rather than being saved for execution later. - Pullin commands are parsed into a different array. The pullin command doesn't actually do anything directly anymore. * Add all the pullin files to the list of files to load. * Do a little setup, including parsing CVARINFOs. * Execute every command that was parsed in the preceding steps. --- src/c_cmds.cpp | 7 +- src/c_dispatch.cpp | 241 +++++++++++++++++++++------------------------ src/c_dispatch.h | 63 +++++++----- src/d_main.cpp | 32 ++++-- 4 files changed, 178 insertions(+), 165 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 74968404d4..a40f1f1a2e 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -450,11 +450,10 @@ CCMD (exec) for (int i = 1; i < argv.argc(); ++i) { - switch (C_ExecFile (argv[i], gamestate == GS_STARTUP)) + if (!C_ExecFile(argv[i])) { - case 1: Printf ("Could not open \"%s\"\n", argv[1]); break; - case 2: Printf ("Error parsing \"%s\"\n", argv[1]); break; - default: break; + Printf ("Could not exec \"%s\"\n", argv[i]); + break; } } } diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 6a526a6614..d72993cb77 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -185,9 +185,6 @@ static const char *KeyConfCommands[] = "clearplayerclasses" }; -static TArray StoredStartupSets; -static bool RunningStoredStartups; - // CODE -------------------------------------------------------------------- IMPLEMENT_CLASS (DWaitingCommand) @@ -540,18 +537,6 @@ void ResetButtonStates () } } -void C_ExecStoredSets() -{ - assert(!RunningStoredStartups); - RunningStoredStartups = true; - for (unsigned i = 0; i < StoredStartupSets.Size(); ++i) - { - C_DoCommand(StoredStartupSets[i]); - } - StoredStartupSets.Clear(); - RunningStoredStartups = false; -} - void C_DoCommand (const char *cmd, int keynum) { FConsoleCommand *com; @@ -627,22 +612,7 @@ void C_DoCommand (const char *cmd, int keynum) if ( (com = FindNameInHashTable (Commands, beg, len)) ) { - if (gamestate == GS_STARTUP && !RunningStoredStartups && - len == 3 && strnicmp(beg, "set", 3) == 0) - { - // Save setting of unknown cvars for later, in case a loaded wad has a - // CVARINFO that defines it. - FCommandLine args(beg); - if (args.argc() > 1 && FindCVar(args[1], NULL) == NULL) - { - StoredStartupSets.Push(beg); - } - else - { - com->Run(args, players[consoleplayer].mo, keynum); - } - } - else if (gamestate != GS_STARTUP || ParsingKeyConf || + if (gamestate != GS_STARTUP || ParsingKeyConf || (len == 3 && strnicmp (beg, "set", 3) == 0) || (len == 7 && strnicmp (beg, "logfile", 7) == 0) || (len == 9 && strnicmp (beg, "unbindall", 9) == 0) || @@ -687,15 +657,7 @@ void C_DoCommand (const char *cmd, int keynum) } else { // We don't know how to handle this command - if (gamestate == GS_STARTUP && !RunningStoredStartups) - { - // Save it for later, in case a CVARINFO defines it. - StoredStartupSets.Push(beg); - } - else - { - Printf ("Unknown command \"%.*s\"\n", (int)len, beg); - } + Printf ("Unknown command \"%.*s\"\n", (int)len, beg); } } } @@ -1368,7 +1330,7 @@ CCMD (key) // Execute any console commands specified on the command line. // These all begin with '+' as opposed to '-'. -void C_ExecCmdLineParams () +FExecList *C_ParseCmdLineParams(FExecList *exec) { for (int currArg = 1; currArg < Args->NumArgs(); ) { @@ -1389,10 +1351,15 @@ void C_ExecCmdLineParams () cmdString = BuildString (cmdlen, Args->GetArgList (argstart)); if (!cmdString.IsEmpty()) { - C_DoCommand (&cmdString[1]); + if (exec == NULL) + { + exec = new FExecList; + } + exec->AddCommand(&cmdString[1]); } } } + return exec; } bool FConsoleCommand::IsAlias () @@ -1469,28 +1436,60 @@ void FConsoleAlias::SafeDelete () } } -static BYTE PullinBad = 2; -static const char *PullinFile; -extern TArray allwads; +void FExecList::AddCommand(const char *cmd, const char *file) +{ + // Pullins are special and need to be separated from general commands. + // They also turned out to be a really bad idea, since they make things + // more complicated. :( + if (file != NULL && strnicmp(cmd, "pullin", 6) == 0 && isspace(cmd[6])) + { + FCommandLine line(cmd); + C_SearchForPullins(this, file, line); + } + // Recursive exec: Parse this file now. + else if (strnicmp(cmd, "exec", 4) == 0 && isspace(cmd[4])) + { + FCommandLine argv(cmd); + for (int i = 1; i < argv.argc(); ++i) + { + C_ParseExecFile(argv[i], this); + } + } + else + { + Commands.Push(cmd); + } +} -int C_ExecFile (const char *file, bool usePullin) +void FExecList::ExecCommands() const +{ + for (unsigned i = 0; i < Commands.Size(); ++i) + { + AddCommandString(Commands[i].LockBuffer()); + Commands[i].UnlockBuffer(); + } +} + +void FExecList::AddPullins(TArray &wads) const +{ + for (unsigned i = 0; i < Pullins.Size(); ++i) + { + D_AddFile(wads, Pullins[i]); + } +} + +FExecList *C_ParseExecFile(const char *file, FExecList *exec) { FILE *f; char cmd[4096]; int retval = 0; - BYTE pullinSaved = PullinBad; - const char *fileSaved = PullinFile; - if ( (f = fopen (file, "r")) ) { - PullinBad = 1-usePullin; - PullinFile = file; - - while (fgets (cmd, 4095, f)) + while (fgets(cmd, countof(cmd)-1, f)) { // Comments begin with // - char *stop = cmd + strlen (cmd) - 1; + char *stop = cmd + strlen(cmd) - 1; char *comment = cmd; int inQuote = 0; @@ -1517,88 +1516,78 @@ int C_ExecFile (const char *file, bool usePullin) { // Comment in middle of line *comment = 0; } - - AddCommandString (cmd); + if (exec == NULL) + { + exec = new FExecList; + } + exec->AddCommand(cmd, file); } - if (!feof (f)) + if (!feof(f)) { - retval = 2; + Printf("Error parsing \"%s\"\n", file); } - fclose (f); + fclose(f); } else { - retval = 1; + Printf ("Could not open \"%s\"\n", file); + } + return exec; +} + +bool C_ExecFile (const char *file) +{ + FExecList *exec = C_ParseExecFile(file, NULL); + if (exec != NULL) + { + exec->ExecCommands(); + if (exec->Pullins.Size() > 0) + { + Printf(TEXTCOLOR_BOLD "Notice: Pullin files were ignored.\n"); + } + delete exec; + } + return exec != NULL; +} + +void C_SearchForPullins(FExecList *exec, const char *file, FCommandLine &argv) +{ + const char *lastSlash; + + assert(exec != NULL); + assert(file != NULL); +#ifdef __unix__ + lastSlash = strrchr(file, '/'); +#else + const char *lastSlash1, *lastSlash2; + + lastSlash1 = strrchr(file, '/'); + lastSlash2 = strrchr(file, '\\'); + lastSlash = MAX(lastSlash1, lastSlash2); +#endif + + for (int i = 1; i < argv.argc(); ++i) + { + // Try looking for the wad in the same directory as the .cfg + // before looking for it in the current directory. + if (lastSlash != NULL) + { + FString path(file, (lastSlash - file) + 1); + path += argv[i]; + if (FileExists(path)) + { + exec->Pullins.Push(path); + continue; + } + } + exec->Pullins.Push(argv[i]); } - PullinBad = pullinSaved; - PullinFile = fileSaved; - return retval; } CCMD (pullin) { - if (PullinBad == 2) - { - Printf ("This command is only valid from .cfg\n" - "files and only when used at startup.\n"); - } - else if (argv.argc() > 1) - { - const char *lastSlash; - -#ifdef __unix__ - lastSlash = strrchr (PullinFile, '/'); -#else - const char *lastSlash1, *lastSlash2; - - lastSlash1 = strrchr (PullinFile, '/'); - lastSlash2 = strrchr (PullinFile, '\\'); - lastSlash = MAX (lastSlash1, lastSlash2); -#endif - - if (PullinBad) - { - Printf ("Not loading:"); - } - for (int i = 1; i < argv.argc(); ++i) - { - if (PullinBad) - { - Printf (" %s", argv[i]); - } - else - { - // Try looking for the wad in the same directory as the .cfg - // before looking for it in the current directory. - char *path = argv[i]; - - if (lastSlash != NULL) - { - size_t pathlen = lastSlash - PullinFile + strlen (argv[i]) + 2; - path = new char[pathlen]; - strncpy (path, PullinFile, (lastSlash - PullinFile) + 1); - strcpy (path + (lastSlash - PullinFile) + 1, argv[i]); - if (!FileExists (path)) - { - delete[] path; - path = argv[i]; - } - else - { - FixPathSeperator (path); - } - } - D_AddFile (allwads, path); - if (path != argv[i]) - { - delete[] path; - } - } - } - if (PullinBad) - { - Printf ("\n"); - } - } + // Actual handling for pullin is now completely special-cased above + Printf (TEXTCOLOR_BOLD "Pullin" TEXTCOLOR_NORMAL " is only valid from .cfg\n" + "files and only when used at startup.\n"); } diff --git a/src/c_dispatch.h b/src/c_dispatch.h index b494005c72..f9aeb0dc32 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -39,31 +39,6 @@ class FConfigFile; class APlayerPawn; -extern bool CheckCheatmode (bool printmsg = true); - -void C_ExecCmdLineParams (); -void C_ExecStoredSets(); - -// Add commands to the console as if they were typed in. Can handle wait -// and semicolon-separated commands. This function may modify the source -// string, but the string will be restored to its original state before -// returning. Therefore, commands passed must not be in read-only memory. -void AddCommandString (char *text, int keynum=0); - -// Process a single console command. Does not handle wait. -void C_DoCommand (const char *cmd, int keynum=0); - -int C_ExecFile (const char *cmd, bool usePullin); - -// Write out alias commands to a file for all current aliases. -void C_ArchiveAliases (FConfigFile *f); - -void C_SetAlias (const char *name, const char *cmd); -void C_ClearAliases (); - -// build a single string out of multiple strings -FString BuildString (int argc, FString *argv); - // Class that can parse command lines class FCommandLine { @@ -83,6 +58,44 @@ private: bool noescapes; }; +// Contains the contents of an exec'ed file +struct FExecList +{ + TArray Commands; + TArray Pullins; + + void AddCommand(const char *cmd, const char *file = NULL); + void ExecCommands() const; + void AddPullins(TArray &wads) const; +}; + + +extern bool CheckCheatmode (bool printmsg = true); + +FExecList *C_ParseCmdLineParams(FExecList *exec); + +// Add commands to the console as if they were typed in. Can handle wait +// and semicolon-separated commands. This function may modify the source +// string, but the string will be restored to its original state before +// returning. Therefore, commands passed must not be in read-only memory. +void AddCommandString (char *text, int keynum=0); + +// Process a single console command. Does not handle wait. +void C_DoCommand (const char *cmd, int keynum=0); + +FExecList *C_ParseExecFile(const char *file, FExecList *source); +void C_SearchForPullins(FExecList *exec, const char *file, class FCommandLine &args); +bool C_ExecFile(const char *file); + +// Write out alias commands to a file for all current aliases. +void C_ArchiveAliases (FConfigFile *f); + +void C_SetAlias (const char *name, const char *cmd); +void C_ClearAliases (); + +// build a single string out of multiple strings +FString BuildString (int argc, FString *argv); + typedef void (*CCmdRun) (FCommandLine &argv, APlayerPawn *instigator, int key); class FConsoleCommand diff --git a/src/d_main.cpp b/src/d_main.cpp index da901bb68e..9b46d42c23 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1723,12 +1723,13 @@ bool ConsiderPatches (const char *arg) // //========================================================================== -void D_MultiExec (DArgs *list, bool usePullin) +FExecList *D_MultiExec (DArgs *list, FExecList *exec) { for (int i = 0; i < list->NumArgs(); ++i) { - C_ExecFile (list->GetArg (i), usePullin); + exec = C_ParseExecFile(list->GetArg(i), exec); } + return exec; } static void GetCmdLineFiles(TArray &wadfiles) @@ -2291,18 +2292,24 @@ void D_DoomMain (void) AddAutoloadFiles(iwad_info->Autoname); - // Run automatically executed files + // Process automatically executed files + FExecList *exec; execFiles = new DArgs; - GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName); - D_MultiExec (execFiles, true); + GameConfig->AddAutoexec(execFiles, gameinfo.ConfigName); + exec = D_MultiExec(execFiles, NULL); - // Run .cfg files at the start of the command line. + // Process .cfg files at the start of the command line. execFiles = Args->GatherFiles ("-exec"); - D_MultiExec (execFiles, true); + exec = D_MultiExec(execFiles, exec); - C_ExecCmdLineParams (); // [RH] do all +set commands on the command line + // [RH] process all + commands on the command line + exec = C_ParseCmdLineParams(exec); CopyFiles(allwads, pwads); + if (exec != NULL) + { + exec->AddPullins(allwads); + } // Since this function will never leave we must delete this array here manually. pwads.Clear(); @@ -2324,8 +2331,13 @@ void D_DoomMain (void) // Now that wads are loaded, define mod-specific cvars. ParseCVarInfo(); - // Try setting previously unknown cvars again, as a CVARINFO may have made them known. - C_ExecStoredSets(); + // Actually exec command line commands and exec files. + if (exec != NULL) + { + exec->ExecCommands(); + delete exec; + exec = NULL; + } // [RH] Initialize localizable strings. GStrings.LoadStrings (false);