Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.github.skriptdev.skript.api.skript.addon;

import com.github.skriptdev.skript.api.utils.Utils;
import com.github.skriptdev.skript.plugin.HySk;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.codec.util.RawJsonReader;
import io.github.syst3ms.skriptparser.log.ErrorType;
import io.github.syst3ms.skriptparser.log.LogEntry;
import io.github.syst3ms.skriptparser.log.SkriptLogger;
import io.github.syst3ms.skriptparser.registration.SkriptAddon;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class AddonLoader {

private final SkriptLogger logger;

public AddonLoader(SkriptLogger logger) {
this.logger = logger;
}

public void loadAddonsFromFolder() {
Path resolve = HySk.getInstance().getDataDirectory().resolve("addons");
File addonFolder = resolve.toFile();
if (!addonFolder.exists()) {
if (!addonFolder.mkdirs()) {
this.logger.error("Failed to create addons folder", ErrorType.STRUCTURE_ERROR);
return;
}
} else if (!addonFolder.isDirectory()) {
this.logger.error("Addons folder is not a directory", ErrorType.STRUCTURE_ERROR);
return;
}
File[] files = addonFolder.listFiles();
if (files == null) {
this.logger.error("Failed to list files in addons folder", ErrorType.STRUCTURE_ERROR);
return;
}

for (File file : Arrays.stream(files)
.filter(File::isFile)
.filter(f -> f.getName().endsWith(".jar"))
.toList()) {
loadAddon(file);
}
}

private void loadAddon(File file) {
try (JarFile jarFile = new JarFile(file)) {
JarEntry jarEntry = jarFile.getJarEntry("manifest.json");
if (jarEntry == null) {
this.logger.error("Manifest.json not found in addon " + file.getName(), ErrorType.STRUCTURE_ERROR);
return;
}

InputStream inputStream = jarFile.getInputStream(jarEntry);
InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
char[] buffer = RawJsonReader.READ_BUFFER.get();
RawJsonReader rawJsonReader = new RawJsonReader(reader, buffer);

Manifest manifest = Manifest.CODEC.decodeJson(rawJsonReader, new ExtraInfo());
if (manifest == null) {
this.logger.error("Failed to decode manifest.json in addon " + file.getName(), ErrorType.STRUCTURE_ERROR);
return;
}

URL[] urls = {file.toURI().toURL()};
URLClassLoader classLoader = new URLClassLoader(urls, HySk.getInstance().getClassLoader());
Class<?> externalClass;
try {
externalClass = classLoader.loadClass(manifest.getMainClass());
} catch (ClassNotFoundException e) {
this.logger.error("Main class not found in addon " + file.getName(), ErrorType.STRUCTURE_ERROR);
return;
}
Object mainClassIntance;
try {
mainClassIntance = externalClass.getDeclaredConstructor(String.class).newInstance(manifest.getName());
} catch (ReflectiveOperationException e) {
this.logger.error("Failed to create instance of addon " + file.getName(), ErrorType.EXCEPTION);
return;
}
if (mainClassIntance instanceof HySkriptAddon addon) {
addon.setManifest(manifest);
addon.setup();
// Finalize registration and logging
for (LogEntry logEntry : addon.getSkriptRegistration().register()) {
Utils.log(null, logEntry);
}
}
} catch (IOException e) {
this.logger.error("Failed to load addon " + file.getName(), ErrorType.EXCEPTION);
}
}

public void shutdownAddons() {
for (SkriptAddon addon : SkriptAddon.getAddons()) {
if (addon instanceof HySkriptAddon hySkriptAddon) {
hySkriptAddon.shutdown();
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.github.skriptdev.skript.api.skript.addon;

import com.hypixel.hytale.server.core.Message;
import io.github.syst3ms.skriptparser.registration.SkriptAddon;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

/**
* Base class for addons for HySkript.
*/
public abstract class HySkriptAddon extends SkriptAddon {

private Manifest manifest;

public HySkriptAddon(String name) {
super(name);
}

/**
* Called when the addon starts to load.
* This is a good time to set up your syntaxes.
*/
abstract public void setup();

/**
* Called when the addon is shutting down.
* This is a good time to clean up resources.
*/
abstract public void shutdown();

final void setManifest(Manifest manifest) {
this.manifest = manifest;
}

public final Manifest getManifest() {
return manifest;
}

public final Message[] getInfo() {
List<Message> info = new ArrayList<>();
info.add(Message.raw("Version: " + this.manifest.getVersion()));

String description = this.manifest.getDescription();
if (description != null) info.add(Message.raw("Description: " + description));

@Nullable String[] authors = this.manifest.getAuthors();
if (authors != null) info.add(Message.raw("Authors: " + String.join(", ", authors)));

String website = this.manifest.getWebsite();
if (website != null) info.add(Message.raw("Website: ").insert(Message.raw(website).link(website)));

return info.toArray(Message[]::new);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.github.skriptdev.skript.api.skript.addon;

import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;

public class Manifest {

private static final BuilderCodec.Builder<Manifest> BUILDER = BuilderCodec.builder(Manifest.class, Manifest::new);
public static final Codec<Manifest> CODEC = BUILDER
.append(new KeyedCodec<>("Main", Codec.STRING),
((manifest, string) -> manifest.mainClass = string),
(manifest -> manifest.mainClass))
.add().append(new KeyedCodec<>("Name", Codec.STRING),
((manifest, string) -> manifest.name = string),
(manifest -> manifest.name))
.add().append(new KeyedCodec<>("Version", Codec.STRING),
((manifest, string) -> manifest.version = string),
(manifest -> manifest.version))
.add().append(new KeyedCodec<>("Description", Codec.STRING),
((manifest, string) -> manifest.description = string),
(manifest -> manifest.description))
.add().append(new KeyedCodec<>("Authors", Codec.STRING_ARRAY),
((manifest, strings) -> manifest.authors = strings),
(manifest -> manifest.authors))
.add().append(new KeyedCodec<>("Website", Codec.STRING),
((manifest, string) -> manifest.website = string),
(manifest -> manifest.website))
.add().build();
private String mainClass;
private String name;
private String version;
private String description;
private String[] authors;
private String website;

public String getMainClass() {
return this.mainClass;
}

public String getName() {
return this.name;
}

public String getVersion() {
return this.version;
}

public String getDescription() {
return this.description;
}

public String[] getAuthors() {
return this.authors;
}

public String getWebsite() {
return this.website;
}

@Override
public String toString() {
return "Manifest{" +
"name='" + name + '\'' +
", version='" + version + '\'' +
", description='" + description + '\'' +
", authors=" + Arrays.toString(authors) +
", website='" + website + '\'' +
'}';
}

}
20 changes: 20 additions & 0 deletions src/main/java/com/github/skriptdev/skript/plugin/Skript.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.skriptdev.skript.plugin;

import com.github.skriptdev.skript.api.skript.ScriptsLoader;
import com.github.skriptdev.skript.api.skript.addon.AddonLoader;
import com.github.skriptdev.skript.api.skript.command.ArgUtils;
import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration;
import com.github.skriptdev.skript.api.skript.variables.JsonVariableStorage;
Expand Down Expand Up @@ -36,6 +37,7 @@ public class Skript extends SkriptAddon {
private final SkriptLogger logger;
private SkriptRegistration registration;
private ElementRegistration elementRegistration;
private AddonLoader addonLoader;
private ScriptsLoader scriptsLoader;

Skript(HySk hySk) {
Expand Down Expand Up @@ -80,6 +82,12 @@ private void setup() {
printSyntaxCount();
Utils.log("HySkript setup complete!");

// LOAD ADDONS
this.logger.info("Loading addons...");
this.addonLoader = new AddonLoader(this.logger);
this.addonLoader.loadAddonsFromFolder();
this.logger.info("Finished loading addons!");

// LOAD VARIABLES
loadVariables();

Expand All @@ -95,6 +103,9 @@ public void shutdown() {
Utils.log("Saving variables...");
Variables.shutdown();
Utils.log("Variable saving complete!");

// SHUTDOWN ADDONS
this.addonLoader.shutdownAddons();
}

private void printSyntaxCount() {
Expand Down Expand Up @@ -194,4 +205,13 @@ public ScriptsLoader getScriptsLoader() {
return this.scriptsLoader;
}

/**
* Get an instance of Skript.
*
* @return Instance of Skript.
*/
public static Skript getInstance() {
return INSTANCE;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.skriptdev.skript.plugin.command;

import com.github.skriptdev.skript.api.skript.addon.HySkriptAddon;
import com.github.skriptdev.skript.api.skript.docs.JsonDocPrinter;
import com.github.skriptdev.skript.api.skript.docs.MarkdownDocPrinter;
import com.github.skriptdev.skript.api.utils.Utils;
Expand All @@ -10,6 +11,7 @@
import com.hypixel.hytale.server.core.command.system.AbstractCommand;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.CommandRegistry;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.command.system.arguments.system.FlagArg;
import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg;
import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg;
Expand Down Expand Up @@ -39,6 +41,7 @@ public SkriptCommand(CommandRegistry registry) {
addAliases("sk");

// Keep these in alphabetical order
addSubCommand(addonsCommand());
addSubCommand(new DocsCommand());
addSubCommand(infoCommand());
addSubCommand(new ReloadCommand());
Expand Down Expand Up @@ -139,6 +142,30 @@ protected CompletableFuture<Void> execute(@NotNull CommandContext commandContext
};
}

private AbstractCommand addonsCommand() {
return new AbstractCommand("addons", "Get info about loaded addons.") {
@Override
protected CompletableFuture<Void> execute(@NotNull CommandContext commandContext) {
return CompletableFuture.runAsync(() -> {
List<SkriptAddon> addons = SkriptAddon.getAddons().stream()
.filter(addon -> !addon.getAddonName().equalsIgnoreCase("skript-parser") && !addon.getAddonName().equalsIgnoreCase("HySkript"))
.toList();
if (addons.isEmpty()) return;
CommandSender sender = commandContext.sender();
Utils.sendMessage(sender, "Loaded Addons:");
addons.forEach(addon -> {
if (addon instanceof HySkriptAddon hySkriptAddon) {
Utils.sendMessage(sender, " - %s:", hySkriptAddon.getAddonName());
for (Message s : hySkriptAddon.getInfo()) {
sender.sendMessage(Message.raw(" ").insert(s));
}
}
});
});
}
};
}

private void printInfo(IMessageReceiver sender) {
Utils.sendMessage(sender, "HySkript Version: %s", HySk.getInstance().getManifest().getVersion());
Utils.sendMessage(sender, "Hytale Version: %s (%s)", ManifestUtil.getImplementationVersion(), ManifestUtil.getPatchline());
Expand Down
Loading