[Addon] NukeDemoter

Language: JP EN DE FR
users online
Forum » Windower » Support » [Addon] NukeDemoter
[Addon] NukeDemoter
Offline
Posts: 148
By RolandJ 2022-06-11 13:25:16
Link | Quote | Reply
 
This thread was originally for getting assistance with the spell-swapping aspect of my code. GearSwap was complicating my addon by injecting the action before my addon ran. However Zarianna, Lili, and Masunasu helped me overcome that and now that is resolved.

If you're here you probably came for the addon, so I'm putting the link at the top here.

You can find the addon in its initial release below! :)
https://github.com/Roland-J/Windower-Addons/tree/main/NukeDemoter


P.S. As I'd imagine you're thinking, the act of demoting nukes is nothing new - I've seen it in various job luas and GS libs - but I haven't found a standalone addon that does it yet. That's why I created this. It's something that all my jobs can use and it can therefore simplify my job luas by centralizing this out of them.

And here is my original post...

RolandJ said: »
I am trying to write an addon to block certain actions of the current player. Eventually it would auto-demote nukes based on recasts, but reliably blocking the original action is the point I am stuck on right now.

This is the code I am using. It is in a conceptual state and is currently just blocking a random spell: Stone IV.
Code
local packets = require('packets')
local res = require('resources')

windower.register_event('outgoing chunk', function(id, data, modified, injected, blocked)
	if id == 0x01A then -- Action Packets (See Windower/addons/libs/packets/data.lua)
		local parsed = packets.parse('outgoing', data)
		if parsed.Category == 3 then --"Magic cast" category
			local spell_english = res.spells[parsed.Param].en
			if spell_english == "Stone IV" then -- a dummy spell to block during initial testing
				windower.add_to_chat(8, 'Trying to stop ' .. spell_english .. '... (injected: ' .. tostring(injected) .. ')')
				return true --prevents the action (fails to do so, with injected printing out as true, if GearSwap is loaded alongside this addon)
			end
		end
	end
end)


What I'm noticing is that the return true on line 11 works - it blocks Stone IV from ever beginning to cast - if GearSwap is not loaded but it stops working - Stone IV can begin casting - if GearSwap is loaded alongside my addon.

I'm trying to keep this as an addon, external to/independent of GearSwap, to A) avoid dependencies and B) make the feature as simple as possible to install. I'd still like it to continue to work when GearSwap is loaded, though.

Any idea how to make this addon successfully block the action even when GearSwap is also loaded? Thanks!

P.S. If absolutely necessary due to limitations, I'd be open to making this internal to GearSwap. In such a case I'd like to do so while A) keeping it as centralized as possible, B) modifying as few existing libraries as possible in order to maximize compatibility, and C) keeping it as simple and user-friendly to install/use as possible. I'd much rather keep this external though, if doing so is actually possible while maintaining compatibility.
Offline
Posts: 12
By Zarianna 2022-06-11 13:44:13
Link | Quote | Reply
 
Pretty sure I have a GEO lua that already has a degrade Array like how you are trying to do.

https://pastebin.com/zHDMWqjd

feel free to pick out the degrade code.
[+]
Offline
Posts: 148
By RolandJ 2022-06-11 13:47:26
Link | Quote | Reply
 
Thanks! Good to know, I will keep that in mind, and thank you for providing your GEO GearSwap lua!

I am trying my best to keep this as its own unique addon, though, to avoid dependencies. Which would mean that it'd be external from any libraries or JOB.luas used in GearSwap. That is actually the core reason that I started writing my own addon, actually.
[+]
Offline
Posts: 148
By RolandJ 2022-06-11 16:09:32
Link | Quote | Reply
 
Thank you for the explanation on GearSwap's internal processes Lili. I had a feeling it was altering the client's actions somehow, though I could not find where it would force the packet to be injected before my register_event runs.

I'm hoping there's some way to make this work consistently. I could not get it to work by loading either before the other ingame, though perhaps load order is dictated in some way other than what I was attempting.

I'll leave this up for a while and if no breakthroughs come I'll end up doing a GearSwap solution like you mentioned. Thanks!
Offline
Posts: 148
By RolandJ 2022-06-11 21:10:50
Link | Quote | Reply
 
If someone comes up with a way of having this as a standalone addon, please share and I'll give you lots of credit. :)

Otherwise, here's my plan. Please advise if you have a better method or some tips for improvement.



Please keep in mind that I'm trying to keep this as simple as possible for a better end-user experience via near-effortless installation and use.

INSTALLATION STEPS
1. The user adds my NukeDemoter.lua to their GearSwap\libs\ folder.
2. The user adds this code to the bottom of Mote-Include.lua. (No making them find an obscure entry point! Just plop it at the bottom!)
Code
-------------------------------------------------------------------------------------------------------------------
-- RolandJ's Nuke Demoter Feature
-------------------------------------------------------------------------------------------------------------------
include('NukeDemoter')


Simple! Even someone who is intimidated simply by having to go into the library could do that, as they don't have to read any code to plop it into the bottom.

This would be the form of the contents of NukeDemoter.lua. A self-sufficient include that's easy to add. It utilizes a function override - which I haven't personally seen yet in the Windower modding scene, though I wouldn't be surprised if they're in various places - and so it might appear unorthodox. However, I did that to prevent overwriting any pre-existing filter_pretarget functions added to anyone's Mote-Include; I don't want to make something that is prone to interfering, after all. I promise that function overrides work and are used in LUA modding for other games. :)
Code
-- Local Variables for NukeDemoter
local demote = true

-- Intercept Applicable Spells in Pretarget
local filter_pretarget_old = filter_pretarget
function filter_pretarget(spell, spellMap, eventArgs, ...)
	-- Intercept if applicable
	if demote and spell.english == 'Cure II' then --dummy var to easily witness interception, full feature would check recast and if it was in a map
		cancel_spell() --NOTE: eventArgs.cancel is only used in [user/job]_filter functions
		local new_spell = 'Cure' --dummy var, full feature would reference a map and process recasts to determine this value
		send_command('input /ma ' .. new_spell .. ' ' .. tostring(spell.target.raw))
		return windower.add_to_chat(8,'NukeDemoter\'s filter_pretarget demoted ' .. spell.english .. ' to ' ..new_spell)
	else
		-- We aren't intercepting, so call the normal filter_pretarget if it exists
		if filter_pretarget_old ~= nil then
			return filter_pretarget_old(spell, spellMap, eventArgs, ...)
		end
	end
end

-- Command Handler for NukeDemoter
windower.raw_register_event('unhandled command', function(cmd, ...) --Credit: Lili for recommending raw version for use inside GearSwap
	-- Return out for non-NukeDemoter commands
	if cmd ~= 'nukedemoter' then return end
	
    local args = T{...}
	if args[1]:lower() == 'toggle' then
		demote = not demote
		windower.add_to_chat(8, 'NukeDemoter ' .. (demote and 'activated' or 'deactivated') .. '...')
	end
end)
Offline
Posts: 148
By RolandJ 2022-06-11 22:01:21
Link | Quote | Reply
 
Thank you for the tip Lili! That's good to know about raw_register_event. I've incorporated your suggestion to my last post.
Offline
Posts: 92
By Masunasu 2022-06-11 22:59:11
Link | Quote | Reply
 
This can be done as a standalone addon with Gearswap still active.

Since the goal is simply to degrade spells rather than cancel, perform that logic directly in your block, modify the param field as necessary and return the new packet. Example using what you have and upgrading Stone to Stone II:
Code
local packets = require('packets')
local res = require('resources')
 
windower.register_event('outgoing chunk', function(id, data, modified, injected, blocked)
    if id == 0x01A then -- Action Packets (See Windower/addons/libs/packets/data.lua)
        local parsed = packets.parse('outgoing', data)
        if parsed.Category == 3 then --"Magic cast" category
            local spell_english = res.spells[parsed.Param].en
            if spell_english == "Stone" then -- a dummy spell to block during initial testing
                windower.add_to_chat(8, 'Trying to stop ' .. spell_english .. '... (injected: ' .. tostring(injected) .. ')')
				--160 is Stone II, lazy
				parsed.Param = 160
                return packets.build(parsed) --Replaces original spell with new spell
            end
        end
    end
end)


A caveat is that Gearswap will process your rules based on the original spell not the modified spell. So doing something like swapping Silence for Stone will have you casting a nuke in your enfeebling set. This could pertain to spell-specific sets as well, like swapping Paralyna for Cursna would have you missing your Cursna+ gear even though they're both healing.
[+]
Offline
Posts: 148
By RolandJ 2022-06-12 07:30:54
Link | Quote | Reply
 
That is working during my testing, thank you very much! I had a feeling there would be a way to do this, code tends to be flexible. I wouldn't have thought that modifying an already-injected packet would work, nor did I know how to, so I'm glad you shared this!

Switching between spell kinds shouldn't occur in this addon, as I'm wanting to make a very generic (all-jobs) addon that only demotes spells within their own kind.
Ex: Stone 5 > Stone 4 > Stone 3 > etc

This may run into slight issues for people who have tier-dependent sets (who does that?), but as I said I'd think that would only make a very slight impact indeed. I would not think that casting T1/2/3/4/5 in your standard (T6) set would have any noticeable impact.

You can find the addon in its initial release below! :)
https://github.com/Roland-J/Windower-Addons/tree/main/NukeDemoter
Log in to post.