I would like to use Blockbench (a 3d modelling application like blender) to create an entirely new Minecraft weapon.
Then, with java and some API (for example bukkit), I want to have a brand-new weapon.
I do not want to retexture an existing weapon for example the diamond sword.
Would someone kindly give me some pointers? For example, what is not clear for me is how to export it from Blockbench, and how to import it into minecraft.
Is Bukkit the correct API to use? Does know of another API that will better meet my needs. I am not a java beginner.
You can do this absolutely. Since Minecraft version 1.9, Mojang introduced the ability to texture items based on their durability. What is so exciting about this is it allows for virtually infinite custom models that don't replace existing ones! Yes, even if you go in survival and damage it to the exact durability you set the custom model at, it will still be separate. This is because you can set the item so it can't be damaged, but still have a certain durability value. How sneaky! The only problem is if you're developing for 1.8 (usually for a 1.8-latest server) then you can’t use any of this.
How this works is, for example, a diamond hoe has a maximum durability of 1561. This means you can have 1560 custom models using the diamond hoe! It's 1560 and not 1561 because 1561/1561 would be full durability or just a normal diamond hoe.
Also, in 1.14, Mojang introduced the custom_model_data
modifier. It’s another way to create custom models. It allows you to replace the model for any item in the game. You aren’t limited to the maximum durability value either. That means you could put almost infinite values I believe. People have even figured out how to make custom blocks with this! Anyway, I will only show you how to make custom models with the first method because that is all you need right now.
So, I'll start with Blockbench. To export your model, it's File
-> Export
-> Export Block/Item Model
. That will export it as a JSON file. When you export the model don't name the item diamond_hoe
or whatever item you'll be using under model id
. Name it actually what it's going to be called. I'll show you why in this next step. You could even add a whole 'nother namespace if you wanted, but we'll just stick to the Minecraft
namespace. To export the texture, right-click it and press Save As
.
We'll make a basic resource pack. Call the resource pack folder whatever you want. Put the JSON in <your resource pack folder>
-> assets
-> minecraft
-> models
-> item
. Put the texture in <your resource pack folder>
-> assets
-> minecraft
-> textures
-> item
. In the resource pack folder, you must also have a pack.mcmeta file and a pack.png file. You're most likely already familiar with this. Make sure you're using the correct pack format version (e.g. 1.20.4 is on pack format version 23).
After you have made a basic resource pack, it's time to create the model for the diamond hoe, which will point to your model. This is why you named it the actual item in the previous step. The diamond_hoe.json
should look something like this:
{
"parent": "item/handheld",
"textures": {
"layer0": "item/diamond_hoe"
},
"overrides": [
{"predicate": {"damage": 0}, "model": "item/diamond_hoe"},
{"predicate": {"damaged": 0, "damage": 0.000640614990391}, "model": "item/your_custom_item" },
{"predicate": {"damaged": 1}, "model": "item/diamond_hoe"}
]
}
The predicate
modifier is what tells the game when a different model should be shown. This tool can generate the JSON for you. The damage value is whatever damage you want it to use over the total durability (e.g. one durability would be 1/1561 which equals 0.000640614990391).
After that, your layout with just one custom item should look something like this:
.
└── resource pack folder/
├── assets/
│ └── minecraft/
│ ├── models/
│ │ └── item/
│ │ ├── diamond_hoe.json
│ │ └── your_custom_item.json
│ └── textures/
│ └── item/
│ └── your_custom_item.png
├── pack.mcmeta
└── pack.png
Again, there are different ways you could lay it out. You could have your custom stuff in another namespace. This is just how I'm doing it though.
To add multiple items (for example three more items), modify your diamond_hoe.json
to look like this:
{
"parent": "item/handheld",
"textures": {
"layer0": "item/diamond_hoe"
},
"overrides": [
{"predicate": {"damage": 0}, "model": "item/diamond_hoe"},
{"predicate": {"damaged": 0, "damage": 0.000640614990391}, "model": "item/your_custom_item"},
{"predicate": {"damaged": 0, "damage": 0.001281229980782}, "model": "item/your_custom_item2"},
{"predicate": {"damaged": 0, "damage": 0.001921844971172}, "model": "item/your_custom_item3"},
{"predicate": {"damaged": 0, "damage": 0.002562459961563}, "model": "item/your_custom_item4"},
{"predicate": {"damaged": 1}, "model": "item/diamond_hoe"}
]
}
Now, after all that. It's time to use the API. Yes, the Bukkit API is what you need. The Spigot API includes the Bukkit API, so you should be using the Spigot API. If you aren't already using it, change it to that. No one uses the Bukkit server itself anymore. I'm assuming you're running a Spigot/Paper server. I will assume you are using the latest version (1.20.4) also.
You sound like you might be new to Spigot plugins, so we'll make a plugin from scratch. Here is the basic layout of a Spigot plugin. You should already be familiar with the basic layout of a Java project, but here is what this project should end up looking like:
.
├── src
├── pom.xml/build.gradle
└── other_build_junk/
└── main/
├── java/
│ └── your_website_ending/me/
│ └── your_company_or_name/
│ └── yourplugin/
│ ├── commands/
│ │ └── GiveItem.java
│ └── YourPlugin.java <- Main class
└── resources/
└── plugin.yml
Use your favorite Java IDE (it better be IntelliJ, not Eclipse or anything else) to make a Java project, but if you have IntelliJ just install the Minecraft Development
plugin and make a Minecraft project. It creates the plugin.yml
and the build scripts for you. You can use whichever build system you want. I like Gradle, but I'll show you what the dependencies should look like for both.
Gradle (Groovy):
repositories {
mavenCentral()
maven {
name = "spigotmc-repo"
url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/groups/public/"
}
}
dependencies {
compileOnly "org.spigotmc:spigot-api:1.20.4-R0.1-SNAPSHOT"
}
Maven:
<repositories>
<repository>
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
Now, your main class should look like this:
public final class YourPlugin extends JavaPlugin {
@Override
public void onEnable() {
// Register our "giveitem" command
getCommand("giveitem").setExecutor(new GiveItem());
}
@Override
public void onDisable() {
// Plugin shutdown logic
}
}
Notice how it extends JavaPlugin
. That is how it becomes a plugin. The onEnable
and onDisable
methods run every time the server is started or stopped. This line of code in the onEnable
assigns our command Giveitem
, to its executor, the GiveItem
class. It will be the command that gives us our custom item. Create the commands folder if you haven't already. Then, the GiveItem
class. Which will end up looking like this:
public class GiveItem implements CommandExecutor {
@Override
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
if (commandSender instanceof Player player) {
// Create a diamond hoe that will become our item
ItemStack customItem = new ItemStack(Material.DIAMOND_HOE);
// Item meta allows for modifying its data
Damageable itemMeta = (Damageable) customItem.getItemMeta();
// Set damage to 1 or like how we did in the JSON except the actual number
// Why can't they do it this way in the JSON?
itemMeta.setDamage(1);
// Make it always stay the same durability
itemMeta.setUnbreakable(true);
// Use the following line to remove the extra lore we don't need
itemMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE);
// Name it whatever you want
itemMeta.setDisplayName("My Custom Item");
customItem.setItemMeta(itemMeta);
// Add item to player's inventory
player.getInventory().addItem(customItem);
}
return true;
}
}
If you're wondering why we can't just use give
, that would override the game's built-in /give
command and we don't want to do that. Keep in mind you can get your item any way you like whether it's from a command, minigame, or a gui shop. We just want to get your item. That's why we're starting with this basic command. That is what is so cool about the Spigot API though. You can build your Minecraft dreams. Almost anything you can imagine.
Anyways, your plugin.yml should look like this:
name: YourPlugin
version: '${version}' # Should be '${project.version}' for Maven
main: me.myname.yourplugin.YourPlugin
api-version: '1.20'
commands:
giveitem:
description:
Give a custom item
This is what makes your plugin official. It also tells the server any commands that should be created for this plugin.
Finally, build your plugin (should already be ready in IntelliJ). If you're using something else use package
command for Maven and build
command for Gradle. Put the plugin into your server plugin
folder. It should be in the target
folder for Maven and the build/libs
folder for Gradle.
Make sure your resource pack is in the right place. Launch Minecraft and enable your resource pack. Then, start up your server, and once logged in, run the giveitem
command we created with /giveitem
and you should have your custom item!
Remember, you could make virtually infinite custom items without replacing existing items. I could show you how to use custom_model_data
, how to make recipes using the Spigot API, and more, but I suppose that would be out of the scope for your question.
Some of this I originally got from this guide. It's slightly outdated now, but if you know the latest API, it works. Yikes, some of it's incorrect though. Maybe I should fix it...