forked from GeyserMC/Geyser
send resource packs
A lot of this code is nukkit-credits in the classes
This commit is contained in:
parent
bb601daf26
commit
e36285f20c
10 changed files with 324 additions and 9 deletions
|
@ -42,6 +42,7 @@ import org.geysermc.connector.network.remote.RemoteServer;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.Translators;
|
import org.geysermc.connector.network.translators.Translators;
|
||||||
import org.geysermc.connector.thread.PingPassthroughThread;
|
import org.geysermc.connector.thread.PingPassthroughThread;
|
||||||
|
import org.geysermc.connector.utils.ResourcePack;
|
||||||
import org.geysermc.connector.utils.Toolbox;
|
import org.geysermc.connector.utils.Toolbox;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
import org.geysermc.common.IGeyserConfiguration;
|
||||||
|
|
||||||
|
@ -60,6 +61,8 @@ public class GeyserConnector {
|
||||||
|
|
||||||
public static final String NAME = "Geyser";
|
public static final String NAME = "Geyser";
|
||||||
public static final String VERSION = "1.0-SNAPSHOT";
|
public static final String VERSION = "1.0-SNAPSHOT";
|
||||||
|
//Change this on every game version
|
||||||
|
public static final String GAME_VERSION = "1.14.0";
|
||||||
|
|
||||||
private final Map<Object, GeyserSession> players = new HashMap<>();
|
private final Map<Object, GeyserSession> players = new HashMap<>();
|
||||||
|
|
||||||
|
@ -103,8 +106,9 @@ public class GeyserConnector {
|
||||||
|
|
||||||
logger.setDebug(config.isDebugMode());
|
logger.setDebug(config.isDebugMode());
|
||||||
|
|
||||||
Toolbox.init();
|
|
||||||
Translators.start();
|
Translators.start();
|
||||||
|
Toolbox.init();
|
||||||
|
ResourcePack.loadPacks();
|
||||||
|
|
||||||
commandMap = new GeyserCommandMap(this);
|
commandMap = new GeyserCommandMap(this);
|
||||||
remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort());
|
remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort());
|
||||||
|
|
|
@ -31,7 +31,11 @@ import org.geysermc.common.IGeyserConfiguration;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.Registry;
|
import org.geysermc.connector.network.translators.Registry;
|
||||||
import org.geysermc.connector.utils.LoginEncryptionUtils;
|
import org.geysermc.connector.utils.*;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
|
|
||||||
|
@ -57,24 +61,55 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
session.getUpstream().sendPacket(playStatus);
|
session.getUpstream().sendPacket(playStatus);
|
||||||
|
|
||||||
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
|
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
|
||||||
|
for(ResourcePack resourcePack : ResourcePack.PACKS.values()) {
|
||||||
|
ResourcePackManifest.Header header = resourcePack.getManifest().getHeader();
|
||||||
|
String version = header.getVersion()[0] + "." + header.getVersion()[1] + "." + header.getVersion()[2];
|
||||||
|
resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry(header.getUuid().toString(), version, resourcePack.getFile().length(), "", "", "", false));
|
||||||
|
}
|
||||||
|
resourcePacksInfo.setForcedToAccept(true);
|
||||||
session.getUpstream().sendPacket(resourcePacksInfo);
|
session.getUpstream().sendPacket(resourcePacksInfo);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(ResourcePackClientResponsePacket packet) {
|
public boolean handle(ResourcePackClientResponsePacket packet) {
|
||||||
|
System.out.println(packet.getStatus());
|
||||||
switch (packet.getStatus()) {
|
switch (packet.getStatus()) {
|
||||||
case COMPLETED:
|
case COMPLETED:
|
||||||
session.connect(connector.getRemoteServer());
|
session.connect(connector.getRemoteServer());
|
||||||
connector.getLogger().info("Player connected with username " + session.getAuthData().getName());
|
connector.getLogger().info("Player connected with username " + session.getAuthData().getName());
|
||||||
break;
|
break;
|
||||||
case HAVE_ALL_PACKS:
|
|
||||||
ResourcePackStackPacket stack = new ResourcePackStackPacket();
|
case SEND_PACKS:
|
||||||
stack.setExperimental(false);
|
for(String id : packet.getPackIds()) {
|
||||||
stack.setForcedToAccept(false);
|
ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket();
|
||||||
stack.setGameVersion("*");
|
ResourcePack pack = ResourcePack.PACKS.get(id.split("_")[0]);
|
||||||
session.getUpstream().sendPacket(stack);
|
ResourcePackManifest.Header header = pack.getManifest().getHeader();
|
||||||
|
|
||||||
|
data.setPackId(header.getUuid());
|
||||||
|
data.setChunkCount(pack.getFile().length()/ResourcePack.CHUNK_SIZE);
|
||||||
|
data.setCompressedPackSize(pack.getFile().length());
|
||||||
|
data.setMaxChunkSize(ResourcePack.CHUNK_SIZE);
|
||||||
|
data.setHash(pack.getSha256());
|
||||||
|
|
||||||
|
session.getUpstream().sendPacket(data);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HAVE_ALL_PACKS:
|
||||||
|
ResourcePackStackPacket stackPacket = new ResourcePackStackPacket();
|
||||||
|
|
||||||
|
stackPacket.setExperimental(false);
|
||||||
|
stackPacket.setForcedToAccept(true);
|
||||||
|
stackPacket.setGameVersion(GeyserConnector.GAME_VERSION);
|
||||||
|
for(ResourcePack pack : ResourcePack.PACKS.values()) {
|
||||||
|
ResourcePackManifest.Header header = pack.getManifest().getHeader();
|
||||||
|
String version = header.getVersion()[0] + "." + header.getVersion()[1] + "." + header.getVersion()[2];
|
||||||
|
stackPacket.getResourcePacks().add(new ResourcePackStackPacket.Entry(header.getUuid().toString(), version, ""));
|
||||||
|
}
|
||||||
|
session.getUpstream().sendPacket(stackPacket);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
session.getUpstream().disconnect("disconnectionScreen.resourcePack");
|
session.getUpstream().disconnect("disconnectionScreen.resourcePack");
|
||||||
break;
|
break;
|
||||||
|
@ -126,4 +161,28 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
boolean defaultHandler(BedrockPacket packet) {
|
boolean defaultHandler(BedrockPacket packet) {
|
||||||
return translateAndDefault(packet);
|
return translateAndDefault(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(ResourcePackChunkRequestPacket packet) {
|
||||||
|
ResourcePackChunkDataPacket data = new ResourcePackChunkDataPacket();
|
||||||
|
ResourcePack pack = ResourcePack.PACKS.get(data.getPackId().toString());
|
||||||
|
|
||||||
|
data.setChunkIndex(packet.getChunkIndex());
|
||||||
|
data.setProgress(packet.getChunkIndex()*ResourcePack.CHUNK_SIZE);
|
||||||
|
data.setPackVersion(packet.getPackVersion());
|
||||||
|
data.setPackId(packet.getPackId());
|
||||||
|
byte[] packData = new byte[(int) MathUtils.constrain(pack.getFile().length(), 0, ResourcePack.CHUNK_SIZE)];
|
||||||
|
|
||||||
|
try (InputStream inputStream = new FileInputStream(pack.getFile())) {
|
||||||
|
int offset = packet.getChunkIndex()*ResourcePack.CHUNK_SIZE;
|
||||||
|
|
||||||
|
inputStream.read(packData, offset, packData.length);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
data.setData(packData);
|
||||||
|
|
||||||
|
session.getUpstream().sendPacket(data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,6 +400,6 @@ public class GeyserSession implements CommandSender {
|
||||||
startGamePacket.setItemEntries(Toolbox.ITEMS);
|
startGamePacket.setItemEntries(Toolbox.ITEMS);
|
||||||
startGamePacket.setVanillaVersion("*");
|
startGamePacket.setVanillaVersion("*");
|
||||||
// startGamePacket.setMovementServerAuthoritative(true);
|
// startGamePacket.setMovementServerAuthoritative(true);
|
||||||
upstream.sendPacket(startGamePacket);
|
upstream.sendPacketImmediately(startGamePacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,10 @@ import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
//import org.geysermc.connector.network.translators.forge.Blocks;
|
||||||
import org.geysermc.connector.utils.Toolbox;
|
import org.geysermc.connector.utils.Toolbox;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ public class BlockTranslator {
|
||||||
ListTag<CompoundTag> blocksTag;
|
ListTag<CompoundTag> blocksTag;
|
||||||
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) {
|
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) {
|
||||||
blocksTag = (ListTag<CompoundTag>) nbtInputStream.readTag();
|
blocksTag = (ListTag<CompoundTag>) nbtInputStream.readTag();
|
||||||
|
//Blocks.registerBlocks(new File("mods"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to get blocks from runtime block states", e);
|
throw new AssertionError("Unable to get blocks from runtime block states", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*package org.geysermc.connector.network.translators.forge;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public class Blocks {
|
||||||
|
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().enable(JsonParser.Feature.ALLOW_COMMENTS);
|
||||||
|
|
||||||
|
public static void registerBlocks(File directory) throws Exception {
|
||||||
|
for(File file : directory.listFiles()) {
|
||||||
|
ZipFile zip = new ZipFile(file);
|
||||||
|
|
||||||
|
zip.stream().forEach((x) -> {
|
||||||
|
if(x.getName().contains("blockstates") && x.getName().endsWith(".json")) {
|
||||||
|
try {
|
||||||
|
System.out.println(x.getName());
|
||||||
|
InputStream stream = zip.getInputStream(x);
|
||||||
|
|
||||||
|
TypeReference<Map<String, JsonNode>> type = new TypeReference<Map<String, JsonNode>>() {};
|
||||||
|
|
||||||
|
registerBlock(JSON_MAPPER.readValue(stream, type));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerBlock(Map<String, JsonNode> map) {
|
||||||
|
System.out.println(map);
|
||||||
|
}
|
||||||
|
}*/
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
package org.geysermc.connector.utils;
|
package org.geysermc.connector.utils;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
|
|
||||||
|
@ -40,6 +42,11 @@ public class FileUtils {
|
||||||
return objectMapper.readValue(src, valueType);
|
return objectMapper.readValue(src, valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T loadJson(InputStream src, Class<T> valueType) throws IOException {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()).enable(JsonParser.Feature.IGNORE_UNDEFINED).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||||
|
return objectMapper.readValue(src, valueType);
|
||||||
|
}
|
||||||
|
|
||||||
public static File fileOrCopiedFromResource(String name, Function<String, String> s) throws IOException {
|
public static File fileOrCopiedFromResource(String name, Function<String, String> s) throws IOException {
|
||||||
return fileOrCopiedFromResource(new File(name), name, s);
|
return fileOrCopiedFromResource(new File(name), name, s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,4 +31,15 @@ public class MathUtils {
|
||||||
int truncated = (int) floatNumber;
|
int truncated = (int) floatNumber;
|
||||||
return floatNumber > truncated ? truncated + 1 : truncated;
|
return floatNumber > truncated ? truncated + 1 : truncated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double constrain(double num, double min, double max) {
|
||||||
|
if(num > max) {
|
||||||
|
num = max;
|
||||||
|
}
|
||||||
|
if(num < min) {
|
||||||
|
num = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
package org.geysermc.connector.utils;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.voxelwind.server.jni.hash.JavaHash;
|
||||||
|
import com.voxelwind.server.jni.hash.NativeHash;
|
||||||
|
import com.voxelwind.server.jni.hash.VoxelwindHash;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
|
import net.md_5.bungee.jni.NativeCode;
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.floodgate.util.EncryptionUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public class ResourcePack {
|
||||||
|
public static final Map<String, ResourcePack> PACKS = new HashMap<>();
|
||||||
|
public static final NativeCode<VoxelwindHash> HASH = new NativeCode<>("native-hash", JavaHash.class, NativeHash.class);
|
||||||
|
public static final int CHUNK_SIZE = 1048576;
|
||||||
|
|
||||||
|
private boolean hashed;
|
||||||
|
private byte[] sha256;
|
||||||
|
private File file;
|
||||||
|
private ResourcePackManifest manifest;
|
||||||
|
private ResourcePackManifest.Version version;
|
||||||
|
|
||||||
|
public static void loadPacks() {
|
||||||
|
File directory = new File("packs");
|
||||||
|
|
||||||
|
for(File file : directory.listFiles()) {
|
||||||
|
try {
|
||||||
|
ZipFile zip = new ZipFile(file);
|
||||||
|
|
||||||
|
zip.stream().forEach((x) -> {
|
||||||
|
if(x.getName().contains("manifest.json")) {
|
||||||
|
try {
|
||||||
|
ResourcePackManifest manifest = FileUtils.loadJson(zip.getInputStream(x), ResourcePackManifest.class);
|
||||||
|
|
||||||
|
ResourcePack pack = new ResourcePack();
|
||||||
|
|
||||||
|
pack.file = file;
|
||||||
|
pack.manifest = manifest;
|
||||||
|
pack.version = ResourcePackManifest.Version.fromArray(manifest.getHeader().getVersion());
|
||||||
|
|
||||||
|
PACKS.put(pack.getManifest().getHeader().getUuid().toString(), pack);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
GeyserConnector.getInstance().getLogger().error(file.getName() + " " + "is broken!");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* author: NukkitX
|
||||||
|
* Nukkit Project
|
||||||
|
*/
|
||||||
|
//TODO: calculate this separately
|
||||||
|
public byte[] getSha256() {
|
||||||
|
if (!hashed) {
|
||||||
|
VoxelwindHash hash = HASH.newInstance();
|
||||||
|
ByteBuf bytes = null;
|
||||||
|
try {
|
||||||
|
bytes = PooledByteBufAllocator.DEFAULT.directBuffer(Math.toIntExact(Files.size(file.toPath()))); // Hopefully there is not a resource pack big enough to need a long...
|
||||||
|
bytes.writeBytes(Files.readAllBytes(file.toPath()));
|
||||||
|
hash.update(bytes);
|
||||||
|
sha256 = hash.digest();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Could not calculate pack hash", e);
|
||||||
|
} finally {
|
||||||
|
if (bytes != null) {
|
||||||
|
bytes.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sha256;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourcePackManifest getManifest() {
|
||||||
|
return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourcePackManifest.Version getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package org.geysermc.connector.utils;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* author: NukkitX
|
||||||
|
* Nukkit Project
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class ResourcePackManifest {
|
||||||
|
@JsonProperty("format_version")
|
||||||
|
private Integer formatVersion;
|
||||||
|
private Header header;
|
||||||
|
private Collection<Module> modules;
|
||||||
|
protected Collection<Dependency> dependencies;
|
||||||
|
|
||||||
|
public Collection<Module> getModules() {
|
||||||
|
return Collections.unmodifiableCollection(modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public static class Header {
|
||||||
|
private String description;
|
||||||
|
private String name;
|
||||||
|
private UUID uuid;
|
||||||
|
private int[] version;
|
||||||
|
@JsonProperty("min_engine_version")
|
||||||
|
private int[] minimumSupportedMinecraftVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public static class Module {
|
||||||
|
private String description;
|
||||||
|
private String name;
|
||||||
|
private UUID uuid;
|
||||||
|
private int[] version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public static class Dependency {
|
||||||
|
private UUID uuid;
|
||||||
|
private int[] version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public static class Version {
|
||||||
|
private final int major;
|
||||||
|
private final int minor;
|
||||||
|
private final int patch;
|
||||||
|
|
||||||
|
public static Version fromString(String ver) {
|
||||||
|
String[] split = ver.replace(']', ' ')
|
||||||
|
.replace('[', ' ')
|
||||||
|
.replaceAll(" ", "").split(",");
|
||||||
|
|
||||||
|
return new Version(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Version fromArray(int[] ver) {
|
||||||
|
return new Version(ver[0], ver[1], ver[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Version(int major, int minor, int patch) {
|
||||||
|
this.major = major;
|
||||||
|
this.minor = minor;
|
||||||
|
this.patch = patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return major + "." + minor + "." + patch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ public class Toolbox {
|
||||||
biomesTag = (CompoundTag) biomenbtInputStream.readTag();
|
biomesTag = (CompoundTag) biomenbtInputStream.readTag();
|
||||||
BIOMES = biomesTag;
|
BIOMES = biomesTag;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?");
|
GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?");
|
||||||
throw new AssertionError(ex);
|
throw new AssertionError(ex);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue