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 fabric/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
val moduleName by extra("dev.faststats.fabric")

plugins {
id("fabric-loom") version ("1.15-SNAPSHOT")
}

dependencies {
api(project(":core"))
mappings(loom.officialMojangMappings())
minecraft("com.mojang:minecraft:1.21.11")
modCompileOnly("net.fabricmc.fabric-api:fabric-api:0.139.4+1.21.11")
modImplementation("net.fabricmc:fabric-loader:0.18.4")
}
16 changes: 16 additions & 0 deletions fabric/example-mod/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
id("fabric-loom")
}

dependencies {
implementation(project(":fabric"))
mappings(loom.officialMojangMappings())
minecraft("com.mojang:minecraft:1.21.11")
modCompileOnly("net.fabricmc:fabric-loader:0.18.4")
}

tasks.jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(project(":fabric").sourceSets["main"].output)
from(project(":core").sourceSets["main"].output)
}
51 changes: 51 additions & 0 deletions fabric/example-mod/src/main/java/com/example/ExampleMod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.example;

import dev.faststats.core.ErrorTracker;
import dev.faststats.core.Metrics;
import dev.faststats.core.chart.Chart;
import dev.faststats.fabric.FabricMetrics;
import net.fabricmc.api.ModInitializer;

import java.net.URI;

public class ExampleMod implements ModInitializer {
// context-aware error tracker, automatically tracks errors in the same class loader
public static final ErrorTracker ERROR_TRACKER = ErrorTracker.contextAware();

// context-unaware error tracker, does not automatically track errors
public static final ErrorTracker CONTEXT_UNAWARE_ERROR_TRACKER = ErrorTracker.contextUnaware();

private final Metrics metrics = FabricMetrics.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}))

// Attach an error tracker
// This must be enabled in the project settings
.errorTracker(ERROR_TRACKER)

.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("example-mod"); // your mod id as defined in fabric.mod.json

public void doSomethingWrong() {
try {
// Do something that might throw an error
throw new RuntimeException("Something went wrong!");
} catch (Exception e) {
CONTEXT_UNAWARE_ERROR_TRACKER.trackError(e);
}
}

@Override
public void onInitialize() {
}
}
20 changes: 20 additions & 0 deletions fabric/example-mod/src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"schemaVersion": 1,
"id": "example-mod",
"version": "1.0.0",
"name": "Example Mod",
"authors": [
"Your Name"
],
"environment": "server",
"entrypoints": {
"main": [
"com.example.ExampleMod"
]
},
"depends": {
"fabricloader": ">=0.18.4",
"minecraft": "1.21.11",
"fabric-api": ">=0.139.4"
}
}
42 changes: 42 additions & 0 deletions fabric/src/main/java/dev/faststats/fabric/FabricMetrics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package dev.faststats.fabric;

import dev.faststats.core.Metrics;
import org.jetbrains.annotations.Async;
import org.jetbrains.annotations.Contract;

/**
* Fabric metrics implementation.
*
* @since 0.13.0
*/
public sealed interface FabricMetrics extends Metrics permits FabricMetricsImpl {
/**
* Creates a new metrics factory for Fabric.
*
* @return the metrics factory
* @since 0.13.0
*/
@Contract(pure = true)
static Factory factory() {
return new FabricMetricsImpl.Factory();
}

interface Factory extends Metrics.Factory<String, Factory> {
/**
* Creates a new metrics instance.
* <p>
* Metrics submission will start automatically.
*
* @param modId the mod id
* @return the metrics instance
* @throws IllegalStateException if the token is not specified
* @throws IllegalArgumentException if the mod is not found
* @see #token(String)
* @since 0.13.0
*/
@Override
@Async.Schedule
@Contract(value = "_ -> new", mutates = "io")
Metrics create(String modId) throws IllegalStateException, IllegalArgumentException;
}
}
87 changes: 87 additions & 0 deletions fabric/src/main/java/dev/faststats/fabric/FabricMetricsImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package dev.faststats.fabric;

import com.google.gson.JsonObject;
import dev.faststats.core.Metrics;
import dev.faststats.core.SimpleMetrics;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.server.MinecraftServer;
import org.jetbrains.annotations.Async;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.file.Path;
import java.util.Optional;
import java.util.function.Supplier;

final class FabricMetricsImpl extends SimpleMetrics implements FabricMetrics {
private final Logger logger = LoggerFactory.getLogger("FastStats");
private final ModContainer mod;

private @Nullable MinecraftServer server;

@Async.Schedule
@Contract(mutates = "io")
private FabricMetricsImpl(Factory factory, ModContainer mod, Path config) throws IllegalStateException {
super(factory, config);

this.mod = mod;

ServerLifecycleEvents.SERVER_STARTED.register(server -> {
this.server = server;
startSubmitting();
});
ServerLifecycleEvents.SERVER_STOPPING.register(server -> shutdown());
}

@Override
protected void appendDefaultData(JsonObject charts) {
assert server != null : "Server not initialized";
charts.addProperty("minecraft_version", server.getServerVersion());
charts.addProperty("online_mode", server.usesAuthentication());
charts.addProperty("player_count", server.getPlayerCount());
charts.addProperty("plugin_version", mod.getMetadata().getVersion().getFriendlyString());
charts.addProperty("server_type", "Fabric");
}

@Override
protected void printError(String message, @Nullable Throwable throwable) {
logger.error(message, throwable);
}

@Override
protected void printInfo(String message) {
logger.info(message);
}

@Override
protected void printWarning(String message) {
logger.warn(message);
}

private <T> Optional<T> tryOrEmpty(Supplier<T> supplier) {
try {
return Optional.of(supplier.get());
} catch (NoSuchMethodError | Exception e) {
return Optional.empty();
}
}

static final class Factory extends SimpleMetrics.Factory<String, FabricMetrics.Factory> implements FabricMetrics.Factory {
@Override
public Metrics create(String modId) throws IllegalStateException, IllegalArgumentException {
var fabric = FabricLoader.getInstance();
var mod = fabric.getModContainer(modId).orElseThrow(() -> {
return new IllegalArgumentException("Mod not found: " + modId);
});

var dataFolder = fabric.getConfigDir().resolve("faststats");
var config = dataFolder.resolve("config.properties");

return new FabricMetricsImpl(this, mod, config);
}
}
}
14 changes: 14 additions & 0 deletions fabric/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import org.jspecify.annotations.NullMarked;

@NullMarked
module dev.faststats.fabric {
exports dev.faststats.fabric;

requires com.google.gson;
requires dev.faststats.core;
requires net.fabricmc.loader;
requires org.slf4j;

requires static org.jetbrains.annotations;
requires static org.jspecify;
}
7 changes: 7 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
pluginManagement.repositories {
maven("https://maven.fabricmc.net/")
gradlePluginPortal()
}

plugins {
id("org.gradle.toolchains.foojay-resolver-convention").version("1.0.0")
}
Expand All @@ -7,6 +12,8 @@ include("bukkit")
include("bukkit:example-plugin")
include("bungeecord")
include("core")
include("fabric")
include("fabric:example-mod")
include("hytale")
include("hytale:example-plugin")
include("minestom")
Expand Down
Loading