As reported by user1 and some other lobby players, if a non-natural number is used in the batch-train-size option,
the simulation becomes broken in various ways.
Details
- Reviewers
wraitii - Commits
- rP19826: Prevent players from gaining unlimited resources by setting the batch-train…
- Trac Tickets
- #4459
Don't apply the patch, start a game, open the options, set a string that isn't a number and observe
the GUI breaking when pressing shift and training something, as well as
having NaN resources, that avoid the resource cost restriction.
A non-natural number as a string will train N % 1 units and the remaining fraction can't be trained.
The population counter can also becomes a non-natural number.
Apply only the simulation patch to verify that even malicious multiplayer clients can't break the simulation anymore when controlling their GUI.
Apply the entire patch to verify that casual player can't break anything, even if they type a non-natural number or non-number in that option field.
Diff Detail
- Repository
- rP 0 A.D. Public Repository
- Branch
- batchtrainNaN
- Lint
No Linters Available - Unit
No Unit Test Coverage - Build Status
Buildable 242 Build 385: Vulcan Build Jenkins Build 384: arc lint + arc unit
Event Timeline
The GUI already prevents entering numbers smaller than 1 and that's not going to change as the number of entities will always be a natural number.
By editing the user.cfg, this can still be set to 0 or a negative number. However the simulation and GUI still work correctly. The user can only shoot himself in the foot, noone else.
Build is green
Updating workspaces. Build (release)... Build (debug)... Running debug tests... Running cxxtest tests (302 tests)..............................................................................................................................................................................................................................................................................................................OK!
http://jw:8080/job/phabricator/165/ for more details.
We'll have to check that a slightly malicious host can't set up the game in a way that makes his player an AI and thus enables him to bypass that one check. I guess that could even be something wanted for a trainer AI, but meh.
binaries/data/mods/public/simulation/helpers/Commands.js | ||
---|---|---|
269 | Why not floor? User code that supplies something that isn't an int is broken anyway. Actually why not if (Math.round(+cmd.count) != +cmd.count) { warn("fix that gui of yours."); return; } ```? (Yes, that most likely breaks on `NaN`, but so does the current code.) |
This would be a good spot for a regression test on second thought, but otherwise imo you can commit this.
Obviously this is broken all over the place in the simulation, for example we can also send NaN resource amounts to a player when sending a custom command via F9.
(That must have been meant for D65)
For the wiki page, suggesting to add
=== Batch simulating games === The behavior of the AI can be tested by running multiple games consecutively, for example by analyzing the summary screen data at the end of the game from the replay menu. As described in source:/ps/trunk/binaries/system/readme.txt, a new match can be started directly by passing the mapname and player assignments as command line arguments. Add an `API3.exit()` statement to an arbitrary place of the AI code or an `Engine.ExitProgram()` statement to the GUI code (for example if all players have been defeated or won in `messages.js`). Using a unix shell or windows batch script allows to repeatedly start matches after the previous pyrogenesis instance exited.
binaries/data/mods/public/simulation/helpers/Commands.js | ||
---|---|---|
269 | We should avoid adding warnings to every place where a modder could break the GUI, since they'd be everywhere. Adding a fix to test for all cases. |
Indeed, same for your wiki addition ;-)
binaries/data/mods/public/simulation/helpers/Commands.js | ||
---|---|---|
269 | Then we just encourage them to write broken code (which I do appreciate for testing the simulation sanity checks, but I'd rather have them not write broken code). I guess we might need some sanity checking for places where we take numbers from the GUI. And I think I still prefer floor here. |
Number.isInteger check.
ProductionQueue check.
Merge duplication.
1 check.
Probably nicer to read if the other places are fixed in separate patches.
Build is green
Updating workspaces. Build (release)... Build (debug)... Running release tests... Running cxxtest tests (306 tests)..................................................................................................................................................................................................................................................................................................................OK! Running debug tests... Running cxxtest tests (306 tests)..................................................................................................................................................................................................................................................................................................................OK! Checking XML files...
http://jw:8080/job/phabricator/1614/ for more details.
Executing section Default... Executing section Source... Executing section JS... | | [NORMAL] ESLintBear (no-else-return): | | Unnecessary 'else' after 'return'. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 240| 240| return (cmpTechnologyManager.IsTechnologyResearched(template.top) || cmpTechnologyManager.IsInProgress(template.top) | 241| 241| || cmpTechnologyManager.IsTechnologyResearched(template.bottom) || cmpTechnologyManager.IsInProgress(template.bottom)); | 242| 242| } | 243| |- else | 244| |- { | | 243|+ | 245| 244| return (cmpTechnologyManager.IsTechnologyResearched(tech) || cmpTechnologyManager.IsInProgress(tech)); | 246| |- } | | 245|+ | 247| 246| }; | 248| 247| | 249| 248| /* | | [NORMAL] ESLintBear (no-multi-spaces): | | Multiple spaces found before '+'. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 299| 299| totalCosts[res] = Math.floor(count * costs[res]); | 300| 300| } | 301| 301| | 302| |- var population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, cmpPlayer.GetPlayerID(), template); | | 302|+ var population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, cmpPlayer.GetPlayerID(), template); | 303| 303| | 304| 304| // TrySubtractResources should report error to player (they ran out of resources) | 305| 305| if (!cmpPlayer.TrySubtractResources(totalCosts)) | | [NORMAL] ESLintBear (no-multi-spaces): | | Multiple spaces found before 'techCostMultiplier'. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 349| 349| } | 350| 350| | 351| 351| let techCostMultiplier = this.GetTechCostMultiplier(); | 352| |- let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier(); | | 352|+ let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier(); | 353| 353| | 354| 354| let cost = {}; | 355| 355| for (let res in template.cost) | | [NORMAL] ESLintBear (no-undef-init): | | It's not necessary to initialize 'cmpAutoGarrison' to undefined. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 596| 596| } | 597| 597| } | 598| 598| | 599| |- var cmpAutoGarrison = undefined; | | 599|+ var cmpAutoGarrison; | 600| 600| if (cmpRallyPoint) | 601| 601| { | 602| 602| var data = cmpRallyPoint.GetData()[0]; | | [NORMAL] ESLintBear (no-multi-spaces): | | Multiple spaces found before '+'. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 706| 706| { | 707| 707| // If something change population cost | 708| 708| var template = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager).GetTemplate(item.unitTemplate); | 709| |- item.population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, item.player, template); | | 709|+ item.population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, item.player, template); | 710| 710| | 711| 711| // Batch's training hasn't started yet. | 712| 712| // Try to reserve the necessary population slots binaries/data/mods/public/simulation/components/ProductionQueue.js | 352| » » » let·time·=··techCostMultiplier.time·*·template.researchTime·*·cmpPlayer.GetCheatTimeMultiplier(); | | [NORMAL] ESLintBear (no-shadow): | | 'time' is already declared in the upper scope. binaries/data/mods/public/simulation/components/ProductionQueue.js | 189| » for·(var·i·in·techList) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 191| » » var·tech·=·techList[i]; | | [NORMAL] JSHintBear: | | 'tech' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 203| » for·(var·i·=·0;·i·<·techList.length;·i++) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 205| » » var·tech·=·techList[i]; | | [NORMAL] JSHintBear: | | 'tech' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 212| » » var·template·=·cmpTechnologyManager.GetTechnologyTemplate(tech); | | [NORMAL] JSHintBear: | | 'template' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 241| » » » ||·cmpTechnologyManager.IsTechnologyResearched(template.bottom)·||·cmpTechnologyManager.IsInProgress(template.bottom)); | | [NORMAL] JSHintBear: | | Misleading line break before '||'; readers may interpret this as an expression boundary. binaries/data/mods/public/simulation/components/ProductionQueue.js | 279| » » » » if·(requiredXp·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 337| » » » var·template·=·cmpDataTemplateManager.GetTechnologyTemplate(templateName); | | [NORMAL] JSHintBear: | | 'template' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 366| » » » if·(this.queue.length·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 381| » » » var·cmpTrigger·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Trigger); | | [NORMAL] JSHintBear: | | 'cmpTrigger' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 420| » for·(var·i·=·0;·i·<·this.queue.length;·++i) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 577| » if·(this.entityCache.length·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 599| » var·cmpAutoGarrison·=·undefined; | | [NORMAL] JSHintBear: | | It's not necessary to initialize 'cmpAutoGarrison' to 'undefined'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 607| » for·(var·i·=·0;·i·<·count;·++i) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 609| » » var·ent·=·this.entityCache[0]; | | [NORMAL] JSHintBear: | | 'ent' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 642| » » if·(createdEnts.length·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 779| » » » » » var·cmpPlayer·=·QueryOwnerInterface(this.entity); | | [NORMAL] JSHintBear: | | 'cmpPlayer' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 790| » » » var·cmpTechnologyManager·=·QueryOwnerInterface(this.entity,·IID_TechnologyManager); | | [NORMAL] JSHintBear
http://jw:8080/job/phabricator_lint/231/ for more details.
If we write a test AddBatch in test_ProductionQueue by passing a NaN we also run into the issue of having to silence warnings for a specific test (because that should definitely show a warning the code before returning).
binaries/data/mods/public/gui/session/input.js | ||
---|---|---|
1448 | Might just as well nuke the duplication then. A new function will also force this to be >= 1, in case something changes in the future in the following code. | |
binaries/data/mods/public/simulation/helpers/Commands.js | ||
269 | Then the shortest and most accurate check would be https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger for (let value of [1, 1.1, "1", -1, 0, NaN, ({}).nope, undefined]) warn(uneval(value) + " isNumber: " + uneval(Number.isInteger(value))); WARNING: 1 isNumber: true WARNING: 1.1 isNumber: false WARNING: "1" isNumber: false WARNING: -1 isNumber: true WARNING: 0 isNumber: true WARNING: NaN isNumber: false WARNING: (void 0) isNumber: false WARNING: (void 0) isNumber: false |
As fatherbushido mentioned, isNumber also returns false for Infinity, whereas Math.floor(x) == x returns true (and we want to return false).
Also error out on negative numbers.
In particular prevent display of warnings for all players if someone set a non-numerical string by accident.
Build is green
Updating workspaces. Build (release)... Build (debug)... Running release tests... Running cxxtest tests (306 tests)..................................................................................................................................................................................................................................................................................................................OK! Running debug tests... Running cxxtest tests (306 tests)..................................................................................................................................................................................................................................................................................................................OK! Checking XML files...
http://jw:8080/job/phabricator/1618/ for more details.
Executing section Default... Executing section Source... Executing section JS... binaries/data/mods/public/simulation/helpers/InitGame.js | 51| » » if·(settings.PlayerData[i]·&&·settings.PlayerData[i].AI·&&·settings.PlayerData[i].AI·!=·"") | | [NORMAL] JSHintBear: | | Use '!==' to compare with ''. | | [NORMAL] ESLintBear (no-else-return): | | Unnecessary 'else' after 'return'. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 240| 240| return (cmpTechnologyManager.IsTechnologyResearched(template.top) || cmpTechnologyManager.IsInProgress(template.top) | 241| 241| || cmpTechnologyManager.IsTechnologyResearched(template.bottom) || cmpTechnologyManager.IsInProgress(template.bottom)); | 242| 242| } | 243| |- else | 244| |- { | | 243|+ | 245| 244| return (cmpTechnologyManager.IsTechnologyResearched(tech) || cmpTechnologyManager.IsInProgress(tech)); | 246| |- } | | 245|+ | 247| 246| }; | 248| 247| | 249| 248| /* | | [NORMAL] ESLintBear (no-multi-spaces): | | Multiple spaces found before '+'. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 299| 299| totalCosts[res] = Math.floor(count * costs[res]); | 300| 300| } | 301| 301| | 302| |- var population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, cmpPlayer.GetPlayerID(), template); | | 302|+ var population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, cmpPlayer.GetPlayerID(), template); | 303| 303| | 304| 304| // TrySubtractResources should report error to player (they ran out of resources) | 305| 305| if (!cmpPlayer.TrySubtractResources(totalCosts)) | | [NORMAL] ESLintBear (no-multi-spaces): | | Multiple spaces found before 'techCostMultiplier'. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 349| 349| } | 350| 350| | 351| 351| let techCostMultiplier = this.GetTechCostMultiplier(); | 352| |- let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier(); | | 352|+ let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier(); | 353| 353| | 354| 354| let cost = {}; | 355| 355| for (let res in template.cost) | | [NORMAL] ESLintBear (no-undef-init): | | It's not necessary to initialize 'cmpAutoGarrison' to undefined. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 596| 596| } | 597| 597| } | 598| 598| | 599| |- var cmpAutoGarrison = undefined; | | 599|+ var cmpAutoGarrison; | 600| 600| if (cmpRallyPoint) | 601| 601| { | 602| 602| var data = cmpRallyPoint.GetData()[0]; | | [NORMAL] ESLintBear (no-multi-spaces): | | Multiple spaces found before '+'. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/simulation/components/ProductionQueue.js | 706| 706| { | 707| 707| // If something change population cost | 708| 708| var template = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager).GetTemplate(item.unitTemplate); | 709| |- item.population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, item.player, template); | | 709|+ item.population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, item.player, template); | 710| 710| | 711| 711| // Batch's training hasn't started yet. | 712| 712| // Try to reserve the necessary population slots binaries/data/mods/public/simulation/components/ProductionQueue.js | 352| » » » let·time·=··techCostMultiplier.time·*·template.researchTime·*·cmpPlayer.GetCheatTimeMultiplier(); | | [NORMAL] ESLintBear (no-shadow): | | 'time' is already declared in the upper scope. binaries/data/mods/public/simulation/components/ProductionQueue.js | 189| » for·(var·i·in·techList) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 191| » » var·tech·=·techList[i]; | | [NORMAL] JSHintBear: | | 'tech' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 203| » for·(var·i·=·0;·i·<·techList.length;·i++) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 205| » » var·tech·=·techList[i]; | | [NORMAL] JSHintBear: | | 'tech' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 212| » » var·template·=·cmpTechnologyManager.GetTechnologyTemplate(tech); | | [NORMAL] JSHintBear: | | 'template' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 241| » » » ||·cmpTechnologyManager.IsTechnologyResearched(template.bottom)·||·cmpTechnologyManager.IsInProgress(template.bottom)); | | [NORMAL] JSHintBear: | | Misleading line break before '||'; readers may interpret this as an expression boundary. binaries/data/mods/public/simulation/components/ProductionQueue.js | 279| » » » » if·(requiredXp·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 337| » » » var·template·=·cmpDataTemplateManager.GetTechnologyTemplate(templateName); | | [NORMAL] JSHintBear: | | 'template' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 366| » » » if·(this.queue.length·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 381| » » » var·cmpTrigger·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Trigger); | | [NORMAL] JSHintBear: | | 'cmpTrigger' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 420| » for·(var·i·=·0;·i·<·this.queue.length;·++i) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 577| » if·(this.entityCache.length·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 599| » var·cmpAutoGarrison·=·undefined; | | [NORMAL] JSHintBear: | | It's not necessary to initialize 'cmpAutoGarrison' to 'undefined'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 607| » for·(var·i·=·0;·i·<·count;·++i) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 609| » » var·ent·=·this.entityCache[0]; | | [NORMAL] JSHintBear: | | 'ent' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 642| » » if·(createdEnts.length·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/simulation/components/ProductionQueue.js | 779| » » » » » var·cmpPlayer·=·QueryOwnerInterface(this.entity); | | [NORMAL] JSHintBear: | | 'cmpPlayer' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 790| » » » var·cmpTechnologyManager·=·QueryOwnerInterface(this.entity,·IID_TechnologyManager); | | [NORMAL] JSHintBear: | | 'cmpTechnologyManager' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 793| » » » var·template·=·cmpTechnologyManager.GetTechnologyTemplate(item.technologyTemplate); | | [NORMAL] JSHintBear: | | 'template' is already defined. binaries/data/mods/public/simulation/components/ProductionQueue.js | 811| » if·(this.queue.length·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. | | [NORMAL] ESLintBear (no-undef-init): | | It's not necessary to initialize 'target' to undefined. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/gui/session/input.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/gui/session/input.js | 271| 271| if (!g_DevSettings.controlAll && !allOwnedByPlayer) | 272| 272| return undefined; | 273| 273| | 274| |- var target = undefined; | | 274|+ var target; | 275| 275| if (!fromMinimap) | 276| 276| { | 277| 277| var ent = Engine.PickEntityAtPoint(x, y); | | [NORMAL] ESLintBear (no-undef-init): | | It's not necessary to initialize 'actionInfo' to undefined. |----| | /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/gui/session/input.js | |++++| /mnt/data/jenkins-phabricator/workspace/phabricator_lint/binaries/data/mods/public/gui/session/input.js | 285| 285| var actions = Object.keys(unitActions).slice(); | 286| 286| actions.sort((a, b) => unitActions[a].specificness - unitActions[b].specificness); | 287| 287| | 288| |- var actionInfo = undefined; | | 288|+ var actionInfo; | 289| 289| if (preSelectedAction != ACTION_NONE) | 290| 290| { | 291| 291| for (var action of actions) binaries/data/mods/public/gui/session/input.js | 267| » » var·entState·=·GetEntityState(ent); | | [NORMAL] ESLintBear (no-shadow): | | 'entState' is already declared in the upper scope. binaries/data/mods/public/gui/session/input.js | 492| » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 519| » switch·(inputState) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 523| » » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 578| » » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 585| » » » var·maxDragDelta·=·16; | | [NORMAL] ESLintBear (no-shadow): | | 'maxDragDelta' is already declared in the upper scope. binaries/data/mods/public/gui/session/input.js | 628| » » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 657| » » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 726| » » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 843| » switch·(inputState) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 846| » » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 948| » » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js |1040| » » switch·(ev.type) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js |1109| » » » switch·(ev.hotkey) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js |1339| » return·Number.isInteger(num)·&&·num·>·0·?·num·:·5; | | [NORMAL] ESLintBear (no-unreachable): | | Unreachable code. binaries/data/mods/public/gui/session/input.js |1533| » switch·(action) | | [NORMAL] ESLintBear (default-case): | | Expected a default case. binaries/data/mods/public/gui/session/input.js | 232| » » var·entState·=·GetExtendedEntityState(entityID); | | [NORMAL] JSHintBear: | | 'entState' is already defined. binaries/data/mods/public/gui/session/input.js | 274| » var·target·=·undefined; | | [NORMAL] JSHintBear: | | It's not necessary to initialize 'target' to 'undefined'. binaries/data/mods/public/gui/session/input.js | 288| » var·actionInfo·=·undefined; | | [NORMAL] JSHintBear: | | It's not necessary to initialize 'actionInfo' to 'undefined'. binaries/data/mods/public/gui/session/input.js | 302| » for·(var·action·of·actions) | | [NORMAL] JSHintBear: | | 'action' is already defined. binaries/data/mods/public/gui/session/input.js | 305| » » » var·r·=·unitActions[action].hotkeyActionCheck(target,·selection); | | [NORMAL] JSHintBear: | | 'r' is already defined. binaries/data/mods/public/gui/session/input.js | 310| » for·(var·action·of·actions) | | [NORMAL] JSHintBear: | | 'action' is already defined. binaries/data/mods/public/gui/session/input.js | 313| » » » var·r·=·unitActions[action].actionCheck(target,·selection); | | [NORMAL] JSHintBear: | | 'r' is already defined. binaries/data/mods/public/gui/session/input.js | 503| » mouseIsOverObject·=·(hoveredObject·!=·null); | | [NORMAL] JSHintBear: | | Use '!==' to compare with 'null'. binaries/data/mods/public/gui/session/input.js | 507| » » &&·(ev.button·==·SDL_BUTTON_LEFT·||·ev.button·==·SDL_BUTTON_RIGHT)) | | [NORMAL] JSHintBear: | | Misleading line break before '&&'; readers may interpret this as an expression boundary. binaries/data/mods/public/gui/session/input.js | 537| » » » » var·rect·=·updateBandbox(bandbox,·ev,·true); | | [NORMAL] JSHintBear: | | 'rect' is already defined. binaries/data/mods/public/gui/session/input.js | 540| » » » » var·ents·=·getPreferredEntities(Engine.PickPlayerEntitiesInRect(rect[0],·rect[1],·rect[2],·rect[3],·g_ViewedPlayer)); | | [NORMAL] JSHintBear: | | 'ents' is already defined. binaries/data/mods/public/gui/session/input.js | 689| » » » » » var·queued·=·Engine.HotkeyIsPressed("session.queue"); | | [NORMAL] JSHintBear: | | 'queued' is already defined. binaries/data/mods/public/gui/session/input.js | 729| » » » var·dragDeltaX·=·ev.x·-·dragStart[0]; | | [NORMAL] JSHintBear: | | 'dragDeltaX' is already defined. binaries/data/mods/public/gui/session/input.js | 730| » » » var·dragDeltaY·=·ev.y·-·dragStart[1]; | | [NORMAL] JSHintBear: | | 'dragDeltaY' is already defined. binaries/data/mods/public/gui/session/input.js | 731| » » » var·maxDragDelta·=·16; | | [NORMAL] JSHintBear: | | 'maxDragDelta' is already defined. binaries/data/mods/public/gui/session/input.js | 763| » » » » var·queued·=·Engine.HotkeyIsPressed("session.queue"); | | [NORMAL] JSHintBear: | | 'queued' is already defined. binaries/data/mods/public/gui/session/input.js | 879| » » » » if·(ev.hotkey.indexOf("selection.group.")·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/gui/session/input.js | 884| » » » » » » if·(ev.hotkey.indexOf("selection.group.select.")·==·0) | | [NORMAL] JSHintBear: | | Use '===' to compare with '0'. binaries/data/mods/public/gui/session/input.js | 892| » » »
http://jw:8080/job/phabricator_lint/234/ for more details.