HomShaBom Posted May 1, 2017 Share Posted May 1, 2017 Hello I am trying to do something that I cannot get to work. The client needs information that only exists on the host. For something that I'm trying to do, I need to give certain edible items new custom food types, but by doing that, they are no long edible to players. To fix that, I can insert my new custom food type into the food group table.insert(GLOBAL.FOODGROUP.OMNI.types, GLOBAL.FOODTYPE.UU_HONEY) I technically can do this for all of the edible prefabs that I am changing the foodtype on, but I wanted a better, more forward-compatible method for doing this. Let's say Klei adds a new character that can eat honeycomb, currently honeycomb is not edible so I'm obviously not adding it into any existing food groups, only to my new custom foodgroups that I am creating. What I would like to do is something like this: local AddFoodTypeToFoodGroups(oldfoodtype, newfoodtype) for gkey,group in pairs(GLOBAL.FOODGROUP) do for tkey,type in pairs(group.types) do if type == oldfoodtype then table.insert(group.types, newfoodtype) break end end end end local MakeFoodType(inst, newfoodtype) if GLOBAL.TheWorld.ismastersim then -- edible component only exists on host local edible = inst.components.edible if edible ~= nil then AddFoodTypeToFoodGroup(edible.foodtype, newfoodtype) else inst:AddComponent("edible") edible = inst.components.edible end edible.foodtype = newfoodtype end end So what this does is if the edible prefab is already in an existing food group before i change the foodtype, i insert the new foodtype into that group. This way I don't mess with anyone's diets, everything they used to be able to eat they will still be able to eat, but now I can do what I need to do with the new food type. The problem is, this only works for the host. Clients do not get the prompt to eat unless the correct foodtype is in the foodgroup, client side. So the clients need information that only exists on the host. What can I do to fix this? Link to comment Share on other sites More sharing options...
HomShaBom Posted May 9, 2017 Author Share Posted May 9, 2017 Anyone have any idea how I can do this? Maybe there's some way to do it with netvars? Maybe making an edible replica will allow the client to get access to this data? I have no idea how to even use netvars or replicas so I don't even know know where to begin with even trying it out. Link to comment Share on other sites More sharing options...
DarkXero Posted May 9, 2017 Share Posted May 9, 2017 On 1/5/2017 at 1:01 AM, HomShaBom said: So the clients need information that only exists on the host. What can I do to fix this? If you edit foodgroups or foodtypes, then the mod is all_clients_require_mod = true. You should be editing the tables of both host and client. Still, I don't really understand what you are trying to do. A foodtype that everybody will be able to eat no matter the new foodgroups or foodtypes that are introduced? local FOODTYPE = GLOBAL.FOODTYPE FOODTYPE.UU_HONEY = "UU_HONEY" AddPlayerPostInit(function(inst) local eater = inst.components.eater if eater then table.insert(eater.preferseating, FOODTYPE.UU_HONEY) table.insert(eater.caneat, FOODTYPE.UU_HONEY) inst:AddTag(FOODTYPE.UU_HONEY.."_eater") end end) Why would you give the an edible item a different foodtype? If you want to make it not edible for monsters just edit the eater component. Link to comment Share on other sites More sharing options...
HomShaBom Posted May 9, 2017 Author Share Posted May 9, 2017 (edited) 9 hours ago, DarkXero said: If you edit foodgroups or foodtypes, then the mod is all_clients_require_mod = true. You should be editing the tables of both host and client. all_clients_require_mod is already set to true. The mod already runs on clients. That's not the issue. The problem is when the mod runs on a client, the prefab does not have an edible component. The component only exists on the host. So the client cannot see the original foodtype of the edible component. Edited May 9, 2017 by HomShaBom Link to comment Share on other sites More sharing options...
DarkXero Posted May 9, 2017 Share Posted May 9, 2017 47 minutes ago, HomShaBom said: That's not the issue. The problem is when the mod runs on a client, the prefab does not have an edible component. The component only exists on the host. So the client cannot see the original foodtype of the edible component. I see it now. Having only changes propagate wouldn't work, because once the host edits the table, new clients wouldn't get the old edits. That's why the game just setups the same tables on both sides, or uses a whole bunch of tags. With tags: local AddFoodTypeToFoodGroups(oldfoodtype, newfoodtype) for gkey, group in pairs(GLOBAL.FOODGROUP) do for tkey, type in pairs(group.types) do if type == oldfoodtype then table.insert(group.types, newfoodtype) break end end end end local function GetOldFoodType(food) for k, v in pairs(GLOBAL.FOODTYPE) do if food:HasTag("oldft_"..v) then return v end end end local function SyncType(food, newfoodtype) local oldft = GetOldFoodType(food) AddFoodTypeToFoodGroup(oldft, newfoodtype) end local MakeFoodType(inst, newfoodtype) if GLOBAL.TheWorld.ismastersim then -- edible component only exists on host local edible = inst.components.edible if edible ~= nil then AddFoodTypeToFoodGroup(edible.foodtype, newfoodtype) inst:AddTag("oldft_"..edible.foodtype) else inst:AddComponent("edible") edible = inst.components.edible end edible.foodtype = newfoodtype else -- give time for tag to propagate inst:DoTaskInTime(1, SyncType, newfoodtype) end end There are other options. Turning the foodgroup table into a JSON string and sending it when a player joins or the table updates. Turning edible into a replica. Or making a new replicable component and attaching it when you attach the edible one. In any case, you would need to map the foodtypes to use with integer netvariables. Or use string netvariables. -- modmain AddReplicableComponent("netfoodtype") local AddFoodTypeToFoodGroups(oldfoodtype, newfoodtype) for gkey, group in pairs(GLOBAL.FOODGROUP) do for tkey, type in pairs(group.types) do if type == oldfoodtype then table.insert(group.types, newfoodtype) break end end end end local function SyncType(inst, newfoodtype) AddFoodTypeToFoodGroup(inst.replica.netfoodtype.foodtype:value(), newfoodtype) end local MakeFoodType(inst, newfoodtype) if GLOBAL.TheWorld.ismastersim then -- edible component only exists on host local edible = inst.components.edible if edible ~= nil then AddFoodTypeToFoodGroup(edible.foodtype, newfoodtype) inst:AddComponent("netfoodtype") inst.components.netfoodtype.foodtype = edible.foodtype else inst:AddComponent("edible") edible = inst.components.edible end edible.foodtype = newfoodtype else -- give time for info to propagate inst:DoTaskInTime(1, SyncType, newfoodtype) end end -- components/netfoodtype local function onchangefoodtype(self, foodtype) self.inst.replica.netfoodtype.foodtype:set_local(foodtype) self.inst.replica.netfoodtype.foodtype:set(foodtype) end local netfoodtype = Class(function(self, inst) self.inst = inst -- self.foodtype = nil -- I dont want a default foodtype triggering the netvar end, nil, { foodtype = onchangefoodtype, }) return netfoodtype -- components/netfoodtype_replica local netfoodtype = Class(function(self, inst) self.inst = inst self.foodtype = net_string(inst.GUID, "food.netfood") end) return netfoodtype If you want something forward-compatible as you say, you have to pay a price. Also, I think you should check if newfoodtype is already in the types table before adding it. Link to comment Share on other sites More sharing options...
HomShaBom Posted May 9, 2017 Author Share Posted May 9, 2017 I think I understand this... When the host adds a tag to a prefab, does that tag get automatically synced to all clients, but after some delay so that's why the client does it as a task that runs at a later time? Link to comment Share on other sites More sharing options...
CarlZalph Posted May 9, 2017 Share Posted May 9, 2017 9 minutes ago, HomShaBom said: I think I understand this... When the host adds a tag to a prefab, does that tag get automatically synced to all clients, but after some delay so that's why the client does it as a task that runs at a later time? Yeah, tags are networked. It's why on the base prefabs Klei puts tags on the entity before the pristine state- this is the state where no networking would be expected to happen after the prefab is fully initialized on both server and client. With variable latency you'd ideally poll periodically for tag changes if you're expecting them to change. Though it'd probably be better just to use a netvar at this point. 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