Page MenuHomeWildfire Games

Catch PSError MapReader and MapGenerator exceptions
ClosedPublic

Authored by elexis on Jul 16 2019, 11:12 PM.

Details

Reviewers
historic_bruno
Group Reviewers
Restricted Owners Package(Owns No Changed Paths)
Commits
rP22521: Correct uncaught MapReader and MapGenerator throw statements following rP9193…
Summary

If a C++ exception is triggered during the loading screen when loading the mapfile (regardless of maptype), then
the program behaves as intended and calls terminate.
But a range of exceptions is caught in main.cpp, so these remaining errors should be caught as well.

rP3728 introduced the PSERROR_File_InvalidVersion and PSERROR_File_ReadFailed exception.
rP9193 introduced the catch for PSERROR_Game_World_MapLoadFailed.
rP21131 copied the PSERROR_File_InvalidVersion and added a PSERROR_File_OpenFailed one.

Test Plan

Consider whether it is intended to catch these rather than to terminate the program. Consider whether all exceptions should be caught or only this specific PSERROR_Game_World_MapLoadFailed.

Diff Detail

Repository
rP 0 A.D. Public Repository
Branch
/ps/trunk
Lint
Lint OK
Unit
No Unit Test Coverage
Build Status
Buildable 8470
Build 13841: Vulcan BuildJenkins
Build 13840: arc lint + arc unit

Event Timeline

elexis created this revision.Jul 16 2019, 11:12 PM

Build failure - The Moirai have given mortals hearts that can endure.

Link to build: https://jenkins.wildfiregames.com/job/docker-differential/106/display/redirect

wraitii added a reviewer: Restricted Owners Package.Jul 17 2019, 10:01 AM
elexis added a comment.EditedJul 17 2019, 12:27 PM

Some excerpts of the irc discussion on 2019-07-16-QuakeNet-#0ad-dev.log leading to this diff:

19:35 < historicbruno> elexis, yeah if those occur in their own thread, and we don't a catch() for them, it will be uncaught and bad things happen. Hard to believe that code has never been tested...
19:36 < historicbruno> elexis, those exceptions are supposed to be thrown/caught in the main thread, I believe
19:43 < historicbruno> elexis, but we definitely need to fix this problem too
19:44 < historicbruno> yeah it's broken now, since we don't catch those exceptions (I dont know what happened, maybe they were moved? originally in the main thread?)
21:41 < historicbruno> elexis, doesn't matter to me how it's handled, as long as it results in a clean failure and return to the main menu :)

and from 2019-07-17-QuakeNet-#0ad-dev.log:

00:12 < elexis> historicbruno: D2089 was what you had in mind?
00:15 < elexis> one can also change the catch (PSERROR_Game_World_MapLoadFailed& e) in main.cpp to be more generous, but not sure if one wants to catch everything
00:21 < historicbruno> elexis, I like the helpful error messages, and fixing multiple crashes :)

More discussion in http://irclogs.wildfiregames.com/2019-07/2019-07-17-QuakeNet-%230ad-dev.log

16:11 < elexis> historicbruno: for D2089 should the exceptions be changed as proposed there to the common PSERROR_Game_World_MapLoadFailed, or should main.cpp / GameSetup.cpp be changed to catch more widely? or a different PSERROR that is wider?
16:11 < WildfireBot> D2089: Catch all MapReader and MapGenerator exceptions [Needs Review] – https://code.wildfiregames.com/D2089
16:18 < historicbruno> elexis: PSERROR_Game_World_MapLoadFailed makes sense to me (for now). We might want to rethink the exceptions at some point
16:20 < historicbruno> I think the best practice is to be as specific as you can with exception handling, so you implement only what is expected to be caught there
16:21 < historicbruno> (if you catch something that wasn't expected, you might not be able to handle it properly, everything else should be passed to another handler)
16:22 < elexis> agree
16:22 < elexis> one can go through the entire code and see if some call can raise some exception noone thought about yet
16:22 < elexis> it wouldnt be a regression if such was triggered though
16:23 < elexis> I scanned that file, but I didnt recurse through the dependent ones

I would propose to limit the objective of this diff to correcting the present throw calls that result in std::termine() instead of JS error message popup returning to main menu. (At least there are some greater priority tasks at hand currently it seems.)

historic_bruno added inline comments.
source/graphics/MapGenerator.cpp
343

Could add the name of the file to the error message, to ease troubleshooting.

354

Same here

elexis retitled this revision from Catch all MapReader and MapGenerator exceptions to Catch PSError MapReader and MapGenerator exceptions.Jul 19 2019, 4:42 PM

Current PSERROR_Game_World_MapLoadFailed(" messages:

graphics/MapReader.cpp:		throw PSERROR_Game_World_MapLoadFailed("Could not load terrain file - too old version!");
graphics/MapReader.cpp:		throw PSERROR_Game_World_MapLoadFailed("Error loading map: no terrain data.\nCheck application log for details.");
graphics/MapReader.cpp:		throw PSERROR_Game_World_MapLoadFailed("Could not read map XML file!");
graphics/MapReader.cpp:		throw PSERROR_Game_World_MapLoadFailed("Error generating random map.\nCheck application log for details.");
graphics/MapReader.cpp:			throw PSERROR_Game_World_MapLoadFailed("Error generating random map.\nCheck application log for details.");
graphics/MapReader.cpp:			throw PSERROR_Game_World_MapLoadFailed("Error parsing terrain data.\nCheck application log for details"); }
ps/GameSetup/GameSetup.cpp:		throw PSERROR_Game_World_MapLoadFailed("Unable to load map file, check the path for typos.");
ps/GameSetup/GameSetup.cpp:			throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details.");
ps/GameSetup/GameSetup.cpp:		throw PSERROR_Game_World_MapLoadFailed("Unrecognized map type.\nConsult readme.txt for the currently supported types.");
ps/GameSetup/GameSetup.cpp:			throw PSERROR_Game_World_MapLoadFailed("Error reading victory script.\nCheck application log for details.");
ps/World.cpp:			throw PSERROR_Game_World_MapLoadFailed("Failed to load map.\nCheck application log for details.");
ps/Errors.cpp:	case 0x07040001: throw PSERROR_Game_World_MapLoadFailed(); break;

Those are the others:

graphics/ModelDef.h:	 * @throw PSERROR_File if it can't load the model
graphics/SkeletonAnimDef.cpp:		throw PSERROR_File_InvalidVersion();
graphics/MapGenerator.cpp.orig:		throw PSERROR_File_OpenFailed();
graphics/MapGenerator.cpp.orig:		throw PSERROR_File_InvalidVersion();
graphics/ModelDef.cpp:		throw PSERROR_File_InvalidVersion();
gui/IGUIObject.cpp:		throw PSERROR_GUI_ObjectNeedsName();
gui/IGUIObject.cpp:		throw PSERROR_GUI_NameAmbiguity(m_Name.c_str());
gui/IGUIObject.cpp:		throw PSERROR_GUI_OperationNeedsGUIObject();
gui/IGUIObject.cpp:		throw PSERROR_GUI_OperationNeedsGUIObject();
gui/CDropDown.cpp:		throw PSERROR_GUI_OperationNeedsGUIObject();
gui/CGUI.cpp:					throw PSERROR_GUI_JSOpenFailed();
scriptinterface/ScriptInterface.cpp:		throw PSERROR_Scripting_DefineType_AlreadyExists();
scriptinterface/ScriptInterface.cpp:		throw PSERROR_Scripting_DefineType_CreationFailed();
scriptinterface/ScriptInterface.cpp:		throw PSERROR_Scripting_TypeDoesNotExist();
simulation2/serialization/ISerializer.h:	 * @throw PSERROR_Serialize_OutOfBounds if value is out of bounds
simulation2/serialization/ISerializer.h:	 * @throw PSERROR_Serialize for any other errors
simulation2/serialization/ISerializer.h:	 * @throw PSERROR_Serialize for any errors
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ReadFailed();
simulation2/serialization/StdDeserializer.cpp:// 		throw PSERROR_Deserialize_OutOfBounds("RequireBytesInStream");
simulation2/serialization/StdDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds("RequireBytesInStream");
simulation2/serialization/StdDeserializer.cpp:				throw PSERROR_Deserialize_ScriptError("Failed to find serializable prototype for object");
simulation2/serialization/StdDeserializer.cpp:				throw PSERROR_Deserialize_ScriptError("JS_NewObject failed");
simulation2/serialization/StdDeserializer.cpp:				throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");
simulation2/serialization/StdDeserializer.cpp:					throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("Deserializer failed to create new object");
simulation2/serialization/StdDeserializer.cpp:					throw PSERROR_Deserialize_ScriptError();
simulation2/serialization/StdDeserializer.cpp:					throw PSERROR_Deserialize_ScriptError();
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_NewNumberValue failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("Invalid backref tag");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_New failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError();
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_New failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_New failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError();
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("js_IsArrayBuffer failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("Failed to deserialize unrecognized typed array view");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("js_CreateTypedArrayWithBuffer failed");
simulation2/serialization/StdDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds();
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_NewStringCopyN failed");
simulation2/serialization/StdDeserializer.cpp:			throw PSERROR_Deserialize_ScriptError("JS_NewUCStringCopyN failed");
simulation2/serialization/StdDeserializer.cpp:		throw PSERROR_Deserialize_ScriptError();
simulation2/serialization/IDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds(name);
simulation2/serialization/IDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds(name);
simulation2/serialization/IDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds(name);
simulation2/serialization/IDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds(name);
simulation2/serialization/IDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds(name);
simulation2/serialization/IDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds(name);
simulation2/serialization/IDeserializer.cpp:			throw PSERROR_Deserialize_InvalidCharInString();
simulation2/serialization/IDeserializer.cpp:		throw PSERROR_Deserialize_InvalidCharInString();
simulation2/serialization/IDeserializer.cpp:		throw PSERROR_Deserialize_OutOfBounds(name);
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_OutOfBounds();
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_OutOfBounds();
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_OutOfBounds();
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_OutOfBounds();
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_OutOfBounds();
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_OutOfBounds();
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_OutOfBounds();
simulation2/serialization/ISerializer.cpp:			throw PSERROR_Serialize_InvalidCharInString();
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_OutOfBounds();
simulation2/serialization/ISerializer.cpp:		throw PSERROR_Serialize_InvalidCharInString();
simulation2/serialization/BinarySerializer.cpp:		throw PSERROR_Serialize_InvalidScriptValue();
simulation2/serialization/BinarySerializer.cpp:				throw PSERROR_Serialize_ScriptError("JS_GetArrayLength failed");
simulation2/serialization/BinarySerializer.cpp:				throw PSERROR_Serialize_ScriptError("JS_GetClass failed");
simulation2/serialization/BinarySerializer.cpp:					throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed");
simulation2/serialization/BinarySerializer.cpp:						throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");
simulation2/serialization/BinarySerializer.cpp:							throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");
simulation2/serialization/BinarySerializer.cpp:								throw PSERROR_Serialize_ScriptError("Prototype Serialize function failed");
simulation2/serialization/BinarySerializer.cpp:					throw PSERROR_Serialize_ScriptError("JS::ToNumber failed");
simulation2/serialization/BinarySerializer.cpp:					throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");
simulation2/serialization/BinarySerializer.cpp:					throw PSERROR_Serialize_ScriptError("JS::MapEntries failed");
simulation2/serialization/BinarySerializer.cpp:					throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::init failed");
simulation2/serialization/BinarySerializer.cpp:						throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::next failed");
simulation2/serialization/BinarySerializer.cpp:				throw PSERROR_Serialize_InvalidScriptValue();
simulation2/serialization/BinarySerializer.cpp:			throw PSERROR_Serialize_ScriptError("JS_Enumerate failed");
simulation2/serialization/BinarySerializer.cpp:				throw PSERROR_Serialize_ScriptError("JS_GetPropertyDescriptorById failed");
simulation2/serialization/BinarySerializer.cpp:				throw PSERROR_Serialize_ScriptError("Cannot serialize property getters");
simulation2/serialization/BinarySerializer.cpp:				throw PSERROR_Serialize_ScriptError("JS_IdToValue failed");
simulation2/serialization/BinarySerializer.cpp:				throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");
simulation2/serialization/BinarySerializer.cpp:				throw PSERROR_Serialize_ScriptError("JS_GetPropertyById failed");
simulation2/serialization/BinarySerializer.cpp:		throw PSERROR_Serialize_InvalidScriptValue();
simulation2/serialization/BinarySerializer.cpp:		throw PSERROR_Serialize_InvalidScriptValue();
simulation2/serialization/BinarySerializer.cpp:			throw PSERROR_Serialize_ScriptError("JS_GetLatin1StringCharsAndLength failed");
simulation2/serialization/BinarySerializer.cpp:			throw PSERROR_Serialize_ScriptError("JS_GetTwoByteStringCharsAndLength failed");
simulation2/components/CCmpAIManager.cpp:				throw PSERROR_Deserialize_ScriptError();
ps/GameSetup/GameSetup.cpp:		throw PSERROR_System_SDLInitFailed();
ps/GameSetup/GameSetup.cpp:			throw PSERROR_System_VmodeFailed(); // abort startup
ps/Errors.h:	void foo() { throw PSERROR_ModuleName_FrobnificationFailed(); }
ps/Errors.h:	void bar() { throw PSERROR_ModuleName_FrobnificationFailed("More informative message"); }
ps/FileIo.cpp:		throw PSERROR_File_WriteFailed();
ps/FileIo.cpp:		throw PSERROR_File_OpenFailed();
ps/FileIo.cpp:		throw PSERROR_File_OpenFailed();
ps/FileIo.cpp:		throw PSERROR_File_ReadFailed();
ps/FileIo.cpp:		throw PSERROR_File_InvalidType();
ps/FileIo.cpp:		throw PSERROR_File_UnexpectedEOF();
ps/FileIo.cpp:		throw PSERROR_File_UnexpectedEOF();
ps/Errors.cpp:	case 0x01000001: throw PSERROR_CVFSFile_AlreadyLoaded(); break;
ps/Errors.cpp:	case 0x01000002: throw PSERROR_CVFSFile_InvalidBufferAccess(); break;
ps/Errors.cpp:	case 0x01000003: throw PSERROR_CVFSFile_LoadFailed(); break;
ps/Errors.cpp:	case 0x02000001: throw PSERROR_Deserialize_InvalidCharInString(); break;
ps/Errors.cpp:	case 0x02000002: throw PSERROR_Deserialize_OutOfBounds(); break;
ps/Errors.cpp:	case 0x02000003: throw PSERROR_Deserialize_ReadFailed(); break;
ps/Errors.cpp:	case 0x02000004: throw PSERROR_Deserialize_ScriptError(); break;
ps/Errors.cpp:	case 0x03000001: throw PSERROR_DllLoader_DllNotLoaded(); break;
ps/Errors.cpp:	case 0x03000002: throw PSERROR_DllLoader_SymbolNotFound(); break;
ps/Errors.cpp:	case 0x04000001: throw PSERROR_Error_InvalidError(); break;
ps/Errors.cpp:	case 0x05000001: throw PSERROR_File_InvalidType(); break;
ps/Errors.cpp:	case 0x05000002: throw PSERROR_File_InvalidVersion(); break;
ps/Errors.cpp:	case 0x05000003: throw PSERROR_File_OpenFailed(); break;
ps/Errors.cpp:	case 0x05000004: throw PSERROR_File_ReadFailed(); break;
ps/Errors.cpp:	case 0x05000005: throw PSERROR_File_UnexpectedEOF(); break;
ps/Errors.cpp:	case 0x05000006: throw PSERROR_File_WriteFailed(); break;
ps/Errors.cpp:	case 0x06000001: throw PSERROR_GUI_InvalidSetting(); break;
ps/Errors.cpp:	case 0x06000002: throw PSERROR_GUI_JSOpenFailed(); break;
ps/Errors.cpp:	case 0x06000003: throw PSERROR_GUI_NameAmbiguity(); break;
ps/Errors.cpp:	case 0x06000004: throw PSERROR_GUI_NullObjectProvided(); break;
ps/Errors.cpp:	case 0x06000005: throw PSERROR_GUI_ObjectNeedsName(); break;
ps/Errors.cpp:	case 0x06000006: throw PSERROR_GUI_OperationNeedsGUIObject(); break;
ps/Errors.cpp:	case 0x06000007: throw PSERROR_GUI_UnableToParse(); break;
ps/Errors.cpp:	case 0x08030001: throw PSERROR_I18n_Script_SetupFailed(); break;
ps/Errors.cpp:	case 0x09000001: throw PSERROR_Renderer_VBOFailed(); break;
ps/Errors.cpp:	case 0x0a010001: throw PSERROR_Scripting_DefineType_AlreadyExists(); break;
ps/Errors.cpp:	case 0x0a010002: throw PSERROR_Scripting_DefineType_CreationFailed(); break;
ps/Errors.cpp:	case 0x0a020001: throw PSERROR_Scripting_LoadFile_EvalErrors(); break;
ps/Errors.cpp:	case 0x0a020002: throw PSERROR_Scripting_LoadFile_OpenFailed(); break;
ps/Errors.cpp:	case 0x0a000001: throw PSERROR_Scripting_CallFunctionFailed(); break;
ps/Errors.cpp:	case 0x0a000002: throw PSERROR_Scripting_ConversionFailed(); break;
ps/Errors.cpp:	case 0x0a000003: throw PSERROR_Scripting_CreateObjectFailed(); break;
ps/Errors.cpp:	case 0x0a000004: throw PSERROR_Scripting_DefineConstantFailed(); break;
ps/Errors.cpp:	case 0x0a000005: throw PSERROR_Scripting_RegisterFunctionFailed(); break;
ps/Errors.cpp:	case 0x0a000006: throw PSERROR_Scripting_SetupFailed(); break;
ps/Errors.cpp:	case 0x0a000007: throw PSERROR_Scripting_TypeDoesNotExist(); break;
ps/Errors.cpp:	case 0x0b000001: throw PSERROR_Serialize_InvalidCharInString(); break;
ps/Errors.cpp:	case 0x0b000002: throw PSERROR_Serialize_InvalidScriptValue(); break;
ps/Errors.cpp:	case 0x0b000003: throw PSERROR_Serialize_OutOfBounds(); break;
ps/Errors.cpp:	case 0x0b000004: throw PSERROR_Serialize_ScriptError(); break;
ps/Errors.cpp:	case 0x0c000001: throw PSERROR_System_RequiredExtensionsMissing(); break;
ps/Errors.cpp:	case 0x0c000002: throw PSERROR_System_SDLInitFailed(); break;
ps/Errors.cpp:	case 0x0c000003: throw PSERROR_System_VmodeFailed(); break;
ps/Errors.cpp:	case 0x0d000001: throw PSERROR_Xeromyces_XMLOpenFailed(); break;
ps/Errors.cpp:	case 0x0d000002: throw PSERROR_Xeromyces_XMLParseError(); break;
ps/Errors.cpp:	default: throw PSERROR_Error_InvalidError(); // Hmm...
ps/DllLoader.cpp:		throw PSERROR_DllLoader_DllNotLoaded();
ps/DllLoader.cpp:		throw PSERROR_DllLoader_SymbolNotFound();

So not sure if the filename should be added to the error message,as it is one of multiple arguments involved in the stacktrace. Arguably the most relevant for the exceptions in question on the other hand.

Reading again, those two modified instances in MapReader.cpp are file-related and thus would be justifiable to display the string. But given that it doesn't work without changing PSERROR to consume copies, meh.

source/graphics/MapReader.cpp
454

When changing it to:

+		throw PSERROR_Game_World_MapLoadFailed(
+			("Could not read map XML file \"" + xml_filename.string8() + "\"!").c_str());

It displays the correct stack in the commandline output but the messagebox displays random characters. But it displays the data correctly when defining a literal instead of using c_str.
The c_str() pointer is owned by the intermediary object, so that intermediary object is already destroyed when the messagebox is shown, and the PSError constructor only takes over the pointer but doesn't copy the string, hence we can only use literals for PSERRORS or change PSERROR to copy that string.

elexis updated this revision to Diff 9005.Jul 20 2019, 2:02 AM

Report error to include the filename, but not PSERROR since that doesnt copy the string and breaks.

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  62|  62| var g_RomanNumbers = [undefined, "I", "II", "III", "IV", "V", "VI", "VII", "VIII"];
|  63|  63| 
|  64|  64| var g_PlayerTeamList = prepareForDropdown([{
|  65|    |-		"label": translateWithContext("team", "None"),
|    |  65|+	"label": translateWithContext("team", "None"),
|  66|  66| 		"id": -1
|  67|  67| 	}].concat(
|  68|  68| 		Array(g_MaxTeams).fill(0).map((v, i) => ({
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  63|  63| 
|  64|  64| var g_PlayerTeamList = prepareForDropdown([{
|  65|  65| 		"label": translateWithContext("team", "None"),
|  66|    |-		"id": -1
|    |  66|+	"id": -1
|  67|  67| 	}].concat(
|  68|  68| 		Array(g_MaxTeams).fill(0).map((v, i) => ({
|  69|  69| 			"label": i + 1,
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 0 tabs but found 1.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  64|  64| var g_PlayerTeamList = prepareForDropdown([{
|  65|  65| 		"label": translateWithContext("team", "None"),
|  66|  66| 		"id": -1
|  67|    |-	}].concat(
|    |  67|+}].concat(
|  68|  68| 		Array(g_MaxTeams).fill(0).map((v, i) => ({
|  69|  69| 			"label": i + 1,
|  70|  70| 			"id": i
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  65|  65| 		"label": translateWithContext("team", "None"),
|  66|  66| 		"id": -1
|  67|  67| 	}].concat(
|  68|    |-		Array(g_MaxTeams).fill(0).map((v, i) => ({
|    |  68|+	Array(g_MaxTeams).fill(0).map((v, i) => ({
|  69|  69| 			"label": i + 1,
|  70|  70| 			"id": i
|  71|  71| 		}))
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  66|  66| 		"id": -1
|  67|  67| 	}].concat(
|  68|  68| 		Array(g_MaxTeams).fill(0).map((v, i) => ({
|  69|    |-			"label": i + 1,
|    |  69|+		"label": i + 1,
|  70|  70| 			"id": i
|  71|  71| 		}))
|  72|  72| 	)
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  67|  67| 	}].concat(
|  68|  68| 		Array(g_MaxTeams).fill(0).map((v, i) => ({
|  69|  69| 			"label": i + 1,
|  70|    |-			"id": i
|    |  70|+		"id": i
|  71|  71| 		}))
|  72|  72| 	)
|  73|  73| );
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  68|  68| 		Array(g_MaxTeams).fill(0).map((v, i) => ({
|  69|  69| 			"label": i + 1,
|  70|  70| 			"id": i
|  71|    |-		}))
|    |  71|+	}))
|  72|  72| 	)
|  73|  73| );
|  74|  74| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 0 tabs but found 1.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  69|  69| 			"label": i + 1,
|  70|  70| 			"id": i
|  71|  71| 		}))
|  72|    |-	)
|    |  72|+)
|  73|  73| );
|  74|  74| 
|  75|  75| /**
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  78|  78| var g_RelicCountList = Object.keys(g_CivData).map((civ, i) => i + 1);
|  79|  79| 
|  80|  80| var g_PlayerCivList = g_CivData && prepareForDropdown([{
|  81|    |-		"name": translateWithContext("civilization", "Random"),
|    |  81|+	"name": translateWithContext("civilization", "Random"),
|  82|  82| 		"tooltip": translate("Picks one civilization at random when the game starts."),
|  83|  83| 		"color": g_ColorRandom,
|  84|  84| 		"code": "random"
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  79|  79| 
|  80|  80| var g_PlayerCivList = g_CivData && prepareForDropdown([{
|  81|  81| 		"name": translateWithContext("civilization", "Random"),
|  82|    |-		"tooltip": translate("Picks one civilization at random when the game starts."),
|    |  82|+	"tooltip": translate("Picks one civilization at random when the game starts."),
|  83|  83| 		"color": g_ColorRandom,
|  84|  84| 		"code": "random"
|  85|  85| 	}].concat(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  80|  80| var g_PlayerCivList = g_CivData && prepareForDropdown([{
|  81|  81| 		"name": translateWithContext("civilization", "Random"),
|  82|  82| 		"tooltip": translate("Picks one civilization at random when the game starts."),
|  83|    |-		"color": g_ColorRandom,
|    |  83|+	"color": g_ColorRandom,
|  84|  84| 		"code": "random"
|  85|  85| 	}].concat(
|  86|  86| 		Object.keys(g_CivData).filter(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  81|  81| 		"name": translateWithContext("civilization", "Random"),
|  82|  82| 		"tooltip": translate("Picks one civilization at random when the game starts."),
|  83|  83| 		"color": g_ColorRandom,
|  84|    |-		"code": "random"
|    |  84|+	"code": "random"
|  85|  85| 	}].concat(
|  86|  86| 		Object.keys(g_CivData).filter(
|  87|  87| 			civ => g_CivData[civ].SelectableInGameSetup
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 0 tabs but found 1.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  82|  82| 		"tooltip": translate("Picks one civilization at random when the game starts."),
|  83|  83| 		"color": g_ColorRandom,
|  84|  84| 		"code": "random"
|  85|    |-	}].concat(
|    |  85|+}].concat(
|  86|  86| 		Object.keys(g_CivData).filter(
|  87|  87| 			civ => g_CivData[civ].SelectableInGameSetup
|  88|  88| 		).map(civ => ({
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  83|  83| 		"color": g_ColorRandom,
|  84|  84| 		"code": "random"
|  85|  85| 	}].concat(
|  86|    |-		Object.keys(g_CivData).filter(
|    |  86|+	Object.keys(g_CivData).filter(
|  87|  87| 			civ => g_CivData[civ].SelectableInGameSetup
|  88|  88| 		).map(civ => ({
|  89|  89| 			"name": g_CivData[civ].Name,
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  84|  84| 		"code": "random"
|  85|  85| 	}].concat(
|  86|  86| 		Object.keys(g_CivData).filter(
|  87|    |-			civ => g_CivData[civ].SelectableInGameSetup
|    |  87|+		civ => g_CivData[civ].SelectableInGameSetup
|  88|  88| 		).map(civ => ({
|  89|  89| 			"name": g_CivData[civ].Name,
|  90|  90| 			"tooltip": g_CivData[civ].History,
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  85|  85| 	}].concat(
|  86|  86| 		Object.keys(g_CivData).filter(
|  87|  87| 			civ => g_CivData[civ].SelectableInGameSetup
|  88|    |-		).map(civ => ({
|    |  88|+	).map(civ => ({
|  89|  89| 			"name": g_CivData[civ].Name,
|  90|  90| 			"tooltip": g_CivData[civ].History,
|  91|  91| 			"color": g_ColorRegular,
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  86|  86| 		Object.keys(g_CivData).filter(
|  87|  87| 			civ => g_CivData[civ].SelectableInGameSetup
|  88|  88| 		).map(civ => ({
|  89|    |-			"name": g_CivData[civ].Name,
|    |  89|+		"name": g_CivData[civ].Name,
|  90|  90| 			"tooltip": g_CivData[civ].History,
|  91|  91| 			"color": g_ColorRegular,
|  92|  92| 			"code": civ
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  87|  87| 			civ => g_CivData[civ].SelectableInGameSetup
|  88|  88| 		).map(civ => ({
|  89|  89| 			"name": g_CivData[civ].Name,
|  90|    |-			"tooltip": g_CivData[civ].History,
|    |  90|+		"tooltip": g_CivData[civ].History,
|  91|  91| 			"color": g_ColorRegular,
|  92|  92| 			"code": civ
|  93|  93| 		})).sort(sortNameIgnoreCase)
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  88|  88| 		).map(civ => ({
|  89|  89| 			"name": g_CivData[civ].Name,
|  90|  90| 			"tooltip": g_CivData[civ].History,
|  91|    |-			"color": g_ColorRegular,
|    |  91|+		"color": g_ColorRegular,
|  92|  92| 			"code": civ
|  93|  93| 		})).sort(sortNameIgnoreCase)
|  94|  94| 	)
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  89|  89| 			"name": g_CivData[civ].Name,
|  90|  90| 			"tooltip": g_CivData[civ].History,
|  91|  91| 			"color": g_ColorRegular,
|  92|    |-			"code": civ
|    |  92|+		"code": civ
|  93|  93| 		})).sort(sortNameIgnoreCase)
|  94|  94| 	)
|  95|  95| );
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  90|  90| 			"tooltip": g_CivData[civ].History,
|  91|  91| 			"color": g_ColorRegular,
|  92|  92| 			"code": civ
|  93|    |-		})).sort(sortNameIgnoreCase)
|    |  93|+	})).sort(sortNameIgnoreCase)
|  94|  94| 	)
|  95|  95| );
|  96|  96| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 0 tabs but found 1.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|  91|  91| 			"color": g_ColorRegular,
|  92|  92| 			"code": civ
|  93|  93| 		})).sort(sortNameIgnoreCase)
|  94|    |-	)
|    |  94|+)
|  95|  95| );
|  96|  96| 
|  97|  97| /**
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|1240|1240| 			offset = -Math.min(slideSpeed * dt, maxOffset);
|1241|1241| 	}
|1242|1242| 
|1243|    |-	updateSettingsPanelPosition(offset);	
|    |1243|+	updateSettingsPanelPosition(offset);
|1244|1244| }
|1245|1245| 
|1246|1246| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js
|1774|1774| 	let biomeList;
|1775|1775| 
|1776|1776| 	if (g_GameAttributes.mapType == "random" && g_GameAttributes.settings.SupportedBiomes)
|1777|    |-	{
|    |1777|+	
|1778|1778| 		if (typeof g_GameAttributes.settings.SupportedBiomes == "string")
|1779|1779| 			biomeList = g_Settings.Biomes.filter(biome => biome.Id.startsWith(g_GameAttributes.settings.SupportedBiomes));
|1780|1780| 		else
|1781|1781| 			biomeList = g_Settings.Biomes.filter(
|1782|1782| 				biome => g_GameAttributes.settings.SupportedBiomes.indexOf(biome.Id) != -1);
|1783|    |-	}
|    |1783|+	
|1784|1784| 
|1785|1785| 	g_BiomeList = biomeList && prepareForDropdown(
|1786|1786| 		[{

binaries/data/mods/public/gui/gamesetup/gamesetup.js
|2018| »   while·(g_IsNetworked)
|    | [NORMAL] ESLintBear (no-unmodified-loop-condition):
|    | 'g_IsNetworked' is not modified in this loop.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/docker-differential/140/display/redirect

historic_bruno accepted this revision.Jul 20 2019, 9:36 PM
historic_bruno added inline comments.
source/graphics/MapReader.cpp
454

Yeah that's a known issue with the exceptions (and why I didn't recommend changing those). I'm happy with the nicer JS errors for this diff.

This revision is now accepted and ready to land.Jul 20 2019, 9:36 PM
This revision was automatically updated to reflect the committed changes.
Owners added subscribers: Restricted Owners Package, Restricted Owners Package.Jul 21 2019, 3:35 AM