FAForever Forums
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Login

    Question on SetCurrentFactoryForQueueDisplay engine method

    Scheduled Pinned Locked Moved Modding & Tools
    6 Posts 3 Posters 367 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C
      clyf
      last edited by

      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
      
      1 Reply Last reply Reply Quote 0
      • Ctrl-KC
        Ctrl-K
        last edited by

        I'd suggest to move into discord server and discuss it there. Take a modder role and go to #modding-general

        “Be a yardstick of quality. Some people aren’t used to an environment where excellence is expected.”
        — Steve Jobs.
        My UI Mods
        Support me

        1 Reply Last reply Reply Quote 0
        • C
          clyf
          last edited by

          Having asked a number of questions in that channel I felt this one was more suited to a forum post.

          1 Reply Last reply Reply Quote 0
          • C
            clyf
            last edited by clyf

            Update: Testing with no mods and this appears to be an engine bug. A set of factories (in which one is assisting a factory which is assisting another factory outside the set) will produce some factor of the original number of units in the build queue.

            Update 2.0: The factory with the build queue, assisting another idle factory, doesn't subtract from its own build queue (except for the last unit it builds). Appears it gets confused about where it's getting the unit from.

            S 1 Reply Last reply Reply Quote 0
            • S
              Sprouto @clyf
              last edited by

              @slicknixon We are also aware of a rare issue that can cause a complete lock-up when factory assists form a complete circle - A >> B >>> C >> A

              1 Reply Last reply Reply Quote 0
              • C
                clyf
                last edited by

                I investigated that in the course of the above and found that it automatically broke the chain when the circle was completed (might not apply in all cases).

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post