Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ jobs:
java-version: 21
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
- name: Cache Hytale Server
uses: actions/cache@v4
with:
path: |
hytale/libs/HytaleServer.jar
hytale/build/download/hytale-downloader-linux-amd64
key: ${{ runner.os }}-hytale-download
restore-keys: |
${{ runner.os }}-hytale-
- name: Download Hytale Server
env:
HYTALE_DOWNLOADER_CREDENTIALS: ${{ secrets.HYTALE_DOWNLOADER_CREDENTIALS }}
run: ./gradlew :hytale:download-server
- name: Build with Gradle
run: ./gradlew build
- name: Test with Gradle
Expand Down
19 changes: 16 additions & 3 deletions .github/workflows/maven-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ on:
types: [ prereleased, released ]
jobs:
build:
env:
REPOSITORY_USER: ${{ secrets.REPOSITORY_USER }}
REPOSITORY_TOKEN: ${{ secrets.REPOSITORY_TOKEN }}
runs-on: ubuntu-latest
steps:
- name: Checkout sources
Expand All @@ -18,5 +15,21 @@ jobs:
java-version: 21
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
- name: Cache Hytale Server
uses: actions/cache@v4
with:
path: |
hytale/libs/HytaleServer.jar
hytale/build/download/hytale-downloader-linux-amd64
key: ${{ runner.os }}-hytale-download
restore-keys: |
${{ runner.os }}-hytale-
- name: Download Hytale Server
env:
HYTALE_DOWNLOADER_CREDENTIALS: ${{ secrets.HYTALE_DOWNLOADER_CREDENTIALS }}
run: ./gradlew :hytale:download-server
- name: Publish with Gradle to Repository
env:
REPOSITORY_USER: ${{ secrets.REPOSITORY_USER }}
REPOSITORY_TOKEN: ${{ secrets.REPOSITORY_TOKEN }}
run: ./gradlew publish
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=0.8.1
version=0.9.0
3 changes: 3 additions & 0 deletions hytale/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Credentials ###
.hytale-downloader-credentials.json
libs
52 changes: 52 additions & 0 deletions hytale/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Hytale Module

Since the Hytale API is not public yet, and redistribution is not allowed,
you have to download the Hytale server yourself.

## Initial Setup

Before building this module, you need to authenticate with your Hytale account. You have two options:

### Option 1: Using Environment Variable (Recommended for CI)

Set the `HYTALE_DOWNLOADER_CREDENTIALS` environment variable with your Hytale authentication credentials:

```bash
export HYTALE_DOWNLOADER_CREDENTIALS='{"your":"auth","json":"here"}'
./gradlew :hytale:download-server
```

This token can be obtained by running the download task without credentials once (
see [Obtaining Hytale Authentication](#obtaining-hytale-authentication)).

### Option 2: Using Credentials File (Recommended for Local Development)

1. Create `.hytale-downloader-credentials.json` in the `hytale/` directory
2. Paste your Hytale authentication JSON credentials in the file
3. Run the download task:

```bash
./gradlew :hytale:download-server
```

The credentials file is gitignored and won't be committed.

## Obtaining Hytale Authentication

To get your Hytale authentication credentials:

1. Run the download task without credentials:
```bash
./gradlew :hytale:download-server
```
2. The Hytale downloader will prompt you to authenticate
3. After successful authentication, the credentials will be saved to
`.hytale-downloader-credentials.json` for future use

## Updating the Server

To update the Hytale server:

```bash
./gradlew :hytale:update-server
```
136 changes: 136 additions & 0 deletions hytale/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
val moduleName by extra("dev.faststats.hytale")

val libsDir: Directory = layout.projectDirectory.dir("libs")
val hytaleServerJar: RegularFile = libsDir.file("HytaleServer.jar")
val credentialsFile: RegularFile = layout.projectDirectory.file(".hytale-downloader-credentials.json")
val downloadDir: Provider<Directory> = layout.buildDirectory.dir("download")
val hytaleZip: Provider<RegularFile> = downloadDir.map { it.file("hytale.zip") }

dependencies {
api(project(":core"))
compileOnly(files(hytaleServerJar))
}

tasks.register("download-server") {
group = "hytale"

doLast {
if (hytaleServerJar.asFile.exists()) {
println("HytaleServer.jar already exists, skipping download")
return@doLast
}

val downloaderZip: Provider<RegularFile> = downloadDir.map { it.file("hytale-downloader.zip") }

libsDir.asFile.mkdirs()
downloadDir.get().asFile.mkdirs()

val os = org.gradle.internal.os.OperatingSystem.current()
val downloaderExecutable = when {
os.isLinux -> downloadDir.map { it.file("hytale-downloader-linux-amd64") }
os.isWindows -> downloadDir.map { it.file("hytale-downloader-windows-amd64.exe") }
else -> throw GradleException("Unsupported operating system: ${os.name}")
}

if (!downloaderExecutable.get().asFile.exists()) {
if (!downloaderZip.get().asFile.exists()) ant.invokeMethod(
"get", mapOf(
"src" to "https://downloader.hytale.com/hytale-downloader.zip",
"dest" to downloaderZip.get().asFile.absolutePath
)
) else {
println("hytale-downloader.zip already exists, skipping download")
}

copy {
from(zipTree(downloaderZip))
include(downloaderExecutable.get().asFile.name)
into(downloadDir)
}
} else {
println("Hytale downloader binary already exists, skipping download and extraction")
}

if (downloaderZip.get().asFile.delete()) {
println("Deleted hytale-downloader.zip after extracting binaries")
}

downloaderExecutable.get().asFile.setExecutable(true)

if (!hytaleZip.get().asFile.exists()) {
val credentials = System.getenv("HYTALE_DOWNLOADER_CREDENTIALS")
if (!credentials.isNullOrBlank()) {
if (!credentialsFile.asFile.exists()) {
credentialsFile.asFile.writeText(credentials)
println("Hytale downloader credentials written from environment variable to ${credentialsFile.asFile.absolutePath}")
} else {
println("Using existing credentials file at ${credentialsFile.asFile.absolutePath}")
}
}

val processBuilder = ProcessBuilder(
downloaderExecutable.get().asFile.absolutePath,
"-download-path",
"hytale",
"-credentials-path",
credentialsFile.asFile.absolutePath
)
processBuilder.directory(downloadDir.get().asFile)
processBuilder.redirectErrorStream(true)
val process = processBuilder.start()

process.inputStream.bufferedReader().use { reader ->
reader.lines().forEach { line ->
println(line)
}
}

val exitCode = process.waitFor()
if (exitCode != 0) {
throw GradleException("Hytale downloader failed with exit code: $exitCode")
}
} else {
println("hytale.zip already exists, skipping download")
}

if (hytaleZip.get().asFile.exists()) {
val serverDir = downloadDir.map { it.dir("Server") }
copy {
from(zipTree(hytaleZip))
include("Server/HytaleServer.jar")
into(downloadDir)
}

val extractedJar = serverDir.map { it.file("HytaleServer.jar") }
if (extractedJar.get().asFile.exists()) {
extractedJar.get().asFile.copyTo(hytaleServerJar.asFile, overwrite = true)
serverDir.get().asFile.deleteRecursively()
} else {
throw GradleException("HytaleServer.jar was not found in Server/ subdirectory")
}

if (!hytaleServerJar.asFile.exists()) {
throw GradleException("HytaleServer.jar was not found in hytale.zip")
}

hytaleZip.get().asFile.delete()
println("Deleted hytale.zip after extracting HytaleServer.jar")
} else {
throw GradleException(
"hytale.zip not found at ${hytaleZip.get().asFile.absolutePath}. " +
"The downloader may not have completed successfully."
)
}
}
}

tasks.register("update-server") {
group = "hytale"
hytaleServerJar.asFile.delete()
hytaleZip.get().asFile.delete()
dependsOn(tasks.named("download-server"))
}

tasks.compileJava {
dependsOn(tasks.named("download-server"))
}
16 changes: 16 additions & 0 deletions hytale/example-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
id("com.gradleup.shadow") version "9.3.1"
}

val libsDir: Directory = project(":hytale").layout.projectDirectory.dir("libs")
val hytaleServerJar: RegularFile = libsDir.file("HytaleServer.jar")

dependencies {
compileOnly(files(hytaleServerJar))
implementation(project(":hytale"))
}

tasks.shadowJar {
// optionally relocate faststats
relocate("dev.faststats", "com.example.utils.faststats")
}
37 changes: 37 additions & 0 deletions hytale/example-plugin/src/main/java/com/example/ExamplePlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.example;

import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import dev.faststats.hytale.HytaleMetrics;
import dev.faststats.core.Metrics;
import dev.faststats.core.chart.Chart;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;

import java.net.URI;

public class ExamplePlugin extends JavaPlugin {
private final Metrics metrics = HytaleMetrics.factory()
.url(URI.create("https://metrics.example.com/v1/collect")) // For self-hosted metrics servers only

// Custom example charts
// For this to work you have to create a corresponding data source in your project settings first
.addChart(Chart.number("example_chart", () -> 42))
.addChart(Chart.string("example_string", () -> "Hello, World!"))
.addChart(Chart.bool("example_boolean", () -> true))
.addChart(Chart.stringArray("example_string_array", () -> new String[]{"Option 1", "Option 2"}))
.addChart(Chart.numberArray("example_number_array", () -> new Number[]{1, 2, 3}))
.addChart(Chart.booleanArray("example_boolean_array", () -> new Boolean[]{true, false}))

.debug(true) // Enable debug mode for development and testing

.token("YOUR_TOKEN_HERE") // required -> token can be found in the settings of your project
.create(this);

public ExamplePlugin(JavaPluginInit init) {
super(init);
}

@Override
protected void shutdown() {
metrics.shutdown();
}
}
16 changes: 16 additions & 0 deletions hytale/example-plugin/src/main/resources/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"group": "com.example",
"name": "Example Plugin",
"version": "1.0.0",
"description": "An example plugin for Hytale",
"authors": [
{
"name": "Your Name",
"email": "yourname@example.com",
"url": "https://yourname.example.com"
}
],
"website": "https://example.com/example-plugin",
"serverVersion": "*",
"main": "com.example.ExamplePlugin"
}
23 changes: 23 additions & 0 deletions hytale/src/main/java/dev/faststats/hytale/HytaleMetrics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dev.faststats.hytale;

import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import dev.faststats.core.Metrics;
import org.jetbrains.annotations.Contract;

/**
* Hytale metrics implementation.
*
* @since 0.9.0
*/
public sealed interface HytaleMetrics extends Metrics permits HytaleMetricsImpl {
/**
* Creates a new metrics factory for Hytale.
*
* @return the metrics factory
* @since 0.9.0
*/
@Contract(pure = true)
static Metrics.Factory<JavaPlugin> factory() {
return new HytaleMetricsImpl.Factory();
}
}
Loading
Loading