Jump to content

Recommended Posts

Posted (edited)

so I noticed this was occurring on client side vanilla to is there any way to get to put the fire out I called extinguish several times.

Edited by jredfox
Posted

have you tried

entity.extinguish()

?

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted
2 hours ago, Cadiboo said:

have you tried

entity.extinguish()

?

several times does nothing. I tried on tick and eventually between 1-14 ticks it works. What is not updating instantly on the server side that it takes that long

Posted
4 minutes ago, jredfox said:

several times does nothing. I tried on tick and eventually between 1-14 ticks it works. What is not updating instantly on the server side that it takes that long

have you tried placing breakpoints to find out?

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted (edited)
3 hours ago, Cadiboo said:

have you tried placing breakpoints to find out?

yes still no idea why it doesn't extinguish for half a second when I called new and old player extinguish. My fix was on respawn on tick for a full second extinguish otherwise it will just keep being on fire since one-two ticks does nothing.

So I am thinking there is another variable somewhere that is setting the entity on fire or somehow the client is resetting the server side on fire

Edited by jredfox
Posted
2 hours ago, jredfox said:

yes still no idea why it doesn't extinguish for half a second when I called new and old player extinguish. My fix was on respawn on tick for a full second extinguish otherwise it will just keep being on fire since one-two ticks does nothing.

So I am thinking there is another variable somewhere that is setting the entity on fire or somehow the client is resetting the server side on fire

If you traced it with breakpoints, it should be obvious. You should see that when you call extinguish that the value changes and then you keep following and see if something else sets it back again.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)
1 hour ago, jabelar said:

If you traced it with breakpoints, it should be obvious. You should see that when you call extinguish that the value changes and then you keep following and see if something else sets it back again.

I do it says 0 but, the entity player keeps burning. Stop acting like it's always a simple fix sometimes it's not maybe it resets next tick maybe that value isn't actually what burns the player maybe in about x amount of ticks the client sends to server it thinks it should be burning

Edited by jredfox
Posted
7 hours ago, Cadiboo said:

have you tried placing breakpoints to find out?

I also tried always using extinguish regardless of world is remote and on every tick the client side doesn't get put out. The server side eventually calling that enough times on tick does put it out. The only thing that puts it out on client is sprinting weird

Posted (edited)
5 hours ago, jabelar said:

If you traced it with breakpoints, it should be obvious. You should see that when you call extinguish that the value changes and then you keep following and see if something else sets it back again.

I went ahead and debuged more no answers just more questions. It says it was not burning after the re spawn then the next tick it gets reset on fire again. Then it says after a couple ticks player moved wrongly and then it finally allows the player to be extinguished because I was doing it on tick

Where it says burning respawned that is its status during the death event next tick says is burning

 

[16:42:17] [Server thread/INFO] [STDOUT]: [com.evilnotch.respawnscreen.MainJava:onDeath:136]: burning Respawned:false
true
true
true
[16:42:17] [Server thread/WARN]: Player873 moved wrongly!
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false

 

Edited by jredfox
Posted (edited)
14 hours ago, jredfox said:

Stop acting like it's always a simple fix sometimes it's not maybe it resets next tick maybe that value isn't actually what burns the player maybe in about x amount of ticks the client sends to server it thinks it should be burning

 

It IS almost always simple. You're just too impatient. Like you said it could be that the fire field is getting set again. But that is super easy to check. In the code you can look at the call hierarchy and see everywhere in the whole code where the fire field is accessed. And you can use debug mode to step through the code and watch every time it changes.

 

Also, you really need to understand the client and server stuff diesieben07 and I keep mentioning. I think your problem here is related to this. A "player moved wrongly" means that you're running code on the client side that shouldn't be run. Here is what I think is happening. On the client you are extinguishing and moving (wrongly) the respawned player. However, the server sees the movement as illegal because it is different than normal movement requests from the client so it ignores it. Therefore as far as the server is concerned the player is still in the lava or whatever fire that killed the player. So the server will keep burning the player. 

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)
11 hours ago, jabelar said:

 

It IS almost always simple. You're just too impatient. Like you said it could be that the fire field is getting set again. But that is super easy to check. In the code you can look at the call hierarchy and see everywhere in the whole code where the fire field is accessed. And you can use debug mode to step through the code and watch every time it changes.

 

Also, you really need to understand the client and server stuff diesieben07 and I keep mentioning. I think your problem here is related to this. A "player moved wrongly" means that you're running code on the client side that shouldn't be run. Here is what I think is happening. On the client you are extinguishing and moving (wrongly) the respawned player. However, the server sees the movement as illegal because it is different than normal movement requests from the client so it ignores it. Therefore as far as the server is concerned the player is still in the lava or whatever fire that killed the player. So the server will keep burning the player. 

but, if you look at my code all the respawn  and teleportation is done via the server side as well as the extinguishing.

is there a way I can notify the server that the movement I am making aka respawning if you viewed my code as legal? I am doing this all on the server side as well.

 

were are the older values it's looking for? Is it possible I could just set those older values of xyz and just edit them via reflection to the players new coords therefore fixing the bug?

Edited by jredfox
Posted (edited)

So what are you trying to do exactly again? I was looking at your github code (is that up to date?) and I don't understand your whole handling of the death event. You are currently copying all the code from the onDeath() method and putting that in your death event handler and then cancelling the event. The only thing you are adding is the particles which you can add without all that work. 

 

It looks like you're still treating the player as dead (you are setting to dead, you're updating the stats, sending death message, etc.). So why are you canceling the death event exactly if you want all the regular death behavior?

 

Why don't you let the player die normally (but add particles if you want) and then control the respawn separately in the clone event? And why do you want to manually control the respawn exactly? Are you just trying to make it so it automatically respawns so the player doesn't have to see the respawn GUI? Because if so then there are a lot easier ways of doing that...

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)
2 hours ago, jabelar said:

So what are you trying to do exactly again? I was looking at your github code (is that up to date?) and I don't understand your whole handling of the death event. You are currently copying all the code from the onDeath() method and putting that in your death event handler and then cancelling the event. The only thing you are adding is the particles which you can add without all that work. 

 

It looks like you're still treating the player as dead (you are setting to dead, you're updating the stats, sending death message, etc.). So why are you canceling the death event exactly if you want all the regular death behavior?

 

Why don't you let the player die normally (but add particles if you want) and then control the respawn separately in the clone event? And why do you want to manually control the respawn exactly? Are you just trying to make it so it automatically respawns so the player doesn't have to see the respawn GUI? Because if so then there are a lot easier ways of doing that...

cancle the death event so it doesn't try and constantly repsawn screen try and show up on tick and or make the player wait a full second before re spawning.

The particles are necessary because on death the particles do not show up for a full 20 death ticks or one second on death. So for instant re-spawn it's necessary for xp and particles for manual re-spawning.

I am trying to get the player to respawn without being on fire if last death with in lava/fire please help me figure out exactly where it's trying to reset the coords yet failing.

Code I gave has been updated several dozen times since I posted this remove the tick event and the fire bug will always occur.

Edited by jredfox
Posted (edited)

So instant respawn is easy. Just handle the Gui open event, check if instanceof GuiGameOver and set that to null instead and run the code that normally happens with delayed respawn button. You can find that in the actionPerformed() method. It is simply:  this.mc.player.respawnPlayer(); That should be it. You should instantly respawn. Just takes about four lines of code.

 

For the particles, I would spawn those from the LivingDeathEvent since that will occur on the server side and so will create the particles for everyone to see. If you spawn them in your gui open event handler only the player that died would see them. These particles would spawn where the player died. If you'd rather have the particles where he respawns I think you could spawn them from the clone event. In any case handle one of these event and spawn the particles. But you don't need to copy all that other death code and you don't cancel the event. 

 

Regarding the fire thing, it might just be fixed by the above code since it is mostly following the vanilla process for repawning and death. However, you it might be the case that there is something about the time delay for respawn that helps with extinguishing. But why don't you get the first two parts working and see if there is still a problem with the extinguish and I can help further.

 

I'm going to bed now but will check on your progress tomorrow. Cheers!

 

 

 

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)

Actually I decided to try it before going to bed. By simply putting this in my client handler (which is also an EventSubscriber for client side events) I respawned instantly and when I died with lava it was extinguished properly.

 

    @SubscribeEvent(priority = EventPriority.NORMAL, receiveCanceled = true)
    public static void onEvent(GuiOpenEvent event)
    {
        if (event.getGui() instanceof GuiGameOver)
        {
            EntityPlayerSP thePlayer = Minecraft.getMinecraft().player;
            if (thePlayer != null)
            {
                thePlayer.respawnPlayer();
            }
            event.setGui(null);
          }
    }

 

Note it is possible you might want to check for hardcore mode and not respawn if it is hardcore mode, but you can figure that out if you want that.

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)
7 hours ago, jabelar said:

Actually I decided to try it before going to bed. By simply putting this in my client handler (which is also an EventSubscriber for client side events) I respawned instantly and when I died with lava it was extinguished properly.

 


    @SubscribeEvent(priority = EventPriority.NORMAL, receiveCanceled = true)
    public static void onEvent(GuiOpenEvent event)
    {
        if (event.getGui() instanceof GuiGameOver)
        {
            EntityPlayerSP thePlayer = Minecraft.getMinecraft().player;
            if (thePlayer != null)
            {
                thePlayer.respawnPlayer();
            }
            event.setGui(null);
          }
    }

 

Note it is possible you might want to check for hardcore mode and not respawn if it is hardcore mode, but you can figure that out if you want that.

If you looked at my code I already handled hardcore mode with spectator same as vanilla.

your respawn player fires twice I already tried that. It's best to do it on the server side. Yes I could do this and then manually spawn the xp and the particles but, I would prefer doing it on server side especially since your code will make respawn forge events fire twice on server. Use a println during where you respawn the player

Edited by jredfox
Posted (edited)
1 hour ago, jredfox said:

If you looked at my code I already handled hardcore mode with spectator same as vanilla.

your respawn player fires twice I already tried that. It's best to do it on the server side. Yes I could do this and then manually spawn the xp and the particles but, I would prefer doing it on server side especially since your code will make respawn forge events fire twice on server. Use a println during where you respawn the player

Sure, but it is a good starting point to have it working including the extinguish. Now you can work through the issues, try to intercept on the server again.

 

Regarding the event firing twice, that happens in vanilla already. In fact before firing the gui open event there is special code just for the game over screen that checks to ensure there is no GUi already open.

if (guiScreenIn == null && this.player.getHealth() <= 0.0F)
        {
            guiScreenIn = new GuiGameOver((ITextComponent)null);
        }

 

So that can be fixed pretty easy, with a small cooldown where you only respawn if you didn't just do it.

 

Okay, but then next step is to move it to the server side. So we track back in the process. It seems that the GUI game over is called in only one place on the client -- when it receives the SPacketCombatEvent with type ENTITY_DIED and the entity is the player. So we need to look at the server at the exact point that packet is sent. That happens in the onDeath() method which you can simulate with the LivingDeathEvent. I know you already tried this approach, but I'm going through carefully to make sure every step is correct.

 

Luckily the only thing that packet does on client is open the game over gui, so we can simply not send the packet. However, we have to remember the fact that the respawn only happens when the client sends respawn back. So we need to figure out how the server responds to that. If you look at the gui game over you'll see that the respawn causes a CPacketClientStatus with type PERFORM_RESPAWN.

 

So looking at what the server does when it receives the PERFORM_RESPAWN, it is:

                if (this.player.queuedEndExit)
                {
                    this.player.queuedEndExit = false;
                    this.player = this.server.getPlayerList().recreatePlayerEntity(this.player, 0, true);
                    CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, DimensionType.THE_END, DimensionType.OVERWORLD);
                }
                else
                {
                    if (this.player.getHealth() > 0.0F)
                    {
                        return;
                    }

                    this.player = this.server.getPlayerList().recreatePlayerEntity(this.player, player.dimension, false);

                    if (this.server.isHardcore())
                    {
                        this.player.setGameType(GameType.SPECTATOR);
                        this.player.getServerWorld().getGameRules().setOrCreateGameRule("spectatorsGenerateChunks", "false");
                    }
                }

 

So putting it all together, I think your original approach was close but needed to add the code I just posted above.

 

In other words:

1) Handle the LivingDeathEvent

2) In the LivingDeathEvent handler check that !world.isRemote to confirm on server, and check that entity is a player.

3) Copy the onDeath() code but remove the sending of the SPacketCombatEvent.

4) Use reflection to access the onDeath stuff which causes problems. I see you did that in your original attempt, so yeah do that.

5) Add the code above for the actual respawning.

6) Cancel the event.

 

I expect that should work. I might try implementing it myself, but theoretically it would follow exactly the same process as normal respawn. There is still a chance that the quick timing is an issue, but let's see.

Edited by jabelar

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)
31 minutes ago, jabelar said:

 

if you read the code the gui opens up twice the packet for the player isn't sent twice unlike your code. And unless you send the packet twice it makes you wait a minimum of 1 second before respawning. If you send the packet twice the respawn events occur twice thus really screwing up other mods data like dropping modded inventories twice

I already do all of that except for onDeath() don't cause an endless recursion where it constantly fires the death event. the reflection isn't causing issues I use my mcpmappings api to change the string based on which dev it's in.


Again I already handled hardcore mode and have seen that code before. The only other code that could possible not fire is the end dimension to overworld code which in a normal respawn death it never fires

I also have a client proxy to always cancel the death screen event so that's not it.

What I need to know is where are the values stored that the server thinks I am still there from previous death. Those are what need to be changed possibly with reflection.

Edited by jredfox
Posted

Okay, so I've been working on it. It is pretty tricky. The problem is the way client server games work. In a perfect world, the client would only run code for rendering, sound and user input and all the game logic would run only on server. However, due to imperfections in network bandwidth and lag to create smooth gameplay all games need the client to "smooth" over the experience by running some of the game logic and occasionally syncing to the server which ensures that no client-side cheating is happening.

 

Unfortunately, for the respawning stuff it seems that the Minecraft client is doing some of this and so it is really hard to get both client and server to perfectly (in terms of timing and other sync) on jumping straight to the respawn.

 

Are you really sure you can't do some client side processing? Because if you can, then it is really simple. But otherwise it is pretty tough.

 

I've actually implemented a server-only side approach and it almost works -- it auto repawns, skips the client message and extinguishes the fire. However, it creates a "ghost" player entity on the client. It is weird because all the code is pretty much copied from the vanilla respawn. But I'll try to debug a bit more.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)
1 hour ago, jabelar said:

Okay, so I've been working on it. It is pretty tricky. The problem is the way client server games work. In a perfect world, the client would only run code for rendering, sound and user input and all the game logic would run only on server. However, due to imperfections in network bandwidth and lag to create smooth gameplay all games need the client to "smooth" over the experience by running some of the game logic and occasionally syncing to the server which ensures that no client-side cheating is happening.

 

Unfortunately, for the respawning stuff it seems that the Minecraft client is doing some of this and so it is really hard to get both client and server to perfectly (in terms of timing and other sync) on jumping straight to the respawn.

 

Are you really sure you can't do some client side processing? Because if you can, then it is really simple. But otherwise it is pretty tough.

 

I've actually implemented a server-only side approach and it almost works -- it auto repawns, skips the client message and extinguishes the fire. However, it creates a "ghost" player entity on the client. It is weird because all the code is pretty much copied from the vanilla respawn. But I'll try to debug a bit more.

I can do stuff to the client from the server (packet) what should I be doing?

If you got the fire extinguished and not rendered straight after death in lava death I would like to know what your code is. Thanks for looking into this

Also make sure you send the respawn packet that could by why your a ghost player

Edited by jredfox
Posted

Okay, I am pretty busy rest of weekend, so not sure how much more I can look at it, but it is definitely tricky. The logic is actually really simple -- it is just what I said above. But it looks like there is another thing happening where respawn gets sent again in some code that cleans up dimension changes which I think must be running. Haven't had time to look at it.

 

But here is the code I wrote, feel free to copy it as it is fairly straight forward: https://github.com/jabelar/ExampleMod-1.12/blob/master/src/main/java/com/blogspot/jabelarminecraft/examplemod/EventHandler.java#L1156

 

Note there are other things in that class for other event handling that isn't related to your problem, but basically everything after that line is for that auto-respawn. I also used a little bit of reflection and those fields are declared earlier in the file.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)
57 minutes ago, jabelar said:

Okay, I am pretty busy rest of weekend, so not sure how much more I can look at it, but it is definitely tricky. The logic is actually really simple -- it is just what I said above. But it looks like there is another thing happening where respawn gets sent again in some code that cleans up dimension changes which I think must be running. Haven't had time to look at it.

 

But here is the code I wrote, feel free to copy it as it is fairly straight forward: https://github.com/jabelar/ExampleMod-1.12/blob/master/src/main/java/com/blogspot/jabelarminecraft/examplemod/EventHandler.java#L1156

 

Note there are other things in that class for other event handling that isn't related to your problem, but basically everything after that line is for that auto-respawn. I also used a little bit of reflection and those fields are declared earlier in the file.

", receiveCanceled = true)" > awesome didn't know this was a feature so it's going to fire even if the event cancels?

your respawn breaks player cannot do anything. Have you tried player.connection.player = newPlayer at the end? That's what I called and then the bug started happening again.

I think you were onto something better originally with the cheat system just tell me what coords and what class then I will use reflection to change them and see if that does anything different?

Edited by jredfox
Posted

I didn't have a lot of time to look at this further, as I have a very busy weekend. But I did a little research and based on several discussions in Bukkit and Spigot developer forums there is pretty much agreement that there is basically two ways to go.

 

1) If you have ability to do client-side mod, do it that way -- the simple way I explained above where you cancel the GUI and send the respawn packet immediately.

 

2) Otherwise, you can't let the entity actually die normally at all. Instead of letting it actually respawn (along with recreating/cloning the entity and such) you basically just want to restore the health and teleport to the spawn location. Of course you need to clean up other things like extinguishing fire, food and oxygen levels, stats, and all the rest of the stuff. But you want to avoid either the server or client entering any of the vanilla respawn code. 

 

I agree that once you get into the actual respawning process it is way to hard to get it all to work and have client and server sync. Despite literally copying the exact vanilla code it is still behaving badly (I think because of lack of synchronization between the client and server). I'm sure there is some advanced solution but I can't see it. So I think it is worth thinking about Option #2 where you don't do the full cloning of the player but rather just move them and get them back to fresh status like an actual respawn.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)
12 hours ago, jabelar said:

I didn't have a lot of time to look at this further, as I have a very busy weekend. But I did a little research and based on several discussions in Bukkit and Spigot developer forums there is pretty much agreement that there is basically two ways to go.

 

1) If you have ability to do client-side mod, do it that way -- the simple way I explained above where you cancel the GUI and send the respawn packet immediately.

 

2) Otherwise, you can't let the entity actually die normally at all. Instead of letting it actually respawn (along with recreating/cloning the entity and such) you basically just want to restore the health and teleport to the spawn location. Of course you need to clean up other things like extinguishing fire, food and oxygen levels, stats, and all the rest of the stuff. But you want to avoid either the server or client entering any of the vanilla respawn code. 

 

I agree that once you get into the actual respawning process it is way to hard to get it all to work and have client and server sync. Despite literally copying the exact vanilla code it is still behaving badly (I think because of lack of synchronization between the client and server). I'm sure there is some advanced solution but I can't see it. So I think it is worth thinking about Option #2 where you don't do the full cloning of the player but rather just move them and get them back to fresh status like an actual respawn.

I disagree because there are things called forge capabilities and this isn't a bukkit plugin where I can hardcode vanilla things and it always works for vanilla. This is a forge mod which has to fully work with forge. 

I think there are issues with the vanilla respawn method to begin with. So I have a new plan recreate the player same as they did exact code teleport player to right dim and coords manually using my own teleport method and see if it fixes itself.

I will post results here

"I didn't have a lot of time to look at this further"
That's ok I will be fixing this manually if I have to but, I do need help bad on another issue here for when your not busy please and thanks: trying to get player to update variables when loading from the disk it does that then it glitches out. 

 

Edited by jredfox

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.