diff --git a/build.gradle b/build.gradle index f49b7c8..ddb35fe 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,9 @@ repositories { } dependencies { + implementation 'org.projectlombok:lombok:1.18.26' + annotationProcessor 'org.projectlombok:lombok:1.18.26' + // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" @@ -33,6 +36,7 @@ dependencies { // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" implementation files('libs/java-curl-1.2.2.jar') + implementation 'com.google.code.gson:gson:2.10.1' } processResources { diff --git a/src/main/java/me/jonasjones/mcwebserver/McWebserver.java b/src/main/java/me/jonasjones/mcwebserver/McWebserver.java index 7a17f50..e7c7570 100644 --- a/src/main/java/me/jonasjones/mcwebserver/McWebserver.java +++ b/src/main/java/me/jonasjones/mcwebserver/McWebserver.java @@ -2,6 +2,7 @@ package me.jonasjones.mcwebserver; import com.roxstudio.utils.CUrl; import me.jonasjones.mcwebserver.config.ModConfigs; +import me.jonasjones.mcwebserver.web.api.v1.ApiHandler; import me.jonasjones.mcwebserver.web.ServerHandler; import net.fabricmc.api.ModInitializer; import org.slf4j.Logger; @@ -9,7 +10,7 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.TimeUnit; -import static me.jonasjones.mcwebserver.config.ModConfigs.WEB_PORT; +import static me.jonasjones.mcwebserver.config.ModConfigs.*; public class McWebserver implements ModInitializer { // This logger is used to write text to the console and the log file. @@ -18,44 +19,26 @@ public class McWebserver implements ModInitializer { public static String MOD_ID = "mcwebserver"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER"); - private static ServerHandler webserver = new ServerHandler(); - public static Thread webserverthread = new Thread(webserver); - public static boolean mcserveractive = true; @Override public void onInitialize() { // register configs ModConfigs.registerConfigs(); - LOGGER.info("McWebserver initialized!"); - - webserverthread.start(); - new Thread(() -> { - while (true) { - if (!mcserveractive) { - sleep(2); - for (int i = 0; i < 2; i++) { - CUrl curl = new CUrl("http://localhost:" + WEB_PORT + "/index.html").timeout(1, 1); - curl.exec(); - sleep(1); - } - LOGGER.info("Webserver Stopped!"); - break; - } else { - sleep(2); - } - } - }).start(); - } - - private void sleep(int seconds) { - try { - TimeUnit.SECONDS.sleep(seconds); - } catch (InterruptedException e) { - throw new RuntimeException(e); + if (SERVER_API_ENABLED) { + //start collecting api info + ApiHandler.startHandler(); + LOGGER.info("Server API enabled!"); } - } + if (ADV_API_ENABLED) { + //start collecting advanced api info + ApiHandler.startAdvHandler(); + LOGGER.info("Advanced Server API enabled!"); + } + + ServerHandler.start(); + } } diff --git a/src/main/java/me/jonasjones/mcwebserver/config/ModConfigs.java b/src/main/java/me/jonasjones/mcwebserver/config/ModConfigs.java index ddecaf5..41e2936 100644 --- a/src/main/java/me/jonasjones/mcwebserver/config/ModConfigs.java +++ b/src/main/java/me/jonasjones/mcwebserver/config/ModConfigs.java @@ -15,6 +15,8 @@ public class ModConfigs { public static String WEB_ROOT; public static String WEB_FILE_ROOT; public static String WEB_FILE_404; + public static Boolean SERVER_API_ENABLED; + public static Boolean ADV_API_ENABLED; public static String WEB_FILE_NOSUPPORT; public static Boolean VERBOSE = false; //needs to be set to false since the verbose logger is called before config file is fully loaded @@ -40,6 +42,8 @@ public class ModConfigs { config.addKeyValuePair(new Pair<>("web.root", "webserver/"), "the root directory of the webserver, starting from the main server directory"); config.addKeyValuePair(new Pair<>("web.file.root", "index.html"), "the name of the html file for the homepage"); config.addKeyValuePair(new Pair<>("web.file.404", "404.html"), "the name of the html file for 404 page"); + config.addKeyValuePair(new Pair<>("web.api", true), "whether or not the webserver api should be enabled or not"); + config.addKeyValuePair(new Pair<>("web.api.adv", true), "whether or not the api should expose information such as player coordinates and inventory"); config.addKeyValuePair(new Pair<>("web.file.notSupported", "not_supported.html"), "the name of the html file for 'not supported' page"); config.addKeyValuePair(new Pair<>("logger.verbose", true), "whether or not to log verbose output"); } @@ -50,6 +54,8 @@ public class ModConfigs { WEB_ROOT = CONFIG.getOrDefault("web.root", "webserver/"); WEB_FILE_ROOT = CONFIG.getOrDefault("web.file.root", "index.html"); WEB_FILE_404 = CONFIG.getOrDefault("web.file.404", "404.html"); + SERVER_API_ENABLED = CONFIG.getOrDefault("web.api", true); + ADV_API_ENABLED = CONFIG.getOrDefault("web.api.adv", true); WEB_FILE_NOSUPPORT = CONFIG.getOrDefault("web.file.notSupported", "not_supported.html"); VERBOSE = CONFIG.getOrDefault("logger.verbose", true); } diff --git a/src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java b/src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java index baeceaa..ba64004 100644 --- a/src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java +++ b/src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java @@ -1,6 +1,7 @@ package me.jonasjones.mcwebserver.mixin; import me.jonasjones.mcwebserver.McWebserver; +import me.jonasjones.mcwebserver.web.ServerHandler; import net.minecraft.server.MinecraftServer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -12,6 +13,6 @@ public class WebserverStopMixin { @Inject(at = @At("HEAD"), method = "shutdown") private void init(CallbackInfo info) { McWebserver.LOGGER.info("Stopping Webserver..."); - McWebserver.mcserveractive = false; + ServerHandler.mcserveractive = false; } } diff --git a/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java b/src/main/java/me/jonasjones/mcwebserver/web/HttpServer.java similarity index 74% rename from src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java rename to src/main/java/me/jonasjones/mcwebserver/web/HttpServer.java index 2e270d4..f151822 100644 --- a/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java +++ b/src/main/java/me/jonasjones/mcwebserver/web/HttpServer.java @@ -3,6 +3,9 @@ package me.jonasjones.mcwebserver.web; import me.jonasjones.mcwebserver.config.ModConfigs; import me.jonasjones.mcwebserver.McWebserver; import me.jonasjones.mcwebserver.util.VerboseLogger; +import me.jonasjones.mcwebserver.web.api.v1.ApiHandler; +import me.jonasjones.mcwebserver.web.api.v1.ApiRequests; +import me.jonasjones.mcwebserver.web.api.v1.ApiRequestsUtil; import java.io.BufferedOutputStream; import java.io.BufferedReader; @@ -20,9 +23,10 @@ import java.nio.file.Path; import java.time.Instant; import java.util.StringTokenizer; -import static me.jonasjones.mcwebserver.McWebserver.mcserveractive; +import static me.jonasjones.mcwebserver.web.ServerHandler.mcserveractive; +import static me.jonasjones.mcwebserver.web.api.v1.ApiHandler.isApiRequest; -public class HTTPServer implements Runnable { +public class HttpServer implements Runnable { static Path WEB_ROOT; static final String DEFAULT_FILE = ModConfigs.WEB_FILE_ROOT; static final String FILE_NOT_FOUND = ModConfigs.WEB_FILE_404; @@ -44,6 +48,7 @@ public class HTTPServer implements Runnable { // Client Connection via Socket Class private final Socket connect; + private Boolean isApiRequest = false; static { try { @@ -53,7 +58,7 @@ public class HTTPServer implements Runnable { } } - public HTTPServer(Socket c) { + public HttpServer(Socket c) { connect = c; } @@ -65,12 +70,13 @@ public class HTTPServer implements Runnable { // we listen until user halts server execution while (mcserveractive) { - HTTPServer myServer = new HTTPServer(serverConnect.accept()); + HttpServer myServer = new HttpServer(serverConnect.accept()); VerboseLogger.info("Connection opened. (" + Instant.now() + ")"); // create dedicated thread to manage the client connection Thread thread = new Thread(myServer); + thread.setName("McWebserver-worker"); thread.start(); } @@ -108,6 +114,7 @@ public class HTTPServer implements Runnable { // we support only GET and HEAD methods, we check if (!method.equals("GET") && !method.equals("HEAD")) { + isApiRequest = false; VerboseLogger.info("501 Not Implemented : " + method + " method."); // we return the not supported file to the client @@ -127,8 +134,50 @@ public class HTTPServer implements Runnable { // file dataOut.write(fileData, 0, fileData.length); dataOut.flush(); + } else if (isApiRequest(fileRequested)) { + isApiRequest = true; + + // Set appropriate response headers + dataOut.write("HTTP/1.1 200 OK\r\n".getBytes(StandardCharsets.UTF_8)); + dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); + if (fileRequested.equals("/api/v1/servericon")) { + dataOut.write("Content-Type: image/png\r\n".getBytes(StandardCharsets.UTF_8)); + // Get server icon from ApiHandler + byte[] serverIcon = ApiRequestsUtil.getServerIcon(); + int contentLength = serverIcon.length; + + dataOut.write(("Content-Length: " + contentLength + "\r\n").getBytes(StandardCharsets.UTF_8)); + dataOut.write("\r\n".getBytes(StandardCharsets.UTF_8)); // Blank line before content + + // Send server icon + dataOut.write(serverIcon, 0, contentLength); + dataOut.flush(); + } else { + dataOut.write("Content-Type: application/json\r\n".getBytes(StandardCharsets.UTF_8)); + String jsonString = ""; + try { + // Get JSON data from ApiHandler + jsonString = ApiHandler.handle(fileRequested); + } catch (Exception e) { + VerboseLogger.error("Error getting JSON data from ApiHandler: " + e.getMessage()); + jsonString = ApiRequests.internalServerError(); + } + + + byte[] jsonBytes = jsonString.getBytes(StandardCharsets.UTF_8); + int contentLength = jsonBytes.length; + + dataOut.write(("Content-Length: " + contentLength + "\r\n").getBytes(StandardCharsets.UTF_8)); + dataOut.write("\r\n".getBytes(StandardCharsets.UTF_8)); // Blank line before content + + // Send JSON data + dataOut.write(jsonBytes, 0, contentLength); + dataOut.flush(); + } + } else { + isApiRequest = false; // GET or HEAD method if (fileRequested.endsWith("/")) { fileRequested += DEFAULT_FILE; @@ -164,6 +213,8 @@ public class HTTPServer implements Runnable { } catch (NoSuchFileException e) { try { + assert out != null; + assert dataOut != null; fileNotFound(out, dataOut, fileRequested); } catch (IOException ioe) { VerboseLogger.error("Error with file not found exception : " + ioe.getMessage()); @@ -175,6 +226,7 @@ public class HTTPServer implements Runnable { try { in.close(); out.close(); + assert dataOut != null; dataOut.close(); connect.close(); // we close socket connection } catch (Exception e) { @@ -193,7 +245,9 @@ public class HTTPServer implements Runnable { // return supported MIME Types private String getContentType(String fileRequested) { - if (fileRequested.endsWith(".htm") || fileRequested.endsWith(".html")) + if (isApiRequest) { + return "application/json"; + } else if (fileRequested.endsWith(".htm") || fileRequested.endsWith(".html")) return "text/html"; else if (fileRequested.endsWith(".css")) return "text/css"; diff --git a/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java b/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java index 4adae22..d27dc0e 100644 --- a/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java +++ b/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java @@ -1,21 +1,60 @@ package me.jonasjones.mcwebserver.web; +import com.roxstudio.utils.CUrl; import me.jonasjones.mcwebserver.config.ModConfigs; import java.net.Socket; +import java.util.concurrent.TimeUnit; import static me.jonasjones.mcwebserver.McWebserver.LOGGER; +import static me.jonasjones.mcwebserver.config.ModConfigs.WEB_PORT; public class ServerHandler implements Runnable { public static Socket socket = new Socket(); + private static final ServerHandler webserver = new ServerHandler(); + public static Thread webserverthread = new Thread(webserver); + + public static boolean mcserveractive = true; + + public static void start() { + webserverthread.setName("McWebserver-webserver"); + webserverthread.start(); + Thread serverthread = new Thread(() -> { + while (true) { + if (!mcserveractive) { + sleep(2); + for (int i = 0; i < 2; i++) { + CUrl curl = new CUrl("http://localhost:" + WEB_PORT + "/api/v1/dummy").timeout(1, 1); // a truly awful way of stopping this thread + curl.exec(); + sleep(1); + } + LOGGER.info("Webserver Stopped!"); + break; + } else { + sleep(2); + } + } + }); + serverthread.setName("McWebserver-main"); + serverthread.start(); + } + + private static void sleep(int seconds) { + try { + TimeUnit.SECONDS.sleep(seconds); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + public void run() { if (ModConfigs.IS_ENABLED) { LOGGER.info("Starting Webserver..."); - new HTTPServer(socket); - HTTPServer.main(); + new HttpServer(socket); + HttpServer.main(); } else { LOGGER.info("Webserver disabled in the config file."); } diff --git a/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiHandler.java b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiHandler.java new file mode 100644 index 0000000..9d58e5a --- /dev/null +++ b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiHandler.java @@ -0,0 +1,100 @@ +package me.jonasjones.mcwebserver.web.api.v1; + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; + +public class ApiHandler { + + public static Boolean isApiRequest(String request) { + return request.startsWith("/api/v1/"); + } + public static String handle(String request) { + switch (request.replace("/api/v1/", "")) { + // Simple API Requests + case "motd" -> { + return ApiRequests.singleValueRequest(ApiRequestsUtil.getMOTD()); + } + case "serverip" -> { + return ApiRequests.singleValueRequest(ApiRequestsUtil.getSERVER_IP()); + } + case "serverport" -> { + return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getSERVER_PORT())); + } + case "servername" -> { + return ApiRequests.singleValueRequest(ApiRequestsUtil.getSERVER_NAME()); + } + case "serverversion" -> { + return ApiRequests.singleValueRequest(ApiRequestsUtil.getSERVER_VERSION()); + } + case "loaderversion" -> { + return ApiRequests.singleValueRequest(ApiRequestsUtil.getLOADER_VERSION()); + } + case "currentplayercount" -> { + return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getCURRENT_PLAYER_COUNT())); + } + case "defaultgamemode" -> { + return ApiRequests.singleValueRequest(ApiRequestsUtil.getDEFAULT_GAME_MODE().toString()); + } + case "maxplayercount" -> { + return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getMAX_PLAYER_COUNT())); + } + case "playernames" -> { + return ApiRequests.playerNamesRequest(); + } + case "servermetadata" -> { + return ApiRequests.serverMetadataRequest(); + } + case "ticks" -> { + return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getTICKS())); + } + case "ticktime" -> { + return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getTICK_TIME())); + } + case "timereference" -> { + return ApiRequests.singleValueRequest(String.valueOf(ApiRequestsUtil.getTIME_REFERENCE())); + } + case "getall" -> { + return ApiRequests.serverGetAllRequest(); + } + default -> { + return ApiRequests.badRequest(); + } + } + } + + public static void startHandler() { + //This is a really awful way of collection all this info. Please don't kill me. + ServerTickEvents.END_SERVER_TICK.register(server -> { + if (server.isRunning()) { + ApiRequestsUtil.setMOTD(server.getServerMotd()); + ApiRequestsUtil.setSERVER_IP(server.getServerIp()); + ApiRequestsUtil.setSERVER_PORT(server.getServerPort()); + ApiRequestsUtil.setSERVER_NAME(server.getName()); + ApiRequestsUtil.setSERVER_VERSION(server.getVersion()); + ApiRequestsUtil.setCURRENT_PLAYER_COUNT(server.getCurrentPlayerCount()); + ApiRequestsUtil.setDEFAULT_GAME_MODE(server.getDefaultGameMode()); + ApiRequestsUtil.setMAX_PLAYER_COUNT(server.getMaxPlayerCount()); + ApiRequestsUtil.setSERVER_METADATA(server.getServerMetadata()); + ApiRequestsUtil.setTICKS(server.getTicks()); + ApiRequestsUtil.setTICK_TIME(server.getTickTime()); + ApiRequestsUtil.setTIME_REFERENCE(server.getTimeReference()); + } + }); + } + + public static void startAdvHandler() { + //This is a really awful way of collection all this info. Please don't kill me. + ServerTickEvents.END_SERVER_TICK.register(server -> { + if (server.isRunning()) { + ApiRequestsUtil.setSERVER_PLAYER_ENTITY_LIST(server.getPlayerManager().getPlayerList()); + ApiRequestsUtil.setSERVER_RESOURCE_PACK_PROFILE_COLLECTION(server.getDataPackManager().getProfiles()); + ApiRequestsUtil.setSERVER_ADVANCEMENT_COLLECTION(server.getAdvancementLoader().getAdvancements()); + ApiRequestsUtil.setSERVER_BOSSBAR_COLLECTION(server.getBossBarManager().getAll()); + ApiRequestsUtil.getSERVER_PLAYER_ENTITY_LIST().forEach(serverPlayerEntity -> { + + }); + //SERVER_PLAYER_ENTITY_LIST = server.getPlayerInteractionManager().getPlayerList(); + } + }); + } + +} diff --git a/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiRequests.java b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiRequests.java new file mode 100644 index 0000000..af6ce47 --- /dev/null +++ b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiRequests.java @@ -0,0 +1,31 @@ +package me.jonasjones.mcwebserver.web.api.v1; + +import com.google.gson.Gson; + +public class ApiRequests { + private static final Gson gson = new Gson(); + + public static String singleValueRequest(String value) { + return "[\"" + value + "\"]"; + } + + public static String playerNamesRequest() { + return gson.toJsonTree(ApiRequestsUtil.convertPlayerList(ApiRequestsUtil.getSERVER_METADATA().players().get().sample())).getAsJsonArray().toString(); + } + + public static String serverMetadataRequest() { + return gson.toJson(ApiRequestsUtil.serverMetadata()); + } + + public static String serverGetAllRequest() { + return gson.toJson(ApiRequestsUtil.getAll()); + } + + public static String badRequest() { + return "{\"error\":{\"status\":400,\"message\":\"Bad Request\"}}"; + } + + public static String internalServerError() { + return "{\"error\":{\"status\":500,\"message\":\"Internal Server Error\"}}"; + } +} diff --git a/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiRequestsUtil.java b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiRequestsUtil.java new file mode 100644 index 0000000..8178fbf --- /dev/null +++ b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/ApiRequestsUtil.java @@ -0,0 +1,122 @@ +package me.jonasjones.mcwebserver.web.api.v1; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.authlib.GameProfile; +import lombok.Getter; +import lombok.Setter; +import me.jonasjones.mcwebserver.web.api.v1.json.ApiServerInfo; +import me.jonasjones.mcwebserver.web.api.v1.json.ApiServerMetadata; +import me.jonasjones.mcwebserver.web.api.v1.json.ApiServerMetadataPlayer; +import me.jonasjones.mcwebserver.web.api.v1.json.ApiServerMetadataPlayers; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.advancement.Advancement; +import net.minecraft.entity.boss.CommandBossBar; +import net.minecraft.resource.ResourcePackProfile; +import net.minecraft.server.ServerMetadata; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.world.GameMode; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static me.jonasjones.mcwebserver.config.ModConfigs.WEB_PORT; + +public class ApiRequestsUtil { + @Getter @Setter + private static String MOTD; + @Getter @Setter + private static String SERVER_IP; + @Getter @Setter + private static int SERVER_PORT; + @Getter @Setter + private static String SERVER_NAME; + @Getter @Setter + private static String SERVER_VERSION; + @Getter @Setter + private static int CURRENT_PLAYER_COUNT; + @Getter @Setter + private static GameMode DEFAULT_GAME_MODE; + @Getter + private static final String LOADER_VERSION = FabricLoader.getInstance().getModContainer("fabricloader").get().getMetadata().getVersion().getFriendlyString(); + @Getter @Setter + private static int MAX_PLAYER_COUNT; + @Getter @Setter + private static ServerMetadata SERVER_METADATA; + @Getter @Setter + private static int TICKS; + @Getter @Setter + private static float TICK_TIME; + @Getter @Setter + private static long TIME_REFERENCE; + @Getter @Setter + private static List SERVER_PLAYER_ENTITY_LIST = new ArrayList<>(); + @Getter @Setter + private static Collection SERVER_RESOURCE_PACK_PROFILE_COLLECTION = new ArrayList<>(); + @Getter @Setter + private static Collection SERVER_ADVANCEMENT_COLLECTION = new ArrayList<>(); + @Getter @Setter + private static Collection SERVER_BOSSBAR_COLLECTION = new ArrayList<>(); + private static final ApiServerInfo apiServerInfo = new ApiServerInfo(); + private static final ApiServerMetadata apiServerMetadata = new ApiServerMetadata(); + private static final ApiServerMetadataPlayers apiServerMetadataPlayers = new ApiServerMetadataPlayers(); + private static final Gson gson = new Gson(); + + + public static JsonObject serverMetadata() { + apiServerMetadataPlayers.setMAX(ApiRequestsUtil.getSERVER_METADATA().players().get().max()); + apiServerMetadataPlayers.setONLINE(ApiRequestsUtil.getSERVER_METADATA().players().get().online()); + apiServerMetadataPlayers.setSAMPLE(convertPlayerList(ApiRequestsUtil.getSERVER_METADATA().players().get().sample())); + + apiServerMetadata.setDESCRIPTION(ApiRequestsUtil.getSERVER_METADATA().description().getString()); + apiServerMetadata.setPLAYERS(JsonParser.parseString(gson.toJson(apiServerMetadataPlayers)).getAsJsonObject()); + apiServerMetadata.setVERSION((JsonObject) JsonParser.parseString("{\"version\":\"" + ApiRequestsUtil.getSERVER_METADATA().version().get().gameVersion() + "\",\"protocol\":" + ApiRequestsUtil.getSERVER_METADATA().version().get().protocolVersion() + "}")); + if (ApiRequestsUtil.getSERVER_METADATA().favicon().isPresent()) { + if (!ApiRequestsUtil.getSERVER_IP().equals("")) { + apiServerMetadata.setFAVICON("http://" + ApiRequestsUtil.getSERVER_IP() + ":" + WEB_PORT + "/api/v1/servericon"); + } else { + apiServerMetadata.setFAVICON("/api/v1/servericon"); + } + } else { + apiServerMetadata.setFAVICON(""); // if favicon doesn't exist + } + + apiServerMetadata.setSECURE_CHAT_EINFORCED(ApiRequestsUtil.getSERVER_METADATA().secureChatEnforced()); + + return JsonParser.parseString(gson.toJson(apiServerMetadata)).getAsJsonObject(); + } + + public static ArrayList convertPlayerList(List list) { + ArrayList players = new ArrayList<>(); + for (GameProfile profile : list) { + ApiServerMetadataPlayer player = new ApiServerMetadataPlayer(); + player.setID(profile.getId().toString()); + player.setNAME(profile.getName()); + //player.setPROPERTIES(profile.getProperties().toString()); //Add support for the properties later + player.setLEGACY(profile.isLegacy()); + players.add(player); + } + return players; + } + + public static JsonObject getAll() { + apiServerInfo.setSERVER_IP(ApiRequestsUtil.getSERVER_IP()); + apiServerInfo.setSERVER_PORT(ApiRequestsUtil.getSERVER_PORT()); + apiServerInfo.setSERVER_NAME(ApiRequestsUtil.getSERVER_NAME()); + apiServerInfo.setDEFAULT_GAME_MODE(ApiRequestsUtil.getDEFAULT_GAME_MODE().toString()); + apiServerInfo.setLOADER_VERSION(LOADER_VERSION); + apiServerInfo.setMETADATA(serverMetadata()); + apiServerInfo.setTICKS(ApiRequestsUtil.getTICKS()); + apiServerInfo.setTICK_TIME(ApiRequestsUtil.getTICK_TIME()); + apiServerInfo.setTIME_REFERENCE(ApiRequestsUtil.getTIME_REFERENCE()); + + return gson.toJsonTree(apiServerInfo).getAsJsonObject(); + } + + public static byte[] getServerIcon() { + return ApiRequestsUtil.getSERVER_METADATA().favicon().get().iconBytes(); + } + +} diff --git a/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerInfo.java b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerInfo.java new file mode 100644 index 0000000..6746d12 --- /dev/null +++ b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerInfo.java @@ -0,0 +1,17 @@ +package me.jonasjones.mcwebserver.web.api.v1.json; + +import com.google.gson.JsonObject; +import lombok.Setter; + +@Setter +public class ApiServerInfo { + private String SERVER_IP; + private int SERVER_PORT; + private String SERVER_NAME; + private String DEFAULT_GAME_MODE; + private String LOADER_VERSION; + private JsonObject METADATA; + private int TICKS; + private float TICK_TIME; + private long TIME_REFERENCE; +} diff --git a/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadata.java b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadata.java new file mode 100644 index 0000000..2998599 --- /dev/null +++ b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadata.java @@ -0,0 +1,14 @@ +package me.jonasjones.mcwebserver.web.api.v1.json; + +import com.google.gson.JsonObject; +import lombok.Setter; + +@Setter +public class ApiServerMetadata { + private String DESCRIPTION; + private JsonObject PLAYERS; + private JsonObject VERSION; + private String FAVICON; + private Boolean SECURE_CHAT_EINFORCED; + +} diff --git a/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayer.java b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayer.java new file mode 100644 index 0000000..9e2a962 --- /dev/null +++ b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayer.java @@ -0,0 +1,11 @@ +package me.jonasjones.mcwebserver.web.api.v1.json; + +import lombok.Setter; + +@Setter +public class ApiServerMetadataPlayer { + private String ID; + private String NAME; + private String PROPERTIES; + private Boolean LEGACY; +} diff --git a/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayerProperty.java b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayerProperty.java new file mode 100644 index 0000000..fd93fe3 --- /dev/null +++ b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayerProperty.java @@ -0,0 +1,4 @@ +package me.jonasjones.mcwebserver.web.api.v1.json; + +public class ApiServerMetadataPlayerProperty { +} diff --git a/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayers.java b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayers.java new file mode 100644 index 0000000..5ac2fb1 --- /dev/null +++ b/src/main/java/me/jonasjones/mcwebserver/web/api/v1/json/ApiServerMetadataPlayers.java @@ -0,0 +1,12 @@ +package me.jonasjones.mcwebserver.web.api.v1.json; + +import lombok.Setter; + +import java.util.ArrayList; + +@Setter +public class ApiServerMetadataPlayers { + private int MAX; + private int ONLINE; + private ArrayList SAMPLE; +}