Documentation menu

Build your first game

Zero to a running SkyWars in five steps. Every file shown whole, then build, run and join.

This walks the whole path: an empty folder to a SkyWars you can join. It targets Hytale, so you write one module and never think about engines. Total: three files and a manifest.

1. Scaffold the module

A game is an ordinary Gradle module that produces a shadow jar. Two dependencies: the SDK and the engine adapter.

Project layout
skywars/
  build.gradle.kts
  src/main/
    java/net/example/
      SkyWars.java
      SkyWarsConfig.java
    resources/
      hive-game.json
build.gradle.kts
plugins {
  java
  id("com.gradleup.shadow") version "8.3.0"
}

dependencies {
  // the SDK + the Hytale adapter; nothing else to wire
  implementation("dev.hivescale:hive-sdk:1.0.0")
  implementation("dev.hivescale:minigame-hytale:1.0.0")
}

2. Declare it: hive-game.json

This sits in resources/ and is the only thing the network needs to register, size and route your game. minPlayers / maxPlayers / countdownSeconds drive the lobby; arena tells the genre which world to load and which markers are spawns. Full field list in Manifest & config.

src/main/resources/hive-game.json
{
  "id": "skywars",
  "name": "SkyWars",
  "genre": "match",
  "engine": "hytale",
  "main": "net.example.SkyWars",

  "minPlayers": 2,
  "maxPlayers": 12,
  "countdownSeconds": 20,

  "arena": {
    "world": "skywars-map-1",
    "spawns": "Player_Spawnpoint"
  }
}

3. Type your settings

Per-network knobs are a plain class. The network loads it, validates it, and hands it to your instance as ctx.config(). Operators tune these from the dashboard without a rebuild.

SkyWarsConfig.java
package net.example;

public final class SkyWarsConfig {
  public int chestRefillSeconds = 120;
  public boolean doubleJump = true;
}

4. Write the game

The whole game is three overrides. You describe what happens at start, on death, and at the end; the genre runs everything else around them, the countdown, the win check, scoring, and sending the winner home.

SkyWars.java
package net.example;

import dev.hivescale.minigame.match.MatchLifecycle;
import dev.hivescale.minigame.match.MatchContext;
import dev.hivescale.minigame.match.MatchResult;
import dev.hivescale.minigame.PlayerHandle;

public final class SkyWars extends MatchLifecycle<SkyWarsConfig> {

  // The lobby filled and the countdown hit zero. Drop everyone
  // onto their island. ctx.spawn(p) reads the arena's
  // "Player_Spawnpoint" markers for you.
  @Override
  public void onStart(MatchContext ctx) {
    ctx.players().forEach(p -> p.teleport(ctx.spawn(p)));
    ctx.broadcast("Last one standing wins. Go!");
  }

  // A player died. Eliminate them; the genre checks the win
  // condition and ends the match when one player is left.
  @Override
  public void onDeath(PlayerHandle p, MatchContext ctx) {
    ctx.eliminate(p);
    ctx.broadcast(p.name() + " is out. " + ctx.alive().size() + " left.");
  }

  // The match ended. The winner is already paid out and sent
  // home; this is just the closing line.
  @Override
  public void onEnd(MatchResult result, MatchContext ctx) {
    result.winner().ifPresent(w -> ctx.broadcast(w.name() + " won!"));
  }
}

That is the complete game. There is no game loop, no tick handler, no thread management, no server registration code.

Coming from raw Hytale? That last paragraph is the whole point. A hand-written Hytale party game has to stand up its own 30 Hz tick loop and hop every callback onto the world thread before it can do anything:

The part you no longer write
// What a hand-rolled Hytale party game does for the loop alone
// (GINCo's Byte Crashers, paraphrased):
Timer timer = new Timer("GameTick", true);
timer.scheduleAtFixedRate(new TimerTask() {
  public void run() {
    World w = gameStateManager.getBoardWorld();
    if (w != null && w.isAlive()) w.execute(() -> gameStateManager.tick());
  }
}, 0L, 33L);   // 30 Hz, by hand, plus thread-hopping into the world

The genre owns that loop. You only fill in the verbs.

5. Build, run, join

terminal
# Build the jar
$ ./gradlew shadowJar

# Drop it on a Hytale server and point it at your network
$ cp build/libs/skywars-all.jar  myserver/mods/
$ export HIVE_API_KEY=hv_live_••••••••••••••••
$ java -jar HytaleServer.jar

The jar self-registers on startup, so the server shows up as a skywars host in matchmaking immediately. Now join from a lobby (or a second client) and watch the flow:

  1. You land in the waiting lobby. Matchmaking keeps routing players in.
  2. At minPlayers the countdown starts, announced for you.
  3. At zero, onStart fires, everyone is teleported to a spawn, and the match begins.
  4. As players die, onDeath eliminates them and broadcasts the count.
  5. One left, the genre pays out, onEnd runs, and the winner is sent home.

You wrote three methods and got all of that.

Where to go next

  • Add a Hytale-only flourish (a particle burst on elimination) with the native escape hatch. It is one line and stays clearly marked.
  • Match games covers the full lifecycle, teams and custom win conditions.
  • Building a Mario-Party-style host instead? Party games.