From 8627787ea991f66b368e93648c79abf051820fe9 Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Mon, 10 Jan 2022 18:45:26 +0100 Subject: [PATCH 1/8] Added basic extension loading --- .../java/org/geysermc/geyser/GeyserImpl.java | 5 + .../geysermc/geyser/extension/Extension.java | 50 ++++ .../extension/ExtensionClassLoader.java | 97 +++++++ .../extension/ExtensionDescription.java | 94 +++++++ .../geyser/extension/ExtensionLoader.java | 173 +++++++++++++ .../geyser/extension/ExtensionManager.java | 243 ++++++++++++++++++ .../geyser/extension/GeyserExtension.java | 176 +++++++++++++ .../InvalidDescriptionException.java | 40 +++ .../exception/InvalidExtensionException.java | 40 +++ 9 files changed, 918 insertions(+) create mode 100644 core/src/main/java/org/geysermc/geyser/extension/Extension.java create mode 100644 core/src/main/java/org/geysermc/geyser/extension/ExtensionClassLoader.java create mode 100644 core/src/main/java/org/geysermc/geyser/extension/ExtensionDescription.java create mode 100644 core/src/main/java/org/geysermc/geyser/extension/ExtensionLoader.java create mode 100644 core/src/main/java/org/geysermc/geyser/extension/ExtensionManager.java create mode 100644 core/src/main/java/org/geysermc/geyser/extension/GeyserExtension.java create mode 100644 core/src/main/java/org/geysermc/geyser/extension/exception/InvalidDescriptionException.java create mode 100644 core/src/main/java/org/geysermc/geyser/extension/exception/InvalidExtensionException.java diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index eaadd15fa..abfc7bb83 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -52,6 +52,7 @@ import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.command.CommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; +import org.geysermc.geyser.extension.ExtensionManager; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.network.ConnectorServerEventHandler; import org.geysermc.geyser.pack.ResourcePack; @@ -161,6 +162,8 @@ public class GeyserImpl implements GeyserApi { ResourcePack.loadPacks(); + ExtensionManager.init(); + if (platformType != PlatformType.STANDALONE && config.getRemote().getAddress().equals("auto")) { // Set the remote address to localhost since that is where we are always connecting try { @@ -444,6 +447,8 @@ public class GeyserImpl implements GeyserApi { newsHandler.shutdown(); this.getCommandManager().getCommands().clear(); + ExtensionManager.getExtensionManager().disableExtensions(); + bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); } diff --git a/core/src/main/java/org/geysermc/geyser/extension/Extension.java b/core/src/main/java/org/geysermc/geyser/extension/Extension.java new file mode 100644 index 000000000..a911e56ad --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/Extension.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension; + +import org.geysermc.geyser.GeyserImpl; +import java.io.File; +import java.io.InputStream; + +public interface Extension { + void onLoad(); + void onEnable(); + void onDisable(); + + boolean isEnabled(); + boolean isDisabled(); + + File getDataFolder(); + ExtensionDescription getDescription(); + String getName(); + + InputStream getResource(String filename); + void saveResource(String filename, boolean replace); + + GeyserImpl getGeyser(); + ClassLoader getClassLoader(); + ExtensionLoader getExtensionLoader(); +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/ExtensionClassLoader.java b/core/src/main/java/org/geysermc/geyser/extension/ExtensionClassLoader.java new file mode 100644 index 000000000..3261adc01 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/ExtensionClassLoader.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension; + +import org.geysermc.geyser.extension.exception.InvalidExtensionException; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class ExtensionClassLoader extends URLClassLoader { + private ExtensionLoader loader; + private Map classes = new HashMap<>(); + public GeyserExtension extension; + + public ExtensionClassLoader(ExtensionLoader loader, ClassLoader parent, ExtensionDescription description, File file) throws InvalidExtensionException, MalformedURLException { + super(new URL[] { file.toURI().toURL() }, parent); + this.loader = loader; + + try { + Class jarClass; + try { + jarClass = Class.forName(description.getMain(), true, this); + } catch (ClassNotFoundException ex) { + throw new InvalidExtensionException("Class " + description.getMain() + " not found, extension cannot be loaded", ex); + } + + Class extensionClass; + try { + extensionClass = jarClass.asSubclass(GeyserExtension.class); + } catch (ClassCastException ex) { + throw new InvalidExtensionException("Main class " + description.getMain() + " should extends GeyserExtension, but extends " + jarClass.getSuperclass().getSimpleName(), ex); + } + + extension = extensionClass.newInstance(); + } catch (IllegalAccessException ex) { + throw new InvalidExtensionException("No public constructor", ex); + } catch (InstantiationException ex) { + throw new InvalidExtensionException("Abnormal extension type", ex); + } + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + return this.findClass(name, true); + } + + protected Class findClass(String name, boolean checkGlobal) throws ClassNotFoundException { + if (name.startsWith("org.geysermc.geyser.") || name.startsWith("org.geysermc.connector.") || name.startsWith("net.minecraft.")) { + throw new ClassNotFoundException(name); + } + Class result = classes.get(name); + if(result == null) { + if(checkGlobal) { + result = loader.getClassByName(name); + } + if(result == null) { + result = super.findClass(name); + if (result != null) { + loader.setClass(name, result); + } + } + classes.put(name, result); + } + return result; + } + + Set getClasses() { + return classes.keySet(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/ExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/ExtensionDescription.java new file mode 100644 index 000000000..9f714dc11 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/ExtensionDescription.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension; + +import org.geysermc.geyser.extension.exception.InvalidDescriptionException; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +import java.util.*; + +public class ExtensionDescription { + private String name; + private String main; + private List api; + private String version; + private final List authors = new ArrayList<>(); + + public ExtensionDescription(String yamlString) throws InvalidDescriptionException { + DumperOptions dumperOptions = new DumperOptions(); + dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml yaml = new Yaml(dumperOptions); + this.loadMap(yaml.loadAs(yamlString, LinkedHashMap.class)); + } + + private void loadMap(Map yamlMap) throws InvalidDescriptionException { + this.name = ((String) yamlMap.get("name")).replaceAll("[^A-Za-z0-9 _.-]", ""); + if (this.name.equals("")) { + throw new InvalidDescriptionException("Invalid extension name"); + } + this.name = this.name.replace(" ", "_"); + this.version = String.valueOf(yamlMap.get("version")); + this.main = (String) yamlMap.get("main"); + + Object api = yamlMap.get("api"); + if (api instanceof List) { + this.api = (List) api; + } else { + List list = new ArrayList<>(); + list.add((String) api); + this.api = list; + } + + if (yamlMap.containsKey("author")) { + this.authors.add((String) yamlMap.get("author")); + } + + if (yamlMap.containsKey("authors")) { + this.authors.addAll((Collection) yamlMap.get("authors")); + } + } + + public String getName() { + return this.name; + } + + public String getMain() { + return this.main; + } + + public List getAPIVersions() { + return api; + } + + public String getVersion() { + return this.version; + } + + public List getAuthors() { + return this.authors; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/ExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/ExtensionLoader.java new file mode 100644 index 000000000..15795c2c5 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/ExtensionLoader.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension; + +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.extension.exception.InvalidDescriptionException; +import org.geysermc.geyser.extension.exception.InvalidExtensionException; +import java.io.*; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.regex.Pattern; + +public class ExtensionLoader { + private final Map classes = new HashMap<>(); + private final Map classLoaders = new HashMap<>(); + + public GeyserExtension loadExtension(File file) throws InvalidExtensionException { + if (file == null) { + throw new InvalidExtensionException("File is null"); + } + + if (!file.exists()) { + throw new InvalidExtensionException(new FileNotFoundException(file.getPath()) + " does not exist"); + } + + final ExtensionDescription description; + try { + description = getExtensionDescription(file); + } catch (InvalidDescriptionException e) { + throw new InvalidExtensionException(e); + } + + final File parentFile = file.getParentFile(); + final File dataFolder = new File(parentFile, description.getName()); + if (dataFolder.exists() && !dataFolder.isDirectory()) { + throw new InvalidExtensionException("The folder " + dataFolder.getPath() + " is not a directory and is the data folder for the extension " + description.getName() + "!"); + } + + final ExtensionClassLoader loader; + try { + loader = new ExtensionClassLoader(this, getClass().getClassLoader(), description, file); + } catch (Throwable e) { + throw new InvalidExtensionException(e); + } + classLoaders.put(description.getName(), loader); + + setup(loader.extension, description, dataFolder, file); + return loader.extension; + } + + private void setup(GeyserExtension extension, ExtensionDescription description, File dataFolder, File file) { + extension.init(GeyserImpl.getInstance(), description, dataFolder, file, this); + extension.onLoad(); + } + + public ExtensionDescription getExtensionDescription(File file) throws InvalidDescriptionException { + JarFile jarFile = null; + InputStream stream = null; + + try { + jarFile = new JarFile(file); + + JarEntry descriptionEntry = jarFile.getJarEntry("extension.yml"); + if (descriptionEntry == null) { + throw new InvalidDescriptionException(new FileNotFoundException("extension.yml") + " does not exist in the jar file!"); + } + + stream = jarFile.getInputStream(descriptionEntry); + + InputStreamReader reader = new InputStreamReader(stream); + StringBuilder builder = new StringBuilder(); + String temp; + BufferedReader bufferedReader = new BufferedReader(reader); + temp = bufferedReader.readLine(); + while (temp != null) { + if (builder.length() != 0) { + builder.append("\n"); + } + builder.append(temp); + temp = bufferedReader.readLine(); + } + + return new ExtensionDescription(builder.toString()); + } catch (IOException e) { + throw new InvalidDescriptionException(e); + } finally { + if (jarFile != null) { + try { + jarFile.close(); + } catch (IOException e) { + } + } + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + } + + public Pattern[] getExtensionFilters() { + return new Pattern[] { Pattern.compile("^.+\\.jar$") }; + } + + public Class getClassByName(final String name) throws ClassNotFoundException{ + Class clazz = classes.get(name); + try { + for(ExtensionClassLoader loader : classLoaders.values()) { + try { + clazz = loader.findClass(name,false); + } catch(NullPointerException e) { + } + } + return clazz; + } catch(NullPointerException s) { + return null; + } + } + + public void setClass(String name, final Class clazz) { + if(!classes.containsKey(name)) { + classes.put(name,clazz); + } + } + + protected void removeClass(String name) { + Class clazz = classes.remove(name); + } + + public void enableExtension(Extension extension) { + if (extension instanceof GeyserExtension) { + if(!extension.isEnabled()) { + GeyserImpl.getInstance().getLogger().info("Enabled extension " + extension.getDescription().getName()); + ((GeyserExtension) extension).setEnabled(true); + } + } + } + + public void disableExtension(Extension extension) { + if (extension instanceof GeyserExtension) { + if(extension.isEnabled()) { + GeyserImpl.getInstance().getLogger().info("Disabled extension " + extension.getDescription().getName()); + ((GeyserExtension) extension).setEnabled(false); + } + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/ExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/ExtensionManager.java new file mode 100644 index 000000000..ad757d499 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/ExtensionManager.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension; + +import org.geysermc.geyser.GeyserImpl; + +import java.io.File; +import java.io.FilenameFilter; +import java.lang.reflect.Constructor; +import java.util.*; +import java.util.regex.Pattern; + +public class ExtensionManager { + private static ExtensionManager extensionManager = null; + + protected Map extensions = new LinkedHashMap<>(); + protected Map fileAssociations = new HashMap<>(); + + public static void init() { + GeyserImpl.getInstance().getLogger().info("Loading extensions..."); + extensionManager = new ExtensionManager(); + extensionManager.registerInterface(ExtensionLoader.class); + extensionManager.loadExtensions(new File("extensions")); + GeyserImpl.getInstance().getLogger().info("Loaded " + extensionManager.extensions.size() + " extensions."); + + for (Extension extension : extensionManager.getExtensions().values()) { + if (!extension.isEnabled()) { + extensionManager.enableExtension(extension); + } + } + } + + public static ExtensionManager getExtensionManager() { + return extensionManager; + } + + public Extension getExtension(String name) { + if (this.extensions.containsKey(name)) { + return this.extensions.get(name); + } + return null; + } + + public Map getExtensions() { + return this.extensions; + } + + public void registerInterface(Class loader) { + ExtensionLoader instance; + + if (ExtensionLoader.class.isAssignableFrom(loader)) { + Constructor constructor; + + try { + constructor = loader.getConstructor(); + instance = constructor.newInstance(); + } catch (NoSuchMethodException ex) { // This should never happen + String className = loader.getName(); + + throw new IllegalArgumentException("Class " + className + " does not have a public constructor", ex); + } catch (Exception ex) { // This should never happen + throw new IllegalArgumentException("Unexpected exception " + ex.getClass().getName() + " while attempting to construct a new instance of " + loader.getName(), ex); + } + } else { + throw new IllegalArgumentException("Class " + loader.getName() + " does not implement interface ExtensionLoader"); + } + + Pattern[] patterns = instance.getExtensionFilters(); + + synchronized (this) { + for (Pattern pattern : patterns) { + fileAssociations.put(pattern, instance); + } + } + } + + public GeyserExtension loadExtension(File file, Map loaders) { + for (ExtensionLoader loader : (loaders == null ? this.fileAssociations : loaders).values()) { + for (Pattern pattern : loader.getExtensionFilters()) { + if (pattern.matcher(file.getName()).matches()) { + try { + ExtensionDescription description = loader.getExtensionDescription(file); + if (description != null) { + GeyserExtension extension = loader.loadExtension(file); + + if (extension != null) { + this.extensions.put(extension.getDescription().getName(), extension); + + return extension; + } + } + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error("Could not load extension", e); + return null; + } + } + } + } + + return null; + } + + public Map loadExtensions(File dictionary) { + if (GeyserImpl.VERSION.equalsIgnoreCase("dev")) { + GeyserImpl.getInstance().getLogger().error("Cannot load extensions in a development environment, aborting extension loading"); + return new HashMap<>(); + } + if (!GeyserImpl.VERSION.contains(".")) { + GeyserImpl.getInstance().getLogger().error("Something went wrong with the Geyser version number, aborting extension loading"); + return new HashMap<>(); + } + + if (!dictionary.exists()) { + dictionary.mkdir(); + } + if (!dictionary.isDirectory()) { + return new HashMap<>(); + } + + Map extensions = new LinkedHashMap<>(); + Map loadedExtensions = new LinkedHashMap<>(); + + for (final ExtensionLoader loader : this.fileAssociations.values()) { + for (File file : dictionary.listFiles((dir, name) -> { + for (Pattern pattern : loader.getExtensionFilters()) { + if (pattern.matcher(name).matches()) { + return true; + } + } + return false; + })) { + if (file.isDirectory()) { + continue; + } + + try { + ExtensionDescription description = loader.getExtensionDescription(file); + if (description != null) { + String name = description.getName(); + + if (extensions.containsKey(name) || this.getExtension(name) != null) { + GeyserImpl.getInstance().getLogger().warning("Found duplicate extension '" + name + "', ignoring '" + file.getName() + "'"); + continue; + } + + boolean compatible = false; + + for (String version : description.getAPIVersions()) { + try { + //Check the format: majorVersion.minorVersion.patch + if (!Pattern.matches("^[0-9]+\\.[0-9]+\\.[0-9]+$", version)) { + throw new IllegalArgumentException(); + } + } catch (NullPointerException | IllegalArgumentException e) { + GeyserImpl.getInstance().getLogger().error("Could't load extension " + name + ": Wrong API format"); + continue; + } + + String[] versionArray = version.split("\\."); + String[] apiVersion = GeyserImpl.VERSION.split("\\."); + + //Completely different API version + if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); + continue; + } + + //If the extension requires new API features, being backwards compatible + if (Integer.parseInt(versionArray[1]) > Integer.parseInt(apiVersion[1])) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); + continue; + } + + compatible = true; + break; + } + + if (!compatible) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name +": Incompatible API version"); + } + + extensions.put(name, file); + loadedExtensions.put(name, this.loadExtension(file, this.fileAssociations)); + } + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error("Couldn't load " +file.getName()+ " in folder " + dictionary + ": ", e); + } + } + } + + return loadedExtensions; + } + + public void enableExtension(Extension extension) { + if (!extension.isEnabled()) { + try { + extension.getExtensionLoader().enableExtension(extension); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error("Error enabling extension " + extension.getName() + ": ", e); + this.disableExtension(extension); + } + } + } + + public void disableExtension(Extension extension) { + if (extension.isEnabled()) { + try { + extension.getExtensionLoader().disableExtension(extension); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error("Error disabling extension " + extension.getName() + ": ", e); + } + } + } + + public void disableExtensions() { + for (Extension extension : this.getExtensions().values()) { + this.disableExtension(extension); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtension.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtension.java new file mode 100644 index 000000000..c6d7b6f10 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtension.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension; + +import org.geysermc.geyser.GeyserImpl; +import java.io.*; +import java.net.URL; +import java.net.URLConnection; + +public class GeyserExtension implements Extension { + private boolean initialized = false; + private boolean enabled = false; + private File file = null; + private File dataFolder = null; + private ClassLoader classLoader = null; + private GeyserImpl geyser = null; + private ExtensionLoader loader; + private ExtensionDescription description = null; + + @Override + public void onLoad() { + } + + @Override + public void onEnable() { + } + + @Override + public void onDisable() { + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean value) { + if (this.enabled != value) { + this.enabled = value; + if (this.enabled) { + onEnable(); + } else { + onDisable(); + } + } + } + + @Override + public boolean isDisabled() { + return !this.enabled; + } + + @Override + public File getDataFolder() { + return this.dataFolder; + } + + @Override + public ExtensionDescription getDescription() { + return this.description; + } + + @Override + public String getName() { + return this.description.getName(); + } + + public void init(GeyserImpl geyser, ExtensionDescription description, File dataFolder, File file, ExtensionLoader loader) { + if (!this.initialized) { + this.initialized = true; + this.file = file; + this.dataFolder = dataFolder; + this.classLoader = this.getClass().getClassLoader(); + this.geyser = geyser; + this.loader = loader; + this.description = description; + } + } + + @Override + public InputStream getResource(String filename) { + if (filename == null) { + throw new IllegalArgumentException("Filename cannot be null"); + } + + try { + URL url = this.classLoader.getResource(filename); + + if (url == null) { + return null; + } + + URLConnection connection = url.openConnection(); + connection.setUseCaches(false); + return connection.getInputStream(); + } catch (IOException ex) { + return null; + } + } + + @Override + public void saveResource(String filename, boolean replace) { + if (filename == null || filename.equals("")) { + throw new IllegalArgumentException("ResourcePath cannot be null or empty"); + } + + filename = filename.replace('\\', '/'); + InputStream in = getResource(filename); + if (in == null) { + throw new IllegalArgumentException("The embedded resource '" + filename + "' cannot be found in " + file); + } + + File outFile = new File(dataFolder, filename); + int lastIndex = filename.lastIndexOf('/'); + File outDir = new File(dataFolder, filename.substring(0, Math.max(lastIndex, 0))); + + if (!outDir.exists()) { + outDir.mkdirs(); + } + + try { + if (!outFile.exists() || replace) { + OutputStream out = new FileOutputStream(outFile); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + out.close(); + in.close(); + } else { + this.geyser.getLogger().warning("Could not save " + outFile.getName() + " to " + outFile + " because " + outFile.getName() + " already exists."); + } + } catch (IOException ex) { + this.geyser.getLogger().severe("Could not save " + outFile.getName() + " to " + outFile, ex); + } + } + + @Override + public GeyserImpl getGeyser() { + return this.geyser; + } + + @Override + public ClassLoader getClassLoader() { + return this.classLoader; + } + + @Override + public ExtensionLoader getExtensionLoader() { + return this.loader; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidDescriptionException.java b/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidDescriptionException.java new file mode 100644 index 000000000..0764dc1d1 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidDescriptionException.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension.exception; + +public class InvalidDescriptionException extends Exception { + public InvalidDescriptionException(Throwable cause) { + super(cause); + } + + public InvalidDescriptionException(String message) { + super(message); + } + + public InvalidDescriptionException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidExtensionException.java b/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidExtensionException.java new file mode 100644 index 000000000..f29f5d280 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidExtensionException.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension.exception; + +public class InvalidExtensionException extends Exception { + public InvalidExtensionException(Throwable cause) { + super(cause); + } + + public InvalidExtensionException(String message) { + super(message); + } + + public InvalidExtensionException(String message, Throwable cause) { + super(message, cause); + } +} From 6757437193b7ad0c72ffc9bf47e1fb7614f459f7 Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Mon, 10 Jan 2022 20:01:36 +0100 Subject: [PATCH 2/8] Moved the extension into geyser-api --- .../geyser/api}/extension/Extension.java | 17 ++-- .../api/extension/ExtensionDescription.java | 36 ++++++++ .../geyser/api/extension/ExtensionLoader.java | 41 +++++++++ .../geyser/api/extension/ExtensionLogger.java | 90 +++++++++++++++++++ .../api}/extension/GeyserExtension.java | 43 +++++---- .../InvalidDescriptionException.java | 2 +- .../exception/InvalidExtensionException.java | 2 +- .../java/org/geysermc/geyser/GeyserImpl.java | 8 +- ...r.java => GeyserExtensionClassLoader.java} | 18 ++-- ...n.java => GeyserExtensionDescription.java} | 22 +++-- ...Loader.java => GeyserExtensionLoader.java} | 51 ++++++----- .../extension/GeyserExtensionLogger.java | 88 ++++++++++++++++++ ...nager.java => GeyserExtensionManager.java} | 65 +++++++------- 13 files changed, 382 insertions(+), 101 deletions(-) rename {core/src/main/java/org/geysermc/geyser => api/geyser/src/main/java/org/geysermc/geyser/api}/extension/Extension.java (83%) create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java rename {core/src/main/java/org/geysermc/geyser => api/geyser/src/main/java/org/geysermc/geyser/api}/extension/GeyserExtension.java (81%) rename {core/src/main/java/org/geysermc/geyser => api/geyser/src/main/java/org/geysermc/geyser/api}/extension/exception/InvalidDescriptionException.java (96%) rename {core/src/main/java/org/geysermc/geyser => api/geyser/src/main/java/org/geysermc/geyser/api}/extension/exception/InvalidExtensionException.java (96%) rename core/src/main/java/org/geysermc/geyser/extension/{ExtensionClassLoader.java => GeyserExtensionClassLoader.java} (80%) rename core/src/main/java/org/geysermc/geyser/extension/{ExtensionDescription.java => GeyserExtensionDescription.java} (85%) rename core/src/main/java/org/geysermc/geyser/extension/{ExtensionLoader.java => GeyserExtensionLoader.java} (74%) create mode 100644 core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLogger.java rename core/src/main/java/org/geysermc/geyser/extension/{ExtensionManager.java => GeyserExtensionManager.java} (79%) diff --git a/core/src/main/java/org/geysermc/geyser/extension/Extension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java similarity index 83% rename from core/src/main/java/org/geysermc/geyser/extension/Extension.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java index a911e56ad..8a820d8ac 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/Extension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java @@ -23,9 +23,9 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.extension; +package org.geysermc.geyser.api.extension; -import org.geysermc.geyser.GeyserImpl; +import org.geysermc.api.GeyserApiBase; import java.io.File; import java.io.InputStream; @@ -37,14 +37,15 @@ public interface Extension { boolean isEnabled(); boolean isDisabled(); - File getDataFolder(); - ExtensionDescription getDescription(); - String getName(); + File dataFolder(); + ExtensionDescription description(); + String name(); InputStream getResource(String filename); void saveResource(String filename, boolean replace); - GeyserImpl getGeyser(); - ClassLoader getClassLoader(); - ExtensionLoader getExtensionLoader(); + ClassLoader classLoader(); + ExtensionLoader extensionLoader(); + ExtensionLogger logger(); + GeyserApiBase geyserApi(); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java new file mode 100644 index 000000000..0f752e72d --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.extension; + +import java.util.*; + +public interface ExtensionDescription { + String name(); + String main(); + List ApiVersions(); + String version(); + List authors(); +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java new file mode 100644 index 000000000..c558957eb --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.extension; + +import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; +import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; + +import java.io.File; +import java.util.regex.Pattern; + +public interface ExtensionLoader { + GeyserExtension loadExtension(File file) throws InvalidExtensionException; + ExtensionDescription extensionDescription(File file) throws InvalidDescriptionException; + Pattern[] extensionFilters(); + Class classByName(final String name) throws ClassNotFoundException; + void enableExtension(Extension extension); + void disableExtension(Extension extension); +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java new file mode 100644 index 000000000..6b5d86153 --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.extension; + +public interface ExtensionLogger { + /** + * Get the logger prefix + * @return the logger prefix + */ + String prefix(); + + /** + * Logs a severe message to console + * + * @param message the message to log + */ + void severe(String message); + + /** + * Logs a severe message and an exception to console + * + * @param message the message to log + * @param error the error to throw + */ + void severe(String message, Throwable error); + + /** + * Logs an error message to console + * + * @param message the message to log + */ + void error(String message); + + /** + * Logs an error message and an exception to console + * + * @param message the message to log + * @param error the error to throw + */ + void error(String message, Throwable error); + + /** + * Logs a warning message to console + * + * @param message the message to log + */ + void warning(String message); + + /** + * Logs an info message to console + * + * @param message the message to log + */ + void info(String message); + + /** + * Logs a debug message to console + * + * @param message the message to log + */ + void debug(String message); + + /** + * If debug is enabled for this logger + */ + boolean isDebug(); +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java similarity index 81% rename from core/src/main/java/org/geysermc/geyser/extension/GeyserExtension.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java index c6d7b6f10..3ed66b444 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java @@ -23,9 +23,9 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.extension; +package org.geysermc.geyser.api.extension; -import org.geysermc.geyser.GeyserImpl; +import org.geysermc.api.GeyserApiBase; import java.io.*; import java.net.URL; import java.net.URLConnection; @@ -36,9 +36,10 @@ public class GeyserExtension implements Extension { private File file = null; private File dataFolder = null; private ClassLoader classLoader = null; - private GeyserImpl geyser = null; private ExtensionLoader loader; + private ExtensionLogger logger; private ExtensionDescription description = null; + private GeyserApiBase api = null; @Override public void onLoad() { @@ -74,29 +75,30 @@ public class GeyserExtension implements Extension { } @Override - public File getDataFolder() { + public File dataFolder() { return this.dataFolder; } @Override - public ExtensionDescription getDescription() { + public ExtensionDescription description() { return this.description; } @Override - public String getName() { - return this.description.getName(); + public String name() { + return this.description.name(); } - public void init(GeyserImpl geyser, ExtensionDescription description, File dataFolder, File file, ExtensionLoader loader) { + public void init(GeyserApiBase api, ExtensionLogger logger, ExtensionLoader loader, ExtensionDescription description, File dataFolder, File file) { if (!this.initialized) { this.initialized = true; this.file = file; this.dataFolder = dataFolder; this.classLoader = this.getClass().getClassLoader(); - this.geyser = geyser; this.loader = loader; + this.logger = logger; this.description = description; + this.api = api; } } @@ -152,25 +154,30 @@ public class GeyserExtension implements Extension { out.close(); in.close(); } else { - this.geyser.getLogger().warning("Could not save " + outFile.getName() + " to " + outFile + " because " + outFile.getName() + " already exists."); + this.logger.warning("Could not save " + outFile.getName() + " to " + outFile + " because " + outFile.getName() + " already exists."); } } catch (IOException ex) { - this.geyser.getLogger().severe("Could not save " + outFile.getName() + " to " + outFile, ex); + this.logger.severe("Could not save " + outFile.getName() + " to " + outFile, ex); } } @Override - public GeyserImpl getGeyser() { - return this.geyser; - } - - @Override - public ClassLoader getClassLoader() { + public ClassLoader classLoader() { return this.classLoader; } @Override - public ExtensionLoader getExtensionLoader() { + public ExtensionLoader extensionLoader() { return this.loader; } + + @Override + public ExtensionLogger logger() { + return this.logger; + } + + @Override + public GeyserApiBase geyserApi() { + return this.api; + } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidDescriptionException.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java similarity index 96% rename from core/src/main/java/org/geysermc/geyser/extension/exception/InvalidDescriptionException.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java index 0764dc1d1..ca2fabad9 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidDescriptionException.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.extension.exception; +package org.geysermc.geyser.api.extension.exception; public class InvalidDescriptionException extends Exception { public InvalidDescriptionException(Throwable cause) { diff --git a/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidExtensionException.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java similarity index 96% rename from core/src/main/java/org/geysermc/geyser/extension/exception/InvalidExtensionException.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java index f29f5d280..1053e6d50 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/exception/InvalidExtensionException.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.extension.exception; +package org.geysermc.geyser.api.extension.exception; public class InvalidExtensionException extends Exception { public InvalidExtensionException(Throwable cause) { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 82a5fd354..7e61b3af7 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -52,7 +52,7 @@ import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.command.CommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; -import org.geysermc.geyser.extension.ExtensionManager; +import org.geysermc.geyser.extension.GeyserExtensionManager; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.network.ConnectorServerEventHandler; import org.geysermc.geyser.pack.ResourcePack; @@ -155,6 +155,8 @@ public class GeyserImpl implements GeyserApi { MessageTranslator.init(); MinecraftLocale.init(); + GeyserExtensionManager.init(); + start(); GeyserConfiguration config = bootstrap.getGeyserConfig(); @@ -198,8 +200,6 @@ public class GeyserImpl implements GeyserApi { ResourcePack.loadPacks(); - ExtensionManager.init(); - if (platformType != PlatformType.STANDALONE && config.getRemote().getAddress().equals("auto")) { // Set the remote address to localhost since that is where we are always connecting try { @@ -460,7 +460,7 @@ public class GeyserImpl implements GeyserApi { ResourcePack.PACKS.clear(); - ExtensionManager.getExtensionManager().disableExtensions(); + GeyserExtensionManager.getExtensionManager().disableExtensions(); bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); } diff --git a/core/src/main/java/org/geysermc/geyser/extension/ExtensionClassLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java similarity index 80% rename from core/src/main/java/org/geysermc/geyser/extension/ExtensionClassLoader.java rename to core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java index 3261adc01..a1ccc063e 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/ExtensionClassLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java @@ -25,7 +25,9 @@ package org.geysermc.geyser.extension; -import org.geysermc.geyser.extension.exception.InvalidExtensionException; +import org.geysermc.geyser.api.extension.ExtensionDescription; +import org.geysermc.geyser.api.extension.GeyserExtension; +import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; import java.io.File; import java.net.MalformedURLException; import java.net.URL; @@ -34,28 +36,28 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -public class ExtensionClassLoader extends URLClassLoader { - private ExtensionLoader loader; +public class GeyserExtensionClassLoader extends URLClassLoader { + private GeyserExtensionLoader loader; private Map classes = new HashMap<>(); public GeyserExtension extension; - public ExtensionClassLoader(ExtensionLoader loader, ClassLoader parent, ExtensionDescription description, File file) throws InvalidExtensionException, MalformedURLException { + public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, ExtensionDescription description, File file) throws InvalidExtensionException, MalformedURLException { super(new URL[] { file.toURI().toURL() }, parent); this.loader = loader; try { Class jarClass; try { - jarClass = Class.forName(description.getMain(), true, this); + jarClass = Class.forName(description.main(), true, this); } catch (ClassNotFoundException ex) { - throw new InvalidExtensionException("Class " + description.getMain() + " not found, extension cannot be loaded", ex); + throw new InvalidExtensionException("Class " + description.main() + " not found, extension cannot be loaded", ex); } Class extensionClass; try { extensionClass = jarClass.asSubclass(GeyserExtension.class); } catch (ClassCastException ex) { - throw new InvalidExtensionException("Main class " + description.getMain() + " should extends GeyserExtension, but extends " + jarClass.getSuperclass().getSimpleName(), ex); + throw new InvalidExtensionException("Main class " + description.main() + " should extends GeyserExtension, but extends " + jarClass.getSuperclass().getSimpleName(), ex); } extension = extensionClass.newInstance(); @@ -78,7 +80,7 @@ public class ExtensionClassLoader extends URLClassLoader { Class result = classes.get(name); if(result == null) { if(checkGlobal) { - result = loader.getClassByName(name); + result = loader.classByName(name); } if(result == null) { result = super.findClass(name); diff --git a/core/src/main/java/org/geysermc/geyser/extension/ExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java similarity index 85% rename from core/src/main/java/org/geysermc/geyser/extension/ExtensionDescription.java rename to core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index 9f714dc11..ee215f2e4 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/ExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -25,20 +25,19 @@ package org.geysermc.geyser.extension; -import org.geysermc.geyser.extension.exception.InvalidDescriptionException; +import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; - import java.util.*; -public class ExtensionDescription { +public class GeyserExtensionDescription implements org.geysermc.geyser.api.extension.ExtensionDescription { private String name; private String main; private List api; private String version; private final List authors = new ArrayList<>(); - public ExtensionDescription(String yamlString) throws InvalidDescriptionException { + public GeyserExtensionDescription(String yamlString) throws InvalidDescriptionException { DumperOptions dumperOptions = new DumperOptions(); dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); Yaml yaml = new Yaml(dumperOptions); @@ -72,23 +71,28 @@ public class ExtensionDescription { } } - public String getName() { + @Override + public String name() { return this.name; } - public String getMain() { + @Override + public String main() { return this.main; } - public List getAPIVersions() { + @Override + public List ApiVersions() { return api; } - public String getVersion() { + @Override + public String version() { return this.version; } - public List getAuthors() { + @Override + public List authors() { return this.authors; } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/ExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java similarity index 74% rename from core/src/main/java/org/geysermc/geyser/extension/ExtensionLoader.java rename to core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index 15795c2c5..9b741fb2d 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/ExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -25,9 +25,13 @@ package org.geysermc.geyser.extension; +import org.geysermc.api.Geyser; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.extension.exception.InvalidDescriptionException; -import org.geysermc.geyser.extension.exception.InvalidExtensionException; +import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.api.extension.ExtensionLoader; +import org.geysermc.geyser.api.extension.GeyserExtension; +import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; +import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; import java.io.*; import java.util.HashMap; import java.util.Map; @@ -35,10 +39,11 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Pattern; -public class ExtensionLoader { +public class GeyserExtensionLoader implements ExtensionLoader { private final Map classes = new HashMap<>(); - private final Map classLoaders = new HashMap<>(); + private final Map classLoaders = new HashMap<>(); + @Override public GeyserExtension loadExtension(File file) throws InvalidExtensionException { if (file == null) { throw new InvalidExtensionException("File is null"); @@ -48,37 +53,39 @@ public class ExtensionLoader { throw new InvalidExtensionException(new FileNotFoundException(file.getPath()) + " does not exist"); } - final ExtensionDescription description; + final GeyserExtensionDescription description; try { - description = getExtensionDescription(file); + description = extensionDescription(file); } catch (InvalidDescriptionException e) { throw new InvalidExtensionException(e); } final File parentFile = file.getParentFile(); - final File dataFolder = new File(parentFile, description.getName()); + final File dataFolder = new File(parentFile, description.name()); if (dataFolder.exists() && !dataFolder.isDirectory()) { - throw new InvalidExtensionException("The folder " + dataFolder.getPath() + " is not a directory and is the data folder for the extension " + description.getName() + "!"); + throw new InvalidExtensionException("The folder " + dataFolder.getPath() + " is not a directory and is the data folder for the extension " + description.name() + "!"); } - final ExtensionClassLoader loader; + final GeyserExtensionClassLoader loader; try { - loader = new ExtensionClassLoader(this, getClass().getClassLoader(), description, file); + loader = new GeyserExtensionClassLoader(this, getClass().getClassLoader(), description, file); } catch (Throwable e) { throw new InvalidExtensionException(e); } - classLoaders.put(description.getName(), loader); + classLoaders.put(description.name(), loader); setup(loader.extension, description, dataFolder, file); return loader.extension; } - private void setup(GeyserExtension extension, ExtensionDescription description, File dataFolder, File file) { - extension.init(GeyserImpl.getInstance(), description, dataFolder, file, this); + private void setup(GeyserExtension extension, GeyserExtensionDescription description, File dataFolder, File file) { + GeyserExtensionLogger logger = new GeyserExtensionLogger(GeyserImpl.getInstance().getLogger(), description.name()); + extension.init(Geyser.api(), logger, this, description, dataFolder, file); extension.onLoad(); } - public ExtensionDescription getExtensionDescription(File file) throws InvalidDescriptionException { + @Override + public GeyserExtensionDescription extensionDescription(File file) throws InvalidDescriptionException { JarFile jarFile = null; InputStream stream = null; @@ -105,7 +112,7 @@ public class ExtensionLoader { temp = bufferedReader.readLine(); } - return new ExtensionDescription(builder.toString()); + return new GeyserExtensionDescription(builder.toString()); } catch (IOException e) { throw new InvalidDescriptionException(e); } finally { @@ -124,14 +131,16 @@ public class ExtensionLoader { } } - public Pattern[] getExtensionFilters() { + @Override + public Pattern[] extensionFilters() { return new Pattern[] { Pattern.compile("^.+\\.jar$") }; } - public Class getClassByName(final String name) throws ClassNotFoundException{ + @Override + public Class classByName(final String name) throws ClassNotFoundException{ Class clazz = classes.get(name); try { - for(ExtensionClassLoader loader : classLoaders.values()) { + for(GeyserExtensionClassLoader loader : classLoaders.values()) { try { clazz = loader.findClass(name,false); } catch(NullPointerException e) { @@ -153,19 +162,21 @@ public class ExtensionLoader { Class clazz = classes.remove(name); } + @Override public void enableExtension(Extension extension) { if (extension instanceof GeyserExtension) { if(!extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info("Enabled extension " + extension.getDescription().getName()); + GeyserImpl.getInstance().getLogger().info("Enabled extension " + extension.description().name()); ((GeyserExtension) extension).setEnabled(true); } } } + @Override public void disableExtension(Extension extension) { if (extension instanceof GeyserExtension) { if(extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info("Disabled extension " + extension.getDescription().getName()); + GeyserImpl.getInstance().getLogger().info("Disabled extension " + extension.description().name()); ((GeyserExtension) extension).setEnabled(false); } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLogger.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLogger.java new file mode 100644 index 000000000..225d6cda3 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLogger.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.extension; + +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.api.extension.ExtensionLogger; + +public class GeyserExtensionLogger implements ExtensionLogger { + private GeyserLogger logger; + private String loggerPrefix; + + public GeyserExtensionLogger(GeyserLogger logger, String prefix) { + this.logger = logger; + this.loggerPrefix = prefix; + } + + @Override + public String prefix() { + return this.loggerPrefix; + } + + private String addPrefix(String message) { + return "[" + this.loggerPrefix + "] " + message; + } + + @Override + public void severe(String message) { + this.logger.severe(this.addPrefix(message)); + } + + @Override + public void severe(String message, Throwable error) { + this.logger.severe(this.addPrefix(message), error); + } + + @Override + public void error(String message) { + this.logger.error(this.addPrefix(message)); + } + + @Override + public void error(String message, Throwable error) { + this.logger.error(this.addPrefix(message), error); + } + + @Override + public void warning(String message) { + this.logger.warning(this.addPrefix(message)); + } + + @Override + public void info(String message) { + this.logger.info(this.addPrefix(message)); + } + + @Override + public void debug(String message) { + this.logger.debug(this.addPrefix(message)); + } + + @Override + public boolean isDebug() { + return this.logger.isDebug(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/extension/ExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java similarity index 79% rename from core/src/main/java/org/geysermc/geyser/extension/ExtensionManager.java rename to core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index ad757d499..c06feba1e 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/ExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -26,35 +26,36 @@ package org.geysermc.geyser.extension; import org.geysermc.geyser.GeyserImpl; - +import org.geysermc.geyser.api.extension.Extension; +import org.geysermc.geyser.api.extension.ExtensionDescription; +import org.geysermc.geyser.api.extension.GeyserExtension; import java.io.File; -import java.io.FilenameFilter; import java.lang.reflect.Constructor; import java.util.*; import java.util.regex.Pattern; -public class ExtensionManager { - private static ExtensionManager extensionManager = null; +public class GeyserExtensionManager { + private static GeyserExtensionManager geyserExtensionManager = null; protected Map extensions = new LinkedHashMap<>(); - protected Map fileAssociations = new HashMap<>(); + protected Map fileAssociations = new HashMap<>(); public static void init() { GeyserImpl.getInstance().getLogger().info("Loading extensions..."); - extensionManager = new ExtensionManager(); - extensionManager.registerInterface(ExtensionLoader.class); - extensionManager.loadExtensions(new File("extensions")); - GeyserImpl.getInstance().getLogger().info("Loaded " + extensionManager.extensions.size() + " extensions."); + geyserExtensionManager = new GeyserExtensionManager(); + geyserExtensionManager.registerInterface(GeyserExtensionLoader.class); + geyserExtensionManager.loadExtensions(new File("extensions")); + GeyserImpl.getInstance().getLogger().info("Loaded " + geyserExtensionManager.extensions.size() + " extensions."); - for (Extension extension : extensionManager.getExtensions().values()) { + for (Extension extension : geyserExtensionManager.getExtensions().values()) { if (!extension.isEnabled()) { - extensionManager.enableExtension(extension); + geyserExtensionManager.enableExtension(extension); } } } - public static ExtensionManager getExtensionManager() { - return extensionManager; + public static GeyserExtensionManager getExtensionManager() { + return geyserExtensionManager; } public Extension getExtension(String name) { @@ -68,11 +69,11 @@ public class ExtensionManager { return this.extensions; } - public void registerInterface(Class loader) { - ExtensionLoader instance; + public void registerInterface(Class loader) { + GeyserExtensionLoader instance; - if (ExtensionLoader.class.isAssignableFrom(loader)) { - Constructor constructor; + if (GeyserExtensionLoader.class.isAssignableFrom(loader)) { + Constructor constructor; try { constructor = loader.getConstructor(); @@ -88,7 +89,7 @@ public class ExtensionManager { throw new IllegalArgumentException("Class " + loader.getName() + " does not implement interface ExtensionLoader"); } - Pattern[] patterns = instance.getExtensionFilters(); + Pattern[] patterns = instance.extensionFilters(); synchronized (this) { for (Pattern pattern : patterns) { @@ -97,17 +98,17 @@ public class ExtensionManager { } } - public GeyserExtension loadExtension(File file, Map loaders) { - for (ExtensionLoader loader : (loaders == null ? this.fileAssociations : loaders).values()) { - for (Pattern pattern : loader.getExtensionFilters()) { + public GeyserExtension loadExtension(File file, Map loaders) { + for (GeyserExtensionLoader loader : (loaders == null ? this.fileAssociations : loaders).values()) { + for (Pattern pattern : loader.extensionFilters()) { if (pattern.matcher(file.getName()).matches()) { try { - ExtensionDescription description = loader.getExtensionDescription(file); + ExtensionDescription description = loader.extensionDescription(file); if (description != null) { GeyserExtension extension = loader.loadExtension(file); if (extension != null) { - this.extensions.put(extension.getDescription().getName(), extension); + this.extensions.put(extension.description().name(), extension); return extension; } @@ -143,9 +144,9 @@ public class ExtensionManager { Map extensions = new LinkedHashMap<>(); Map loadedExtensions = new LinkedHashMap<>(); - for (final ExtensionLoader loader : this.fileAssociations.values()) { + for (final GeyserExtensionLoader loader : this.fileAssociations.values()) { for (File file : dictionary.listFiles((dir, name) -> { - for (Pattern pattern : loader.getExtensionFilters()) { + for (Pattern pattern : loader.extensionFilters()) { if (pattern.matcher(name).matches()) { return true; } @@ -157,9 +158,9 @@ public class ExtensionManager { } try { - ExtensionDescription description = loader.getExtensionDescription(file); + ExtensionDescription description = loader.extensionDescription(file); if (description != null) { - String name = description.getName(); + String name = description.name(); if (extensions.containsKey(name) || this.getExtension(name) != null) { GeyserImpl.getInstance().getLogger().warning("Found duplicate extension '" + name + "', ignoring '" + file.getName() + "'"); @@ -168,7 +169,7 @@ public class ExtensionManager { boolean compatible = false; - for (String version : description.getAPIVersions()) { + for (String version : description.ApiVersions()) { try { //Check the format: majorVersion.minorVersion.patch if (!Pattern.matches("^[0-9]+\\.[0-9]+\\.[0-9]+$", version)) { @@ -217,9 +218,9 @@ public class ExtensionManager { public void enableExtension(Extension extension) { if (!extension.isEnabled()) { try { - extension.getExtensionLoader().enableExtension(extension); + extension.extensionLoader().enableExtension(extension); } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Error enabling extension " + extension.getName() + ": ", e); + GeyserImpl.getInstance().getLogger().error("Error enabling extension " + extension.name() + ": ", e); this.disableExtension(extension); } } @@ -228,9 +229,9 @@ public class ExtensionManager { public void disableExtension(Extension extension) { if (extension.isEnabled()) { try { - extension.getExtensionLoader().disableExtension(extension); + extension.extensionLoader().disableExtension(extension); } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Error disabling extension " + extension.getName() + ": ", e); + GeyserImpl.getInstance().getLogger().error("Error disabling extension " + extension.name() + ": ", e); } } } From 805f7f666a68aee6950c9bda6ed5d25dc20bfc40 Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Wed, 12 Jan 2022 13:50:54 +0100 Subject: [PATCH 3/8] Added javadocs & fixed API version & more --- .../geyser/api/extension/Extension.java | 51 ---------- .../api/extension/ExtensionDescription.java | 33 ++++++- .../geyser/api/extension/ExtensionLoader.java | 42 +++++++- .../geyser/api/extension/ExtensionLogger.java | 1 + .../geyser/api/extension/GeyserExtension.java | 95 ++++++++++++++----- .../InvalidDescriptionException.java | 3 + .../exception/InvalidExtensionException.java | 3 + .../extension/GeyserExtensionDescription.java | 21 ++-- .../extension/GeyserExtensionLoader.java | 28 +++--- .../extension/GeyserExtensionManager.java | 91 +++++++++--------- 10 files changed, 214 insertions(+), 154 deletions(-) delete mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java deleted file mode 100644 index 8a820d8ac..000000000 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.api.extension; - -import org.geysermc.api.GeyserApiBase; -import java.io.File; -import java.io.InputStream; - -public interface Extension { - void onLoad(); - void onEnable(); - void onDisable(); - - boolean isEnabled(); - boolean isDisabled(); - - File dataFolder(); - ExtensionDescription description(); - String name(); - - InputStream getResource(String filename); - void saveResource(String filename, boolean replace); - - ClassLoader classLoader(); - ExtensionLoader extensionLoader(); - ExtensionLogger logger(); - GeyserApiBase geyserApi(); -} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java index 0f752e72d..d32300e09 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java @@ -25,12 +25,41 @@ package org.geysermc.geyser.api.extension; -import java.util.*; +import java.util.List; public interface ExtensionDescription { + /** + * Gets the extension's name + * + * @return the extension's name + */ String name(); + + /** + * Gets the extension's main class + * + * @return the extension's main class + */ String main(); - List ApiVersions(); + + /** + * Gets the extension's api version + * + * @return the extension's api version + */ + String ApiVersion(); + + /** + * Gets the extension's description + * + * @return the extension's description + */ String version(); + + /** + * Gets the extension's authors + * + * @return the extension's authors + */ List authors(); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java index c558957eb..291a34daf 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java @@ -27,15 +27,47 @@ package org.geysermc.geyser.api.extension; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; - import java.io.File; -import java.util.regex.Pattern; public interface ExtensionLoader { + /** + * Loads an extension from a given file + * + * @param file the file to load the extension from + * @return the loaded extension + * @throws InvalidExtensionException + */ GeyserExtension loadExtension(File file) throws InvalidExtensionException; + + /** + * Gets an extension's description from a given file + * + * @param file the file to get the description from + * @return the extension's description + * @throws InvalidDescriptionException + */ ExtensionDescription extensionDescription(File file) throws InvalidDescriptionException; - Pattern[] extensionFilters(); + + /** + * Gets a class by its name from the extension's classloader + * + * @param name the name of the class + * @return the class + * @throws ClassNotFoundException + */ Class classByName(final String name) throws ClassNotFoundException; - void enableExtension(Extension extension); - void disableExtension(Extension extension); + + /** + * Enables an extension + * + * @param extension the extension to enable + */ + void enableExtension(GeyserExtension extension); + + /** + * Disables an extension + * + * @param extension the extension to disable + */ + void disableExtension(GeyserExtension extension); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java index 6b5d86153..60ee45572 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.api.extension; public interface ExtensionLogger { /** * Get the logger prefix + * * @return the logger prefix */ String prefix(); diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java index 3ed66b444..a3f911580 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java @@ -30,34 +30,52 @@ import java.io.*; import java.net.URL; import java.net.URLConnection; -public class GeyserExtension implements Extension { +public class GeyserExtension { private boolean initialized = false; private boolean enabled = false; private File file = null; private File dataFolder = null; private ClassLoader classLoader = null; - private ExtensionLoader loader; - private ExtensionLogger logger; + private ExtensionLoader loader = null; + private ExtensionLogger logger = null; private ExtensionDescription description = null; private GeyserApiBase api = null; - @Override + /** + * Called when the extension is loaded + */ public void onLoad() { + } - @Override + /** + * Called when the extension is enabled + */ public void onEnable() { + } - @Override + /** + * Called when the extension is disabled + */ public void onDisable() { + } - @Override + /** + * Gets if the extension is enabled + * + * @return true if the extension is enabled + */ public boolean isEnabled() { return this.enabled; } + /** + * Gets if the extension is enabled + * + * @return true if the extension is enabled + */ public void setEnabled(boolean value) { if (this.enabled != value) { this.enabled = value; @@ -69,27 +87,34 @@ public class GeyserExtension implements Extension { } } - @Override - public boolean isDisabled() { - return !this.enabled; - } - - @Override + /** + * Gets the extension's data folder + * + * @return the extension's data folder + */ public File dataFolder() { return this.dataFolder; } - @Override + /** + * Gets the extension's description + * + * @return the extension's description + */ public ExtensionDescription description() { return this.description; } - @Override + /** + * Gets the extension's name + * + * @return the extension's name + */ public String name() { return this.description.name(); } - public void init(GeyserApiBase api, ExtensionLogger logger, ExtensionLoader loader, ExtensionDescription description, File dataFolder, File file) { + public void init(GeyserApiBase api, ExtensionLoader loader, ExtensionLogger logger, ExtensionDescription description, File dataFolder, File file) { if (!this.initialized) { this.initialized = true; this.file = file; @@ -102,7 +127,12 @@ public class GeyserExtension implements Extension { } } - @Override + /** + * Gets a resource from the extension jar file + * + * @param filename the file name + * @return the input stream + */ public InputStream getResource(String filename) { if (filename == null) { throw new IllegalArgumentException("Filename cannot be null"); @@ -123,7 +153,12 @@ public class GeyserExtension implements Extension { } } - @Override + /** + * Saves a resource from the extension jar file to the extension's data folder + * + * @param filename the file name + * @param replace whether to replace the file if it already exists + */ public void saveResource(String filename, boolean replace) { if (filename == null || filename.equals("")) { throw new IllegalArgumentException("ResourcePath cannot be null or empty"); @@ -161,22 +196,38 @@ public class GeyserExtension implements Extension { } } - @Override + /** + * Gets the extension's class loader + * + * @return the extension's class loader + */ public ClassLoader classLoader() { return this.classLoader; } - @Override + /** + * Gets the extension's loader + * + * @return the extension's loader + */ public ExtensionLoader extensionLoader() { return this.loader; } - @Override + /** + * Gets the extension's logger + * + * @return the extension's logger + */ public ExtensionLogger logger() { return this.logger; } - @Override + /** + * Gets the {@link GeyserApiBase} instance + * + * @return the {@link GeyserApiBase} instance + */ public GeyserApiBase geyserApi() { return this.api; } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java index ca2fabad9..1fe88e9e9 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java @@ -25,6 +25,9 @@ package org.geysermc.geyser.api.extension.exception; +/** + * Thrown when an extension's description is invalid. + */ public class InvalidDescriptionException extends Exception { public InvalidDescriptionException(Throwable cause) { super(cause); diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java index 1053e6d50..7fb6b6922 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java @@ -25,6 +25,9 @@ package org.geysermc.geyser.api.extension.exception; +/** + * Thrown when an extension is invalid. + */ public class InvalidExtensionException extends Exception { public InvalidExtensionException(Throwable cause) { super(cause); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index ee215f2e4..e2a09c598 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -33,7 +33,7 @@ import java.util.*; public class GeyserExtensionDescription implements org.geysermc.geyser.api.extension.ExtensionDescription { private String name; private String main; - private List api; + private String api; private String version; private final List authors = new ArrayList<>(); @@ -47,19 +47,18 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten private void loadMap(Map yamlMap) throws InvalidDescriptionException { this.name = ((String) yamlMap.get("name")).replaceAll("[^A-Za-z0-9 _.-]", ""); if (this.name.equals("")) { - throw new InvalidDescriptionException("Invalid extension name"); + throw new InvalidDescriptionException("Invalid extension name, cannot be empty"); } this.name = this.name.replace(" ", "_"); this.version = String.valueOf(yamlMap.get("version")); this.main = (String) yamlMap.get("main"); Object api = yamlMap.get("api"); - if (api instanceof List) { - this.api = (List) api; + if (api instanceof String) { + this.api = (String) api; } else { - List list = new ArrayList<>(); - list.add((String) api); - this.api = list; + this.api = "0.0.0"; + throw new InvalidDescriptionException("Invalid api version format, should be a string: major.minor.patch"); } if (yamlMap.containsKey("author")) { @@ -67,7 +66,11 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten } if (yamlMap.containsKey("authors")) { - this.authors.addAll((Collection) yamlMap.get("authors")); + try { + this.authors.addAll((Collection) yamlMap.get("authors")); + } catch (Exception e) { + throw new InvalidDescriptionException("Invalid authors format, should be a list of strings", e); + } } } @@ -82,7 +85,7 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten } @Override - public List ApiVersions() { + public String ApiVersion() { return api; } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index 9b741fb2d..a7e4bac3d 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.extension; import org.geysermc.api.Geyser; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionLoader; import org.geysermc.geyser.api.extension.GeyserExtension; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; @@ -80,7 +79,7 @@ public class GeyserExtensionLoader implements ExtensionLoader { private void setup(GeyserExtension extension, GeyserExtensionDescription description, File dataFolder, File file) { GeyserExtensionLogger logger = new GeyserExtensionLogger(GeyserImpl.getInstance().getLogger(), description.name()); - extension.init(Geyser.api(), logger, this, description, dataFolder, file); + extension.init(Geyser.api(), this, logger, description, dataFolder, file); extension.onLoad(); } @@ -131,7 +130,6 @@ public class GeyserExtensionLoader implements ExtensionLoader { } } - @Override public Pattern[] extensionFilters() { return new Pattern[] { Pattern.compile("^.+\\.jar$") }; } @@ -152,33 +150,29 @@ public class GeyserExtensionLoader implements ExtensionLoader { } } - public void setClass(String name, final Class clazz) { + void setClass(String name, final Class clazz) { if(!classes.containsKey(name)) { classes.put(name,clazz); } } - protected void removeClass(String name) { + void removeClass(String name) { Class clazz = classes.remove(name); } @Override - public void enableExtension(Extension extension) { - if (extension instanceof GeyserExtension) { - if(!extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info("Enabled extension " + extension.description().name()); - ((GeyserExtension) extension).setEnabled(true); - } + public void enableExtension(GeyserExtension extension) { + if (!extension.isEnabled()) { + GeyserImpl.getInstance().getLogger().info("Enabled extension " + extension.description().name()); + extension.setEnabled(true); } } @Override - public void disableExtension(Extension extension) { - if (extension instanceof GeyserExtension) { - if(extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info("Disabled extension " + extension.description().name()); - ((GeyserExtension) extension).setEnabled(false); - } + public void disableExtension(GeyserExtension extension) { + if (extension.isEnabled()) { + GeyserImpl.getInstance().getLogger().info("Disabled extension " + extension.description().name()); + extension.setEnabled(false); } } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index c06feba1e..edda15ade 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -26,9 +26,9 @@ package org.geysermc.geyser.extension; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.GeyserExtension; + import java.io.File; import java.lang.reflect.Constructor; import java.util.*; @@ -37,35 +37,34 @@ import java.util.regex.Pattern; public class GeyserExtensionManager { private static GeyserExtensionManager geyserExtensionManager = null; - protected Map extensions = new LinkedHashMap<>(); + protected Map extensions = new LinkedHashMap<>(); protected Map fileAssociations = new HashMap<>(); public static void init() { GeyserImpl.getInstance().getLogger().info("Loading extensions..."); + geyserExtensionManager = new GeyserExtensionManager(); geyserExtensionManager.registerInterface(GeyserExtensionLoader.class); geyserExtensionManager.loadExtensions(new File("extensions")); - GeyserImpl.getInstance().getLogger().info("Loaded " + geyserExtensionManager.extensions.size() + " extensions."); - for (Extension extension : geyserExtensionManager.getExtensions().values()) { - if (!extension.isEnabled()) { - geyserExtensionManager.enableExtension(extension); - } - } + String plural = geyserExtensionManager.extensions.size() == 1 ? "" : "s"; + GeyserImpl.getInstance().getLogger().info("Loaded " + geyserExtensionManager.extensions.size() + " extension" + plural); + + geyserExtensionManager.enableExtensions(); } public static GeyserExtensionManager getExtensionManager() { return geyserExtensionManager; } - public Extension getExtension(String name) { + public GeyserExtension getExtension(String name) { if (this.extensions.containsKey(name)) { return this.extensions.get(name); } return null; } - public Map getExtensions() { + public Map getExtensions() { return this.extensions; } @@ -124,8 +123,8 @@ public class GeyserExtensionManager { return null; } - public Map loadExtensions(File dictionary) { - if (GeyserImpl.VERSION.equalsIgnoreCase("dev")) { + public Map loadExtensions(File dictionary) { + if (GeyserImpl.VERSION.equalsIgnoreCase("dev")) { // If your IDE says this is always true, ignore it, it isn't. GeyserImpl.getInstance().getLogger().error("Cannot load extensions in a development environment, aborting extension loading"); return new HashMap<>(); } @@ -134,6 +133,8 @@ public class GeyserExtensionManager { return new HashMap<>(); } + String[] apiVersion = GeyserImpl.VERSION.split("\\."); + if (!dictionary.exists()) { dictionary.mkdir(); } @@ -142,7 +143,7 @@ public class GeyserExtensionManager { } Map extensions = new LinkedHashMap<>(); - Map loadedExtensions = new LinkedHashMap<>(); + Map loadedExtensions = new LinkedHashMap<>(); for (final GeyserExtensionLoader loader : this.fileAssociations.values()) { for (File file : dictionary.listFiles((dir, name) -> { @@ -167,47 +168,35 @@ public class GeyserExtensionManager { continue; } - boolean compatible = false; - - for (String version : description.ApiVersions()) { - try { - //Check the format: majorVersion.minorVersion.patch - if (!Pattern.matches("^[0-9]+\\.[0-9]+\\.[0-9]+$", version)) { - throw new IllegalArgumentException(); - } - } catch (NullPointerException | IllegalArgumentException e) { - GeyserImpl.getInstance().getLogger().error("Could't load extension " + name + ": Wrong API format"); - continue; + try { + //Check the format: majorVersion.minorVersion.patch + if (!Pattern.matches("^[0-9]+\\.[0-9]+\\.[0-9]+$", description.ApiVersion())) { + throw new IllegalArgumentException(); } - - String[] versionArray = version.split("\\."); - String[] apiVersion = GeyserImpl.VERSION.split("\\."); - - //Completely different API version - if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); - continue; - } - - //If the extension requires new API features, being backwards compatible - if (Integer.parseInt(versionArray[1]) > Integer.parseInt(apiVersion[1])) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); - continue; - } - - compatible = true; - break; + } catch (NullPointerException | IllegalArgumentException e) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version format, should be 'majorVersion.minorVersion.patch', current version: " + apiVersion[0] + "." + apiVersion[1]); + continue; } - if (!compatible) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name +": Incompatible API version"); + String[] versionArray = description.ApiVersion().split("\\."); + + //Completely different API version + if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); + continue; + } + + //If the extension requires new API features, being backwards compatible + if (Integer.parseInt(versionArray[1]) > Integer.parseInt(apiVersion[1])) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); + continue; } extensions.put(name, file); loadedExtensions.put(name, this.loadExtension(file, this.fileAssociations)); } } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Couldn't load " +file.getName()+ " in folder " + dictionary + ": ", e); + GeyserImpl.getInstance().getLogger().error("Couldn't load " + file.getName() + " in folder " + dictionary.getAbsolutePath() + ": ", e); } } } @@ -215,7 +204,7 @@ public class GeyserExtensionManager { return loadedExtensions; } - public void enableExtension(Extension extension) { + public void enableExtension(GeyserExtension extension) { if (!extension.isEnabled()) { try { extension.extensionLoader().enableExtension(extension); @@ -226,7 +215,7 @@ public class GeyserExtensionManager { } } - public void disableExtension(Extension extension) { + public void disableExtension(GeyserExtension extension) { if (extension.isEnabled()) { try { extension.extensionLoader().disableExtension(extension); @@ -236,8 +225,14 @@ public class GeyserExtensionManager { } } + public void enableExtensions() { + for (GeyserExtension extension : this.getExtensions().values()) { + this.enableExtension(extension); + } + } + public void disableExtensions() { - for (Extension extension : this.getExtensions().values()) { + for (GeyserExtension extension : this.getExtensions().values()) { this.disableExtension(extension); } } From f3a331981fdf26afbc61b38709a27aa1e2a0a395 Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Wed, 12 Jan 2022 15:31:28 +0100 Subject: [PATCH 4/8] Added extension dump data & make plugins be enabled on reload --- .../api/extension/ExtensionDescription.java | 5 +++- .../geyser/api/extension/ExtensionLoader.java | 3 +++ .../geyser/api/extension/ExtensionLogger.java | 3 +++ .../geyser/api/extension/GeyserExtension.java | 3 +++ .../java/org/geysermc/geyser/GeyserImpl.java | 3 ++- .../org/geysermc/geyser/dump/DumpInfo.java | 24 +++++++++++++++---- .../extension/GeyserExtensionDescription.java | 2 +- .../extension/GeyserExtensionManager.java | 6 ++--- 8 files changed, 39 insertions(+), 10 deletions(-) diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java index d32300e09..4426a4a92 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java @@ -27,6 +27,9 @@ package org.geysermc.geyser.api.extension; import java.util.List; +/** + * This is the Geyer extension description + */ public interface ExtensionDescription { /** * Gets the extension's name @@ -47,7 +50,7 @@ public interface ExtensionDescription { * * @return the extension's api version */ - String ApiVersion(); + String apiVersion(); /** * Gets the extension's description diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java index 291a34daf..1301493d5 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java @@ -29,6 +29,9 @@ import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; import java.io.File; +/** + * The extension loader is responsible for loading, unloading, enabling and disabling extensions + */ public interface ExtensionLoader { /** * Loads an extension from a given file diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java index 60ee45572..17e108455 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java @@ -25,6 +25,9 @@ package org.geysermc.geyser.api.extension; +/** + * This is the Geyser extension logger + */ public interface ExtensionLogger { /** * Get the logger prefix diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java index a3f911580..210452c3c 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java @@ -30,6 +30,9 @@ import java.io.*; import java.net.URL; import java.net.URLConnection; +/** + * This class is to be extended by a Geyser extension + */ public class GeyserExtension { private boolean initialized = false; private boolean enabled = false; diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 7e61b3af7..b563892cc 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -460,7 +460,7 @@ public class GeyserImpl implements GeyserApi { ResourcePack.PACKS.clear(); - GeyserExtensionManager.getExtensionManager().disableExtensions(); + GeyserExtensionManager.getInstance().disableExtensions(); bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); } @@ -468,6 +468,7 @@ public class GeyserImpl implements GeyserApi { @Override public void reload() { shutdown(); + GeyserExtensionManager.getInstance().enableExtensions(); bootstrap.onEnable(); } diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 2734c7443..316f095c0 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -36,6 +36,8 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.AllArgsConstructor; import lombok.Getter; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.extension.GeyserExtension; +import org.geysermc.geyser.extension.GeyserExtensionManager; import org.geysermc.geyser.text.AsteriskSerializer; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.network.MinecraftProtocol; @@ -54,10 +56,7 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.util.*; import java.util.stream.Collectors; @Getter @@ -76,6 +75,7 @@ public class DumpInfo { private LogsInfo logsInfo; private final BootstrapDumpInfo bootstrapInfo; private final FlagsInfo flagsInfo; + private final List extensionInfo; public DumpInfo(boolean addLog) { this.versionInfo = new VersionInfo(); @@ -125,6 +125,11 @@ public class DumpInfo { this.bootstrapInfo = GeyserImpl.getInstance().getBootstrap().getDumpInfo(); this.flagsInfo = new FlagsInfo(); + + this.extensionInfo = new ArrayList<>(); + for (GeyserExtension extension : GeyserExtensionManager.getInstance().getExtensions().values()) { + this.extensionInfo.add(new ExtensionInfo(extension.isEnabled(), extension.name(), extension.description().version(), extension.description().main(), extension.description().authors(), extension.description().apiVersion())); + } } @Getter @@ -277,4 +282,15 @@ public class DumpInfo { this.flags = ManagementFactory.getRuntimeMXBean().getInputArguments(); } } + + @Getter + @AllArgsConstructor + public static class ExtensionInfo { + public boolean enabled; + public String name; + public String version; + public String main; + public List authors; + public String apiVersion; + } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index e2a09c598..228b88426 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -85,7 +85,7 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten } @Override - public String ApiVersion() { + public String apiVersion() { return api; } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index edda15ade..db0515906 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -53,7 +53,7 @@ public class GeyserExtensionManager { geyserExtensionManager.enableExtensions(); } - public static GeyserExtensionManager getExtensionManager() { + public static GeyserExtensionManager getInstance() { return geyserExtensionManager; } @@ -170,7 +170,7 @@ public class GeyserExtensionManager { try { //Check the format: majorVersion.minorVersion.patch - if (!Pattern.matches("^[0-9]+\\.[0-9]+\\.[0-9]+$", description.ApiVersion())) { + if (!Pattern.matches("^[0-9]+\\.[0-9]+\\.[0-9]+$", description.apiVersion())) { throw new IllegalArgumentException(); } } catch (NullPointerException | IllegalArgumentException e) { @@ -178,7 +178,7 @@ public class GeyserExtensionManager { continue; } - String[] versionArray = description.ApiVersion().split("\\."); + String[] versionArray = description.apiVersion().split("\\."); //Completely different API version if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { From cb18c969d7f2cb1e8e2f18bc708caf80c6f5d61d Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Wed, 12 Jan 2022 15:32:49 +0100 Subject: [PATCH 5/8] I forgot the "s" in Geyser --- .../org/geysermc/geyser/api/extension/ExtensionDescription.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java index 4426a4a92..487df3926 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.api.extension; import java.util.List; /** - * This is the Geyer extension description + * This is the Geyser extension description */ public interface ExtensionDescription { /** From 8bb8e48a55050dbeff523ad2568f322d3382b632 Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Wed, 12 Jan 2022 16:40:51 +0100 Subject: [PATCH 6/8] Fixed what Konicai asked --- .../geyser/api/extension/GeyserExtension.java | 4 +-- .../java/org/geysermc/geyser/GeyserImpl.java | 14 +++++++-- .../org/geysermc/geyser/dump/DumpInfo.java | 6 ++-- .../extension/GeyserExtensionClassLoader.java | 6 ++-- .../extension/GeyserExtensionDescription.java | 29 +++++++++++++++++++ .../extension/GeyserExtensionLoader.java | 18 ++---------- .../extension/GeyserExtensionManager.java | 19 +++--------- 7 files changed, 53 insertions(+), 43 deletions(-) diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java index 210452c3c..bd53bafd3 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java @@ -75,9 +75,7 @@ public class GeyserExtension { } /** - * Gets if the extension is enabled - * - * @return true if the extension is enabled + * Enables or disables the extension */ public void setEnabled(boolean value) { if (this.enabled != value) { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index b563892cc..2fbcbaddd 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -123,6 +123,8 @@ public class GeyserImpl implements GeyserApi { private final PlatformType platformType; private final GeyserBootstrap bootstrap; + private final GeyserExtensionManager extensionManager; + private Metrics metrics; private static GeyserImpl instance; @@ -155,7 +157,8 @@ public class GeyserImpl implements GeyserApi { MessageTranslator.init(); MinecraftLocale.init(); - GeyserExtensionManager.init(); + extensionManager = new GeyserExtensionManager(); + extensionManager.init(); start(); @@ -200,6 +203,8 @@ public class GeyserImpl implements GeyserApi { ResourcePack.loadPacks(); + extensionManager.enableExtensions(); + if (platformType != PlatformType.STANDALONE && config.getRemote().getAddress().equals("auto")) { // Set the remote address to localhost since that is where we are always connecting try { @@ -460,7 +465,7 @@ public class GeyserImpl implements GeyserApi { ResourcePack.PACKS.clear(); - GeyserExtensionManager.getInstance().disableExtensions(); + extensionManager.disableExtensions(); bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); } @@ -468,7 +473,6 @@ public class GeyserImpl implements GeyserApi { @Override public void reload() { shutdown(); - GeyserExtensionManager.getInstance().enableExtensions(); bootstrap.onEnable(); } @@ -514,6 +518,10 @@ public class GeyserImpl implements GeyserApi { return bootstrap.getWorldManager(); } + public GeyserExtensionManager getExtensionManager() { + return extensionManager; + } + public static GeyserImpl getInstance() { return instance; } diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 316f095c0..3377f7ee5 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -127,8 +127,8 @@ public class DumpInfo { this.flagsInfo = new FlagsInfo(); this.extensionInfo = new ArrayList<>(); - for (GeyserExtension extension : GeyserExtensionManager.getInstance().getExtensions().values()) { - this.extensionInfo.add(new ExtensionInfo(extension.isEnabled(), extension.name(), extension.description().version(), extension.description().main(), extension.description().authors(), extension.description().apiVersion())); + for (GeyserExtension extension : GeyserImpl.getInstance().getExtensionManager().getExtensions().values()) { + this.extensionInfo.add(new ExtensionInfo(extension.isEnabled(), extension.name(), extension.description().version(), extension.description().apiVersion(), extension.description().main(), extension.description().authors())); } } @@ -289,8 +289,8 @@ public class DumpInfo { public boolean enabled; public String name; public String version; + public String apiVersion; public String main; public List authors; - public String apiVersion; } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java index a1ccc063e..3ce0a00ae 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java @@ -78,11 +78,11 @@ public class GeyserExtensionClassLoader extends URLClassLoader { throw new ClassNotFoundException(name); } Class result = classes.get(name); - if(result == null) { - if(checkGlobal) { + if (result == null) { + if (checkGlobal) { result = loader.classByName(name); } - if(result == null) { + if (result == null) { result = super.findClass(name); if (result != null) { loader.setClass(name, result); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index 228b88426..31d6c3a46 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -28,6 +28,10 @@ package org.geysermc.geyser.extension; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.*; public class GeyserExtensionDescription implements org.geysermc.geyser.api.extension.ExtensionDescription { @@ -37,7 +41,32 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten private String version; private final List authors = new ArrayList<>(); + public GeyserExtensionDescription(InputStream inputStream) throws InvalidDescriptionException { + try { + InputStreamReader reader = new InputStreamReader(inputStream); + StringBuilder builder = new StringBuilder(); + String temp; + BufferedReader bufferedReader = new BufferedReader(reader); + temp = bufferedReader.readLine(); + while (temp != null) { + if (builder.length() != 0) { + builder.append("\n"); + } + builder.append(temp); + temp = bufferedReader.readLine(); + } + + this.loadString(builder.toString()); + } catch (IOException e) { + throw new InvalidDescriptionException(e); + } + } + public GeyserExtensionDescription(String yamlString) throws InvalidDescriptionException { + this.loadString(yamlString); + } + + private void loadString(String yamlString) throws InvalidDescriptionException { DumperOptions dumperOptions = new DumperOptions(); dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); Yaml yaml = new Yaml(dumperOptions); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index a7e4bac3d..cffd513a1 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -97,21 +97,7 @@ public class GeyserExtensionLoader implements ExtensionLoader { } stream = jarFile.getInputStream(descriptionEntry); - - InputStreamReader reader = new InputStreamReader(stream); - StringBuilder builder = new StringBuilder(); - String temp; - BufferedReader bufferedReader = new BufferedReader(reader); - temp = bufferedReader.readLine(); - while (temp != null) { - if (builder.length() != 0) { - builder.append("\n"); - } - builder.append(temp); - temp = bufferedReader.readLine(); - } - - return new GeyserExtensionDescription(builder.toString()); + return new GeyserExtensionDescription(stream); } catch (IOException e) { throw new InvalidDescriptionException(e); } finally { @@ -151,7 +137,7 @@ public class GeyserExtensionLoader implements ExtensionLoader { } void setClass(String name, final Class clazz) { - if(!classes.containsKey(name)) { + if (!classes.containsKey(name)) { classes.put(name,clazz); } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index db0515906..6dcfca0b5 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -28,33 +28,22 @@ package org.geysermc.geyser.extension; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.GeyserExtension; - import java.io.File; import java.lang.reflect.Constructor; import java.util.*; import java.util.regex.Pattern; public class GeyserExtensionManager { - private static GeyserExtensionManager geyserExtensionManager = null; - protected Map extensions = new LinkedHashMap<>(); protected Map fileAssociations = new HashMap<>(); - public static void init() { + public void init() { GeyserImpl.getInstance().getLogger().info("Loading extensions..."); - geyserExtensionManager = new GeyserExtensionManager(); - geyserExtensionManager.registerInterface(GeyserExtensionLoader.class); - geyserExtensionManager.loadExtensions(new File("extensions")); + this.registerInterface(GeyserExtensionLoader.class); + this.loadExtensions(new File("extensions")); - String plural = geyserExtensionManager.extensions.size() == 1 ? "" : "s"; - GeyserImpl.getInstance().getLogger().info("Loaded " + geyserExtensionManager.extensions.size() + " extension" + plural); - - geyserExtensionManager.enableExtensions(); - } - - public static GeyserExtensionManager getInstance() { - return geyserExtensionManager; + GeyserImpl.getInstance().getLogger().info("Loaded " + this.extensions.size() + " extension(s)"); } public GeyserExtension getExtension(String name) { From f8c173aae8ed9ba70443b04ea3f48c6b5a4b2ed3 Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Wed, 12 Jan 2022 16:47:25 +0100 Subject: [PATCH 7/8] Actually did what Konicai wanted --- .../extension/GeyserExtensionDescription.java | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index 31d6c3a46..b14291b01 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -42,28 +42,10 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten private final List authors = new ArrayList<>(); public GeyserExtensionDescription(InputStream inputStream) throws InvalidDescriptionException { - try { - InputStreamReader reader = new InputStreamReader(inputStream); - StringBuilder builder = new StringBuilder(); - String temp; - BufferedReader bufferedReader = new BufferedReader(reader); - temp = bufferedReader.readLine(); - while (temp != null) { - if (builder.length() != 0) { - builder.append("\n"); - } - builder.append(temp); - temp = bufferedReader.readLine(); - } - - this.loadString(builder.toString()); - } catch (IOException e) { - throw new InvalidDescriptionException(e); - } - } - - public GeyserExtensionDescription(String yamlString) throws InvalidDescriptionException { - this.loadString(yamlString); + DumperOptions dumperOptions = new DumperOptions(); + dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml yaml = new Yaml(dumperOptions); + this.loadMap(yaml.loadAs(inputStream, LinkedHashMap.class)); } private void loadString(String yamlString) throws InvalidDescriptionException { From 0ccd85ccfbb0735844503639ca994a69cbe3bb5b Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Wed, 12 Jan 2022 18:43:10 +0100 Subject: [PATCH 8/8] Use Geyser locale for log messages --- .../extension/GeyserExtensionClassLoader.java | 6 ++--- .../extension/GeyserExtensionDescription.java | 10 -------- .../extension/GeyserExtensionLoader.java | 7 +++--- .../extension/GeyserExtensionLogger.java | 4 +-- .../extension/GeyserExtensionManager.java | 25 ++++++++++--------- core/src/main/resources/languages | 2 +- core/src/main/resources/mappings | 2 +- 7 files changed, 24 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java index 3ce0a00ae..67363a40f 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java @@ -37,8 +37,8 @@ import java.util.Map; import java.util.Set; public class GeyserExtensionClassLoader extends URLClassLoader { - private GeyserExtensionLoader loader; - private Map classes = new HashMap<>(); + private final GeyserExtensionLoader loader; + private final Map classes = new HashMap<>(); public GeyserExtension extension; public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, ExtensionDescription description, File file) throws InvalidExtensionException, MalformedURLException { @@ -74,7 +74,7 @@ public class GeyserExtensionClassLoader extends URLClassLoader { } protected Class findClass(String name, boolean checkGlobal) throws ClassNotFoundException { - if (name.startsWith("org.geysermc.geyser.") || name.startsWith("org.geysermc.connector.") || name.startsWith("net.minecraft.")) { + if (name.startsWith("org.geysermc.geyser.") || name.startsWith("org.geysermc.connector.") || name.startsWith("org.geysermc.platform.") || name.startsWith("org.geysermc.floodgate.") || name.startsWith("org.geysermc.api.") || name.startsWith("org.geysermc.processor.") || name.startsWith("net.minecraft.")) { throw new ClassNotFoundException(name); } Class result = classes.get(name); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index b14291b01..f8a3d9bbe 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -28,10 +28,7 @@ package org.geysermc.geyser.extension; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; -import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.util.*; public class GeyserExtensionDescription implements org.geysermc.geyser.api.extension.ExtensionDescription { @@ -48,13 +45,6 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten this.loadMap(yaml.loadAs(inputStream, LinkedHashMap.class)); } - private void loadString(String yamlString) throws InvalidDescriptionException { - DumperOptions dumperOptions = new DumperOptions(); - dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - Yaml yaml = new Yaml(dumperOptions); - this.loadMap(yaml.loadAs(yamlString, LinkedHashMap.class)); - } - private void loadMap(Map yamlMap) throws InvalidDescriptionException { this.name = ((String) yamlMap.get("name")).replaceAll("[^A-Za-z0-9 _.-]", ""); if (this.name.equals("")) { diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index cffd513a1..f029eb797 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -31,6 +31,7 @@ import org.geysermc.geyser.api.extension.ExtensionLoader; import org.geysermc.geyser.api.extension.GeyserExtension; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; +import org.geysermc.geyser.text.GeyserLocale; import java.io.*; import java.util.HashMap; import java.util.Map; @@ -143,13 +144,13 @@ public class GeyserExtensionLoader implements ExtensionLoader { } void removeClass(String name) { - Class clazz = classes.remove(name); + classes.remove(name); } @Override public void enableExtension(GeyserExtension extension) { if (!extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info("Enabled extension " + extension.description().name()); + GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.enable.success", extension.description().name())); extension.setEnabled(true); } } @@ -157,7 +158,7 @@ public class GeyserExtensionLoader implements ExtensionLoader { @Override public void disableExtension(GeyserExtension extension) { if (extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info("Disabled extension " + extension.description().name()); + GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.disable.success", extension.description().name())); extension.setEnabled(false); } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLogger.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLogger.java index 225d6cda3..fe23417f8 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLogger.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLogger.java @@ -29,8 +29,8 @@ import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.api.extension.ExtensionLogger; public class GeyserExtensionLogger implements ExtensionLogger { - private GeyserLogger logger; - private String loggerPrefix; + private final GeyserLogger logger; + private final String loggerPrefix; public GeyserExtensionLogger(GeyserLogger logger, String prefix) { this.logger = logger; diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index 6dcfca0b5..169053182 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.extension; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.GeyserExtension; +import org.geysermc.geyser.text.GeyserLocale; import java.io.File; import java.lang.reflect.Constructor; import java.util.*; @@ -38,12 +39,12 @@ public class GeyserExtensionManager { protected Map fileAssociations = new HashMap<>(); public void init() { - GeyserImpl.getInstance().getLogger().info("Loading extensions..."); + GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.load.loading")); this.registerInterface(GeyserExtensionLoader.class); this.loadExtensions(new File("extensions")); - GeyserImpl.getInstance().getLogger().info("Loaded " + this.extensions.size() + " extension(s)"); + GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.load.done", this.extensions.size())); } public GeyserExtension getExtension(String name) { @@ -102,7 +103,7 @@ public class GeyserExtensionManager { } } } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Could not load extension", e); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed"), e); return null; } } @@ -114,11 +115,11 @@ public class GeyserExtensionManager { public Map loadExtensions(File dictionary) { if (GeyserImpl.VERSION.equalsIgnoreCase("dev")) { // If your IDE says this is always true, ignore it, it isn't. - GeyserImpl.getInstance().getLogger().error("Cannot load extensions in a development environment, aborting extension loading"); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_dev_environment")); return new HashMap<>(); } if (!GeyserImpl.VERSION.contains(".")) { - GeyserImpl.getInstance().getLogger().error("Something went wrong with the Geyser version number, aborting extension loading"); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_version_number")); return new HashMap<>(); } @@ -153,7 +154,7 @@ public class GeyserExtensionManager { String name = description.name(); if (extensions.containsKey(name) || this.getExtension(name) != null) { - GeyserImpl.getInstance().getLogger().warning("Found duplicate extension '" + name + "', ignoring '" + file.getName() + "'"); + GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, file.getName())); continue; } @@ -163,7 +164,7 @@ public class GeyserExtensionManager { throw new IllegalArgumentException(); } } catch (NullPointerException | IllegalArgumentException e) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version format, should be 'majorVersion.minorVersion.patch', current version: " + apiVersion[0] + "." + apiVersion[1]); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion[0] + "." + apiVersion[1])); continue; } @@ -171,13 +172,13 @@ public class GeyserExtensionManager { //Completely different API version if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, apiVersion[0] + "." + apiVersion[1])); continue; } //If the extension requires new API features, being backwards compatible if (Integer.parseInt(versionArray[1]) > Integer.parseInt(apiVersion[1])) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, apiVersion[0] + "." + apiVersion[1])); continue; } @@ -185,7 +186,7 @@ public class GeyserExtensionManager { loadedExtensions.put(name, this.loadExtension(file, this.fileAssociations)); } } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Couldn't load " + file.getName() + " in folder " + dictionary.getAbsolutePath() + ": ", e); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", file.getName(), dictionary.getAbsolutePath()), e); } } } @@ -198,7 +199,7 @@ public class GeyserExtensionManager { try { extension.extensionLoader().enableExtension(extension); } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Error enabling extension " + extension.name() + ": ", e); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.enable.failed", extension.name()), e); this.disableExtension(extension); } } @@ -209,7 +210,7 @@ public class GeyserExtensionManager { try { extension.extensionLoader().disableExtension(extension); } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Error disabling extension " + extension.name() + ": ", e); + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.disable.failed", extension.name()), e); } } } diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 1a50238c1..94c185193 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 1a50238c1c743579a1dbd93c57d02b5da3be14fa +Subproject commit 94c1851931f2319a7e7f42c2fe9066b78235bc39 diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 82ad7ba27..b60cfcdd4 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 82ad7ba279c68eb11a0b1a969c9efb3228c59227 +Subproject commit b60cfcdd40cd58a93143b489fc9153a347e48c41