Tools for managing and comparing Minecraft mounts. Today that means a JavaFX desktop app that ranks horses by the average of their three normalized stats (speed, jump height, health) so you can pick the two best ones to breed. Tomorrow it will hopefully also mean a Minecraft mod that reads those stats straight out of the game.
This application started as a university project for the course TDT4100 Object-Oriented Programming Spring 2026 at NTNU. The below image shows the class structure from the original submission, it features the 3 logic handling classes in the program.
Animal.java is an abstract superclass that implements the interface Comparable, the purpose of having the superclass is to allow other animals from minecraft (such as Donkeys) to be easier to implement in the future. Currently only the Horse class extends the Animal class. The Animal/Horse class handles the logic that goes into validating input (not error handling) and calculation of the average, on which the horses gets sorted.
HorseListManager.java is the class that handles loading and saving to file, additions, removals, and soriting.
HorseStatController.java handles user input and updates the view, all actions that manage the horses are delegated to HorseListManager.java.
HorseStatApp.java is the launcher/main class
mmm/
├── pom.xml ← parent pom: module list + all versions (read its comments!)
├── mmm-core/ ← pure Java library: Animal, Horse, HorseListManager
│ └── src/main/java/io/github/sofushl/mmm/core/
├── mmm-desktop/ ← JavaFX app: Application class, controller, FXML, CSS
│ ├── src/main/java/io/github/sofushl/mmm/desktop/
│ └── src/main/resources/io/github/sofushl/mmm/desktop/ (App.fxml, style.css)
└── mmm-mod/ ← empty placeholder for the future mod (see its README —
mods use Gradle, so it is NOT a Maven module)
The rule that keeps this manageable: mmm-core never imports anything from JavaFX (or any other framework). Logic goes in core; anything that touches a Scene, Stage, or FXML goes in desktop. If you're unsure where a new class belongs, ask "would the Minecraft mod need this?" — if yes, it's core.
mvn install # build everything, in dependency order
mvn javafx:run -pl mmm-desktop # run the desktop app (-pl = only that module)
mvn javafx:jlink -pl mmm-desktop # optional: self-contained runtime imagemvn install also copies mmm-core-<version>.jar into your local Maven
repository (~/.m2/repository), which is how the future Gradle-built mod
will consume the core library (mavenLocal()).
- Lifecycle:
mvn installruns a chain of phases in order —validate → compile → test → package → verify → install. Asking for a phase runs everything before it too.install's own job is just the last step: copy the built jar into~/.m2/repository. - Parent pom / inheritance: children declare
<parent>and inherit groupId, version, properties, and managed versions. That's why the child poms contain almost nothing. dependencyManagementvsdependencies: management only pins versions; it adds nothing to any classpath. A child still has to list the dependency, but without a<version>. One property (javafx.version) in one file controls every JavaFX artifact.- Reactor: the parent's
<modules>list. Maven builds modules in dependency order (core before desktop) automatically. - Transitive dependencies: desktop declares only
javafx-controlsandjavafx-fxml;javafx-baseandjavafx-graphicsarrive transitively.mvn dependency:tree -pl mmm-desktopshows the whole picture. - GAV coordinates: every artifact is identified by
groupId:artifactId:version.io.github.sofushlfollows the convention of using a domain you control (your GitHub namespace) reversed.
Animal.validStringCheckreturnstruefor invalid strings, andsetNamecalls it without using the result — names are never actually validated. Rename/fix when you next touch validation.HorseListManager.save(Horse)(the single-horse overload) opens the file in overwrite mode, so it would wipe the list; it's unused. Consider deleting it.- The controller hardcodes
./horses.txt, so the file appears in whatever directory you launch from.
MIT License — Copyright (c) 2026 Sofus Højberg Lind. See LICENSE.
