Jump to content

Recommended Posts

Posted

Hello!

 

Due to my derp nature, I felt the need to make a door mob in-game (literally, a door which walks around and beets the shizz out of you). As many of you may know, you can only ever see up to three sides of a block when you look at it, this means if the block is transparent, you can't see textures from the other side of the block.

 

This is the case for doors as well. Doors have a window in the top part of the block, because of the above rule you can look through the window and never see the other side of the door.

 

Unfortunately, this rule doesn't apply to rendering mobs. Mobs appear to have all sides rendered, meaning if you have create a door and look through the window you will still see the back of the door.

 

An screenshot below I took illustrates this:

 

width=800 height=424DvTJrqK.png?1 [/img]

 

Could somebody please explain to me how I would create a mob with the same effect as the door has.

 

I haven't supplied code because I didn't feel it was needed, if code is needed please ask.

 

Thanks!

 

~Joe

Posted

But this would make one side look like it has a massive hole in it, surely that's worse?

 

I had hoped there was some option to disable rendering invisible sides.

Posted

I had hoped there was some option to disable rendering invisible sides.

 

The problem is that the back side is NOT invisible.  I mean the transparency on the front side means that the graphics engine will try to render the back too -- I think even with culling it would decide that it should be rendered.  I'm not expert on this, just thinking that a good graphics engine would try to do that.

 

But this would make one side look like it has a massive hole in it, surely that's worse?

 

Well, it is good to be picky, but I'm not sure it would look that bad -- I'm suggesting to just remove the lattice between the panes in the window on the back side.  There would still be the lattice on the other side which people would see from the back (indeed that is your current problem from the front).

 

Anyway, someone that is good with the rendering may know a better way to do client-side disabling.  However, a block is different than an entity because blocks have a regular model and so the idea of sides is well-defined whereas generally entities have all sorts of moving pieces and so I don't think there is a general solution.

 

One other idea is to swap the texture depending on what side of the entity is facing the player running the client.  That would take a little bit of coding, but shouldn't be too hard.  So you could use a texture with the back transparent if the front is facing player, and use a texture with the front transparent if the back is facing the player.

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

Posted

Try comparing the yaws of your entity and the player and switching between two textures depending on what side of the door the player is facing. Each texture would have a different side of the door transparent!

Posted

I had hoped there was some option to disable rendering invisible sides.

 

The problem is that the back side is NOT invisible.  I mean the transparency on the front side means that the graphics engine will try to render the back too -- I think even with culling it would decide that it should be rendered.  I'm not expert on this, just thinking that a good graphics engine would try to do that.

 

But this would make one side look like it has a massive hole in it, surely that's worse?

 

Well, it is good to be picky, but I'm not sure it would look that bad -- I'm suggesting to just remove the lattice between the panes in the window on the back side.  There would still be the lattice on the other side which people would see from the back (indeed that is your current problem from the front).

 

Anyway, someone that is good with the rendering may know a better way to do client-side disabling.  However, a block is different than an entity because blocks have a regular model and so the idea of sides is well-defined whereas generally entities have all sorts of moving pieces and so I don't think there is a general solution.

 

One other idea is to swap the texture depending on what side of the entity is facing the player running the client.  That would take a little bit of coding, but shouldn't be too hard.  So you could use a texture with the back transparent if the front is facing player, and use a texture with the front transparent if the back is facing the player.

 

In fact, I think it would be easier (possible more efficient?) to just create a model which is made of 6 cubes shaped like a door, that way the "inside" sides of the cubes could be textured to be transparent.

 

The only problem I could see, is Techne seems to have a bug when texturing objects - if I have two cubes in Techne, they will use the same coordinates on the texture map meaning I can't have individual textures :S Please not it is completely possible that this is not a bug and is me being a derp; I don't have to time to conduct proper research right now :P

 

I think that the reason blocks have this feature and entities do not is because entities are more subject to moving around and exposing the "invisible" sides. Blocks don't turn around, the only way the invisible sides can be rendered is for the player to move around the block.

 

Try comparing the yaws of your entity and the player and switching between two textures depending on what side of the door the player is facing. Each texture would have a different side of the door transparent!

 

This may be the way I have to go, but it seems a bit sloppy? I would need 6 textures, which seems a bit stupid :S

 

Why? The door has 6 sides, therefore there are 6 possible combinations of the 3 sides the player can see, for each one of those combinations there are 3 sides which should be invisible. I certainly don't like the sound of having to:

 

a) make 6 textures for each one of these blocks I am making (more blocks to be like this one)

 

b) use this method - I hate hard coding stuff like this :( (it's not the nature of programming...).

 

Thanks for both of your replies, I suspect when I get home later today I will have bigger and deeper look at this (hopefully finding some kind of holy grail).

 

~Joe

Posted

Hi

 

There is an easy way to do this, it is called back face culling.  If you turn culling off, the game will render both sides of each face.  If you turn back face culling on, you will only see one of them.

 

        GL11.glCullFace(GL11.GL_BACK);

        GL11.glEnable(GL11.GL_CULL_FACE);

or

        GL11.glDisable(GL11.GL_CULL_FACE);

 

 

This guide to openGL is pretty good and has more details.

http://www.glprogramming.com/red/

 

This link talks a bit about the tessellator and the "sides" of faces if you turn back face culling on.

 

http://greyminecraftcoder.blogspot.com.au/2013/08/the-tessellator.html

 

-TGG

Posted

Hmm, I was thinking that backface culling wouldn't work if the front polygon is transparent -- normally in backface culling you use it for polygons that are fully not visible, but I guess you are right -- it will probably cull the back face anyway since that is usually determined simply by the direction considered the outside of the surface.  Basically in this particular case he wants an artifact that is usually undesirable.

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.