Jump to content

[1.10.2] Lamp won't update lighting properly


That_Martin_Guy
 Share

Recommended Posts

My lamp has a tile entity that updates its lighting depending on how much power it holds. The lighting doesn't update properly, though. When I place the lamp it is at full brightness, if it's power level reduces it goes a tad bit darker, but not mutch. It never completely goes black. When I break the block the lighting doesn't update and lingers until I restart the world. What am I doing wrong?

 

BlockLamp

public class BlockLamp extends Block implements ITileEntityProvider
{
    int capacity;
    int loss;
    float lifetime;
    float lowEnergyMultiplier;
    float mediumEnergyMultiplier;
    float highEnergyMultiplier;

    public BlockLamp(Material material, String name, float lightLevel, float lifetime, int capacity, int loss)
    {
        this(material, name, lightLevel, lifetime, capacity, loss, 1, 2, 3);
    }

    public BlockLamp(Material material, String name, float lightLevel , float lifetime, int capacity, int loss, float lowEnergyMultiplier, float mediumEnergyMultiplier, float highEnergyMultiplier)
    {
        super(material);
        this.setUnlocalizedName(name);
        this.setRegistryName(name);
        this.setCreativeTab(BrightenUp.tabBrightenUp);
        this.setLightLevel(lightLevel);

        this.loss = loss;
        this.capacity = capacity;
        this.lifetime = lifetime;
        this.lowEnergyMultiplier = lowEnergyMultiplier;
        this.mediumEnergyMultiplier = mediumEnergyMultiplier;
        this.highEnergyMultiplier = highEnergyMultiplier;
    }

    @Override
    public TileEntity createNewTileEntity(World worldIn, int meta)
    {
        return new TileEntityLamp(capacity, loss, lifetime, lowEnergyMultiplier, mediumEnergyMultiplier, highEnergyMultiplier);
    }

    @Override
    public void breakBlock(World worldIn, BlockPos pos, IBlockState state)
    {
        if(worldIn.getTileEntity(pos) instanceof TileEntityLamp)
        {
            worldIn.removeTileEntity(pos);
        }
    }

    public float getBaseLightValue()
    {
        return this.lightValue;
    }
}

 

TileEntityLamp

public class TileEntityLamp extends TileEntity implements ITickable, IEnergyReceiver
{
    EnergyStorage storage;
    int loss;
    float lifetime;
    float lowEnergyMultiplier;
    float mediumEnergyMultiplier;
    float highEnergyMultiplier;

    public TileEntityLamp(int capacity, int loss, float lifetime, float lowEnergyMultiplier, float mediumEnergyMultiplier, float highEnergyMultiplier)
    {
        storage = new EnergyStorage(capacity);
        this.loss = loss;
        this.lifetime = lifetime;
        this.lowEnergyMultiplier = lowEnergyMultiplier;
        this.mediumEnergyMultiplier = mediumEnergyMultiplier;
        this.highEnergyMultiplier = highEnergyMultiplier;
    }

    @Override
    public void update()
    {
            if (this.worldObj.getBlockState(this.pos).getBlock() instanceof BlockLamp)
            {
                BlockLamp lamp = (BlockLamp) this.worldObj.getBlockState(pos).getBlock();
                EnergyLevel previousLevel = this.getEnergyLevel();
                System.out.println(this.getEnergyPercentage());
                storage.modifyEnergyStored(-loss);
                if (this.getEnergyLevel() != previousLevel)
                {
                    switch (this.getEnergyLevel())
                    {
                        case EMPTY:
                            lamp.setLightLevel(0);
                            break;
                        case LOW:
                            this.lifetime -= 1 * lowEnergyMultiplier;
                            lamp.setLightLevel(lamp.getBaseLightValue());
                            break;
                        case MEDIUM:
                            this.lifetime -= 1 * mediumEnergyMultiplier;
                            lamp.setLightLevel(lamp.getBaseLightValue() * 3);
                            break;
                        case HIGH:
                            this.lifetime -= 1 * highEnergyMultiplier;
                            lamp.setLightLevel(lamp.getBaseLightValue() * 5);
                            break;
                    }
                    this.worldObj.notifyBlockUpdate(pos, this.worldObj.getBlockState(pos), this.worldObj.getBlockState(pos), 3);
                }
                this.markDirty();
            }
        this.worldObj.checkLightFor(EnumSkyBlock.BLOCK, pos);
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound)
    {
        super.writeToNBT(compound);
        storage.writeToNBT(compound);
        compound.setFloat("lifetime", lifetime);
        return compound;
    }

    @Override
    public void readFromNBT(NBTTagCompound compound)
    {
        super.readFromNBT(compound);
        storage.readFromNBT(compound);
        lifetime = compound.getFloat("lifetime");
    }

    @Override
    public int receiveEnergy(EnumFacing from, int maxReceive, boolean simulate)
    {
        return storage.receiveEnergy(maxReceive, simulate);
    }

    @Override
    public int getEnergyStored(EnumFacing from)
    {
        return storage.getEnergyStored();
    }

    @Override
    public int getMaxEnergyStored(EnumFacing from)
    {
        return storage.getMaxEnergyStored();
    }

    @Override
    public boolean canConnectEnergy(EnumFacing from)
    {
        return from == EnumFacing.DOWN || from == EnumFacing.UP;
    }

    private float getEnergyPercentage()
    {
        return (storage.getEnergyStored() * 100) / storage.getMaxEnergyStored();
    }

    public EnergyLevel getEnergyLevel()
    {
        if(this.getEnergyPercentage() <= 40)
        {
            return EnergyLevel.LOW;
        }
        else if(this.getEnergyPercentage() > 40 && this.getEnergyPercentage() < 60)
        {
            return EnergyLevel.MEDIUM;
        }
        else if(this.getEnergyPercentage() <= 0)
        {
            return EnergyLevel.EMPTY;
        }
        else
        {
            return EnergyLevel.HIGH;
        }
    }

    public enum EnergyLevel
    {
        EMPTY,
        LOW,
        MEDIUM,
        HIGH
    }
}

 

I have also tried having the block handle the update, but that had a similar result. Any ideas?

Link to comment
Share on other sites

20 minutes ago, That_Martin_Guy said:

ITileEntityProvider

Is outdated. Use Block::createTileEntity and Block::hasTileEntity. 

 

20 minutes ago, That_Martin_Guy said:

BlockLamp lamp = (BlockLamp) this.worldObj.getBlockState(pos).getBlock();

 

20 minutes ago, That_Martin_Guy said:

lamp.setLightLevel(0);

Blocks are singletons. Tile entities are not. You can't change the value like that as the change will be reflected on all lamps in the world. 

You can override Block::getLightValue(IBlockState, IBlockAccess, BlockPos) and return the appropriate light level there based on the tile you get at the coordinates. You will also have to call World::checkLight to redraw the light levels around your lamp as you change them as they are not updated automatically for you.

Link to comment
Share on other sites

I added

    @Override
    public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos)
    {
        if(world.getTileEntity(pos) instanceof TileEntityLamp)
        {
            TileEntityLamp tileEntity = (TileEntityLamp) world.getTileEntity(pos);
            TileEntityLamp.EnergyLevel energyLevel = tileEntity.getEnergyLevel();

            switch(energyLevel)
            {
                case LOW:
                    return getBaseLightValue();
                case MEDIUM:
                    return getBaseLightValue() * 3;
                case HIGH:
                    return getBaseLightValue() * 5;
                default:
                    return 0;
            }
        }
        return 0;
    }

to my block and changed the tile entity's update method to

    @Override
    public void update()
    {
            if (this.worldObj.getBlockState(this.pos).getBlock() instanceof BlockLamp)
            {
                EnergyLevel previousLevel = this.getEnergyLevel();
                System.out.println(this.getEnergyPercentage());
                storage.modifyEnergyStored(-loss);
                if (this.getEnergyLevel() != previousLevel)
                {
                    switch (this.getEnergyLevel())
                    {
                        case LOW:
                            this.lifetime -= 1 * lowEnergyMultiplier;
                            break;
                        case MEDIUM:
                            this.lifetime -= 1 * mediumEnergyMultiplier;
                            break;
                        case HIGH:
                            this.lifetime -= 1 * highEnergyMultiplier;
                            break;
                    }
                    this.worldObj.checkLight(pos);
                }
                this.markDirty();
            }
    }

. Still has very similar behavior.

Link to comment
Share on other sites

Bingo! The client is always at LOW, no matter how much energy the server has. To fix this I encased the contents of 

update

in

if(!worldObj.isRemote) 

and 

getLightValue

 

in 

if(FMLCommonHandler.instance().getSide().isServer())

. The problem is that now the block doesn't have lighting at all. Does this mean that the light is checked on the client while the energy level is checked on the server? Big bummer if this is the case.

Link to comment
Share on other sites

  • You cannot store the energy level in the block class like that. The block object has singleton-like nature, i.e. there is only one instance of it for all occurrences of your Block. In single player this object is even shared between client and server. You must store any block-specific data (like the energy level in your case) in metadata or in the TileEntity.
  • Do not send the energy level to all players. This would include players in other dimensions, which means the client would incorrectly try to set the energy level of whatever is at the same position in their dimension. You need to use WorldServer::getPlayerChunkMap().getEntry(chunkX, chunkZ).players to obtain all players tracking the chunk containing your TileEntity (to convert block coordinates into chunk coordinates use chunkCoord = blockCoord >> 4). Then send your packet to all those players. Alternatively you can use the methods getUpdateTaghandleUpdateTaggetUpdatePacket and onDataPacket to use the built-in methods for TileEntity data syncing. Due to being based on NBT these have some overhead though.
  • Why are you calling markDirty every tick?
Link to comment
Share on other sites

40 minutes ago, diesieben07 said:
  • (to convert block coordinates into chunk coordinates use chunkCoord = blockCoord >> 4).

Doesn't seem to be possible to convert it like this, unless I'm doing something wrong. I got the method you mentioned this way instead:

worldObj.getMinecraftServer().worldServerForDimension(worldObj.provider.getDimension()).getPlayerChunkMap().getEntry(worldObj.getChunkFromBlockCoords(pos).xPosition, worldObj.getChunkFromBlockCoords(pos).zPosition)

. The problem is that I can't add .players to the end of this line. Further digging reveals that the only players field in PlayerChunkMapEntry is a private final List<EntityPlayerMP>. How do I access this field?

49 minutes ago, diesieben07 said:
  • Why are you calling markDirty every tick?

Woops! Mistake on my part. Don't know when I moved it, but it's only supposed to be called if the energy value actually changed.

Link to comment
Share on other sites

3 minutes ago, That_Martin_Guy said:

Doesn't seem to be possible to convert it like this, unless I'm doing something wrong. I got the method you mentioned this way instead: <snip>

That way is terrible and slow. Show what you tried that did not work.

 

4 minutes ago, That_Martin_Guy said:

Further digging reveals that the only players field in PlayerChunkMapEntry is a private final List<EntityPlayerMP>. How do I access this field?

I forgot to mention this, you will need reflection to access it.

Link to comment
Share on other sites

53 minutes ago, diesieben07 said:

I forgot to mention this, you will need reflection to access it.

Never heard of reflection before, so I looked it up. I tried to find something related to getting a private List with a non-generic type, but I didn't find anything. I'm completely lost here. I tried 

Class<?> playerEntry = worldObj.getMinecraftServer().worldServerForDimension(worldObj.provider.getDimension()).getPlayerChunkMap().getEntry(worldObj.getChunkFromBlockCoords(pos).xPosition, worldObj.getChunkFromBlockCoords(pos).zPosition).getClass();
                    try
                    {
                        Field players = playerEntry.getDeclaredField("players");
                        List<EntityPlayerMP> playerList = players.getDeclaringClass().cast(List<EntityPlayerMP>());
                    }
                    catch (NoSuchFieldException e)
                    {
                        e.printStackTrace();
                    }
                    catch (IllegalAccessException e)
                    {
                        e.printStackTrace();
                    }

, but IDEA gives me "Expression expected" under

//                                                                 this here
//                                                                 |                   |
//                                                                 \/                  \/
List<EntityPlayerMP> playerList = players.getDeclaringClass().cast(List<EntityPlayerMP>());

.

Link to comment
Share on other sites

  • Don't use getClass to obtain the class, use a ClassName.class literal.
  • Do not look up the Field every time you need it. Do it once and store the Field in a static final field. I also recommend you use FMLs ReflectionHelper, since you will need to provide the SRG name of the field as well. Use MCPBot to look it up.
  • Just use a normal cast operation.
Link to comment
Share on other sites

This is not how you get a value from a field using reflection. There is a Field::get(Object) method you must call to get a value the field stores. The object parameter is an instance of a class the field belongs to. If the field is static you simply pass null. If not - you need to pass the instance to get the value from.

Additionaly you need to call Field::setAccessible(true) before doing anything with a field, as if it is not public you will get your access denied.

Link to comment
Share on other sites

I feel like I'm getting close, but I still have a problem. The lighting doesn't update properly (only seems to send network messages when un-charging) and every time the energy level changes the lamp turns on for a split second, then immediatly turns off.

 

Some changes to the code are a new IProperty called PropertyEnum in the block class for the energy level, EnergyLevel is now in a seperate class (thatmartinguy.brightenup.energy.EnergyLevel) and the LampEnergyMessage now requires a string (to be converted into an enum) and a pos instead of an int and a pos.

 

Github

Link to comment
Share on other sites

  • You now have data duplication, which is terrible. When you change the energy, you always have to remember to also update the block state, or things will get out of sync. In addition, you do not save this ENERGY_LEVEL property anywhere. Block state properties do not persist "by magic". You must either serialize them to 4-Bit metadata (override getStateFromMeta and getMetaFromState) or get them from somewhere else (e.g. your TileEntity). In your case you want the latter (since the value is already stored there). You need to use getActualState for this.
    But you do not really need this block state property anyways, you can just access the TileEntity data directly in getLightValue.
  • Your TileEntity moreover again duplicates the "how much energy do I have" information, by having both the EnergyStorage and the EnergyLevel stored. But this is completely broken, since you never write any meaningful value to the energyLevel field.
  • As a side note, why in gods name are all your fields package-visible and not final? Make things final if possible! And why do you duplicate some fields (the energy multipliers) between your TE and your Block?
  • What on earth is this construct: (worldObj.getMinecraftServer().worldServerForDimension(worldObj.provider.getDimension())?
  • Construct the IMessage instance once and then send it to all players. Also, please use an enhanced for loop ("foreach loop") and not this atrocious "i keep track of my own indices" stuff.
  • Why is your energy level in the packet a String?
  • Don't just print out exceptions to the console and carry on as if nothing was wrong.
Link to comment
Share on other sites

You can definitely tell I was tired when programming this because... Oh god it's horrible. Let's just go through the list shall we?

On 2017-06-22 at 10:46 PM, diesieben07 said:

But you do not really need this block state property anyways, you can just access the TileEntity data directly in getLightValue.

Fully agree. State removed, replaced all the blockstate related methods with this change in getLightValue:

    public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos)
    {
        if(world.getTileEntity(pos) instanceof TileEntityLamp)
        {
            TileEntityLamp lamp = (TileEntityLamp) world.getTileEntity(pos);
            switch(lamp.getEnergyLevel())
            {
                case LOW:
                    return getBaseLightValue();
                case MEDIUM:
                    return getBaseLightValue() * 2;
                case HIGH:
                    return getBaseLightValue() * 5;
            }
            System.out.println(lamp.getEnergyLevel());
        }
        return 0;
    }

and LampEnergyMessage#Handler#onMessage to 

        public IMessage onMessage(LampEnergyMessage message, MessageContext ctx)
        {
            FMLCommonHandler.instance().getWorldThread(ctx.getClientHandler()).addScheduledTask(() ->
            {
               final World world = Minecraft.getMinecraft().theWorld;
               assert world != null;

               if(world.getTileEntity(message.pos) instanceof TileEntityLamp)
               {
                   TileEntityLamp lamp = (TileEntityLamp) world.getTileEntity(message.pos);
                   lamp.setEnergyLevel(EnergyLevel.valueOf(message.energyLevel.toUpperCase()));
                   world.checkLight(message.pos);
                   System.out.println("Message sent as " + message.energyLevel.toUpperCase());
               }
            });
            return null;
        }

. TileEntityLamp#getEnergyLevel and setEnergyLevel are the simplest getters and setters you can get and not really worth posting.

On 2017-06-22 at 10:46 PM, diesieben07 said:

Your TileEntity moreover again duplicates the "how much energy do I have" information, by having both the EnergyStorage and the EnergyLevel stored. But this is completely broken, since you never write any meaningful value to the energyLevel field.

...

Construct the IMessage instance once and then send it to all players. Also, please use an enhanced for loop ("foreach loop") and not this atrocious "i keep track of my own indices" stuff.

Thank you for the heads up! Completely missed that I didn't ever change energyLevelTileEntityLamp#update has been changed to

    public void update()
    {
        if(!worldObj.isRemote)
        {
            if (worldObj.getBlockState(this.pos).getBlock() instanceof BlockLamp)
            {
                EnergyLevel previousLevel = EnergyLevel.getEnergyLevel(storage.getEnergyStored(), storage.getMaxEnergyStored());
                storage.modifyEnergyStored(-loss);
                if (EnergyLevel.getEnergyLevel(storage.getEnergyStored(), storage.getMaxEnergyStored()) != previousLevel)
                {
                    switch (EnergyLevel.getEnergyLevel(storage.getEnergyStored(), storage.getMaxEnergyStored()))
                    {
                        case EMPTY:
                            energyLevel = EMPTY;
                            break;
                        case LOW:
                            this.lifetime -= 1 * lowEnergyMultiplier;
                            energyLevel = LOW;
                            break;
                        case MEDIUM:
                            this.lifetime -= 1 * mediumEnergyMultiplier;
                            energyLevel = MEDIUM;
                            break;
                        case HIGH:
                            this.lifetime -= 1 * highEnergyMultiplier;
                            energyLevel = HIGH;
                            break;
                    }
                    try
                    {
                        List<EntityPlayerMP> playerList = (List<EntityPlayerMP>) PLAYER_ENTRY_LIST.get(worldObj.getMinecraftServer().worldServerForDimension(worldObj.provider.getDimension()).getPlayerChunkMap().getEntry(worldObj.getChunkFromBlockCoords(pos).xPosition, worldObj.getChunkFromBlockCoords(pos).zPosition));
                        LampEnergyMessage message = new LampEnergyMessage(energyLevel.toString(), pos);
                        for(EntityPlayerMP player : playerList)
                        {
                            BrightenUp.network.sendTo(message, player);
                        }
                    }
                  //Hang with me on this one
                    catch (IllegalAccessException e)
                    {
                        e.printStackTrace();
                    }
                    worldObj.checkLight(pos);
                    worldObj.notifyBlockUpdate(pos, worldObj.getBlockState(pos), worldObj.getBlockState(pos), 3);
                    this.markDirty();
                }
            }
        }
    }

 

 

On 2017-06-22 at 10:46 PM, diesieben07 said:

As a side note, why in gods name are all your fields package-visible and not final? Make things final if possible! And why do you duplicate some fields (the energy multipliers) between your TE and your Block?

I honestly thought not including the access type in the declaration made it private. TIL.

Any fields that could be are now final.

I make duplicate values in both my block and TE because I don't know any other way to transfer its properties from the block to the TE (other than setting up setters in a similar way to vanilla minecraft, but IMO that makes the code way too unorganized for my taste).

On 2017-06-22 at 10:46 PM, diesieben07 said:

What on earth is this construct: (worldObj.getMinecraftServer().worldServerForDimension(worldObj.provider.getDimension())?

Don't really know a simpler to do this. The best way to get a MinecraftServer (that I've heard of) is with a World object. I didn't see any other way to call get a WorldServer without MinecraftServer other than worldServerForDimension, although I might be wrong on this. World#provider#getDimension was the only way I found were you could get a dimension ID, but again, I might be wrong.

On 2017-06-22 at 10:46 PM, diesieben07 said:

Why is your energy level in the packet a String?

'Cause I didn't find any other way to transfer enums through the network, so I figured using toString and valueOf was the second best option.

 

On 2017-06-22 at 10:46 PM, diesieben07 said:

Don't just print out exceptions to the console and carry on as if nothing was wrong.

I keep it as a simple print since I might re-design my code a lot, and it is just easier to keep it like this in case I need to move or remove it. Will definitely improve it once the lamp light works properly.

 

However, even after all of these changes, I still cannot get the lamp's lighting to work. It doesn't update when a creative energy cell is next to it, only when it would normally update (block next to it destroyed, placed etc). When it is empty it does update, however, and turns off completely. Not when it is HIGH, MEDIUM or LOW, though. 

Link to comment
Share on other sites

5 minutes ago, That_Martin_Guy said:

'Cause I didn't find any other way to transfer enums through the network, so I figured using toString and valueOf was the second best option.

Best way is to use ordinal() to turn the enum value into an int, and then values()[ordinal] to turn the int back into the enum value.

 

11 minutes ago, That_Martin_Guy said:

It doesn't update when a creative energy cell is next to it

Where is the code which is supposed to make this happen?

Link to comment
Share on other sites

34 minutes ago, That_Martin_Guy said:

Thank you for the heads up! Completely missed that I didn't ever change energyLevelTileEntityLamp#update has been changed to <snip>

This, honestly, is not much better. Like I said, you have data duplication here. You do not need to store the energyLevel value. You know it implicitly from whatever is stored in the EnergyStorage.

 

35 minutes ago, That_Martin_Guy said:

I make duplicate values in both my block and TE because I don't know any other way to transfer its properties from the block to the TE (other than setting up setters in a similar way to vanilla minecraft, but IMO that makes the code way too unorganize

Make them public (or use getters) in your block class and then access them when you need them from the TE.

 

36 minutes ago, That_Martin_Guy said:

Don't really know a simpler to do this. The best way to get a MinecraftServer (that I've heard of) is with a World object. I didn't see any other way to call get a WorldServer without MinecraftServer other than worldServerForDimension, although I might be wrong on this. World#provider#getDimension was the only way I found were you could get a dimension ID, but again, I might be wrong.

(WorldServer) world - tada, you now have a WorldServer. Jokes aside, this of course will only work when the world is actually a WorldServer, which it always is on the server thread.

Link to comment
Share on other sites

6 hours ago, Jay Avery said:

Where is the code which is supposed to make this happen?

worldObj.notifyBlockUpdate(pos, worldObj.getBlockState(pos), worldObj.getBlockState(pos), 3);

in TileEntityLamp#update? Or is this not how you update blocks?

 

Also, after applying the changes diesieben suggested the block doesn't update its lighting at all, unless by normal means (placing/breaking blocks for example). My github has been updated once again.

 

EDIT: I also feel the LampEnergyMessage is a bit unnecessary at this point, since I can call TileEntityLamp#getEnergyLevel on both sides. I'm not really using the message properly, currently. Not really sure how to set it since the old energyLevel field has been removed.

Edited by That_Martin_Guy
Link to comment
Share on other sites

  • You still have modifiable data in your Block class (lifetime field). This will not work.
  • Your packet does not do anything. It simply tells the client to re-check for light, but the client still has no idea what the energy value is, so it cannot compute the light properly.
Link to comment
Share on other sites

58 minutes ago, diesieben07 said:

Your packet does not do anything. It simply tells the client to re-check for light, but the client still has no idea what the energy value is, so it cannot compute the light properly

I'm aware of this. The problem is that I'm not sure what I want it to do. There is no EnergyLevel field, so I can't set that property somehow. I also thought that getEnergyLevel was how I was supposed to set it, since it could be called on both sides, but I guess I'm wrong.

Link to comment
Share on other sites

TE knows what the data is. --done

TE changes and sends a packet with the changed data. --half done

Client gets the packet and changes its local copy of the TE. --missing entirely

Client re-renders. --done

  • Like 1

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

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
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.

 Share



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • I am using a modified MeleeAttackGoal to make an entity pick a random button, go to it and press it. But after a while it just stops and stares at the current button target. I found out that it's just staring at it because it's too far away to press it.  And its's not moving because the current path in the mob navigation is "done". If I move it further away it recalculates a non weird path and fixes itself. If I push it towards the button so it can press it, it sets the target to null, so it once again calculates a new path and fixes itself. What is causing the path to be "done"? And how can I fix this? This is the tick method in the custom goal class: public void tick() { if (mob.buttonTarget != null) { float x = mob.buttonTarget.getX(); float y = mob.buttonTarget.getY(); float z = mob.buttonTarget.getZ(); float hx = x + 0.5f; float hy = y + 0.5f; float hz = z + 0.5f; mob.getLookControl().setLookAt(hx, hy, hz, 30.0F, 30.0F); double distSqr = mob.distanceToSqr(hx, hy, hz); ticksUntilNextPathRecalculation = Math.max(ticksUntilNextPathRecalculation - 1, 0); if ((followingTargetEvenIfNotSeen || hasLineOfSight(mob, mob.buttonTarget)) && ticksUntilNextPathRecalculation <= 0 && ((pathedTargetX == 0.0D && pathedTargetY == 0.0D && pathedTargetZ == 0.0D) || mob.buttonTarget.distSqr(new Vec3i(pathedTargetX, pathedTargetY, pathedTargetZ)) >= 1.0D || mob.getRandom().nextFloat() < 0.05F)) { pathedTargetX = hx; pathedTargetY = hy; pathedTargetZ = hz; ticksUntilNextPathRecalculation = 4 + mob.getRandom().nextInt(7); if (distSqr > 1024.0D) ticksUntilNextPathRecalculation += 10; else if (distSqr > 256.0D) ticksUntilNextPathRecalculation += 5; Path newPath = mob.getNavigation().createPath(mob.buttonTarget, 0); if (newPath != null && !newPath.canReach()) { mob.buttonTarget = null; return; } if (!mob.getNavigation().moveTo(newPath, speedModifier)) ticksUntilNextPathRecalculation += 15; ticksUntilNextPathRecalculation = adjustedTickDelay(ticksUntilNextPathRecalculation); } ticksUntilNextAttack = Math.max(getTicksUntilNextAttack() - 1, 0); checkAndPerformAttack(mob.buttonTarget, distSqr); } }  
    • As of Forge version 44.1.5 and above, Minecraft has started crashing whenever I played it with the Create mod. Without any mods, it loads normally, but when I put in a mod, like MrCrayfish's furniture mod for example, it fails to read the mod properly. Basically I press play and it loads. When the launcher closes, it opens back up again with an Exit Code 1 error, stating that the game crashed due to an unexpected error. Here's my latest.log for more information. https://pastebin.com/pUPBjpbr  
    • The files are harmed by system flaws and glitches. Additionally, the installation procedure might cause files to be lost. The game is so terminated, and an exit code 1 error is displayed. Therefore, attempt a game reinstall.
    • Hello there!  I'm hosting a Minecraft Tekxit PI server on Minecraft 1.12.2 on my computer and I have a little issue. Everything was going great until one day my light in my house went down while a friend was inside the server. The server crashed and when I came back 2 chunks swapped but everything seemed normal. Fastforward in time my friend who was inside the server tried to come back in it but everti-me he tries to join he cannot do it and there is a crash in the server logs. If any other friend tries to join they can, but, that friend that was inside the server when that occurred cannot join. I tried rebooting, rebooting my modem, deleting his player data to start over and nothing works. I'm leaving the crash logs here. Thank you!!! ----------------------------------------------- CRASH LOGS   [10:27:10] [Netty Server IO #1/INFO]: Transforming class 'gu', alias 'net.minecraft.network.NettyCompressionDecoder' [10:27:10] [Netty Server IO #1/INFO]: Scanning method 'decode(Lio/netty/channel/ChannelHandlerContext;Lio/netty/buffer/ByteBuf;Ljava/util/List;)V' [10:27:10] [Netty Server IO #1/INFO]: Patching constant (java.lang.Integer) 2097152 [10:27:10] [Netty Server IO #1/INFO]: Patching constant (java.lang.Integer) 2097152 [10:27:10] [Netty Server IO #1/INFO]: [com.creativemd.creativecore.transformer.CreativeTransformer:transform:49]: [littletiles] Patched net.minecraft.network.NettyCompressionDecoder ... [10:27:13] [Server thread/ERROR]: HandshakeMessageHandler exception java.lang.OutOfMemoryError: Java heap space     at java.util.ArrayList.<init>(Unknown Source) ~[?:1.8.0_361]     at com.google.common.collect.Lists.newArrayListWithCapacity(Lists.java:190) ~[minecraft_server.1.12.2.jar:?]     at net.minecraft.nbt.NBTTagList.read(NBTTagList.java:58) ~[ge.class:?]     at net.minecraft.nbt.NBTTagCompound.readNBT(NBTTagCompound.java:497) ~[fy.class:?]     at net.minecraft.nbt.NBTTagCompound.read(NBTTagCompound.java:58) ~[fy.class:?]     at net.minecraft.nbt.NBTTagCompound.readNBT(NBTTagCompound.java:497) ~[fy.class:?]     at net.minecraft.nbt.NBTTagCompound.read(NBTTagCompound.java:58) ~[fy.class:?]     at net.minecraft.nbt.CompressedStreamTools.read(CompressedStreamTools.java:133) ~[gi.class:?]     at net.minecraft.nbt.CompressedStreamTools.read(CompressedStreamTools.java:88) ~[gi.class:?]     at net.minecraft.nbt.CompressedStreamTools.readCompressed(CompressedStreamTools.java:31) ~[gi.class:?]     at net.minecraft.world.storage.SaveHandler.getPlayerNBT(SaveHandler.java:278) ~[bfb.class:?]     at net.minecraft.server.management.PlayerList.getPlayerNBT(PlayerList.java:340) ~[pl.class:?]     at net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.serverInitiateHandshake(NetworkDispatcher.java:220) ~[NetworkDispatcher.class:?]     at net.minecraftforge.fml.common.network.handshake.FMLHandshakeServerState$1.accept(FMLHandshakeServerState.java:49) ~[FMLHandshakeServerState$1.class:?]     at net.minecraftforge.fml.common.network.handshake.HandshakeMessageHandler.userEventTriggered(HandshakeMessageHandler.java:65) ~[HandshakeMessageHandler.class:?]     at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:329) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:315) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.fireUserEventTriggered(AbstractChannelHandlerContext.java:307) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.ChannelInboundHandlerAdapter.userEventTriggered(ChannelInboundHandlerAdapter.java:108) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:329) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:315) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.fireUserEventTriggered(AbstractChannelHandlerContext.java:307) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.ChannelInboundHandlerAdapter.userEventTriggered(ChannelInboundHandlerAdapter.java:108) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:329) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:315) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.fireUserEventTriggered(AbstractChannelHandlerContext.java:307) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.DefaultChannelPipeline$HeadContext.userEventTriggered(DefaultChannelPipeline.java:1352) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:329) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:315) ~[minecraft_server.1.12.2.jar:?]     at io.netty.channel.DefaultChannelPipeline.fireUserEventTriggered(DefaultChannelPipeline.java:920) ~[minecraft_server.1.12.2.jar:?]     at net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.insertIntoChannel(NetworkDispatcher.java:183) ~[NetworkDispatcher.class:?]     at net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.serverToClientHandshake(NetworkDispatcher.java:154) ~[NetworkDispatcher.class:?]
    • (Mod name is Custom Npcs)
  • Topics

×
×
  • Create New...

Important Information

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