Jump to content

[1.7.2] [Solved] Particle crash by custom block renderer


Recommended Posts

Posted

Hello.

 

I'm using the lastest forge version with Java 8 and I'm getting every time a crash when I add particle to my Campfire block. So what I'm doing wrong, and no its not the particle class, because the same code without TileEntity and custom renderer worked fine.

 

 

 

package minecraftplaye.primevalforest.blocks;

import java.util.Random;

import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import minecraftplaye.primevalforest.PrimevalForest;
import minecraftplaye.primevalforest.items.PFItems;
import minecraftplaye.primevalforest.tilentities.TileEntityCampFire;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;

public class BlockPFCampFire extends Block implements ITileEntityProvider
{

protected BlockPFCampFire() 
{
	super(Material.wood);

	this.setStepSound(Block.soundTypeWood);
        this.setHardness(3.0F);
}

@Override
    /**
     * Returns a new instance of a block's tile entity class. Called on placing the block.
     */
public TileEntity createNewTileEntity(World world, int var2)
{
	return new TileEntityCampFire();
}

    public IIcon getIcon(int side, int meta)
    {
        return Blocks.log.getIcon(side, 0);
    }
    
    // It's not an opaque cube, so you need this.
    @Override
    public boolean isOpaqueCube()
    {
        return false;
    }
    
    // You don't want the normal render type, or it wont render properly.
    @Override
    public int getRenderType()
    {
        return -1;
    }
    
    // It's not a normal block, so you need this too.
    @Override
    public boolean renderAsNormalBlock()
    {
        return false;
    }
    
    @Override
    /**
     * Returns the items to drop on destruction.
     */
    public Item getItemDropped(int metadata, Random random, int fortune)
    {
        return Items.stick;
    }
    
    @Override
    /**
     * Returns the quantity of items to drop on block destruction.
     */
    public int quantityDropped(Random random)
    {
        return 3;
    }
    
    @Override
    @SideOnly(Side.CLIENT)
    /**
     * only called by clickMiddleMouseButton, and passed to inventory.setCurrentItem (along with isCreative)
     */
    public Item getItem(World world, int x, int y, int z)
    {
        return PFItems.campFireItem;
    }
    
    @Override
    /**
     * Updates the blocks bounds based on its current state. Args: world, x, y, z
     */
    public void setBlockBoundsBasedOnState(IBlockAccess world, int x, int y, int z)
    {
        int l = world.getBlockMetadata(x, y, z) & 7;

        switch (l)
        {
            case 1:
            default:
                this.setBlockBounds(0.25F, 0.0F, 0.25F, 0.75F, 0.5F, 0.75F);
                break;
        }

        /*switch (l)
        {
            case 1:
            default:
                this.setBlockBounds(0.25F, 0.0F, 0.25F, 0.75F, 0.5F, 0.75F);
                break;
            case 2:
                this.setBlockBounds(0.25F, 0.25F, 0.5F, 0.75F, 0.75F, 1.0F);
                break;
            case 3:
                this.setBlockBounds(0.25F, 0.25F, 0.0F, 0.75F, 0.75F, 0.5F);
                break;
            case 4:
                this.setBlockBounds(0.5F, 0.25F, 0.25F, 1.0F, 0.75F, 0.75F);
                break;
            case 5:
                this.setBlockBounds(0.0F, 0.25F, 0.25F, 0.5F, 0.75F, 0.75F);
        }*/
    }
    
    @Override
    /**
     * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
     * cleared to be reused)
     */
    public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z)
    {
        this.setBlockBoundsBasedOnState(world, x, y, z);
        return super.getCollisionBoundingBoxFromPool(world, x, y, z);
    }

    @Override
    /**
     * Called when the block is placed in the world.
     */
    public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase livingBase, ItemStack itemStack)
    {
    	if(world.isRemote)
    		return;
    	
    	if(livingBase instanceof EntityPlayer)
    	{
            int l = MathHelper.floor_double((double)(livingBase.rotationYaw * 4.0F / 360.0F) + 2.5D) & 3;
            world.setBlockMetadataWithNotify(x, y, z, l, 2);
    	}
    }

    @Override
    public void breakBlock(World world, int x, int y, int z, Block blocks, int par6)
    {
        super.breakBlock(world, x, y, z, blocks, par6);
    }

@Override
    @SuppressWarnings("static-access")
    /**
     * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
     */
    public boolean canPlaceBlockAt(World world, int x, int y, int z)
    {
        return world.doesBlockHaveSolidTopSurface(world, x, y - 1, z);
    }

/**
 * Spawns flame particle over the camp fire
 */
@Override
@SideOnly(Side.CLIENT)
public void randomDisplayTick(World world, int x, int y, int z, Random random)
{
	TileEntityCampFire tile = (TileEntityCampFire)world.getTileEntity(x, y, z);

	for(int i = 0; i < 3; i++)
	{
		float motionY = (random.nextFloat() / 40F) + 0.025F;

		double particleX = ((x + 0.5F) - 0.15F) + (random.nextInt(30) / 100F);
		double particleY = y + 0.1F + (random.nextInt(15) / 100F);
		double particleZ = ((z + 0.5F) - 0.15F) + (random.nextInt(30) / 100F);

		PrimevalForest.proxy.spawnFlame(world, particleX, particleY, particleZ, 0.0F, motionY, 0.0F, 16);
		world.spawnParticle("smoke", particleX, particleY, particleZ, 0.0D, 0.05D, 0.0D);
	}
}

@Override
    @SuppressWarnings("static-access")
    /**
     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
     * their own) Args: x, y, z, neighbor blockID
     */
    public void onNeighborBlockChange(World world, int x, int y, int z, Block blocks)
    {
        if (!world.isRemote)
        {
            int i1 = world.getBlockMetadata(x, y, z);
            int j1 = i1;
            boolean flag = false;

            if (!world.doesBlockHaveSolidTopSurface(world, x, y - 1, z))
            {
                flag = true;
            }
            
            if (world.doesBlockHaveSolidTopSurface(world, x, y + 1, z))
            {
                flag = true;
            }

            if (flag)
            {
                this.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0);
                world.setBlockToAir(x, y, z);
            }
            else
            {
                this.func_94358_a(world, x, y, z, i1, j1, blocks);
            }
        }
    }
    
    protected void func_94358_a(World world, int x, int y, int z, int par5, int par6, Block blocks) {}
}

 

 

 

 

 

package minecraftplaye.primevalforest.client.render;

import org.lwjgl.opengl.GL11;

import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
import cpw.mods.fml.client.registry.RenderingRegistry;
import minecraftplaye.primevalforest.client.model.ModelCampFire;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;

public class RenderTileEntityCampFire extends TileEntitySpecialRenderer
{

    private final ModelCampFire model;
    public static int blockRenderId = RenderingRegistry.getNextAvailableRenderId();
    
    public RenderTileEntityCampFire()
    {
        this.model = new ModelCampFire();
    }
    
    @Override
    public void renderTileEntityAt(TileEntity te, double x, double y, double z, float scale)
    {
        //The PushMatrix tells the renderer to "start" doing something.
        GL11.glPushMatrix();
        //This is setting the initial location.
        GL11.glTranslatef((float) x + 0.5F, (float) y + 1.5F, (float) z + 0.5F);
        //This is the texture of your block. It's pathed to be the same place as your other blocks here.
        //ResourceLocation textures = (new ResourceLocation("primevalforest:textures/model/campFire.png"));
        //the ':' is very important
        //binding the textures
        Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation("primevalforest:textures/model/campFire.png"));
        //This rotation part is very important! Without it, your model will render upside-down! And for some reason you DO need PushMatrix again!
        GL11.glPushMatrix();
        GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
        //A reference to your Model file. Again, very important.
        this.model.render((Entity)null, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F);
        //Tell it to stop rendering for both the PushMatrix's
        GL11.glPopMatrix();
        GL11.glPopMatrix();
    }

    private void adjustRotatePivotViaMeta(World world, int x, int y, int z)
    {
        int meta = world.getBlockMetadata(x, y, z);
        GL11.glPushMatrix();
        GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
        GL11.glPopMatrix();
    }

    //Set the lighting stuff, so it changes it's brightness properly.
    /*@SuppressWarnings("unused")
private void adjustLightFixture(World world, int i, int j, int k, Block block)
    {
        Tessellator tess = Tessellator.instance;
        float brightness = block.getBlockBrightness(world, i, j, k);
        int skyLight = world.getLightBrightnessForSkyBlocks(i, j, k, 0);
        int modulousModifier = skyLight % 65536;
        int divModifier = skyLight / 65536;
        tess.setColorOpaque_F(brightness, brightness, brightness);
        OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float) modulousModifier,  divModifier);
    }*/
}

 

 

 

 

 

package minecraftplaye.primevalforest.tilentities;

import java.util.Random;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;

public class TileEntityCampFire extends TileEntity
{

    /** The Camp Fire rotation. */
    private int campFireRotation;

    public TileEntityCampFire() {}
    
    @Override
    /**
     * Writes a tile entity to NBT.
     */
    public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    {
        super.writeToNBT(par1NBTTagCompound);
        par1NBTTagCompound.setByte("Rot", (byte)(this.campFireRotation & 255));
    }

    @Override
    /**
     * Reads a tile entity from NBT.
     */
    public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    {
        this.campFireRotation = par1NBTTagCompound.getByte("Rot");
    }

    @Override
    /**
     * Overridden in a sign to provide the text.
     */
    public S35PacketUpdateTileEntity getDescriptionPacket()
    {
        NBTTagCompound nbttagcompound = new NBTTagCompound();
        this.writeToNBT(nbttagcompound);
        return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 4, nbttagcompound);
    }
    
    /**
     * Set the skull's rotation
     */
    public void setSkullRotation(int par1)
    {
        this.campFireRotation = par1;
    }

    @SideOnly(Side.CLIENT)
    public int func_82119_b()
    {
        return this.campFireRotation;
    }
}

 

 

 

And yes, I tested it with different Forge versions...

 

Oh and before I forget it ... here is the crash:

 

 

---- Minecraft Crash Report ----
// Ooh. Shiny.

Time: 13.06.14 23:17
Description: Exception in server tick loop

java.lang.ArrayIndexOutOfBoundsException: -88
at net.minecraft.world.chunk.NibbleArray.get(NibbleArray.java:42)
at net.minecraft.world.chunk.storage.ExtendedBlockStorage.getExtBlockMetadata(ExtendedBlockStorage.java:125)
at net.minecraft.world.chunk.Chunk.getBlockMetadata(Chunk.java:620)
at net.minecraft.world.chunk.Chunk.func_150812_a(Chunk.java:967)
at net.minecraft.world.chunk.Chunk.addTileEntity(Chunk.java:951)
at net.minecraft.world.chunk.storage.AnvilChunkLoader.loadEntities(AnvilChunkLoader.java:529)
at net.minecraftforge.common.chunkio.ChunkIOProvider.callStage2(ChunkIOProvider.java:41)
at net.minecraftforge.common.chunkio.ChunkIOProvider.callStage2(ChunkIOProvider.java:12)
at net.minecraftforge.common.util.AsynchronousExecutor.skipQueue(AsynchronousExecutor.java:344)
at net.minecraftforge.common.util.AsynchronousExecutor.getSkipQueue(AsynchronousExecutor.java:302)
at net.minecraftforge.common.chunkio.ChunkIOExecutor.syncChunkLoad(ChunkIOExecutor.java:12)
at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:140)
at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:115)
at net.minecraft.server.MinecraftServer.initialWorldChunkLoad(MinecraftServer.java:307)
at net.minecraft.server.integrated.IntegratedServer.loadAllWorlds(IntegratedServer.java:79)
at net.minecraft.server.integrated.IntegratedServer.startServer(IntegratedServer.java:96)
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:442)
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:747)


A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------

-- System Details --
Details:
Minecraft Version: 1.7.2
Operating System: Windows 8.1 (amd64) version 6.3
Java Version: 1.8.0_05, Oracle Corporation
Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation
Memory: 873440400 bytes (832 MB) / 1038876672 bytes (990 MB) up to 1038876672 bytes (990 MB)
JVM Flags: 3 total; -Xincgc -Xmx1024M -Xms1024M
AABB Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
IntCache: cache: 15, tcache: 0, allocated: 13, tallocated: 95
FML: MCP v9.03 FML v7.2.211.1124 Minecraft Forge 10.12.2.1124 4 mods loaded, 4 mods active
mcp{9.03} [Minecraft Coder Pack] (minecraft.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available
FML{7.2.211.1124} [Forge Mod Loader] (forgeSrc-1.7.2-10.12.2.1124.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available
Forge{10.12.2.1124} [Minecraft Forge] (forgeSrc-1.7.2-10.12.2.1124.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available
primevalforest{Dev Build 1 - Beta 0.0.9} [Primeval Forest] (bin) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available
Profiler Position: N/A (disabled)
Vec3 Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
Player Count: 0 / 8; []
Type: Integrated Server (map_client.txt)
Is Modded: Definitely; Client brand changed to 'fml,forge'

 

 

 

Bektor

Developer of Primeval Forest.

Posted

Hi

 

The problem is related to your TileEntity setup code.

FYI I traced it back like this:

NibbleArray::
    /**
     * Returns the nibble of data corresponding to the passed in x, y, z. y is at most 6 bits, z is at most 4.
     */
    public int get(int par1, int par2, int par3)
    {
        int l = par2 << this.depthBitsPlusFour | par3 << this.depthBits | par1;
        int i1 = l >> 1;
        int j1 = l & 1;
        return j1 == 0 ? this.data[i1] & 15 : this.data[i1] >> 4 & 15;   // From Error log: error is here, i1 is -88
    }

So int par1, par2, and par3 are out of the expected range, and from the index it looks one or more is probably negative when they're expected to be positive

Tracing this back up through the list of callers brings us eventually to 

 

    public void addTileEntity(TileEntity p_150813_1_)
    {
        int i = p_150813_1_.xCoord - this.xPosition * 16;
        int j = p_150813_1_.yCoord;
        int k = p_150813_1_.zCoord - this.zPosition * 16;
        this.func_150812_a(i, j, k, p_150813_1_);             // i, j, and/or k are out of expected range, probably smaller than the chunk [x,y,z] position

//[..]
    }

 

So it looks to me like your TileEntity x coordinate and/or z coordinate is wrong for the chunk that it's being added to; the vanilla assumes that the TileEntity [x,y,z] will be within the  16x256x16 block cube for that chunk.

A search through the code shows that xCoord is normally set in only two places:

Chunk.setChunkBlockTileEntity()

and

TileEntity.readFromNBT()

 

Your TileEntity had an override of readFromNBT, so what should that look like for a vanilla TileEntity such as TileEntityChest?

 

TileEntityChest::
    /**
     * Reads a tile entity from NBT.
     */
    public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    {
        super.readFromNBT(par1NBTTagCompound);
        NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items");

--> I think this is the problem - compare with yours

 

-TGG

 

Posted

Well... :P I am wondering the same thing. I have made a small fix for this problem by creating an item that places the wanted block via the onItemUse() method. Then, from there, create an IItemRenderer (I think its called) and register it. Then for the actual rendering you use your tile entity renderer and position 0,0,0.

 

But I would like to know the better way of doing it...

We all stuff up sometimes... But I seem to be at the bottom of that pot.

Posted

@TGG How does ISimpleBlockRenderingHandler take care of rendering a block in the inventory? Can you give an example?

We all stuff up sometimes... But I seem to be at the bottom of that pot.

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

    • So me and a couple of friends are playing with a shitpost mod pack and one of the mods in the pack is corail tombstone and for some reason there is a problem with it, where on death to fire the player will get kicked out of the server and the tombstone will not spawn basically deleting an entire inventory, it doesn't matter what type of fire it is, whether it's from vanilla fire/lava, or from modded fire like ice&fire/lycanites and it's common enough to where everyone on the server has experienced at least once or twice and it doesn't give any crash log. a solution to this would be much appreciated thank you!
    • It is 1.12.2 - I have no idea if there is a 1.12 pack
    • Okay, but does the modpack works with 1.12 or just with 1.12.2, because I need the Forge client specifically for Minecraft 1.12, not 1.12.2
    • 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() ); } }  
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

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