Host a HTTP server instead of sending data to third party.

This commit is contained in:
Alessandro Proto 2024-08-02 11:13:53 +02:00
parent 4f3912ac7b
commit 3505a3f44f
7 changed files with 152 additions and 91 deletions

View file

@ -16,6 +16,8 @@ repositories {
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
maven { url 'https://maven.wispforest.io' }
}
loom {
@ -38,6 +40,8 @@ dependencies {
// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
annotationProcessor modImplementation("io.wispforest:owo-lib:${project.owo_version}")
}

View file

@ -14,4 +14,6 @@ maven_group=ct.server
archives_base_name=ct-server
# Dependencies
fabric_version=0.100.8+1.21
fabric_version=0.100.8+1.21
owo_version=0.12.8-alpha.7+1.21

View file

@ -0,0 +1,80 @@
package ct.server;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
public class CtServer implements ModInitializer {
public static final String MOD_ID = "ct-server";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
public static final ct.server.CtServerConfig CONFIG = ct.server.CtServerConfig.createAndLoad();
private static float currentTps = 0;
private static float currentMspt = 0;
private static int currentPlayerCount = 0;
private static CtServer INSTANCE;
public static CtServer getInstance() {
return INSTANCE;
}
@Override
public void onInitialize() {
INSTANCE = this;
LOGGER.info("Starting ct-client");
ServerTickEvents.END_SERVER_TICK.register(server -> {
currentMspt = server.getAverageTickTime();
if (currentMspt != 0) {
currentTps = Math.min(20, 1000 / currentMspt);
}
});
ServerEntityEvents.ENTITY_LOAD.register((entity, world) -> {
if(entity instanceof ServerPlayerEntity) {
currentPlayerCount = world.getServer().getCurrentPlayerCount();
}
});
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
currentPlayerCount = server.getCurrentPlayerCount() - 1;
});
try {
var httpServer = new ServiceHttpServer();
} catch (IOException e) {
LOGGER.error("Unable to start HTTP server", e);
}
}
public static float getTPS() {
return currentTps;
}
public static float getMSPT() {
return currentMspt;
}
public static int getPlayerCount() {
return currentPlayerCount;
}
}

View file

@ -0,0 +1,8 @@
package ct.server;
import io.wispforest.owo.config.annotation.Config;
@Config(name = "ct-server-config", wrapperName = "CtServerConfig")
public class CtServerConfigModel {
public short httpPort = 25581;
}

View file

@ -1,89 +0,0 @@
package ct.server;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
public class Ctserver implements ModInitializer {
// This logger is used to write text to the console and the log file.
// It is considered best practice to use your mod id as the logger's name.
// That way, it's clear which mod wrote info, warnings, and errors.
public static final Logger LOGGER = LoggerFactory.getLogger("ct-server");
private int tickCounter = 0;
@Override
public void onInitialize() {
// This code runs as soon as Minecraft is in a mod-load-ready state.
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
LOGGER.info("Starting ct-client");
ServerTickEvents.END_SERVER_TICK.register(server -> {
try {
onEndServerTick(server);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
private void sendPostRequest(String urlString, String tps, String playerCount) throws Exception {
URL url = new URL(urlString);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "text/plain; utf-8");
con.setRequestProperty("TPS", tps);
con.setRequestProperty("PLAYERCOUNT", playerCount);
con.setRequestProperty("Accept", "text/plain");
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
byte[] input = tps.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
int code = con.getResponseCode();
//LOGGER.info("POST Response Code :: " + code);
con.disconnect();
}
long zeroTicks = 0;
private void onEndServerTick(MinecraftServer minecraftServer) throws Exception {
tickCounter++;
if (tickCounter >= 20) {
int playerCount = minecraftServer.getCurrentPlayerCount();
//LOGGER.info(String.valueOf(playerCount));
double afterTicks = Instant.now().toEpochMilli();
double timeBetween = afterTicks - zeroTicks;
double mspt = (timeBetween / 20) ;
double tps = 1000 / mspt;
//LOGGER.info(String.valueOf(timeBetween));
//LOGGER.info(String.valueOf(mspt));
//LOGGER.info(String.valueOf(tps));
if (tps <= 20) {
CompletableFuture.runAsync(() -> {
try {
sendPostRequest("http://us-ky-medium-0004.knijn.one:58926/tps", String.valueOf(tps),String.valueOf(playerCount));
} catch (Exception e) {
LOGGER.error("Failed to send POST request", e);
}
});
}
//LOGGER.info("Sent HTTP request");
tickCounter = 0;
zeroTicks = Instant.now().toEpochMilli();
}
}
}

View file

@ -0,0 +1,56 @@
package ct.server;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
public class ServiceHttpServer {
private HttpServer server;
public ServiceHttpServer() throws IOException {
server = HttpServer.create(new InetSocketAddress(CtServer.CONFIG.httpPort()), 0);
server.createContext("/tps", new TPSHandler());
server.createContext("/mspt", new MSPTHandler());
server.createContext("/player", new PlayerCountHandler());
server.setExecutor(null);
var httpThread = new Thread(() -> server.start());
httpThread.start();
}
static class TPSHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
var tps = String.valueOf(CtServer.getTPS());
t.sendResponseHeaders(200, tps.length());
var body = t.getResponseBody();
body.write(tps.getBytes());
body.close();
}
}
static class MSPTHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
var tps = String.valueOf(CtServer.getMSPT());
t.sendResponseHeaders(200, tps.length());
var body = t.getResponseBody();
body.write(tps.getBytes());
body.close();
}
}
static class PlayerCountHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
var tps = String.valueOf(CtServer.getPlayerCount());
t.sendResponseHeaders(200, tps.length());
var body = t.getResponseBody();
body.write(tps.getBytes());
body.close();
}
}
}

View file

@ -16,7 +16,7 @@
"environment": "*",
"entrypoints": {
"main": [
"ct.server.Ctserver"
"ct.server.CtServer"
],
"client": [
"ct.server.CtserverClient"