MrDoge124 Posted May 1, 2020 Share Posted May 1, 2020 In this previous post I managed to get a AOE stun attack working. However when I enable caves it doesn't work. Turns out I think I'm missing something. It might be an action handler or some sort of net code which could be why it doesn't work when caves are enabled. It also doesn't crash or print anything to the logs, So I'm not sure why it isn't working. This is the code. It's all contained inside a character lua file. Spoiler -- This function is rather complicated. You don't need to change anything in here. local function ApplyBuff(buffData, instToBuff, ents) --print(ents) local buffUniqueName = buffData.uniqueName -- Cancel any existing duplicate timed buff. if instToBuff[buffUniqueName.."Task"] ~= nil then buffData.removeFunction(instToBuff, ents) instToBuff[buffUniqueName.."Task"]:Cancel() instToBuff[buffUniqueName.."Task"] = nil end -- Make sure that our buff is removed BEFORE the entity is saved (the server is closed or player quits). -- This is only necessary if you change variables which are saved, like current health, health-penalty, etc. -- Without it, you could apply a max-health buff, quit before it ran out, rejoin, and you would have kept -- the extra max health! local buffOnSave = function(self, inst, data) if inst[buffUniqueName.."Task"] ~= nil then buffData.removeFunction(inst, ents) inst[buffUniqueName.."Task"]:Cancel() inst[buffUniqueName.."Task"] = nil end end if instToBuff.OnSave ~= nil then local oldOnSave = instToBuff.OnSave instToBuff.OnSave = function(self, inst, data) buffOnSave(self, inst, data) oldOnSave(self, inst, data) end else instToBuff.OnSave = buffOnSave end -- Apply the buff. buffData.applyFunction(instToBuff, ents) -- Set up removal after a certain amount of time. instToBuff[buffUniqueName.."Task"] = instToBuff:DoTaskInTime(buffData.duration, function(inst) buffData.removeFunction(inst, ents) inst[buffUniqueName.."Task"] = nil end) end -- Now to make some buffs and put them in a Buffs-dictionary. local Buffs = {"stunbuff",} -- This function creates a new buff-data object and adds it to the Buffs-dictionary -- with the uniqueName as key. local function CreateBuff(uniqueName, duration, applyFunction, removeFunction) local newBuff = {} newBuff.uniqueName = uniqueName newBuff.duration = duration newBuff.applyFunction = applyFunction newBuff.removeFunction = removeFunction Buffs[uniqueName] = newBuff end -- This is an example of how to use the CreateBuff() function to create a new buff. CreateBuff("stunbuff", 5.0, function(inst, ents) -- Apply all your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them.-- Store the current maxhealth in a variable. -- Add 0% speed boost in all situations for i, ent in ipairs(ents) do --local ds = ent.entity:GetDebugString() --local tagsstr = string.match(ds, "Tags: ([^\n]+)\n") --print(tagsstr) ent.components.locomotor:SetExternalSpeedMultiplier(inst, "stunkey", 0) if ent.brain then ent.brain:Stop() end end end, function(inst, ents) -- Revert your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them. -- Remove speed bonus. for i, ent in ipairs(ents) do ent.components.locomotor:RemoveExternalSpeedMultiplier(inst, "stunkey") if ent.brain then ent.brain:Start() end end end ) TheInput:AddKeyDownHandler(KEY_Z, function() local x, y, z = inst.Transform:GetWorldPosition() local range = 5 local ents = TheSim:FindEntities(x, y, z, range, { "_combat"}, { "player", "playermerm", "playermonster", "structure", "INLIMBO", "playermonster", "NOCLICK"}, {"hostile", "pig", "merm", "monster", "prey", "animal", "bee",}) --Find Entity nearby if not chargeincooldown and inst.components.sanity.current > 10 and table.getn(ents) > 0 then --If chargeincooldown is false and current sanity is larger than 10 and there is more that 0 entities nearby chargeincooldown = true --Disable the move by starting the cooldown ApplyBuff(Buffs["stunbuff"], inst, ents) --Run the apply buff function, inputting the entity table. God only knows how the rest of the function works. print("buff applied") inst.components.sanity.current = inst.components.sanity.current - 10 --Remove 10 sanity inst.SoundEmitter:PlaySound("dontstarve/characters/green/stun") inst.Light:SetIntensity(0.75) inst.Light:SetFalloff(.1) inst.Light:SetRadius(1.5)--Deal with lighting inst:DoTaskInTime(0.2, function() inst.Light:Enable (false)--Hide light after 1 second end) --Reset everything after 15 seconds inst:DoTaskInTime(480, function() print("recharged") inst.Light:SetIntensity(.75) inst.Light:SetFalloff(.5) inst.Light:SetRadius(0.8) inst.Light:Enable (true) chargeincooldown = false end) end end) Any help would be appreciated. Link to comment Share on other sites More sharing options...
CarlZalph Posted May 1, 2020 Share Posted May 1, 2020 Actions done to server-side entities' components should be handled with an RPC, specifically a mod RPC, where the server then runs the callback for said RPC when a client does a thing. Link to comment Share on other sites More sharing options...
MrDoge124 Posted May 1, 2020 Author Share Posted May 1, 2020 I've seen mods use those before but I'm not sure how I'd set one up for myself. Link to comment Share on other sites More sharing options...
Ultroman Posted May 1, 2020 Share Posted May 1, 2020 I would love for someone to do an RPC tutorial or example, so I can link to it in my tutorial compilation. Would really fill a void for everyone. Please tag me if you find one, @MrDoge124. Link to comment Share on other sites More sharing options...
MrDoge124 Posted May 2, 2020 Author Share Posted May 2, 2020 (edited) I've tried to add RPC handlers to the code but it doesn't work, I'm not sure what I'm doing. Spoiler AddModRPCHandler(modname, "GREEN_STUN", function() local x, y, z = inst.Transform:GetWorldPosition() local range = 5 local ents = TheSim:FindEntities(x, y, z, range, { "_combat"}, { "player", "playermerm", "playermonster", "structure", "INLIMBO", "playermonster", "NOCLICK"}, {"hostile", "pig", "merm", "monster", "prey", "animal", "bee",}) --Find Entity nearby if not chargeincooldown and inst.components.sanity.current > 10 and table.getn(ents) > 0 then --If chargeincooldown is false and current sanity is larger than 10 and there is more that 0 entities nearby chargeincooldown = true --Disable the move by starting the cooldown ApplyBuff(Buffs["stunbuff"], inst, ents) --Run the apply buff function, inputting the entity table. God only knows how the rest of the function works. print("buff applied") inst.components.sanity.current = inst.components.sanity.current - 10 --Remove 10 sanity inst.SoundEmitter:PlaySound("dontstarve/characters/green/stun") inst.Light:SetIntensity(0.75) inst.Light:SetFalloff(.1) inst.Light:SetRadius(1.5)--Deal with lighting inst:DoTaskInTime(0.2, function() inst.Light:Enable (false)--Hide light after 1 second end) --Reset everything after 15 seconds inst:DoTaskInTime(480, function() print("recharged") inst.Light:SetIntensity(.75) inst.Light:SetFalloff(.5) inst.Light:SetRadius(0.8) inst.Light:Enable (true) chargeincooldown = false end) end end) local greenhandlers = {} AddPlayerPostInit(function(inst) -- We hack inst:DoTaskInTime(0, function() -- We check if the character is ourselves -- So if another green player joins, we don't get the handlers if inst == GLOBAL.ThePlayer then -- If we are green if inst.prefab == "green" then -- We create and store the key handlers greenhandlers[1] = TheInput:AddKeyDownHandler(KEY_R, function() SendModRPCToServer(MOD_RPC[modname]["GREENCHARGE"]) end) -- If not, we go to the handlerslist and empty it -- This is to avoid having the handlers if we switch characters in wilderness -- If it's already empty, nothing changes for k, v in pairs(greenhandlers) do greenhandlers[k] = nil end end end end) end) I've found this error in the code. Spoiler [00:00:52]: [string "../mods/Green/scripts/prefabs/green.lua"]:244: variable 'Green' is not declared LUA ERROR stack traceback: =[C]:-1 in (global) error (C) <-1--1> scripts/strict.lua:23 in () ? (Lua) <21-26> t = table: 08D51E68 n = Green ../mods/Green/scripts/prefabs/green.lua:244 in (upvalue) master_postinit (Lua) <78-300> inst = 118130 - (valid:true) speedadjustment = function - ../mods/Green/scripts/prefabs/green.lua:113 ApplyBuff = function - ../mods/Green/scripts/prefabs/green.lua:156 Buffs = table: 2049C948 CreateBuff = function - ../mods/Green/scripts/prefabs/green.lua:205 scripts/prefabs/player_common.lua:1768 in (field) fn (Lua) <1395-1797> inst = 118130 - (valid:true) gamemode = endless scripts/mainfunctions.lua:258 in () ? (Lua) <247-289> name = green prefab = Prefab green - [00:00:52]: [string "../mods/Green/scripts/prefabs/green.lua"]:244: variable 'Green' is not declared LUA ERROR stack traceback: =[C]:-1 in (global) error (C) <-1--1> scripts/strict.lua:23 in () ? (Lua) <21-26> ../mods/Green/scripts/prefabs/green.lua:244 in (upvalue) master_postinit (Lua) <78-300> scripts/prefabs/player_common.lua:1768 in (field) fn (Lua) <1395-1797> scripts/mainfunctions.lua:258 in () ? (Lua) <247-289> [00:00:52]: Error decoding lua RPC sender [00:00:52]: Warning: Widget:SetFocusFromChild is happening on a widget outside of the screen/widget hierachy. This will cause focus moves to fail. Is ScriptErrorWidget not a screen? [00:00:52]: stack traceback: scripts/widgets/widget.lua:605 in (method) SetFocusFromChild (Lua) <602-627> scripts/widgets/widget.lua:624 in (method) SetFocusFromChild (Lua) <602-627> scripts/widgets/widget.lua:624 in (method) SetFocusFromChild (Lua) <602-627> scripts/widgets/widget.lua:656 in (method) SetFocus (Lua) <629-665> scripts/widgets/menu.lua:83 in (method) SetFocus (Lua) <74-85> scripts/widgets/scripterrorwidget.lua:109 in (method) OnUpdate (Lua) <102-119> scripts/update.lua:90 in () ? (Lua) <33-129> Edited May 2, 2020 by MrDoge124 Link to comment Share on other sites More sharing options...
Auhrer Posted May 2, 2020 Share Posted May 2, 2020 (edited) The cave really complicates everything, many mods or commands don't work with the cave in the world. They could launch an easy way to link the mods to caves, or something, to fix this, official Edited May 2, 2020 by Auhrer Link to comment Share on other sites More sharing options...
Ultroman Posted May 2, 2020 Share Posted May 2, 2020 5 hours ago, Auhrer said: The cave really complicates everything, many mods or commands don't work with the cave in the world. They could launch an easy way to link the mods to caves, or something, to fix this, official I get your frustration, but it's not really something they can just "fix". It's a multiplayer game, so you need to define how your mod should work for servers and clients. We have neat functions to split up the code, and we have RPC-calls to bridge the information sharing gap. If you want to make a mod, you need to tell the game how it should work on both the client and the server. That's just how it is when you're doing multiplayer games. 1 Link to comment Share on other sites More sharing options...
pickleplayer Posted May 4, 2020 Share Posted May 4, 2020 On 5/2/2020 at 1:19 PM, Auhrer said: The cave really complicates everything, many mods or commands don't work with the cave in the world. They could launch an easy way to link the mods to caves, or something, to fix this, official Ultroman's reply sums it up pretty well, but I'd like to also point out that it isn't "caves" that cause the issue. it's whenever the world isn't being hosted client-side (if i'm using the terminology correctly) Running any world on a dedicated server, even without caves, will run into all of the same issues. 1 Link to comment Share on other sites More sharing options...
MrDoge124 Posted May 4, 2020 Author Share Posted May 4, 2020 I got it to work. I asked a friend and we fixed it. So while poking around at another character, we discovered differences in the code that allowed us to reverse engineer a solution. With the error message telling us that “Inst” was a null value. Initially we thought that Inst was always in reference to the player whenever it’s called. THIS IS NOT THE CASE. We then found that whenever we declared a function, "Inst" was not declared. AddModRPCHandler(“Green”,"GREEN_STUN", function(---INST IS MISSING HERE---) We changed “Inst” to “player” just to make the code more readable in the future and then changed any reference to Inst into player. In addition to this, several functions were missing declarations which we fixed by adding player. AddModRPCHandler(“Green”,"GREEN_STUN", function(player) Spoiler TheInput = GLOBAL.TheInput local KEY_Z = GLOBAL.KEY_Z -- This function is rather complicated. You don't need to change anything in here. local function ApplyBuff(buffData, instToBuff, ents) --print(ents) local buffUniqueName = buffData.uniqueName -- Cancel any existing duplicate timed buff. if instToBuff[buffUniqueName.."Task"] ~= nil then buffData.removeFunction(instToBuff, ents) instToBuff[buffUniqueName.."Task"]:Cancel() instToBuff[buffUniqueName.."Task"] = nil end -- Make sure that our buff is removed BEFORE the entity is saved (the server is closed or player quits). -- This is only necessary if you change variables which are saved, like current health, health-penalty, etc. -- Without it, you could apply a max-health buff, quit before it ran out, rejoin, and you would have kept -- the extra max health! local buffOnSave = function(self, player, data) if player[buffUniqueName.."Task"] ~= nil then buffData.removeFunction(player, ents) player[buffUniqueName.."Task"]:Cancel() player[buffUniqueName.."Task"] = nil end end if instToBuff.OnSave ~= nil then local oldOnSave = instToBuff.OnSave instToBuff.OnSave = function(self, player, data) buffOnSave(self, player, data) oldOnSave(self, player, data) end else instToBuff.OnSave = buffOnSave end -- Apply the buff. buffData.applyFunction(instToBuff, ents) -- Set up removal after a certain amount of time. instToBuff[buffUniqueName.."Task"] = instToBuff:DoTaskInTime(buffData.duration, function(player) buffData.removeFunction(player, ents) player[buffUniqueName.."Task"] = nil end) end -- Now to make some buffs and put them in a Buffs-dictionary. local Buffs = {"stunbuff",} -- This function creates a new buff-data object and adds it to the Buffs-dictionary -- with the uniqueName as key. local function CreateBuff(uniqueName, duration, applyFunction, removeFunction) local newBuff = {} newBuff.uniqueName = uniqueName newBuff.duration = duration newBuff.applyFunction = applyFunction newBuff.removeFunction = removeFunction Buffs[uniqueName] = newBuff end -- This is an example of how to use the CreateBuff() function to create a new buff. CreateBuff("stunbuff", 5.0, function(player, ents) -- Apply all your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them.-- Store the current maxhealth in a variable. -- Add 0% speed boost in all situations for i, ent in ipairs(ents) do --local ds = ent.entity:GetDebugString() --local tagsstr = string.match(ds, "Tags: ([^\n]+)\n") --print(tagsstr) ent.components.locomotor:SetExternalSpeedMultiplier(player, "stunkey", 0) if ent.brain then ent.brain:Stop() end end end, function(player, ents) -- Revert your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them. -- Remove speed bonus. for i, ent in ipairs(ents) do ent.components.locomotor:RemoveExternalSpeedMultiplier(player, "stunkey") if ent.brain then ent.brain:Start() end end end ) AddModRPCHandler("Green", "GREEN_STUN", function(player) local x, y, z = player.Transform:GetWorldPosition() local range = 5 local ents = TheSim:FindEntities(x, y, z, range, { "_combat"}, { "player", "playermerm", "playermonster", "structure", "INLIMBO", "playermonster", "NOCLICK"}, {"hostile", "pig", "merm", "monster", "prey", "animal", "bee",}) --Find Entity nearby if not chargeincooldown and player.components.sanity.current > 10 and table.getn(ents) > 0 then --If chargeincooldown is false and current sanity is larger than 10 and there is more that 0 entities nearby chargeincooldown = true --Disable the move by starting the cooldown ApplyBuff(Buffs["stunbuff"], player, ents) --Run the apply buff function, inputting the entity table. God only knows how the rest of the function works. print("buff applied") player.components.sanity.current = player.components.sanity.current - 10 --Remove 10 sanity player.SoundEmitter:PlaySound("dontstarve/characters/green/stun") player.Light:SetIntensity(0.75) player.Light:SetFalloff(.1) player.Light:SetRadius(1.5)--Deal with lighting player:DoTaskInTime(0.2, function() player.Light:Enable (false)--Hide light after 1 second end) --Reset everything after 15 seconds player:DoTaskInTime(480, function() print("recharged") player.Light:SetIntensity(.75) player.Light:SetFalloff(.5) player.Light:SetRadius(0.8) player.Light:Enable (true) chargeincooldown = false end) end end) local greenhandlers = {} AddPlayerPostInit(function(player) -- We hack player:DoTaskInTime(0, function() -- We check if the character is ourselves -- So if another green player joins, we don't get the handlers if player == GLOBAL.ThePlayer then -- If we are green if player.prefab == "green" then -- We create and store the key handlers greenhandlers[1] = TheInput:AddKeyDownHandler(KEY_Z, function() SendModRPCToServer(MOD_RPC["Green"]["GREEN_STUN"]) end) -- If not, we go to the handlerslist and empty it -- This is to avoid having the handlers if we switch characters in wilderness -- If it's already empty, nothing changes for k, v in pairs(greenhandlers) do greenhandlers[k] = nil end end end end) end) Thanks for the help! 1 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