Jump to content

Recommended Posts

Posted (edited)

Guys you might be confused because many people will put the code for both classes in a single file. But they are still separate classes. if you think about it, the message itself gets instantiated every time it is sent, whereas there should be a single handler.

 

The general concept is:

1) Make a class that extends IMessage.

2) This class can have fields representing the payload information, and you need a constructor that takes in that information and assigns it to the field. (Note I think you also need a default constructor with no parameters as well.)

3) You need to override the toBytes() and fromBytes() methods to put your field information into the ByteBuf that is passed in. You should use ByteBufUtils for converting your information.

4) You make a separate class that extends IMessageHandler

5) In that class you need to override the onMessage() method. The message instance will be passed to you and you can access the fields and do whatever you need to do. Note that due to threaded nature, for packets that go from client to server, I think you need to encapsulate your code as a Runnable.

6) The return value for the onMessage() method should generally be null. It is possible to create a confirmation method where the receiver sends a packet back to confirm receipt and unerrored processing, but that is a more advanced topic.

 

I have an example here: https://github.com/jabelar/ExampleMod-1.12/blob/master/src/main/java/com/blogspot/jabelarminecraft/examplemod/networking/MessageSyncEntityToServer.java

Edited by jabelar

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

Posted (edited)
10 minutes ago, jabelar said:

Guys you might be confused because many people will put the code for both classes in a single file. But they are still separate classes. if you think about it, the message itself gets instantiated every time it is sent, whereas there should be a single handler.

 

The general concept is:

1) Make a class that extends IMessage.

2) This class can have fields representing the payload information, and you need a constructor that takes in that information and assigns it to the field. (Note I think you also need a default constructor with no parameters as well.)

3) You need to override the toBytes() and fromBytes() methods to put your field information into the ByteBuf that is passed in. You should use ByteBufUtils for converting your information.

4) You make a separate class that extends IMessageHandler

5) In that class you need to override the onMessage() method. The message instance will be passed to you and you can access the fields and do whatever you need to do. Note that due to threaded nature I think you need to encapsulate your code as a Runnable.

6) The return value for the onMessage() method should generally be null. It is possible to create a confirmation method where the receiver sends a packet back to confirm receipt and unerrored processing, but that is a more advanced topic.

 

I have an example here: https://github.com/jabelar/ExampleMod-1.12/blob/master/src/main/java/com/blogspot/jabelarminecraft/examplemod/networking/MessageSyncEntityToServer.java

So I debuged my code and discovered the data isn't being transferred to the client.
 

[10:16:11] [Netty Local Client IO #0/INFO] [STDOUT]: [com.evilnotch.respawnscreen.network.PacketParticle:handleClientSide:39]: idEnt:0 idParticle:0


On server side I printed the particle id during the consturctor it said "Server:42" for the id rather then both being 0. Why is this occurring I specified a specific packet constructor when sending to the client and to and from bytes looks like they should work.
 

    @Override
    public void toBytes(ByteBuf buffer){
        buffer.writeInt(this.particleId);
        buffer.writeInt(this.entid);
    }

    @Override
    public void fromBytes(ByteBuf buffer){
        this.particleId = buffer.readInt();
        this.entid = buffer.readInt();
    }


Here is my code:
https://github.com/jredfox/norespawnscreen

here is how I call the packet from the server:
NetWorkHandler.INSTANCE.sendToDimension(new PacketParticle(EnumParticleTypes.DRAGON_BREATH,player.getEntityId() ),player.dimension);

Edited by jredfox
Posted (edited)
7 minutes ago, diesieben07 said:

Here you are accessing the fields from the message handler's instance. However you never set these to any meaningful values (how could you, it's the message handler, only the message has useful values here). You need to get the data from the message passed to the method.

This is why you do not implement IMessageHandler and IMessage on the same class (which you are still doing). It is confusing and creates weird, meaningless fields in your message handler.

 

Not to be snarky, but this is making me very happy right now. You didn't want to listen because you are oh so smart and don't need to follow conventions. And guess what, you made the exact mistake that is the reason for me recommending not to do what you did.

 

So, for the love of god: I do not say the things I say because I am bored or want to screw with you.

yeah a beginners mistake I forgot that there was the messege argument there. I was fallowing a youtube video which seemed pretty good to me.

I see why there are separate objects but, I don't see why forge just can't combine them and remove the arg of IMessege so sending to and from you don't have to worry about additional classes. Not saying it don't work just happy I was noob.

 

Edited by jredfox
Posted
11 minutes ago, diesieben07 said:

No, that is a terrible tutorial, because he is teaching that terrible practice.

This is a holdover from pre-1.7 (I think, might be even older) networking, where SimpleNetworkWrapper was not a thing. If you do not like this separation into message handler and message then do not use SimpleMessageHandler! There are other systems available (event based, for example) from the NetworkRegistry. Do not shoe-horn your old habits into the new system in a completely broken way.

Wasn't mine was the videos. Thanks for pointing that out.

My packet handler doesn't work for anything else that isn't explosion particle do you know why this is? This is the code that executes off of the client side I know the width should have been passed from the original entity as well but, for now only testing players which will always be the same when sending the packet.

	public static void spawnParticles(Entity e,int particleId,double x, double y, double z) 
	{
        for (int k = 0; k < 20; ++k)
        {
        	Random rand = getRND(e);
            double d2 = rand.nextGaussian() * 0.02D;
            double d0 = rand.nextGaussian() * 0.02D;
            double d1 = rand.nextGaussian() * 0.02D;
            e.world.spawnParticle(EnumParticleTypes.getParticleFromId(particleId), x + (double)(rand.nextFloat() * e.width * 2.0F) - (double)e.width, y + (double)(rand.nextFloat() * e.height), e.posZ + (double)(rand.nextFloat() * e.width * 2.0F) - (double)e.width, d2, d0, d1);
        }
	}

 

Posted
1 minute ago, jredfox said:

My packet handler doesn't work for anything else that isn't explosion particle do you know why this is?

You need to trace the execution. Like you've already done a bit of, put console statements throughout your code (or use debug mode in your IDE). It should be really obvious quickly -- what ID does it think it is getting? Does that id match what you sent? Does that id match the id for the particle you intended?

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

Posted (edited)
13 minutes ago, jabelar said:

Also another problem with your packet code is that you're reaching across logical sides. You can't access Minecraft() class directly in your onMessage() method. You'll need to call a proxy method.

if you look it's only called on client side.

the particle id does change it just doesn't render anything but, the explosion.

Another issue I am having is the particle xyz double coords are no where near the death of the player.
https://github.com/jredfox/norespawnscreen

 

I could test on hurt event to but, I think the results would be the same

Edit: I printed out the coords sent to the client they are the same as sent from the server of the original player

Edited by jredfox
Posted (edited)
5 minutes ago, jredfox said:

if you look it's only called on client side.

Dude, you're really not listening to all the good advice you're getting. We know better as we've been doing this for over a decade. We're not just making stuff up.

 

You're missing some very fundamental concepts that are very important. In this case, it has nothing to do with being called on the client side. The problem is your class is still going to load on the server side (it needs to because that is where the packet is constructed). When the class is loaded, at some point it is going to try to "understand" what the code is supposed to do and the problem is that the Minecraft class isn't loaded on the server at all. So that code is basically broken (not compilable/interpretable) on the server and will cause an error. You may not notice the error when you're testing on an integrated server because technically both client and server code is available to the same JVM, but with dedicated server it will fail.

 

What  I've noticed is that you're running around way too fast without fully understanding what you're doing. Furthermore, you're really not listening to our advice. We are giving advice because we know it is important. Why are you even asking if you are discounting our advice?

Edited by jabelar

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

Posted (edited)
6 minutes ago, jabelar said:

Dude, you're really not listening to all the good advice you're getting. We know better as we've been doing this for over a decade. We're not just making stuff up.

 

You're missing some very fundamental concepts that are very important. In this case, it has nothing to do with being called on the client side. The problem is your class is still going to load on the server side (it needs to because that is where the packet is constructed). When the class is loaded, at some point it is going to try to "understand" what the code is supposed to do and the problem is that the Minecraft class isn't loaded on the server at all. So that code is basically broken (not compilable/interpretable) on the server and will cause an error. You may not notice the error when you're testing on an integrated server because technically both client and server code is available to the same JVM, but with dedicated server it will fail.

 

What  I've noticed is that you're running around way too fast without fully understanding what you're doing. Furthermore, you're really not listening to our advice. We are giving advice because we know it is important. Why are you even asking if you are discounting our advice?

will fix it later if it crashes right now all I care about is does the particles appear and if so when and where do they appear? If it loads on the server like you say then it will crash but, it won't load on the server it should be the imports that are crashing on startup not during that event it loads into memory going into the else statement which will never happen on the server and crash. It will crash before it even gets into that statement from class not found nothing to do with going into the else statement.

Edited by jredfox
Posted
Just now, jredfox said:

will fix it later if it crashes right now all I care about is does the particles appear?

This is sort of what I mean you you're running too fast. In programming you need to progress cautiously, making sure each piece of code works fully bug-free before moving on to the next part. 

 

Anyway, again are you tracing the execution? If you step through the execution it will be obvious -- you'll see the id, you'll step through the particle spawning code, and you'll see everything that is happening.

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

Posted (edited)
6 minutes ago, diesieben07 said:

That's not how imports work. The class file has no concept of imports. What will crash is the verifier. If you don't know what that is, look it up. It's complicated.

However, if you don't want to do that, trust us please and understand that no, you cannot reference client-only classes from common code. No, even if it's "never called".

Well I didn't even execute code on startup but, had client imports and next thing I know on dedicated server it crashes I never even used them could be mistaking but, remember it in 1.12 with deving silkspawners.

jeblar I need to verify the client code works before making minor patches on server. Or I would constantly be going back and forth and forget what I need to do on the client. If it's major I fix it immediately and I always launch dedicated and test stuff before compiling. "So if anything going too fast would be not fixing client before going back to server" I copied it from a tutorial and minechess mod.

Edited by jredfox
Posted

ok the particle was not right z location I figured out it had nothing to do with packet not working.

I have tested this on hurt event it works as well as on death.

Posted (edited)
On 5/9/2018 at 7:24 AM, Choonster said:

 

Entity#getEntityId is completely unrelated to global entity IDs. It's a unique entity ID specifically designed to be sent over the network.

ok thanks

Edited by jredfox
Posted
1 hour ago, jredfox said:

Well I didn't even execute code on startup but, had client imports and next thing I know on dedicated server it crashes I never even used them could be mistaking but, remember it in 1.12 with deving silkspawners.

It has nothing to do with executing. It has to do with the class file being valid at all, meaning that the JVM has to recognize what is inside the file even if it is not executing.

 

If you just had a class that never executed at all that contained reference to a client-only class such as Minecraft or Renderer and such, it will fail. Because the JVM can't have files that it doesn't understand. The server literally has no idea what the Minecraft class is.

 

You might as well have random text in the method -- would you expect a method with random text in it to not cause an error? There is no difference between saying Minecraft.getMinecraft() and Garbage.getGarbage() -- they'll throw the same error.

 

Code can cause an error just by existing if it causes invalid Java, it doesn't have to be executed. Compilation (and the related activities like linking) can't just say "I don't know what that class is but I hope it is never executed".

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

Posted
6 minutes ago, jabelar said:

It has nothing to do with executing. It has to do with the class file being valid at all, meaning that the JVM has to recognize what is inside the file even if it is not executing.

 

If you just had a class that never executed at all that contained reference to a client-only class such as Minecraft or Renderer and such, it will fail. Because the JVM can't have files that it doesn't understand. The server literally has no idea what the Minecraft class is.

 

You might as well have random text in the method -- would you expect a method with random text in it to not cause an error? There is no difference between saying Minecraft.getMinecraft() and Garbage.getGarbage() -- they'll throw the same error.

 

Code can cause an error just by existing if it causes invalid Java, it doesn't have to be executed. Compilation (and the related activities like linking) can't just say "I don't know what that class is but I hope it is never executed".

Yeah don't worry already fixed it on server side 

Posted (edited)
On 5/8/2018 at 5:52 AM, Choonster said:

 

Yes, call World#spawnParticles on the client World in the packet's handler to spawn the particles.

Edit: after some detailed tests I used EnumParticleTypes.getshouldIngoreRange() since that seems to be what vanilla uses I kill entity player without any mods and it was long distense

could you please explain what EnumParticleTypes.getShouldIgnoreRange() should be done in my code? Should I be using that boolean for long distance when using/creating my own sendPacketToPlayersWithinRange() ?
 

	public static void sendToAllPlayersWithinRange(World world,double x, double y, double z, boolean longDistance,IMessage packet) 
	{
        for (int i = 0; i < world.playerEntities.size(); ++i)
        {
        	EntityPlayerMP player = (EntityPlayerMP) world.playerEntities.get(i);
        	BlockPos blockpos = player.getPosition();
        	double d0 = blockpos.distanceSq(x, y, z);

        	if (d0 <= 1024.0D || longDistance && d0 <= 262144.0D)
        	{
            	NetWorkHandler.INSTANCE.sendTo(packet, player);
        	}
        }
	}

 

Edited by jredfox
Posted
11 hours ago, jredfox said:

could you please explain what EnumParticleTypes.getShouldIgnoreRange() should be done in my code? Should I be using that boolean for long distance whe

 

Looking at the vanilla code it isn't quite clear. Here is all the vanilla type definitions and the boolean is the ignoreRange value:

 

    EXPLOSION_NORMAL("explode", 0, true),
    EXPLOSION_LARGE("largeexplode", 1, true),
    EXPLOSION_HUGE("hugeexplosion", 2, true),
    FIREWORKS_SPARK("fireworksSpark", 3, false),
    WATER_BUBBLE("bubble", 4, false),
    WATER_SPLASH("splash", 5, false),
    WATER_WAKE("wake", 6, false),
    SUSPENDED("suspended", 7, false),
    SUSPENDED_DEPTH("depthsuspend", 8, false),
    CRIT("crit", 9, false),
    CRIT_MAGIC("magicCrit", 10, false),
    SMOKE_NORMAL("smoke", 11, false),
    SMOKE_LARGE("largesmoke", 12, false),
    SPELL("spell", 13, false),
    SPELL_INSTANT("instantSpell", 14, false),
    SPELL_MOB("mobSpell", 15, false),
    SPELL_MOB_AMBIENT("mobSpellAmbient", 16, false),
    SPELL_WITCH("witchMagic", 17, false),
    DRIP_WATER("dripWater", 18, false),
    DRIP_LAVA("dripLava", 19, false),
    VILLAGER_ANGRY("angryVillager", 20, false),
    VILLAGER_HAPPY("happyVillager", 21, false),
    TOWN_AURA("townaura", 22, false),
    NOTE("note", 23, false),
    PORTAL("portal", 24, false),
    ENCHANTMENT_TABLE("enchantmenttable", 25, false),
    FLAME("flame", 26, false),
    LAVA("lava", 27, false),
    FOOTSTEP("footstep", 28, false),
    CLOUD("cloud", 29, false),
    REDSTONE("reddust", 30, false),
    SNOWBALL("snowballpoof", 31, false),
    SNOW_SHOVEL("snowshovel", 32, false),
    SLIME("slime", 33, false),
    HEART("heart", 34, false),
    BARRIER("barrier", 35, false),
    ITEM_CRACK("iconcrack", 36, false, 2),
    BLOCK_CRACK("blockcrack", 37, false, 1),
    BLOCK_DUST("blockdust", 38, false, 1),
    WATER_DROP("droplet", 39, false),
    ITEM_TAKE("take", 40, false),
    MOB_APPEARANCE("mobappearance", 41, true),
    DRAGON_BREATH("dragonbreath", 42, false),
    END_ROD("endRod", 43, false),
    DAMAGE_INDICATOR("damageIndicator", 44, true),
    SWEEP_ATTACK("sweepAttack", 45, true),
    FALLING_DUST("fallingdust", 46, false, 1),
    TOTEM("totem", 47, false),
    SPIT("spit", 48, true);

 

If you look at the RenderGlobal#spawnParticle0() method you'll see that the code includes the following:

            int k1 = this.calculateParticleLevel(minParticles);
            double d3 = entity.posX - xCoord;
            double d4 = entity.posY - yCoord;
            double d5 = entity.posZ - zCoord;

            if (ignoreRange)
            {
                return this.mc.effectRenderer.spawnEffectParticle(particleID, xCoord, yCoord, zCoord, xSpeed, ySpeed, zSpeed, parameters);
            }
            else if (d3 * d3 + d4 * d4 + d5 * d5 > 1024.0D)
            {
                return null;
            }

 

So it looks like if ignoreRange is false then particles will only spawn in a radius of 32 blocks (square root of 1024).

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

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.