Sign in to follow this  
Ryuushu

UpvalueHacker and component

Recommended Posts

Ryuushu    43

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

Share this post


Link to post
Share on other sites
Ryuushu    43

@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?

Share this post


Link to post
Share on other sites
ptr    41

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)

 

Share this post


Link to post
Share on other sites
Ryuushu    43

@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)

 

Share this post


Link to post
Share on other sites
ptr    41

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)

 

Share this post


Link to post
Share on other sites
DarkXero    2892

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")

 

Share this post


Link to post
Share on other sites
ptr    41

@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)

 

Share this post


Link to post
Share on other sites
DarkXero    2892
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.

Share this post


Link to post
Share on other sites
ptr    41
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?

Share this post


Link to post
Share on other sites
DarkXero    2892
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.

Share this post


Link to post
Share on other sites
ptr    41
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...

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this