[JAVA] I made a mod that instantly calls a vehicle with Minecraft

Introduction

Hello. Recently, innokinn is thinking about Minecraft whether he sleeps or wakes up.

Minecraft is fun, isn't it? It's fun to make things in the game, but these days, you can build a server for multiplayer on AWS and operate it while having fun with your relatives, or create your own avatar skin to create a unique character. , Introducing the game extension program (MOD) created by various people, enjoying the chaotic world and enjoying crafting from various directions.

Well, such Minecraft, but you can also keep a pet in this game. You can keep a horse and ride it, but if you leave it at a distance, it will be difficult to find it.

So, I thought, "I wish I could call my beloved horse instantly ...", but when I searched for it, I couldn't find such a mod, so I thought I'd try to make one if it wasn't there, so I made the title mod, so below. The work process so far is summarized in.

MOD requirements

--Add the item "Mount Whistle" that registers the vehicle MOB (hereinafter referred to as "mount") and immediately calls the registered mount when using the item. --I'm sad when my beloved horse dies, so make the registered mount immortal </ b>

What i did

Prepare the MOD development environment

I will omit this because the procedure will come out if you google.

Add an item

Follow the steps below to add a new item.

Write the item registration process in the MOD main program

The actual code is shown below. (Import statement omitted)

MountWhistle.java


@Mod(modid = MountWhistle.MODID, name = MountWhistle.NAME, version = MountWhistle.VERSION)
public class MountWhistle {
    public static final String MODID = "mountwhistle";
    public static final String NAME = "Mount Whistle";
    public static final String VERSION = "1.0.2";
    public static final String PAKETNAME = "MountWhistle";

    public static Item mountWhistle;

    @Mod.EventHandler
    public void construct(FMLConstructionEvent event) {
        MinecraftForge.EVENT_BUS.register(this);
    }

    @SubscribeEvent
    public void registerItems(RegistryEvent.Register<Item> event) {
    	mountWhistle = new Whistle()
    			.setCreativeTab(CreativeTabs.TRANSPORTATION)
    			.setUnlocalizedName("mountwhistle")
    			.setRegistryName("mountwhistle")
    			.setMaxStackSize(1);
        event.getRegistry().register(mountWhistle);
    }

    @SubscribeEvent
    @SideOnly(Side.CLIENT)
    public void registerModels(ModelRegistryEvent event) {
        ModelLoader.setCustomModelResourceLocation(mountWhistle, 0, new ModelResourceLocation(new ResourceLocation("mountwhistle", "mountwhistle"), "inventory"));
    }
}

--In the registerItems (RegistryEvent.Register <Item> event) method, write the item registration process.
Item information is described here. --In the registerModels (ModelRegistryEvent event) method, write the item model registration process. This will reference the json file under src.main.resources.assets.MOD_ID.models.items.

Describe the information about the item texture in the json file

Create a src / main / resources / assets / MOD_ID / models / items package and write a json file under it that specifies the image file with item name.json.

mountwhistle.json


{
	"parent": "item/generated",
	"textures": {
		"layer0": "mountwhistle:items/whistle"
	}
}

Add item texture to project

Create a src / main / resources / assets / MOD_ID / textures / items package and save the image file under it with item name.png.

Implement the behavior when using the item

From here is the production. First, create a class of mount whistle items. Since the base class of Minecraft items is net.minecraft.item.Item, we will implement it by overriding this.

First, the implemented source code is shown below, and then the explanation is started.

Whistle.java source code

Whistle.java


public class Whistle extends Item {

	@Override
	public void setDamage(ItemStack stack, int damage) {
		return;
	}

	@Override
	public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn) {
		Entity mount = playerIn.getRidingEntity();
		ItemStack itemStack = playerIn.getHeldItem(handIn);
		//Are you riding
		if (mount != null) {
			//Register the mount you are currently riding
			NBTTagCompound nbtTag = itemStack.getTagCompound();
			if (nbtTag == null) {
				nbtTag = new NBTTagCompound();
				itemStack.setTagCompound(nbtTag);
			}

			if (nbtTag.hasKey("MountId") &&
					!UUID.fromString(nbtTag.getString("MountId")).equals(mount.getUniqueID())) {
				return new ActionResult<ItemStack>(EnumActionResult.PASS, playerIn.getHeldItem(handIn));
			}

			String name = mount.getName();

			if (worldIn.isRemote) {
				Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString("On the mount whistle" + name + "I registered!"));
			} else {
				nbtTag.setString("MountId", mount.getUniqueID().toString());
				nbtTag.setString("Name", name);
				itemStack.setStackDisplayName(name);

				//Make the mount immortal
				mount.setEntityInvulnerable(true);
			}
		} else {
			NBTTagCompound nbtTag = itemStack.getTagCompound();
			if (nbtTag == null || !nbtTag.hasKey("MountId")) {
				if (worldIn.isRemote) {
					Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString("You can register the mount by using it while riding."));
				}
				return new ActionResult<ItemStack>(EnumActionResult.PASS, playerIn.getHeldItem(handIn));
			}

			UUID mountId = UUID.fromString(nbtTag.getString("MountId"));

			MinecraftServer server =  worldIn.getMinecraftServer();

			if(server == null) {
				Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString("I tried to summon it."));
			} else {
				//Find mounts from all entities
				mount = server.getEntityFromUuid(mountId);
				mount.setLocationAndAngles(playerIn.posX, playerIn.posY, playerIn.posZ, 0.0F, 0.0F);

				if (worldIn.isRemote) {
					if (mount != null) {
						String name = mount.getName();
						Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(name + "Was summoned."));
					}
				}
			}
		}

		return new ActionResult<ItemStack>(EnumActionResult.PASS, playerIn.getHeldItem(handIn));
	}
}

Commentary

Avoid consuming items

Items usually disappear after use, but mount whistle is an item you want to use again and again. The method that handles consumption when used is setDamage (ItemStack stack, int damage), so I override this and immediately return to prevent anything from happening.

Behavior when using items

The method called when using an item by right-clicking is ʻActionResult onItemRightClick (World worldIn, EntityPlayer playerIn, EnumHand handIn) `. By overriding this, you can implement the right-click event.

Here, we first determine if the player is riding on the mount. If you are riding, register the mount with the NBT of the mount whistle and process the mount to be immortal. If you are not riding, summon the mount registered in the mount whistle NBT to the player's coordinates.

What is NBT

When giving information to an item, we use a mechanism called NBT. NBT is an abbreviation of Named Binary Tag, and Minecraft stores various data in the data format called NBT. If the item does not have an NBT tag, create an instance of NBTTagCompound, firstsetTagCompound (nbtTag), and then register the UUID (unique identifier of the entity object) of the mount. Please note that the item will not retain any information unless you do the first setTagCompound (nbtTag). One thing to keep in mind when assigning NBT tags to items is that NBT tags cannot be attached to items, and the actual target to be attached is ʻItemStack`. ItemStack is a bundle of items and refers to "one frame in the inventory".

Things to be aware of when playing multiplayer

The MOD program fires on both the client and the server. However, I would like this process to work only on the client, or vice versa. As a handling at that time, you can branch by looking at the value of ʻisRemote of the Worldobject. True on the client side and false` on the server side. Here, the chat message is displayed only when the client side is executed, and the mount coordinates are changed only when the server side is executed. If you do not handle the server and client, the mount will move to you for a moment, and then the mount will start walking from the coordinates on the server side, so it will return to its original position instantly.

What was made

I uploaded it on GitHub. https://github.com/inokinn/MountWhistle

I will actually move it

First, get the mount whistle. By default, you can craft with 9 items "Gisar's Vegetables" added by the mod Chococraft . I will. By using the mount whistle when riding the mount, registration is successful if the item name becomes the name of the mount. After that, it is OK if you use the mount whistle when not riding and the mount comes to the player.

  • Due to the specifications of Minecraft that can only refer to on-memory entities, it is not possible to call a mount that is too far away.

in conclusion

Minecraft MOD development related, there are few information, it takes time to build and check the operation, the behavior is different between single play and multiplayer, etc. As a result of repeating trial and error, from the start of development to the completion 2 It took about a day. In particular, the Japanese documentation was old and rare, so I felt like I had to read the actual source code. I hope Minecraft MOD development will be more exciting in Japan as well.

Recommended Posts

I made a mod that instantly calls a vehicle with Minecraft
I made a Wrapper that calls KNP from Java
I made a GUI with Swing
I made a risky die with Ruby
I made a rock-paper-scissors app with kotlin
I made a rock-paper-scissors app with android
I made a class that automatically generates Json that specifies Minecraft texture etc. [1.12.2]
I made a site that summarizes information on carbohydrate restriction with Vue.js
04. I made a front end with SpringBoot + Thymeleaf
I made a mosaic art with Pokemon images
I made a gender selection column with enum
I made a viewer app that displays a PDF
I made a LINE bot with Rails + heroku
I made a portfolio with Ruby On Rails
[Ruby] I made a crawler with anemone and nokogiri.
I made a library that works like a Safari tab !!
I made an Android application that GETs with HTTP
I made a development environment with rails6 + docker + postgreSQL + Materialize.
I made a plugin to execute jextract with Gradle task
I made a chat app.
I made a program in Java that solves the traveling salesman problem with a genetic algorithm
I made a command line interface with WinMerge Plugin using JD-Core
A story that I struggled to challenge a competition professional with Java
[Rails] I made a simple calendar mini app with customized specifications.
I made a simple search form with Spring Boot + GitHub Search API.
I made a source that automatically generates JPA Entity class files
I made a question that can be used for a technical interview
I made a shopify app @java
How to sign a Minecraft MOD
I made a simple recommendation function.
I made a matching app (Android app)
I made a package.xml generation tool.
[Android] I made a pedometer app.
I tried learning Java with a series that beginners can understand clearly
I tried to make a Web API that connects to DB with Quarkus
I made a class that can use JUMAN and KNP from Java
[LINE BOT] I made a ramen BOT with Java (Maven) + Heroku + Spring Boot (1)
[Ruby] I made a simple Ping client
I made an eco server with scala
I tried playing with BottomNavigationView a little ①
I made a plugin for IntelliJ IDEA
I made a calculator app on Android
I made a new Java deployment tool
I made a bulletin board using Docker 1
Learn Java with Progate → I will explain because I made a basic game myself
A story that I was really into when I did triple DES with ruby