Silisiban Posted May 7, 2019 Share Posted May 7, 2019 Hey guys I have been trying to figure out how to listen for an event for a certain player on the server. I am trying to make a mod for my 4 year old son so that when it becomes night it automatically checks his inventory for a miners hat and if he doesn't have one it gives it to him and equips it. So that being said I need a way to listen for the event for his player. I am testing it with just myself first and after I will get all players and the display name to do the final check. Here is the code and the error that I am getting. -- For debugging tables. function dump(o) if type(o) == 'table' then local s = '{ ' for k,v in pairs(o) do if type(k) ~= 'number' then k = '"'..k..'"' end s = s .. '['..k..'] = ' .. dump(v) .. ',' end return s .. '} ' else return tostring(o) end end G = GLOBAL T = G.TUNING RECIPETABS = G.RECIPETABS Recipe = G.Recipe Ingredient = G.Ingredient _world = TheWorld function G.ShowMeStuff() local me = G.AllPlayers[1] local x,y,z = me.Transform:GetWorldPosition() local ents = TheSim:FindEntities(x,y,z,3) for k,v in pairs(ents) do print(dump(v.entity.tags)) end end G.AllPlayers[1]:ListenForEvent("phasechanged", OnPhaseChanged, _world) local function OnPhaseChanged(src, phase) if phase == "night" then inst.components.talker:Say("Oh no its night") else inst.components.talker:Say("Good not night time") end end Here is the error [00:00:25]: Could not load mod_config_data/modconfiguration_Test [00:00:25]: Network tick rate: U=15(2), D=0 [00:00:25]: ModWorkshop::CancelDownloads clearing all unfinished downloads [00:00:25]: About to start a server with the following settings: [00:00:25]: Dedicated: false [00:00:25]: Online: true [00:00:25]: Passworded: false [00:00:25]: ServerPort: 10999 [00:00:25]: SteamAuthPort: 8766 [00:00:25]: SteamMasterServerPort: 27016 [00:00:25]: ClanID: false [00:00:25]: ClanOnly: false [00:00:25]: ClanAdmin: false [00:00:25]: LanOnly: true [00:00:25]: FriendsOnly: false [00:00:25]: EnableAutosaver: true [00:00:25]: EncodeUserPath: true [00:00:25]: PVP: false [00:00:25]: MaxPlayers: 1 [00:00:25]: GameMode: endless [00:00:25]: OverridenDNS: [00:00:25]: PauseWhenEmpty: true [00:00:25]: IdleTimeout: 1800s [00:00:25]: VoteEnabled: false [00:00:25]: InternetBroadcasting: true [00:00:25]: Intent: social [00:00:25]: [Warning] Could not confirm port 10999 is open in the firewall. [00:00:25]: Could not load mod_config_data/modconfiguration_Test [00:00:25]: Online Server Started on port: 10999 [00:00:25]: Collecting garbage... [00:00:25]: lua_gc took 0.03 seconds [00:00:25]: ~ShardLuaProxy() [00:00:25]: ~cEventLeaderboardProxy() [00:00:25]: ~ItemServerLuaProxy() [00:00:25]: ~InventoryLuaProxy() [00:00:25]: ~NetworkLuaProxy() [00:00:25]: ~SimLuaProxy() [00:00:25]: ModWorkshop::CancelDownloads clearing all unfinished downloads [00:00:25]: lua_close took 0.04 seconds [00:00:25]: ReleaseAll [00:00:25]: ReleaseAll Finished [00:00:25]: cGame::StartPlaying [00:00:25]: LOADING LUA [00:00:25]: DoLuaFile scripts/main.lua [00:00:25]: DoLuaFile loading buffer scripts/main.lua [00:00:25]: taskgrouplist: default Together [00:00:25]: taskgrouplist: classic Classic [00:00:25]: taskgrouplist: cave_default Underground [00:00:25]: taskgrouplist: lavaarena_taskset The Forge [00:00:25]: taskgrouplist: quagmire_taskset The Gorge [00:00:25]: running main.lua [00:00:25]: loaded modindex [00:00:25]: ModIndex: Beginning normal load sequence. [00:00:25]: ModIndex:GetModsToLoad inserting moddir, Test [00:00:25]: Could not load mod_config_data/modconfiguration_Test [00:00:25]: Loading mod: Test Version:0.0.1 [00:00:25]: Mod: Test Loading modworldgenmain.lua [00:00:25]: Mod: Test Mod had no modworldgenmain.lua. Skipping. [00:00:25]: Mod: Test Loading modmain.lua [00:00:25]: MOD ERROR: Test: Mod: Test [00:00:26]: Event data unavailable: lavaarena_event_server/lavaarena_achievement_quest_defs [00:00:26]: [string "../mods/Test/modmain.lua"]:33: attempt to index field '?' (a nil value) LUA ERROR stack traceback: ../mods/Test/modmain.lua(33,1) in main chunk =[C] in function 'xpcall' scripts/util.lua(711,1) in function 'RunInEnvironment' scripts/mods.lua(513,1) in function 'InitializeModMain' scripts/mods.lua(487,1) in function 'LoadMods' scripts/main.lua(302,1) in function 'ModSafeStartup' scripts/main.lua(375,1) =[C] in function 'SetPersistentString' scripts/mainfunctions.lua(26,1) in function 'SavePersistentString' scripts/modindex.lua(80,1) =[C] in function 'GetPersistentString' scripts/modindex.lua(67,1) in function 'BeginStartupSequence' scripts/main.lua(374,1) in function 'callback' scripts/modindex.lua(545,1) =[C] in function 'GetPersistentString' scripts/modindex.lua(519,1) in function 'Load' scripts/main.lua(373,1) in main chunk [00:00:26]: [string "scripts/mainfunctions.lua"]:1089: variable 'global_error_widget' is not declared LUA ERROR stack traceback: =[C] in function 'error' scripts/strict.lua(23,1) scripts/mainfunctions.lua(1089,1) =[C] in function 'GetPersistentString' scripts/quagmire_recipebook.lua(54,1) in function 'Load' scripts/main.lua(320,1) in function 'ModSafeStartup' scripts/main.lua(375,1) =[C] in function 'SetPersistentString' scripts/mainfunctions.lua(26,1) in function 'SavePersistentString' scripts/modindex.lua(80,1) =[C] in function 'GetPersistentString' scripts/modindex.lua(67,1) in function 'BeginStartupSequence' scripts/main.lua(374,1) in function 'callback' scripts/modindex.lua(545,1) =[C] in function 'GetPersistentString' scripts/modindex.lua(519,1) in function 'Load' scripts/main.lua(373,1) in main chunk [00:00:26]: DoLuaFile Error: (null) [00:00:26]: LuaError but no error string [00:00:26]: Error loading main.lua [00:00:26]: Failed mSimulation->Reset() [00:00:26]: Error during game restart! [00:00:27]: AddPortMapping(10999, 10999, 192.168.1.62) failed with code 718 (ConflictInMappingEntry) [00:00:27]: AddPortMapping(10999, 10999, 192.168.1.62) failed with code 718 (ConflictInMappingEntry) Any help and explanation of what I am doing wrong here would be greatly appreciated. Link to comment Share on other sites More sharing options...
YakumoYukari Posted May 7, 2019 Share Posted May 7, 2019 (edited) TheWorld does not exist(is just nil) when modmain loads. It will become valid after most prefabs are loaded. So don't make the shortcut of TheWorld in modmain. Just manually call GLOBAL.TheWorld Also, TUNING does not need GLOBAL Edited May 7, 2019 by YakumoYukari Link to comment Share on other sites More sharing options...
CarlZalph Posted May 7, 2019 Share Posted May 7, 2019 What you want is a prefab post init callback to then use for your needs. There's a generic one for any player as well if that's what you're wanting. Put it after your local OnPhaseChanged definition, too, to ensure that it exists for the JIT. Further, I'd suggest not using a hard coded player offset and instead opt for the similar syntax found in consolecommands.lua Example: GLOBAL.blah = function() local player = GLOBAL.ConsoleCommandPlayer() if player and player.components.builder then player.components.builder:GiveAllRecipes() end end Link to comment Share on other sites More sharing options...
Silisiban Posted May 7, 2019 Author Share Posted May 7, 2019 @CarlZalph I can't say that I understand what you mean by prefab post init callback. I can understand the consolecommandplayer and I plan on refactoring after I have tested the functionality for what I am doing. @YakumoYukari I went ahead and called GLOBAL.TheWorld and I am still getting this error. This is what I have changed. What am I missing? -- For debugging tables. function dump(o) if type(o) == 'table' then local s = '{ ' for k,v in pairs(o) do if type(k) ~= 'number' then k = '"'..k..'"' end s = s .. '['..k..'] = ' .. dump(v) .. ',' end return s .. '} ' else return tostring(o) end end G = GLOBAL T = TUNING RECIPETABS = G.RECIPETABS Recipe = G.Recipe Ingredient = G.Ingredient function G.ShowMeStuff() local me = G.AllPlayers[1] local x,y,z = me.Transform:GetWorldPosition() local ents = TheSim:FindEntities(x,y,z,3) for k,v in pairs(ents) do print(dump(v.entity.tags)) end end G.AllPlayers[1]:ListenForEvent("phasechanged", OnPhaseChanged, GLOBAL.TheWorld) local function OnPhaseChanged(src, phase) if phase == "night" then inst.components.talker:Say("Oh no its night") else inst.components.talker:Say("Good not night time") end end Here is the error again. [00:00:33]: Mod: Test Mod had no modworldgenmain.lua. Skipping. [00:00:33]: Mod: Test Loading modmain.lua [00:00:33]: MOD ERROR: Test: Mod: Test [00:00:33]: Mod: workshop-881455419 (Fix For Too Many Items) Loading modworldgenmain.lua [00:00:33]: Mod: workshop-881455419 (Fix For Too Many Items) Mod had no modworldgenmain.lua. Skipping. [00:00:33]: Mod: workshop-881455419 (Fix For Too Many Items) Loading modmain.lua [00:00:33]: [string "../mods/Test/modmain.lua"]:33: attempt to index field '?' (a nil value) LUA ERROR stack traceback: ../mods/Test/modmain.lua(33,1) in main chunk =[C] in function 'xpcall' scripts/util.lua(711,1) in function 'RunInEnvironment' scripts/mods.lua(513,1) in function 'InitializeModMain' scripts/mods.lua(487,1) in function 'LoadMods' scripts/main.lua(302,1) in function 'ModSafeStartup' scripts/main.lua(375,1) =[C] in function 'SetPersistentString' scripts/mainfunctions.lua(26,1) in function 'SavePersistentString' scripts/modindex.lua(80,1) =[C] in function 'GetPersistentString' scripts/modindex.lua(67,1) in function 'BeginStartupSequence' scripts/main.lua(374,1) in function 'callback' scripts/modindex.lua(545,1) =[C] in function 'GetPersistentString' scripts/modindex.lua(519,1) in function 'Load' scripts/main.lua(373,1) in main chunk [00:00:33]: [string "scripts/mainfunctions.lua"]:1089: variable 'global_error_widget' is not declared LUA ERROR stack traceback: =[C] in function 'error' scripts/strict.lua(23,1) scripts/mainfunctions.lua(1089,1) =[C] in function 'SetPersistentString' scripts/mainfunctions.lua(26,1) in function 'SavePersistentString' scripts/modindex.lua(80,1) =[C] in function 'GetPersistentString' scripts/modindex.lua(67,1) in function 'BeginStartupSequence' scripts/main.lua(374,1) in function 'callback' scripts/modindex.lua(545,1) =[C] in function 'GetPersistentString' scripts/modindex.lua(519,1) in function 'Load' scripts/main.lua(373,1) in main chunk [00:00:33]: DoLuaFile Error: (null) [00:00:33]: LuaError but no error string [00:00:33]: Error loading main.lua [00:00:33]: Failed mSimulation->Reset() [00:00:33]: Error during game restart! [00:00:34]: ModWorkshop::CancelDownloads clearing all unfinished downloads [00:00:34]: Collecting garbage... [00:00:34]: lua_gc took 0.04 seconds [00:00:34]: ~ShardLuaProxy() [00:00:34]: ~cEventLeaderboardProxy() [00:00:34]: ~ItemServerLuaProxy() [00:00:34]: ~InventoryLuaProxy() [00:00:34]: ~NetworkLuaProxy() [00:00:34]: ~SimLuaProxy() [00:00:34]: ModWorkshop::CancelDownloads clearing all unfinished downloads [00:00:34]: lua_close took 0.02 seconds [00:00:34]: AddPortMapping(10999, 10999, 192.168.1.62) failed with code 718 (ConflictInMappingEntry) [00:00:34]: AddPortMapping(10999, 10999, 192.168.1.62) failed with code 718 (ConflictInMappingEntry) [00:00:34]: ModWorkshop::CancelDownloads clearing all unfinished downloads [00:00:34]: [Steam] Auth ticket cancelled [00:00:35]: CurlRequestManager::ClientThread::Main() complete [00:00:35]: HttpClient2 discarded 0 callbacks. [00:00:35]: steamnetworkingsockets_lowlevel.cpp (88) : Assertion Failed: SteamDatagramTransportLock held for 251.3ms! [00:00:35]: Shutting down Link to comment Share on other sites More sharing options...
YakumoYukari Posted May 7, 2019 Share Posted May 7, 2019 Actually, here's the code. local function OnPhaseChanged(inst, phase) if phase == "night" then inst.components.talker:Say("Oh no its night") else inst.components.talker:Say("Good not night time") end end AddPlayerPostInit(function(inst) if not GLOBAL.TheWorld.ismastersim then return end if inst == GLOBAL.AllPlayers[1] then inst:WatchWorldState("phase", OnPhaseChanged) end end) There're some modutil/entityscripts' methods used. I think you could guess enough about this. AddPlayerPostInit is defined at modutil.lua. Also, Look this thread if you need the explanation about WatchWorldState(). Otherwise, it's common and recommended expressions of how you could write things related to prefab for mods. Link to comment Share on other sites More sharing options...
Ultroman Posted May 7, 2019 Share Posted May 7, 2019 (edited) 4 minutes ago, YakumoYukari said: snip Yeah, that'll work. prefab post init callback <=> e.g. AddPrefabPostInit or AddPlayerPostInit If your 4-year-old always plays alone, YakumoYukari's code will do fine. If he ever plays with your other kids, you'd have to make it specific to his username, instead of just picking the first available player in AllPlayers. Edited May 7, 2019 by Ultroman Link to comment Share on other sites More sharing options...
Silisiban Posted May 7, 2019 Author Share Posted May 7, 2019 (edited) What I am trying to do is get a list off all the players and iterate through their respective display names. Then assign inst to the correct player. @YakumoYukari Thank you for the code that you posted as I do now have it listening for the event. However, I started a new server and soon as it hit dusk the event fired and gave me the same error as (attempt to index a field ?) this time it was a warning and not a crash. Edited May 7, 2019 by Silisiban Link to comment Share on other sites More sharing options...
YakumoYukari Posted May 7, 2019 Share Posted May 7, 2019 (edited) I don't precisely know what 'respective display names,' but I think you want something like this : function GLOBAL.SearchUserId(name) local ClientObjs = GLOBAL.TheNet:GetClientTable() local result = {} if ClientObjs ~= nil and #ClientObjs > 0 then for i, v in ipairs(ClientObjs) do if v.name == name then table.insert(result, v.userid) end end end return result end function GLOBAL.GetPlayerObjectByUserName(name) local ids = GLOBAL.SearchUserId(name) if #ids == 0 then print("Couldn't find any user named \""..name.."\"") return end local result = {} for k, v in pairs(ids) do for _, player in pairs(GLOBAL.AllPlayers) do if player.userid == v then table.insert(result, player) end end end return #result == 1 and result[1] or result end So, I've just made functions to find and get a reference of the player by DisplayName(Steam profile name if Steam). It's just simple to use, but there could be more than one players that have the same DisplayName. If that, it will return a list of the player prefab. Oh, and you could remove "GLOBAL.". That's not necessary if you don't test it via console. And the crash one. Well, I have tested that it works fine on me with the same code. Perhaps it may be the reason if you change any references to your 'shortcut' thing. And I don't care if the error is warning or crash, consider it same though. If you still get crashed with the same code, the crash log would help. Also, all the code I've written in here uploaded in GitHub Page to be Open Source. Edited May 7, 2019 by YakumoYukari Link to comment Share on other sites More sharing options...
Silisiban Posted May 8, 2019 Author Share Posted May 8, 2019 First of all I want to say a HUGE!!! thanks to @Ultroman especially, @YakumoYukari and @CarlZalph. I really do want you guys / gals to know that your help has made the game for my family and I even more enjoyable then it already was. Again HUGE THANKS!! So from all the posted code and working with @Ultroman I finally was able to create what I was trying to accomplish for my young son. Basically it just hooks him up so he doesn't die all the time lol. It gives him full health, hunger and sanity at the beginning of each day and when it hits night it automatically gives him a Miners Hat and equips it. Here is the code below. local function FindHat(item) return item.prefab == "minerhat" end local function RefuelHat(item) item.components.fueled:SetPercent(1) end local function GiveHat(inst) local hat = G.SpawnPrefab("minerhat") inst.components.inventory:Equip(hat) end local function OnPhase(inst, thePhase) if thePhase == "day" then inst.components.talker:Say("I am Healed!!! Thanks Daddy!") inst.components.health:SetPercent(1) inst.components.sanity:SetPercent(1) inst.components.hunger:SetPercent(1) elseif thePhase == "night" then local head_item = inst.components.inventory:GetEquippedItem(G.EQUIPSLOTS.HEAD) if head_item and head_item.prefab == "minerhat" then --print(head_item.prefab) RefuelHat(head_item) return end local item = inst.components.inventory:FindItem(FindHat) if item then inst.components.inventory:Equip(item) RefuelHat(item) else GiveHat(inst) end end end AddPlayerPostInit(function(inst) if not GLOBAL.TheWorld.ismastersim then return end inst:DoTaskInTime(0.1, function(inst) if inst:GetDisplayName() == "Aiden" then inst:WatchWorldState("phase", OnPhase) end end) end) Link to comment Share on other sites More sharing options...
Ultroman Posted May 8, 2019 Share Posted May 8, 2019 (edited) You are very welcome, m8. I'm very happy to be able to help you and your family have an even better time with the game One thing: if GLOBAL.TheWorld.ismastersim then AddPlayerPostInit(function(inst) inst:DoTaskInTime(0.1, function(inst) if inst:GetDisplayName() == "Aiden" then inst:WatchWorldState("phase", OnPhase) end end) end) end This way the postinit function is only registered on the server, so instead of hooking up the function for all clients, who just ignored it immediately with the ismastersim check, we now just don't hook them up. Edited May 8, 2019 by Ultroman 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