Slight cleanups and make Extension an interface

This commit is contained in:
RednedEpic 2022-01-15 16:27:35 -06:00
parent 142bb95c06
commit 778f004d99
18 changed files with 708 additions and 586 deletions

View file

@ -6,6 +6,7 @@
<groupId>org.geysermc</groupId>
<artifactId>api-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -14,6 +15,8 @@
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<adventure.version>4.9.3</adventure.version>
</properties>
<dependencies>
@ -23,6 +26,12 @@
<version>3.19.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
<version>${adventure.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.geysermc</groupId>
<artifactId>base-api</artifactId>

View file

@ -27,8 +27,10 @@ package org.geysermc.geyser.api;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.api.Geyser;
import org.geysermc.api.GeyserApiBase;
import org.geysermc.geyser.api.connection.GeyserConnection;
import org.geysermc.geyser.api.extension.ExtensionManager;
import java.util.List;
import java.util.UUID;
@ -78,4 +80,20 @@ public interface GeyserApi extends GeyserApiBase {
*/
@NonNull
List<? extends GeyserConnection> onlineConnections();
/**
* Gets the {@link ExtensionManager}.
*
* @return the extension manager
*/
ExtensionManager extensionManager();
/**
* Gets the current {@link GeyserApiBase} instance.
*
* @return the current geyser api instance
*/
static GeyserApi api() {
return Geyser.api(GeyserApi.class);
}
}

View file

@ -0,0 +1,136 @@
/*
* 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 org.geysermc.geyser.api.GeyserApi;
import java.nio.file.Path;
/**
* Represents an extension within Geyser.
*/
public interface Extension {
/**
* Called when the extension is loaded
*/
default void onLoad() {
}
/**
* Called when the extension is enabled
*/
default void onEnable() {
}
/**
* Called when the extension is disabled
*/
default void onDisable() {
}
/**
* Gets if the extension is enabled
*
* @return true if the extension is enabled
*/
default boolean isEnabled() {
return this.extensionLoader().isEnabled(this);
}
/**
* Enables or disables the extension
*
* @param enabled if the extension should be enabled
*/
default void setEnabled(boolean enabled) {
this.extensionLoader().setEnabled(this, enabled);
}
/**
* Gets the extension's data folder
*
* @return the extension's data folder
*/
default Path dataFolder() {
return this.extensionLoader().dataFolder(this);
}
/**
* Gets the {@link ExtensionManager}.
*
* @return the extension manager
*/
default ExtensionManager extensionManager() {
return this.geyserApi().extensionManager();
}
/**
* Gets the extension's name
*
* @return the extension's name
*/
default String name() {
return this.description().name();
}
/**
* Gets this extension's {@link ExtensionDescription}.
*
* @return the extension's description
*/
default ExtensionDescription description() {
return this.extensionLoader().description(this);
}
/**
* Gets the extension's logger
*
* @return the extension's logger
*/
default ExtensionLogger logger() {
return this.extensionLoader().logger(this);
}
/**
* Gets the {@link ExtensionLoader}.
*
* @return the extension loader
*/
default ExtensionLoader extensionLoader() {
return this.extensionManager().extensionLoader(this);
}
/**
* Gets the {@link GeyserApiBase} instance
*
* @return the geyser api instance
*/
default GeyserApi geyserApi() {
return GeyserApi.api();
}
}

View file

@ -25,17 +25,21 @@
package org.geysermc.geyser.api.extension;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
/**
* This is the Geyser extension description
*/
public interface ExtensionDescription {
/**
* Gets the extension's name
*
* @return the extension's name
*/
@NonNull
String name();
/**
@ -43,6 +47,7 @@ public interface ExtensionDescription {
*
* @return the extension's main class
*/
@NonNull
String main();
/**
@ -50,6 +55,7 @@ public interface ExtensionDescription {
*
* @return the extension's api version
*/
@NonNull
String apiVersion();
/**
@ -57,6 +63,7 @@ public interface ExtensionDescription {
*
* @return the extension's description
*/
@NonNull
String version();
/**
@ -64,5 +71,6 @@ public interface ExtensionDescription {
*
* @return the extension's authors
*/
@NonNull
List<String> authors();
}

View file

@ -25,52 +25,72 @@
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 org.checkerframework.checker.nullness.qual.NonNull;
import java.nio.file.Path;
/**
* The extension loader is responsible for loading, unloading, enabling and disabling extensions
*/
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;
public abstract class ExtensionLoader {
/**
* Gets an extension's description from a given file
* Gets if the given {@link Extension} is enabled.
*
* @param file the file to get the description from
* @return the extension's description
* @throws InvalidDescriptionException
* @param extension the extension
* @return if the extension is enabled
*/
ExtensionDescription extensionDescription(File file) throws InvalidDescriptionException;
protected abstract boolean isEnabled(@NonNull Extension extension);
/**
* 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;
/**
* Enables an extension
* Sets if the given {@link Extension} is enabled.
*
* @param extension the extension to enable
* @param enabled if the extension should be enabled
*/
void enableExtension(GeyserExtension extension);
protected abstract void setEnabled(@NonNull Extension extension, boolean enabled);
/**
* Disables an extension
* Gets the given {@link Extension}'s data folder.
*
* @param extension the extension to disable
* @param extension the extension
* @return the data folder of the given extension
*/
void disableExtension(GeyserExtension extension);
}
@NonNull
protected abstract Path dataFolder(@NonNull Extension extension);
/**
* Gets the given {@link Extension}'s {@link ExtensionDescription}.
*
* @param extension the extension
* @return the description of the given extension
*/
@NonNull
protected abstract ExtensionDescription description(@NonNull Extension extension);
/**
* Gets the {@link ExtensionLogger} for the given {@link Extension}.
*
* @param extension the extension
* @return the extension logger for the given extension
*/
@NonNull
protected abstract ExtensionLogger logger(@NonNull Extension extension);
/**
* Loads all extensions.
*
* @param extensionManager the extension manager
*/
protected abstract void loadAllExtensions(@NonNull ExtensionManager extensionManager);
/**
* Registers the given {@link Extension} with the given {@link ExtensionManager}.
*
* @param extension the extension
* @param extensionManager the extension manager
*/
protected void register(@NonNull Extension extension, @NonNull ExtensionManager extensionManager) {
extensionManager.register(extension, this);
}
}

View file

@ -0,0 +1,120 @@
/*
* 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 net.kyori.adventure.key.Key;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Map;
/**
* Manages Geyser {@link Extension}s
*/
public abstract class ExtensionManager {
/**
* Gets an extension with the given name.
*
* @param name the name of the extension
* @return an extension with the given name
*/
@Nullable
public abstract Extension extension(@NotNull String name);
/**
* Enables the given {@link Extension}.
*
* @param extension the extension to enable
*/
public abstract void enable(@NonNull Extension extension);
/**
* Disables the given {@link Extension}.
*
* @param extension the extension to disable
*/
public abstract void disable(@NonNull Extension extension);
/**
* Gets the {@link ExtensionLoader} responsible for loading
* the given {@link Extension}.
*
* @return the extension loader for loading the given extension
*/
@Nullable
public abstract ExtensionLoader extensionLoader(@NotNull Extension extension);
/**
* Gets all the {@link Extension}s currently loaded.
*
* @return all the extensions currently loaded
*/
@NonNull
public abstract Collection<Extension> extensions();
/**
* Gets the {@link ExtensionLoader} with the given identifier.
*
* @param identifier the identifier
* @return the extension loader at the given identifier
*/
@Nullable
public abstract ExtensionLoader extensionLoader(@NonNull Key identifier);
/**
* Registers an {@link ExtensionLoader} with the given identifier.
*
* @param identifier the identifier
* @param extensionLoader the extension loader
*/
public abstract void registerExtensionLoader(@NonNull Key identifier, @NotNull ExtensionLoader extensionLoader);
/**
* Gets all the currently registered {@link ExtensionLoader}s.
*
* @return all the currently registered extension loaders
*/
@NonNull
public abstract Map<Key, ExtensionLoader> extensionLoaders();
/**
* Registers an {@link Extension} with the given {@link ExtensionLoader}.
*
* @param extension the extension
* @param loader the loader
*/
public abstract void register(@NotNull Extension extension, @NotNull ExtensionLoader loader);
/**
* Loads all extensions from the given {@link ExtensionLoader}.
*/
protected final void loadAllExtensions(@NotNull ExtensionLoader extensionLoader) {
extensionLoader.loadAllExtensions(this);
}
}

View file

@ -1,235 +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.*;
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;
private File file = null;
private File dataFolder = null;
private ClassLoader classLoader = null;
private ExtensionLoader loader = null;
private ExtensionLogger logger = null;
private ExtensionDescription description = null;
private GeyserApiBase api = null;
/**
* Called when the extension is loaded
*/
public void onLoad() {
}
/**
* Called when the extension is enabled
*/
public void onEnable() {
}
/**
* Called when the extension is disabled
*/
public void onDisable() {
}
/**
* Gets if the extension is enabled
*
* @return true if the extension is enabled
*/
public boolean isEnabled() {
return this.enabled;
}
/**
* Enables or disables the extension
*/
public void setEnabled(boolean value) {
if (this.enabled != value) {
this.enabled = value;
if (this.enabled) {
onEnable();
} else {
onDisable();
}
}
}
/**
* Gets the extension's data folder
*
* @return the extension's data folder
*/
public File dataFolder() {
return this.dataFolder;
}
/**
* Gets the extension's description
*
* @return the extension's description
*/
public ExtensionDescription description() {
return this.description;
}
/**
* Gets the extension's name
*
* @return the extension's name
*/
public String name() {
return this.description.name();
}
public void init(GeyserApiBase api, ExtensionLoader loader, ExtensionLogger logger, ExtensionDescription description, File dataFolder, File file) {
if (!this.initialized) {
this.initialized = true;
this.file = file;
this.dataFolder = dataFolder;
this.classLoader = this.getClass().getClassLoader();
this.loader = loader;
this.logger = logger;
this.description = description;
this.api = api;
}
}
/**
* 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");
}
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;
}
}
/**
* 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");
}
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.logger.warning("Could not save " + outFile.getName() + " to " + outFile + " because " + outFile.getName() + " already exists.");
}
} catch (IOException ex) {
this.logger.severe("Could not save " + outFile.getName() + " to " + outFile, ex);
}
}
/**
* Gets the extension's class loader
*
* @return the extension's class loader
*/
public ClassLoader classLoader() {
return this.classLoader;
}
/**
* Gets the extension's loader
*
* @return the extension's loader
*/
public ExtensionLoader extensionLoader() {
return this.loader;
}
/**
* Gets the extension's logger
*
* @return the extension's logger
*/
public ExtensionLogger logger() {
return this.logger;
}
/**
* Gets the {@link GeyserApiBase} instance
*
* @return the {@link GeyserApiBase} instance
*/
public GeyserApiBase geyserApi() {
return this.api;
}
}

View file

@ -7,6 +7,7 @@
<groupId>org.geysermc</groupId>
<artifactId>geyser-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>api-parent</artifactId>