mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-01-24 09:16:05 +01:00
Allow for implementations to provide a custom resource loader
This will allow Geyser-Fabric to work without resource loading issues. This commit also ensures try-with-resources is used anywhere a resource is accessed.
This commit is contained in:
parent
9084c59003
commit
763743a845
22 changed files with 220 additions and 211 deletions
|
@ -63,17 +63,21 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
if (!getDataFolder().exists())
|
if (!getDataFolder().exists())
|
||||||
getDataFolder().mkdir();
|
getDataFolder().mkdir();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!getDataFolder().exists())
|
if (!getDataFolder().exists())
|
||||||
getDataFolder().mkdir();
|
getDataFolder().mkdir();
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"),
|
||||||
|
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
getLogger().log(Level.WARNING, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getProxy().getConfig().getListeners().size() == 1) {
|
if (getProxy().getConfig().getListeners().size() == 1) {
|
||||||
|
|
|
@ -79,16 +79,21 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
// This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
|
// This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
|
||||||
try {
|
try {
|
||||||
if (!getDataFolder().exists()) {
|
if (!getDataFolder().exists()) {
|
||||||
getDataFolder().mkdir();
|
getDataFolder().mkdir();
|
||||||
}
|
}
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml",
|
||||||
|
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
getLogger().log(Level.WARNING, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -71,15 +71,19 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
if (!configDir.exists())
|
if (!configDir.exists())
|
||||||
configDir.mkdirs();
|
configDir.mkdirs();
|
||||||
|
|
||||||
File configFile = null;
|
File configFile;
|
||||||
try {
|
try {
|
||||||
configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml",
|
||||||
|
(file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.warn(GeyserLocale.getLocaleStringLog("geyser.config.failed"));
|
logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"));
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -90,6 +90,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
boolean useGuiOpts = bootstrap.useGui;
|
boolean useGuiOpts = bootstrap.useGui;
|
||||||
String configFilenameOpt = bootstrap.configFilename;
|
String configFilenameOpt = bootstrap.configFilename;
|
||||||
|
|
||||||
|
GeyserLocale.init(bootstrap);
|
||||||
|
|
||||||
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||||
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
@ -188,7 +190,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
LoopbackUtil.checkLoopback(geyserLogger);
|
LoopbackUtil.checkLoopback(geyserLogger);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml",
|
||||||
|
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
|
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
|
||||||
|
|
||||||
handleArgsConfigOptions();
|
handleArgsConfigOptions();
|
||||||
|
|
|
@ -83,16 +83,19 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!configFolder.toFile().exists())
|
if (!configFolder.toFile().exists())
|
||||||
//noinspection ResultOfMethodCallIgnored
|
//noinspection ResultOfMethodCallIgnored
|
||||||
configFolder.toFile().mkdirs();
|
configFolder.toFile().mkdirs();
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(configFolder.resolve("config.yml").toFile(),
|
File configFile = FileUtils.fileOrCopiedFromResource(configFolder.resolve("config.yml").toFile(),
|
||||||
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.warn(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InetSocketAddress javaAddr = proxyServer.getBoundAddress();
|
InetSocketAddress javaAddr = proxyServer.getBoundAddress();
|
||||||
|
|
|
@ -25,16 +25,16 @@
|
||||||
|
|
||||||
package org.geysermc.geyser;
|
package org.geysermc.geyser;
|
||||||
|
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
|
||||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
|
||||||
import org.geysermc.geyser.GeyserLogger;
|
|
||||||
import org.geysermc.geyser.command.CommandManager;
|
import org.geysermc.geyser.command.CommandManager;
|
||||||
|
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
import org.geysermc.geyser.level.GeyserWorldManager;
|
||||||
import org.geysermc.geyser.level.WorldManager;
|
import org.geysermc.geyser.level.WorldManager;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
@ -126,4 +126,29 @@ public interface GeyserBootstrap {
|
||||||
default Path getLogsPath() {
|
default Path getLogsPath() {
|
||||||
return Paths.get("logs/latest.log");
|
return Paths.get("logs/latest.log");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an InputStream for the given resource path.
|
||||||
|
* Overridden on platforms that have different class loader properties.
|
||||||
|
*
|
||||||
|
* @param resource Resource to get
|
||||||
|
* @return InputStream of the given resource, or null if not found
|
||||||
|
*/
|
||||||
|
default @Nullable InputStream getResourceOrNull(String resource) {
|
||||||
|
return GeyserBootstrap.class.getClassLoader().getResourceAsStream(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an InputStream for the given resource path, throws AssertionError if resource is not found.
|
||||||
|
*
|
||||||
|
* @param resource Resource to get
|
||||||
|
* @return InputStream of the given resource
|
||||||
|
*/
|
||||||
|
default @Nonnull InputStream getResource(String resource) {
|
||||||
|
InputStream stream = getResourceOrNull(resource);
|
||||||
|
if (stream == null) {
|
||||||
|
throw new AssertionError("Unable to find resource: " + resource);
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ import org.geysermc.geyser.util.*;
|
||||||
|
|
||||||
import javax.naming.directory.Attribute;
|
import javax.naming.directory.Attribute;
|
||||||
import javax.naming.directory.InitialDirContext;
|
import javax.naming.directory.InitialDirContext;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
@ -139,6 +140,8 @@ public class GeyserImpl implements GeyserApi {
|
||||||
|
|
||||||
this.platformType = platformType;
|
this.platformType = platformType;
|
||||||
|
|
||||||
|
GeyserLocale.finalizeDefaultLocale(this);
|
||||||
|
|
||||||
logger.info("******************************************");
|
logger.info("******************************************");
|
||||||
logger.info("");
|
logger.info("");
|
||||||
logger.info(GeyserLocale.getLocaleStringLog("geyser.core.load", NAME, VERSION));
|
logger.info(GeyserLocale.getLocaleStringLog("geyser.core.load", NAME, VERSION));
|
||||||
|
@ -214,9 +217,9 @@ public class GeyserImpl implements GeyserApi {
|
||||||
String branch = "unknown";
|
String branch = "unknown";
|
||||||
int buildNumber = -1;
|
int buildNumber = -1;
|
||||||
if (this.productionEnvironment()) {
|
if (this.productionEnvironment()) {
|
||||||
try {
|
try (InputStream stream = bootstrap.getResource("git.properties")) {
|
||||||
Properties gitProperties = new Properties();
|
Properties gitProperties = new Properties();
|
||||||
gitProperties.load(FileUtils.getResource("git.properties"));
|
gitProperties.load(stream);
|
||||||
branch = gitProperties.getProperty("git.branch");
|
branch = gitProperties.getProperty("git.branch");
|
||||||
String build = gitProperties.getProperty("git.build.number");
|
String build = gitProperties.getProperty("git.build.number");
|
||||||
if (build != null) {
|
if (build != null) {
|
||||||
|
|
|
@ -30,14 +30,14 @@ import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.command.CommandSender;
|
import org.geysermc.geyser.command.CommandSender;
|
||||||
import org.geysermc.geyser.command.GeyserCommand;
|
import org.geysermc.geyser.command.GeyserCommand;
|
||||||
import org.geysermc.geyser.text.ChatColor;
|
|
||||||
import org.geysermc.geyser.network.MinecraftProtocol;
|
import org.geysermc.geyser.network.MinecraftProtocol;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
import org.geysermc.geyser.util.WebUtils;
|
import org.geysermc.geyser.util.WebUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -69,9 +69,9 @@ public class VersionCommand extends GeyserCommand {
|
||||||
// Disable update checking in dev mode and for players in Geyser Standalone
|
// Disable update checking in dev mode and for players in Geyser Standalone
|
||||||
if (GeyserImpl.getInstance().productionEnvironment() && !(!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) {
|
if (GeyserImpl.getInstance().productionEnvironment() && !(!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) {
|
||||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.getLocale()));
|
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.getLocale()));
|
||||||
try {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("git.properties")) {
|
||||||
Properties gitProp = new Properties();
|
Properties gitProp = new Properties();
|
||||||
gitProp.load(FileUtils.getResource("git.properties"));
|
gitProp.load(stream);
|
||||||
|
|
||||||
String buildXML = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" +
|
String buildXML = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" +
|
||||||
URLEncoder.encode(gitProp.getProperty("git.branch"), StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber");
|
URLEncoder.encode(gitProp.getProperty("git.branch"), StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber");
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.geysermc.floodgate.util.FloodgateInfoHolder;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.lang.management.ManagementFactory;
|
import java.lang.management.ManagementFactory;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
@ -78,9 +79,9 @@ public class DumpInfo {
|
||||||
public DumpInfo(boolean addLog) {
|
public DumpInfo(boolean addLog) {
|
||||||
this.versionInfo = new VersionInfo();
|
this.versionInfo = new VersionInfo();
|
||||||
|
|
||||||
try {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("git.properties")) {
|
||||||
this.gitInfo = new Properties();
|
this.gitInfo = new Properties();
|
||||||
this.gitInfo.load(FileUtils.getResource("git.properties"));
|
this.gitInfo.load(stream);
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
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.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -45,10 +44,10 @@ public class BiomeIdentifierRegistryLoader implements RegistryLoader<String, Obj
|
||||||
// The server sends the corresponding Java network IDs, so we don't need to worry about that now.
|
// The server sends the corresponding Java network IDs, so we don't need to worry about that now.
|
||||||
|
|
||||||
// Reference variable for Jackson to read off of
|
// Reference variable for Jackson to read off of
|
||||||
TypeReference<Map<String, BiomeEntry>> biomeEntriesType = new TypeReference<Map<String, BiomeEntry>>() { };
|
TypeReference<Map<String, BiomeEntry>> biomeEntriesType = new TypeReference<>() { };
|
||||||
Map<String, BiomeEntry> biomeEntries;
|
Map<String, BiomeEntry> biomeEntries;
|
||||||
|
|
||||||
try (InputStream stream = FileUtils.getResource("mappings/biomes.json")) {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("mappings/biomes.json")) {
|
||||||
biomeEntries = GeyserImpl.JSON_MAPPER.readValue(stream, biomeEntriesType);
|
biomeEntries = GeyserImpl.JSON_MAPPER.readValue(stream, biomeEntriesType);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new AssertionError("Unable to load Bedrock runtime biomes", e);
|
throw new AssertionError("Unable to load Bedrock runtime biomes", e);
|
||||||
|
|
|
@ -65,10 +65,8 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load collision mappings file
|
// Load collision mappings file
|
||||||
InputStream stream = FileUtils.getResource(input.value());
|
|
||||||
|
|
||||||
List<BoundingBox[]> collisionList;
|
List<BoundingBox[]> collisionList;
|
||||||
try {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource(input.value())) {
|
||||||
ArrayNode collisionNode = (ArrayNode) GeyserImpl.JSON_MAPPER.readTree(stream);
|
ArrayNode collisionNode = (ArrayNode) GeyserImpl.JSON_MAPPER.readTree(stream);
|
||||||
collisionList = loadBoundingBoxes(collisionNode);
|
collisionList = loadBoundingBoxes(collisionNode);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.registry.loader;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -43,10 +42,9 @@ public abstract class EffectRegistryLoader<T> implements RegistryLoader<String,
|
||||||
|
|
||||||
public void loadFile(String input) {
|
public void loadFile(String input) {
|
||||||
if (!loadedFiles.containsKey(input)) {
|
if (!loadedFiles.containsKey(input)) {
|
||||||
InputStream effectsStream = FileUtils.getResource(input);
|
|
||||||
JsonNode effects;
|
JsonNode effects;
|
||||||
try {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource(input)) {
|
||||||
effects = GeyserImpl.JSON_MAPPER.readTree(effectsStream);
|
effects = GeyserImpl.JSON_MAPPER.readTree(stream);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load registrations for " + input, e);
|
throw new AssertionError("Unable to load registrations for " + input, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,11 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.network.MinecraftProtocol;
|
|
||||||
import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment;
|
import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment;
|
||||||
|
import org.geysermc.geyser.network.MinecraftProtocol;
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.registry.type.EnchantmentData;
|
import org.geysermc.geyser.registry.type.EnchantmentData;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
@ -45,9 +44,8 @@ import java.util.Map;
|
||||||
public class EnchantmentRegistryLoader implements RegistryLoader<String, Map<JavaEnchantment, EnchantmentData>> {
|
public class EnchantmentRegistryLoader implements RegistryLoader<String, Map<JavaEnchantment, EnchantmentData>> {
|
||||||
@Override
|
@Override
|
||||||
public Map<JavaEnchantment, EnchantmentData> load(String input) {
|
public Map<JavaEnchantment, EnchantmentData> load(String input) {
|
||||||
InputStream enchantmentsStream = FileUtils.getResource(input);
|
|
||||||
JsonNode enchantmentsNode;
|
JsonNode enchantmentsNode;
|
||||||
try {
|
try (InputStream enchantmentsStream = GeyserImpl.getInstance().getBootstrap().getResource(input)) {
|
||||||
enchantmentsNode = GeyserImpl.JSON_MAPPER.readTree(enchantmentsStream);
|
enchantmentsNode = GeyserImpl.JSON_MAPPER.readTree(enchantmentsStream);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load enchantment data", e);
|
throw new AssertionError("Unable to load enchantment data", e);
|
||||||
|
|
|
@ -28,9 +28,7 @@ package org.geysermc.geyser.registry.loader;
|
||||||
import com.nukkitx.nbt.NBTInputStream;
|
import com.nukkitx.nbt.NBTInputStream;
|
||||||
import com.nukkitx.nbt.NbtMap;
|
import com.nukkitx.nbt.NbtMap;
|
||||||
import com.nukkitx.nbt.NbtUtils;
|
import com.nukkitx.nbt.NbtUtils;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads NBT data from the given resource path.
|
* Loads NBT data from the given resource path.
|
||||||
|
@ -39,8 +37,8 @@ public class NbtRegistryLoader implements RegistryLoader<String, NbtMap> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NbtMap load(String input) {
|
public NbtMap load(String input) {
|
||||||
InputStream stream = FileUtils.getResource(input);
|
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(GeyserImpl.getInstance().getBootstrap().getResource(input),
|
||||||
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream, true, true)) {
|
true, true)) {
|
||||||
return (NbtMap) nbtInputStream.readTag();
|
return (NbtMap) nbtInputStream.readTag();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Failed to load registrations for " + input, e);
|
throw new AssertionError("Failed to load registrations for " + input, e);
|
||||||
|
|
|
@ -28,7 +28,6 @@ package org.geysermc.geyser.registry.loader;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.registry.type.SoundMapping;
|
import org.geysermc.geyser.registry.type.SoundMapping;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -43,9 +42,8 @@ public class SoundRegistryLoader implements RegistryLoader<String, Map<String, S
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, SoundMapping> load(String input) {
|
public Map<String, SoundMapping> load(String input) {
|
||||||
InputStream stream = FileUtils.getResource(input);
|
|
||||||
JsonNode soundsTree;
|
JsonNode soundsTree;
|
||||||
try {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource(input)) {
|
||||||
soundsTree = GeyserImpl.JSON_MAPPER.readTree(stream);
|
soundsTree = GeyserImpl.JSON_MAPPER.readTree(stream);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new AssertionError("Unable to load sound mappings", e);
|
throw new AssertionError("Unable to load sound mappings", e);
|
||||||
|
|
|
@ -43,7 +43,6 @@ import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||||
import org.geysermc.geyser.registry.type.BlockMappings;
|
import org.geysermc.geyser.registry.type.BlockMappings;
|
||||||
import org.geysermc.geyser.util.BlockUtils;
|
import org.geysermc.geyser.util.BlockUtils;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -83,9 +82,9 @@ public class BlockRegistryPopulator {
|
||||||
|
|
||||||
private static void registerBedrockBlocks() {
|
private static void registerBedrockBlocks() {
|
||||||
for (Map.Entry<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> palette : BLOCK_MAPPERS.entrySet()) {
|
for (Map.Entry<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> palette : BLOCK_MAPPERS.entrySet()) {
|
||||||
InputStream stream = FileUtils.getResource(String.format("bedrock/block_palette.%s.nbt", palette.getKey().key()));
|
|
||||||
NbtList<NbtMap> blocksTag;
|
NbtList<NbtMap> blocksTag;
|
||||||
try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)), true, true)) {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource(String.format("bedrock/block_palette.%s.nbt", palette.getKey().key()));
|
||||||
|
NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)), true, true)) {
|
||||||
NbtMap blockPalette = (NbtMap) nbtInputStream.readTag();
|
NbtMap blockPalette = (NbtMap) nbtInputStream.readTag();
|
||||||
blocksTag = (NbtList<NbtMap>) blockPalette.getList("blocks", NbtType.COMPOUND);
|
blocksTag = (NbtList<NbtMap>) blockPalette.getList("blocks", NbtType.COMPOUND);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -208,10 +207,8 @@ public class BlockRegistryPopulator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerJavaBlocks() {
|
private static void registerJavaBlocks() {
|
||||||
InputStream stream = FileUtils.getResource("mappings/blocks.json");
|
|
||||||
|
|
||||||
JsonNode blocksJson;
|
JsonNode blocksJson;
|
||||||
try {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("mappings/blocks.json")) {
|
||||||
blocksJson = GeyserImpl.JSON_MAPPER.readTree(stream);
|
blocksJson = GeyserImpl.JSON_MAPPER.readTree(stream);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load Java block mappings", e);
|
throw new AssertionError("Unable to load Java block mappings", e);
|
||||||
|
|
|
@ -38,14 +38,17 @@ import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
||||||
import com.nukkitx.protocol.bedrock.v465.Bedrock_v465;
|
import com.nukkitx.protocol.bedrock.v465.Bedrock_v465;
|
||||||
import com.nukkitx.protocol.bedrock.v471.Bedrock_v471;
|
import com.nukkitx.protocol.bedrock.v471.Bedrock_v471;
|
||||||
import com.nukkitx.protocol.bedrock.v475.Bedrock_v475;
|
import com.nukkitx.protocol.bedrock.v475.Bedrock_v475;
|
||||||
import it.unimi.dsi.fastutil.ints.*;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import it.unimi.dsi.fastutil.objects.*;
|
import it.unimi.dsi.fastutil.objects.*;
|
||||||
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.inventory.item.StoredItemMappings;
|
import org.geysermc.geyser.inventory.item.StoredItemMappings;
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.registry.type.*;
|
import org.geysermc.geyser.registry.type.*;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -69,13 +72,13 @@ public class ItemRegistryPopulator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void populate() {
|
public static void populate() {
|
||||||
// Load item mappings from Java Edition to Bedrock Edition
|
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
|
||||||
InputStream stream = FileUtils.getResource("mappings/items.json");
|
|
||||||
|
|
||||||
TypeReference<Map<String, GeyserMappingItem>> mappingItemsType = new TypeReference<>() { };
|
TypeReference<Map<String, GeyserMappingItem>> mappingItemsType = new TypeReference<>() { };
|
||||||
|
|
||||||
Map<String, GeyserMappingItem> items;
|
Map<String, GeyserMappingItem> items;
|
||||||
try {
|
try (InputStream stream = bootstrap.getResource("mappings/items.json")) {
|
||||||
|
// Load item mappings from Java Edition to Bedrock Edition
|
||||||
items = GeyserImpl.JSON_MAPPER.readValue(stream, mappingItemsType);
|
items = GeyserImpl.JSON_MAPPER.readValue(stream, mappingItemsType);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load Java runtime item IDs", e);
|
throw new AssertionError("Unable to load Java runtime item IDs", e);
|
||||||
|
@ -83,8 +86,6 @@ public class ItemRegistryPopulator {
|
||||||
|
|
||||||
/* Load item palette */
|
/* Load item palette */
|
||||||
for (Map.Entry<String, PaletteVersion> palette : PALETTE_VERSIONS.entrySet()) {
|
for (Map.Entry<String, PaletteVersion> palette : PALETTE_VERSIONS.entrySet()) {
|
||||||
stream = FileUtils.getResource(String.format("bedrock/runtime_item_states.%s.json", palette.getKey()));
|
|
||||||
|
|
||||||
TypeReference<List<PaletteItem>> paletteEntriesType = new TypeReference<>() {};
|
TypeReference<List<PaletteItem>> paletteEntriesType = new TypeReference<>() {};
|
||||||
|
|
||||||
// Used to get the Bedrock namespaced ID (in instances where there are small differences)
|
// Used to get the Bedrock namespaced ID (in instances where there are small differences)
|
||||||
|
@ -94,7 +95,7 @@ public class ItemRegistryPopulator {
|
||||||
List<String> itemNames = new ArrayList<>();
|
List<String> itemNames = new ArrayList<>();
|
||||||
|
|
||||||
List<PaletteItem> itemEntries;
|
List<PaletteItem> itemEntries;
|
||||||
try {
|
try (InputStream stream = bootstrap.getResource(String.format("bedrock/runtime_item_states.%s.json", palette.getKey()))) {
|
||||||
itemEntries = GeyserImpl.JSON_MAPPER.readValue(stream, paletteEntriesType);
|
itemEntries = GeyserImpl.JSON_MAPPER.readValue(stream, paletteEntriesType);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load Bedrock runtime item IDs", e);
|
throw new AssertionError("Unable to load Bedrock runtime item IDs", e);
|
||||||
|
@ -112,10 +113,8 @@ public class ItemRegistryPopulator {
|
||||||
|
|
||||||
// Load creative items
|
// Load creative items
|
||||||
// We load this before item mappings to get overridden block runtime ID mappings
|
// We load this before item mappings to get overridden block runtime ID mappings
|
||||||
stream = FileUtils.getResource(String.format("bedrock/creative_items.%s.json", palette.getKey()));
|
|
||||||
|
|
||||||
JsonNode creativeItemEntries;
|
JsonNode creativeItemEntries;
|
||||||
try {
|
try (InputStream stream = bootstrap.getResource(String.format("bedrock/creative_items.%s.json", palette.getKey()))) {
|
||||||
creativeItemEntries = GeyserImpl.JSON_MAPPER.readTree(stream).get("items");
|
creativeItemEntries = GeyserImpl.JSON_MAPPER.readTree(stream).get("items");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load creative items", e);
|
throw new AssertionError("Unable to load creative items", e);
|
||||||
|
|
|
@ -40,12 +40,11 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
|
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -60,10 +59,8 @@ import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID;
|
||||||
public class RecipeRegistryPopulator {
|
public class RecipeRegistryPopulator {
|
||||||
|
|
||||||
public static void populate() {
|
public static void populate() {
|
||||||
InputStream stream = FileUtils.getResource("mappings/recipes.json");
|
|
||||||
|
|
||||||
JsonNode items;
|
JsonNode items;
|
||||||
try {
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("mappings/recipes.json")) {
|
||||||
items = GeyserImpl.JSON_MAPPER.readTree(stream);
|
items = GeyserImpl.JSON_MAPPER.readTree(stream);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
||||||
|
|
|
@ -26,37 +26,36 @@
|
||||||
package org.geysermc.geyser.skin;
|
package org.geysermc.geyser.skin;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
public class ProvidedSkin {
|
public class ProvidedSkin {
|
||||||
@Getter private byte[] skin;
|
@Getter private byte[] skin;
|
||||||
|
|
||||||
public ProvidedSkin(String internalUrl) {
|
public ProvidedSkin(String internalUrl) {
|
||||||
try {
|
try {
|
||||||
BufferedImage image = ImageIO.read(ProvidedSkin.class.getClassLoader().getResource(internalUrl));
|
BufferedImage image;
|
||||||
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource(internalUrl)) {
|
||||||
|
image = ImageIO.read(stream);
|
||||||
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(image.getWidth() * 4 + image.getHeight() * 4);
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(image.getWidth() * 4 + image.getHeight() * 4);
|
||||||
try {
|
for (int y = 0; y < image.getHeight(); y++) {
|
||||||
for (int y = 0; y < image.getHeight(); y++) {
|
for (int x = 0; x < image.getWidth(); x++) {
|
||||||
for (int x = 0; x < image.getWidth(); x++) {
|
int rgba = image.getRGB(x, y);
|
||||||
int rgba = image.getRGB(x, y);
|
outputStream.write((rgba >> 16) & 0xFF); // Red
|
||||||
outputStream.write((rgba >> 16) & 0xFF); // Red
|
outputStream.write((rgba >> 8) & 0xFF); // Green
|
||||||
outputStream.write((rgba >> 8) & 0xFF); // Green
|
outputStream.write(rgba & 0xFF); // Blue
|
||||||
outputStream.write(rgba & 0xFF); // Blue
|
outputStream.write((rgba >> 24) & 0xFF); // Alpha
|
||||||
outputStream.write((rgba >> 24) & 0xFF); // Alpha
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
image.flush();
|
|
||||||
skin = outputStream.toByteArray();
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
outputStream.close();
|
|
||||||
} catch (IOException ignored) {}
|
|
||||||
}
|
}
|
||||||
|
image.flush();
|
||||||
|
skin = outputStream.toByteArray();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,19 +94,19 @@ public class SkinProvider {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
/* Load in the normal ears geometry */
|
/* Load in the normal ears geometry */
|
||||||
EARS_GEOMETRY = new String(FileUtils.readAllBytes(FileUtils.getResource("bedrock/skin/geometry.humanoid.ears.json")), StandardCharsets.UTF_8);
|
EARS_GEOMETRY = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.ears.json"), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
/* Load in the slim ears geometry */
|
/* Load in the slim ears geometry */
|
||||||
EARS_GEOMETRY_SLIM = new String(FileUtils.readAllBytes(FileUtils.getResource("bedrock/skin/geometry.humanoid.earsSlim.json")), StandardCharsets.UTF_8);
|
EARS_GEOMETRY_SLIM = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.earsSlim.json"), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
/* Load in the custom skull geometry */
|
/* Load in the custom skull geometry */
|
||||||
String skullData = new String(FileUtils.readAllBytes(FileUtils.getResource("bedrock/skin/geometry.humanoid.customskull.json")), StandardCharsets.UTF_8);
|
String skullData = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.customskull.json"), StandardCharsets.UTF_8);
|
||||||
SKULL_GEOMETRY = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.customskull\"}}", skullData, false);
|
SKULL_GEOMETRY = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.customskull\"}}", skullData, false);
|
||||||
|
|
||||||
/* Load in the player head skull geometry */
|
/* Load in the player head skull geometry */
|
||||||
String wearingCustomSkull = new String(FileUtils.readAllBytes(FileUtils.getResource("bedrock/skin/geometry.humanoid.wearingCustomSkull.json")), StandardCharsets.UTF_8);
|
String wearingCustomSkull = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.wearingCustomSkull.json"), StandardCharsets.UTF_8);
|
||||||
WEARING_CUSTOM_SKULL = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkull\"}}", wearingCustomSkull, false);
|
WEARING_CUSTOM_SKULL = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkull\"}}", wearingCustomSkull, false);
|
||||||
String wearingCustomSkullSlim = new String(FileUtils.readAllBytes(FileUtils.getResource("bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json")), StandardCharsets.UTF_8);
|
String wearingCustomSkullSlim = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json"), StandardCharsets.UTF_8);
|
||||||
WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim, false);
|
WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim, false);
|
||||||
|
|
||||||
// Schedule Daily Image Expiry if we are caching them
|
// Schedule Daily Image Expiry if we are caching them
|
||||||
|
|
|
@ -25,9 +25,10 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.text;
|
package org.geysermc.geyser.text;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -40,48 +41,106 @@ import java.util.Properties;
|
||||||
public class GeyserLocale {
|
public class GeyserLocale {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we determine the locale that the user wishes to use, use that locale
|
* If we determine the default locale that the user wishes to use, use that locale
|
||||||
*/
|
*/
|
||||||
private static String CACHED_LOCALE;
|
private static String DEFAULT_LOCALE;
|
||||||
|
/**
|
||||||
|
* Whether the system locale cannot be loaded by Geyser.
|
||||||
|
*/
|
||||||
|
private static boolean SYSTEM_LOCALE_INVALID;
|
||||||
|
|
||||||
private static final Map<String, Properties> LOCALE_MAPPINGS = new HashMap<>();
|
private static final Map<String, Properties> LOCALE_MAPPINGS = new HashMap<>();
|
||||||
|
|
||||||
static {
|
/**
|
||||||
// Load it as a backup in case something goes really wrong
|
* Loads the initial locale(s) with the help of the bootstrap.
|
||||||
if (!"en_US".equals(formatLocale(getDefaultLocale()))) { // getDefaultLocale() loads the locale automatically
|
*/
|
||||||
loadGeyserLocale("en_US");
|
public static void init(GeyserBootstrap bootstrap) {
|
||||||
|
String defaultLocale = formatLocale(Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry());
|
||||||
|
String loadedLocale = loadGeyserLocale(defaultLocale, bootstrap);
|
||||||
|
if (loadedLocale != null) {
|
||||||
|
DEFAULT_LOCALE = loadedLocale;
|
||||||
|
// Load English as a backup in case something goes really wrong
|
||||||
|
if (!"en_US".equals(loadedLocale)) {
|
||||||
|
loadGeyserLocale("en_US", bootstrap);
|
||||||
|
}
|
||||||
|
SYSTEM_LOCALE_INVALID = false;
|
||||||
|
} else {
|
||||||
|
DEFAULT_LOCALE = loadGeyserLocale("en_US", bootstrap);
|
||||||
|
if (DEFAULT_LOCALE == null) {
|
||||||
|
// en_US can't be loaded?
|
||||||
|
throw new IllegalStateException("English locale not found in Geyser. Did you clone the submodules? (git submodule update --init)");
|
||||||
|
}
|
||||||
|
SYSTEM_LOCALE_INVALID = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize the default locale, now that we know what the default locale should be.
|
||||||
|
*/
|
||||||
|
public static void finalizeDefaultLocale(GeyserImpl geyser) {
|
||||||
|
String newDefaultLocale = geyser.getConfig().getDefaultLocale();
|
||||||
|
if (newDefaultLocale == null) {
|
||||||
|
// We want to use the system locale which is already loaded
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String loadedNewLocale = loadGeyserLocale(newDefaultLocale, geyser.getBootstrap());
|
||||||
|
if (loadedNewLocale != null) {
|
||||||
|
// The config's locale is valid
|
||||||
|
DEFAULT_LOCALE = loadedNewLocale;
|
||||||
|
} else if (SYSTEM_LOCALE_INVALID) {
|
||||||
|
geyser.getLogger().warning(Locale.getDefault().toString() + " is not a valid Bedrock language.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDefaultLocale() {
|
||||||
|
return DEFAULT_LOCALE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a Geyser locale from resources, if the file doesn't exist it just logs a warning
|
* Loads a Geyser locale from resources, if the file doesn't exist it just logs a warning
|
||||||
*
|
*
|
||||||
* @param locale Locale to load
|
* @param locale Locale to load
|
||||||
*/
|
*/
|
||||||
public static void loadGeyserLocale(String locale) {
|
public static void loadGeyserLocale(String locale) {
|
||||||
|
GeyserImpl geyser = GeyserImpl.getInstance();
|
||||||
|
if (geyser == null) {
|
||||||
|
throw new IllegalStateException("Geyser instance cannot be null when loading a locale!");
|
||||||
|
}
|
||||||
|
loadGeyserLocale(locale, geyser.getBootstrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String loadGeyserLocale(String locale, GeyserBootstrap bootstrap) {
|
||||||
locale = formatLocale(locale);
|
locale = formatLocale(locale);
|
||||||
// Don't load the locale if it's already loaded.
|
// Don't load the locale if it's already loaded.
|
||||||
if (LOCALE_MAPPINGS.containsKey(locale)) {
|
if (LOCALE_MAPPINGS.containsKey(locale)) {
|
||||||
return;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream localeStream = GeyserImpl.class.getClassLoader().getResourceAsStream("languages/texts/" + locale + ".properties");
|
InputStream localeStream = bootstrap.getResourceOrNull("languages/texts/" + locale + ".properties");
|
||||||
|
|
||||||
// Load the locale
|
// Load the locale
|
||||||
if (localeStream != null) {
|
if (localeStream != null) {
|
||||||
Properties localeProp = new Properties();
|
try {
|
||||||
try (InputStreamReader reader = new InputStreamReader(localeStream, StandardCharsets.UTF_8)) {
|
Properties localeProp = new Properties();
|
||||||
localeProp.load(reader);
|
try (InputStreamReader reader = new InputStreamReader(localeStream, StandardCharsets.UTF_8)) {
|
||||||
} catch (Exception e) {
|
localeProp.load(reader);
|
||||||
throw new AssertionError(getLocaleStringLog("geyser.language.load_failed", locale), e);
|
} catch (Exception e) {
|
||||||
}
|
throw new AssertionError(getLocaleStringLog("geyser.language.load_failed", locale), e);
|
||||||
|
}
|
||||||
|
|
||||||
// Insert the locale into the mappings
|
// Insert the locale into the mappings
|
||||||
LOCALE_MAPPINGS.put(locale, localeProp);
|
LOCALE_MAPPINGS.put(locale, localeProp);
|
||||||
|
return locale;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
localeStream.close();
|
||||||
|
} catch (IOException ignored) {}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (GeyserImpl.getInstance() != null && GeyserImpl.getInstance().getLogger() != null) {
|
if (GeyserImpl.getInstance() != null) {
|
||||||
GeyserImpl.getInstance().getLogger().warning("Missing locale: " + locale);
|
GeyserImpl.getInstance().getLogger().warning("Missing locale: " + locale);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,66 +216,4 @@ public class GeyserLocale {
|
||||||
String country = locale.substring(3);
|
String country = locale.substring(3);
|
||||||
return language.toLowerCase(Locale.ENGLISH) + "_" + country.toUpperCase(Locale.ENGLISH);
|
return language.toLowerCase(Locale.ENGLISH) + "_" + country.toUpperCase(Locale.ENGLISH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the default locale that Geyser should use
|
|
||||||
* @return the current default locale
|
|
||||||
*/
|
|
||||||
public static String getDefaultLocale() {
|
|
||||||
if (CACHED_LOCALE != null) {
|
|
||||||
return CACHED_LOCALE; // We definitely know the locale the user is using
|
|
||||||
}
|
|
||||||
|
|
||||||
String locale;
|
|
||||||
boolean isValid = true;
|
|
||||||
if (GeyserImpl.getInstance() != null &&
|
|
||||||
GeyserImpl.getInstance().getConfig() != null &&
|
|
||||||
GeyserImpl.getInstance().getConfig().getDefaultLocale() != null) { // If the config option for getDefaultLocale does not equal null, use that
|
|
||||||
locale = formatLocale(GeyserImpl.getInstance().getConfig().getDefaultLocale());
|
|
||||||
if (isValidLanguage(locale)) {
|
|
||||||
CACHED_LOCALE = locale;
|
|
||||||
return locale;
|
|
||||||
} else {
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
locale = formatLocale(Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry());
|
|
||||||
if (!isValidLanguage(locale)) { // Bedrock does not support this language
|
|
||||||
locale = "en_US";
|
|
||||||
loadGeyserLocale(locale);
|
|
||||||
}
|
|
||||||
if (GeyserImpl.getInstance() != null &&
|
|
||||||
GeyserImpl.getInstance().getConfig() != null && (GeyserImpl.getInstance().getConfig().getDefaultLocale() == null || !isValid)) { // Means we should use the system locale for sure
|
|
||||||
CACHED_LOCALE = locale;
|
|
||||||
}
|
|
||||||
return locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures that the given locale is supported by Bedrock
|
|
||||||
* @param locale the locale to validate
|
|
||||||
* @return true if the given locale is supported by Bedrock and by extension Geyser
|
|
||||||
*/
|
|
||||||
private static boolean isValidLanguage(String locale) {
|
|
||||||
boolean result = true;
|
|
||||||
if (FileUtils.class.getResource("/languages/texts/" + locale + ".properties") == null) {
|
|
||||||
result = false;
|
|
||||||
if (GeyserImpl.getInstance() != null && GeyserImpl.getInstance().getLogger() != null) { // Could be too early for these to be initialized
|
|
||||||
if (locale.equals("en_US")) {
|
|
||||||
GeyserImpl.getInstance().getLogger().error("English locale not found in Geyser. Did you clone the submodules? (git submodule update --init)");
|
|
||||||
} else {
|
|
||||||
GeyserImpl.getInstance().getLogger().warning(locale + " is not a valid Bedrock language."); // We can't translate this since we just loaded an invalid language
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!LOCALE_MAPPINGS.containsKey(locale)) {
|
|
||||||
loadGeyserLocale(locale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void init() {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,9 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.util;
|
package org.geysermc.geyser.util;
|
||||||
|
|
||||||
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;
|
||||||
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
@ -58,28 +57,11 @@ public class FileUtils {
|
||||||
return objectMapper.readValue(src, valueType);
|
return objectMapper.readValue(src, valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T loadYaml(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 <T> T loadJson(InputStream src, Class<T> valueType) throws IOException {
|
public static <T> T loadJson(InputStream src, Class<T> valueType) throws IOException {
|
||||||
// Read specifically with UTF-8 to allow any non-UTF-encoded JSON to read
|
// Read specifically with UTF-8 to allow any non-UTF-encoded JSON to read
|
||||||
return GeyserImpl.JSON_MAPPER.readValue(new InputStreamReader(src, StandardCharsets.UTF_8), valueType);
|
return GeyserImpl.JSON_MAPPER.readValue(new InputStreamReader(src, StandardCharsets.UTF_8), valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the specified file or copy if from resources
|
|
||||||
*
|
|
||||||
* @param name File and resource name
|
|
||||||
* @param fallback Formatting callback
|
|
||||||
* @return File handle of the specified file
|
|
||||||
* @throws IOException if the file failed to copy from resource
|
|
||||||
*/
|
|
||||||
public static File fileOrCopiedFromResource(String name, Function<String, String> fallback) throws IOException {
|
|
||||||
return fileOrCopiedFromResource(new File(name), name, fallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the specified file or copy if from resources
|
* Open the specified file or copy if from resources
|
||||||
*
|
*
|
||||||
|
@ -89,12 +71,12 @@ public class FileUtils {
|
||||||
* @return File handle of the specified file
|
* @return File handle of the specified file
|
||||||
* @throws IOException if the file failed to copy from resource
|
* @throws IOException if the file failed to copy from resource
|
||||||
*/
|
*/
|
||||||
public static File fileOrCopiedFromResource(File file, String name, Function<String, String> format) throws IOException {
|
public static File fileOrCopiedFromResource(File file, String name, Function<String, String> format, GeyserBootstrap bootstrap) throws IOException {
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
//noinspection ResultOfMethodCallIgnored
|
//noinspection ResultOfMethodCallIgnored
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
try (InputStream input = GeyserImpl.class.getResourceAsStream("/" + name)) { // resources need leading "/" prefix
|
try (InputStream input = bootstrap.getResource(name)) {
|
||||||
byte[] bytes = new byte[input.available()];
|
byte[] bytes = new byte[input.available()];
|
||||||
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
@ -144,20 +126,6 @@ public class FileUtils {
|
||||||
writeFile(new File(name), data);
|
writeFile(new File(name), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an InputStream for the given resource path, throws AssertionError if resource is not found
|
|
||||||
*
|
|
||||||
* @param resource Resource to get
|
|
||||||
* @return InputStream of the given resource
|
|
||||||
*/
|
|
||||||
public static InputStream getResource(String resource) {
|
|
||||||
InputStream stream = FileUtils.class.getClassLoader().getResourceAsStream(resource);
|
|
||||||
if (stream == null) {
|
|
||||||
throw new AssertionError("Unable to find resource: " + resource);
|
|
||||||
}
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the SHA256 hash of a file
|
* Calculate the SHA256 hash of a file
|
||||||
*
|
*
|
||||||
|
@ -208,6 +176,18 @@ public class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param resource the internal resource to read off from
|
||||||
|
* @return the byte array of an InputStream
|
||||||
|
*/
|
||||||
|
public static byte[] readAllBytes(String resource) {
|
||||||
|
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource(resource)) {
|
||||||
|
return readAllBytes(stream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Error while trying to read internal input stream!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param stream the InputStream to read off of
|
* @param stream the InputStream to read off of
|
||||||
* @return the byte array of an InputStream
|
* @return the byte array of an InputStream
|
||||||
|
@ -265,15 +245,18 @@ public class FileUtils {
|
||||||
* @return a set of all the classes annotated by the given annotation
|
* @return a set of all the classes annotated by the given annotation
|
||||||
*/
|
*/
|
||||||
public static Set<Class<?>> getGeneratedClassesForAnnotation(String input) {
|
public static Set<Class<?>> getGeneratedClassesForAnnotation(String input) {
|
||||||
InputStream annotatedClass = FileUtils.getResource(input);
|
try (InputStream annotatedClass = GeyserImpl.getInstance().getBootstrap().getResource(input);
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(annotatedClass));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(annotatedClass))) {
|
||||||
return reader.lines().map(className -> {
|
return reader.lines().map(className -> {
|
||||||
try {
|
try {
|
||||||
return Class.forName(className);
|
return Class.forName(className);
|
||||||
} catch (ClassNotFoundException ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Failed to find class " + className, ex);
|
GeyserImpl.getInstance().getLogger().error("Failed to find class " + className, ex);
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
}).collect(Collectors.toSet());
|
}).collect(Collectors.toSet());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue