Ticket #3826: patch.patch

File patch.patch, 10.6 KB (added by Stephen Imhoff, 8 years ago)
  • binaries/data/mods/public/gui/session/input.js

    From d2e8ad2998691cbf531ba3a5b31d7d0924379fc3 Mon Sep 17 00:00:00 2001
    From: "Stephen A. Imhoff" <clockwork-muse@outlook.com>
    Date: Sun, 1 May 2016 15:18:29 +0900
    Subject: [PATCH] Improve FindIdleUnits
    
    ---
     binaries/data/mods/public/gui/session/input.js     | 89 ++++++++------------
     binaries/data/mods/public/gui/session/session.js   | 15 +---
     .../public/simulation/components/GuiInterface.js   | 98 +++++++++++++++++-----
     3 files changed, 119 insertions(+), 83 deletions(-)
    
    diff --git a/binaries/data/mods/public/gui/session/input.js b/binaries/data/mods/public/gui/session/input.js
    index 9ef4ee6..9357ca0 100644
    a b function setCameraFollow(entity)  
    16831683}
    16841684
    16851685var lastIdleUnit = 0;
    1686 var currIdleClass = 0;
    1687 var lastIdleType = undefined;
     1686var currIdleClassIndex = 0;
     1687var lastIdleClasses = [];
    16881688
    16891689function resetIdleUnit()
    16901690{
    16911691    lastIdleUnit = 0;
    1692     currIdleClass = 0;
    1693     lastIdleType = undefined;
     1692    currIdleClassIndex = 0;
     1693    lastIdleClasses = [];
    16941694}
    16951695
    16961696function findIdleUnit(classes)
    function findIdleUnit(classes)  
    16991699    var selectall = Engine.HotkeyIsPressed("selection.offscreen");
    17001700
    17011701    // Reset the last idle unit, etc., if the selection type has changed.
    1702     var type = classes.join();
    1703     if (selectall || type != lastIdleType)
     1702    if (selectall || classes.length != lastIdleClasses.length || !classes.every((v,i) => v === lastIdleClasses[i]))
    17041703        resetIdleUnit();
    1705     lastIdleType = type;
     1704    lastIdleClasses = classes;
    17061705
    1707     // If selectall is true, there is no limit and it's necessary to iterate
    1708     // over all of the classes, resetting only when the first match is found.
    1709     var matched = false;
    1710 
    1711     for (var i = 0; i < classes.length; ++i)
     1706    var data = {
     1707        "viewedPlayer": g_ViewedPlayer,
     1708        "excludeUnits": append ? g_Selection.toList() : [],
     1709        // If the current idle class index is not 0, put the class at that index first.
     1710        "idleClasses": classes.slice(currIdleClassIndex, classes.length).concat(classes.slice(0, currIdleClassIndex))
     1711    };
     1712    if (!selectall)
    17121713    {
    1713         var data = {
    1714             "idleClass": classes[currIdleClass],
    1715             "prevUnit": lastIdleUnit,
    1716             "limit": 1,
    1717             "excludeUnits": []
    1718         };
    1719 
    1720         if (append)
    1721             data.excludeUnits = g_Selection.toList();
    1722 
    1723         if (selectall)
    1724             data = { "idleClass": classes[currIdleClass] };
    1725 
    1726         data.viewedPlayer = g_ViewedPlayer;
    1727 
    1728         // Check if we have new valid entity
    1729         var idleUnits = Engine.GuiInterfaceCall("FindIdleUnits", data);
    1730         if (idleUnits.length && idleUnits[0] != lastIdleUnit)
    1731         {
    1732             lastIdleUnit = idleUnits[0];
    1733             if (!append && (!selectall || selectall && !matched))
    1734                 g_Selection.reset();
     1714        data.limit = 1;
     1715        data.prevUnit = lastIdleUnit;
     1716    }
    17351717
    1736             if (selectall)
    1737                 g_Selection.addList(idleUnits);
    1738             else
    1739             {
    1740                 g_Selection.addList([lastIdleUnit]);
    1741                 var position = GetEntityState(lastIdleUnit).position;
    1742                 if (position)
    1743                     Engine.CameraMoveTo(position.x, position.z);
    1744                 return;
    1745             }
     1718    var idleUnits = Engine.GuiInterfaceCall("FindIdleUnits", data);
     1719    if (!idleUnits.length)
     1720    {
     1721        // TODO: display a message or play a sound to indicate no more idle units, or something
     1722        // Reset for next cycle
     1723        resetIdleUnit();
     1724        return;
     1725    }
    17461726
    1747             matched = true;
    1748         }
     1727    if (!append)
     1728        g_Selection.reset();
     1729    g_Selection.addList(idleUnits);
    17491730
    1750         lastIdleUnit = 0;
    1751         currIdleClass = (currIdleClass + 1) % classes.length;
    1752     }
     1731    if (selectall)
     1732        return;
    17531733
    1754     // TODO: display a message or play a sound to indicate no more idle units, or something
    1755     // Reset for next cycle
    1756     resetIdleUnit();
     1734    lastIdleUnit = idleUnits[0];
     1735    var entityState = GetEntityState(lastIdleUnit);
     1736    var position = entityState.position;
     1737    if (position)
     1738        Engine.CameraMoveTo(position.x, position.z);
     1739    // Move the idle class index to the first class an idle unit was found for.
     1740    var indexChange = data.idleClasses.findIndex(elem => hasClass(entityState, elem));
     1741    currIdleClassIndex = (currIdleClassIndex + indexChange) % classes.length;
    17571742}
    17581743
    17591744function stopUnits(entities)
  • binaries/data/mods/public/gui/session/session.js

    diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js
    index 8b23cb3..5d6cb18 100644
    a b function changeGameSpeed(speed)  
    650650
    651651function hasIdleWorker()
    652652{
    653     for (let workerType of g_WorkerTypes)
    654     {
    655         let idleUnits = Engine.GuiInterfaceCall("FindIdleUnits", {
     653    return Engine.GuiInterfaceCall("HasIdleUnits", {
    656654            "viewedPlayer": g_ViewedPlayer,
    657             "idleClass": workerType,
    658             "prevUnit": undefined,
    659             "limit": 1,
     655            "idleClasses": g_WorkerTypes,
    660656            "excludeUnits": []
    661         });
    662 
    663         if (idleUnits.length > 0)
    664             return true;
    665     }
    666     return false;
     657    });
    667658}
    668659
    669660function updateIdleWorkerButton()
  • binaries/data/mods/public/simulation/components/GuiInterface.js

    diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
    index e4b7300..8aeff3f 100644
    a b GuiInterface.prototype.PlaySound = function(player, data)  
    16451645    PlaySound(data.name, data.entity);
    16461646};
    16471647
     1648/**
     1649 * Find any idle units.
     1650 *
     1651 * @param data.viewedPlayer The player for which to find idle units.
     1652 * @param data.idleClasses      Array of class names to include.
     1653 * @param data.prevUnit     The previous idle unit, if calling a second time to iterate through units.  May be left undefined.
     1654 * @param data.limit            The number of idle units to return.  May be left undefined (will return all idle units).
     1655 * @param data.excludeUnits Array of units to exclude.
     1656 *
     1657 * Returns an array of idle units.
     1658 * If multiple classes were supplied, and multiple items will be returned, the items will be sorted by class.
     1659 */
    16481660GuiInterface.prototype.FindIdleUnits = function(player, data)
    16491661{
     1662    let idleUnits = [];
     1663    // The general case is that only the 'first' idle unit is required; filtering would examine every unit.
     1664    // This loop imitates a grouping/aggregation on the first matching idle class.
    16501665    let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    1651     let playerEntities = cmpRangeManager.GetEntitiesByPlayer(data.viewedPlayer).filter(entity => {
     1666    for (let entity of cmpRangeManager.GetEntitiesByPlayer(data.viewedPlayer))
     1667    {
     1668        let filtered = this.IdleUnitFilter(entity, data.idleClasses, data.excludeUnits);
     1669        if (!filtered.idle)
     1670            continue;
    16521671
    1653         let cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
    1654         if (!cmpUnitAI || !cmpUnitAI.IsIdle() || cmpUnitAI.IsGarrisoned())
    1655             return false;
     1672        // If the entity is in the 'current' (first, 0) bucket on a resumed search, it must be after the "previous" unit, if any.
     1673        // By adding to the 'end', there is no pause if the series of units loops.
     1674        var bucket = filtered.bucket;
     1675        if(bucket == 0 && data.prevUnit && entity <= data.prevUnit)
     1676            bucket = data.idleClasses.length;
    16561677
    1657         let cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
    1658         if (!cmpIdentity || !cmpIdentity.HasClass(data.idleClass))
    1659             return false;
     1678        if (!idleUnits[bucket])
     1679            idleUnits[bucket] = [];
     1680        idleUnits[bucket].push(entity);
    16601681
    1661         return true;
    1662     });
     1682        // If enough units have been collected in the first bucket, go ahead and return them.
     1683        if (data.limit && bucket == 0 && idleUnits[0].length == data.limit)
     1684            return idleUnits[0];
     1685    }
    16631686
    1664     let idleUnits = [];
     1687    let reduced = idleUnits.reduce((prev, curr) => prev.concat(curr), []);
     1688    if (data.limit && reduced.length > data.limit)
     1689        return reduced.slice(0, data.limit);
    16651690
    1666     for (let ent of playerEntities)
    1667     {
    1668         if (ent <= data.prevUnit|0 || data.excludeUnits.indexOf(ent) > -1)
    1669             continue;
    1670         idleUnits.push(ent);
    1671         if (data.limit && idleUnits.length >= data.limit)
    1672             break;
    1673     }
     1691    return reduced;
     1692};
     1693
     1694/**
     1695 * Discover if the player has idle units.
     1696 *
     1697 * @param data.viewedPlayer The player for which to find idle units.
     1698 * @param data.idleClasses  Array of class names to include.
     1699 * @param data.excludeUnits Array of units to exclude.
     1700 *
     1701 * Returns a boolean of whether the player has any idle units
     1702 */
     1703GuiInterface.prototype.HasIdleUnits = function(player, data)
     1704{
     1705    let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     1706    return cmpRangeManager.GetEntitiesByPlayer(data.viewedPlayer).some(unit => this.IdleUnitFilter(unit, data.idleClasses, data.excludeUnits).idle);
     1707};
     1708
     1709/**
     1710 * Whether to filter an idle unit
     1711 *
     1712 * @param unit          The unit to filter.
     1713 * @param idleclasses   Array of class names to include.
     1714 * @param excludeUnits  Array of units to exclude.
     1715 *
     1716 * Returns an object with the following fields:
     1717 *  - idle - true if the unit is considered idle by the filter, false otherwise.
     1718 *  - bucket - if idle, set to the index of the first matching idle class, undefined otherwise.
     1719 */
     1720GuiInterface.prototype.IdleUnitFilter = function(unit, idleClasses, excludeUnits)
     1721{
     1722    let cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
     1723    if (!cmpUnitAI || !cmpUnitAI.IsIdle() || cmpUnitAI.IsGarrisoned())
     1724        return { "idle": false };
     1725
     1726    let cmpIdentity = Engine.QueryInterface(unit, IID_Identity);
     1727    if(!cmpIdentity)
     1728        return { "idle": false };
     1729
     1730    let bucket = idleClasses.findIndex(elem => cmpIdentity.HasClass(elem));
     1731    if (bucket == -1 || excludeUnits.some(elem => elem == unit))
     1732        return { "idle": false };
    16741733
    1675     return idleUnits;
     1734    return { "idle": true, "bucket": bucket };
    16761735};
    16771736
    16781737GuiInterface.prototype.GetTradingRouteGain = function(player, data)
    let exposedFunctions = {  
    18991958    "GetFoundationSnapData": 1,
    19001959    "PlaySound": 1,
    19011960    "FindIdleUnits": 1,
     1961    "HasIdleUnits": 1,
    19021962    "GetTradingRouteGain": 1,
    19031963    "GetTradingDetails": 1,
    19041964    "CanCapture": 1,
  • binaries/data/mods/public/gui/credits/texts/programming.json

    -- 
    1.9.5.msysgit.0
    
    From 4d2d7326216fe9242ab61ffeeb18c86b2c0cc122 Mon Sep 17 00:00:00 2001
    From: "Stephen A. Imhoff" <clockwork-muse@outlook.com>
    Date: Sun, 1 May 2016 15:17:29 +0900
    Subject: [PATCH] Add contribution credit.
    
    ---
     binaries/data/mods/public/gui/credits/texts/programming.json | 1 +
     1 file changed, 1 insertion(+)
    
    diff --git a/binaries/data/mods/public/gui/credits/texts/programming.json b/binaries/data/mods/public/gui/credits/texts/programming.json
    index d7cb950..86dae45 100644
    a b  
    3939            {"nick": "Calvinh", "name": "Carl-Johan Höiby"},
    4040            {"name": "Cédric Houbart"},
    4141            {"nick": "Chakakhan", "name": "Kenny Long"},
     42            {"nick": "Clockwork-Muse", "name": "Stephen A. Imhoff"},
    4243            {"nick": "Cracker78", "name": "Chad Heim"},
    4344            {"nick": "Crynux", "name": "Stephen J. Fewer"},
    4445            {"nick": "cwprogger"},