Jump to content

[Solved] Can't get EntityBehaviorHunger


Frepo

Recommended Posts

I'm just.... baffled. Trying to make the player unable to sleep when starving. Replaced the vanilla BlockBed (patched it with a /replace op on the /class) with my own to include the extra checks.
Just a couple of lines above, they get a behavior from the player to check tiredness. I'm trying to do the same to get the hunger behavior... but it turns up null somehow. The player should for sure have the behavior, since well... hunger is very much a thing for the player :) . It is this one from the RegisterDefaultEntityBehaviors. that the player entity is using, right?
image.png.ee7f619ef627dc6f77f240932880b5f5.png

.. still the behavior doesn't seem to exist in the player entity.

BlockFTBed

Spoiler
    internal class BlockFTBed : BlockBed
    {
        public override bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel)
        {
            if (!world.Claims.TryAccess(byPlayer, blockSel.Position, EnumBlockAccessFlags.Use))
            {
                return false;
            }
            BlockFacing facing = BlockFacing.FromCode(base.LastCodePart(0)).Opposite;
            BlockEntityBed beBed = world.BlockAccessor.GetBlockEntity((base.LastCodePart(1) == "feet") ? blockSel.Position.AddCopy(facing) : blockSel.Position) as BlockEntityBed;
            if (beBed == null)
            {
                return false;
            }
            // bed already taken
            if (beBed.MountedBy != null)
            {
                if (world.Side == EnumAppSide.Client)
                {
                    (this.api as ICoreClientAPI).TriggerIngameError(this, "cantsleep-bedtaken", Lang.Get("fregtech:cantsleep-bedtaken", Array.Empty<object>()));
                }
                return false;
            }
            // not tired
            EntityBehaviorTiredness ebt = byPlayer.Entity.GetBehavior("tiredness") as EntityBehaviorTiredness;
            if (ebt != null && ebt.Tiredness <= 8f)
            {
                if (world.Side == EnumAppSide.Client)
                {
                    (this.api as ICoreClientAPI).TriggerIngameError(this, "nottiredenough", Lang.Get("not-tired-enough", Array.Empty<object>()));
                }
                else
                {
                    byPlayer.Entity.TryUnmount();
                }
                return false;
            }
            // temporal storm
            if (this.api.World.Config.GetString("temporalStormSleeping", "0").ToInt(0) == 0 && this.api.ModLoader.GetModSystem<SystemTemporalStability>(true).StormStrength > 0f)
            {
                if (world.Side == EnumAppSide.Client)
                {
                    (this.api as ICoreClientAPI).TriggerIngameError(this, "cantsleep-tempstorm", Lang.Get("cantsleep-tempstorm", Array.Empty<object>()));
                }
                else
                {
                    byPlayer.Entity.TryUnmount();
                }
                return false;
            }
            // too hungry
            EntityBehaviorHunger ebh = byPlayer.Entity.GetBehavior<EntityBehaviorHunger>();
            //EntityBehaviorHunger ebh = byPlayer.Entity.GetBehavior("hunger") as EntityBehaviorHunger;
            //EntityBehaviorHunger ebh = (byPlayer as IServerPlayer).Entity.GetBehavior<EntityBehaviorHunger>();
            if (ebh != null && ebh.Saturation <= 1f)
            {
                if (world.Side == EnumAppSide.Client)
                {
                    (this.api as ICoreClientAPI).TriggerIngameError(this, "cantsleep-toohungry", Lang.Get("fregtech:cantsleep-toohungry", Array.Empty<object>()));
                }
                else
                {
                    byPlayer.Entity.TryUnmount();
                }
                return false;
            }
            // too cold
            // TODO...

            // in rain
            // TODO...

            return byPlayer.Entity.TryMount(beBed);
        }
    }

 

Has someone else dealt with this behavior? Who could maybe give me a hint here?

Edited by Frepo
Link to comment
Share on other sites

On 2/16/2023 at 7:28 AM, DArkHekRoMaNT said:

Hunger behavior only exists on the server, according to assets/game/entities/humanoid/player.json

I see... or... oh, I don know... I'm having a hard time wrapping my head around the client/server stuff. I mean, I understand that some code is only relevant for the client and vice versa. But I don't understand fully how to know when certain code is "visible" to one or the other (or both).

So the entire BlockBed class is only ever read by the client? And that's why the hunger is not "visible" there? This is tricky, usually the IDE tells me when something is out of scope or not visible due to protection levels and such.

So I guess what I need to do (from the client here) is tell the server "hey, I want you to give the saturation level of this player that's sleeping in this bed here". But how is that accomplished? I'm gonna search for some keywords here and investigate each place where the hunger is referenced/used/accessed, maybe things will clear up a bit.

Thanks for the hint thou, Dark!

Edited by Frepo
Link to comment
Share on other sites

14 minutes ago, Frepo said:

I see... or... oh, I don know... I'm having a hard time wrapping my head around the client/server stuff. I mean, I understand that some code is only relevant for the client and vice versa. But I don't understand fully how to know when certain code is "visible" to one or the other (or both).

So the entire BlockBed class is only ever read by the client? And that's why the hunger is not "visible" there? This is tricky, usually the IDE tells me when something is out of scope or not visible due to protection levels and such.

So I guess what I need to do (from the client here) is tell the server "hey, I want you to give the saturation level of this player that's sleeping in this bed here". But how is that accomplished? I'm gonna search for some keywords here and investigate each place where the hunger is referenced/used/accessed, maybe things will clear up a bit.

Thanks for the hint thou, Dark!

Most of the methods associated with the actions of the players (for example, interaction) are run twice. First on the client and then on the server.

Sometimes this requires you to explicitly indicate that the interaction on the client is successful and you need to repeat it on the server for sync. For example ref handling parameter or return value.

In this case, you need to skip processing on the client (by checking api or world.Side), return true or false (see the comment for function) and process it on the server side

Link to comment
Share on other sites

Ok, so this method, OnBlockInteractStart, is first run by the client, where the hunger behavior is not visible. Then the server runs it, where it is visible.

There are several checks now to see if the player is allowed to sleep:
Temporal storm
Tiredness
Exposed to rain
Too cold
Hunger (this one is the only one giving me trouble, the rest works fine)

So the client will only check storm, tiredness, rain and coldness, and maybe say "everything's fine here, let the player sleep" (return true).
But then the server checks with the inclusion of hunger
image.png.4a649b63343a906697b54ad93c107b87.png
and may say "no, it's not fine!" (return false).

What happens then? Will the player go to bed, but the sleeping mechanics won't kick in? How do we sync this?

Link to comment
Share on other sites

2 hours ago, Frepo said:

Will the player go to bed, but the sleeping mechanics won't kick in?

Yeah, that seems to be exacly what happens. Which could be good enough I guess. But I want it to behave consistently with the other restrictions, meaning the character wont lay down at all and instead the client recieves an error message.

How do I make the server tell the client not to allow the player to lay down?

Edited by Frepo
Link to comment
Share on other sites

11 hours ago, Frepo said:

Yeah, that seems to be exacly what happens. Which could be good enough I guess. But I want it to behave consistently with the other restrictions, meaning the character wont lay down at all and instead the client recieves an error message.

How do I make the server tell the client not to allow the player to lay down?

Have you tried canceling this on the server?

byPlayer.Entity.TryUnmount();
Link to comment
Share on other sites

Dark, my man! I've been sniffing around in that behavior before, but I was only there to see how to get the saturation level. I would never have thought there was such a connection (through the watchedattributes)... oooh thank you!!! God knows how much time you saved me!
image.thumb.png.880bdc6bbe883ceae088d970aa8504e2.png

Now... on to climb the next mountain; Making all players wake up if you run out of saturation while sleeping. And that (from what I can tell based on my limitied knowledge so far) doesn't seem possible without overriding the entire ModSleeping since it references BlockEntityBed in its WakeAllPlayers method. Meaning I must extend BlockEntityBed with my BlockEntityFTBed. And in BlockEntityBed are two cruicial methods i need to override (DidMount and DidUnmount) because the ticklistener is created there. But these methods are not marked as virtual, so I can't override them :(  ...I was so close.

Link to comment
Share on other sites

53 minutes ago, Frepo said:

Dark, my man! I've been sniffing around in that behavior before, but I was only there to see how to get the saturation level. I would never have thought there was such a connection (through the watchedattributes)... oooh thank you!!! God knows how much time you saved me!
image.thumb.png.880bdc6bbe883ceae088d970aa8504e2.png

Now... on to climb the next mountain; Making all players wake up if you run out of saturation while sleeping. And that (from what I can tell based on my limitied knowledge so far) doesn't seem possible without overriding the entire ModSleeping since it references BlockEntityBed in its WakeAllPlayers method. Meaning I must extend BlockEntityBed with my BlockEntityFTBed. And in BlockEntityBed are two cruicial methods i need to override (DidMount and DidUnmount) because the ticklistener is created there. But these methods are not marked as virtual, so I can't override them :(  ...I was so close.

If you need to insert code into a method before or after the current code, then it is quite simple to do this through Harmony prefixes and postfixes

Link to comment
Share on other sites

  • Frepo changed the title to [Solved] Can't get EntityBehaviorHunger

So I've started looking into Harmony now. I copied some code from another mod with the intent to experiment with it. First thing I get is an error from just copying the over the code:

image.png.5fef75771be86360035965a5a55f7d1f.png

I don't understand why this is not recognized by my compiler (when it obviously works in the original mod). It's a small mod with only one ItemClass, the mod core class, and this EntityPlayer_LightHsv_Patched class. Ok, it also comes with a config class, which I skipped. But can't see that the config should have anything to do with this error.

Anyway, we are both refencing the same 0Harmony.dll

image.png.7a85b513cf3515128c20615392f6856d.png

...or so I think, there were a bunch of 0Harmony-dll's in the package I downloaded. I'm referencing the net6.0 version (tried them all with the same result).

image.png.306bb4c90cb9979105f4762038052887.png

What is this second parameter, "1"??? My compiler doesn't want it there.

 

Edited by Frepo
Link to comment
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.