Hornete Posted July 13, 2019 Share Posted July 13, 2019 Hello everyone! I have a couple states that are activated by an action, they work perfectly fine if you don't have lag compensation enabled, If you do however.... It does not work! It works for hosts with lag compensation, but If you are a client or on a caves server and have lag compensation enabled, the state won't activate and instead the character just moves to the mouse. It does work without the lag compensation enabled. AddStategraphState("wilson", State { name = "dodge", tags = {"busy", "evade","no_stun"}, onenter = function(inst) inst.sg:SetTimeout(0.25) -- 0.15 inst.components.locomotor:Stop() inst.AnimState:PlayAnimation("slide_pre") inst.AnimState:PushAnimation("slide_loop") inst.SoundEmitter:PlaySound("dontstarve_DLC003/characters/wheeler/slide") inst.Physics:SetMotorVelOverride(20,0,0) inst.components.locomotor:EnableGroundSpeedMultiplier(false) inst.components.health:SetInvincible(true) inst:PerformBufferedAction() if GLOBAL.TheNet:GetServerGameMode() == "lavaarena" then COMMON_FNS.DoFrontAOE(inst, 5, 0, 3.25, "strong", nil) inst:DoTaskInTime(0.5, function() COMMON_FNS.DoFrontAOE(inst, 5, 0, 3.25, "strong", nil) end) end inst.last_dodge_time = GLOBAL.GetTime() end, ontimeout = function(inst) inst.sg:GoToState("dodge_pst") end, onexit = function(inst) inst.components.locomotor:EnableGroundSpeedMultiplier(true) inst.Physics:ClearMotorVelOverride() inst.components.locomotor:Stop() end, } ) AddStategraphState("wilson", State { name = "dodge_pst", tags = {"evade","no_stun"}, onenter = function(inst) inst.AnimState:PlayAnimation("slide_pst") inst.components.locomotor:SetBufferedAction(nil) inst.components.health:SetInvincible(false) if GLOBAL.TheNet:GetServerGameMode() == "lavaarena" then if inst.laserdodge ~= nil then inst.laserdodge:Cancel() inst.laserdodge = nil end end end, events = { EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ), } } ) AddStategraphEvent("wilson", EventHandler("locomote", function(inst, data) if inst.sg:HasStateTag("busy") then return end local is_moving = inst.sg:HasStateTag("moving") local should_move = inst.components.locomotor:WantsToMoveForward() local bufferedaction = inst:GetBufferedAction() if inst.sg:HasStateTag("bedroll") or inst.sg:HasStateTag("tent") or inst.sg:HasStateTag("waking") then -- wakeup on locomote if inst.sleepingbag ~= nil and inst.sg:HasStateTag("sleeping") then inst.sleepingbag.components.sleepingbag:DoWakeUp() inst.sleepingbag = nil end elseif bufferedaction and bufferedaction.action.id == "DODGE" then inst.sg:GoToState("dodge") elseif is_moving and not should_move then inst.sg:GoToState("run_stop") elseif not is_moving and should_move then inst.sg:GoToState("run_start") elseif data.force_idle_state and not (is_moving or should_move or inst.sg:HasStateTag("idle")) then inst.sg:GoToState("idle") end end) ) These states are called when you right click doing the action. I'd appreciate any help!, Also I'd like a way to have the action used while the player is running or attacking. However you must pause in order to do the action. How can I make it so that the action can be performed whilst running or attacking? Thanks for your help! Link to comment Share on other sites More sharing options...
Hornete Posted July 14, 2019 Author Share Posted July 14, 2019 bump a wump Link to comment Share on other sites More sharing options...
Ultroman Posted July 14, 2019 Share Posted July 14, 2019 Sorry, m8. I have very, very limited insight into the finer details of the action system. I hope some of the veterans or developers can chime in on this one. Link to comment Share on other sites More sharing options...
ksaab Posted July 14, 2019 Share Posted July 14, 2019 There is "wilson_client" stategraph. The game uses it if lag compenstion is enabled on client (when you're playing as host without caves you are actually not a client and don't use this stategraph). It is almost the same but doesn't contain any game logic. The solution for the problem — you need to add lightweight versions of your states to "wilson_client". Link to comment Share on other sites More sharing options...
Hornete Posted July 14, 2019 Author Share Posted July 14, 2019 3 hours ago, ksaab said: There is "wilson_client" stategraph. The game uses it if lag compenstion is enabled on client (when you're playing as host without caves you are actually not a client and don't use this stategraph). It is almost the same but doesn't contain any game logic. The solution for the problem — you need to add lightweight versions of your states to "wilson_client". Thank you so much!, what should I exactly remove? I copied and pasted everything and added it to the client stategraph, Removed the the SetInvincible line, The dodge works perfectly but when I move after that. I teleport to the original position from where I dodged. Again Thank you so much. Link to comment Share on other sites More sharing options...
ksaab Posted July 14, 2019 Share Posted July 14, 2019 (edited) Your character moves after dodging because of inst.Physics:SetMotorVelOverride(20,0,0). Client draws fake position for character, but real doesn't change (actually it doesn't work at all). Any client state should contain animation and tag things only. AddStategraphState("wilson_client", State { name = "dodge", tags = {"busy", "evade", "no_stun"}, onenter = function(inst) inst.components.locomotor:Stop() inst.AnimState:PlayAnimation("slide_pre", false) --only pre animation, the slide animation command must come from server inst:PerformPreviewBufferedAction() --this thing says to server "hey man, I'm doing something" inst.sg:SetTimeout(2) end, --[[I use this chunk, but I don't have idea what it really does. Sometime state doesn't work without "onupdate". It requires "doing" tag for server and client states onupdate = function(inst) if inst:HasTag("doing") then if inst.entity:FlattenMovementPrediction() then inst.sg:GoToState("idle", "noanim") end elseif inst.bufferedaction == nil then inst.sg:GoToState("idle") end end, ]]-- --timeout happens only if player have a lag ontimeout = function(inst) inst:ClearBufferedAction() inst.sg:GoToState("idle") end, ) I think the second state is not requied for the client stategraph. Edited July 14, 2019 by ksaab Link to comment Share on other sites More sharing options...
Hornete Posted July 15, 2019 Author Share Posted July 15, 2019 6 hours ago, ksaab said: Your character moves after dodging because of inst.Physics:SetMotorVelOverride(20,0,0). Client draws fake position for character, but real doesn't change (actually it doesn't work at all). Any client state should contain animation and tag things only. AddStategraphState("wilson_client", State { name = "dodge", tags = {"busy", "evade", "no_stun"}, onenter = function(inst) inst.components.locomotor:Stop() inst.AnimState:PlayAnimation("slide_pre", false) --only pre animation, the slide animation command must come from server inst:PerformPreviewBufferedAction() --this thing says to server "hey man, I'm doing something" inst.sg:SetTimeout(2) end, --[[I use this chunk, but I don't have idea what it really does. Sometime state doesn't work without "onupdate". It requires "doing" tag for server and client states onupdate = function(inst) if inst:HasTag("doing") then if inst.entity:FlattenMovementPrediction() then inst.sg:GoToState("idle", "noanim") end elseif inst.bufferedaction == nil then inst.sg:GoToState("idle") end end, ]]-- --timeout happens only if player have a lag ontimeout = function(inst) inst:ClearBufferedAction() inst.sg:GoToState("idle") end, ) I think the second state is not requied for the client stategraph. AddStategraphState("wilson_client", State { name = "dodge", tags = {"busy", "evade", "no_stun"}, onenter = function(inst) inst.components.locomotor:Stop() inst.AnimState:PlayAnimation("slide_pre", false) inst:PerformPreviewBufferedAction() inst.sg:SetTimeout(2) end, onupdate = function(inst) --I've tried with and without this if inst:HasTag("doing") then if inst.entity:FlattenMovementPrediction() then inst.sg:GoToState("idle", "noanim") end elseif inst.bufferedaction == nil then inst.sg:GoToState("idle") end end, ontimeout = function(inst) inst:ClearBufferedAction() inst.sg:GoToState("idle") end, } ) AddStategraphEvent("wilson_client", --I need this or the Dodge won't happen at all EventHandler("locomote", function(inst) if inst.sg:HasStateTag("busy") or inst:HasTag("busy") then return end local is_moving = inst.sg:HasStateTag("moving") local should_move = inst.components.locomotor:WantsToMoveForward() local bufferedaction = inst:GetBufferedAction() if inst:HasTag("sleeping") then if should_move and not inst.sg:HasStateTag("waking") then inst.sg:GoToState("wakeup") end elseif not inst.entity:CanPredictMovement() then if not inst.sg:HasStateTag("idle") then inst.sg:GoToState("idle") end elseif bufferedaction and bufferedaction.action.id == "DODGE" then inst.sg:GoToState("dodge") elseif is_moving and not should_move then inst.sg:GoToState("run_stop") elseif not is_moving and should_move then inst.sg:GoToState("run_start") end end) ) Sorry for bothering you again, but now the player won't even move, and instead does the dodge animation in its place and instantly reverts to the idle state. Thank you so much for your help. Link to comment Share on other sites More sharing options...
ksaab Posted July 15, 2019 Share Posted July 15, 2019 AddStategraphState("wilson", State { name = "dodge_pre", tags = {"doing", "busy", "evade", "no_stun"}, onenter = function(inst) inst.components.locomotor:Stop() inst.AnimState:PlayAnimation("parry_pre", false) end, events = { EventHandler("animover", function(inst) inst.sg:GoToState("dodge") end), } }) AddStategraphState("wilson", State { name = "dodge", tags = {"doing", "evade", "no_stun", "nopredict", "nomorph",}, onenter = function(inst) inst.AnimState:PlayAnimation("parry_loop", true) inst.components.health:SetInvincible(true) inst.components.locomotor:EnableGroundSpeedMultiplier(true) inst.last_dodge_time = GLOBAL.GetTime() inst.Physics:SetMotorVel(-20,0,0) --this should be moved to the action code ----------------------------------------- if GLOBAL.TheNet:GetServerGameMode() == "lavaarena" then COMMON_FNS.DoFrontAOE(inst, 5, 0, 3.25, "strong", nil) inst:DoTaskInTime(0.5, function() COMMON_FNS.DoFrontAOE(inst, 5, 0, 3.25, "strong", nil) end) if inst.laserdodge ~= nil then inst.laserdodge:Cancel() inst.laserdodge = nil end end ----------------------------------------- inst.SoundEmitter:PlaySound("dontstarve_DLC003/characters/wheeler/slide") inst:PerformBufferedAction() --not the best idea --because of latency character will dash for shorter distance then you're expecting --will be much better to calculate target postion and use onupdate until character reaches it; --after fire your custom event and catch it in EventHandler("yourevent", function() place code from ontimeout end) inst.sg:SetTimeout(0.25) end, events = { EventHandler("animqueueover", function(inst) --this happens only after inst.AnimState:PlayAnimation("parry_pst", false) will be complete if inst.AnimState:AnimDone() then inst.sg:GoToState("idle") end end), }, ontimeout = function(inst) inst.Physics:SetMotorVel(0, 0, 0) inst.components.health:SetInvincible(false) inst.components.locomotor:EnableGroundSpeedMultiplier(false) inst.AnimState:PlayAnimation("parry_pst", false) end, onexit = function(inst) --need to double this code — case when we will leave the state before timeout inst.Physics:SetMotorVel(0, 0, 0) inst.components.health:SetInvincible(false) inst.components.locomotor:EnableGroundSpeedMultiplier(false) end, }) AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.DODGE, "dodge_pre")) AddStategraphState("wilson_client", State { name = "dodge_pre", tags = {"doing", "busy", "evade", "no_stun"}, onenter = function(inst) inst.components.locomotor:Stop() inst.AnimState:PlayAnimation("parry_pre", false) inst.AnimState:PushAnimation("parry_loop", true) inst:PerformPreviewBufferedAction() inst.sg:SetTimeout(2) end, onupdate = function(inst) if inst:HasTag("doing") then if inst.entity:FlattenMovementPrediction() then inst.sg:GoToState("idle", "noanim") end elseif inst.bufferedaction == nil then inst.sg:GoToState("idle") end end, ontimeout = function(inst) inst:ClearBufferedAction() inst.sg:GoToState("idle") end, } ) AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.DODGE, "dodge_pre")) --actions collectors, dodge will work with any equipped weapon. Not good but it's just an example --I'm not sure overriding onlocomote event handler is a good idea --check out the wortox prefab if you want use dodge like wortox's soul hop AddComponentAction("EQUIPPED", "weapon", function(inst, doer, target, actions, right) if right then table.insert(actions, ACTIONS.DODGE) end end) AddComponentAction("POINT", "weapon", function(inst, doer, pos, actions, right) if right then table.insert(actions, ACTIONS.DODGE) end end) don't forget to rename animation Link to comment Share on other sites More sharing options...
Hornete Posted July 15, 2019 Author Share Posted July 15, 2019 57 minutes ago, ksaab said: [snip snop] Thank you so much, but sadly it didn't work, The component action thing doesn't work and thats why I edit the locomotoe event. I'll try experimenting around with the states, thank you. Link to comment Share on other sites More sharing options...
ksaab Posted July 15, 2019 Share Posted July 15, 2019 AddAction("DODGE", "Dodge", function(act) act.doer:PushEvent("letsdododge", {pos = act.pos or Vector3(act.target.Transform:GetWorldPosition())}) return true end) ACTIONS.DODGE.distance = math.huge ACTIONS.DODGE.instant = true AddStategraphEvent("wilson", EventHandler("letsdododge", function(inst, data) inst.sg:GoToState("dodge_pre", data) end) ) I think you want something like this — use dodge while player is moving. It's a bit dirty-tricky and looks weird on clients. But the second could be fixed I suppose. Client-stategraph doesn't need any code at all. Other things from the previous post. Dodge direction should be handled in the "pre" state with data.pos. One more thing — pos = act.pos will work incorrect after RoT release. Klei has changed this filed. Check out bufferedaction.lua after update. Two more thing — 0.25 widnow is too short. Clients with high unstable ping will have problems (I did a parry spell with 0.5 seconds window in The Forge Battle Pack and recieved a lot of complaints) Link to comment Share on other sites More sharing options...
Hornete Posted July 16, 2019 Author Share Posted July 16, 2019 1 hour ago, ksaab said: snip Ok! I'm getting there, just a couple of problems 1. The dodge can be cancelled by moving, I thought the busy tag prevents this which I have? It's weird how I can cancel the dodge by moving, this didn't happen before 2. The dodge happens in the direction the character is facing, not the direction of the mouse 3. The Dodge text prompt does not dissapear after the action is done. Link to comment Share on other sites More sharing options...
ksaab Posted July 16, 2019 Share Posted July 16, 2019 1) Yep. Busy tag should help. 2) Dodge direction should be handled in the "pre" state with data.pos if data and data.pos then inst:ForceFacePoint(data.pos.x, 0, data.pos.z) end 3) Add conditions to action collectors. Something like this: if not inst:HasTag("busy") then Link to comment Share on other sites More sharing options...
Hornete Posted July 16, 2019 Author Share Posted July 16, 2019 9 hours ago, ksaab said: snip snop Busy tag helped! Thank you! 2. I put that code in but my character still dodges in the direction there facng 3. What do you mean action collectors? Sorry, i'm not familiar with that term 4. It works great with lag compensation turned on, but while im running and decide to dodge, my character teleports back for some reason. If i'm standing still, it works perfectly fine. 5. ontimeout = function(inst) inst.Physics:SetMotorVel(0, 0, 0) inst.components.health:SetInvincible(false) inst.components.locomotor:EnableGroundSpeedMultiplier(false) inst.AnimState:PlayAnimation("slide_pst", false) end, I wanna remove the busy tag here, does inst:RemoveStateTag("busy"), work? Link to comment Share on other sites More sharing options...
ksaab Posted July 16, 2019 Share Posted July 16, 2019 2) Did you add data as second argument for onenter function? 3) AddComponentAction functions. 4) I suppose a fix for this problem requires a dirty hook. I don't have a good solution for it. Try to add inst.Physics:Teleport(inst.Transform:GetWorldPosition()) to pre state. 5) It should. Link to comment Share on other sites More sharing options...
Hornete Posted July 16, 2019 Author Share Posted July 16, 2019 (edited) 1 hour ago, ksaab said: snip snop 2) Thank you! it worked! 3) AddComponentAction("EQUIPPED", "weapon", function(inst, doer, target, actions, right) if not inst:HasTag("busy") then if right then table.insert(actions, GLOBAL.ACTIONS.DODGE) end end end) AddComponentAction("POINT", "weapon", function(inst, doer, pos, actions, right) if not inst:HasTag("busy") then if right then table.insert(actions, GLOBAL.ACTIONS.DODGE) end end end) Is that correct? The prompt still appears, the prompt dissapears if your the host. 4. AddStategraphState("wilson", GLOBAL.State { name = "dodge_pre", tags = {"doing", "busy", "evade", "no_stun"}, onenter = function(inst, data) inst.components.locomotor:Stop() inst.AnimState:PlayAnimation("slide_pre", false) inst.Physics:Teleport(inst.Transform:GetWorldPosition()) if data and data.pos then inst:ForceFacePoint(data.pos.x, 0, data.pos.z) end end, events = { GLOBAL.EventHandler("animover", function(inst) inst.sg:GoToState("dodge") end), } }) I put it there, is that correct? Do I also need to put it in the client stategraph? 5. It crashed for me, RemoveStateTag is a nil value. Edited July 16, 2019 by Hornete Link to comment Share on other sites More sharing options...
ksaab Posted July 16, 2019 Share Posted July 16, 2019 3) Yes... busy tag doesn't sync... hmmm. Net variable? Anyway it's required if you want to add a cooldown for dodge. 4) Yep. But with this implementation you don't use client ctategraph at all. 5) You've lost sg — inst.sg:RemoveStateTag("busy") Link to comment Share on other sites More sharing options...
Hornete Posted July 16, 2019 Author Share Posted July 16, 2019 1 hour ago, ksaab said: 3)What's a net variable exactly? 4) So, I should remove the client state? It still isn't working, though thats with the client state 5) a new problem has rised, Whenever I have something equipped in my hand slot, There's no cooldown but when there isn't, theres still the regular 1.5 seconds of cooldown, AddComponentAction("EQUIPPED", "weapon", function(inst, doer, target, actions, right) if right then table.insert(actions, GLOBAL.ACTIONS.DODGE) end end) I suspect it has to do with this? Link to comment Share on other sites More sharing options...
ksaab Posted July 16, 2019 Share Posted July 16, 2019 3) Check out the forum, there is a pinned thread about them; 4) I offer variants to you. How you will implement dependng on your preferences. The last variant doesn't requie a client stategraph; 5) How do you use dodge without weapon? GetPointSpecialActions? Or key binding? How do you realize cooldown on the client side? You can remove my AddComponentAction if you don't need them. Link to comment Share on other sites More sharing options...
Mobbstar Posted July 17, 2019 Share Posted July 17, 2019 11 hours ago, Hornete said: What's a net variable exactly? On 23.12.2014 at 1:28 AM, rezecib said: Networked variables: Spoiler These are special variables that are synced over the network (exclusively from the server to the client, and not the other way around-- that's what RPCs are for), and that when they get changed it triggers an event on the client-- these are usually called "dirty" events, because they signal that any visuals that were relying on the value are now outdated (or "dirty") and need to be updated (or "cleaned"). Most of the game's net variables are a bit overwhelming to look at, but PeterA's The Hunt mod shows how to use them, and he also made a guide on all the network variables available. When setting up a network variable, there are several key considerations. They attach to a specific entity via the GUID, so choosing the right entity is important. You can either ride onto existing game entities, or you can create your own like the classifieds. Then you need to make sure that whatever events happen on the server are hooked up to setting the network variables. Then, if the client needs to know when a network variable has changed (usually ones that require a visual update as a result, as opposed to ones where the client just looks at the value when it needs to), you can specify an event to be triggered when the value changes. There's a file called "scripts/netvars.lua" that lists the exact netvars implemented. Link to comment Share on other sites More sharing options...
Hornete Posted July 17, 2019 Author Share Posted July 17, 2019 17 hours ago, ksaab said: snip 4) Ok, so I've put that line in and gotten rid of the client state, and it still teleports me back. With or without the client state, Thank you so much for all the help, I would have never solved this without you. 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