]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Fix compatibility with .arena and .defi files that contain multiple map listings
authorMario <mario.mario@y7mail.com>
Tue, 14 Jul 2020 18:08:04 +0000 (04:08 +1000)
committerMario <mario.mario@y7mail.com>
Tue, 14 Jul 2020 18:08:04 +0000 (04:08 +1000)
qcsrc/common/mapinfo.qc

index 60f5c40d17feba539f18bec1640670f7c48bb79f..cc9c0f93c6145e741af3a47042c1f1a9527342b6 100644 (file)
@@ -761,8 +761,15 @@ float MapInfo_isRedundant(string fn, string t)
        return false;
 }
 
-void _MapInfo_ParseArena(int fh, Gametype pGametypeToSet, bool isdefi)
+bool _MapInfo_ParseArena(int fh, string pFilename, Gametype pGametypeToSet, bool isdefi)
 {
+       // NOTE: .arena files can hold more than 1 map's information!
+       // to handle this, we're going to store gathered information in local variables and save it if we encounter the correct map name
+       bool testing_map = false; // testing a potential mapinfo section (within brackets)
+       bool dosave = false; // variables will be stored in map info upon reaching finishing bracket
+       string stored_Map_description = "";
+       string stored_Map_title = "";
+       int stored_supportedGametypes = 0;
        string t, s;
        for (;;)
        {
@@ -778,8 +785,38 @@ void _MapInfo_ParseArena(int fh, Gametype pGametypeToSet, bool isdefi)
                        continue;
                if(substring(s, 0, 1) == "_")  // q3map style
                        continue;
-               if(s == "{" || s == "}")       // opening/closing brackets TODO: make sure we're checking this map's brackets! Q3 can have multiple
+               if(s == "{")
+               {
+                       if(testing_map)
+                               return false; // edge case? already in a bracketed section!
+                       testing_map = true;
                        continue;
+               }
+               if(s == "}" || s == " }") // check for a space (common practice in kool maps)
+               {
+                       if(!testing_map)
+                               return false; // no starting bracket! let the mapinfo generation system handle it
+                       testing_map = false;
+                       if(dosave)
+                       {
+                               MapInfo_Map_description = stored_Map_description;
+                               MapInfo_Map_title = stored_Map_title;
+                               FOREACH(Gametypes, it.m_flags & stored_supportedGametypes,
+                               {
+                                       _MapInfo_Map_ApplyGametype ("", pGametypeToSet, it, true);
+                               });
+                               break; // no need to continue through the file, we have our map!
+                       }
+                       else
+                       {
+                               // discard any gathered locals, we're not using the correct map!
+                               stored_Map_description = "";
+                               stored_Map_title = "";
+                               stored_supportedGametypes = 0;
+                               continue;
+                       }
+               }
+
                s = strreplace("\t", " ", s);
 
                float p = strstrofs(s, "//", 0);
@@ -804,9 +841,9 @@ void _MapInfo_ParseArena(int fh, Gametype pGametypeToSet, bool isdefi)
                {
                        // in .defi files, this is the description, whereas in .arena files, this is generally the title
                        if(isdefi)
-                               MapInfo_Map_description = s;
+                               stored_Map_description = s;
                        else
-                               MapInfo_Map_title = s;
+                               stored_Map_title = s;
                }
                else if(t == "author")
                        MapInfo_Map_author = s;
@@ -819,17 +856,28 @@ void _MapInfo_ParseArena(int fh, Gametype pGametypeToSet, bool isdefi)
                        {
                                Gametype f = MapInfo_Type_FromString(it);
                                if(f)
-                                       _MapInfo_Map_ApplyGametype ("", pGametypeToSet, f, true);
+                                       stored_supportedGametypes |= f.m_flags;
                        });
                }
                else if(t == "style" && isdefi)
                {
                        // we have a defrag map on our hands, add CTS!
                        // TODO: styles
-                       _MapInfo_Map_ApplyGametype ("", pGametypeToSet, MAPINFO_TYPE_CTS, true);
+                       stored_supportedGametypes |= MAPINFO_TYPE_CTS.m_flags;
+               }
+               else if(t == "map")
+               {
+                       if(strtolower(s) == strtolower(pFilename))
+                               dosave = true; // yay, found our map!
                }
                // TODO: fraglimit
        }
+
+       // didn't find a closing bracket, uh oh!
+       // nothing has been saved anyway, let's abort and use generated mapinfo
+       if(testing_map)
+               return false;
+       return true;
 }
 
 #if defined(CSQC) || defined(MENUQC)
@@ -919,8 +967,8 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                if(fh >= 0)
                {
                        _MapInfo_Map_Reset();
-                       _MapInfo_ParseArena(fh, pGametypeToSet, isdefi);
-                       goto mapinfo_handled; // skip generation
+                       if(_MapInfo_ParseArena(fh, pFilename, pGametypeToSet, isdefi))
+                               goto mapinfo_handled; // skip generation
                }
 
                fn = strcat("maps/autogenerated/", pFilename, ".mapinfo");