Move several Dependency Injectors into the API
This commit is contained in:
+2
-2
@@ -1,7 +1,7 @@
|
||||
package com.seibel.lod.api.items.interfaces.override;
|
||||
|
||||
import com.seibel.lod.core.dependencyInjection.IBindable;
|
||||
import com.seibel.lod.core.dependencyInjection.IOverrideInjector;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IOverrideInjector;
|
||||
|
||||
/**
|
||||
* Implemented by all DhApi objects that can be overridden.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.seibel.lod.api.methods.events.interfaces;
|
||||
|
||||
import com.seibel.lod.core.dependencyInjection.IBindable;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
|
||||
|
||||
/**
|
||||
* A combination of all interfaces required by all
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.DependencyInjection;
|
||||
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IDependencyInjector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class takes care of tracking objects used in dependency injection.
|
||||
*
|
||||
* @param <BindableType> extends IBindable and defines what interfaces this dependency handler can deal with.
|
||||
* @author James Seibel
|
||||
* @version 2022-8-15
|
||||
*/
|
||||
public class DependencyInjector<BindableType extends IBindable> implements IDependencyInjector<BindableType>
|
||||
{
|
||||
protected final Map<Class<? extends BindableType>, ArrayList<BindableType>> dependencies = new HashMap<>();
|
||||
|
||||
/** Internal class reference to BindableType since we can't get it any other way. */
|
||||
protected final Class<? extends BindableType> bindableInterface;
|
||||
|
||||
protected final boolean allowDuplicateBindings;
|
||||
|
||||
|
||||
public DependencyInjector(Class<BindableType> newBindableInterface)
|
||||
{
|
||||
this.bindableInterface = newBindableInterface;
|
||||
this.allowDuplicateBindings = false;
|
||||
}
|
||||
|
||||
public DependencyInjector(Class<BindableType> newBindableInterface, boolean newAllowDuplicateBindings)
|
||||
{
|
||||
this.bindableInterface = newBindableInterface;
|
||||
this.allowDuplicateBindings = newAllowDuplicateBindings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void bind(Class<? extends BindableType> dependencyInterface, BindableType dependencyImplementation) throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
// duplicate check if requested
|
||||
if (dependencies.containsKey(dependencyInterface) && !this.allowDuplicateBindings)
|
||||
{
|
||||
throw new IllegalStateException("The dependency [" + dependencyInterface.getSimpleName() + "] has already been bound.");
|
||||
}
|
||||
|
||||
|
||||
// make sure the given dependency implements the necessary interfaces
|
||||
boolean implementsInterface = checkIfClassImplements(dependencyImplementation.getClass(), dependencyInterface)
|
||||
|| checkIfClassExtends(dependencyImplementation.getClass(), dependencyInterface);
|
||||
boolean implementsBindable = checkIfClassImplements(dependencyImplementation.getClass(), this.bindableInterface);
|
||||
|
||||
// display any errors
|
||||
if (!implementsInterface)
|
||||
{
|
||||
throw new IllegalArgumentException("The dependency [" + dependencyImplementation.getClass().getSimpleName() + "] doesn't implement or extend: [" + dependencyInterface.getSimpleName() + "].");
|
||||
}
|
||||
if (!implementsBindable)
|
||||
{
|
||||
throw new IllegalArgumentException("The dependency [" + dependencyImplementation.getClass().getSimpleName() + "] doesn't implement the interface: [" + IBindable.class.getSimpleName() + "].");
|
||||
}
|
||||
|
||||
|
||||
// make sure the hashSet has an array to hold the dependency
|
||||
if (!dependencies.containsKey(dependencyInterface))
|
||||
{
|
||||
dependencies.put(dependencyInterface, new ArrayList<BindableType>());
|
||||
}
|
||||
|
||||
// add the dependency
|
||||
dependencies.get(dependencyInterface).add(dependencyImplementation);
|
||||
}
|
||||
@Override
|
||||
public boolean checkIfClassImplements(Class<?> classToTest, Class<?> interfaceToLookFor)
|
||||
{
|
||||
// check the parent class (if applicable)
|
||||
if (classToTest.getSuperclass() != Object.class && classToTest.getSuperclass() != null)
|
||||
{
|
||||
if (checkIfClassImplements(classToTest.getSuperclass(), interfaceToLookFor))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check interfaces
|
||||
for (Class<?> implementationInterface : classToTest.getInterfaces())
|
||||
{
|
||||
// recurse to check interface parents if necessary
|
||||
if (implementationInterface.getInterfaces().length != 0)
|
||||
{
|
||||
if (checkIfClassImplements(implementationInterface, interfaceToLookFor))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (implementationInterface.equals(interfaceToLookFor))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean checkIfClassExtends(Class<?> classToTest, Class<?> extensionToLookFor)
|
||||
{
|
||||
return extensionToLookFor.isAssignableFrom(classToTest);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends BindableType> T get(Class<T> interfaceClass) throws ClassCastException
|
||||
{
|
||||
return (T) getInternalLogic(interfaceClass, false).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BindableType> ArrayList<T> getAll(Class<T> interfaceClass) throws ClassCastException
|
||||
{
|
||||
return getInternalLogic(interfaceClass, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends BindableType> T get(Class<T> interfaceClass, boolean allowIncompleteDependencies) throws ClassCastException
|
||||
{
|
||||
return (T) getInternalLogic(interfaceClass, allowIncompleteDependencies).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns a list of size 1 or greater,
|
||||
* if no dependencies have been bound the list will contain null.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends BindableType> ArrayList<T> getInternalLogic(Class<T> interfaceClass, boolean allowIncompleteDependencies) throws ClassCastException
|
||||
{
|
||||
ArrayList<BindableType> dependencyList = dependencies.get(interfaceClass);
|
||||
if (dependencyList != null && dependencyList.size() != 0)
|
||||
{
|
||||
// check if each dependencies' delayed setup has been completed
|
||||
for (IBindable dependency : dependencyList)
|
||||
{
|
||||
if (!dependency.getDelayedSetupComplete() && !allowIncompleteDependencies)
|
||||
{
|
||||
// a warning can be used here instead if desired
|
||||
//this.logger.warn("Got dependency of type [" + interfaceClass.getSimpleName() + "], but the dependency's delayed setup hasn't been run!");
|
||||
throw new IllegalStateException("Got dependency of type [" + interfaceClass.getSimpleName() + "], but the dependency's delayed setup hasn't been run!");
|
||||
}
|
||||
}
|
||||
|
||||
return (ArrayList<T>) dependencyList;
|
||||
}
|
||||
|
||||
|
||||
// return an empty list to prevent null pointers
|
||||
ArrayList<T> emptyList = new ArrayList<T>();
|
||||
emptyList.add(null);
|
||||
return emptyList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Removes all bound dependencies. */
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
this.dependencies.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Runs delayed setup for any dependencies that require it. */
|
||||
@Override
|
||||
public void runDelayedSetup()
|
||||
{
|
||||
for (Class<? extends BindableType> interfaceKey : dependencies.keySet())
|
||||
{
|
||||
IBindable concreteObject = get(interfaceKey, true);
|
||||
if (!concreteObject.getDelayedSetupComplete())
|
||||
{
|
||||
concreteObject.finishDelayedSetup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.DependencyInjection;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IDhApiEventInjector;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class takes care of dependency injection for API events.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-9-13
|
||||
*/
|
||||
public class DhApiEventInjector extends DependencyInjector<IDhApiEvent> implements IDhApiEventInjector // Note to self: Don't try adding a generic type to IDhApiEvent, the consturctor won't accept it
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger(DhApiEventInjector.class.getSimpleName());
|
||||
|
||||
public static final DhApiEventInjector INSTANCE = new DhApiEventInjector();
|
||||
|
||||
|
||||
|
||||
public DhApiEventInjector()
|
||||
{
|
||||
super(IDhApiEvent.class, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean unbind(Class<? extends IDhApiEvent> dependencyInterface, Class<? extends IDhApiEvent> dependencyClassToRemove) throws IllegalArgumentException
|
||||
{
|
||||
// make sure the given dependency implements the necessary interfaces
|
||||
boolean implementsInterface = checkIfClassImplements(dependencyClassToRemove, dependencyInterface)
|
||||
|| checkIfClassExtends(dependencyClassToRemove, dependencyInterface);
|
||||
boolean implementsBindable = checkIfClassImplements(dependencyClassToRemove, this.bindableInterface);
|
||||
|
||||
// display any errors
|
||||
if (!implementsInterface)
|
||||
{
|
||||
throw new IllegalArgumentException("The event handler [" + dependencyClassToRemove.getSimpleName() + "] doesn't implement or extend: [" + dependencyInterface.getSimpleName() + "].");
|
||||
}
|
||||
if (!implementsBindable)
|
||||
{
|
||||
throw new IllegalArgumentException("The event handler [" + dependencyClassToRemove.getSimpleName() + "] doesn't implement the interface: [" + IBindable.class.getSimpleName() + "].");
|
||||
}
|
||||
|
||||
|
||||
// actually remove the dependency
|
||||
if (this.dependencies.containsKey(dependencyInterface))
|
||||
{
|
||||
ArrayList<IDhApiEvent> dependencyList = this.dependencies.get(dependencyInterface);
|
||||
int indexToRemove = -1;
|
||||
for(int i = 0; i < dependencyList.size(); i++)
|
||||
{
|
||||
IBindable dependency = dependencyList.get(i);
|
||||
if (dependency.getClass().equals(dependencyClassToRemove))
|
||||
{
|
||||
indexToRemove = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (indexToRemove != -1)
|
||||
{
|
||||
return dependencyList.remove(indexToRemove) != null;
|
||||
}
|
||||
}
|
||||
|
||||
// no item was removed
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, U extends IDhApiEvent<T>> boolean fireAllEvents(Class<U> dependencyInterface, T eventParameterObject)
|
||||
{
|
||||
boolean cancelEvent = false;
|
||||
|
||||
ArrayList<U> eventList = this.getAll(dependencyInterface);
|
||||
for (IDhApiEvent<T> event : eventList)
|
||||
{
|
||||
if (event != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// fire each event and record if any of them
|
||||
// request to cancel the event.
|
||||
cancelEvent |= event.fireEvent(eventParameterObject);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// TODO log the failed event handler
|
||||
LOGGER.error("Exception thrown by event handler :" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cancelEvent;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.DependencyInjection;
|
||||
|
||||
import com.seibel.lod.api.items.interfaces.override.IDhApiOverrideable;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IOverrideInjector;
|
||||
import com.seibel.lod.core.util.StringUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class takes care of dependency injection for overridable objects. <Br>
|
||||
* This is done so other mods can override our methods to improve features down the line.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-9-8
|
||||
*/
|
||||
public class OverrideInjector implements IOverrideInjector<IDhApiOverrideable>
|
||||
{
|
||||
public static final OverrideInjector INSTANCE = new OverrideInjector();
|
||||
|
||||
private final HashMap<Class<? extends IDhApiOverrideable>, OverridePriorityListContainer> overrideContainerByInterface = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* This is used to determine if an override is part of Distant Horizons'
|
||||
* Core or not.
|
||||
* This probably isn't the best way of going about this, but it works for now.
|
||||
*/
|
||||
private final String corePackagePath;
|
||||
|
||||
|
||||
|
||||
public OverrideInjector()
|
||||
{
|
||||
String thisPackageName = this.getClass().getPackage().getName();
|
||||
int secondPackageEndingIndex = StringUtil.nthIndexOf(thisPackageName, ".", 3);
|
||||
|
||||
this.corePackagePath = thisPackageName.substring(0, secondPackageEndingIndex); // this should be "com.seibel.lod"
|
||||
}
|
||||
|
||||
public OverrideInjector(String newCorePackagePath) { this.corePackagePath = newCorePackagePath; }
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void bind(Class<? extends IDhApiOverrideable> dependencyInterface, IDhApiOverrideable dependencyImplementation) throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
// make sure a override container exists
|
||||
OverridePriorityListContainer overrideContainer = this.overrideContainerByInterface.get(dependencyInterface);
|
||||
if (overrideContainer == null)
|
||||
{
|
||||
overrideContainer = new OverridePriorityListContainer();
|
||||
this.overrideContainerByInterface.put(dependencyInterface, overrideContainer);
|
||||
}
|
||||
|
||||
|
||||
// validate the new override //
|
||||
|
||||
// check if this override is a core override
|
||||
if (dependencyImplementation.getPriority() == CORE_PRIORITY)
|
||||
{
|
||||
// this claims to be a core override, is that true?
|
||||
String packageName = dependencyImplementation.getClass().getPackage().getName();
|
||||
if (!packageName.startsWith(this.corePackagePath))
|
||||
{
|
||||
throw new IllegalArgumentException("Only Distant Horizons internal objects can use the Override Priority [" + CORE_PRIORITY + "]. Please use a higher number.");
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the override has a valid priority
|
||||
else if (dependencyImplementation.getPriority() < MIN_NON_CORE_OVERRIDE_PRIORITY)
|
||||
{
|
||||
throw new IllegalArgumentException("Invalid priority value [" + dependencyImplementation.getPriority() + "], override priorities must be [" + MIN_NON_CORE_OVERRIDE_PRIORITY + "] or greater.");
|
||||
}
|
||||
|
||||
// check if an override already exists with this priority
|
||||
IDhApiOverrideable existingOverride = overrideContainer.getOverrideWithPriority(dependencyImplementation.getPriority());
|
||||
if (existingOverride != null)
|
||||
{
|
||||
throw new IllegalStateException("An override already exists with the priority [" + dependencyImplementation.getPriority() + "].");
|
||||
}
|
||||
|
||||
|
||||
// bind the override
|
||||
overrideContainer.addOverride(dependencyImplementation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IDhApiOverrideable> T get(Class<T> interfaceClass) throws ClassCastException
|
||||
{
|
||||
OverridePriorityListContainer overrideContainer = this.overrideContainerByInterface.get(interfaceClass);
|
||||
return overrideContainer != null ? (T) overrideContainer.getOverrideWithHighestPriority() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IDhApiOverrideable> T get(Class<T> interfaceClass, int priority) throws ClassCastException
|
||||
{
|
||||
OverridePriorityListContainer overrideContainer = this.overrideContainerByInterface.get(interfaceClass);
|
||||
return overrideContainer != null ? (T) overrideContainer.getOverrideWithPriority(priority) : null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void clear() { this.overrideContainerByInterface.clear(); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.seibel.lod.core.DependencyInjection;
|
||||
|
||||
import com.seibel.lod.api.items.interfaces.override.IDhApiOverrideable;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Contains a list of overrides and their priorities.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-9-5
|
||||
*/
|
||||
public class OverridePriorityListContainer implements IBindable
|
||||
{
|
||||
/** Sorted highest priority to lowest */
|
||||
private final ArrayList<OverridePriorityPair> overridePairList = new ArrayList<>();
|
||||
|
||||
|
||||
/** Doesn't do any validation */
|
||||
public void addOverride(IDhApiOverrideable override)
|
||||
{
|
||||
OverridePriorityPair priorityPair = new OverridePriorityPair(override, override.getPriority());
|
||||
this.overridePairList.add(priorityPair);
|
||||
|
||||
sortList();
|
||||
}
|
||||
|
||||
/** @return true if the override was removed from the list, false otherwise. */
|
||||
public boolean removeOverride(IDhApiOverrideable override)
|
||||
{
|
||||
if (this.overridePairList.contains(override))
|
||||
{
|
||||
this.overridePairList.remove(override);
|
||||
sortList();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// getters //
|
||||
|
||||
public IDhApiOverrideable getOverrideWithLowestPriority()
|
||||
{
|
||||
if (this.overridePairList.size() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// last item should have the highest priority
|
||||
return this.overridePairList.get(this.overridePairList.size() - 1).override;
|
||||
}
|
||||
}
|
||||
public IDhApiOverrideable getOverrideWithHighestPriority()
|
||||
{
|
||||
if (this.overridePairList.size() != 0)
|
||||
{
|
||||
return this.overridePairList.get(0).override;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public IDhApiOverrideable getCoreOverride()
|
||||
{
|
||||
int lastIndex = this.overridePairList.size() - 1;
|
||||
if (this.overridePairList.get(lastIndex) != null && this.overridePairList.get(lastIndex).priority == OverrideInjector.CORE_PRIORITY)
|
||||
{
|
||||
return this.overridePairList.get(lastIndex).override;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/** Returns null if no override with the given priority is found */
|
||||
public IDhApiOverrideable getOverrideWithPriority(int priority)
|
||||
{
|
||||
for (OverridePriorityPair pair : this.overridePairList)
|
||||
{
|
||||
if (pair.priority == priority)
|
||||
{
|
||||
return pair.override;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// utils //
|
||||
|
||||
/** sort the list so the highest priority item is first in the list */
|
||||
private void sortList() { this.overridePairList.sort((x,y) -> Integer.compare(y.priority, x.priority)); }
|
||||
|
||||
|
||||
|
||||
private class OverridePriorityPair
|
||||
{
|
||||
public final IDhApiOverrideable override;
|
||||
public int priority;
|
||||
|
||||
public OverridePriorityPair(IDhApiOverrideable newOverride, int newPriority)
|
||||
{
|
||||
this.override = newOverride;
|
||||
this.priority = newPriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.DependencyInjection;
|
||||
|
||||
import com.seibel.lod.api.items.interfaces.override.worldGenerator.IDhApiWorldGenerator;
|
||||
import com.seibel.lod.api.items.interfaces.world.IDhApiLevelWrapper;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
|
||||
import com.seibel.lod.core.util.StringUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class takes care of dependency injection for world generators. <Br>
|
||||
* This is done so other mods can override our world generator(s) to improve or replace them.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-9-8
|
||||
*/
|
||||
public class WorldGeneratorInjector
|
||||
{
|
||||
public static final WorldGeneratorInjector INSTANCE = new WorldGeneratorInjector();
|
||||
|
||||
private final HashMap<IDhApiLevelWrapper, OverrideInjector> worldGeneratorByLevelWrapper = new HashMap<>();
|
||||
/** World generators that aren't bound to a specific level and are used if no other world generators are bound. */
|
||||
private final OverrideInjector backupUniversalWorldGenerators;
|
||||
|
||||
/**
|
||||
* This is used to determine if an override is part of Distant Horizons'
|
||||
* Core or not.
|
||||
* This probably isn't the best way of going about this, but it works for now.
|
||||
*/
|
||||
private final String corePackagePath;
|
||||
|
||||
|
||||
|
||||
public WorldGeneratorInjector()
|
||||
{
|
||||
String thisPackageName = this.getClass().getPackage().getName();
|
||||
int secondPackageEndingIndex = StringUtil.nthIndexOf(thisPackageName, ".", 3);
|
||||
this.corePackagePath = thisPackageName.substring(0, secondPackageEndingIndex); // this should be "com.seibel.lod"
|
||||
|
||||
this.backupUniversalWorldGenerators = new OverrideInjector(this.corePackagePath);
|
||||
}
|
||||
|
||||
/** This constructor should only be used for testing different corePackagePaths. */
|
||||
public WorldGeneratorInjector(String newCorePackagePath)
|
||||
{
|
||||
this.corePackagePath = newCorePackagePath;
|
||||
|
||||
this.backupUniversalWorldGenerators = new OverrideInjector(this.corePackagePath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Binds the backup world generator. <Br>
|
||||
* See {@link DependencyInjector#bind(Class, IBindable) bind(Class, IBindable)} for full documentation.
|
||||
*
|
||||
* @throws IllegalArgumentException if a non-Distant Horizons world generator with the priority CORE is passed in
|
||||
* @see DependencyInjector#bind(Class, IBindable)
|
||||
*/
|
||||
public void bind(IDhApiWorldGenerator worldGeneratorImplementation) throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
bind(null, worldGeneratorImplementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the world generator to the given level. <Br>
|
||||
* See {@link DependencyInjector#bind(Class, IBindable) bind(Class, IBindable)} for full documentation.
|
||||
*
|
||||
* @throws IllegalArgumentException if a non-Distant Horizons world generator with the priority CORE is passed in
|
||||
* @see DependencyInjector#bind(Class, IBindable)
|
||||
*/
|
||||
public void bind(IDhApiLevelWrapper levelForWorldGenerator, IDhApiWorldGenerator worldGeneratorImplementation) throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
if (levelForWorldGenerator != null)
|
||||
{
|
||||
// bind this generator to a specific level
|
||||
if (!worldGeneratorByLevelWrapper.containsKey(levelForWorldGenerator))
|
||||
{
|
||||
worldGeneratorByLevelWrapper.put(levelForWorldGenerator, new OverrideInjector(this.corePackagePath));
|
||||
}
|
||||
|
||||
worldGeneratorByLevelWrapper.get(levelForWorldGenerator).bind(IDhApiWorldGenerator.class, worldGeneratorImplementation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// a null level wrapper binds the generator to all levels
|
||||
backupUniversalWorldGenerators.bind(IDhApiWorldGenerator.class, worldGeneratorImplementation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the backup world generator with the highest priority. <br>
|
||||
* See {@link OverrideInjector#get(Class) get(Class)} for more documentation.
|
||||
*
|
||||
* @see OverrideInjector#get(Class)
|
||||
*/
|
||||
public IDhApiWorldGenerator get() throws ClassCastException
|
||||
{
|
||||
return backupUniversalWorldGenerators.get(IDhApiWorldGenerator.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bound world generator with the highest priority. <br>
|
||||
* (Returns a backup world generator if no world generators have been bound for this specific level.) <br>
|
||||
* See {@link OverrideInjector#get(Class) get(Class)} for more documentation.
|
||||
*
|
||||
* @see OverrideInjector#get(Class)
|
||||
*/
|
||||
public IDhApiWorldGenerator get(IDhApiLevelWrapper levelForWorldGenerator) throws ClassCastException
|
||||
{
|
||||
if (!worldGeneratorByLevelWrapper.containsKey(levelForWorldGenerator))
|
||||
{
|
||||
// no generator exists for this specific level.
|
||||
// check for a backup universal world generator
|
||||
return backupUniversalWorldGenerators.get(IDhApiWorldGenerator.class);
|
||||
}
|
||||
|
||||
// use the existing world generator
|
||||
return worldGeneratorByLevelWrapper.get(levelForWorldGenerator).get(IDhApiWorldGenerator.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Removes all bound world generators. */
|
||||
public void clearBoundDependencies() // TODO this should be done when leaving the current world/server
|
||||
{
|
||||
this.worldGeneratorByLevelWrapper.clear();
|
||||
this.backupUniversalWorldGenerators.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
package com.seibel.lod.core;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* This file is similar to mcmod.info
|
||||
* <br>
|
||||
@@ -50,6 +48,5 @@ public final class ModInfo
|
||||
public static final int API_MAJOR_VERSION = 0;
|
||||
/** This version should be updated whenever new methods are added to the DH API */
|
||||
public static final int API_MINOR_VERSION = 0;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.dependencyInjection;
|
||||
package com.seibel.lod.core.interfaces.dependencyInjection;
|
||||
|
||||
/**
|
||||
* Necessary for all singletons that can be dependency injected.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.dependencyInjection;
|
||||
package com.seibel.lod.core.interfaces.dependencyInjection;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.interfaces.dependencyInjection;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
|
||||
/**
|
||||
* This class takes care of dependency injection for API events.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-9-13
|
||||
*/
|
||||
public interface IDhApiEventInjector extends IDependencyInjector<IDhApiEvent> // Note to self: Don't try adding a generic type to IDhApiEvent, the consturctor won't accept it
|
||||
{
|
||||
|
||||
/**
|
||||
* Unlinks the given event handler, preventing the handler from being called in the future.
|
||||
*
|
||||
* @throws IllegalArgumentException if the implementation object doesn't implement the interface
|
||||
* @return true if the handler was unbound, false if the handler wasn't bound.
|
||||
*/
|
||||
public boolean unbind(Class<? extends IDhApiEvent> dependencyInterface, Class<? extends IDhApiEvent> dependencyClassToRemove) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Fires all bound events of the given type (does nothing if no events are bound).
|
||||
*
|
||||
* @param dependencyInterface event type
|
||||
* @param eventParameterObject event parameter
|
||||
* @return if any of the events returned that this event should be canceled.
|
||||
* @param <T> the parameter type taken by the event handlers.
|
||||
*/
|
||||
public <T, U extends IDhApiEvent<T>> boolean fireAllEvents(Class<U> dependencyInterface, T eventParameterObject);
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.seibel.lod.core.dependencyInjection;
|
||||
package com.seibel.lod.core.interfaces.dependencyInjection;
|
||||
|
||||
|
||||
import com.seibel.lod.api.items.interfaces.override.IDhApiOverrideable;
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.core.util;
|
||||
|
||||
/**
|
||||
* Miscellaneous string helper functions.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-7-19
|
||||
*/
|
||||
public class StringUtil
|
||||
{
|
||||
/**
|
||||
* Returns the n-th index of the given string. <br> <br>
|
||||
*
|
||||
* Original source: https://stackoverflow.com/questions/3976616/how-to-find-nth-occurrence-of-character-in-a-string
|
||||
*/
|
||||
public static int nthIndexOf(String str, String substr, int n)
|
||||
{
|
||||
int pos = str.indexOf(substr);
|
||||
while (--n > 0 && pos != -1)
|
||||
pos = str.indexOf(substr, pos + 1);
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user