2020-08-18 14:18:12 +02:00
|
|
|
package net.minestom.server.extensions;
|
|
|
|
|
2021-06-08 16:25:46 +02:00
|
|
|
import net.minestom.server.event.Event;
|
|
|
|
import net.minestom.server.event.EventNode;
|
2020-09-12 08:56:01 +02:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2021-05-21 04:26:35 +02:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2020-08-18 14:18:12 +02:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
2021-05-21 04:26:35 +02:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import java.nio.file.Paths;
|
|
|
|
import java.nio.file.StandardCopyOption;
|
2021-06-08 16:25:46 +02:00
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Set;
|
2020-09-12 08:56:01 +02:00
|
|
|
|
2020-08-18 14:18:12 +02:00
|
|
|
public abstract class Extension {
|
2021-03-23 16:35:52 +01:00
|
|
|
/**
|
|
|
|
* List of extensions that depend on this extension.
|
|
|
|
*/
|
|
|
|
protected final Set<String> dependents = new HashSet<>();
|
2021-02-03 20:47:01 +01:00
|
|
|
|
2020-08-18 14:18:12 +02:00
|
|
|
protected Extension() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public void preInitialize() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public abstract void initialize();
|
|
|
|
|
|
|
|
public void postInitialize() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public void preTerminate() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public abstract void terminate();
|
|
|
|
|
|
|
|
public void postTerminate() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-10-25 17:11:59 +02:00
|
|
|
ExtensionClassLoader getExtensionClassLoader() {
|
|
|
|
if (getClass().getClassLoader() instanceof ExtensionClassLoader extensionClassLoader) {
|
|
|
|
return extensionClassLoader;
|
|
|
|
}
|
|
|
|
throw new IllegalStateException("Extension class loader is not an ExtensionClassLoader");
|
|
|
|
}
|
|
|
|
|
2020-10-25 10:41:51 +01:00
|
|
|
@NotNull
|
2021-03-23 16:35:52 +01:00
|
|
|
public DiscoveredExtension getOrigin() {
|
2022-10-25 17:11:59 +02:00
|
|
|
return getExtensionClassLoader().getDiscoveredExtension();
|
2020-08-18 14:18:12 +02:00
|
|
|
}
|
|
|
|
|
2021-03-23 16:35:52 +01:00
|
|
|
/**
|
|
|
|
* Gets the logger for the extension
|
2021-06-08 16:25:46 +02:00
|
|
|
*
|
2021-03-23 16:35:52 +01:00
|
|
|
* @return The logger for the extension
|
|
|
|
*/
|
2020-10-25 10:41:51 +01:00
|
|
|
@NotNull
|
2021-03-24 13:48:37 +01:00
|
|
|
public Logger getLogger() {
|
2022-10-25 17:11:59 +02:00
|
|
|
return getExtensionClassLoader().getLogger();
|
2020-08-18 14:18:12 +02:00
|
|
|
}
|
2020-09-12 08:56:01 +02:00
|
|
|
|
2021-06-08 16:25:46 +02:00
|
|
|
public @NotNull EventNode<Event> getEventNode() {
|
2022-10-25 17:11:59 +02:00
|
|
|
return getExtensionClassLoader().getEventNode();
|
2021-06-08 16:25:46 +02:00
|
|
|
}
|
|
|
|
|
2021-05-21 14:56:30 +02:00
|
|
|
public @NotNull Path getDataDirectory() {
|
2021-05-21 04:26:35 +02:00
|
|
|
return getOrigin().getDataDirectory();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a resource from the extension directory, or from inside the jar if it does not
|
|
|
|
* exist in the extension directory.
|
|
|
|
* <p>
|
|
|
|
* If it does not exist in the extension directory, it will be copied from inside the jar.
|
|
|
|
* <p>
|
|
|
|
* The caller is responsible for closing the returned {@link InputStream}.
|
|
|
|
*
|
|
|
|
* @param fileName The file to read
|
|
|
|
* @return The file contents, or null if there was an issue reading the file.
|
|
|
|
*/
|
2021-05-21 14:56:30 +02:00
|
|
|
public @Nullable InputStream getResource(@NotNull String fileName) {
|
2021-05-21 04:26:35 +02:00
|
|
|
return getResource(Paths.get(fileName));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a resource from the extension directory, or from inside the jar if it does not
|
|
|
|
* exist in the extension directory.
|
|
|
|
* <p>
|
|
|
|
* If it does not exist in the extension directory, it will be copied from inside the jar.
|
|
|
|
* <p>
|
|
|
|
* The caller is responsible for closing the returned {@link InputStream}.
|
|
|
|
*
|
|
|
|
* @param target The file to read
|
|
|
|
* @return The file contents, or null if there was an issue reading the file.
|
|
|
|
*/
|
2021-05-21 14:56:30 +02:00
|
|
|
public @Nullable InputStream getResource(@NotNull Path target) {
|
2021-05-21 04:26:35 +02:00
|
|
|
final Path targetFile = getDataDirectory().resolve(target);
|
|
|
|
try {
|
|
|
|
// Copy from jar if the file does not exist in the extension data directory.
|
|
|
|
if (!Files.exists(targetFile)) {
|
|
|
|
savePackagedResource(target);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Files.newInputStream(targetFile);
|
|
|
|
} catch (IOException ex) {
|
|
|
|
getLogger().info("Failed to read resource {}.", target, ex);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a resource from inside the extension jar.
|
|
|
|
* <p>
|
|
|
|
* The caller is responsible for closing the returned {@link InputStream}.
|
|
|
|
*
|
|
|
|
* @param fileName The file to read
|
|
|
|
* @return The file contents, or null if there was an issue reading the file.
|
|
|
|
*/
|
2021-05-21 14:56:30 +02:00
|
|
|
public @Nullable InputStream getPackagedResource(@NotNull String fileName) {
|
2021-07-08 20:25:10 +02:00
|
|
|
try {
|
2021-11-16 18:23:15 +01:00
|
|
|
final URL url = getOrigin().getClassLoader().getResource(fileName);
|
2021-07-08 20:25:10 +02:00
|
|
|
if (url == null) {
|
|
|
|
getLogger().debug("Resource not found: {}", fileName);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return url.openConnection().getInputStream();
|
|
|
|
} catch (IOException ex) {
|
|
|
|
getLogger().debug("Failed to load resource {}.", fileName, ex);
|
|
|
|
return null;
|
|
|
|
}
|
2021-05-21 04:26:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a resource from inside the extension jar.
|
|
|
|
* <p>
|
|
|
|
* The caller is responsible for closing the returned {@link InputStream}.
|
|
|
|
*
|
|
|
|
* @param target The file to read
|
|
|
|
* @return The file contents, or null if there was an issue reading the file.
|
|
|
|
*/
|
2021-05-21 14:56:30 +02:00
|
|
|
public @Nullable InputStream getPackagedResource(@NotNull Path target) {
|
2021-07-08 20:25:10 +02:00
|
|
|
return getPackagedResource(target.toString().replace('\\', '/'));
|
2021-05-21 04:26:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copies a resource file to the extension directory, replacing any existing copy.
|
|
|
|
*
|
|
|
|
* @param fileName The resource to save
|
|
|
|
* @return True if the resource was saved successfully, null otherwise
|
|
|
|
*/
|
|
|
|
public boolean savePackagedResource(@NotNull String fileName) {
|
|
|
|
return savePackagedResource(Paths.get(fileName));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copies a resource file to the extension directory, replacing any existing copy.
|
|
|
|
*
|
|
|
|
* @param target The resource to save
|
|
|
|
* @return True if the resource was saved successfully, null otherwise
|
|
|
|
*/
|
|
|
|
public boolean savePackagedResource(@NotNull Path target) {
|
|
|
|
final Path targetFile = getDataDirectory().resolve(target);
|
|
|
|
try (InputStream is = getPackagedResource(target)) {
|
|
|
|
if (is == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Files.createDirectories(targetFile.getParent());
|
|
|
|
Files.copy(is, targetFile, StandardCopyOption.REPLACE_EXISTING);
|
|
|
|
return true;
|
|
|
|
} catch (IOException ex) {
|
|
|
|
getLogger().debug("Failed to save resource {}.", target, ex);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-23 16:35:52 +01:00
|
|
|
/**
|
|
|
|
* @return A modifiable list of dependents.
|
|
|
|
*/
|
|
|
|
public Set<String> getDependents() {
|
|
|
|
return dependents;
|
2020-09-12 08:56:01 +02:00
|
|
|
}
|
2020-08-18 14:18:12 +02:00
|
|
|
}
|