mc-missile

Mod

Blow up your friends in Minecraft with guided missiles.

Server EquipmentGame MechanicsTechnology

59 downloads
0 followers
Follow Save

mc_missile

Blow up your friends in Minecraft 1.21.4 with guided missiles.

This is a server-only Fabric Minecraft mod. It allows all players to program guided missiles and fire them from a crossbow or dispenser. See Guided Missiles in Minecraft for what you can do with this mod.

Application Structure

This is a special Minecraft mod that connects to external processes through gRPC.

architecture overview diagram

Every player programs a guidance server application. These guidance servers could be hosted in Docker containers on the same host as the Minecraft server. Whenever a missile is fired Minecraft connects to the player's guidance server and sends the missile state (e.g., position, velocity) every tick. The guidance server can send control inputs to the missile after each received missile state.

Developing Missile Guidance

You can implement your guidance server in any language you like. It has to do two things:

  • Read the PORT environment variable.
  • Expose a gRPC server at that port adhering to the protocol defined in src/main/proto/guidance.proto. This guidance.proto file contains more documentation about the specifics of that protocol. The Guided Missiles in Minecraft article by Christopher Besch gives a detailed description of what a guidance system can do and how to achieve that.

Guidance Server Templates

Right now there are these templates to get you started right away:

Other People's Guidance Code

There are a few open-source guidance servers you can use for inspiration:

Flight Dynamics

Like the player the missile is an entity in Minecraft. The missile has

  • a position $p = \begin{pmatrix} p_1 \ p_2 \ p_3 \end{pmatrix} \in \mathbb{R}^3$ (with the elevation $p_2$),

  • velocity $v \in \mathbb{R}^3$,

  • pitch $\theta \in [-90, 90]$ and

  • yaw $\psi \in [-180, 180]$.

    These angles are in degrees and there's no roll. Additionally, they are the negated angles displayed in the Mincraft F3 Menu. That's because projectiles have flipped headings for some reason: $\theta=90$ is up, $\theta=-90$ down and $\psi \in {-180, 180}$ is north, $\psi = 90$ east, $\psi = 0$ south and $\psi = -90$ west.

Minecraft updates the missile's state every tick (20 times a second). The update in tick $t \in \mathbb{N}_0$ is separated into three stages:

  1. Receive the control input: The missile's only input method is an unrealisticly beefy control moment gyroscope. So the player's guidance code produces a requested change in pitch $\theta_{in}$ and yaw $\psi_{in}$. It has no direct control over the missiles position, velocity, or thrust — only the rotation.

  2. Update the missile's state: The gyroscope is powerful but not overly powerful. When the control input is too large (larger than $M_r$ defined by the airframe), it is scaled down linearly:

    \begin{aligned}
    l &= \sqrt{\theta_{in}^2 + \psi_{in}^2} \\
    \begin{pmatrix} \theta_{in} \\ \psi_{in} \end{pmatrix} 
      &\rightarrow \max{\left\{\frac{M_r}{l}, 1\right\}}
       \begin{pmatrix} \theta_{in} \\ \psi_{in} \end{pmatrix}.
    \end{aligned}
    

    With this, Minecraft applies the adjusted control input plus some random noise.

    \begin{aligned}
    \theta &\rightarrow \theta + \theta_{in} + N_r \\
    \psi   &\rightarrow \psi + \psi_{in} + N_r \\
    \end{aligned}
    

    each $N_r$ is normally distributed noise dependent on the air frame used by the missile. So you don't have perfect control over the missiles rotation, there is always some variance.

    Now the acceleration $a \in \mathbb{R}^3$ can be calculated from the rotation vector $r \in \mathbb{R}^3$, the current thrust $T(t) \in [0, \infty)$ and gravity $g = \begin{pmatrix} 0 \ -|g| \ 0 \end{pmatrix} \in \mathbb{R}^3$.

    \begin{aligned}
    r & =
    \begin{pmatrix}
        \sin(\psi) \cos(\theta) \\
        \sin(\theta) \\
        \cos(\psi) \cos(\theta)
    \end{pmatrix} \\
    a & = \begin{pmatrix} a_1 \\ a_2 \\ a_3 \end{pmatrix} \\
      & = \left(T(t) + N_T \right) \cdot r + g
    \end{aligned}
    

    $N_T$ is normally distributed noise and like the thrust function $T$ defined by the rocket motor.

    Lastly, the velocity and position are updated with the airframe defined drag $d \in [0, 1)$.

    \begin{aligned}
    v &\rightarrow (1 - d) \cdot (v + a) \\
    p &\rightarrow p + v
    \end{aligned}
    
  3. Now that the missile's state has been updated Minecraft sends that state to the player's guidance code. All these values contain some variance, too — depending on the missile's inertial measurement unit. The guidance server has a little less than 50ms to send the rotation change for the next tick.

In the first tick ($t=0$), the missile doesn't have guidance input yet and thus flies straight ahead with the velocity and rotation of the shooter. No variance is applied here.

Disclaimer: As you can see the flight dynamics of Minecraft missiles don't have anything to do with real missiles. There are no aerodynamic aspects simulated at all, for example. All we do is magically rotate a rock in vacuum. Thus the guidance code explained in this article can only be applied to the toy world that is Minecraft and nothing else. Still, it'll be fun!

Crafting Your First Missile

This is a server-only mod so you don't have to install any mods on your Minecraft client. As such there are no new items coming with this mod. All missiles are normal firework rocket items before launch. There are two special things differentiating missiles from normal Minecraft fireworks:

  • the item's name and
  • the ingredients used to craft the missile.

Missile Naming

In Minecraft you can change an item's name with an anvil. To convert a normal firework rockt into a missile you have need to give your firework rocket a special name.

  <- the id of the guidance server to use
     <- some string that is passed to the guidance server
m/69/test_name

This allows the Minecraft mod to identify what guidance server should be used. Additionally, each guidance server can implement multiple different missiles.

You still need to fulfill the ingredient requirements in the below section to craft a working missile.

Missile Budget

Your missile needs to be crafted with at least one firework star. There are many ways of crafting a missile. The mc_missile mod calculated what ingredients you used to craft the firework item. It gives every ingredient a value and adds these values up. This is the budget of the missile, which can be used to improve the missile's characteristics, see the Missile Components section.

Note: When you craft a firework rocket you get three firework rockets from one crafting recipe. If you invest one diamond into such a recipe, you'll have three firework rockets with 1/3 the value of a diamond each.

Example: A simple firework star can be crafted from one gunpowder and one dye. With this you can craft the cheapest missile: That firework star, one gunpowder and a paper and you get three missile with a budget of 99€.

These are all values for every possible ingredient.

==== Material Values ====
  PAPER =                            90€
  GUNPOWDER =                        90€
  DYE =                              27€
  BLAZE_POWDER =                     900€
  COAL =                             180€
  GOLD_NUGGET =                      90€
  HEAD =                             90000€
  FEATHER =                          180€
  DIAMOND =                          9000€
  GLOWSTONE_DUST =                   90€
  Lowest Possible Missile Budget =   99€
  Highest Possible Missile Budget =  231543€
==== Material Values ====

Missile Components

A missile is built from components, each with a price tag and effects on the missile. See guidance.proto for what effects they have.

These are the components' prices:

==== Hardware Component Costs ====
  == Warhead Costs ==
    BLANK =                          0€
    TNT_M =                          450€
    TNT_L =                          9000€
    TNT_XL =                         90000€
    INCENDIARY_M =                   900€
    INCENDIARY_L =                   18000€
    INCENDIARY_XL =                  180000€
    NEUTRON_BOMB_S =                 450€
    NEUTRON_BOMB_L =                 900€
    TUNGSTEN_PENETRATOR_S =          180€
    TUNGSTEN_PENETRATOR_M =          450€
    TUNGSTEN_PENETRATOR_L =          900€
    BUNKER_BUSTER_M =                18000€
    BUNKER_BUSTER_L =                27000€
    BUNKER_BUSTER_XL =               180000€
  == Warhead Costs ==
  == Airframe Costs ==
    SPACE_SHUTTLE =                  450000€
    BRICK =  0€
    DEFAULT_AIRFRAME =               180€
    PERFECT_AIRFRAME =               1800€
  == Airframe Costs ==
  == Motor Costs ==
    NO_MOTOR =                       0€
    SIMPLE_S =                       900€
    SIMPLE_M =                       1800€
    SIMPLE_L =                       2700€
    SIMPLE_XL =                      90000€
    BOOST_S =                        450€
    BOOST_M =                        900€
    TWO_STAGE_M =                    450€
    TWO_STAGE_L =                    900€
    RANDOM_S =                       450€
    RANDOM_L =                       900€
    CHANGING_S =                     450€
    CHANGING_M =                     900€
    CHANGING_L =                     1350€
  == Motor Costs ==
  == Battery Costs ==
    NO_BATTERY =                     0€
    LI_ION_XS =                      450€
    LI_ION_S =                       900€
    LI_ION_M =                       1350€
    LI_ION_L =                       2700€
    LI_ION_XL =                      5400€
    LI_ION_XXL =                     9000€
    NUCLEAR =                        90000€
  == Battery Costs ==
  == Seeker Costs ==
    NO_SEEKER =                      0€
    IR_SEEKER_WIDE_S =               9000€
    IR_SEEKER_WIDE_L =               18000€
    IR_SEEKER_WIDE_INACCURATE_S =    6000€
    IR_SEEKER_WIDE_INACCURATE_L =    12000€
    IR_SEEKER_SNIPER_S =             6000€
    IR_SEEKER_SNIPER_L =             12000€
    IR_SEEKER_SNIPER_INACCURATE_S =  2000€
    IR_SEEKER_SNIPER_INACCURATE_L =  4000€
    IR_SEEKER_360_S =                12000€
    IR_SEEKER_360_L =                24000€
    IR_SEEKER_360_INACCURATE_S =     6000€
    IR_SEEKER_360_INACCURATE_L =     12000€
    LASER_DISTANCE_SEEKER =          3000€
  == Seeker Costs ==
  == InertialSystem Costs ==
    BLIND =                          0€
    BAD_IMU =                        180€
    DEFAULT_IMU =                    1260€
    ACCURATE_IMU =                   2700€
    PERFECT_IMU =                    9000€
  == InertialSystem Costs ==
  Cheapest Possible Missile =        0€
  Most Expensive Possible Missile =  843000€
==== Hardware Component Costs ====

The summed prices of all components must be smaller or equal to the missile's budget.

Mod Installation

This mod is designed to be used by a Docker deployment. Take a look at the example_deployment and it's docker-compose.yml.

Mod Development

Development environment

  • Install Docker.
  • Create the dev container in this directory with: sudo docker run --net host -ti --name mc_missile_java -v ./:/home/gradle/mc_missile -p 25565:25565 --entrypoint /bin/bash gradle
  • When you leave that shell start the container again with: sudo docker start mc_missile_java
  • Now you can enter it with: sudo docker exec -ti mc_missile_java /bin/bash

Decompile Minecraft

  • run these commands in the mc_missile directory in the Docker container.
  • ./gradlew genSources
  • jar xf ../.gradle/loom-cache/minecraftMaven/net/minecraft/minecraft-merged-abba00472f/1.21.4-net.fabricmc.yarn.1_21_4.1.21.4+build.8-v2/minecraft-merged-abba00472f-1.21.4-net.fabricmc.yarn.1_21_4.1.21.4+build.8-v2-sources.jar com /net
  • jar xf ../.gradle/loom-cache/minecraftMaven/net/minecraft/minecraft-merged-abba00472f/1.21.4-net.fabricmc.yarn.1_21_4.1.21.4+build.8-v2/minecraft-merged-abba00472f-1.21.4-net.fabricmc.yarn.1_21_4.1.21.4+build.8-v2.jar assets/ data /

Gradle

  • run these commands in the mc_missile directory in the Docker container.
  • ./gradlew validateAccessWidener
  • cp ./env.sh.example ./env.sh and enter your desired config
  • ./gradlew runServer

Deploy

  • cp ./env.sh.example ./env.sh and enter your modrinth token (only do this once)
  • source ./env.sh
  • ./gradlew modrinth
  • you can also find the final jar in ./build/libs/mc_missile-1.0.0.jar

Formatting

  • Download google-java-format
  • run find ./src -name '*.java' -type f -print0 | xargs -0 java -jar ~/dwn/google-java-format-1.26.0-all-deps.jar --aosp -r

Project members

christopher-besch

Member

Details

Published 2 months ago
Updated 2 months ago