Skip to content

Minecraft modding and plug ins

Created: 2020-02-26 09:00:28 -0800 Modified: 2020-03-07 09:40:40 -0800

  • Plug-ins vs. mods: the way the community seems to differentiate is that plug-ins are only for the server and would allow you to play with the vanilla client. Mods can be for the client or for both, but not only for the server.
    • Data packs and resource packs are officially supported ways of adding custom content to the server and/or the client without needing any third-party software.
      • Data packs are simple overrides for any assets in the game, e.g. functions, achievements, values, etc. You can also add your own, new functions, which would be accessible via old functions or command blocks. However, the big difference between mods and datapacks is that datapacks can only access commands that you can already do through the game itself, e.g. “/teleport”, “/say”, etc. This means they can grant you items, move around in the world, and kill entities.
      • You can see some examples of these packs here. They can do things like add a money system or hookshot to the game.
      • Resource packs are only textures, music, and sounds.
  • Minecraft “PE” stands for “Pocket Edition”. The Windows 10 edition is the pocket edition as well, meaning you can play with mobile/console players.
  • If you want to test multiple players on your own local server, there’s an option to disable auth in called “online-mode” (reference). If you try logging in as the same player twice, then the second session will boot the first one regardless of what “online-mode” is set to, so you need to modify the account name of the second instance (reference).
  • Scrolling up in Spectator Mode makes you fly faster.
  • To launch a Minecraft server with no GUI (to save resources), just put “nogui” at the end of the “java” command (reference).
  • There are two versions of Minecraft: the Java version and the Bedrock version. Some basic differences from what I’ve seen:
    • The Java version is more popular
    • The Java version only runs on desktop operating systems, not mobile or consoles
    • The current Java version is 1.15.2, but most mods work on 1.12.2.
    • Bedrock has an officially supported JavaScript modding API (it was only in public beta as of December, 2018). Despite being officially supported, it’s only documented by the community here on the Minecraft Wiki.
      • There are somewhere between 2K-3K mods for the Bedrock version on mcpedl.
    • Bedrock monetizes skins
  • Most players go to Curse Forge to download Minecraft mods
  • The single-player version of Minecraft still hosts a server so that you can play on LAN with people. There’s much more information here.
  • Java has many modding APIs since none are officially supported
    • Fabric API - they have a getting-started guide for developers here. It sounds like this is for client and server mods.
    • Forge - this is for both mods and plug-ins (docs here).
    • Bukkit - this is only for plug-ins (API docs here). This is seemingly dead and Spigot is its successor. Bukkit was the API name and CraftBukkit was the name of the Minecraft + Bukkit pack that basically gave you the whole modded server in one download.
      • Spigot - a spin-off of Bukkit, meaning it’s only for plug-ins
        • BungeeCord - this is technology to handle linking multiple servers, e.g. walking through a portal on Server A and being handed off to Server B
        • PaperSpigot - seems to mainly add patches and fixes to Spigot (it’s a fork of Spigot). I think it may also focus on performance.
    • Sponge (docs here) - for plug-ins
    • Liteloader - this seems like a mod loader moreso than an API itself.
    • Comparisons
      • Apparently Forge is the most popular for the client-side and Spigot is the most popular for server-side. Because of that, it sounds like PaperSpigot may be a good option if I want to go the Java route.
  • Chat colors:
      • The garbled characters are “magic”
  • Open the debug menu: hold F3 and press Q
  • Summon an entity: /summon cow
  • Middle-click a block to select it from your inventory
  • Here’s the guide on the wiki for how to make these
  • Here are some datapacks that already exist
  • Datapacks seem to have been added in 1.13, meaning they’ve been around since July 18th, 2018.
  • On Windows, %appdata%\minecraft has the files for vanilla.
    • You need a world before you can add any datapacks. If you don’t have one, just launch whatever version you’re making a datapack for, create a world, then save and exit.
    • My final path for testing this out was here: %appdata%\minecraftsaves1_15_2_datapacksdatapacks
  • In order to see the datapack, go into your world and do “/datapack list”. You can hover over the datapack to see the description that you wrote.
  • It seems like namespaces can’t be uppercase, so prefer “adam” over “Adam”.
  • If you want to make changes on the fly, do “/reload” in the game.
  • Command blocks can call functions. To set this up:
    • /give @s command_block
    • Place it in the world by right-clicking
    • Right-click the placed command block to modify its function
      • I typed “function adam:teleport ” in it
    • Activate it via a button or pressure plate
      • /give @s stone_button
      • Shift-right-click a side of the block to place the button on it
      • Right-click the button to activate the command block
    • Note that by doing this through a command block, the function should modify nearby players, e.g. @a[radius=2].
  • Logs can be found in .minecraft/logs/latest.log
    • If “/reload” causes an error, you’ll only see it in the log, not as the result of “/reload” itself.
  • Scoreboards are overlays that can track information. Here’s a simple death scoreboard

/scoreboard objectives add deaths deathCount {“text”:“Player Deaths”,“color”:“red”}

/scoreboard objectives setdisplay sidebar deaths

You can filter based on scores when you’re using tags and arguments, e.g.


  • Scoreboards have a “slot” that they go into, e.g. the “sidebar” or the tab screen, AKA “list” (reference). You can only have one scoreboard per slot. There’s a “below name” scoreboard that you could use to display a player’s level or experience.

  • Frequently, scoreboards are just used for variables since not everything is an entity. For example, the ClawShot datapack uses it to track each claw that a player might use, how far it’s traveled, etc.

  • You can make a function to run whenever your datapack is reloaded or every tick (roughly 1/20th of a second):

    • Create AdamLearnsDatapackdataminecrafttagsfunctionsload.json
    • Make the contents look something like this
"values": [
  • From what I understand, this has to be an existing function and not a slash command like “/teleport”.
  • It seems like it’s common to make your own functions named after these, e.g.
"values": [
"values": [
  • My first datapack was to make a cow drop diamonds. I did this by creating .minecraftsaves1_15_2_datapacksdatapacksAdamLearnsDatapackdataminecraftloot_tablesentitiescow.json with the following JSON:
"pools": [
"rolls": 5,
"entries": [
"type": "item",
"name": "minecraft:diamond",
"weight": 1,
"functions": [
"function": "set_count",
"count": {
"min": 5,
"max": 10
  • All command names
  • Loot table names
  • There’s shorthand for many different types or groups of things. These are called target selectors. To test any of these in the game directly, do something like “/say @s”.
    • @s - self
    • @a - all players
    • @e - all entities, including players
    • @p - nearest person
    • @r - random
    • You can scope these down with arguments inside square brackets, e.g. @e[distance=FORMULA]
      • FORMULA examples
        • 5 - exactly a distance of 5 (you almost never want this since it’s the exact distance)
        • ..5 - anything up to a distance of 5
        • 5.. - anything greater than a distance of 5
        • 5..10 - anything between a distance of 5-10
        • E.g. @a[distance=..5] would basically be all nearby players
    • With those arguments, you can sort, filter, limit, etc. You can also get a lot of “nbt data” (“named binary tag data”) about a player, which includes their inventory, selected hotbar, position, etc.
      • An example of getting this for a “simple” entity like a pig:
        • /summon pig
        • /data get entity @e[distance=5..,limit=1]
  • Coordinates can be offsets if you use a tilde, e.g. /teleport ~-5 ~-5 ~-5
    • If you want the current coordinates, you can specify an offset of nothing with 0 or just a tilde ("").
  • Mod listings for players - Spigot mods should work for PaperSpigot
  • The PaperSpigot source code is on GitHub
  • The getting-started guide is here: . This guide is great! It does a good job at leading you through the setup and then guiding you through the initial parts of the API (e.g. commands and events).
  • API docs are here
  • Installation is pretty much just downloading the JAR, running it, and agreeing to the EULA. Don’t forget to do “op <your name>” in the server UI that pops up so that you have access to all commands.
  • To log something in the game, you can do “player.sendMessage(“hello”)“
  • There’s a quick guide for getting started with Visual Studio Code here. I did not get this completely working, so I ran into ease-of-use issues where it wasn’t autocompleting code or imports.
    • I needed to install Open JDK. I set a Windows-level environment variable for JDK_HOME and pointed it to that folder (NOT the “bin” folder)
    • I installed Maven. I added its bin folder to my PATH environment variable.
    • I made a workspace and saved it somewhere. Then I modified it to contain this:
"folders": [
"path": "."
"settings": {
"files.autoGuessEncoding": true,
"files.encoding": "utf8",
"java.home": "C:\openjdk-1.8.0",
"": "-Dfile.encoding=UTF-8",
"javac-linter.javac": "javac -Dfile.encoding=UTF-8"
  • Ctrl+shift+P → Create Maven Project → quickstart → pick latest version → pick current folder
    • This will download a bunch of stuff into ~/.m2
    • You’ll be prompted to type the following:
      • groupId: Has to be in the format of Java packages, like “”. Don’t try typing spaces or hyphens since this will turn into Java code.
      • artifactId: firstplugin
      • Together, the above two will form a package name of groupId.artifactId.
      • Version number: just press enter to get “1.0-SNAPSHOT”
      • Package: just press enter to get the default setting of the group ID
    • Make a plugin.yml file in src/main/resources (that way Maven will automatically put it into the Jar)
  • Modify pom.xml to include the PaperSpigot repo and dependency as listed here
    • Also include the <build> directives as shown below:
  • To install the plug-in, you have to do ctrl+shift+P → Maven: Execute commands → choose your plug-in → install

  • After you’ve installed, you need to copy the plug-in’s JAR file from the “target” directory to the PaperSpigot/plugins directory and then restart the server. Alternatively, you can “reload confirm” the server through its GUI, but that’s apparently susceptible to bugs.

  • Instructions for setting up a new plug-in for IntelliJ

    • Note that it’s much easier if you just install the Minecraft plug-in. With that, all you have to do is make a new project from the Minecraft template, and you’re basically done.
  • Commands can be sent by one of three things:

    • The player, which is when the player types into chat
    • The console, which is when the administrator types into the server
    • A command block, which is when a block performs the function
  • The server itself has some configuration properties

    • Paper.yml (autogenerated at launch time): this has the properties listed here
    • this has the properties listed here. This is for any Minecraft server.
  • Your plug-in essentially has its own local storage via configuration files (reference)

  • You can debug plug-ins with IntelliJ (reference) or Eclipse (reference)

    • After setting this up, here’s what I ended up doing
      • mvn install
      • Copy the JAR to the right location
      • From the terminal, run PaperSpigot with debugging: java -Xms1G -Xmx1424M -agentlib:jdwp =transport=dt_socket,server=y,suspend=n,address=5005 -jar paper-120.jar nogui
      • From IntelliJ, click the “debug” button.
  • You can run periodic calls with a BukkitRunnable (e.g. runTaskTimer)

  • Yaw vs. pitch diagram

    • These are in degrees in Minecraft which you can see by pressing F3.
    • A pitch of 90 means you’re looking straight down and -90 means you’re looking straight up.
    • Yaw:
      • 0° south
      • 90° west
      • 180° north
      • 270° east
  • The name of the method doesn’t matter; Java will inspect the argument type to figure out which method it’s going to be.

Cannot set rotation of players. Consider teleporting instead.

Section titled Cannot set rotation of players. Consider teleporting instead.

player.setRotation exists, but it errors. Instead, you have to teleport to a location which has the yaw and pitch directly in it:

float yaw = 0;
float pitch = 45;
player.teleport(new Location(world, x, y, z, yaw, pitch));

Cannot find external resources (e.g. files) while loading from Java

Section titled Cannot find external resources (e.g. files) while loading from Java

The problem is that it’s PaperSpigot that’s running Java, no the plug-in itself, so the paths are relative to PaperSpigot’s working directory.

Scheduler worker in group main failed with an uncaught exception

Section titled Scheduler worker in group main failed with an uncaught exception

The full error looks something like this:

[10:09:23 ERROR]: [reactor.core.scheduler.Schedulers] Scheduler worker in group main failed with an uncaught exception

reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalStateException: PlayerTeleportEvent may only be triggered synchronously.

Caused by: java.lang.IllegalStateException: PlayerTeleportEvent may only be triggered synchronously.

This is caused by not running things in the Bukkit server thread. To fix it, you can simply schedule things through Bukkit itself:

Bukkit.getScheduler().runTask(javaPlugin, lambda -> player.teleport(location));

This can be confusing at times because you may have already been on the server thread, e.g. if you were responding to an event like an entity taking damage or a player joining the game. In those cases, you don’t need to schedule the task because you’re already on the correct thread.