Results 1 to 2 of 2

Thread: [Buggy] Applying and Removing modifiers on the same frame

  1. #1
    Basic Member
    Join Date
    Jun 2012
    Posts
    184

    [Buggy] Applying and Removing modifiers on the same frame

    For a while now, people have been encountering issues when trying to add and remove modifiers on the same frame. Here's some Invoker code I wrote that removes his current Quas/Wex/Exort modifier instances and reapplies them, ensuring that the modifiers display in the correct order on his modifier bar:

    Code:
    --[[ ============================================================================================================
    	Author: Rook
    	Date: February 15, 2015
    	Called when Quas, Wex, or Exort is cast or upgraded.  Replaces the modifiers on the caster's modifier bar to
    	ensure the correct order, which also has the effect of leveling the effects of any currently existing orbs.
    ================================================================================================================= ]]
    function invoker_retro_orb_replace_modifiers(keys)
    	if keys.caster.invoked_orbs == nil then
    		keys.caster.invoked_orbs = {}
    	end
    
    	--Reapply all the orbs Invoker has out in order to benefit from the upgraded ability's level.  By reapplying all
    	--three orb modifiers, they will maintain their order on the modifier bar (so long as all are removed before any
    	--are reapplied, since ordering problems arise there are two of the same type of orb otherwise).
    	while keys.caster:HasModifier("modifier_invoker_retro_quas_instance") do
    		keys.caster:RemoveModifierByName("modifier_invoker_retro_quas_instance")
    	end
    	while keys.caster:HasModifier("modifier_invoker_retro_wex_instance") do
    		keys.caster:RemoveModifierByName("modifier_invoker_retro_wex_instance")
    	end
    	while keys.caster:HasModifier("modifier_invoker_retro_exort_instance") do
    		keys.caster:RemoveModifierByName("modifier_invoker_retro_exort_instance")
    	end
    
    	for i=1, 3, 1 do
    		if keys.caster.invoked_orbs[i] ~= nil then
    			local orb_name = keys.caster.invoked_orbs[i]:GetName()
    			if orb_name == "invoker_retro_quas" then
    				local quas_ability = keys.caster:FindAbilityByName("invoker_retro_quas")
    				if quas_ability ~= nil then
    					quas_ability:ApplyDataDrivenModifier(keys.caster, keys.caster, "modifier_invoker_retro_quas_instance", nil)
    					print(i .. " = quas")
    				end
    			elseif orb_name == "invoker_retro_wex" then
    				local wex_ability = keys.caster:FindAbilityByName("invoker_retro_wex")
    				if wex_ability ~= nil then
    					wex_ability:ApplyDataDrivenModifier(keys.caster, keys.caster, "modifier_invoker_retro_wex_instance", nil)
    					print(i .. " = wex")
    				end
    			elseif orb_name == "invoker_retro_exort" then
    				local exort_ability = keys.caster:FindAbilityByName("invoker_retro_exort")
    				if exort_ability ~= nil then
    					exort_ability:ApplyDataDrivenModifier(keys.caster, keys.caster, "modifier_invoker_retro_exort_instance", nil)
    					print(i .. " = exort")
    				end
    			end
    		end
    	end
    	print("")
    end
    The print statements were used to verify that the order of the orbs were being stored correctly internally; they are. However, it is possible to enter a buggy state from this code where the order of the modifiers on the modifier bar is incorrect, and the order remains unusual and buggy thereafter. The only way I was able to reproduce this was by mashing Q, W, and E (doing so while under the effects of a cyclone like Eul's helped), and it became more likely to enter this state as the game went on, to the point where it could somewhat reliably be entered by the time the creeps spawned at 0:00.

    Eventually determining that this strange problem might be a result of adding and removing modifiers on the same frame, I added wait times in between each modifier like so:

    Code:
    --[[ ============================================================================================================
    	Author: Rook
    	Date: February 15, 2015
    	Called when Quas, Wex, or Exort is cast or upgraded.  Replaces the modifiers on the caster's modifier bar to
    	ensure the correct order, which also has the effect of leveling the effects of any currently existing orbs.
    ================================================================================================================= ]]
    function invoker_retro_orb_replace_modifiers(keys)
    	if keys.caster.invoked_orbs == nil then
    		keys.caster.invoked_orbs = {}
    	end
    
    	--Reapply all the orbs Invoker has out in order to benefit from the upgraded ability's level.  By reapplying all
    	--three orb modifiers, they will maintain their order on the modifier bar (so long as all are removed before any
    	--are reapplied, since ordering problems arise there are two of the same type of orb otherwise).
    	while keys.caster:HasModifier("modifier_invoker_retro_quas_instance") do
    		keys.caster:RemoveModifierByName("modifier_invoker_retro_quas_instance")
    	end
    	while keys.caster:HasModifier("modifier_invoker_retro_wex_instance") do
    		keys.caster:RemoveModifierByName("modifier_invoker_retro_wex_instance")
    	end
    	while keys.caster:HasModifier("modifier_invoker_retro_exort_instance") do
    		keys.caster:RemoveModifierByName("modifier_invoker_retro_exort_instance")
    	end
    
    	for i=1, 3, 1 do
    		if keys.caster.invoked_orbs[i] ~= nil then
    			local orb_name = keys.caster.invoked_orbs[i]:GetName()
    			if orb_name == "invoker_retro_quas" then
    				local quas_ability = keys.caster:FindAbilityByName("invoker_retro_quas")
    				if quas_ability ~= nil then
    					Timers:CreateTimer({
    						endTime = .03 * i,
    						callback = function()
    							quas_ability:ApplyDataDrivenModifier(keys.caster, keys.caster, "modifier_invoker_retro_quas_instance", nil)
    							print(i .. " = quas")
    						end
    					})
    				end
    			elseif orb_name == "invoker_retro_wex" then
    				local wex_ability = keys.caster:FindAbilityByName("invoker_retro_wex")
    				if wex_ability ~= nil then
    					Timers:CreateTimer({
    						endTime = .03 * i,
    						callback = function()
    							wex_ability:ApplyDataDrivenModifier(keys.caster, keys.caster, "modifier_invoker_retro_wex_instance", nil)
    							print(i .. " = wex")
    						end
    					})
    				end
    			elseif orb_name == "invoker_retro_exort" then
    				local exort_ability = keys.caster:FindAbilityByName("invoker_retro_exort")
    				if exort_ability ~= nil then
    					Timers:CreateTimer({
    						endTime = .03 * i,
    						callback = function()
    							exort_ability:ApplyDataDrivenModifier(keys.caster, keys.caster, "modifier_invoker_retro_exort_instance", nil)
    							print(i .. " = exort")
    						end
    					})
    				end
    			end
    		end
    	end
    	print("")
    end
    This appears to have fixed the bug. My question to you is whether a large amount of entities in the game (on the order of the first creepwave), or removing and reapplying modifiers in the same frame, could cause ApplyDataDrivenModifier() to be pushed to the next frame or finish in a non-sequential order. This seems like a very backend bug, and was a rather obnoxious one to track down, so I wanted to post it here and see if anyone had experience with something similar or knew enough about the backend to conjecture more specifically about what was happening.

  2. #2
    Basic Member Noya's Avatar
    Join Date
    Dec 2011
    Location
    Uruguay
    Posts
    12,904
    Confirm and added

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •