Jump to content

custom block that prevents spawning of mobs in a certain perimeter


Thaliviel

Recommended Posts

Hey there, I haven't done modding in a while, so I'm a bit out of shape, but I know the basics.

 

Is it possible to create a custom block, which prevents the spawning of monsters in a certain radius around it?

 

If someone with great knowledge of modding could help me as a beginner, I'd really appreciate it! :)

Link to comment
Share on other sites

  • Replies 61
  • Created
  • Last Reply

Top Posters In This Topic

You can subscribe to

LivingSpawnEvent.CheckSpawn

and set the result to

DENY

to prevent a passive mob spawn. This isn't fired for mobs spawned from a mob spawner.

 

You'll probably want to maintain a list of locations that have this block using World Saved Data and iterate through them to check whether any are in range to prevent the spawn in your event handler.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Okay, so I created my custom block with a texture and a recipe.

 

Now I'm having problems creating the list of locations. I know that I can use writeToNBT and readFromNBT in order to save additional data, like an array that contains the list of my blocks and their location. But I'm not really sure how and when to use these. I guess I can use BreakEvent when I want to delete blocks from my list.

 

Could you give me some advice how to maintain a list of locations that have this block?

Link to comment
Share on other sites

I would use WorldSavedData for that.

Everytime one of ur blocks get added safe the position in that class.

Everytime one of ur blocks get removed remove it from the class.

Everytime a mod gets spawned access ur WorldSavedData, iterate over all blocks and check if they are in range to prevent spawning.

If there is one block to prevent the spawn, deny the spawning and break the loop

Link to comment
Share on other sites

welcome to pseudo code island, I will beyour guide

 



public void blockAdded(Event event) {

if(event.state.getBlock()==myBlock) {
	CustomWorldData data = CustomWorldData.get(event.world);
	data.addBlock(event.pos);
}
}

public void blockRemoved(Event event) {
if(event.state.getBlock()==myBlock) {
	CustomWorldData data = CustomWorldData.get(event.world);
	data.removeBlock(event.pos);
}

}

Link to comment
Share on other sites

I suggest you override

Block#onBlockAdded

(called after a block is added to the world) and

Block#breakBlock

(called when a block is removed from the world, make sure you call the super method so the

TileEntity

[if any] is removed). Use these to add and remove the block's position to your

WorldSavedData

.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Okay, one question: If I use onBlockAdded() in my custom block's class, will it only be called when I add my custom block, or will it be called everytime I add any block?

Edit: I checked it with system message - it only activates when I add the custom block. Problem solved :)

 

This is my code for the custom block so far:

package com.monsterBlocker;

import java.util.ArrayList;
import java.util.List;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.world.World;

public class MBBlock extends Block
{
// A list of all MBBlocks and their location
public List mbBlockList = new ArrayList();

        public MBBlock (int id)
        {
                super(id, Material.iron);
                this.setUnlocalizedName(MonsterBlocker.mbBlock_unlocalizedName);
                this.setCreativeTab(CreativeTabs.tabBlock);
                
                this.setHardness(5F);
                this.setResistance(15F);
                this.setStepSound(Block.soundMetalFootstep);
                this.setLightValue(2F);
        }
        
        @Override
        @SideOnly(Side.CLIENT)
        public void registerIcons(IconRegister icon) {
        blockIcon = icon.registerIcon(MonsterBlocker.AID + ":" + "monsterBlocker");
        }

        @Override
        public void onBlockAdded(World world, int x, int y, int z)
        {
        	//CustomWorldData data = CustomWorldData.get(world);
    		//data.addBlock(x, y, z);
        	
        	Position pos = new Position(x, y, z);
        	mbBlockList.add(pos);
        }
}

Link to comment
Share on other sites

In general, instance methods will only be called if the instance was actually involved in whatever happened.

 

This means that

Block#onBlockAdded

will only be called on the

Block

that was actually added to the world.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

You must create a class that extends

WorldSavedData

and store the data in each instance of that, yes. The page I linked in my first post explains this in more detail.

 

You can't store the list in your

Block

class directly, since you don't have any way to load/save the data and can't easily separate each dimension's list.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Fair warning:

You're going to need to learn about concurrency.

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

Okay, I think I begin to understand what I have to do in order to maintain the list:

 

I can only save IntArrays in the NBT, no ArrayLists containing objects. When a player spawns inside a dimension, the NBT will be read (x,y,z) and the ArrayList will be created. When a player adds or removes a MBBlock, the ArrayList is updated and saved to the NBT as 3 IntArrays (containing x,y,z).

 

Am I right so far or did I miss something important?

Link to comment
Share on other sites

Okay, I think I begin to understand what I have to do in order to maintain the list:

 

I can only save IntArrays in the NBT, no ArrayLists containing objects. When a player spawns inside a dimension, the NBT will be read (x,y,z) and the ArrayList will be created. When a player adds or removes a MBBlock, the ArrayList is updated and saved to the NBT as 3 IntArrays (containing x,y,z).

 

Am I right so far or did I miss something important?

 

You can either save each position as an int array or a compound tag.

 

You don't write to NBT every time a block is added/removed, Minecraft will call

readFromNBT

and

writeToNBT

for you.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Fair warning:

You're going to need to learn about concurrency.

 

If the list is only maintained and checked on the server, won't it all be running in a single thread?

 

Even if you needed to maintain the list on both sides, wouldn't each side have its own

WorldSavedData

instance(s) each only being accessed from a single thread?

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

If the list is only maintained and checked on the server, won't it all be running in a single thread?

 

That entirely depends on how the data is being saved to disk.  HOO BOY.

 

FileIO runs on a separate thread.

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

Okay, I think it is easier to store the data as a NBTTagList of NBTTagcompounds.

 

So I have this class "Position"

public class Position {

public int x;
public int y;
public int z;

public Position(int posx, int posy, int posz){
       	x = posx;
       	y = posy;
       	z = posz;
}
}

 

And I use an ArrayList in order to store the list of blocks while playing

public void onBlockAdded(World world, int x, int y, int z)
{
    Position pos = new Position(x, y, z);
    mbBlockList.add(pos);
}

 

So when I want to save the data to the NBT, I think this should work, right?

    @Override
    public void writeToNBT(NBTTagCompound nbt) {
    	
    	NBTTagList nbttaglist = new NBTTagList();
    	for(int i = 0; i < mbBlockList.size(); i++) {
            NBTTagCompound compound = new NBTTagCompound();
    	    Position pos = (Position) mbBlockList.get(i);
       	    compound.setInteger("x", pos.x);
       	    compound.setInteger("y", pos.y);
       	    compound.setInteger("z", pos.z);
       	    nbttaglist.appendTag(compound);
    	}    	 
    }

 

Now I have a question about the NBTTagList: how do I set the key?

Because when loading I obviously need to tell the program which NBTTagList I want to load...

    @Override
    public void readFromNBT(NBTTagCompound nbt) {
    	NBTTagList mbBlockList = nbt.getTagList("mbBlockList");

Link to comment
Share on other sites

You need to save the NBT list tag inside the provided NBT compound tag using

NBTTagCompound#setTag

in

writeToNBT

.

 

If you're using generics properly, you shouldn't need to cast objects from your list to

Position

.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

You need to save the NBT list tag inside the provided NBT compound tag using

NBTTagCompound#setTag

in

writeToNBT

.

 

Great! So this is...

    @Override
    public void writeToNBT(NBTTagCompound nbt) {
    	
    	NBTTagList nbttaglist = new NBTTagList();
    	nbt.setTag("mbBlockList", nbttaglist);

 

If you're using generics properly, you shouldn't need to cast objects from your list to

Position

.

 

When I don't cast it to Position, Eclipse displays an error:

"Type mismatch: cannot convert from Object to Position"

Did I do something wrong?

Link to comment
Share on other sites

Great! So this is...

Yes, that looks correct.

 

When I don't cast it to Position, Eclipse displays an error:

"Type mismatch: cannot convert from Object to Position"

Did I do something wrong?

Is your field a

List

or a

List<Position>

? Always use generic types when they're available.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Okay, the saving/loading starts looking good. The only thing missing is the initialization when a player spawns in a dimension.

I try to call onMBInit() and return the ArrayList containing the loaded BlockList, but I'm not sure how to do that.

 

Here is the full code:

package com.monsterBlocker;

import java.util.ArrayList;
import java.util.List;

import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.WorldSavedData;

public class MBBlockList extends WorldSavedData {

private static final String DATA_NAME = MonsterBlocker.MODID + "_BlockList";
public List<Position> mbBlockList = new ArrayList();

public MBBlockList() {
    super(DATA_NAME);
}

public MBBlockList(String s) {
	super(s);
}
    
    public List<Position> onMBInit() {
    	readFromNBT(nbt);
    	return mbBlockList;
    }
    
    public void onMBBlockChange(List<Position> newMBBlockList) {
    	mbBlockList = newMBBlockList;
    	markDirty();
    }

    @Override
    public void readFromNBT(NBTTagCompound nbt) {
    	mbBlockList.clear();
    	
    	NBTTagList nbttaglist = nbt.getTagList("mbBlockList");
    	for (int i = 0; i < nbttaglist.tagCount(); ++i) {
    		NBTTagCompound posCompound = (NBTTagCompound) nbttaglist.tagAt(i);
    		Position pos = new Position(posCompound.getInteger("x"), posCompound.getInteger("y"), posCompound.getInteger("z"));
    		mbBlockList.add(pos);
    	}
    }

    @Override
    public void writeToNBT(NBTTagCompound nbt) {
    	
    	NBTTagList nbttaglist = new NBTTagList();
    	nbt.setTag("mbBlockList", nbttaglist);
    	for(int i = 0; i < mbBlockList.size(); i++) {
    		NBTTagCompound compound = new NBTTagCompound();
    		Position pos = mbBlockList.get(i);
       	    compound.setInteger("x", pos.x);
       	    compound.setInteger("y", pos.y);
       	    compound.setInteger("z", pos.z);
       	    nbttaglist.appendTag(compound);
    	}    	 
    }
}

 

Soo, first question:

Do I call onMBInit() in preInit(FMLPreInitializationEvent event)?

 

Second question:

What do I write in onMBInit(), so that the BlockList is loaded, so that I can return it?

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




×
×
  • Create New...

Important Information

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