Short Question
What does calling SetCurrentFactoryForQueueDisplay() do beside return the build queue of the factory passed as a parameter? What does ClearCurrentFactoryForQueueDisplay() do? Is there a better way to do a simple check for the existence of a factory queue in the background other than the former?
Background
I'm working on a UI mod to extend control groups inheritance from factories (it's actually mostly complete, aside from this issue). Adding a control group while a unit is under construction updates the control group on that unit. A factory assisting another factory will inherit the source factories control group and apply it to the unit under construction.
Problem
Trying to chase down a bug in a UI mod where:
A factory (FacA) is assisting another factory (FacB), which in turn is assisting another factory (FacC).
The build queue's of FacA and FacC are empty (so only FacB, the middle factory in the assist chain, is building units).
Unusual behavior: When FacB is given an order to build more than one unit, FacA (the assisting factory) will begin construction before FacB, and the total number of units built will be roughly twice the number of units added to the queue (pseudo double dip situation). Additionally, if FacB is constructing a single unit (so one unit added to the queue originally) and another unit is added to the queue, FacB will restart construction on its own unit after FacA (the assisting factory) begins construction. This only happens when FacB is assisting the (idle) FacC.
Suffice to say I don't really understand what's going on under the hood, but process of elimination suggests SetCurrentFactoryForQueueDisplay is somehow responsible. I'm using it in a very basic sense to check if a factory has a build queue, but experimentation suggests it has other effects on the UI when called. If anybody has any insight on those effects I would be very thankful to hear them.
Code/Hooks
selection.lua
local modpath = ('/mods/ControlGroupOverhaul')
local SmartPop = import(modpath .. '/modules/utilities.lua').SmartPop
local Dummy = import(modpath .. '/modules/utilities.lua').Dummy
local LogTable = import(modpath .. '/modules/LogTable.lua').LogTable
local Units = import('/mods/UMT/modules/units.lua')
--local Selection = import('/lua/ui/game/selection.lua')
--local Units = import('/mods/common/units.lua')
do
local unitId = nil
local factory = nil
local sets = {}
local assistedFactory = nil
local oldAddUnitToSelectionSet = AddUnitToSelectionSet
function AddUnitToSelectionSet(name, unit)
if unitId == nil or unit:GetEntityId() ~= unitId then
if unit:HasSelectionSet(Dummy()) then unit:RemoveSelectionSet(Dummy()) end
unitId = unit:GetEntityId()
LOG('AddUnitToSelectionSet: New unit ID : ' .. unitId)
factory = unit:GetCreator()
LOG('AddUnitToSelectionSet: Factory focus : ' .. tostring(factory:GetFocus():GetEntityId()))
sets = factory:GetSelectionSets()
assistedFactory = FindFacTargetRecursive(factory)
if sets == {Dummy()} and assistedFactory ~= nil then
return
elseif assistedFactory ~= nil and not GetFactoryQueue(factory) then
sets = assistedFactory:GetSelectionSets()
end
for _, name in sets do
if name ~= Dummy() then
LOG('AddUnitToSelectionSet/name: '..name)
oldAddUnitToSelectionSet(name, unit)
end
end
end
LOG('AddUnitToSelectionSet/End')
end
local oldAddSelectionSet = AddSelectionSet
function AddSelectionSet(name, unitArray)
LOG('AddSelectionSet/name: '..name)
local aOutgoingFactories = EntityCategoryFilterDown(categories.FACTORY, ProcessSelectionSet(name)) or {}
local aIncomingFactories = EntityCategoryFilterDown(categories.FACTORY, unitArray) or {}
--remove dummy group in advance of oldAddSelectionSet so we don't jack up selectionSets[other]
if next(aIncomingFactories) then
for _, factory in aIncomingFactories do
if factory:HasSelectionSet(Dummy()) then
factory:RemoveSelectionSet(Dummy())
end
end
end
--call oldAddSelectionSet as usual
LOG('AddSelectionSet/oldAddSelectionSet')
oldAddSelectionSet(name, unitArray)
--add dummy selection set to outgoing factories
LOG('AddSelectionSet/aOutgoingFactories')
if next(aOutgoingFactories) then
for _, factory in aOutgoingFactories do
if not next(factory:GetSelectionSets()) then
factory:AddSelectionSet(Dummy())
end
end
end
--add selection set to unit under construction
--then find relevant assisting factories and add selection set to those units under construction
LOG('AddSelectionSet/aIncomingFactories')
if next(aIncomingFactories) then
for _, factory in aIncomingFactories do
if factory:GetFocus() ~= nil and not next(factory:GetFocus():GetSelectionSets()) then
if GetFactoryQueue(factory) then
oldAddUnitToSelectionSet(name, factory:GetFocus())
end
end
if factory.AssistingFactories ~= nil and next(factory.AssistingFactories) then
LOG('AddSelectionSet/ Factory is assisted (potentially)')
for assistingFactory in factory.AssistingFactories do
if assistingFactory.RecursiveGuardedEntity == factory and assistingFactory:GetFocus() then
LOG(' assistingFactory.GetEntityId: '..assistingFactory:GetEntityId())
LOG(' assistingFactory.GetFocus:GetEntityId: '..assistingFactory:GetFocus():GetEntityId())
LOG(' assistingFactory.RecursiveGuardedEntity:GetEntityId: '..assistingFactory.RecursiveGuardedEntity:GetEntityId())
oldAddUnitToSelectionSet(name, assistingFactory:GetFocus())
end
end
else
LOG('AddSelectionSet/ No assisting factories')
end
end
end
LOG('AddSelectionSet/End')
end
end
function FindFacTargetRecursive(factory)
LOG('FindFacTargetRecursive')
local recursiveFac = factory
while recursiveFac:GetGuardedEntity() and not GetFactoryQueue(recursiveFac) do
recursiveFac = recursiveFac:GetGuardedEntity()
end
if recursiveFac:GetEntityId() ~= factory:GetEntityId() then
recursiveFac.AssistingFactories = recursiveFac.AssistingFactories or {}
recursiveFac.AssistingFactories[factory] = true
if GetFactoryQueue(recursiveFac) then LogTable(GetFactoryQueue(recursiveFac)) end
else
recursiveFac = nil
end
factory.RecursiveGuardedEntity = recursiveFac
LOG('FindFacTargetRecursive/End')
return recursiveFac
end
function GetFactoryQueue(factory)
local queue = SetCurrentFactoryForQueueDisplay(factory) or nil
local selectedFactories = EntityCategoryFilterDown(categories.FACTORY, GetSelectedUnits())
LOG('Num of selected factories: '..tostring(TableLength(selectedFactories)))
if TableLength(selectedFactories) == 1 then
SetCurrentFactoryForQueueDisplay(selectedFactories[1])
else
ClearCurrentFactoryForQueueDisplay()
end
return queue
end
function TableLength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
commandmode.lua
local modpath = ('/mods/ControlGroupOverhaul')
local Dummy = import(modpath .. '/modules/utilities.lua').Dummy
oldOnGuard = OnGuard
function OnGuard(guardees, unit)
if EntityCategoryContains(categories.FACTORY, unit) then
local guardingFactories = EntityCategoryFilterDown(categories.FACTORY, guardees)
for _, factory in guardingFactories do
if not next(factory:GetSelectionSets()) then
factory:AddSelectionSet(Dummy())
end
end
end
oldOnGuard(guardees, unit)
end