If there is a building that has a paired tech researchable, where the two techs have a civ requirement but the parent pair tech doesn't, then the selection panels will throw errors.
This has happened with rP18653, https://wildfiregames.com/forum/index.php?/topic/24732-de-alpha-24/page/2/, and other incidences.
It should not throw an error but handle it more gracefully.
Details
- Reviewers
- None
- Commits
- rP24621: Avoid GUI errors for captured structures with paired tech of different civ.
- Trac Tickets
- #5915
Dig through the tech parsing maze. Consider whether returning false for unmet civ requirements still makes sense over returning an array. Conclude that the GUI is the one making assumptions that are not always true, or at least should be handled gracefully if not met, rather than the tech req parsing code being in the wrong.
Figure something out about the indentation.
The issue can be tested by:
- removing the requirements from pair_unlock_champions.json
- starting a cheat game with sele and non-sele
- "gift from the gods" cheat to fast build and age 3
- build fortress with sele
- alt+d / change perspective to brit, reveal map
- select fortress, type "wololo" to capture it
Result are errors, expected result are no errors and a happy panel.
Diff Detail
- Repository
- rP 0 A.D. Public Repository
- Branch
- /ps/trunk
- Lint
Lint OK Severity Location Code Message Warning binaries/data/mods/public/gui/session/selection_panels.js:50 ESLintBear (default-case) ESLintBear (default-case) Warning binaries/data/mods/public/gui/session/selection_panels.js:61 ESLintBear (default-case) ESLintBear (default-case) Warning binaries/data/mods/public/gui/session/selection_panels.js:709 ESLintBear (default-case) ESLintBear (default-case) Warning binaries/data/mods/public/gui/session/selection_panels.js:744 ESLintBear (no-multi-spaces) ESLintBear (no-multi-spaces) - Unit
No Unit Test Coverage - Build Status
Buildable 14993 Build 32393: Vulcan Build Jenkins Build 32392: Vulcan Build (macOS) Jenkins Build 32391: Vulcan Build (Windows) Jenkins Build 32390: arc lint + arc unit
Event Timeline
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 5 tabs but found 4. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 721| 721| let reqs = template.reqs; | 722| 722| | 723| 723| if (reqs) | 724| |- for (let req of reqs) | | 724|+ for (let req of reqs) | 725| 725| { | 726| 726| if (!req.entities) | 727| 727| continue; | | [NORMAL] ESLintBear (indent): | | Expected indentation of 5 tabs but found 4. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 722| 722| | 723| 723| if (reqs) | 724| 724| for (let req of reqs) | 725| |- { | | 725|+ { | 726| 726| if (!req.entities) | 727| 727| continue; | 728| 728| | | [NORMAL] ESLintBear (indent): | | Expected indentation of 6 tabs but found 5. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 723| 723| if (reqs) | 724| 724| for (let req of reqs) | 725| 725| { | 726| |- if (!req.entities) | | 726|+ if (!req.entities) | 727| 727| continue; | 728| 728| | 729| 729| let entityCounts = []; | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 724| 724| for (let req of reqs) | 725| 725| { | 726| 726| if (!req.entities) | 727| |- continue; | | 727|+ continue; | 728| 728| | 729| 729| let entityCounts = []; | 730| 730| for (let entity of req.entities) | | [NORMAL] ESLintBear (indent): | | Expected indentation of 6 tabs but found 5. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 726| 726| if (!req.entities) | 727| 727| continue; | 728| 728| | 729| |- let entityCounts = []; | | 729|+ let entityCounts = []; | 730| 730| for (let entity of req.entities) | 731| 731| { | 732| 732| let current = 0; | | [NORMAL] ESLintBear (indent): | | Expected indentation of 6 tabs but found 5. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 727| 727| continue; | 728| 728| | 729| 729| let entityCounts = []; | 730| |- for (let entity of req.entities) | | 730|+ for (let entity of req.entities) | 731| 731| { | 732| 732| let current = 0; | 733| 733| switch (entity.check) | | [NORMAL] ESLintBear (indent): | | Expected indentation of 6 tabs but found 5. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 728| 728| | 729| 729| let entityCounts = []; | 730| 730| for (let entity of req.entities) | 731| |- { | | 731|+ { | 732| 732| let current = 0; | 733| 733| switch (entity.check) | 734| 734| { | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 729| 729| let entityCounts = []; | 730| 730| for (let entity of req.entities) | 731| 731| { | 732| |- let current = 0; | | 732|+ let current = 0; | 733| 733| switch (entity.check) | 734| 734| { | 735| 735| case "count": | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 730| 730| for (let entity of req.entities) | 731| 731| { | 732| 732| let current = 0; | 733| |- switch (entity.check) | | 733|+ switch (entity.check) | 734| 734| { | 735| 735| case "count": | 736| 736| current = playerState.classCounts[entity.class] || 0; | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 731| 731| { | 732| 732| let current = 0; | 733| 733| switch (entity.check) | 734| |- { | | 734|+ { | 735| 735| case "count": | 736| 736| current = playerState.classCounts[entity.class] || 0; | 737| 737| break; | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 732| 732| let current = 0; | 733| 733| switch (entity.check) | 734| 734| { | 735| |- case "count": | | 735|+ case "count": | 736| 736| current = playerState.classCounts[entity.class] || 0; | 737| 737| break; | 738| 738| | | [NORMAL] ESLintBear (indent): | | Expected indentation of 8 tabs but found 7. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 733| 733| switch (entity.check) | 734| 734| { | 735| 735| case "count": | 736| |- current = playerState.classCounts[entity.class] || 0; | | 736|+ current = playerState.classCounts[entity.class] || 0; | 737| 737| break; | 738| 738| | 739| 739| case "variants": | | [NORMAL] ESLintBear (indent): | | Expected indentation of 8 tabs but found 7. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 734| 734| { | 735| 735| case "count": | 736| 736| current = playerState.classCounts[entity.class] || 0; | 737| |- break; | | 737|+ break; | 738| 738| | 739| 739| case "variants": | 740| 740| current = playerState.typeCountsByClass[entity.class] ? | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 736| 736| current = playerState.classCounts[entity.class] || 0; | 737| 737| break; | 738| 738| | 739| |- case "variants": | | 739|+ case "variants": | 740| 740| current = playerState.typeCountsByClass[entity.class] ? | 741| 741| Object.keys(playerState.typeCountsByClass[entity.class]).length : 0; | 742| 742| break; | | [NORMAL] ESLintBear (indent): | | Expected indentation of 8 tabs but found 7. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 737| 737| break; | 738| 738| | 739| 739| case "variants": | 740| |- current = playerState.typeCountsByClass[entity.class] ? | | 740|+ current = playerState.typeCountsByClass[entity.class] ? | 741| 741| Object.keys(playerState.typeCountsByClass[entity.class]).length : 0; | 742| 742| break; | 743| 743| } | | [NORMAL] ESLintBear (indent): | | Expected indentation of 9 tabs but found 8. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 738| 738| | 739| 739| case "variants": | 740| 740| current = playerState.typeCountsByClass[entity.class] ? | 741| |- Object.keys(playerState.typeCountsByClass[entity.class]).length : 0; | | 741|+ Object.keys(playerState.typeCountsByClass[entity.class]).length : 0; | 742| 742| break; | 743| 743| } | 744| 744| | | [NORMAL] ESLintBear (indent): | | Expected indentation of 8 tabs but found 7. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 739| 739| case "variants": | 740| 740| current = playerState.typeCountsByClass[entity.class] ? | 741| 741| Object.keys(playerState.typeCountsByClass[entity.class]).length : 0; | 742| |- break; | | 742|+ break; | 743| 743| } | 744| 744| | 745| 745| let remaining = entity.number - current; | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 740| 740| current = playerState.typeCountsByClass[entity.class] ? | 741| 741| Object.keys(playerState.typeCountsByClass[entity.class]).length : 0; | 742| 742| break; | 743| |- } | | 743|+ } | 744| 744| | 745| 745| let remaining = entity.number - current; | 746| 746| if (remaining < 1) | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 742| 742| break; | 743| 743| } | 744| 744| | 745| |- let remaining = entity.number - current; | | 745|+ let remaining = entity.number - current; | 746| 746| if (remaining < 1) | 747| 747| continue; | 748| 748| | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 743| 743| } | 744| 744| | 745| 745| let remaining = entity.number - current; | 746| |- if (remaining < 1) | | 746|+ if (remaining < 1) | 747| 747| continue; | 748| 748| | 749| 749| entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { | | [NORMAL] ESLintBear (indent): | | Expected indentation of 8 tabs but found 7. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 744| 744| | 745| 745| let remaining = entity.number - current; | 746| 746| if (remaining < 1) | 747| |- continue; | | 747|+ continue; | 748| 748| | 749| 749| entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { | 750| 750| "number": remaining, | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 746| 746| if (remaining < 1) | 747| 747| continue; | 748| 748| | 749| |- entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { | | 749|+ entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { | 750| 750| "number": remaining, | 751| 751| "class": entity.class | 752| 752| })); | | [NORMAL] ESLintBear (indent): | | Expected indentation of 8 tabs but found 7. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 747| 747| continue; | 748| 748| | 749| 749| entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { | 750| |- "number": remaining, | | 750|+ "number": remaining, | 751| 751| "class": entity.class | 752| 752| })); | 753| 753| } | | [NORMAL] ESLintBear (indent): | | Expected indentation of 8 tabs but found 7. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 748| 748| | 749| 749| entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { | 750| 750| "number": remaining, | 751| |- "class": entity.class | | 751|+ "class": entity.class | 752| 752| })); | 753| 753| } | 754| 754| | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 749| 749| entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { | 750| 750| "number": remaining, | 751| 751| "class": entity.class | 752| |- })); | | 752|+ })); | 753| 753| } | 754| 754| | 755| 755| tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { | | [NORMAL] ESLintBear (indent): | | Expected indentation of 6 tabs but found 5. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 750| 750| "number": remaining, | 751| 751| "class": entity.class | 752| 752| })); | 753| |- } | | 753|+ } | 754| 754| | 755| 755| tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { | 756| 756| "entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", ")) | | [NORMAL] ESLintBear (indent): | | Expected indentation of 6 tabs but found 5. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 752| 752| })); | 753| 753| } | 754| 754| | 755| |- tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { | | 755|+ tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { | 756| 756| "entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", ")) | 757| 757| }); | 758| 758| } | | [NORMAL] ESLintBear (indent): | | Expected indentation of 7 tabs but found 6. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 753| 753| } | 754| 754| | 755| 755| tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { | 756| |- "entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", ")) | | 756|+ "entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", ")) | 757| 757| }); | 758| 758| } | 759| 759| tooltips.push(tip); | | [NORMAL] ESLintBear (indent): | | Expected indentation of 6 tabs but found 5. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 754| 754| | 755| 755| tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { | 756| 756| "entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", ")) | 757| |- }); | | 757|+ }); | 758| 758| } | 759| 759| tooltips.push(tip); | 760| 760| } | | [NORMAL] ESLintBear (indent): | | Expected indentation of 5 tabs but found 4. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 755| 755| tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { | 756| 756| "entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", ")) | 757| 757| }); | 758| |- } | | 758|+ } | 759| 759| tooltips.push(tip); | 760| 760| } | 761| 761| tooltips.push(getNeededResourcesTooltip(neededResources)); | | [NORMAL] ESLintBear (space-before-function-paren): | | Unexpected space before function parentheses. |----| | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js | 765| 765| addResearchToQueue(data.item.researchFacilityId, t); | 766| 766| })(tech); | 767| 767| | 768| |- button.onPressRight = (t => function () { | | 768|+ button.onPressRight = (t => function() { | 769| 769| showTemplateDetails( | 770| 770| t, | 771| 771| GetTemplateData(data.unitEntStates.find(state => state.id == data.item.researchFacilityId).template).nativeCiv); binaries/data/mods/public/gui/session/selection_panels.js | 48| » » » switch·(data.item) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/selection_panels.js | 59| » » switch·(data.item) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/selection_panels.js | 733| » » » » » » switch·(entity.check) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. Executing section cli...
Link to build: https://jenkins.wildfiregames.com/job/docker-differential/361/display/redirect
The patches fixes the bug.
But it seems it reveals a new one.
With your test plan and the patch the paired tech is greyed out and says this tech will be unlocked in city phase...
@Imarok's finding can probably be fixed by not showing techs from another civ.
I'll look into this.
Build has FAILED
builderr-debug-macos.txt /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libsimulation2_dbg.a(precompiled.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libengine_dbg.a(precompiled.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libgraphics_dbg.a(precompiled.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libatlas_dbg.a(precompiled.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libgui_dbg.a(precompiled.o) has no symbols ld: warning: text-based stub file /System/Library/Frameworks//CoreAudio.framework/CoreAudio.tbd and library file
Link to build: https://jenkins.wildfiregames.com/job/macos-differential/2832/display/redirect
See console output for more information: https://jenkins.wildfiregames.com/job/macos-differential/2832/display/redirectconsole