Jump to content

Recommended Posts

Hi. The goal: make the Finder mod fully client-side.

The method: find a way to retrieve contents of visible containers, then cache the results in a tree or table structure for better performance and reducing network traffic.

The question: how to get contents of containers on client side in any meaningful way.

So the first thing to check is prefab.replica.container.classified of course which uses netvars to sync data. When a container is closed, classified prefab is removed and the field is set to nil, when the container is opened, a new classified prefab springs into existence and is attached to the container replica. Tracing it back on the client side leads to global ReplicateEntity function in mainfunctions.lua, which appears to be never called (from accessible lua code):

modding$ grep -nwr ReplicateEntity
entityscript.lua:501:--         EntityScript:ReplicateEntity()
entityreplica.lua:73:function EntityScript:ReplicateEntity()
mainfunctions.lua:441:function ReplicateEntity(guid)
mainfunctions.lua:442:    Ents[guid]:ReplicateEntity()

Ok, the next option are netvars themselves. This is how they are used in container_classified.lua (corresponding event listeners are in RegisterNetListeners):

table.insert(inst._itemspool, net_entity(inst.GUID, "container._items["..tostring(i).."]", "items["..tostring(i).."]dirty"))

The code is pretty simple, it's not difficult to create a custom entity but for this to work one needs a way to make the server to do the similar steps and this brings us back to the classified object which exists when the container is open.

I'd be opening and immediately closing containers from the code just to get the contents and cache them but then I looked for existing RPC handlers in networkclientrpc.lua. There are methods to work with already opened containers but no handler to actually open them except general ones like LeftClick handler.

P. S. may be the rummage action will do if it works at distance and the data can be accessed between :Open and :OnUpdate runs

P. P. S. no, it will not, doesn't work at distance

Am I missing something?

Edited by modding
Link to comment
https://forums.kleientertainment.com/forums/topic/70927-finder-mod-client-side/
Share on other sites

@IvanX Hey, can you tell me why is it not possible to hack into your Foodcrafting widget? I made this Finder mod "all_clients_require" and added support for your craft pot mod (so hovering over eg the ingredient meat will highlight all containers with meat ;) )
I use FoodIngredientUI OnGainFocus and OnLooseFocus for that. But if you move mouse too fast, it seems OnLooseFocus is not called. That's why I want to remove highlighting when the craft pot UI is closed. But I'm not able to hack into FoodCrafting widget... my code is:
 

-- ### Compatible to Craft Pot Mod, to find food with the searched tags
local function testCraftPot()
    local FoodIngredientUI = _G.require 'widgets/foodingredientui'
end
if GLOBAL.pcall(testCraftPot) then
    local cooking = _G.require("cooking")
    local ing = cooking.ingredients
    local FoodIngredientUI = _G.require 'widgets/foodingredientui'
    local __FoodIngredientUI_OnGainFocus = FoodIngredientUI.OnGainFocus
    
    function FoodIngredientUI:OnGainFocus(...)
        local searchtag   = self.prefab -- tag or name
        local isname = self.is_name
        local owner = self.owner
        local prefabs = {} -- find all the prefabs with that cooking tag
        
        if not isname then
            for prefab,xyz in pairs(ing) do
                for tag,number in pairs(xyz.tags) do
                    if tag==searchtag then
                        table.insert(prefabs,prefab)
                    end
                end
            end
        elseif isname and GLOBAL.PREFABDEFINITIONS[searchtag] then
            table.insert(prefabs,GLOBAL.PREFABDEFINITIONS[searchtag].name)
        end

        onactiveitem(owner) -- to unhighlight
        for k,prefab in pairs(prefabs) do -- send one prefab after the other, cause sedning an array via rpc does not work..
            if prefab and owner then
              local rpc = GetModRPC("FinderMod", "CheckContainersItem") 
              SendModRPCToServer(rpc,prefab)
            end
        end
        
        if __FoodIngredientUI_OnGainFocus then
            return __FoodIngredientUI_OnGainFocus(self,...)
        end
    end
    
    local __FoodIngredientUI_OnLoseFocus = FoodIngredientUI.OnLoseFocus
    function FoodIngredientUI:OnLoseFocus(...)
        local owner = self.owner
        onactiveitem(owner) -- to unhighlight
        if __FoodIngredientUI_OnLoseFocus then
            return __FoodIngredientUI_OnLoseFocus(self,...)
        end
    end
    
    -- following code does not work ?!
    local FoodCrafting = _G.require 'widgets/foodcrafting'
    local __FoodCrafting_Close = FoodCrafting.Close -- sometimes OnLoseFocus is not called if moving mouse too fast
    function FoodCrafting:Close(...)
        print("HERE finder test close")   -- this is never printed and also it is not unhighligted...
        local owner = self.owner
        onactiveitem(owner) -- to unhighlight
        if __FoodCrafting_Close then
            return __FoodCrafting_Close(self,...)
        end
    end
end

I wonder why it is possible to hack into FoodIngredientUI, but not into FoodCrafting....

Edited by Serpens
18 hours ago, Serpens said:

I wonder why it is possible to hack into FoodIngredientUI, but not into FoodCrafting....

Because when "Close" method is called:

player.HUD.controls.foodcrafting:Close(inst.inst)

It is called on the instance of MouseFoodCrafting:

self.foodcrafting = self.containerroot:AddChild(MouseFoodCrafting())

Which has reference to the original method due to the way how inheritance is simulated in class.lua:

    elseif type(base) == 'table' then
    -- our new class is a shallow copy of the base class!
        for i,v in pairs(base) do
            c[i] = v
        end
        c._base = base
    end

 

The hack just must be into the proper class:

local FoodCrafting = _G.require 'widgets/mousefoodcrafting'

Given the other code is correct, it will work (I checked it). Of course your code must be executed after Craft Pot's directory was added to package.path

For anyone interested, AddClassPostConstruct uses the same wrapper approach but does entirely different thing. It wraps constructor function and __call metamethod of a class which means that your code will be executed for every instance as opposed to modification of the class itself which will serve as a shared metatable for all instances.

I don't like the idea of tailoring code like this for a specific mod though.

 

Quote

sometimes OnLoseFocus is not called if moving mouse too fast

Sometimes it is also called in reverse order (Gain, Lose instead of Lose, Gain). This is why I don't use it. 

 

On 10/22/2016 at 6:45 AM, DarkXero said:

there is no way to make it work as a client_only_mod.

Challenge accepted :D

By the way, the game interprets "client_only_mod = true" in a manner that allows code execution for mastersim. Yes probably it will end up with server-side portion but still useful without it and not required for all clients (I avoid introducing new netvars).

 

Edited by modding

ah hi modding :)
It sounds like you know more than me about mods, great :)
 

Quote

sometimes OnLoseFocus is not called if moving mouse too fast

I found out this was not true. The problem was, that the RPC server calls took ~ 0.05 seconds, so the "unhighlight" command is sent before the highliting is done, when moving mouse to fast.
So if craft pot is closed, the highlight is removed now, if it was highlighted by craftpot previously.

Same happens for the CraftMenu, but there it is not possible to apply such a workaround, cause it is closed too fast.


So if I get you right, you continue working on a "only_client_require" mod? If it works, it will be of course the best solution... but if it does not, I guess the code of my uploaded version is okay. Maybe you can take a look at it ;)

The only thing that has to be done by server, is to check the content of containers... like you arelady described in your first post, the client only knows content of opened containers... =/

edit:
in case you find a solutio for client_only, please still add the support for Craft Pot Mod ;) Because finding foods in several iceboxes is still too complicated ;)

Edited by Serpens
30 minutes ago, Serpens said:

I found out this was not true. The problem was, that the RPC server calls took ~ 0.05 seconds, so the "unhighlight" command is sent before the highliting is done, when moving mouse to fast.

If I recall correctly, both problems were present in single player version when I was testing it: reverse order of events and missing losefocus.

30 minutes ago, Serpens said:

So if I get you right, you continue to working on a "only_client_require" mod? If it works, it will be of course the best solution... but if it does not, I guess the code of my uploaded version is okay. Maybe you can take a look at it ;)

Unless some pitfalls appear, I hope to make it not required for all clients at least. I'll take a look.

 

Edited by modding

@modding My all_clients_require" version had some bugs, but I think I fixed them now (also already uploaded here at klei)
I also uploaded it to steam, but for now only visible for friends, so I can use it with them.

But am I allowed to make it also visible to public?

Edited by Serpens

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
×
  • Create New...