Feldoth Posted January 12, 2017 Share Posted January 12, 2017 (edited) Here's the offending code, this is a character specific widget that keeps track of childspawner children (displaying how many are inside the spawner). It is a simple text widget: AddClassPostConstruct("widgets/statusdisplays", function(self) local player = self.owner if player.prefab=="mychar" then local beeCounter = require "widgets/beecounter" self.beeCounter = beeCounter(player) player:DoPeriodicTask(0, function(inst) if inst.components.childspawner then local children = tostring(inst.components.childspawner.childreninside) self.beeCounter:Update("Bees: "..children) end end) end end) The problems start with the line "if inst.components.childspawner then" - this line only exists because if I let the next line execute on a caveĀ enabled server, the game crashes. For whatever reason, at this point the player does not have defined components (for the childspawner at least). However it goes deeper than that, as if I move that DoPeriodicTask function into the character itself, running the code to update the widget causes a disconnect from the server. This may be because I'm not sure what "self" is in the context of the AddClassPostConstruct closure parameter, so I'm not correctly referencing it when I try to move the code out of modmain.lua, however I'm more than a little surprised that the periodic task doesn't start working once the player is spawned in and fully set up - shouldn't they get the component at some point and the if state begin evaluating as true? The component works, things related to it function in game, just this widget fails and I have no idea why. I should mention that this works perfectly on a non-cave enabled server (and does so in several of the different configurations I've tried). Any help would be appreciated. Thanks! Edited January 12, 2017 by Feldoth Link to comment Share on other sites More sharing options...
Feldoth Posted January 14, 2017 Author Share Posted January 14, 2017 Any ideas, anyone? Even just knowing how/why Cave enabled servers are different from normal servers might help. Link to comment Share on other sites More sharing options...
alainmcd Posted January 14, 2017 Share Posted January 14, 2017 Welcome to the forums! When you host a game without caves, there's only one process running, which includes the world simulation and your character. However, hosting a world with caves runs 3 separate processes: the overworld simulation, the caves simulation, and your character. In this case, you are a client which happens to be hosting the game instead of being the host, hence why you need the remote console to execute commands. Component logic is usually handled only by the server. So what happens is that the code is valid for the host (as in player-hosted game with overworld only or the separate simulations for either overworld or caves), but the client (a pure client or the third process in a multi-shard setup) is missing the component and crashing. The TL;DR is that you'll probably want to write something like if not GLOBAL.TheWorld.ismastersim then return end before handling components, and remember to set all_clients_require_mod to false in your modinfo.lua whenever possible. As for the rest: I haven't tried anything with widgets, so I have no idea. Sorry! Link to comment Share on other sites More sharing options...
Feldoth Posted January 15, 2017 Author Share Posted January 15, 2017 Thanks for your help, I was able to get this working by using net_variables - your comment about the server handling component logic got me on the right track. Here's what I came up with - it feels like I might not have done everything exactly right, but it is working and might be useful to someone else: AddClassPostConstruct("widgets/statusdisplays", function(self) local player = self.owner if player.prefab=="mychar" then local beeCounter = require "widgets/beecounter" player.beeCounter = beeCounter(player) player.beeCounter:Update("") if not player.components.childspawner then -- Update bee counter for cave enabled servers self.netBeeTotal = GLOBAL.net_ushortint(player.GUID, "beeTotal", "mychar_bee_update") self.netBeeTotal:set(0) player:ListenForEvent("guude_bee_update", function(inst) inst.beeCounter:Update("Bees: "..self.netBeeTotal:value()) end) else -- Update bee counter for non-cave servers player:DoPeriodicTask(0, function(inst) inst.beeCounter:Update("Bees: "..player.components.childspawner.childreninside) end) end end end) I used the old method for non-cave servers as that avoided an issue I was having with duplicate id's for my net_var (it was getting added twice since the server and player are the same thing on non-cave servers - so I decided to just not use it on non-cave servers). The other half of this is in my character's prefab script: local master_postinit = function(player) --snip player.netBeeTotal = net_ushortint(player.GUID, "beeTotal", "mychar_bee_update") player.netBeeTotal:set(0) player:DoPeriodicTask(1, function(inst) inst.netBeeTotal:set(inst.components.childspawner.childreninside) end) --snip end That adds the variable on the server, and updates it with the current childspawner count every second, which in turn causes the event to fire on the client, which updates the display widget. 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