LCOV - code coverage report
Current view: top level - simulation/ai/petra - queueManager.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 329 0.0 %
Date: 2023-04-02 12:52:40 Functions: 0 31 0.0 %

          Line data    Source code
       1             : /**
       2             :  * This takes the input queues and picks which items to fund with resources until no more resources are left to distribute.
       3             :  *
       4             :  * Currently this manager keeps accounts for each queue, split between the 4 main resources
       5             :  *
       6             :  * Each time resources are available (ie not in any account), it is split between the different queues
       7             :  * Mostly based on priority of the queue, and existing needs.
       8             :  * Each turn, the queue Manager checks if a queue can afford its next item, then it does.
       9             :  *
      10             :  * A consequence of the system it's not really revertible. Once a queue has an account of 500 food, it'll keep it
      11             :  * If for some reason the AI stops getting new food, and this queue lacks, say, wood, no other queues will
      12             :  * be able to benefit form the 500 food (even if they only needed food).
      13             :  * This is not to annoying as long as all goes well. If the AI loses many workers, it starts being problematic.
      14             :  *
      15             :  * It also has the effect of making the AI more or less always sit on a few hundreds resources since most queues
      16             :  * get some part of the total, and if all queues have 70% of their needs, nothing gets done
      17             :  * Particularly noticeable when phasing: the AI often overshoots by a good 200/300 resources before starting.
      18             :  *
      19             :  * This system should be improved. It's probably not flexible enough.
      20             :  */
      21             : 
      22           0 : PETRA.QueueManager = function(Config, queues)
      23             : {
      24           0 :         this.Config = Config;
      25           0 :         this.queues = queues;
      26           0 :         this.priorities = {};
      27           0 :         for (let i in Config.priorities)
      28           0 :                 this.priorities[i] = Config.priorities[i];
      29           0 :         this.accounts = {};
      30             : 
      31             :         // the sorting is updated on priority change.
      32           0 :         this.queueArrays = [];
      33           0 :         for (let q in this.queues)
      34             :         {
      35           0 :                 this.accounts[q] = new API3.Resources();
      36           0 :                 this.queueArrays.push([q, this.queues[q]]);
      37             :         }
      38           0 :         let priorities = this.priorities;
      39           0 :         this.queueArrays.sort((a, b) => priorities[b[0]] - priorities[a[0]]);
      40             : };
      41             : 
      42           0 : PETRA.QueueManager.prototype.getAvailableResources = function(gameState)
      43             : {
      44           0 :         let resources = gameState.getResources();
      45           0 :         for (let key in this.queues)
      46           0 :                 resources.subtract(this.accounts[key]);
      47           0 :         return resources;
      48             : };
      49             : 
      50           0 : PETRA.QueueManager.prototype.getTotalAccountedResources = function()
      51             : {
      52           0 :         let resources = new API3.Resources();
      53           0 :         for (let key in this.queues)
      54           0 :                 resources.add(this.accounts[key]);
      55           0 :         return resources;
      56             : };
      57             : 
      58           0 : PETRA.QueueManager.prototype.currentNeeds = function(gameState)
      59             : {
      60           0 :         let needed = new API3.Resources();
      61             :         // queueArrays because it's faster.
      62           0 :         for (let q of this.queueArrays)
      63             :         {
      64           0 :                 let queue = q[1];
      65           0 :                 if (!queue.hasQueuedUnits() || !queue.plans[0].isGo(gameState))
      66           0 :                         continue;
      67           0 :                 let costs = queue.plans[0].getCost();
      68           0 :                 needed.add(costs);
      69             :         }
      70             :         // get out current resources, not removing accounts.
      71           0 :         let current = gameState.getResources();
      72           0 :         for (let res of Resources.GetCodes())
      73           0 :                 needed[res] = Math.max(0, needed[res] - current[res]);
      74             : 
      75           0 :         return needed;
      76             : };
      77             : 
      78             : // calculate the gather rates we'd want to be able to start all elements in our queues
      79             : // TODO: many things.
      80           0 : PETRA.QueueManager.prototype.wantedGatherRates = function(gameState)
      81             : {
      82             :         // default values for first turn when we have not yet set our queues.
      83           0 :         if (gameState.ai.playedTurn === 0)
      84             :         {
      85           0 :                 let ret = {};
      86           0 :                 for (let res of Resources.GetCodes())
      87           0 :                         ret[res] = this.Config.queues.firstTurn[res] || this.Config.queues.firstTurn.default;
      88           0 :                 return ret;
      89             :         }
      90             : 
      91             :         // get out current resources, not removing accounts.
      92           0 :         let current = gameState.getResources();
      93             :         // short queue is the first item of a queue, assumed to be ready in 30s
      94             :         // medium queue is the second item of a queue, assumed to be ready in 60s
      95             :         // long queue contains the isGo=false items, assumed to be ready in 300s
      96           0 :         let totalShort = {};
      97           0 :         let totalMedium = {};
      98           0 :         let totalLong = {};
      99           0 :         for (let res of Resources.GetCodes())
     100             :         {
     101           0 :                 totalShort[res] = this.Config.queues.short[res] || this.Config.queues.short.default;
     102           0 :                 totalMedium[res] = this.Config.queues.medium[res] || this.Config.queues.medium.default;
     103           0 :                 totalLong[res] = this.Config.queues.long[res] || this.Config.queues.long.default;
     104             :         }
     105             :         let total;
     106             :         // queueArrays because it's faster.
     107           0 :         for (let q of this.queueArrays)
     108             :         {
     109           0 :                 let queue = q[1];
     110           0 :                 if (queue.paused)
     111           0 :                         continue;
     112           0 :                 for (let j = 0; j < queue.length(); ++j)
     113             :                 {
     114           0 :                         if (j > 1)
     115           0 :                                 break;
     116           0 :                         let cost = queue.plans[j].getCost();
     117           0 :                         if (queue.plans[j].isGo(gameState))
     118             :                         {
     119           0 :                                 if (j === 0)
     120           0 :                                         total = totalShort;
     121             :                                 else
     122           0 :                                         total = totalMedium;
     123             :                         }
     124             :                         else
     125           0 :                                 total = totalLong;
     126           0 :                         for (let type in total)
     127           0 :                                 total[type] += cost[type];
     128           0 :                         if (!queue.plans[j].isGo(gameState))
     129           0 :                                 break;
     130             :                 }
     131             :         }
     132             :         // global rates
     133           0 :         let rates = {};
     134             :         let diff;
     135           0 :         for (let res of Resources.GetCodes())
     136             :         {
     137           0 :                 if (current[res] > 0)
     138             :                 {
     139           0 :                         diff = Math.min(current[res], totalShort[res]);
     140           0 :                         totalShort[res] -= diff;
     141           0 :                         current[res] -= diff;
     142           0 :                         if (current[res] > 0)
     143             :                         {
     144           0 :                                 diff = Math.min(current[res], totalMedium[res]);
     145           0 :                                 totalMedium[res] -= diff;
     146           0 :                                 current[res] -= diff;
     147           0 :                                 if (current[res] > 0)
     148           0 :                                         totalLong[res] -= Math.min(current[res], totalLong[res]);
     149             :                         }
     150             :                 }
     151           0 :                 rates[res] = totalShort[res]/30 + totalMedium[res]/60 + totalLong[res]/300;
     152             :         }
     153             : 
     154           0 :         return rates;
     155             : };
     156             : 
     157           0 : PETRA.QueueManager.prototype.printQueues = function(gameState)
     158             : {
     159           0 :         let numWorkers = 0;
     160           0 :         gameState.getOwnUnits().forEach(ent => {
     161           0 :                 if (ent.getMetadata(PlayerID, "role") === PETRA.Worker.ROLE_WORKER && ent.getMetadata(PlayerID, "plan") === undefined)
     162           0 :                         numWorkers++;
     163             :         });
     164           0 :         API3.warn("---------- QUEUES ------------ with pop " + gameState.getPopulation() + " and workers " + numWorkers);
     165           0 :         for (let i in this.queues)
     166             :         {
     167           0 :                 let q = this.queues[i];
     168           0 :                 if (q.hasQueuedUnits())
     169             :                 {
     170           0 :                         API3.warn(i + ": ( with priority " + this.priorities[i] +" and accounts " + uneval(this.accounts[i]) +")");
     171           0 :                         API3.warn(" while maxAccountWanted(0.6) is " + uneval(q.maxAccountWanted(gameState, 0.6)));
     172             :                 }
     173           0 :                 for (let plan of q.plans)
     174             :                 {
     175           0 :                         let qStr = "     " + plan.type + " ";
     176           0 :                         if (plan.number)
     177           0 :                                 qStr += "x" + plan.number;
     178           0 :                         qStr += "   isGo " + plan.isGo(gameState);
     179           0 :                         API3.warn(qStr);
     180             :                 }
     181             :         }
     182           0 :         API3.warn("Accounts");
     183           0 :         for (let p in this.accounts)
     184           0 :             API3.warn(p + ": " + uneval(this.accounts[p]));
     185           0 :         API3.warn("Current Resources: " + uneval(gameState.getResources()));
     186           0 :         API3.warn("Available Resources: " + uneval(this.getAvailableResources(gameState)));
     187           0 :         API3.warn("Wanted Gather Rates: " + uneval(gameState.ai.HQ.GetWantedGatherRates(gameState)));
     188           0 :         API3.warn("Current Gather Rates: " + uneval(gameState.ai.HQ.GetCurrentGatherRates(gameState)));
     189           0 :         API3.warn("Most needed resources: " + uneval(gameState.ai.HQ.pickMostNeededResources(gameState)));
     190           0 :         API3.warn("------------------------------------");
     191             : };
     192             : 
     193           0 : PETRA.QueueManager.prototype.clear = function()
     194             : {
     195           0 :         for (let i in this.queues)
     196           0 :                 this.queues[i].empty();
     197             : };
     198             : 
     199             : /**
     200             :  * set accounts of queue i from the unaccounted resources
     201             :  */
     202           0 : PETRA.QueueManager.prototype.setAccounts = function(gameState, cost, i)
     203             : {
     204           0 :         let available = this.getAvailableResources(gameState);
     205           0 :         for (let res of Resources.GetCodes())
     206             :         {
     207           0 :                 if (this.accounts[i][res] >= cost[res])
     208           0 :                         continue;
     209           0 :                 this.accounts[i][res] += Math.min(available[res], cost[res] - this.accounts[i][res]);
     210             :         }
     211             : };
     212             : 
     213             : /**
     214             :  * transfer accounts from queue i to queue j
     215             :  */
     216           0 : PETRA.QueueManager.prototype.transferAccounts = function(cost, i, j)
     217             : {
     218           0 :         for (let res of Resources.GetCodes())
     219             :         {
     220           0 :                 if (this.accounts[j][res] >= cost[res])
     221           0 :                         continue;
     222           0 :                 let diff = Math.min(this.accounts[i][res], cost[res] - this.accounts[j][res]);
     223           0 :                 this.accounts[i][res] -= diff;
     224           0 :                 this.accounts[j][res] += diff;
     225             :         }
     226             : };
     227             : 
     228             : /**
     229             :  * distribute the resources between the different queues according to their priorities
     230             :  */
     231           0 : PETRA.QueueManager.prototype.distributeResources = function(gameState)
     232             : {
     233           0 :         let availableRes = this.getAvailableResources(gameState);
     234           0 :         for (let res of Resources.GetCodes())
     235             :         {
     236           0 :                 if (availableRes[res] < 0)    // rescale the accounts if we've spent resources already accounted (e.g. by bartering)
     237             :                 {
     238           0 :                         let total = gameState.getResources()[res];
     239           0 :                         let scale = total / (total - availableRes[res]);
     240           0 :                         availableRes[res] = total;
     241           0 :                         for (let j in this.queues)
     242             :                         {
     243           0 :                                 this.accounts[j][res] = Math.floor(scale * this.accounts[j][res]);
     244           0 :                                 availableRes[res] -= this.accounts[j][res];
     245             :                         }
     246             :                 }
     247             : 
     248           0 :                 if (!availableRes[res])
     249             :                 {
     250           0 :                         this.switchResource(gameState, res);
     251           0 :                         continue;
     252             :                 }
     253             : 
     254           0 :                 let totalPriority = 0;
     255           0 :                 let tempPrio = {};
     256           0 :                 let maxNeed = {};
     257             :                 // Okay so this is where it gets complicated.
     258             :                 // If a queue requires "res" for the next elements (in the queue)
     259             :                 // And the account is not high enough for it.
     260             :                 // Then we add it to the total priority.
     261             :                 // To try and be clever, we don't want a long queue to hog all resources. So two things:
     262             :                 //      -if a queue has enough of resource X for the 1st element, its priority is decreased (factor 2).
     263             :                 //      -queues accounts are capped at "resources for the first + 60% of the next"
     264             :                 // This avoids getting a high priority queue with many elements hogging all of one resource
     265             :                 // uselessly while it awaits for other resources.
     266           0 :                 for (let j in this.queues)
     267             :                 {
     268             :                         // returns exactly the correct amount, ie 0 if we're not go.
     269           0 :                         let queueCost = this.queues[j].maxAccountWanted(gameState, 0.6);
     270           0 :                         if (this.queues[j].hasQueuedUnits() && this.accounts[j][res] < queueCost[res] && !this.queues[j].paused)
     271             :                         {
     272             :                                 // adding us to the list of queues that need an update.
     273           0 :                                 tempPrio[j] = this.priorities[j];
     274           0 :                                 maxNeed[j] = queueCost[res] - this.accounts[j][res];
     275             :                                 // if we have enough of that resource for our first item in the queue, diminish our priority.
     276           0 :                                 if (this.accounts[j][res] >= this.queues[j].getNext().getCost()[res])
     277           0 :                                         tempPrio[j] /= 2;
     278             : 
     279           0 :                                 if (tempPrio[j])
     280           0 :                                         totalPriority += tempPrio[j];
     281             :                         }
     282           0 :                         else if (this.accounts[j][res] > queueCost[res])
     283             :                         {
     284           0 :                                 availableRes[res] += this.accounts[j][res] - queueCost[res];
     285           0 :                                 this.accounts[j][res] = queueCost[res];
     286             :                         }
     287             :                 }
     288             :                 // Now we allow resources to the accounts. We can at most allow "TempPriority/totalpriority*available"
     289             :                 // But we'll sometimes allow less if that would overflow.
     290           0 :                 let available = availableRes[res];
     291           0 :                 let missing = false;
     292           0 :                 for (let j in tempPrio)
     293             :                 {
     294             :                         // we'll add at much what can be allowed to this queue.
     295           0 :                         let toAdd = Math.floor(availableRes[res] * tempPrio[j]/totalPriority);
     296           0 :                         if (toAdd >= maxNeed[j])
     297           0 :                                 toAdd = maxNeed[j];
     298             :                         else
     299           0 :                                 missing = true;
     300           0 :                         this.accounts[j][res] += toAdd;
     301           0 :                         maxNeed[j] -= toAdd;
     302           0 :                         available -= toAdd;
     303             :                 }
     304           0 :                 if (missing && available > 0)   // distribute the rest (due to floor) in any queue
     305             :                 {
     306           0 :                         for (let j in tempPrio)
     307             :                         {
     308           0 :                                 let toAdd = Math.min(maxNeed[j], available);
     309           0 :                                 this.accounts[j][res] += toAdd;
     310           0 :                                 available -= toAdd;
     311           0 :                                 if (available <= 0)
     312           0 :                                         break;
     313             :                         }
     314             :                 }
     315           0 :                 if (available < 0)
     316           0 :                         API3.warn("Petra: problem with remaining " + res + " in queueManager " + available);
     317             :         }
     318             : };
     319             : 
     320           0 : PETRA.QueueManager.prototype.switchResource = function(gameState, res)
     321             : {
     322             :         // We have no available resources, see if we can't "compact" them in one queue.
     323             :         // compare queues 2 by 2, and if one with a higher priority could be completed by our amount, give it.
     324             :         // TODO: this isn't perfect compression.
     325           0 :         for (let j in this.queues)
     326             :         {
     327           0 :                 if (!this.queues[j].hasQueuedUnits() || this.queues[j].paused)
     328           0 :                         continue;
     329             : 
     330           0 :                 let queue = this.queues[j];
     331           0 :                 let queueCost = queue.maxAccountWanted(gameState, 0);
     332           0 :                 if (this.accounts[j][res] >= queueCost[res])
     333           0 :                         continue;
     334             : 
     335           0 :                 for (let i in this.queues)
     336             :                 {
     337           0 :                         if (i === j)
     338           0 :                                 continue;
     339           0 :                         let otherQueue = this.queues[i];
     340           0 :                         if (this.priorities[i] >= this.priorities[j] || otherQueue.switched !== 0)
     341           0 :                                 continue;
     342           0 :                         if (this.accounts[j][res] + this.accounts[i][res] < queueCost[res])
     343           0 :                                 continue;
     344             : 
     345           0 :                         let diff = queueCost[res] - this.accounts[j][res];
     346           0 :                         this.accounts[j][res] += diff;
     347           0 :                         this.accounts[i][res] -= diff;
     348           0 :                         ++otherQueue.switched;
     349           0 :                         if (this.Config.debug > 2)
     350           0 :                                 API3.warn ("switching queue " + res + " from " + i + " to " + j + " in amount " + diff);
     351           0 :                         break;
     352             :                 }
     353             :         }
     354             : };
     355             : 
     356             : // Start the next item in the queue if we can afford it.
     357           0 : PETRA.QueueManager.prototype.startNextItems = function(gameState)
     358             : {
     359           0 :         for (let q of this.queueArrays)
     360             :         {
     361           0 :                 let name = q[0];
     362           0 :                 let queue = q[1];
     363           0 :                 if (queue.hasQueuedUnits() && !queue.paused)
     364             :                 {
     365           0 :                         let item = queue.getNext();
     366           0 :                         if (this.accounts[name].canAfford(item.getCost()) && item.canStart(gameState))
     367             :                         {
     368             :                                 // canStart may update the cost because of the costMultiplier so we must check it again
     369           0 :                                 if (this.accounts[name].canAfford(item.getCost()))
     370             :                                 {
     371           0 :                                         this.finishingTime = gameState.ai.elapsedTime;
     372           0 :                                         this.accounts[name].subtract(item.getCost());
     373           0 :                                         queue.startNext(gameState);
     374           0 :                                         queue.switched = 0;
     375             :                                 }
     376             :                         }
     377             :                 }
     378           0 :                 else if (!queue.hasQueuedUnits())
     379             :                 {
     380           0 :                         this.accounts[name].reset();
     381           0 :                         queue.switched = 0;
     382             :                 }
     383             :         }
     384             : };
     385             : 
     386           0 : PETRA.QueueManager.prototype.update = function(gameState)
     387             : {
     388           0 :         Engine.ProfileStart("Queue Manager");
     389             : 
     390           0 :         for (let i in this.queues)
     391             :         {
     392           0 :                 this.queues[i].check(gameState);  // do basic sanity checks on the queue
     393           0 :                 if (this.priorities[i] > 0)
     394           0 :                         continue;
     395           0 :                 API3.warn("QueueManager received bad priorities, please report this error: " + uneval(this.priorities));
     396           0 :                 this.priorities[i] = 1;  // TODO: make the Queue Manager not die when priorities are zero.
     397             :         }
     398             : 
     399             :         // Pause or unpause queues depending on the situation
     400           0 :         this.checkPausedQueues(gameState);
     401             : 
     402             :         // Let's assign resources to plans that need them
     403           0 :         this.distributeResources(gameState);
     404             : 
     405             :         // Start the next item in the queue if we can afford it.
     406           0 :         this.startNextItems(gameState);
     407             : 
     408           0 :         if (this.Config.debug > 1 && gameState.ai.playedTurn%50 === 0)
     409           0 :                 this.printQueues(gameState);
     410             : 
     411           0 :         Engine.ProfileStop();
     412             : };
     413             : 
     414             : // Recovery system: if short of workers after an attack, pause (and reset) some queues to favor worker training
     415           0 : PETRA.QueueManager.prototype.checkPausedQueues = function(gameState)
     416             : {
     417           0 :         const numWorkers = gameState.countOwnEntitiesAndQueuedWithRole(PETRA.Worker.ROLE_WORKER);
     418           0 :         let workersMin = Math.min(Math.max(12, 24 * this.Config.popScaling), this.Config.Economy.popPhase2);
     419           0 :         for (let q in this.queues)
     420             :         {
     421           0 :                 let toBePaused = false;
     422           0 :                 if (!gameState.ai.HQ.hasPotentialBase())
     423           0 :                         toBePaused = q != "dock" && q != "civilCentre";
     424           0 :                 else if (numWorkers < workersMin / 3)
     425           0 :                         toBePaused = q != "citizenSoldier" && q != "villager" && q != "emergency";
     426           0 :                 else if (numWorkers < workersMin * 2 / 3)
     427           0 :                         toBePaused = q == "civilCentre" || q == "economicBuilding" ||
     428             :                                 q == "militaryBuilding" || q == "defenseBuilding" || q == "healer" ||
     429             :                                 q == "majorTech" || q == "minorTech" || q.indexOf("plan_") != -1;
     430           0 :                 else if (numWorkers < workersMin)
     431           0 :                         toBePaused = q == "civilCentre" || q == "defenseBuilding" ||
     432             :                                 q == "majorTech" || q.indexOf("_siege") != -1 || q.indexOf("_champ") != -1;
     433             : 
     434           0 :                 if (toBePaused)
     435             :                 {
     436           0 :                         if (q == "field" && gameState.ai.HQ.needFarm &&
     437             :                                 !gameState.getOwnStructures().filter(API3.Filters.byClass("Field")).hasEntities())
     438           0 :                                 toBePaused = false;
     439           0 :                         if (q == "corral" && gameState.ai.HQ.needCorral &&
     440             :                                 !gameState.getOwnStructures().filter(API3.Filters.byClass("Field")).hasEntities())
     441           0 :                                 toBePaused = false;
     442           0 :                         if (q == "dock" && gameState.ai.HQ.needFish &&
     443             :                                 !gameState.getOwnStructures().filter(API3.Filters.byClass("Dock")).hasEntities())
     444           0 :                                 toBePaused = false;
     445           0 :                         if (q == "ships" && gameState.ai.HQ.needFish &&
     446             :                                 !gameState.ai.HQ.navalManager.ships.filter(API3.Filters.byClass("FishingBoat")).hasEntities())
     447           0 :                                 toBePaused = false;
     448             :                 }
     449             : 
     450           0 :                 let queue = this.queues[q];
     451           0 :                 if (!queue.paused && toBePaused)
     452             :                 {
     453           0 :                         queue.paused = true;
     454           0 :                         this.accounts[q].reset();
     455             :                 }
     456           0 :                 else if (queue.paused && !toBePaused)
     457           0 :                         queue.paused = false;
     458             : 
     459             :                 // And reduce the batch sizes of attack queues
     460           0 :                 if (q.indexOf("plan_") != -1 && numWorkers < workersMin && queue.plans[0])
     461             :                 {
     462           0 :                         queue.plans[0].number = 1;
     463           0 :                         if (queue.plans[1])
     464           0 :                                 queue.plans[1].number = 1;
     465             :                 }
     466             :         }
     467             : };
     468             : 
     469           0 : PETRA.QueueManager.prototype.canAfford = function(queue, cost)
     470             : {
     471           0 :         if (!this.accounts[queue])
     472           0 :                 return false;
     473           0 :         return this.accounts[queue].canAfford(cost);
     474             : };
     475             : 
     476           0 : PETRA.QueueManager.prototype.pauseQueue = function(queue, scrapAccounts)
     477             : {
     478           0 :         if (!this.queues[queue])
     479           0 :                 return;
     480           0 :         this.queues[queue].paused = true;
     481           0 :         if (scrapAccounts)
     482           0 :                 this.accounts[queue].reset();
     483             : };
     484             : 
     485           0 : PETRA.QueueManager.prototype.unpauseQueue = function(queue)
     486             : {
     487           0 :         if (this.queues[queue])
     488           0 :                 this.queues[queue].paused = false;
     489             : };
     490             : 
     491           0 : PETRA.QueueManager.prototype.pauseAll = function(scrapAccounts, but)
     492             : {
     493           0 :         for (let q in this.queues)
     494             :         {
     495           0 :                 if (q == but)
     496           0 :                         continue;
     497           0 :                 if (scrapAccounts)
     498           0 :                         this.accounts[q].reset();
     499           0 :                 this.queues[q].paused = true;
     500             :         }
     501             : };
     502             : 
     503           0 : PETRA.QueueManager.prototype.unpauseAll = function(but)
     504             : {
     505           0 :         for (let q in this.queues)
     506           0 :                 if (q != but)
     507           0 :                         this.queues[q].paused = false;
     508             : };
     509             : 
     510             : 
     511           0 : PETRA.QueueManager.prototype.addQueue = function(queueName, priority)
     512             : {
     513           0 :         if (this.queues[queueName] !== undefined)
     514           0 :                 return;
     515             : 
     516           0 :         this.queues[queueName] = new PETRA.Queue();
     517           0 :         this.priorities[queueName] = priority;
     518           0 :         this.accounts[queueName] = new API3.Resources();
     519             : 
     520           0 :         this.queueArrays = [];
     521           0 :         for (let q in this.queues)
     522           0 :                 this.queueArrays.push([q, this.queues[q]]);
     523           0 :         let priorities = this.priorities;
     524           0 :         this.queueArrays.sort((a, b) => priorities[b[0]] - priorities[a[0]]);
     525             : };
     526             : 
     527           0 : PETRA.QueueManager.prototype.removeQueue = function(queueName)
     528             : {
     529           0 :         if (this.queues[queueName] === undefined)
     530           0 :                 return;
     531             : 
     532           0 :         delete this.queues[queueName];
     533           0 :         delete this.priorities[queueName];
     534           0 :         delete this.accounts[queueName];
     535             : 
     536           0 :         this.queueArrays = [];
     537           0 :         for (let q in this.queues)
     538           0 :                 this.queueArrays.push([q, this.queues[q]]);
     539           0 :         let priorities = this.priorities;
     540           0 :         this.queueArrays.sort((a, b) => priorities[b[0]] - priorities[a[0]]);
     541             : };
     542             : 
     543           0 : PETRA.QueueManager.prototype.getPriority = function(queueName)
     544             : {
     545           0 :         return this.priorities[queueName];
     546             : };
     547             : 
     548           0 : PETRA.QueueManager.prototype.changePriority = function(queueName, newPriority)
     549             : {
     550           0 :         if (this.Config.debug > 1)
     551           0 :                 API3.warn(">>> Priority of queue " + queueName + " changed from " + this.priorities[queueName] + " to " + newPriority);
     552           0 :         if (this.queues[queueName] !== undefined)
     553           0 :                 this.priorities[queueName] = newPriority;
     554           0 :         let priorities = this.priorities;
     555           0 :         this.queueArrays.sort((a, b) => priorities[b[0]] - priorities[a[0]]);
     556             : };
     557             : 
     558           0 : PETRA.QueueManager.prototype.Serialize = function()
     559             : {
     560           0 :         let accounts = {};
     561           0 :         let queues = {};
     562           0 :         for (let q in this.queues)
     563             :         {
     564           0 :                 queues[q] = this.queues[q].Serialize();
     565           0 :                 accounts[q] = this.accounts[q].Serialize();
     566           0 :                 if (this.Config.debug == -100)
     567           0 :                         API3.warn("queueManager serialization: queue " + q + " >>> " +
     568             :                                 uneval(queues[q]) + " with accounts " + uneval(accounts[q]));
     569             :         }
     570             : 
     571           0 :         return {
     572             :                 "priorities": this.priorities,
     573             :                 "queues": queues,
     574             :                 "accounts": accounts
     575             :         };
     576             : };
     577             : 
     578           0 : PETRA.QueueManager.prototype.Deserialize = function(gameState, data)
     579             : {
     580           0 :         this.priorities = data.priorities;
     581           0 :         this.queues = {};
     582           0 :         this.accounts = {};
     583             : 
     584             :         // the sorting is updated on priority change.
     585           0 :         this.queueArrays = [];
     586           0 :         for (let q in data.queues)
     587             :         {
     588           0 :                 this.queues[q] = new PETRA.Queue();
     589           0 :                 this.queues[q].Deserialize(gameState, data.queues[q]);
     590           0 :                 this.accounts[q] = new API3.Resources();
     591           0 :                 this.accounts[q].Deserialize(data.accounts[q]);
     592           0 :                 this.queueArrays.push([q, this.queues[q]]);
     593             :         }
     594           0 :         this.queueArrays.sort((a, b) => data.priorities[b[0]] - data.priorities[a[0]]);
     595             : };

Generated by: LCOV version 1.14