Jump to content

How to make a block that mobs of a certain type can't walk over?


AskHow1248

Recommended Posts

I'm been trying to make a block that mobs of a certain type can't walk over, and I've tried using addCollisionBoxesToList() to add the collision box if the entity parameter should be blocked, but then, no matter what my bounds are, the wall only extends 2 blocks high.  I also tried setBlockBoundsBasedOnState(), but then it blocks everything.

Link to comment
Share on other sites

This is going to be very challenging to accomplish. 

 

I haven't done this myself so I'm only guessing.  What you are doing is changing how the mob's path.

 

I think you are either going to need to modify that code universally, modify it in the entities of interest (perhaps my replacing their pathfinding task with a custom one), or do something cheesy.

 

By cheesy I have a few untested ideas:

You could make the material type of your block lava, but then you would have to do some other things inside the block to counter that.

You could also place blocks above it that have no collision but are listed as a solid material.  This would get challenging to maintain though.

 

Long time Bukkit & Forge Programmer

Happy to try and help

Link to comment
Share on other sites

ive seen a tutorial i could maybe link you to if i can find it that can make it so that if a mod steps on said block that a potion effect can be added, maybe you could make it so that rather it being a potion effect the mob experiences knock back or something or maybe you could edit it to allow for bound box changing idk worth a shot maybe?

Link to comment
Share on other sites

  • 1 month later...

There is the issue.  I don't think you will be able to set a custom bounding box based upon entity.

 

You might with tile entities be able to search for entities in the area and change bounding box behavior (but that would effect all mobs) or give certain mobs knockback if they approach the block. 

 

The second idea is probably the one you can acheive.  It would be a pulsar of sorts.

 

Any of those ways is going to screw with the mob pathing.  It will keep trying to path through the block instead of going around.  That might be ok for you.  If its not, then you will have to change the pathing for all the mobs.

 

Long time Bukkit & Forge Programmer

Happy to try and help

Link to comment
Share on other sites

The bounding box would also properly affect the mob's path, but unfortunately it would also affect every other mob and the player -- you player couldn't cross it either.

 

Like Delpi says, it really depends on how you want the mob to behave when blocked with this block. 

 

To really do it "properly" you'd want the mob to be able to figure out a way around it if the path exists, so in that case you would just create your own AI tasks (could copy the vanilla ones) that call custom path finding (you'd copy the vanilla path finding but treat your blocks like having lava or water in the way).  Then to block the mob you'd have to place enough of your blocks to truly block their path.

 

Alternatively, if you don't mind the mob sort of getting "stuck" (i.e. they'll keep trying to cross but get knocked back) when it  tries to cross your block then there are several ways to do it.  One simple way is you can check if the mob is over top of your block and then simply set the position of the mob to its previous position (entities have previous X, Y, Z coordinates stored in fields).

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

Link to comment
Share on other sites

  • 2 weeks later...

If you want all the mobs to path around it, you will have to create your own pathfinding AI first.  Then go into each mob class and delete the normal pathfinding ai task and input yours in its place.  There is a method for that under AITASK or something like that. 

 

It will be failrly involved.

 

One last thing is you might look at the way pathfinding considers blocks that are valid paths.  You 'might' (let me stress might) be able to find something to overwrite with reflection that would do the trick.  If that works, this could be easy.

Long time Bukkit & Forge Programmer

Happy to try and help

Link to comment
Share on other sites

As I think about my proposed suggestion, it might not work on reflection very well.

 

I'm afraid you might have to still set it on every entity.  Each entity creates its own instance of the pathfinder.

 

 

Long time Bukkit & Forge Programmer

Happy to try and help

Link to comment
Share on other sites

i don't make mods for a while, so i don´t know if you can do that, but doesn't he can make the block spawn an entity(no render or something like that), or use a tileentity, to keep searching for entities near the block, then its way?

 

The problem is pathfinding.  Yes you can do things like you suggest which will block the entity by pushing them away, but the entity will not seem smart -- it won't be able to find its way around the block if there is a way.  You need the pathfinding algorithm to know that that block isn't passable.

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

Link to comment
Share on other sites

How can I do that?

 

It will take some coding, but I believe you would have make your own copy of the pathfinding related classes and modify such that the blocks you don't want to walk over are considered similar to lava.  Then you will have to override the methods and/or events your entity uses to process pathfinding.

 

Looking at it quickly, I think EntityLiving has a method called getNavigator() which returns an instance of PathNavigate class.  So assuming that your custom entity extends EntityLiving (or some subclass of EntityLiving) I think if you copied or extended PathNavigate, created an instance of it in your entity, and override the getNavigator() method to point to your instance then you could do it.

 

In your custom PathNavigate class, it calls a getPathToXYZ() which calls worldObj.getEntityPathToXYX() method which in turn creates a PathEntity by calling a PathFinder.creatEntityPathTo() method which calls an addToPath() method.

 

The addToPath() is where I believe you would have to figure out how to avoid your block, although I looked at it quickly.

 

Alternative:

 

There is possibly one other "brute force" method that you might be able to try.  You could try temporarily changing the bounding box of your blocks before calling the getPathToXYX() and then restore the bounding boxes.  This seems like it might work and wouldn't take too much coding.

 

Anyway, hopefully I gave you some ideas on where you might look.

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

Link to comment
Share on other sites

If you are going to do this with base entities, that is going to be much harder.

 

If you are serious about this, I would do the following.

  • Create your own pathing method in a custom entity
  • extend each of the minecraft entities who's pathing you want to modify and replace in their code the pathing with your own
  • Using events, replace the spawn of any base entity with your custom entity extending the base entity.

 

That should work.

Long time Bukkit & Forge Programmer

Happy to try and help

Link to comment
Share on other sites

If you are going to do this with base entities, that is going to be much harder.

 

If you are serious about this, I would do the following.

  • Create your own pathing method in a custom entity
  • extend each of the minecraft entities who's pathing you want to modify and replace in their code the pathing with your own
  • Using events, replace the spawn of any base entity with your custom entity extending the base entity.

 

That should work.

 

Like I said, I only need my entity to path around the block since only my entity will be impeded.

 

Thanks jabelar, I will look into that.  Does anyone know of a tutorial about how the pathing code works, or will I have to figure it out for myself?

Link to comment
Share on other sites

As suggested many times, go look at the pathing code and change it.

 

Look up PathFinder.  Study it.

 

Figure out you need to modify func_82565_a.

 

insert in the the following:

 

 

 

if (block == Blocks.trapdoor)

{

flag3 = true;

}

else if

 

[\spoiler]

 

something like this:

 

 

 

if (block == Blocks.trapdoor)

{

flag3 = true;

}

else if (block == "Your wonder Block" && "Your Wonder Block state says STOP")

{

return 0;

}

else if

 

[\spoiler]

 

You will have to figure out what to override and where to make this work.  Probably multiple classes, but I didn't look that hard.

 

Probably should start in EntityCreature with the following and see where it leads you.

 

this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, f4, true, false, false, true);

Long time Bukkit & Forge Programmer

Happy to try and help

Link to comment
Share on other sites

  • 2 weeks later...

I think this will work, will you check it?

 

 

 

public class DemonPathFinder extends PathFinder {

public DemonPathFinder(IBlockAccess par1iBlockAccess, boolean par2,
		boolean par3, boolean par4, boolean par5) {
	super(par1iBlockAccess, par2, par3, par4, par5);

}

public int getVerticalOffset(Entity par0Entity, int par2, int par3, int par4, PathPoint par5PathPoint)
{

	if(isBlockedByRune(par0Entity, par2, par3, par4, par5PathPoint))
		return 0;
	else
		return super.getVerticalOffset(par0Entity, par2, par3, par4, par5PathPoint);

    }

public static boolean isBlockedByRune(Entity par0Entity, int par1, int par2, int par3, PathPoint par4PathPoint)
    {
        boolean flag3 = false;

        for (int l = par1; l < par1 + par4PathPoint.xCoord; ++l)
        {
            for (int i1 = par2; i1 < par2 + par4PathPoint.yCoord; ++i1)
            {
                for (int j1 = par3; j1 < par3 + par4PathPoint.zCoord; ++j1)
                {
                    if(isOverRune(par0Entity, l, i1, j1))
                    	return true;

                }
            }
        }
        return false;
    }

private static boolean isOverRune(Entity e, int x, int y, int z) {

	for( ; y < 256 ; y++){

		if(e.worldObj.getBlockId(x, y, z) == TMBlocks.magicRune.blockID)
			return true;

	}

	return false;

}

}

 

 

Link to comment
Share on other sites

Think this will work:

 

 

 


public class DemonPathFinder extends PathFinder {

public DemonPathFinder(IBlockAccess par1iBlockAccess, boolean par2,
		boolean par3, boolean par4, boolean par5) {
	super(par1iBlockAccess, par2, par3, par4, par5);

}

public int getVerticalOffset(Entity par0Entity, int par2, int par3, int par4, PathPoint par5PathPoint)
{

	if(isBlockedByRune(par0Entity, par2, par3, par4, par5PathPoint))
		return 0;
	else
		return super.getVerticalOffset(par0Entity, par2, par3, par4, par5PathPoint);

    }

public static boolean isBlockedByRune(Entity par0Entity, int par1, int par2, int par3, PathPoint par4PathPoint)
    {
        boolean flag3 = false;

        for (int l = par1; l < par1 + par4PathPoint.xCoord; ++l)
        {
            for (int i1 = par2; i1 < par2 + par4PathPoint.yCoord; ++i1)
            {
                for (int j1 = par3; j1 < par3 + par4PathPoint.zCoord; ++j1)
                {
                    if(isOverRune(par0Entity, l, i1, j1))
                    	return true;

                }
            }
        }
        return false;
    }

private static boolean isOverRune(Entity e, int x, int y, int z) {

	for( ; y < 256 ; y++){

		if(e.worldObj.getBlockId(x, y, z) == TMBlocks.magicRune.blockID)
			return true;

	}

	return false;

}

}

 

 

Link to comment
Share on other sites

I think you may be making this harder on yourself. All you need is an invisible block to occupy the block position above the block. You would only need something like this in your actual block code:

public void onBlockAdded(World par1World, int par2, int par3, int par4) {
    super.onBlockAdded(par1World, par2, par3, par4);
    if(par1World.isAirBlock(par2, par3 + 1, par4)){
        par1World.setBlock(par2, par3 + 1, par4, MyBlocks.pathBlockingBlock);
    }
    if(par1World.isAirBlock(par2, par3 + 2, par4)){
        par1World.setBlock(par2, par3 + 2, par4, MyBlocks.pathBlockingBlock);
    }
}
public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
{
    if(par1World.isAirBlock(par2, par3 + 1, par4)){
        par1World.setBlock(par2, par3 + 1, par4, MyBlocks.pathBlockingBlock);
    }
    if(par1World.isAirBlock(par2, par3 + 2, par4)){
        par1World.setBlock(par2, par3 + 2, par4, MyBlocks.pathBlockingBlock);
    }
}

Then for your invisibly rendered path blocking block:

//This is not a normal block.
public boolean renderAsNormalBlock()
{
    return false;
}
//Let all light pass through
public int getLightOpacity(World world, int x, int y, int z) {
    return 0;
}
//Set block as replaceable.
public boolean isBlockReplaceable(World world, int x, int y, int z) {
    return true;
}
//0 width length and height box so no wireframe rendered.
public AxisAlignedBB getSelectedBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
    return AxisAlignedBB.getAABBPool().getAABB((double)par2, (double)par3, (double)par4, (double)par2, (double)par3, (double)par4);
}
//Check if the invisible block needs to cleanup
public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
{
   if(par1World.getBlock(par2, par3 - 1, par4) != myBlock && par1World.getBlock(par2, par3 - 2, par4) != myBlock){
      par1World.setBlockToAir(par2, par3, par4);
   }
}
//Only block specific mobs
public void addCollisionBoxesToList(World par1World, int par2, int par3, int par4, AxisAlignedBB par5AxisAlignedBB, List par6List, Entity par7Entity) {
   if(par7Entity instanceof EntityMob){//Or whichever mob you want to block
      super.addCollisionBoxesToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity);
   }
}
//So Raytracing passes through.
public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3) {
   return null;
}
//Nothing needs to be done here like there is no block here.
public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer) {}

I wrote this off the top of my head so you may have to fill in the blanks, but that should make the vanilla path finding work.

Link to comment
Share on other sites

Gotta admit I missed 'addCollisionBoxesToList'.  That is interesting.

 

I just took a quick look, but I think you are changing the wrong thing in pathfinding.

 

You need to modify the method 'getSafePoint'.  It is a private method so you will just have to ovewrite it rather than extend it.  But early in the moethod, you just need to check for your block and return null.

 

Under EntityCreature, you will find the method 'updateEntityActionState()'.  Several places in it, it calls for 'this.worldObj.getPathEntityToEntity'.  This looks at 'getPathEntityToEntity' in the class 'world'.

 

Anyhow, after the brief look, the easiest way to adjust the pathfinding is something they used to call 'coremod', but it isn't something I've played around with.  Someone might be able to help you.  In the case, you would just insert the line we talked about above in there and it would now work for all entities that use pathfinding.

 

 

But, since rich was able to introduce us to something simpler, I'd go for that.

Long time Bukkit & Forge Programmer

Happy to try and help

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

    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
    • It is an issue with quark - update it to this build: https://www.curseforge.com/minecraft/mc-mods/quark/files/3642325
    • Remove Instant Massive Structures Mod from your server     Add new crash-reports with sites like https://paste.ee/  
  • Topics

×
×
  • Create New...

Important Information

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