Skip to content

Commit 3840638

Browse files
committed
Implement FabricMetrics class and example mod setup
1 parent 9b0cb40 commit 3840638

File tree

7 files changed

+238
-0
lines changed

7 files changed

+238
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
plugins {
2+
id("net.fabricmc.fabric-loom-remap") version "1.14-SNAPSHOT"
3+
}
4+
5+
loom {
6+
splitEnvironmentSourceSets()
7+
}
8+
9+
dependencies {
10+
implementation(project(":fabric"))
11+
mappings(loom.officialMojangMappings())
12+
minecraft("com.mojang:minecraft:1.21.11")
13+
modImplementation("net.fabricmc:fabric-loader:0.18.4")
14+
}
15+
16+
tasks.jar {
17+
from(project(":fabric").tasks.jar)
18+
from(project(":core").tasks.jar)
19+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.example;
2+
3+
import dev.faststats.core.ErrorTracker;
4+
import dev.faststats.core.Metrics;
5+
import dev.faststats.core.chart.Chart;
6+
import dev.faststats.fabric.FabricMetrics;
7+
import net.fabricmc.api.ModInitializer;
8+
9+
public class ExampleMod implements ModInitializer {
10+
// context-aware error tracker, automatically tracks errors in the same class loader
11+
public static final ErrorTracker ERROR_TRACKER = ErrorTracker.contextAware();
12+
13+
// context-unaware error tracker, does not automatically track errors
14+
public static final ErrorTracker CONTEXT_UNAWARE_ERROR_TRACKER = ErrorTracker.contextUnaware();
15+
16+
private final Metrics metrics = FabricMetrics.factory()
17+
//.url(URI.create("https://metrics.example.com/v1/collect")) // For self-hosted metrics servers only
18+
19+
// Custom example charts
20+
// For this to work you have to create a corresponding data source in your project settings first
21+
.addChart(Chart.number("example_chart", () -> 42))
22+
.addChart(Chart.string("example_string", () -> "Hello, World!"))
23+
.addChart(Chart.bool("example_boolean", () -> true))
24+
.addChart(Chart.stringArray("example_string_array", () -> new String[]{"Option 1", "Option 2"}))
25+
.addChart(Chart.numberArray("example_number_array", () -> new Number[]{1, 2, 3}))
26+
.addChart(Chart.booleanArray("example_boolean_array", () -> new Boolean[]{true, false}))
27+
28+
// Attach an error tracker
29+
// This must be enabled in the project settings
30+
.errorTracker(ERROR_TRACKER)
31+
32+
.debug(true) // Enable debug mode for development and testing
33+
34+
.token("sadlskmsldmkfglsdkmfgksjdfhngkjd") // required -> token can be found in the settings of your project
35+
.create("example-mod"); // your mod id as defined in fabric.mod.json
36+
37+
public void doSomethingWrong() {
38+
try {
39+
// Do something that might throw an error
40+
throw new RuntimeException("Something went wrong!");
41+
} catch (Exception e) {
42+
CONTEXT_UNAWARE_ERROR_TRACKER.trackError(e);
43+
}
44+
}
45+
46+
@Override
47+
public void onInitialize() {
48+
}
49+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"schemaVersion": 1,
3+
"id": "example-mod",
4+
"version": "1.0.0",
5+
"name": "Example Mod",
6+
"authors": [
7+
"Your Name"
8+
],
9+
"environment": "server",
10+
"entrypoints": {
11+
"main": [
12+
"com.example.ExampleMod"
13+
]
14+
},
15+
"depends": {
16+
"fabricloader": ">=0.18.4",
17+
"minecraft": "1.21.11",
18+
"fabric-api": ">=0.139.4"
19+
}
20+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package dev.faststats.fabric;
2+
3+
import dev.faststats.core.Metrics;
4+
import org.jetbrains.annotations.Async;
5+
import org.jetbrains.annotations.Contract;
6+
7+
/**
8+
* Fabric metrics implementation.
9+
*
10+
* @since 0.13.0
11+
*/
12+
public sealed interface FabricMetrics extends Metrics permits FabricMetricsImpl {
13+
/**
14+
* Creates a new metrics factory for Fabric.
15+
*
16+
* @return the metrics factory
17+
* @since 0.13.0
18+
*/
19+
@Contract(pure = true)
20+
static Factory factory() {
21+
return new FabricMetricsImpl.Factory();
22+
}
23+
24+
interface Factory extends Metrics.Factory<String, Factory> {
25+
/**
26+
* Creates a new metrics instance.
27+
* <p>
28+
* Metrics submission will start automatically.
29+
*
30+
* @param modId the mod id
31+
* @return the metrics instance
32+
* @throws IllegalStateException if the token is not specified
33+
* @throws IllegalArgumentException if the mod is not found
34+
* @see #token(String)
35+
* @since 0.13.0
36+
*/
37+
@Override
38+
@Async.Schedule
39+
@Contract(value = "_ -> new", mutates = "io")
40+
Metrics create(String modId) throws IllegalStateException, IllegalArgumentException;
41+
}
42+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package dev.faststats.fabric;
2+
3+
import com.google.gson.JsonObject;
4+
import dev.faststats.core.Metrics;
5+
import dev.faststats.core.SimpleMetrics;
6+
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
7+
import net.fabricmc.loader.api.FabricLoader;
8+
import net.fabricmc.loader.api.ModContainer;
9+
import net.minecraft.server.MinecraftServer;
10+
import org.jetbrains.annotations.Async;
11+
import org.jetbrains.annotations.Contract;
12+
import org.jspecify.annotations.Nullable;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
import java.nio.file.Path;
17+
import java.util.Optional;
18+
import java.util.function.Supplier;
19+
20+
final class FabricMetricsImpl extends SimpleMetrics implements FabricMetrics {
21+
private final Logger logger = LoggerFactory.getLogger("FastStats");
22+
private final ModContainer mod;
23+
24+
private @Nullable MinecraftServer server;
25+
26+
@Async.Schedule
27+
@Contract(mutates = "io")
28+
private FabricMetricsImpl(Factory factory, ModContainer mod, Path config) throws IllegalStateException {
29+
super(factory, config);
30+
31+
this.mod = mod;
32+
33+
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
34+
this.server = server;
35+
startSubmitting();
36+
});
37+
ServerLifecycleEvents.SERVER_STOPPING.register(server -> shutdown());
38+
}
39+
40+
@Override
41+
protected void appendDefaultData(JsonObject charts) {
42+
assert server != null : "Server not initialized";
43+
charts.addProperty("minecraft_version", server.getServerVersion());
44+
charts.addProperty("online_mode", server.usesAuthentication());
45+
charts.addProperty("player_count", server.getPlayerCount());
46+
charts.addProperty("plugin_version", mod.getMetadata().getVersion().getFriendlyString());
47+
charts.addProperty("server_type", "Fabric");
48+
}
49+
50+
@Override
51+
protected void printError(String message, @Nullable Throwable throwable) {
52+
logger.error(message, throwable);
53+
}
54+
55+
@Override
56+
protected void printInfo(String message) {
57+
logger.info(message);
58+
}
59+
60+
@Override
61+
protected void printWarning(String message) {
62+
logger.warn(message);
63+
}
64+
65+
private <T> Optional<T> tryOrEmpty(Supplier<T> supplier) {
66+
try {
67+
return Optional.of(supplier.get());
68+
} catch (NoSuchMethodError | Exception e) {
69+
return Optional.empty();
70+
}
71+
}
72+
73+
static final class Factory extends SimpleMetrics.Factory<String, FabricMetrics.Factory> implements FabricMetrics.Factory {
74+
@Override
75+
public Metrics create(String modId) throws IllegalStateException, IllegalArgumentException {
76+
var fabric = FabricLoader.getInstance();
77+
var mod = fabric.getModContainer(modId).orElseThrow(() -> {
78+
return new IllegalArgumentException("Mod not found: " + modId);
79+
});
80+
81+
var dataFolder = fabric.getConfigDir().resolve("faststats");
82+
var config = dataFolder.resolve("config.properties");
83+
84+
return new FabricMetricsImpl(this, mod, config);
85+
}
86+
}
87+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import org.jspecify.annotations.NullMarked;
2+
3+
@NullMarked
4+
module dev.faststats.fabric {
5+
exports dev.faststats.fabric;
6+
7+
requires com.google.gson;
8+
requires dev.faststats.core;
9+
requires net.fabricmc.loader;
10+
requires org.slf4j;
11+
12+
requires static org.jetbrains.annotations;
13+
requires static org.jspecify;
14+
}

settings.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
pluginManagement.repositories {
2+
maven("https://maven.fabricmc.net/")
3+
gradlePluginPortal()
4+
}
5+
16
plugins {
27
id("org.gradle.toolchains.foojay-resolver-convention").version("1.0.0")
38
}
@@ -7,6 +12,8 @@ include("bukkit")
712
include("bukkit:example-plugin")
813
include("bungeecord")
914
include("core")
15+
include("fabric")
16+
include("fabric:example-mod")
1017
include("hytale")
1118
include("hytale:example-plugin")
1219
include("minestom")

0 commit comments

Comments
 (0)