fleshed out addon loading

This commit is contained in:
dfsek 2021-02-19 22:49:11 -07:00
parent 5e761c3e29
commit 76f2a3fbc4
20 changed files with 217 additions and 230 deletions

View File

@ -1,11 +0,0 @@
package com.dfsek.terra.addons.annotations.inject;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}

View File

@ -1,5 +1,6 @@
package com.dfsek.terra.api.core.event; package com.dfsek.terra.api.core.event;
import com.dfsek.terra.addons.addon.TerraAddon;
import com.dfsek.terra.api.core.event.events.Event; import com.dfsek.terra.api.core.event.events.Event;
public interface EventManager { public interface EventManager {
@ -10,5 +11,5 @@ public interface EventManager {
*/ */
boolean callEvent(Event event); boolean callEvent(Event event);
void registerListener(EventListener listener); void registerListener(TerraAddon addon, EventListener listener);
} }

View File

@ -1,9 +1,12 @@
package com.dfsek.terra.api.core.event; package com.dfsek.terra.api.core.event;
import com.dfsek.terra.addons.addon.TerraAddon;
import com.dfsek.terra.api.core.TerraPlugin; import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.core.event.annotations.Global;
import com.dfsek.terra.api.core.event.annotations.Priority; import com.dfsek.terra.api.core.event.annotations.Priority;
import com.dfsek.terra.api.core.event.events.Cancellable; import com.dfsek.terra.api.core.event.events.Cancellable;
import com.dfsek.terra.api.core.event.events.Event; import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.api.core.event.events.PackEvent;
import com.dfsek.terra.api.util.ReflectionUtil; import com.dfsek.terra.api.util.ReflectionUtil;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -29,7 +32,14 @@ public class TerraEventManager implements EventManager {
public boolean callEvent(Event event) { public boolean callEvent(Event event) {
listeners.getOrDefault(event.getClass(), Collections.emptyList()).forEach(listenerHolder -> { listeners.getOrDefault(event.getClass(), Collections.emptyList()).forEach(listenerHolder -> {
try { try {
listenerHolder.method.invoke(listenerHolder.listener, event); if(event instanceof PackEvent && !listenerHolder.global) {
PackEvent packEvent = (PackEvent) event;
if(packEvent.getPack().getTemplate().getAddons().contains(listenerHolder.addon)) {
listenerHolder.method.invoke(listenerHolder.listener, event);
}
} else {
listenerHolder.method.invoke(listenerHolder.listener, event);
}
} catch(InvocationTargetException e) { } catch(InvocationTargetException e) {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
e.getTargetException().printStackTrace(new PrintWriter(writer)); e.getTargetException().printStackTrace(new PrintWriter(writer));
@ -51,7 +61,7 @@ public class TerraEventManager implements EventManager {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void registerListener(EventListener listener) { public void registerListener(TerraAddon addon, EventListener listener) {
Class<? extends EventListener> listenerClass = listener.getClass(); Class<? extends EventListener> listenerClass = listener.getClass();
Method[] methods = ReflectionUtil.getMethods(listenerClass); Method[] methods = ReflectionUtil.getMethods(listenerClass);
@ -68,7 +78,7 @@ public class TerraEventManager implements EventManager {
List<ListenerHolder> holders = listeners.computeIfAbsent((Class<? extends Event>) eventParam, e -> new ArrayList<>()); List<ListenerHolder> holders = listeners.computeIfAbsent((Class<? extends Event>) eventParam, e -> new ArrayList<>());
holders.add(new ListenerHolder(method, listener, priority)); holders.add(new ListenerHolder(method, listener, priority, addon, method.getAnnotation(Global.class) != null));
holders.sort(Comparator.comparingInt(ListenerHolder::getPriority)); // Sort priorities. holders.sort(Comparator.comparingInt(ListenerHolder::getPriority)); // Sort priorities.
} }
@ -78,11 +88,15 @@ public class TerraEventManager implements EventManager {
private final Method method; private final Method method;
private final EventListener listener; private final EventListener listener;
private final int priority; private final int priority;
private final TerraAddon addon;
private final boolean global;
private ListenerHolder(Method method, EventListener listener, int priority) { private ListenerHolder(Method method, EventListener listener, int priority, TerraAddon addon, boolean global) {
this.method = method; this.method = method;
this.listener = listener; this.listener = listener;
this.priority = priority; this.priority = priority;
this.addon = addon;
this.global = global;
} }
public int getPriority() { public int getPriority() {

View File

@ -1,7 +1,14 @@
package com.dfsek.terra.api.core.event.annotations; package com.dfsek.terra.api.core.event.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* Specifies that an event handler is to handle all events. * Specifies that an event handler is to handle all events.
*/ */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Global { public @interface Global {
} }

View File

@ -0,0 +1,8 @@
package com.dfsek.terra.api.core.event.events;
import com.dfsek.terra.config.pack.ConfigPack;
@SuppressWarnings("InterfaceMayBeAnnotatedFunctional")
public interface PackEvent extends Event {
ConfigPack getPack();
}

View File

@ -1,15 +1,16 @@
package com.dfsek.terra.api.core.event.events.config; package com.dfsek.terra.api.core.event.events.config;
import com.dfsek.terra.api.core.event.events.Event; import com.dfsek.terra.api.core.event.events.PackEvent;
import com.dfsek.terra.config.pack.ConfigPack; import com.dfsek.terra.config.pack.ConfigPack;
public abstract class ConfigPackLoadEvent implements Event { public abstract class ConfigPackLoadEvent implements PackEvent {
private final ConfigPack pack; private final ConfigPack pack;
public ConfigPackLoadEvent(ConfigPack pack) { public ConfigPackLoadEvent(ConfigPack pack) {
this.pack = pack; this.pack = pack;
} }
@Override
public ConfigPack getPack() { public ConfigPack getPack() {
return pack; return pack;
} }

View File

@ -1,12 +1,13 @@
package com.dfsek.terra.api.core.event.events.world; package com.dfsek.terra.api.core.event.events.world;
import com.dfsek.terra.api.core.event.events.Event; import com.dfsek.terra.api.core.event.events.PackEvent;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.world.TerraWorld; import com.dfsek.terra.world.TerraWorld;
/** /**
* Called upon initialization of a TerraWorld. * Called upon initialization of a TerraWorld.
*/ */
public class TerraWorldLoadEvent implements Event { public class TerraWorldLoadEvent implements PackEvent {
private final TerraWorld world; private final TerraWorld world;
public TerraWorldLoadEvent(TerraWorld world) { public TerraWorldLoadEvent(TerraWorld world) {
@ -16,4 +17,9 @@ public class TerraWorldLoadEvent implements Event {
public TerraWorld getWorld() { public TerraWorld getWorld() {
return world; return world;
} }
@Override
public ConfigPack getPack() {
return world.getConfig();
}
} }

View File

@ -1,6 +1,7 @@
package com.dfsek.terra.config; package com.dfsek.terra.config;
import com.dfsek.tectonic.loading.TypeRegistry; import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.addons.addon.TerraAddon;
import com.dfsek.terra.api.LoaderRegistrar; import com.dfsek.terra.api.LoaderRegistrar;
import com.dfsek.terra.api.core.TerraPlugin; import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.GridSpawn; import com.dfsek.terra.api.math.GridSpawn;
@ -90,6 +91,7 @@ public class GenericLoaders implements LoaderRegistrar {
.registerLoader(CarverPalette.class, new CarverPaletteLoader()) .registerLoader(CarverPalette.class, new CarverPaletteLoader())
.registerLoader(SourceSeeded.class, new SourceBuilderLoader()) .registerLoader(SourceSeeded.class, new SourceBuilderLoader())
.registerLoader(StageSeeded.class, new StageBuilderLoader()) .registerLoader(StageSeeded.class, new StageBuilderLoader())
.registerLoader(TerraAddon.class, main.getAddons())
.registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader()) .registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader())
.registerLoader(ImageSampler.Channel.class, (t, object, cf) -> ImageSampler.Channel.valueOf((String) object)) .registerLoader(ImageSampler.Channel.class, (t, object, cf) -> ImageSampler.Channel.valueOf((String) object))
.registerLoader(BiomeProvider.Type.class, (t, object, cf) -> BiomeProvider.Type.valueOf((String) object)) .registerLoader(BiomeProvider.Type.class, (t, object, cf) -> BiomeProvider.Type.valueOf((String) object))

View File

@ -3,12 +3,14 @@ package com.dfsek.terra.config.pack;
import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ConfigTemplate; import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.addons.addon.TerraAddon;
import com.dfsek.terra.api.util.seeded.NoiseSeeded; import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate; import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set;
@SuppressWarnings({"unused", "FieldMayBeFinal"}) @SuppressWarnings({"unused", "FieldMayBeFinal"})
public class ConfigPackTemplate implements ConfigTemplate { public class ConfigPackTemplate implements ConfigTemplate {
@ -18,6 +20,10 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Value("noise") @Value("noise")
private Map<String, NoiseSeeded> noiseBuilderMap; private Map<String, NoiseSeeded> noiseBuilderMap;
@Value("addons")
@Default
private Set<TerraAddon> addons;
@Value("variables") @Value("variables")
@Default @Default
private Map<String, Double> variables = new HashMap<>(); private Map<String, Double> variables = new HashMap<>();
@ -121,4 +127,8 @@ public class ConfigPackTemplate implements ConfigTemplate {
public boolean doBetaCarvers() { public boolean doBetaCarvers() {
return betaCarvers; return betaCarvers;
} }
public Set<TerraAddon> getAddons() {
return addons;
}
} }

View File

@ -1,6 +1,8 @@
package com.dfsek.terra.registry; package com.dfsek.terra.registry;
import com.dfsek.terra.addons.addon.TerraAddon; import com.dfsek.terra.addons.addon.TerraAddon;
import com.dfsek.terra.addons.annotations.Addon;
import com.dfsek.terra.addons.annotations.Depends;
import com.dfsek.terra.addons.loading.AddonClassLoader; import com.dfsek.terra.addons.loading.AddonClassLoader;
import com.dfsek.terra.addons.loading.AddonLoadException; import com.dfsek.terra.addons.loading.AddonLoadException;
import com.dfsek.terra.api.core.TerraPlugin; import com.dfsek.terra.api.core.TerraPlugin;
@ -9,48 +11,88 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; import java.util.Set;
public class AddonRegistry extends TerraRegistry<TerraAddon> { public class AddonRegistry extends TerraRegistry<TerraAddon> {
public boolean loadAll(TerraPlugin main) { private final TerraPlugin main;
public AddonRegistry(TerraPlugin main) {
this.main = main;
}
public AddonRegistry(TerraAddon addon, TerraPlugin main) {
this.main = main;
add(addon.getName(), addon);
}
@Override
public boolean add(String name, TerraAddon addon) {
addon.initialize();
main.getLogger().info("Loaded addon " + addon.getName() + " v" + addon.getVersion() + ", by " + addon.getAuthor());
return super.add(name, addon);
}
public boolean loadAll() {
boolean valid = true; boolean valid = true;
File addonsFolder = new File(main.getDataFolder(), "addons"); File addonsFolder = new File(main.getDataFolder(), "addons");
addonsFolder.mkdirs(); addonsFolder.mkdirs();
for(File jar : addonsFolder.listFiles(file -> file.getName().endsWith(".jar"))) {
try { Map<String, Class<? extends TerraAddon>> addonIDs = new HashMap<>();
try {
for(File jar : addonsFolder.listFiles(file -> file.getName().endsWith(".jar"))) {
main.getLogger().info("Loading Addon(s) from: " + jar.getName()); main.getLogger().info("Loading Addon(s) from: " + jar.getName());
load(jar, main);
} catch(IOException | AddonLoadException e) { Set<Class<? extends TerraAddon>> addonClasses = AddonClassLoader.fetchAddonClasses(jar);
e.printStackTrace();
valid = false; for(Class<? extends TerraAddon> addonClass : addonClasses) {
String id = addonClass.getAnnotation(Addon.class).value();
if(addonIDs.containsKey(id))
throw new AddonLoadException("Duplicate addon ID: " + id);
addonIDs.put(id, addonClass);
}
} }
for(Map.Entry<String, Class<? extends TerraAddon>> entry : addonIDs.entrySet()) {
Class<? extends TerraAddon> addonClass = entry.getValue();
Depends dependencies = addonClass.getAnnotation(Depends.class);
if(dependencies != null) {
for(String dependency : dependencies.value()) {
if(!addonIDs.containsKey(dependency))
throw new AddonLoadException("Addon " + entry.getKey() + " specifies dependency " + dependency + ", which is not loaded. Please install " + dependency + " to use " + entry.getKey());
}
}
Constructor<? extends TerraAddon> constructor;
try {
constructor = addonClass.getConstructor();
} catch(NoSuchMethodException e) {
throw new AddonLoadException("Addon class has no valid constructor: " + addonClass.getCanonicalName(), e);
}
TerraAddon addon;
try {
addon = constructor.newInstance();
} catch(InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new AddonLoadException("Failed to instantiate addon: " + addonClass.getCanonicalName(), e);
}
try {
addChecked(addon.getName(), addon);
} catch(IllegalArgumentException e) {
throw new AddonLoadException("Duplicate addon ID; addon with ID " + addon.getName() + " is already loaded.");
}
}
} catch(IOException | AddonLoadException e) {
e.printStackTrace();
valid = false;
main.getLogger().severe("Addons failed to load. Please ensure all addons are properly installed.");
} }
return valid; return valid;
} }
public void load(File file, TerraPlugin main) throws AddonLoadException, IOException {
Set<Class<? extends TerraAddon>> addonClasses = AddonClassLoader.fetchAddonClasses(file);
for(Class<? extends TerraAddon> addonClass : addonClasses) {
Constructor<? extends TerraAddon> constructor;
try {
constructor = addonClass.getConstructor();
} catch(NoSuchMethodException e) {
throw new AddonLoadException("Addon class has no valid constructor: " + addonClass.getCanonicalName(), e);
}
TerraAddon addon;
try {
addon = constructor.newInstance();
} catch(InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new AddonLoadException("Failed to instantiate addon: " + addonClass.getCanonicalName(), e);
}
try {
addChecked(addon.getName(), addon);
} catch(IllegalArgumentException e) {
throw new AddonLoadException("Duplicate addon ID; addon with ID " + addon.getName() + " is already loaded.");
}
main.getLogger().info("Loaded addon " + addon.getName() + " v" + addon.getVersion() + ", by " + addon.getAuthor());
addon.initialize();
}
}
} }

View File

@ -38,7 +38,7 @@ public abstract class TerraRegistry<T> implements TypeLoader<T> {
public void addChecked(String name, T value) { public void addChecked(String name, T value) {
if(objects.containsKey(name)) throw new IllegalArgumentException("Value is already defined in registry."); if(objects.containsKey(name)) throw new IllegalArgumentException("Value is already defined in registry.");
objects.put(name, value); add(name, value);
} }
/** /**

View File

@ -1,156 +0,0 @@
package event;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.core.event.EventListener;
import com.dfsek.terra.api.core.event.EventManager;
import com.dfsek.terra.api.core.event.TerraEventManager;
import com.dfsek.terra.api.core.event.annotations.Priority;
import com.dfsek.terra.api.core.event.events.Event;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.debug.DebugLogger;
import com.dfsek.terra.registry.AddonRegistry;
import com.dfsek.terra.registry.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.logging.Logger;
public class EventTest {
public TerraPlugin main = new TerraPlugin() {
private final Logger logger = Logger.getLogger("Terra");
private final EventManager eventManager = new TerraEventManager(this);
@Override
public WorldHandle getWorldHandle() {
return null;
}
@Override
public boolean isEnabled() {
return false;
}
@Override
public TerraWorld getWorld(World world) {
return null;
}
@Override
public Logger getLogger() {
return logger;
}
@Override
public PluginConfig getTerraConfig() {
return null;
}
@Override
public File getDataFolder() {
return null;
}
@Override
public boolean isDebug() {
return false;
}
@Override
public Language getLanguage() {
return null;
}
@Override
public ConfigRegistry getRegistry() {
return null;
}
@Override
public AddonRegistry getAddons() {
return null;
}
@Override
public void reload() {
}
@Override
public ItemHandle getItemHandle() {
return null;
}
@Override
public void saveDefaultConfig() {
}
@Override
public String platformName() {
return null;
}
@Override
public DebugLogger getDebugLogger() {
return null;
}
@Override
public void register(TypeRegistry registry) {
}
@Override
public EventManager getEventManager() {
return eventManager;
}
};
@Test
public void eventTest() {
EventManager eventManager = main.getEventManager();
eventManager.registerListener(new TestListener());
eventManager.registerListener(new TestListener2());
TestEvent event = new TestEvent(4);
eventManager.callEvent(event);
eventManager.registerListener(new TestListenerException());
TestEvent event2 = new TestEvent(5);
eventManager.callEvent(event2);
}
static class TestListener implements EventListener {
public void doThing(TestEvent event) {
System.out.println("Event value: " + event.value);
}
}
static class TestListener2 implements EventListener {
@Priority(Priority.LOWEST)
public void doThing(TestEvent event) {
System.out.println("Event value 2: " + event.value);
}
}
static class TestListenerException implements EventListener {
public void doThing(TestEvent event) {
throw new RuntimeException("bazinga: " + event.value);
}
}
static class TestEvent implements Event {
private final int value;
TestEvent(int value) {
this.value = value;
}
}
}

View File

@ -34,7 +34,7 @@ dependencies {
} }
tasks.withType<ProcessResources> { tasks.withType<ProcessResources> {
include("**/*.yml") include("**/*.*")
filter<org.apache.tools.ant.filters.ReplaceTokens>( filter<org.apache.tools.ant.filters.ReplaceTokens>(
"tokens" to mapOf( "tokens" to mapOf(
"VERSION" to project.version.toString() "VERSION" to project.version.toString()

View File

@ -1,6 +1,10 @@
package com.dfsek.terra.bukkit; package com.dfsek.terra.bukkit;
import com.dfsek.tectonic.loading.TypeRegistry; import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.addons.addon.TerraAddon;
import com.dfsek.terra.addons.annotations.Addon;
import com.dfsek.terra.addons.annotations.Author;
import com.dfsek.terra.addons.annotations.Version;
import com.dfsek.terra.api.core.TerraPlugin; import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.core.event.EventManager; import com.dfsek.terra.api.core.event.EventManager;
import com.dfsek.terra.api.core.event.TerraEventManager; import com.dfsek.terra.api.core.event.TerraEventManager;
@ -56,21 +60,22 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
private WorldHandle handle = new BukkitWorldHandle(); private WorldHandle handle = new BukkitWorldHandle();
private final GenericLoaders genericLoaders = new GenericLoaders(this); private final GenericLoaders genericLoaders = new GenericLoaders(this);
private DebugLogger debugLogger; private DebugLogger debugLogger;
private final AddonRegistry addonRegistry = new AddonRegistry();
private final EventManager eventManager = new TerraEventManager(this); private final EventManager eventManager = new TerraEventManager(this);
public static final BukkitVersion BUKKIT_VERSION;
public static final Version BUKKIT_VERSION;
static { static {
String ver = Bukkit.getServer().getClass().getPackage().getName(); String ver = Bukkit.getServer().getClass().getPackage().getName();
if(ver.contains("1_16")) BUKKIT_VERSION = Version.V1_16; if(ver.contains("1_16")) BUKKIT_VERSION = BukkitVersion.V1_16;
else if(ver.contains("1_15")) BUKKIT_VERSION = Version.V1_15; else if(ver.contains("1_15")) BUKKIT_VERSION = BukkitVersion.V1_15;
else if(ver.contains("1_14")) BUKKIT_VERSION = Version.V1_14; else if(ver.contains("1_14")) BUKKIT_VERSION = BukkitVersion.V1_14;
else if(ver.contains("1_13")) BUKKIT_VERSION = Version.V1_13; else if(ver.contains("1_13")) BUKKIT_VERSION = BukkitVersion.V1_13;
else BUKKIT_VERSION = Version.UNKNOWN; else BUKKIT_VERSION = BukkitVersion.UNKNOWN;
} }
private final AddonRegistry addonRegistry = new AddonRegistry(new BukkitAddon(this), this);
public void reload() { public void reload() {
Map<World, TerraWorld> newMap = new HashMap<>(); Map<World, TerraWorld> newMap = new HashMap<>();
@ -122,10 +127,8 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
public void onEnable() { public void onEnable() {
debugLogger = new DebugLogger(getLogger()); debugLogger = new DebugLogger(getLogger());
eventManager.registerListener(new TerraListener(this)); // Register tree injection event
getLogger().info("Running on version " + BUKKIT_VERSION); getLogger().info("Running on version " + BUKKIT_VERSION);
if(BUKKIT_VERSION.equals(Version.UNKNOWN)) { if(BUKKIT_VERSION == BukkitVersion.UNKNOWN) {
getLogger().warning("Terra is running on an unknown Bukkit version. Proceed with caution."); getLogger().warning("Terra is running on an unknown Bukkit version. Proceed with caution.");
} }
@ -138,7 +141,7 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
LangUtil.load(config.getLanguage(), this); // Load language. LangUtil.load(config.getLanguage(), this); // Load language.
debugLogger.setDebug(isDebug()); debugLogger.setDebug(isDebug());
addonRegistry.loadAll(this); addonRegistry.loadAll();
registry.loadAll(this); // Load all config packs. registry.loadAll(this); // Load all config packs.
PluginCommand c = Objects.requireNonNull(getCommand("terra")); PluginCommand c = Objects.requireNonNull(getCommand("terra"));
@ -253,7 +256,7 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
return addonRegistry; return addonRegistry;
} }
public enum Version { public enum BukkitVersion {
V1_13(13), V1_13(13),
V1_14(14), V1_14(14),
@ -266,7 +269,7 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
private final int index; private final int index;
Version(int index) { BukkitVersion(int index) {
this.index = index; this.index = index;
} }
@ -276,8 +279,24 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
* @param other Other version * @param other Other version
* @return Whether this version is equal to or later than other. * @return Whether this version is equal to or later than other.
*/ */
public boolean above(Version other) { public boolean above(BukkitVersion other) {
return this.index >= other.index; return this.index >= other.index;
} }
} }
@Addon("Terra")
@Version("1.0.0")
@Author("Terra")
private static final class BukkitAddon extends TerraAddon {
private final TerraPlugin main;
private BukkitAddon(TerraPlugin main) {
this.main = main;
}
@Override
public void initialize() {
main.getEventManager().registerListener(this, new TerraListener(main));
}
}
} }

View File

@ -0,0 +1,41 @@
package com.dfsek.terra.bukkit.command.command;
import com.dfsek.terra.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class AddonsCommand extends Command {
public AddonsCommand(Command parent) {
super(parent);
}
@Override
public String getName() {
return "addons";
}
@Override
public List<Command> getSubCommands() {
return Collections.emptyList();
}
@Override
public boolean execute(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command command, @NotNull String label, @NotNull String[] args) {
sender.sendMessage("Installed Addons:");
getMain().getAddons().forEach(addon -> sender.sendMessage(" - " + addon.getName() + " v" + addon.getVersion() + " by " + addon.getAuthor()));
return true;
}
@Override
public int arguments() {
return 0;
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
return Collections.emptyList();
}
}

View File

@ -25,7 +25,8 @@ public class TerraCommand extends Command {
new FixChunkCommand(this), new FixChunkCommand(this),
new VersionCommand(this), new VersionCommand(this),
new GetBlockCommand(this), new GetBlockCommand(this),
new PacksCommand(this)); new PacksCommand(this),
new AddonsCommand(this));
public TerraCommand(TerraPlugin main) { public TerraCommand(TerraPlugin main) {
super(main); super(main);

View File

@ -2,6 +2,7 @@ package com.dfsek.terra.bukkit.listeners;
import com.dfsek.terra.api.core.TerraPlugin; import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.core.event.EventListener; import com.dfsek.terra.api.core.event.EventListener;
import com.dfsek.terra.api.core.event.annotations.Global;
import com.dfsek.terra.api.core.event.events.config.ConfigPackPreLoadEvent; import com.dfsek.terra.api.core.event.events.config.ConfigPackPreLoadEvent;
import com.dfsek.terra.bukkit.world.BukkitAdapter; import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.bukkit.world.BukkitTree; import com.dfsek.terra.bukkit.world.BukkitTree;
@ -14,6 +15,7 @@ public class TerraListener implements EventListener {
this.main = main; this.main = main;
} }
@Global
public void injectTrees(ConfigPackPreLoadEvent event) { public void injectTrees(ConfigPackPreLoadEvent event) {
for(TreeType value : TreeType.values()) { for(TreeType value : TreeType.values()) {
event.getPack().getTreeRegistry().add(BukkitAdapter.TREE_TRANSFORMER.translate(value), new BukkitTree(value, main)); event.getPack().getTreeRegistry().add(BukkitAdapter.TREE_TRANSFORMER.translate(value), new BukkitTree(value, main));

View File

@ -28,7 +28,7 @@ public class BukkitBlockData implements BlockData {
if(bukkitData instanceof Rail) return new BukkitRail((Rail) bukkitData); if(bukkitData instanceof Rail) return new BukkitRail((Rail) bukkitData);
if(bukkitData instanceof Stairs) return new BukkitStairs((Stairs) bukkitData); if(bukkitData instanceof Stairs) return new BukkitStairs((Stairs) bukkitData);
if(bukkitData instanceof Slab) return new BukkitSlab((Slab) bukkitData); if(bukkitData instanceof Slab) return new BukkitSlab((Slab) bukkitData);
if(TerraBukkitPlugin.BUKKIT_VERSION.above(TerraBukkitPlugin.Version.V1_16) && bukkitData instanceof Wall) { // Wall only exists on 1.16 and up. if(TerraBukkitPlugin.BUKKIT_VERSION.above(TerraBukkitPlugin.BukkitVersion.V1_16) && bukkitData instanceof Wall) { // Wall only exists on 1.16 and up.
return new BukkitWall((Wall) bukkitData); return new BukkitWall((Wall) bukkitData);
} }

View File

@ -87,7 +87,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
private final WorldHandle worldHandle = new FabricWorldHandle(); private final WorldHandle worldHandle = new FabricWorldHandle();
private final ConfigRegistry registry = new ConfigRegistry(); private final ConfigRegistry registry = new ConfigRegistry();
private final AddonRegistry addonRegistry = new AddonRegistry(); private final AddonRegistry addonRegistry = new AddonRegistry(this);
private File config; private File config;
private static final Transformer<String, ConfiguredFeature<?, ?>> TREE_TRANSFORMER = new Transformer.Builder<String, ConfiguredFeature<?, ?>>() private static final Transformer<String, ConfiguredFeature<?, ?>> TREE_TRANSFORMER = new Transformer.Builder<String, ConfiguredFeature<?, ?>>()
.addTransform(TerraFabricPlugin::getFeature) .addTransform(TerraFabricPlugin::getFeature)

View File

@ -27,7 +27,7 @@ import java.util.logging.Logger;
public class StandalonePlugin implements TerraPlugin { public class StandalonePlugin implements TerraPlugin {
private final ConfigRegistry registry = new ConfigRegistry(); private final ConfigRegistry registry = new ConfigRegistry();
private final AddonRegistry addonRegistry = new AddonRegistry(); private final AddonRegistry addonRegistry = new AddonRegistry(this);
private final PluginConfig config = new PluginConfig(); private final PluginConfig config = new PluginConfig();
private final RawWorldHandle worldHandle = new RawWorldHandle(); private final RawWorldHandle worldHandle = new RawWorldHandle();
private final EventManager eventManager = new TerraEventManager(this); private final EventManager eventManager = new TerraEventManager(this);