Skip to content

Commit dd7c01f

Browse files
committed
Update to 0.2.0
1 parent 93c7e1f commit dd7c01f

File tree

9 files changed

+116
-114
lines changed

9 files changed

+116
-114
lines changed

README.md

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,23 @@
22
Automatically build, host and require all your installed polymer mods resources!
33

44
## Config `(config/polypack_host.json)`
5-
* `hostIp`: The IP address to host the resource pack on. Leave as `null` to use the server's IP
6-
* Default: `null`
7-
* `hostPort`: The port to host the resource pack on. Make sure this port is also forwarded, so it can be accessed externally.
8-
* Default: `8001`
9-
* `threadCount`: The number of threads the HTTP server is allowed to use. If the server cannot keep up with the requests, this may need to be increased.
10-
* Default: `3`
11-
* `randomiseUrl`: If this is set to true, it will make the client download a new version of the resource pack each time. If you have issues with players joining and being told there was a resource pack error, set this to `true`.
5+
* `external_ip`: The IP address to host the resource pack on. Leave empty to use the IP server's properties file.
6+
* Default: ``
7+
* `host_port`: The port to host the resource pack on. Make sure this port is also forwarded, so it can be accessed externally.
8+
* Default: `24464`
9+
* `thread_count`: The number of threads the HTTP server is allowed to use. If the server cannot keep up with the requests, this may need to be increased.
10+
* Default: `1`
11+
* `randomise_url`: If this is set to true, it will make the client download a new version of the resource pack each time. If you have issues with players joining and being told there was a resource pack error, set this to `true`.
1212
* Default: `false`
1313

1414
## Recommended Server Properties `(server.properties)`
1515
* Set `require-resource-pack` to `true` so the client is mostly forced to use the resource pack.
1616
* Set `resource-pack-prompt` to something like `"Required Mod Resources""` so the player knows why the pack is required.
1717

18-
19-
## Maven
20-
The mod can be obtained by adding the repository:
21-
```gradle
22-
repositories {
23-
maven { url 'https://raw.github.com/aws404/maven/main' }
24-
}
25-
```
26-
and added to the runtime environment using:
27-
```gradle
28-
dependencies {
29-
modRuntime("com.github.aws404:polypack-host:[TAG]")
30-
}
31-
```
18+
## FAQ
19+
* I get a `No external IP address is defined in the configuration, this may cause errors outside of the local network.` warning everytime I start the server, what's the problem?
20+
* If you do not have an external IP defined, the mod cannot tell the client's where to find pack.
21+
* Set the external IP in the configuration or server.properties file to fix.
22+
* Some/All clients fail to download the resource pack.
23+
* The URL that is sent to the client is logged on server start, check this URL to make sure it looks right. Try opening the URL in your browser, it should also download the resource pack file.
24+
* Make sure the specified port is forwarded and accessible externally.

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ dependencies {
2020
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
2121
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
2222

23-
modImplementation("eu.pb4:polymer:${project.polymer_version}")
23+
modImplementation "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_version}"
24+
modImplementation "eu.pb4:polymer:${project.polymer_version}"
2425
}
2526

2627
processResources {

gradle.properties

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ org.gradle.jvmargs=-Xmx1G
33

44
# Fabric Properties
55
# check these on https://fabricmc.net/versions.html
6-
minecraft_version=1.18
7-
yarn_mappings=1.18+build.1
8-
loader_version=0.12.6
9-
polymer_version=0.2.0-beta.4+1.18-rc3
6+
minecraft_version=1.18.2
7+
yarn_mappings=1.18.2+build.3
8+
loader_version=0.14.4
9+
polymer_version=0.2.0-beta.40+1.18.2
10+
fabric_version=0.51.1+1.18.2
1011

1112
# Mod Properties
12-
mod_version = 0.0.1
13+
mod_version = 0.2.0
1314
maven_group = com.github.aws404
1415
archives_base_name = polypack-host

src/main/java/com/github/aws404/polypackhost/PolypackHostConfig.java

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,58 @@
22

33
import com.google.gson.Gson;
44
import com.google.gson.GsonBuilder;
5+
import com.google.gson.JsonElement;
6+
import com.google.gson.JsonObject;
7+
import com.mojang.serialization.Codec;
8+
import com.mojang.serialization.JsonOps;
9+
import com.mojang.serialization.codecs.RecordCodecBuilder;
510
import net.fabricmc.loader.api.FabricLoader;
611

712
import java.io.*;
8-
import java.nio.charset.StandardCharsets;
913

10-
public class PolypackHostConfig {
11-
public static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "polypack_host.json");
12-
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().serializeNulls().disableHtmlEscaping().create();
13-
14-
public String hostIp = null;
15-
public int hostPort = 8001;
16-
public int threadCount = 3;
17-
public boolean randomiseUrl = false;
14+
public record PolypackHostConfig(String ip, int hostPort, int threadCount, boolean randomiseUrl) {
1815

19-
public static PolypackHostConfig loadConfigFile(File file) {
20-
PolypackHostConfig config = null;
21-
22-
if (file.exists()) {
16+
private static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "polypack_host.json");
17+
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().serializeNulls().disableHtmlEscaping().create();
18+
private static final Codec<PolypackHostConfig> CODEC = RecordCodecBuilder.create(instance -> instance.group(
19+
Codec.STRING.fieldOf("external_ip").orElse("").forGetter(PolypackHostConfig::ip),
20+
Codec.INT.fieldOf("host_port").orElse(24464).forGetter(PolypackHostConfig::hostPort),
21+
Codec.INT.fieldOf("thread_count").orElse(1).forGetter(PolypackHostConfig::threadCount),
22+
Codec.BOOL.fieldOf("randomise_url").orElse(false).forGetter(PolypackHostConfig::randomiseUrl)
23+
).apply(instance, PolypackHostConfig::new));
24+
25+
public static PolypackHostConfig loadConfigFile() {
26+
JsonObject parsedFile = null;
27+
if (CONFIG_FILE.exists()) {
2328
try {
24-
BufferedReader fileReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
25-
config = GSON.fromJson(fileReader, PolypackHostConfig.class);
29+
FileReader reader = new FileReader(CONFIG_FILE);
30+
parsedFile = GSON.fromJson(reader, JsonObject.class);
31+
reader.close();
2632
} catch (IOException e) {
27-
PolypackHostMod.LOGGER.error("Failed to load config file. Ignoring and loading defaults.", e);
33+
PolypackHostMod.LOGGER.error("Failed to read configuration file! Resetting config to defaults.", e);
2834
}
35+
} else {
36+
PolypackHostMod.LOGGER.info("Configuration file not found! Creating new one...");
2937
}
30-
if (config == null) {
31-
config = new PolypackHostConfig();
38+
if (parsedFile == null) {
39+
parsedFile = new JsonObject();
3240
}
3341

34-
config.saveConfigFile(file);
42+
PolypackHostConfig config = CODEC.decode(JsonOps.INSTANCE, parsedFile).getOrThrow(false, s -> PolypackHostMod.LOGGER.error("Error deserializing configuration file. Error: {}", s)).getFirst();
43+
config.saveConfigFile();
3544
return config;
3645
}
3746

38-
public void saveConfigFile(File file) {
39-
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
40-
GSON.toJson(this, writer);
47+
public void saveConfigFile() {
48+
JsonElement jsonObject = CODEC.encodeStart(JsonOps.INSTANCE, this).getOrThrow(false, s -> PolypackHostMod.LOGGER.error("Error serializing configuration file. Error: {}", s));
49+
try {
50+
FileOutputStream stream = new FileOutputStream(CONFIG_FILE);
51+
Writer writer = new OutputStreamWriter(stream);
52+
GSON.toJson(jsonObject, writer);
53+
writer.close();
54+
stream.close();
4155
} catch (IOException e) {
42-
PolypackHostMod.LOGGER.error("Failed to save config file.", e);
56+
PolypackHostMod.LOGGER.error("Failed to save configuration file. Changes were not saved.", e);
4357
}
4458
}
4559
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package com.github.aws404.polypackhost;
22

33
import net.fabricmc.api.DedicatedServerModInitializer;
4+
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
45
import org.apache.logging.log4j.LogManager;
56
import org.apache.logging.log4j.Logger;
67

78
public class PolypackHostMod implements DedicatedServerModInitializer {
89
public static final Logger LOGGER = LogManager.getLogger("Polypack Host");
9-
public static final PolypackHostConfig CONFIG = PolypackHostConfig.loadConfigFile(PolypackHostConfig.CONFIG_FILE);
10+
public static final PolypackHostConfig CONFIG = PolypackHostConfig.loadConfigFile();
1011

1112
@Override
1213
public void onInitializeServer() {
13-
LOGGER.info("Starting Polypack Host Mod");
14+
ServerLifecycleEvents.SERVER_STARTED.register(PolypackHttpHandler::start);
15+
ServerLifecycleEvents.SERVER_STOPPING.register(server -> PolypackHttpHandler.stop());
16+
LOGGER.info("Polypack Host Mod Started!");
1417
}
1518
}

src/main/java/com/github/aws404/polypackhost/PolypackHttpHandler.java

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,77 @@
11
package com.github.aws404.polypackhost;
22

3-
import com.google.common.hash.Hashing;
3+
import com.google.common.util.concurrent.ThreadFactoryBuilder;
44
import com.sun.net.httpserver.HttpExchange;
55
import com.sun.net.httpserver.HttpHandler;
66
import com.sun.net.httpserver.HttpServer;
77
import eu.pb4.polymer.api.resourcepack.PolymerRPUtils;
88
import net.fabricmc.loader.api.FabricLoader;
99
import net.minecraft.server.MinecraftServer;
1010

11-
import java.io.File;
12-
import java.io.FileInputStream;
13-
import java.io.IOException;
14-
import java.io.OutputStream;
11+
import java.io.*;
12+
import java.math.BigInteger;
1513
import java.net.InetAddress;
1614
import java.net.InetSocketAddress;
1715
import java.nio.file.Path;
16+
import java.security.MessageDigest;
1817
import java.util.Objects;
1918
import java.util.Random;
19+
import java.util.concurrent.CompletableFuture;
20+
import java.util.concurrent.ExecutorService;
2021
import java.util.concurrent.Executors;
2122

2223
public class PolypackHttpHandler implements HttpHandler {
2324

2425
private static final Path POLYMER_PACK_FILE = Path.of(FabricLoader.getInstance().getGameDir().toFile() + "/polymer-resourcepack.zip");
2526

27+
private static HttpServer server = null;
28+
private static ExecutorService threadPool = null;
29+
30+
public static void stop() {
31+
if (PolypackHttpHandler.server != null) {
32+
PolypackHttpHandler.server.stop(0);
33+
}
34+
if (PolypackHttpHandler.threadPool != null) {
35+
PolypackHttpHandler.threadPool.shutdownNow();
36+
}
37+
}
38+
2639
public static void start(MinecraftServer minecraftServer) {
27-
try {
28-
String serverIp = PolypackHostMod.CONFIG.hostIp == null || PolypackHostMod.CONFIG.hostIp.isEmpty() ? minecraftServer.getServerIp() : PolypackHostMod.CONFIG.hostIp;
29-
if (serverIp.isEmpty()) {
30-
serverIp = InetAddress.getLocalHost().getHostAddress();
31-
}
32-
PolypackHostMod.LOGGER.info("Building polymer resource pack...");
33-
PolymerRPUtils.build(POLYMER_PACK_FILE);
40+
PolypackHttpHandler.threadPool = Executors.newFixedThreadPool(PolypackHostMod.CONFIG.threadCount(), new ThreadFactoryBuilder().setNameFormat("Polypack-Host-%d").build());
3441

35-
String subUrl = PolypackHostMod.CONFIG.randomiseUrl ? Integer.toString(new Random().nextInt(Integer.MAX_VALUE)) : "pack";
42+
CompletableFuture.runAsync(() -> {
43+
try {
44+
PolypackHostMod.LOGGER.info("Starting Polymer resource pack server...");
45+
PolymerRPUtils.build(POLYMER_PACK_FILE);
3646

37-
HttpServer server = HttpServer.create(new InetSocketAddress(serverIp, PolypackHostMod.CONFIG.hostPort), 0);
38-
server.createContext("/" + subUrl, new PolypackHttpHandler());
39-
server.setExecutor(Executors.newFixedThreadPool(PolypackHostMod.CONFIG.threadCount));
40-
server.start();
47+
String serverIp = PolypackHostMod.CONFIG.ip().isEmpty() ? minecraftServer.getServerIp() : PolypackHostMod.CONFIG.ip();
48+
if (serverIp.isEmpty()) {
49+
PolypackHostMod.LOGGER.warn("No external IP address is defined in the configuration, this may cause issues outside of the local network.");
50+
serverIp = InetAddress.getLocalHost().getHostAddress();
51+
}
4152

42-
String packIp = String.format("http://%s:%s/%s", serverIp, PolypackHostMod.CONFIG.hostPort, subUrl);
53+
String subUrl = PolypackHostMod.CONFIG.randomiseUrl() ? Integer.toString(new Random().nextInt(Integer.MAX_VALUE)) : "pack";
4354

44-
PolypackHostMod.LOGGER.info("Polymer resource pack host started at {}", packIp);
55+
PolypackHttpHandler.server = HttpServer.create(new InetSocketAddress("0.0.0.0", PolypackHostMod.CONFIG.hostPort()), 0);
56+
PolypackHttpHandler.server.createContext("/" + subUrl, new PolypackHttpHandler());
57+
PolypackHttpHandler.server.setExecutor(PolypackHttpHandler.threadPool);
58+
PolypackHttpHandler.server.start();
59+
60+
String packIp = String.format("http://%s:%s/%s", serverIp, PolypackHostMod.CONFIG.hostPort(), subUrl);
61+
62+
String hash = String.format("%040x", new BigInteger(1, MessageDigest
63+
.getInstance("SHA-1")
64+
.digest(new FileInputStream(POLYMER_PACK_FILE.toString()).readAllBytes()))
65+
);
66+
67+
minecraftServer.setResourcePack(packIp, hash);
68+
69+
PolypackHostMod.LOGGER.info("Polymer resource pack host started at {} (Hash: {})", packIp, hash);
70+
} catch (Exception e) {
71+
PolypackHostMod.LOGGER.error("Failed to start the resource pack server!", e);
72+
}
73+
}, PolypackHttpHandler.threadPool);
4574

46-
String hash = com.google.common.io.Files.asByteSource(PolypackHttpHandler.POLYMER_PACK_FILE.toFile()).hash(Hashing.sha1()).toString();
47-
minecraftServer.setResourcePack(packIp, hash);
48-
} catch (IOException e) {
49-
PolypackHostMod.LOGGER.error("Failed to start the resource pack server!", e);
50-
e.printStackTrace();
51-
}
5275
}
5376

5477
@Override
@@ -67,10 +90,9 @@ public void handle(HttpExchange exchange) throws IOException {
6790
exchange.sendResponseHeaders(200, pack.length());
6891

6992
FileInputStream fis = new FileInputStream(pack);
70-
int b;
71-
while ((b = fis.read()) != -1) {
72-
outputStream.write(b);
73-
}
93+
BufferedInputStream bis = new BufferedInputStream(fis);
94+
bis.transferTo(outputStream);
95+
bis.close();
7496
fis.close();
7597

7698
outputStream.flush();

src/main/java/com/github/aws404/polypackhost/mixin/MinecraftServerMixin.java

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/main/resources/fabric.mod.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@
2020
"com.github.aws404.polypackhost.PolypackHostMod"
2121
]
2222
},
23-
"mixins": [
24-
"polypack_host.mixins.json"
25-
],
2623

2724
"depends": {
2825
"fabricloader": ">=0.11.3",
2926
"minecraft": "1.18.x",
3027
"polymer": "*",
28+
"fabric-lifecycle-events-v1": "*",
3129
"java": ">=17"
3230
}
3331
}

src/main/resources/polypack_host.mixins.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)