mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-04 00:45:57 +00:00
set up dependency stuff
This commit is contained in:
parent
76f2a3fbc4
commit
45dbe45fb4
@ -51,7 +51,7 @@ public class AddonClassLoader extends URLClassLoader {
|
|||||||
|
|
||||||
set.add((Class<? extends TerraAddon>) clazz);
|
set.add((Class<? extends TerraAddon>) clazz);
|
||||||
} catch(ClassNotFoundException e) {
|
} catch(ClassNotFoundException e) {
|
||||||
e.printStackTrace();
|
throw new IllegalStateException(e); // this should literally never happen, if it does something is very wrong
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.dfsek.terra.addons.loading;
|
package com.dfsek.terra.addons.loading;
|
||||||
|
|
||||||
public class AddonLoadException extends Exception {
|
public class AddonLoadException extends Exception {
|
||||||
|
private static final long serialVersionUID = -4949084729296580176L;
|
||||||
|
|
||||||
public AddonLoadException(String message) {
|
public AddonLoadException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.dfsek.terra.addons.loading.pre;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.loading.AddonLoadException;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class AddonPool {
|
||||||
|
private final Map<String, PreLoadAddon> pool = new HashMap<>();
|
||||||
|
|
||||||
|
public void add(PreLoadAddon addon) throws AddonLoadException {
|
||||||
|
if(pool.containsKey(addon.getId()))
|
||||||
|
throw new AddonLoadException("Duplicate addon ID: " + addon.getId());
|
||||||
|
pool.put(addon.getId(), addon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PreLoadAddon get(String id) {
|
||||||
|
return pool.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buildAll() throws AddonLoadException {
|
||||||
|
for(PreLoadAddon value : pool.values()) {
|
||||||
|
value.rebuildDependencies(this, value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<PreLoadAddon> getAddons() {
|
||||||
|
return new HashSet<>(pool.values());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.dfsek.terra.addons.loading.pre;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.loading.AddonLoadException;
|
||||||
|
|
||||||
|
public class CircularDependencyException extends AddonLoadException {
|
||||||
|
private static final long serialVersionUID = 7398510879124125121L;
|
||||||
|
|
||||||
|
public CircularDependencyException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CircularDependencyException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.dfsek.terra.addons.loading.pre;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.loading.AddonLoadException;
|
||||||
|
|
||||||
|
public class DependencyMissingException extends AddonLoadException {
|
||||||
|
private static final long serialVersionUID = -8419489102208521583L;
|
||||||
|
|
||||||
|
public DependencyMissingException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DependencyMissingException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.dfsek.terra.addons.loading.pre;
|
||||||
|
|
||||||
|
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.AddonLoadException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PreLoadAddon {
|
||||||
|
private final List<PreLoadAddon> depends = new ArrayList<>();
|
||||||
|
private final Class<? extends TerraAddon> addonClass;
|
||||||
|
private final String id;
|
||||||
|
private final String[] dependencies;
|
||||||
|
|
||||||
|
public PreLoadAddon(Class<? extends TerraAddon> addonClass) {
|
||||||
|
this.addonClass = addonClass;
|
||||||
|
this.id = addonClass.getAnnotation(Addon.class).value();
|
||||||
|
Depends depends = addonClass.getAnnotation(Depends.class);
|
||||||
|
this.dependencies = depends == null ? new String[] {} : depends.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PreLoadAddon> getDepends() {
|
||||||
|
return depends;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rebuildDependencies(AddonPool pool, PreLoadAddon origin, boolean levelG1) throws AddonLoadException {
|
||||||
|
if(this.equals(origin) && !levelG1)
|
||||||
|
throw new CircularDependencyException("Detected circular dependency in addon \"" + id + "\", dependencies: " + Arrays.toString(dependencies));
|
||||||
|
|
||||||
|
for(String dependency : dependencies) {
|
||||||
|
PreLoadAddon preLoadAddon = pool.get(dependency);
|
||||||
|
if(preLoadAddon == null) throw new DependencyMissingException("Dependency " + dependency + " was not found.");
|
||||||
|
depends.add(preLoadAddon);
|
||||||
|
preLoadAddon.rebuildDependencies(pool, origin, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends TerraAddon> getAddonClass() {
|
||||||
|
return addonClass;
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,16 @@
|
|||||||
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.addons.loading.pre.AddonPool;
|
||||||
|
import com.dfsek.terra.addons.loading.pre.PreLoadAddon;
|
||||||
import com.dfsek.terra.api.core.TerraPlugin;
|
import com.dfsek.terra.api.core.TerraPlugin;
|
||||||
|
|
||||||
import java.io.File;
|
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;
|
|
||||||
|
|
||||||
public class AddonRegistry extends TerraRegistry<TerraAddon> {
|
public class AddonRegistry extends TerraRegistry<TerraAddon> {
|
||||||
private final TerraPlugin main;
|
private final TerraPlugin main;
|
||||||
@ -30,67 +27,61 @@ public class AddonRegistry extends TerraRegistry<TerraAddon> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean add(String name, TerraAddon addon) {
|
public boolean add(String name, TerraAddon addon) {
|
||||||
|
if(contains(name)) throw new IllegalArgumentException("Addon " + name + " is already registered.");
|
||||||
addon.initialize();
|
addon.initialize();
|
||||||
main.getLogger().info("Loaded addon " + addon.getName() + " v" + addon.getVersion() + ", by " + addon.getAuthor());
|
main.getLogger().info("Loaded addon " + addon.getName() + " v" + addon.getVersion() + ", by " + addon.getAuthor());
|
||||||
return super.add(name, addon);
|
return super.add(name, addon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean loadAll() {
|
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();
|
||||||
|
|
||||||
Map<String, Class<? extends TerraAddon>> addonIDs = new HashMap<>();
|
AddonPool pool = new AddonPool();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for(File jar : addonsFolder.listFiles(file -> file.getName().endsWith(".jar"))) {
|
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());
|
||||||
|
for(Class<? extends TerraAddon> addonClass : AddonClassLoader.fetchAddonClasses(jar)) {
|
||||||
Set<Class<? extends TerraAddon>> addonClasses = AddonClassLoader.fetchAddonClasses(jar);
|
pool.add(new PreLoadAddon(addonClass));
|
||||||
|
|
||||||
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()) {
|
pool.buildAll();
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for(PreLoadAddon addon : pool.getAddons()) {
|
||||||
|
Class<? extends TerraAddon> addonClass = addon.getAddonClass();
|
||||||
Constructor<? extends TerraAddon> constructor;
|
Constructor<? extends TerraAddon> constructor;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
constructor = addonClass.getConstructor();
|
constructor = addonClass.getConstructor();
|
||||||
} catch(NoSuchMethodException e) {
|
} catch(NoSuchMethodException e) {
|
||||||
throw new AddonLoadException("Addon class has no valid constructor: " + addonClass.getCanonicalName(), e);
|
throw new AddonLoadException("Addon class has no valid constructor: " + addonClass.getCanonicalName(), e);
|
||||||
}
|
}
|
||||||
TerraAddon addon;
|
TerraAddon loadedAddon;
|
||||||
try {
|
try {
|
||||||
addon = constructor.newInstance();
|
loadedAddon = constructor.newInstance();
|
||||||
} catch(InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
} catch(InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
throw new AddonLoadException("Failed to instantiate addon: " + addonClass.getCanonicalName(), e);
|
throw new AddonLoadException("Failed to load addon \" + " + addon.getId() + "\": ", e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
addChecked(addon.getName(), addon);
|
addChecked(loadedAddon.getName(), loadedAddon);
|
||||||
} catch(IllegalArgumentException e) {
|
} catch(IllegalArgumentException e) {
|
||||||
throw new AddonLoadException("Duplicate addon ID; addon with ID " + addon.getName() + " is already loaded.");
|
valid = false;
|
||||||
|
main.getLogger().severe("Duplicate addon ID; addon with ID " + loadedAddon.getName() + " is already loaded.");
|
||||||
|
main.getLogger().severe("Existing addon class: " + get(loadedAddon.getName()).getClass().getCanonicalName());
|
||||||
|
main.getLogger().severe("Duplicate addon class: " + addonClass.getCanonicalName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(IOException | AddonLoadException e) {
|
} catch(AddonLoadException | IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
valid = false;
|
valid = false;
|
||||||
main.getLogger().severe("Addons failed to load. Please ensure all addons are properly installed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
|
@ -141,7 +141,12 @@ 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();
|
if(!addonRegistry.loadAll()) {
|
||||||
|
getLogger().severe("Failed to load addons. Please correct addon installations to continue.");
|
||||||
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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"));
|
||||||
|
@ -41,7 +41,7 @@ public final class SerializationUtil {
|
|||||||
try {
|
try {
|
||||||
if(result.getName().contains(oldNameSpace)) {
|
if(result.getName().contains(oldNameSpace)) {
|
||||||
String newClassName = result.getName().replace(oldNameSpace, newNameSpace);
|
String newClassName = result.getName().replace(oldNameSpace, newNameSpace);
|
||||||
Class localClass = Class.forName(newClassName);
|
Class<?> localClass = Class.forName(newClassName);
|
||||||
|
|
||||||
Field nameField = ObjectStreamClass.class.getDeclaredField("name");
|
Field nameField = ObjectStreamClass.class.getDeclaredField("name");
|
||||||
nameField.setAccessible(true);
|
nameField.setAccessible(true);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user