Mario384 Posted June 9, 2015 Share Posted June 9, 2015 Okay, so basically in my mod I've been trying to reference things like Health or even the Leader component, and it works for the server hoster, but not for those who connect. Is there a way around this dilemma? Is there to refer to Health or other components for clients? Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/ Share on other sites More sharing options...
Kzisor Posted June 9, 2015 Share Posted June 9, 2015 @Mario384, clients do not have components, they have replicas. Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/#findComment-645608 Share on other sites More sharing options...
Mario384 Posted June 9, 2015 Author Share Posted June 9, 2015 (edited) @Kzisor, so there's a replica for every component? How can I refer to them? Edited June 9, 2015 by Mario384 Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/#findComment-645611 Share on other sites More sharing options...
DarkXero Posted June 9, 2015 Share Posted June 9, 2015 @Mario384, Some components are client side, like playercontroller, playeractionpicker, playertargetindicator, and talker.You can see this if you join a dedicated server and use:for k, v in pairs(ThePlayer.components) do print(k, v) endThe components that get a replica are the ones in REPLICATABLE_COMPONENTS in entityreplica.lua.You can extend this table via the mod api function AddReplicableComponent(name). So, what are you specifically trying to do?Depending on that, you can refer to a replica via inst.replica.health for example. But you can't currently do, say, get client side, the health number a spider has.Because since clients don't do anything with that number, Klei didn't make it leave the server. Leader does not have a replica, so you will have to make a replica yourself.Or make net variables elsewhere in the code. But we need to know what we are dealing with here. Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/#findComment-645615 Share on other sites More sharing options...
Mario384 Posted June 9, 2015 Author Share Posted June 9, 2015 (edited) @Mario384, Some components are client side, like playercontroller, playeractionpicker, playertargetindicator, and talker.You can see this if you join a dedicated server and use:for k, v in pairs(ThePlayer.components) do print(k, v) endThe components that get a replica are the ones in REPLICATABLE_COMPONENTS in entityreplica.lua.You can extend this table via the mod api function AddReplicableComponent(name). So, what are you specifically trying to do?Depending on that, you can refer to a replica via inst.replica.health for example. But you can't currently do, say, get client side, the health number a spider has.Because since clients don't do anything with that number, Klei didn't make it leave the server. Leader does not have a replica, so you will have to make a replica yourself.Or make net variables elsewhere in the code. But we need to know what we are dealing with here.local function OnKeyAbility(inst, data) if data.inst == ThePlayer then if data.key == KEY_X then if TheWorld.ismastersim then inst:RemoveTag("werepig") inst:AddTag("guard") inst:SetStateGraph("SGpigplayer") inst.AnimState:SetBuild("pig_guard_build") if inst.components.hauntable then inst.components.hauntable.haunted = false inst.components.hauntable.cooldown_on_successful_haunt = true end inst.components.combat:SetDefaultDamage(TUNING.PIG_GUARD_DAMAGE) inst.components.combat:SetAttackPeriod(TUNING.PIG_GUARD_ATTACK_PERIOD) inst.components.locomotor.runspeed = TUNING.PIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.PIG_WALK_SPEED inst.components.health:DoDelta(-40, nil, nil, nil, nil, true) inst.components.lootdropper:SetLoot({}) inst.components.lootdropper:AddRandomLoot("meat",3) inst.components.lootdropper:AddRandomLoot("pigskin",1) inst.components.lootdropper.numrandomloot = 1 inst.components.trader:Enable() inst.components.talker:StopIgnoringAll() inst.components.follower:SetLeader(nil) inst.components.combat:SetHurtSound(nil) else inst:RemoveTag("werepig") inst:AddTag("guard") inst:SetBrain(guardbrain) inst:SetStateGraph("SGpigplayer") inst.AnimState:SetBuild("pig_guard_build") if inst.components.hauntable then inst.components.hauntable.haunted = false inst.components.hauntable.cooldown_on_successful_haunt = true end inst.components.combat:SetDefaultDamage(TUNING.PIG_GUARD_DAMAGE) inst.components.combat:SetAttackPeriod(TUNING.PIG_GUARD_ATTACK_PERIOD) inst.components.locomotor.runspeed = TUNING.PIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.PIG_WALK_SPEED inst.components.lootdropper:SetLoot({}) inst.components.lootdropper:AddRandomLoot("meat",3) inst.components.lootdropper:AddRandomLoot("pigskin",1) inst.components.lootdropper.numrandomloot = 1 inst.components.trader:Enable() inst.components.talker:StopIgnoringAll() inst.components.follower:SetLeader(nil) inst.components.combat:SetHurtSound(nil) end end endendAlright, here's a slather of code. See, originally in the beginning it checked to see if the player's a health was above 41, and then would exocute it. While this worked for the server hoster, it would crash clients. It also crashed due to *inst.components.health:DoDelta(-40, nil, nil, nil, nil, true)* being htere, so I had to set up this instead. So, if I understand what you're saying, if I put *inst.replica.health:DoDelta(-40, nil, nil, nil, nil, true)* in my second part, it will function? Ad if so, how can I check for one's current replica health without crashing the game? Edited June 9, 2015 by Mario384 Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/#findComment-645617 Share on other sites More sharing options...
DarkXero Posted June 9, 2015 Share Posted June 9, 2015 @Mario384, That triggers when the player presses any key, right?But only activates with the KEY_X. You don't need to run any replica changes or anything, you only need the client to trigger a code change in the server. Imagine if one client could run code that modifies replicas and that info gets to the server.Cheating galore, you wouldn't need a mod that allows that. As such, what you do is put the server code inside a AddModRPCHandler.And inside a OnKeyAbility, you put a SendModRPC, so the client tells the server to do something.AddModRPCHandler(modname, "triggerchange", function(player) local inst = player -- code between "if TheWorld.ismastersim then" and "else" goes hereend)local function OnKeyAbility(inst, data) if inst == GLOBAL.ThePlayer and data.key == GLOBAL.KEY_X then SendModRPCToServer(MODRPC[modname]["triggerchange"]) endendThe OnKeyAbility will presumably be handled by a key event, yes? Also, there's no such DoDelta function in health_replica, you can check what you can use from there.In most cases, nothing, since non player prefabs have no classifieds. Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/#findComment-645636 Share on other sites More sharing options...
Mario384 Posted June 9, 2015 Author Share Posted June 9, 2015 (edited) @Mario384, That triggers when the player presses any key, right?But only activates with the KEY_X. You don't need to run any replica changes or anything, you only need the client to trigger a code change in the server. Imagine if one client could run code that modifies replicas and that info gets to the server.Cheating galore, you wouldn't need a mod that allows that. As such, what you do is put the server code inside a AddModRPCHandler.And inside a OnKeyAbility, you put a SendModRPC, so the client tells the server to do something.AddModRPCHandler(modname, "triggerchange", function(player) local inst = player -- code between "if TheWorld.ismastersim then" and "else" goes hereend)local function OnKeyAbility(inst, data) if inst == GLOBAL.ThePlayer and data.key == GLOBAL.KEY_X then SendModRPCToServer(MODRPC[modname]["triggerchange"]) endendThe OnKeyAbility will presumably be handled by a key event, yes? Also, there's no such DoDelta function in health_replica, you can check what you can use from there.In most cases, nothing, since non player prefabs have no classifieds. Okay, the code I posted above was most likely not the best example now I look at it. See, I have Z, X, and C usually do this:local TAUNT = GLOBAL.Action()TAUNT.str = "Taunt"TAUNT.id = "TAUNT"TAUNT.fn = function(act) if not act.target:HasTag("busy") then act.target.sg:GoToState("taunt")endendAddAction(TAUNT) local ABILITY = GLOBAL.Action()ABILITY.str = "Ability"ABILITY.id = "ABILITY"ABILITY.fn = function(act) if not act.target:HasTag("busy") then act.target.sg:GoToState("ability")endendAddAction(ABILITY)local SECONDARY = GLOBAL.Action()SECONDARY.str = "Secondary"SECONDARY.id = "SECONDARY"SECONDARY.fn = function(act) if not act.target:HasTag("busy") then act.target.sg:GoToState("secondary")endendAddAction(SECONDARY) And a normal mob prefab would have this :local function OnKeyTaunt(inst, data) if data.inst == ThePlayer then if data.key == KEY_Z then if TheWorld.ismastersim then BufferedAction(inst, inst, ACTIONS.TAUNT):Do() -- Since we are the server, do the action on the server. else SendRPCToServer(RPC.DoWidgetButtonAction, ACTIONS.TAUNT.code, inst, ACTIONS.TAUNT.mod_name) end end endendlocal function OnKeyAbility(inst, data) if data.inst == ThePlayer then if data.key == KEY_X then if TheWorld.ismastersim then BufferedAction(inst, inst, ACTIONS.ABILITY):Do() -- Since we are the server, do the action on the server. else SendRPCToServer(RPC.DoWidgetButtonAction, ACTIONS.ABILITY.code, inst, ACTIONS.ABILITY.mod_name) end end endendlocal function OnKeySecondary(inst, data) if data.inst == ThePlayer then if data.key == KEY_C then if TheWorld.ismastersim then BufferedAction(inst, inst, ACTIONS.SECONDARY):Do() -- Since we are the server, do the action on the server. else SendRPCToServer(RPC.DoWidgetButtonAction, ACTIONS.SECONDARY.code, inst, ACTIONS.SECONDARY.mod_name) end end endendBut, that part of code from last post was from my pigplayer prefab. Here's the full code:local function OnKeyTaunt(inst, data) if data.inst == ThePlayer then if data.key == KEY_Z then if TheWorld.ismastersim then inst:RemoveTag("werepig") inst:RemoveTag("guard") inst:SetStateGraph("SGpigplayer") inst.AnimState:SetBuild("pig_build") if inst.components.hauntable then inst.components.hauntable.haunted = false inst.components.hauntable.cooldown_on_successful_haunt = true end inst.components.combat:SetDefaultDamage(TUNING.PIG_DAMAGE) inst.components.combat:SetAttackPeriod(TUNING.PIG_ATTACK_PERIOD) inst.components.combat:SetKeepTargetFunction(NormalKeepTargetFn) inst.components.locomotor.runspeed = TUNING.PIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.PIG_WALK_SPEED inst.components.lootdropper:SetLoot({}) inst.components.lootdropper:AddRandomLoot("meat",3) inst.components.lootdropper:AddRandomLoot("pigskin",1) inst.components.lootdropper.numrandomloot = 1 inst.components.trader:Enable() inst.components.talker:StopIgnoringAll() inst.components.combat:SetHurtSound(nil)else inst:RemoveTag("werepig") inst:RemoveTag("guard") inst:SetStateGraph("SGpigplayer") inst.AnimState:SetBuild("pig_build") if inst.components.hauntable then inst.components.hauntable.haunted = false inst.components.hauntable.cooldown_on_successful_haunt = true end inst.components.combat:SetDefaultDamage(TUNING.PIG_DAMAGE) inst.components.combat:SetAttackPeriod(TUNING.PIG_ATTACK_PERIOD) inst.components.combat:SetKeepTargetFunction(NormalKeepTargetFn) inst.components.locomotor.runspeed = TUNING.PIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.PIG_WALK_SPEED inst.components.lootdropper:SetLoot({}) inst.components.lootdropper:AddRandomLoot("meat",3) inst.components.lootdropper:AddRandomLoot("pigskin",1) inst.components.lootdropper.numrandomloot = 1 inst.components.trader:Enable() inst.components.talker:StopIgnoringAll() inst.components.combat:SetHurtSound(nil) end end endendlocal function OnKeyAbility(inst, data) if data.inst == ThePlayer then if data.key == KEY_X then if TheWorld.ismastersim then inst:RemoveTag("werepig") inst:AddTag("guard") inst:SetStateGraph("SGpigplayer") inst.AnimState:SetBuild("pig_guard_build") if inst.components.hauntable then inst.components.hauntable.haunted = false inst.components.hauntable.cooldown_on_successful_haunt = true end inst.components.combat:SetDefaultDamage(TUNING.PIG_GUARD_DAMAGE) inst.components.combat:SetAttackPeriod(TUNING.PIG_GUARD_ATTACK_PERIOD) inst.components.locomotor.runspeed = TUNING.PIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.PIG_WALK_SPEED inst.components.health:DoDelta(-40, nil, nil, nil, nil, true) inst.components.lootdropper:SetLoot({}) inst.components.lootdropper:AddRandomLoot("meat",3) inst.components.lootdropper:AddRandomLoot("pigskin",1) inst.components.lootdropper.numrandomloot = 1 inst.components.trader:Enable() inst.components.talker:StopIgnoringAll() inst.components.follower:SetLeader(nil) inst.components.combat:SetHurtSound(nil) else inst:RemoveTag("werepig") inst:AddTag("guard") inst:SetBrain(guardbrain) inst:SetStateGraph("SGpigplayer") inst.AnimState:SetBuild("pig_guard_build") if inst.components.hauntable then inst.components.hauntable.haunted = false inst.components.hauntable.cooldown_on_successful_haunt = true end inst.components.combat:SetDefaultDamage(TUNING.PIG_GUARD_DAMAGE) inst.components.combat:SetAttackPeriod(TUNING.PIG_GUARD_ATTACK_PERIOD) inst.components.locomotor.runspeed = TUNING.PIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.PIG_WALK_SPEED inst.components.lootdropper:SetLoot({}) inst.components.lootdropper:AddRandomLoot("meat",3) inst.components.lootdropper:AddRandomLoot("pigskin",1) inst.components.lootdropper.numrandomloot = 1 inst.components.trader:Enable() inst.components.talker:StopIgnoringAll() inst.components.follower:SetLeader(nil) inst.components.combat:SetHurtSound(nil) end end endendlocal function OnKeySecondary(inst, data) if data.inst == ThePlayer then if data.key == KEY_C then if TheWorld.ismastersim then inst:AddTag("werepig") inst:RemoveTag("guard") inst:SetStateGraph("SGwerepigplayer") inst.AnimState:SetBuild("werepig_build") inst.components.combat:SetDefaultDamage(TUNING.WEREPIG_DAMAGE) inst.components.combat:SetAttackPeriod(TUNING.WEREPIG_ATTACK_PERIOD) inst.components.locomotor.runspeed = TUNING.WEREPIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.WEREPIG_WALK_SPEED inst.components.health:DoDelta(-40, nil, nil, nil, nil, true) inst.components.lootdropper:SetLoot({"meat","meat", "pigskin"}) inst.components.lootdropper.numrandomloot = 0 inst.components.trader:Disable() inst.components.follower:SetLeader(nil) inst.components.talker:IgnoreAll() inst.components.combat:SetHurtSound("dontstarve/creatures/werepig/hurt") else inst:AddTag("werepig") inst:RemoveTag("guard") inst:SetStateGraph("SGwerepigplayer") inst.AnimState:SetBuild("werepig_build") inst.components.combat:SetDefaultDamage(TUNING.WEREPIG_DAMAGE) inst.components.combat:SetAttackPeriod(TUNING.WEREPIG_ATTACK_PERIOD) inst.components.locomotor.runspeed = TUNING.WEREPIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.WEREPIG_WALK_SPEED inst.components.lootdropper:SetLoot({"meat","meat", "pigskin"}) inst.components.lootdropper.numrandomloot = 0 inst.components.trader:Disable() inst.components.follower:SetLeader(nil) inst.components.talker:IgnoreAll() inst.components.combat:SetHurtSound("dontstarve/creatures/werepig/hurt") end end endend local common_postinit = function(inst) inst.soundsname = "wilson" inst:AddComponent("keyhandler") inst:ListenForEvent("keypressed", OnKeyTaunt) inst:ListenForEvent("keypressed", OnKeyAbility) inst:ListenForEvent("keypressed", OnKeySecondary) inst.MiniMapEntity:SetIcon( "pigplayer.tex" ) inst:DoTaskInTime(0, function() if ThePlayer then ThePlayer:EnableMovementPrediction(false) endend)endFor pig, Taunt made him a regular pig, Ability made him a pig guard and USED TO check to see if his health was above 40 before he could trigger the ability, and took a health penalty, and Secondary makes him a werepig and also used to check for health and do the same penalty. My main question was if I could apply the penalty for both client and serverhosting players, along with checking if his health was over a certain amount before activating it. Edited June 9, 2015 by Mario384 Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/#findComment-645644 Share on other sites More sharing options...
DarkXero Posted June 9, 2015 Share Posted June 9, 2015 @Mario384, yeah, you just do everything in the server. If you modify the penalty of the health component of a player entity in the server then it will trigger client changes, so you don't have to worry there. Your normal mob prefab code is what should be happening: if you are the server, you run code, if not, you send a RPC to make the server run the code. When the RPC arrives, you check for the health and see if you can apply the penalty. Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/#findComment-645662 Share on other sites More sharing options...
Mario384 Posted June 10, 2015 Author Share Posted June 10, 2015 Thanks DarkXero and Kzisor, I appreciate the help. Link to comment https://forums.kleientertainment.com/forums/topic/55035-what-components-do-clients-have/#findComment-645682 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