Jump to content

Some things behind semi-transparent model render strangely [1.7] [UNSOLVED]


Recommended Posts

Posted

Hi everyone.

 

I am working on a pipe that will transport items (like ItemDucts or Buildcrafts pipes, I haven't actually got to the actual item transport part yet, I am just working on rendering today) and I have decided to make the sides transparent so that you can see the items inside. I have successfully achieved this, but unfortunately, there is some weird rendering of the world behind it. Full blocks are fine, but anything else (for some reason, excluding lava) isn't rendered, so this includes water, and any other models.  Here are some screenshots to illustrate what I mean:

width=800 height=423yt7funb.png?1 [/img]

and

width=800 height=4235r6zj2r.png?1 [/img]

 

As you can see, the water behind, and my wind turbine model aren't getting rendered behind the transparent part of the pipe. There are also some transparent bits inside the pipe when looked at as some angles (seen in pic 1)

 

My current code for rendering this is this:

 

 

This is only my renderTileEntityAt method, I do no other lighting, blending, or colouring stuff in any of the other methods being called.

public void renderTileEntityAt(TileEntity tile, double x, double y, double z, float f) {

	int meta = 0;

	if (tile instanceof TileEntityCable) meta = tile.getBlockMetadata();
	if (tile instanceof TileEntityPipe) meta = tile.getBlockMetadata() + 8; // add 8 because cables have 8 subtypes, and for the pipes, the first resource is 8 after the cables first resource.

	GL11.glPushMatrix();
	GL11.glTranslated(x, y, z);
	GL11.glScalef(0.5F, 0.5F, 0.5F);
	GL11.glTranslatef(1.0F, 0.0F, 1.0F);
	GL11.glDisable(GL11.GL_LIGHTING);
	//Calling all the render methods from here with the model and texture specified above.
	if (this.resource[meta][4] != null) {
		this.bindTexture(resource[meta][4]); {
			GL11.glEnable(GL11.GL_BLEND);
			GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
			GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
			if (tile instanceof TileEntityCable) {

				TileEntityCable connectable = (TileEntityCable) tile;
				for (int i = 0; i < 6; i++) {
					//System.out.println("Connections " + i + " = " + connectable.connections[i] + " in Cable");
				}
				if ((!connectable.hasOppositeConnection(connectable.connections))) {
					if (this.model[meta][0] != null) this.drawCore(meta);
				} else if (this.model[meta][1] != null) {
					if (connectable.connections[0] != null) this.drawStraightCore(meta, ForgeDirection.UP);
					if (connectable.connections[2] != null) this.drawStraightCore(meta, ForgeDirection.NORTH);
					if (connectable.connections[4] != null) this.drawStraightCore(meta, ForgeDirection.WEST);
				}

				for (int i = 0; i < connectable.connections.length; i++) {
					if (connectable.connections[i] != null) {
						if (this.model[meta][3] != null) drawConnection(meta, connectable.connections[i], tile.xCoord, tile.yCoord, tile.zCoord, tile); //Drawing and rendering a new connection model for each connected side specified by the tileentity
					}
				}
			} if (tile instanceof TileEntityPipe) {

				TileEntityPipe connectable = (TileEntityPipe) tile;
				for (int i = 0; i < 6; i++) {
					//System.out.println("Connections " + i + " = " + connectable.connections[i] + " in Cable");
				}

				if ((!connectable.hasOppositeConnection(connectable.connections))) {
					if (this.model[meta][0] != null) this.drawCore(meta);
				} else if (this.model[meta][1] != null) {
					if (connectable.connections[0] != null) this.drawStraightCore(meta, ForgeDirection.UP);
					if (connectable.connections[2] != null) this.drawStraightCore(meta, ForgeDirection.NORTH);
					if (connectable.connections[4] != null) this.drawStraightCore(meta, ForgeDirection.WEST);
				}

				for (int i = 0; i < connectable.connections.length; i++) {
					if (connectable.connections[i] != null) {
						if (this.model[meta][3] != null) drawConnection(meta, connectable.connections[i], tile.xCoord, tile.yCoord, tile.zCoord, tile); //Drawing and rendering a new connection model for each connected side specified by the tileentity
					}
				}
			}
			GL11.glDisable(GL11.GL_BLEND);
		}
	}
	GL11.glEnable(GL11.GL_LIGHTING);
	GL11.glPopMatrix();
}

Note: This renderer class does handle all of my connecting blocks, and the one that is transparent uses metadata 8, metadata 0 to 7 are all of my cables, and have no problems.

 

 

 

Any suggestions on how to fix this?

 

Thanks.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Hi

 

It looks to me like the ol' rendering-order-is-important-for-alpha-blended-blocks problem.

 

http://www.minecraftforge.net/forum/index.php/topic,22368.msg113450.html#msg113450

 

Your alpha-blended pane is drawing before the water, and it is also writing to the depth buffer.  So when the water is drawn afterwards, it is behind the pane and gets culled.

 

You can turn off writing to the depth buffer while rendering your pane, using GL11.glDepthMask(false);, but that probably won't help much because then the water will render over the top of your pane which will probably look rather strange.

 

The only way  to correct this properly is to make sure that your panes are rendered last.  Unfortunately this will only work when the pipe is the closest alpha-blended object to the player, so you will need to hope that your pipes are never placed behind another alpha-blended object.

 

There may not be an easy answer unfortunately.  It is for sure possible if you grasp deep into the rendering code to sort all the pass 1 rendering by depth.  I'd suggest trying the depth mask fix or the render-last fix and seeing if you can live with one of them.

 

-TGG

 

Posted

Okay this is a fair bit beyond my understanding of GL11 and the way java handles this, so I guess I have a bit of research to do to truly understand what is happening and to find a solution to this.

 

Thanks anyway.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

setting depth mast to true resulted in this:

width=800 height=412lOaJzKB.png?1 [/img]

and

width=800 height=4126jjahUi.png?1 [/img]

So the water and other TESR models behind it such as the wind turbine, are now getting rendered, but now the pipe itself has really odd transparency. Things like the inside of the pipe looks like it is in front of the outside of the pipe, and in image two, the pipe in the background looks to be in front of the pipe in the foreground.Also, there are really annoying and messy looking dark and light bits.

 

What can I do? I either need a way to fix this, or how do I do the render last fix that you suggested?

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

TheGreyGhost already explained it.  If you think about it, for the graphics engine to calculate the picture when there are transparent things in the background, the only trustworthy way is to draw the stuff in the background first then blend the transparent stuff on top.  Imagine you were painting something and you did a light wash of color first (i.e. the transparent part) and then painted over it with thick paint, versus doing it the other way around -- doing a wash of color over thick paint.  The results are not the same: the order matters.

 

If you leave depth mask as true, then when it comes time to render the transparent stuff there is a chance that it has will be "painted" in the scene before something in the background and then when the background is checked it is considered "behind" the transparent part so is not rendered at all (this is called culling).

 

If you disable depth mask with false, then it will render everything even if it was supposed to be behind.  This can screw things up.

 

The fundamental problem is that Minecraft should ideally render things in order based on depth, but instead does several passes.  So your entity may be rendered before water, even if the water is farther back in the background.  There isn't really an easy solution to this.

 

You can however control the order of depth and rendering within your own rendering code.  I don't know how your pipes are rendered, but you could theoretically draw the transparent parts and solid parts with and without depth checking as needed.

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

Posted

This is a TileEntity, right? Try to override

shouldRenderInPass(int pass)

in your TileEntity class and return [if pass equals 1]. It fixed the rendering issues of my semi-transparent tileentity.

 

I actually took it a step further and saved the pass which the method was called in and rendered solid parts on pass 0 and the transparent parts on pass 1:

https://github.com/SanAndreasP/EnderStuffPlus/blob/master/java/de/sanandrew/mods/enderstuffplus/tileentity/TileEntityBiomeChanger.java#L584-L589

https://github.com/SanAndreasP/EnderStuffPlus/blob/master/java/de/sanandrew/mods/enderstuffplus/client/render/tileentity/RenderTileEntityBiomeChanger.java#L103-L132

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

Posted

I already have done shouldRenderInPass(int pass) and in the block class, getRnderPass() { return 1; } and it still looks really weird. I think, as suggested above, my best option is to somehow make sure my pipe is rendered last. I only need a way to do this.

 

If needed I'll post my code later, I don't have access to it right now.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Okay, I have solved the problem of things behind getting culled, or rendering on top of the pipe. SanAndreasP's suggestion worked, with some tweaking of my GL11 methods too. I also removed the getRenderPass() method from my block class. This is my updated renderTileEntityAt method:

        public void renderTileEntityAt(TileEntity tile, double x, double y, double z, float f) {

	int meta = 0;

	if (tile instanceof TileEntityCable) meta = tile.getBlockMetadata();
	if (tile instanceof TileEntityPipe) meta = tile.getBlockMetadata() + 8; // add 8 because cables have 8 subtypes, and for the pipes, the first resource is 8 after the cables first resource.

	GL11.glPushMatrix();
	GL11.glTranslated(x, y, z);
	GL11.glScalef(0.5F, 0.5F, 0.5F);
	GL11.glTranslatef(1.0F, 0.0F, 1.0F);
	GL11.glDisable(GL11.GL_LIGHTING);
	//Calling all the render methods from here with the model and texture specified above.
	//if (this.resource[meta][4] != null) {
	if (tile instanceof TileEntityCable) {

		TileEntityCable connectable = (TileEntityCable) tile;
		for (int i = 0; i < 6; i++) {
			//System.out.println("Connections " + i + " = " + connectable.connections[i] + " in Cable");
		}

		if (resource[meta][4] != null) this.bindTexture(resource[meta][4]);
		if ((!connectable.hasOppositeConnection(connectable.connections))) {
			if (this.model[meta][0] != null) this.drawCore(meta);
		} else if (this.model[meta][1] != null) {
			if (connectable.connections[0] != null) this.drawStraightCore(meta, ForgeDirection.UP);
			if (connectable.connections[2] != null) this.drawStraightCore(meta, ForgeDirection.NORTH);
			if (connectable.connections[4] != null) this.drawStraightCore(meta, ForgeDirection.WEST);
		}

		for (int i = 0; i < connectable.connections.length; i++) {
			if (connectable.connections[i] != null) {
				if (this.model[meta][3] != null) drawConnection(meta, connectable.connections[i], tile.xCoord, tile.yCoord, tile.zCoord, tile); //Drawing and rendering a new connection model for each connected side specified by the tileentity
			}
		}
	} if (tile instanceof TileEntityPipe) {
		TileEntityPipe connectable = (TileEntityPipe) tile;
		for (int i = 0; i < 6; i++) {
			//System.out.println("Connections " + i + " = " + connectable.connections[i] + " in Cable");
		}
		if (connectable.renderPass == 1) {
			GL11.glEnable(GL11.GL_BLEND);
			GL11.glEnable(GL11.GL_DEPTH_TEST);
			//System.out.println("test");
			GL11.glDepthMask(true);

			GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);

			this.renderTravelingItem(connectable, (float)x, (float)y, (float)z);

			GL11.glShadeModel(GL11.GL_SMOOTH);
			if (resource[meta][4] != null) this.bindTexture(resource[meta][4]);

			if ((!connectable.hasOppositeConnection(connectable.connections))) {
				if (this.model[meta][0] != null) this.drawCore(meta);
			} else if (this.model[meta][1] != null) {
				if (connectable.connections[0] != null) this.drawStraightCore(meta, ForgeDirection.UP);
				if (connectable.connections[2] != null) this.drawStraightCore(meta, ForgeDirection.NORTH);
				if (connectable.connections[4] != null) this.drawStraightCore(meta, ForgeDirection.WEST);
			}

			for (int i = 0; i < connectable.connections.length; i++) {
				if (connectable.connections[i] != null) {
					if (this.model[meta][3] != null) drawConnection(meta, connectable.connections[i], tile.xCoord, tile.yCoord, tile.zCoord, tile); //Drawing and rendering a new connection model for each connected side specified by the tileentity
				}
			}
			GL11.glEnable(GL11.GL_CULL_FACE);
			GL11.glDepthMask(false);
			GL11.glDisable(GL11.GL_BLEND);

		}
	}
	//}
	GL11.glEnable(GL11.GL_LIGHTING);
	GL11.glPopMatrix();
}

 

Again, relevant code starts from "if (tile instanceof TileEntityPipe)", the rest is for my cables.

 

This is now what it looks like:

 

width=800 height=423ELLJ6K9.png?1 [/img]

 

So, the water, and other things in the background look fine, they're rendered behind the pipe as they should be.

But....

Now there is another problem. You can also see in the screenshot, that the inside of the pipe itself looks slightly strange, there are bits of the inside that are missing, and this is only from certain angles, the missing bits move when looked at from another angle. I think they are getting culled, but I am not sure what by, and disabling culling makes it look weird again. Also, another problem, you can see in my code, I have commented out the line this.renderTravelingItem. This was also causing some of the rendering issues, the item renders fine, without any transparency issues, but is rendered behind the pipe. This is what happens when renderTravelingItem isn't commented out:

 

width=800 height=4234bcY6Wb.png?1 [/img]

 

The iron ingot is positioned inside the pipe, but is rendered behind the pipe.

 

This is my travelling item method:

        public void renderTravelingItem(TileEntityPipe pipe, float x, float y, float z) {
	GL11.glPushMatrix();
	GL11.glDisable(GL11.GL_LIGHTING);
	GL11.glDisable(GL11.GL_CULL_FACE);

	TravelingItem itemToRender1 = new TravelingItem(new ItemStack(Items.iron_ingot, 5), 0.0F, 0.0F, 0.0F, 0.05F); //Testing with an item
	TravelingItem itemToRender2 = new TravelingItem(new ItemStack(Blocks.stone, 5), 0.0F, 0.0F, 0.0F, 0.05F); //Testing with a block

	//List<TravelingItem> items = new ArrayList<TravelingItem>();

	/*for (ItemStack s : pipe.getStoredItems()) {
		TravelingItem item = new TravelingItem(s, 0.0F, 0.0F, 0.0F, 0.05F);
		items.add(item);
	}*/

	float scale = 1.25F;

	this.renderTravelingItem(itemToRender1, x, y, z, 0.05F, scale);

	GL11.glEnable(GL11.GL_CULL_FACE);
	GL11.glEnable(GL11.GL_LIGHTING);
	GL11.glPopMatrix();
}

public void renderTravelingItem(TravelingItem item, float x, float y, float z, float speed, float scale) {
	//TravelingItem item = new TravelingItem(stack, x, y, z, speed);
	if (item == null || item.getStack() == null) {
		return;
	}

	ItemStack stack = item.getStack();

	GL11.glPushMatrix();
	GL11.glTranslatef(x, y, z);
	GL11.glTranslatef(0.5F, 0.9F, 0.5F);
	GL11.glScalef(scale, scale, scale);
	fakeItem.setEntityItemStack(stack);
	renderItem.doRender(fakeItem, 0.0D, 0.0D, 0.0D, 0.0F, 0.0F);
	GL11.glPopMatrix();
}

And the TravelingItem class just stores the ItemStack, its position, and I will soon make it also store NBT data.

 

So, one major problem is solved, but now there are two annoying problems to solve.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Hi

>Now there is another problem. You can also see in the screenshot, that the inside of the pipe itself looks slightly strange, there are bits of the inside that are missing, and this is only from certain angles, the missing bits move when looked at from another angle.

 

This is probably the same rendering-order problem again.

 

When you render your TileEntity, draw the rearmost faces first, i.e. the face that is furthest from the player.  As the player moves around the pipe, the "rearmost" face will change.  This might be difficult with a model; you may need to split the model into the six flat faces.

 

> the item renders fine, without any transparency issues, but is rendered behind the pipe

 

That's because you have turned off writing to the depth buffer during rendering of the item (GL11.glDepthMask(false); ), so when you draw the model, it draws over the top of your item since the depth buffer doesn't know the item is there.

 

Just to check - do you understand the difference between

GL11.glDisable(GL11.GL_DEPTH_TEST);

and

GL11.glDepthMask(false);

 

-TGG

Posted

Just to check - do you understand the difference between

GL11.glDisable(GL11.GL_DEPTH_TEST);

and

GL11.glDepthMask(false);

 

No...

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Just to check - do you understand the difference between

GL11.glDisable(GL11.GL_DEPTH_TEST);

and

GL11.glDepthMask(false);

 

No...

Ah ok.

 

GL11.glDisable(GL11.GL_DEPTH_TEST); makes your object draw on top of everything that has been drawn previously, i.e. it ignores the depth of everything that has already been drawn.

 

GL11.glDepthMask(false); turns off writing to the depth buffer when you're drawing an object, so that anything you draw afterwards doesn't know the object is there and writes over the top of it, regardless of whether depth_test is true or not.

 

-TGG

 

 

 

 

 

 

Posted

Okay, that makes sense now.

 

This is probably the same rendering-order problem again.

 

When you render your TileEntity, draw the rearmost faces first, i.e. the face that is furthest from the player.  As the player moves around the pipe, the "rearmost" face will change.  This might be difficult with a model; you may need to split the model into the six flat faces.

 

Okay, so my model is an OBJ model, if I split it into the separate faces in Maya, and then export it as an OBJ, would I be able to somehow control the render order of the faces? If so, how would I achieve this?

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

I know that, but I mean, how would I make it render the furthest face from the player first? or would I need to do this?

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Posted

Hi

 

When you render in a tile entity, the origin is at your eyes (yours, not the player's), and the dx,dy,dz in the renderAt method tells you where the tileentity is relative to your eyes.

 

So for example, if your cube only has four sides: east (+x), west(-x), north (-z), south (+z), then you need to look at the relativex (dx) and relativez  (dz)

http://greyminecraftcoder.blogspot.com.au/2013/07/blocks.html

The cube is 1 wide (x) by 1 deep (z)

 

If we consider just the east/west faces:

if dx > 0, then the cubeis to the east of our eyes, so we see the west face closest --> draw the west face last

if dx < -1, then the cube is to the west of our eyes, so we see the east face closest --> draw the east face last

if dx is between -1 and 0, then our eyes are between the two faces and they can't possibly overlap each other so it doesn't matter which one we draw last.  They can't possibly overlap any of the other faces either so we can always draw them first.

 

Similar logic for north/south (z) and up/down (dy).

 

For a cube (or rectangular prism) it's pretty straightforward. 

If you're between two faces (eg -1 < dx < 0) then draw those first.

Next, draw all the furthest-away faces

Last, draw all the closest faces.

 

Other shapes are harder and usually need maths calcs.

 

-TGG

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.