mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Prioritize least busy buildings and enforce max training queue limit
Use reusable helpers for training metadata extraction, queue time calculation and sorting. Introduced: getTotalQueueTime(queue) getBuildingTrainingMetadata(entities) sortBuildingsByQueueTime(buildings) getBuildingsSortedByQueueTime(entities)
This commit is contained in:
parent
32e5520507
commit
89359ce6d1
1 changed files with 54 additions and 17 deletions
|
|
@ -1617,17 +1617,17 @@ function addTrainingByPosition(position)
|
|||
}
|
||||
|
||||
// Called by GUI when user clicks training button
|
||||
function addTrainingToQueue(selection, trainEntType, playerState)
|
||||
function addTrainingToQueue(unitIds, trainEntType, playerState)
|
||||
{
|
||||
const appropriateBuildings = getBuildingsWhichCanTrainEntity(selection, trainEntType);
|
||||
|
||||
const canBeAddedCount = getEntityLimitAndCount(playerState, trainEntType).canBeAddedCount;
|
||||
|
||||
const decrement = Engine.HotkeyIsPressed("selection.remove");
|
||||
let template;
|
||||
if (!decrement)
|
||||
template = GetTemplateData(trainEntType);
|
||||
|
||||
// Sort the buildings by their current queue length (time-based) before training
|
||||
const sortedBuildingsMetadata = getBuildingsSortedByQueueTime(unitIds);
|
||||
const sortedBuildings = sortedBuildingsMetadata.map(building => building.entity);
|
||||
// Batch training only possible if we can train at least 2 units.
|
||||
if (Engine.HotkeyIsPressed("session.batchtrain") && (canBeAddedCount == undefined || canBeAddedCount > 1))
|
||||
{
|
||||
|
|
@ -1638,8 +1638,8 @@ function addTrainingToQueue(selection, trainEntType, playerState)
|
|||
// If the order changed, we have a new selection and we should create a new batch.
|
||||
// If we're already creating a batch of this unit (in the same structure(s)), then just extend it
|
||||
// (if training limits allow).
|
||||
if (g_BatchTrainingEntities.length == selection.length &&
|
||||
g_BatchTrainingEntities.every((ent, i) => ent == selection[i]) &&
|
||||
if (g_BatchTrainingEntities.length == sortedBuildings.length &&
|
||||
g_BatchTrainingEntities.every((ent, i) => ent == sortedBuildings[i]) &&
|
||||
g_BatchTrainingType == trainEntType)
|
||||
{
|
||||
if (decrement)
|
||||
|
|
@ -1649,7 +1649,7 @@ function addTrainingToQueue(selection, trainEntType, playerState)
|
|||
inputState = INPUT_NORMAL;
|
||||
}
|
||||
else if (canBeAddedCount == undefined ||
|
||||
canBeAddedCount > g_NumberOfBatches * getBatchTrainingSize() * appropriateBuildings.length)
|
||||
canBeAddedCount > g_NumberOfBatches * getBatchTrainingSize() * sortedBuildings.length)
|
||||
{
|
||||
if (Engine.GuiInterfaceCall("GetNeededResources", {
|
||||
"cost": multiplyEntityCosts(template, (g_NumberOfBatches + 1) * getBatchTrainingSize())
|
||||
|
|
@ -1671,16 +1671,14 @@ function addTrainingToQueue(selection, trainEntType, playerState)
|
|||
return;
|
||||
|
||||
inputState = INPUT_BATCHTRAINING;
|
||||
g_BatchTrainingEntities = selection;
|
||||
g_BatchTrainingEntities = sortedBuildings;
|
||||
g_BatchTrainingType = trainEntType;
|
||||
g_BatchTrainingEntityAllowedCount = canBeAddedCount;
|
||||
g_NumberOfBatches = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
let buildingsForTraining = appropriateBuildings;
|
||||
if (canBeAddedCount !== undefined)
|
||||
buildingsForTraining = buildingsForTraining.slice(0, canBeAddedCount);
|
||||
const buildingsForTraining = sortedBuildings.slice(0, canBeAddedCount || sortedBuildings.length);
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "train",
|
||||
"template": trainEntType,
|
||||
|
|
@ -1733,40 +1731,79 @@ function getTrainingStatus(selection, trainEntType, playerState)
|
|||
function flushTrainingBatch()
|
||||
{
|
||||
const batchedSize = g_NumberOfBatches * getBatchTrainingSize();
|
||||
|
||||
// Get the buildings that can train the current batch type
|
||||
const appropriateBuildings = getBuildingsWhichCanTrainEntity(g_BatchTrainingEntities, g_BatchTrainingType);
|
||||
// If training limits don't allow us to train batchedSize in each appropriate structure.
|
||||
|
||||
// Sort buildings by queue length
|
||||
const sortedBuildingsMetadata = getBuildingsSortedByQueueTime(appropriateBuildings);
|
||||
const sortedBuildings = sortedBuildingsMetadata.map(building => building.entity);
|
||||
|
||||
// If training limits don't allow us to train batchedSize in each appropriate structure
|
||||
if (g_BatchTrainingEntityAllowedCount !== undefined &&
|
||||
g_BatchTrainingEntityAllowedCount < batchedSize * appropriateBuildings.length)
|
||||
{
|
||||
// Train as many full batches as we can.
|
||||
// Train as many full batches as we can
|
||||
const buildingsCountToTrainFullBatch = Math.floor(g_BatchTrainingEntityAllowedCount / batchedSize);
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "train",
|
||||
"entities": appropriateBuildings.slice(0, buildingsCountToTrainFullBatch),
|
||||
"entities": sortedBuildings.slice(0, buildingsCountToTrainFullBatch),
|
||||
"template": g_BatchTrainingType,
|
||||
"count": batchedSize,
|
||||
"pushFront": Engine.HotkeyIsPressed("session.pushorderfront")
|
||||
});
|
||||
|
||||
// Train remainer in one more structure.
|
||||
// Train remainder in one more structure
|
||||
const remainer = g_BatchTrainingEntityAllowedCount % batchedSize;
|
||||
if (remainer)
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "train",
|
||||
"entities": [appropriateBuildings[buildingsCountToTrainFullBatch]],
|
||||
"entities": [sortedBuildings[buildingsCountToTrainFullBatch]],
|
||||
"template": g_BatchTrainingType,
|
||||
"count": remainer,
|
||||
"pushFront": Engine.HotkeyIsPressed("session.pushorderfront")
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Train full batch in all selected buildings
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "train",
|
||||
"entities": appropriateBuildings,
|
||||
"entities": sortedBuildings,
|
||||
"template": g_BatchTrainingType,
|
||||
"count": batchedSize,
|
||||
"pushFront": Engine.HotkeyIsPressed("session.pushorderfront")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getTotalQueueTime(queue)
|
||||
{
|
||||
return queue.reduce((sum, item) => sum + (item.timeRemaining ?? item.timeTotal ?? 0), 0);
|
||||
}
|
||||
|
||||
function getBuildingTrainingMetadata(entities)
|
||||
{
|
||||
return entities.map(entity =>
|
||||
{
|
||||
const queue = GetEntityState(entity)?.production?.queue || [];
|
||||
|
||||
return {
|
||||
"entity": entity,
|
||||
"queueLength": queue.length,
|
||||
"totalQueueTime": getTotalQueueTime(queue)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function sortBuildingsByQueueTime(buildings)
|
||||
{
|
||||
return buildings.sort((a, b) => a.totalQueueTime - b.totalQueueTime);
|
||||
}
|
||||
|
||||
function getBuildingsSortedByQueueTime(entities)
|
||||
{
|
||||
return sortBuildingsByQueueTime(getBuildingTrainingMetadata(entities));
|
||||
}
|
||||
|
||||
function performGroup(action, groupId)
|
||||
|
|
|
|||
Loading…
Reference in a new issue