Ryuushu Posted September 21, 2017 Share Posted September 21, 2017 How can I use rezecib's UpvalueHacker util to modify this onAttacked event? local function onAttacked(player, data) ... end ... local SomeComponent = Class(function(self, player) ... player:ListenForEvent("attacked", onAttacked) -- <- event listener I wanna modify end) I just can't figure out the root for the component.. I've tried randomly guessing self.class, self.Class, self.fn, self._ctor but none have worked. Maybe the author can help me on this? @rezecib Link to comment Share on other sites More sharing options...
ptr Posted September 21, 2017 Share Posted September 21, 2017 I have no problem retrieving the function with ._ctor, something must be wrong with your mod code. Link to comment Share on other sites More sharing options...
Ryuushu Posted September 21, 2017 Author Share Posted September 21, 2017 @ptr I just tried this AddClassPostConstruct("components/age", function(self, ...) local fn = UpvalueHacker.FindUpvalue(self._ctor, "OnSetOwner") print("This is what I found:", fn) end) And the result I get is "This is what I found: nil". Can you point out what's wrong? Link to comment Share on other sites More sharing options...
ptr Posted September 21, 2017 Share Posted September 21, 2017 Well, it is due to how AddClassPostConstruct works. It actually overrides the original constructor, adding your function behind the original one. So, in order to protect the original constructor, you have to use AddComponentPostInit instead. I don't know about the UpvalueHacker and how it works, so here's my code... Quote AddComponentPostInit("age",function(inst) for i = 1,math.huge do local n, v = GLOBAL.debug.getupvalue(inst._ctor,i) if n == nil then break elseif n == "OnSetOwner" then print(v) end end end) Link to comment Share on other sites More sharing options...
Ryuushu Posted September 21, 2017 Author Share Posted September 21, 2017 @ptr Ahh, I didn't know that. AddComponentPostInit worked perfectly. Thanks a lot! Link to comment Share on other sites More sharing options...
Ryuushu Posted September 22, 2017 Author Share Posted September 22, 2017 @ptr Well, on a first look it worked. It did find the reference to the function.. but when I tried to modify it I realized it it was the one outside the constructor. How can I access the one inside of it? This is what I have now AddComponentPostInit("age", function(self, ...) local fn = UpvalueHacker.FindUpvalue(self._ctor, "OnSetOwner") print("FindUpvalue", fn) -- This prints correctly local function OnSetOwner(...) print("OnSetOwner") -- This doesn't prints return fn(...) end UpvalueHacker.SetUpvalue(self._ctor, OnSetOwner, "OnSetOwner") -- It's doing nothing since it's the one outside the constructor </3 end) Link to comment Share on other sites More sharing options...
ptr Posted September 22, 2017 Share Posted September 22, 2017 Again, I don't know how that function works, but my code work well... AddComponentPostInit("age",function(inst) for i = 1,math.huge do local n, v = GLOBAL.debug.getupvalue(inst._ctor,i) if n == nil then break elseif n == "OnSetOwner" then GLOBAL.debug.setupvalue(inst._ctor,i,function(inst) v(inst) print("Hooked!") end) end end end) Link to comment Share on other sites More sharing options...
DarkXero Posted September 22, 2017 Share Posted September 22, 2017 The upvalue hacker edits upvalues. What's an upvalue? local something local function fn() return something + 2 end something is an upvalue of fn. In this case, OnSetOwner is an upvalue of the constructor function. Why doesn't it work? Because the constructor function runs before you edit the upvalue from where it will take the value to use for ListenForEvent. local ac = GLOBAL.require("components/age") local fn = UpvalueHacker.FindUpvalue(ac._ctor, "OnSetOwner") local function OnSetOwner(...) print("OnSetOwner") return fn(...) end UpvalueHacker.SetUpvalue(ac._ctor, OnSetOwner, "OnSetOwner") Link to comment Share on other sites More sharing options...
Ryuushu Posted September 22, 2017 Author Share Posted September 22, 2017 Thanks a lot for your explanation @DarkXero, now it's working (for reals this time). Thank you too @ptr. Link to comment Share on other sites More sharing options...
ptr Posted September 22, 2017 Share Posted September 22, 2017 @DarkXero Theoretically, we cannot change the function address assigned to eventlistener table in AddComponentPostInit through assignment, without touching the table itself, as the class has already been constructed. But in DST, the code actually works somehow? It seems the setupvalue has replaced the original function with a pointer to the new function. Quote [00:00:25]: Telling Client our new session identifier: 2A712D96A8427ED7 [00:00:25]: ModIndex: Load sequence finished successfully. [00:00:25]: Reset() returning [00:00:26]: Attempting to send resume request [00:00:26]: Resuming user: session/2A712D96A8427ED7/A7JGRTPS5EPJ/0000000041[00:00:26]: Hooked! [00:00:26]: ResumeExistingUserSession 111200 [00:00:26]: Spawning player at: [Load] (-340.00, 0.00, -124.00) [00:00:26]: ReceiveResumeNotification [00:00:26]: ResumeRequestLoadComplete true [00:00:26]: Deserializing tile data (350 x 350) Link to comment Share on other sites More sharing options...
DarkXero Posted September 22, 2017 Share Posted September 22, 2017 36 minutes ago, ptr said: But in DST, the code actually works somehow? You will have to provide the code and what did you do. AddComponentPostInit("age",function(inst) for i = 1,math.huge do local n, v = GLOBAL.debug.getupvalue(inst._ctor,i) if n == nil then break elseif n == "OnSetOwner" then GLOBAL.debug.setupvalue(inst._ctor,i,function(inst) v(inst) print("Hooked!") end) end end end) This prints nothing. Unless you had something different or another player join you. Clean the logs and try again. Link to comment Share on other sites More sharing options...
ptr Posted September 22, 2017 Share Posted September 22, 2017 @DarkXero Well, it seem the code works in client with only overworld, but does not work in nullrenderer. Link to comment Share on other sites More sharing options...
DarkXero Posted September 22, 2017 Share Posted September 22, 2017 8 minutes ago, ptr said: the code works in client with only overworld Still can't replicate. Link to comment Share on other sites More sharing options...
ptr Posted September 22, 2017 Share Posted September 22, 2017 4 minutes ago, DarkXero said: Still can't replicate. It's really weird, that's all the code in modmain... And here's the modinfo api_version = 6 api_version_dst = 10 dont_starve_compatible = true reign_of_giants_compatible = true shipwrecked_compatible = true dst_compatible = true server_only_mod = false all_clients_require_mod = true client_only_mod = false configuration_options = {} The rest name things won't make a magic right? Link to comment Share on other sites More sharing options...
DarkXero Posted September 22, 2017 Share Posted September 22, 2017 6 minutes ago, ptr said: The rest name things won't make a magic right? I have the same setup. You could zip the folder and upload it here so I can paste it on my mods folder. Link to comment Share on other sites More sharing options...
ptr Posted September 22, 2017 Share Posted September 22, 2017 10 minutes ago, DarkXero said: Still can't replicate. All right, I can't replicate that for a new world either. It seems the mod change has been saved into the session file??? O_o, it makes no sense... Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now