Thread Tools Display Modes
06/17/23, 07:17 AM   #1
Anumaril
 
Anumaril's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2018
Posts: 14
Scoping key for wayshrines

I'm trying to make a simple mod that disables wayshrine travel by making it impossible to interact with wayshrines. I posted about it on the ESO forums some time ago, and a mod creator linked me to their mod and recommended I look at their code since they do something similar with objects like benches, companions, etc.

I've been trying to reverse-engineer it this morning but haven't had much luck. I think part of the problem is I just don't know the way to get the code to "target" wayshrines. The mod "LongPressCtrlToInteract" seems to use the key "LPCI_SEATS" to target seats in the game, but that looks like it's the mod initials so it surely can't be directly from the game's documentation. I've also had a look at the most recent ESO documentation but can't find anything related to seats or wayshrines.

Here's the code I'm working with at the moment, which was reverse-engineered from the other mod's code:

Code:
FISHING_MANAGER.StartInteraction = function(...)
    local text = ...

    if text == GetString(NFT_SEAT) then
        return true
    end

    return orgInteract(...)
end
I tried with the original mod's key "LPCI_SEAT", but that didn't work, so I just changed it to be based on my own mod's name instead since that's likely what LPCI was referring to anyways.
  Reply With Quote
06/17/23, 07:24 AM   #2
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,989
FISHING_MANAGER does not exist any longer since NECROM.
It was replaced by: INTERACTIVE_WHEEL_MANAGER

And instead of using that directly you shoud meanwhile use the library https://www.esoui.com/downloads/info...onFilters.html to filter/react on interactions.

If this does not support wayshrines yet it maybe can be added there or you check for the "action" string (should be something like "teleport" hopefully to detect it).


LPCI_SEATS is by chance a translated language string constant for the game API function GetString(LPCI_SEATS).
Here is an explanation:
https://wiki.esoui.com/How_to_add_localization_support

Somewhere in the language tarnslations files, de.lua, en.lua, etc. of the addon LongPressToInteract (folder "lang") you will fond those defined and pointing to the action string like "Sit down" or "Hinsetzen" (German) then.
As actions are strings and thus translation is needed your addon needs to have the strings for "Use wayshrine" in all client languages.
You can get them by changing the client language ingame (does only change the strings at the UI, no audi or video!):

/script SetCVar("language.2", "en")

Replace "en" with other ISO codes for the supported client languages:

"de"
"es"
"en"
"fr"
"ru"
"zh"

And then move your crosshair above a wayshrine to see the text in that client language and note it down.


If all wents bad the wayshrines action string will be just "Use" (in any language at least) and you are not able to properly detect it or differ from other "Use" actions.
You will need to use the API function GetInteractionInfo() or similar to return more info about the interaction below your crosshair (ESO names that "reticle") to check for a wayshrine type returned or similar)!!!


local interactionType = GetInteractionType()
if interactionType == INTERACTION_WHATEVER A WAYSHRINE RETURNS AND IF THIS IS ONLY RETURNED FOR A WAYSHRINE then

I think there was one interaction type INTERACTION_FAST_TRAVEL

So check if the library linked above supports that already somehow.

Last edited by Baertram : 06/17/23 at 07:35 AM.
  Reply With Quote
06/17/23, 04:36 PM   #3
IsJustaGhost
AddOn Author - Click to view addons
Join Date: May 2020
Posts: 38
My lib would be extremely helpful here.
I'm almost ready to post the update to it.
It's current version has been completely rewritten.

Lua Code:
  1. local registerOnTryHandlingInteraction = LibInteractionHook.RegisterOnTryHandlingInteraction
  2. local hideInteraction = LibInteractionHook.HideInteraction
  3.  
  4. local wayshrineString = tolower(GetString(SI_DEATH_PROMPT_WAYSHRINE))
  5.  
  6. -- I'm not sure if the wayshrineString  will need to be lowered. On the save side, lower both.
  7.  
  8.  
  9. registerOnTryHandlingInteraction(self.name, SI_LIB_IF_GAMECAMERAACTION5, function(action, interactableName, currentFrameTimeSeconds)
  10.     if tolower(interactableName):match(wayshrineString) then
  11.         hideInteraction() -- Using this would hide the target interaction, but, is not needed to disable it.
  12.         return true -- if wanting it always disabled. Could use addon settings or timers to set this for a set time
  13.     end
  14. end)

I have an addon that uses this, the current version and have an update of it for when the lib is updated. It disables select interactions while the player is moving and for a set time from when they stop. All is set in addon settings.
Example:
"Talk" has a slider for cooldown until useable.
And, it dynamically generates actions, settings, and registerOnTryHandlingInteraction per action.
IsJusta Disable Actions While Moving

I'm also looking at making it add additional info to the parameters so that GetGameCameraInteractableActionInfo() is not called so many times from addons.

Last edited by IsJustaGhost : 06/17/23 at 05:18 PM.
  Reply With Quote
06/18/23, 01:15 AM   #4
IsJustaGhost
AddOn Author - Click to view addons
Join Date: May 2020
Posts: 38
I've posted the update to LibInteractionHook

I suggest registering for a specific action. Funny thing is, I can't recall what it is for a wayshrine. "Use" right?
Lua Code:
  1. local registerOnTryHandlingInteraction = LibInteractionHook.RegisterOnTryHandlingInteraction
  2. local wayshrineString = tolower(GetString(SI_DEATH_PROMPT_WAYSHRINE))
  3.  
  4. --Replace _action_ with GetString(SI_LIB_IF_GAMECAMERAACTION5) or SI_LIB_IF_GAMECAMERAACTION5 or "Use"
  5. -- All of the SI_LIB_IF_GAMECAMERAACTION can be found in the lib
  6.  
  7. registerOnTryHandlingInteraction(self.name, _action_ , function(action, interactableName, interactionBlocked, isOwned, additionalInteractInfo, context, contextLink, isCriminalInteract, currentFrameTimeSeconds)
  8.     -- There is no need to check for if interactionPossible, this will only run if it is.
  9.  
  10.     if interactableName:match(wayshrineString) then -- This is in theory
  11.         return true -- to disable it
  12.     end
  13. end)
  14.  
  15.  
  16. -- Omitting the action will register the function for any action.
  17. registerOnTryHandlingInteraction(self.name, function(action, interactableName, interactionBlocked, isOwned, additionalInteractInfo, context, contextLink, isCriminalInteract, currentFrameTimeSeconds)
  18.     -- There is no need to check for if interactionPossible, this will only run if it is.
  19.  
  20.     if interactableName:match(wayshrineString) then -- This is in theory
  21.         return true -- to disable it
  22.     end
  23. end)
Unregistering can be done using the same info used in registering.
Lua Code:
  1. local unregisterOnTryHandlingInteraction = LibInteractionHook.UnregisterOnTryHandlingInteraction
  2. unregisterOnTryHandlingInteraction(self.name, _action_ )
  3. unregisterOnTryHandlingInteraction(self.name)

Last edited by IsJustaGhost : 06/18/23 at 04:11 AM.
  Reply With Quote
06/20/23, 03:03 AM   #5
Anumaril
 
Anumaril's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2018
Posts: 14
Originally Posted by Baertram View Post
If all wents bad the wayshrines action string will be just "Use" (in any language at least) and you are not able to properly detect it or differ from other "Use" actions.
You will need to use the API function GetInteractionInfo() or similar to return more info about the interaction below your crosshair (ESO names that "reticle") to check for a wayshrine type returned or similar)!!!


local interactionType = GetInteractionType()
if interactionType == INTERACTION_WHATEVER A WAYSHRINE RETURNS AND IF THIS IS ONLY RETURNED FOR A WAYSHRINE then

I think there was one interaction type INTERACTION_FAST_TRAVEL

So check if the library linked above supports that already somehow.
I ended up going with this as it seems simpler than what I was doing before, and should also be easy for me to include INTERACTION_FAST_TRAVEL_KEEP in the future (to disable fast travel in Cyrodiil too). But I've ran into an issue with the code:

Code:
-- Function to check if the interaction is with a wayshrine
local function IsWayshrineInteraction()
    local interactionType = GetInteractionType()
	d("[NoFastTravel] Interaction type: " .. tostring(interactionType))
    return interactionType == INTERACTION_FAST_TRAVEL
end

-- Check if the INTERACTIVE_WHEEL_MANAGER table exists, otherwise create it
INTERACTIVE_WHEEL_MANAGER = INTERACTIVE_WHEEL_MANAGER or {}

-- Store the original StartInteraction function
local OriginalInteract = INTERACTIVE_WHEEL_MANAGER.StartInteraction

-- Modify the StartInteraction function
INTERACTIVE_WHEEL_MANAGER.StartInteraction = function(...)
    if IsWayshrineInteraction() then
	d("[NoFastTravel] Wayshrine interaction intercepted!") -- Test code functionality by seeing if this is printed in chat
        return true -- Disable fast travel for wayshrines
    end

    return OriginalInteract(...)
end
The first function defines what's a Wayshrine interaction or not so that the last function can basically intercept the interaction and stop the player from interacting with Wayshrines. But it just doesn't recognise it. I'm using the correct interaction text too (INTERACTION_FAST_TRAVEL) since I can see it in the most recent API documentation.

I've added the line "d("[NoFastTravel] Interaction type: " .. tostring(interactionType))" to the function to see if the game is picking up on the interactions or not, and ALL the interaction types are "0", meaning it's not registering ANY interaction at all.

Yesterday I was messing around with the code and managed to get it to recognise a handful of other interactions (like Companion conversations, which I think are type "14"), but even then it didn't recognise Wayshrines, which were still type "0". But then I continued tweaking the code and now everything's back to 0 again, so I'm pretty lost on what to do


EDIT: Just found out now that with the current code if I double-press the E key to interact, the first interaction type will be "0", but the second time will be the actual interaction type (14 for companion conversations). As for wayshrines, it'll be 0 when I interact with the wayshrine, but once I'm looking at the wayshrine map it will correctly list the interaction type (11) and also print the other text string I have saying it was intercepted. Needless to say, it doesn't work, and I'm quite lost haha

Last edited by Anumaril : 06/20/23 at 04:11 AM.
  Reply With Quote
06/20/23, 10:20 AM   #6
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,989
First of all this is wrong:
Code:
-- Check if the INTERACTIVE_WHEEL_MANAGER table exists, otherwise create it
INTERACTIVE_WHEEL_MANAGER = INTERACTIVE_WHEEL_MANAGER or {}
INTERACTIVE_WHEEL_MANAGER either exists or not. You cannot create an empty table and define your own function StartInteraction and expect it to do anything, if it wasn't there before :-)
So this line is useless and leads to errors in the end.
-> You probably did that because there was FISHING_MANAGER or INTERACTIVE_WHEEL_MANAGER before. This was only a compatibility line for old API before Necrom and new API with Necrom (PTS). Now that Necrom is live the FISHING_MANAGER is gone and INTERACTIVE_WHEEL_MANAGER is the one to use.

And for that:
I've added the line "d("[NoFastTravel] Interaction type: " .. tostring(interactionType))" to the function to see if the game is picking up on the interactions or not, and ALL the interaction types are "0", meaning it's not registering ANY interaction at all.
Often the functions used are working too fast and the interactions might not be recognized properly that way (your code is calling the API before server got the info about the interaction).
Try to add a small delay, like try with 0 first to let it run at next frame, and if this doesn ot work try a 10ms or higher delay before calling
local interactionType = GetInteractionType()

-> You can do this by using zo_callLater

But:
I know this cannot work with your overwritten function then as the return true would be missing, as the delayed code is run AFTER that return would be needed.

Code:
INTERACTIVE_WHEEL_MANAGER.StartInteraction = function(...)
--delaying the call to API local interactionType = GetInteractionType() within IsWayshrineInteraction() va zo_callLater will not return anything here, just false, making the code always be skipped! So this would just be a way to test if the delay helps to find the correct interactionType or not at all!
    if IsWayshrineInteraction() then 
	d("[NoFastTravel] Wayshrine interaction intercepted!") -- Test code functionality by seeing if this is printed in chat
        return true -- Disable fast travel for wayshrines
    end

    return OriginalInteract(...)
end
This is just to test IF the delayed interaction test would return a correct value of the wayshrine interaction type. But maybe it always returns 0 and just in a few circumstances is the correct INTERACTION_FAST_TRAVEL then...

In that case you'd have to rely on other ways to detect the wayshrine interaction then and I do not know how.
  Reply With Quote
06/20/23, 05:36 PM   #7
IsJustaGhost
AddOn Author - Click to view addons
Join Date: May 2020
Posts: 38
As you can see by the grayed out keybind, interaction is disabled
Lua Code:
  1. local registerOnTryHandlingInteraction = LibInteractionHook.RegisterOnTryHandlingInteraction
  2. local wayshrineString = GetString(SI_DEATH_PROMPT_WAYSHRINE):lower()
  3.  
  4. registerOnTryHandlingInteraction("Addon_Name", SI_LIB_IF_GAMECAMERAACTION5, function(action, interactableName, interactionBlocked, isOwned, additionalInteractInfo, context, contextLink, isCriminalInteract, currentFrameTimeSeconds)
  5.     if interactableName:lower():match(wayshrineString) then -- This is in theory
  6.         return true -- to disable it
  7.     end
  8. end)

Here it is also hidden.

Lua Code:
  1. local registerOnTryHandlingInteraction = LibInteractionHook.RegisterOnTryHandlingInteraction
  2. local hideInteraction = LibInteractionHook.HideInteraction
  3. local wayshrineString = GetString(SI_DEATH_PROMPT_WAYSHRINE):lower()
  4.  
  5. registerOnTryHandlingInteraction("Addon_Name", SI_LIB_IF_GAMECAMERAACTION5, function(action, interactableName, interactionBlocked, isOwned, additionalInteractInfo, context, contextLink, isCriminalInteract, currentFrameTimeSeconds)
  6.     if interactableName:lower():match(wayshrineString) then -- This is in theory
  7.         hideInteraction()
  8.         return true -- to disable it
  9.     end
  10. end)

Either one of those could be pasted in a blank addon's lua and it will work. As in, nothing else is needed to be done.
No need to modify INTERACTIVE_WHEEL_MANAGER.StartInteraction

The only other thing that must be done is adding this to the manifest.
## DependsOn: LibInteractionHook>=3

Last edited by IsJustaGhost : 06/20/23 at 05:50 PM.
  Reply With Quote
06/20/23, 06:00 PM   #8
IsJustaGhost
AddOn Author - Click to view addons
Join Date: May 2020
Posts: 38
Also, the method other's use in just replacing INTERACTIVE_WHEEL_MANAGER.StartInteraction is only effective in keyboard mode.
Sure it disables interaction in gamepad mode too but, it also disables the ability to jump at the same time.
  Reply With Quote
06/20/23, 07:28 PM   #9
Dolgubon
 
Dolgubon's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2016
Posts: 409
Another, probably simpler option would be to simply overwrite the actual fast travel functions.
FastTravelToNode = ZO_PreHook(_G, "FastTravelToNode" , function() return shouldBlockTravel end )
TravelToKeep = ZO_PreHook(_G, "FastTravelToNode" , function() return shouldBlockTravel end )


Maybe add some output informing the user that your addon blocked the travel. Other potential target functions would be JumpToSpecificHouse, JumpToHouse, RequestJumpToHouse.


This would additionally disable using the map to port to wayshrines. If you instead block interaction with wayshrines, the user would still be able to teleport using the map, which may or may not be desired functionality.

Another difference is that interacting with a wayshrine with this would still open up the map, they'd just be unable to actually port anywhere.
  Reply With Quote
06/22/23, 10:41 AM   #10
Anumaril
 
Anumaril's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2018
Posts: 14
Originally Posted by Dolgubon View Post
Another, probably simpler option would be to simply overwrite the actual fast travel functions.
FastTravelToNode = ZO_PreHook(_G, "FastTravelToNode" , function() return shouldBlockTravel end )
TravelToKeep = ZO_PreHook(_G, "FastTravelToNode" , function() return shouldBlockTravel end )
This ended up being a much more elegant solution than what I was trying to do before, and also makes it easy to disable fast travel to houses, etc. Thanks so much!

For anyone reading this in the future and thinking of doing the same, I had to alter the above lines to look like:

ZO_PreHook(_G, "FastTravelToNode", function(nodeIndex, ignoreCost)
ZO_PreHook(_G, "TravelToKeep", function(keepId, ignoreCost)
ZO_PreHook(_G, "RequestJumpToHouse", function(houseId)

Thanks everyone for your help, you guys a great
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Scoping key for wayshrines


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off