Add one time API events (IE setup events)
This allows users to bind to setup events after they've happened and still have the event fire. This is useful for setup since mod load order isn't defined.
This commit is contained in:
+28
-3
@@ -1,15 +1,40 @@
|
||||
package com.seibel.lod.api.methods.events.abstractEvents;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-6
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public abstract class DhApiAfterDhInitEvent
|
||||
implements IDhApiEvent<Void>
|
||||
public abstract class DhApiAfterDhInitEvent implements IDhApiEvent<Void>
|
||||
{
|
||||
/** Fired after Distant Horizons finishes its initial setup on Minecraft startup. */
|
||||
public abstract void afterDistantHorizonsInit();
|
||||
|
||||
|
||||
//=========================//
|
||||
// internal DH API methods //
|
||||
//=========================//
|
||||
|
||||
@Override
|
||||
public final boolean fireEvent(Void ignoredParam)
|
||||
{
|
||||
this.afterDistantHorizonsInit();
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiAfterDhInitEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiAfterDhInitEvent.class, new DhApiEventDefinition(false, true));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiAfterDhInitEvent.class); }
|
||||
|
||||
}
|
||||
+15
-6
@@ -2,14 +2,14 @@ package com.seibel.lod.api.methods.events.abstractEvents;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.lod.core.util.math.Mat4f;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-6
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public abstract class DhApiAfterRenderEvent
|
||||
implements IDhApiEvent<DhApiAfterRenderEvent.EventParam>
|
||||
public abstract class DhApiAfterRenderEvent implements IDhApiEvent<DhApiAfterRenderEvent.EventParam>
|
||||
{
|
||||
/** Fired after Distant Horizons finishes rendering fake chunks. */
|
||||
public abstract void afterRender(EventParam input);
|
||||
@@ -22,12 +22,21 @@ public abstract class DhApiAfterRenderEvent
|
||||
@Override
|
||||
public final boolean fireEvent(EventParam input)
|
||||
{
|
||||
afterRender(input);
|
||||
this.afterRender(input);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiAfterRenderEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiAfterRenderEvent.class, new DhApiEventDefinition(false, false));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final boolean getCancelable() { return false; }
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiAfterRenderEvent.class); }
|
||||
|
||||
|
||||
//==================//
|
||||
|
||||
+15
-5
@@ -3,13 +3,14 @@ package com.seibel.lod.api.methods.events.abstractEvents;
|
||||
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-6
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public abstract class DhApiBeforeDhInitEvent
|
||||
implements IDhApiEvent<Void>
|
||||
public abstract class DhApiBeforeDhInitEvent implements IDhApiEvent<Void>
|
||||
{
|
||||
/** Fired before Distant Horizons starts its initial setup on Minecraft startup. */
|
||||
public abstract void beforeDistantHorizonsInit();
|
||||
@@ -22,11 +23,20 @@ public abstract class DhApiBeforeDhInitEvent
|
||||
@Override
|
||||
public final boolean fireEvent(Void ignoredParam)
|
||||
{
|
||||
beforeDistantHorizonsInit();
|
||||
this.beforeDistantHorizonsInit();
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiBeforeDhInitEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiBeforeDhInitEvent.class, new DhApiEventDefinition(false, true));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final boolean getCancelable() { return false; }
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiBeforeDhInitEvent.class); }
|
||||
|
||||
}
|
||||
+15
-6
@@ -2,14 +2,14 @@ package com.seibel.lod.api.methods.events.abstractEvents;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.lod.core.util.math.Mat4f;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-6
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public abstract class DhApiBeforeRenderEvent
|
||||
implements IDhApiEvent<DhApiBeforeRenderEvent.EventParam>
|
||||
public abstract class DhApiBeforeRenderEvent implements IDhApiEvent<DhApiBeforeRenderEvent.EventParam>
|
||||
{
|
||||
/**
|
||||
* Fired before Distant Horizons renders fake chunks.
|
||||
@@ -24,10 +24,19 @@ public abstract class DhApiBeforeRenderEvent
|
||||
//=========================//
|
||||
|
||||
@Override
|
||||
public final boolean fireEvent(EventParam input) { return beforeRender(input); }
|
||||
public final boolean fireEvent(EventParam input) { return this.beforeRender(input); }
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiBeforeRenderEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiBeforeRenderEvent.class, new DhApiEventDefinition(true, false));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final boolean getCancelable() { return true; }
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiBeforeRenderEvent.class); }
|
||||
|
||||
|
||||
//==================//
|
||||
|
||||
+15
-5
@@ -2,13 +2,14 @@ package com.seibel.lod.api.methods.events.abstractEvents;
|
||||
|
||||
import com.seibel.lod.api.interfaces.world.IDhApiLevelWrapper;
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-10
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public abstract class DhApiLevelLoadEvent
|
||||
implements IDhApiEvent<DhApiLevelLoadEvent.EventParam>
|
||||
public abstract class DhApiLevelLoadEvent implements IDhApiEvent<DhApiLevelLoadEvent.EventParam>
|
||||
{
|
||||
/** Fired after Distant Horizons loads a new level. */
|
||||
public abstract void onLevelLoad(EventParam input);
|
||||
@@ -21,12 +22,21 @@ public abstract class DhApiLevelLoadEvent
|
||||
@Override
|
||||
public final boolean fireEvent(EventParam input)
|
||||
{
|
||||
onLevelLoad(input);
|
||||
this.onLevelLoad(input);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiLevelLoadEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiLevelLoadEvent.class, new DhApiEventDefinition(false, false));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final boolean getCancelable() { return false; }
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiLevelLoadEvent.class); }
|
||||
|
||||
|
||||
//==================//
|
||||
|
||||
+15
-5
@@ -2,13 +2,14 @@ package com.seibel.lod.api.methods.events.abstractEvents;
|
||||
|
||||
import com.seibel.lod.api.interfaces.world.IDhApiLevelWrapper;
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-10
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public abstract class DhApiLevelSaveEvent
|
||||
implements IDhApiEvent<DhApiLevelSaveEvent.EventParam>
|
||||
public abstract class DhApiLevelSaveEvent implements IDhApiEvent<DhApiLevelSaveEvent.EventParam>
|
||||
{
|
||||
/** Fired after Distant Horizons saves LOD data for the server. */
|
||||
public abstract void onLevelSave(EventParam input);
|
||||
@@ -21,12 +22,21 @@ public abstract class DhApiLevelSaveEvent
|
||||
@Override
|
||||
public final boolean fireEvent(EventParam input)
|
||||
{
|
||||
onLevelSave(input);
|
||||
this.onLevelSave(input);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiLevelSaveEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiLevelSaveEvent.class, new DhApiEventDefinition(false, false));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final boolean getCancelable() { return false; }
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiLevelSaveEvent.class); }
|
||||
|
||||
|
||||
//==================//
|
||||
|
||||
+15
-5
@@ -2,13 +2,14 @@ package com.seibel.lod.api.methods.events.abstractEvents;
|
||||
|
||||
import com.seibel.lod.api.interfaces.world.IDhApiLevelWrapper;
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-10
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public abstract class DhApiLevelUnloadEvent
|
||||
implements IDhApiEvent<DhApiLevelUnloadEvent.EventParam>
|
||||
public abstract class DhApiLevelUnloadEvent implements IDhApiEvent<DhApiLevelUnloadEvent.EventParam>
|
||||
{
|
||||
/** Fired before Distant Horizons unloads a level. */
|
||||
public abstract void onLevelUnload(EventParam input);
|
||||
@@ -21,12 +22,21 @@ public abstract class DhApiLevelUnloadEvent
|
||||
@Override
|
||||
public final boolean fireEvent(EventParam input)
|
||||
{
|
||||
onLevelUnload(input);
|
||||
this.onLevelUnload(input);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiLevelUnloadEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiLevelUnloadEvent.class, new DhApiEventDefinition(false, false));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final boolean getCancelable() { return false; }
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiLevelUnloadEvent.class); }
|
||||
|
||||
|
||||
//==================//
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.seibel.lod.api.methods.events.interfaces;
|
||||
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.interfaces.dependencyInjection.IBindable;
|
||||
|
||||
/**
|
||||
* A combination of all interfaces required by all
|
||||
* DH Api events.
|
||||
*
|
||||
* The interface used by all DH Api events.
|
||||
*
|
||||
* @param <T> This is the datatype that will be passed into the event handler's method.
|
||||
*
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-9-6
|
||||
* @version 2022-11-20
|
||||
*/
|
||||
public interface IDhApiEvent<T> extends IBindable
|
||||
{
|
||||
@@ -18,11 +18,12 @@ public interface IDhApiEvent<T> extends IBindable
|
||||
//==========//
|
||||
|
||||
/**
|
||||
* Returns if the event should be automatically unbound
|
||||
* Returns true if the event should be automatically unbound
|
||||
* after firing. <br>
|
||||
* Can be useful for one time setup events or waiting for a specific game state. <br> <Br>
|
||||
*
|
||||
* Defaults to False (the event will not be removed after firing).
|
||||
* Defaults to False
|
||||
* IE: The event will not be removed after firing and will continue firing until removed.
|
||||
*/
|
||||
default boolean removeAfterFiring() { return false; };
|
||||
|
||||
@@ -31,8 +32,11 @@ public interface IDhApiEvent<T> extends IBindable
|
||||
// internal //
|
||||
//==========//
|
||||
|
||||
/** Returns true if the event can be canceled. */
|
||||
boolean getCancelable();
|
||||
/**
|
||||
* The event definition includes meta information about how the event will behave. <br>
|
||||
* For example: if the event is cancelable or not.
|
||||
*/
|
||||
DhApiEventDefinition getEventDefinition();
|
||||
|
||||
/**
|
||||
* Called internally by Distant Horizons when the event happens.
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.api.objects.events;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* The event definition includes meta information about how the event will behave.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-11-20
|
||||
*/
|
||||
public class DhApiEventDefinition
|
||||
{
|
||||
/** True if the event can be canceled. */
|
||||
public final boolean isCancelable;
|
||||
|
||||
/**
|
||||
* True if the event will only ever be fired once. <Br>
|
||||
* An example of this would be initial setup methods, DH won't run its initial setup more than once. <br><br>
|
||||
*
|
||||
* If a handler is bound for a one time event after the event has been fired, the handler will be immediately fired.
|
||||
*/
|
||||
public final boolean isOneTimeEvent;
|
||||
|
||||
|
||||
|
||||
public DhApiEventDefinition(boolean isCancelable, boolean isOneTimeEvent)
|
||||
{
|
||||
this.isCancelable = isCancelable;
|
||||
this.isOneTimeEvent = isOneTimeEvent;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,22 +20,25 @@
|
||||
package com.seibel.lod.core.DependencyInjection;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
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;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class takes care of dependency injection for API events.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-9-13
|
||||
* @version 2022-11-20
|
||||
*/
|
||||
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());
|
||||
private static final HashMap<Class<? extends IDhApiEvent>, Object> FIRED_ONE_TIME_EVENT_PARAMETERS_BY_EVENT_INTERFACE = new HashMap<>();
|
||||
|
||||
public static final DhApiEventInjector INSTANCE = new DhApiEventInjector();
|
||||
|
||||
@@ -44,34 +47,56 @@ public class DhApiEventInjector extends DependencyInjector<IDhApiEvent> implemen
|
||||
private DhApiEventInjector() { super(IDhApiEvent.class, true); }
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean unbind(Class<? extends IDhApiEvent> dependencyInterface, Class<? extends IDhApiEvent> dependencyClassToRemove) throws IllegalArgumentException
|
||||
public void bind(Class<? extends IDhApiEvent> eventInterface, IDhApiEvent eventImplementation) throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
// is this a one time event?
|
||||
if (ApiEventDefinitionHandler.getEventDefinition(eventInterface).isOneTimeEvent)
|
||||
{
|
||||
// has this one time event been fired yet?
|
||||
if (FIRED_ONE_TIME_EVENT_PARAMETERS_BY_EVENT_INTERFACE.containsKey(eventInterface))
|
||||
{
|
||||
// the one time event has happened, fire the handler
|
||||
|
||||
// this has to be an unsafe cast since the hash map can't hold the generic objects
|
||||
Object parameter = FIRED_ONE_TIME_EVENT_PARAMETERS_BY_EVENT_INTERFACE.get(eventInterface);
|
||||
eventImplementation.fireEvent(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
// bind the event handler
|
||||
super.bind(eventInterface, eventImplementation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unbind(Class<? extends IDhApiEvent> eventInterface, Class<? extends IDhApiEvent> eventClassToRemove) 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);
|
||||
boolean implementsInterface = this.checkIfClassImplements(eventClassToRemove, eventInterface) ||
|
||||
this.checkIfClassExtends(eventClassToRemove, eventInterface);
|
||||
boolean implementsBindable = this.checkIfClassImplements(eventClassToRemove, this.bindableInterface);
|
||||
|
||||
// display any errors
|
||||
if (!implementsInterface)
|
||||
{
|
||||
throw new IllegalArgumentException("The event handler [" + dependencyClassToRemove.getSimpleName() + "] doesn't implement or extend: [" + dependencyInterface.getSimpleName() + "].");
|
||||
throw new IllegalArgumentException("The event handler [" + eventClassToRemove.getSimpleName() + "] doesn't implement or extend: [" + eventInterface.getSimpleName() + "].");
|
||||
}
|
||||
if (!implementsBindable)
|
||||
{
|
||||
throw new IllegalArgumentException("The event handler [" + dependencyClassToRemove.getSimpleName() + "] doesn't implement the interface: [" + IBindable.class.getSimpleName() + "].");
|
||||
throw new IllegalArgumentException("The event handler [" + eventClassToRemove.getSimpleName() + "] doesn't implement the interface: [" + IBindable.class.getSimpleName() + "].");
|
||||
}
|
||||
|
||||
|
||||
// actually remove the dependency
|
||||
if (this.dependencies.containsKey(dependencyInterface))
|
||||
if (this.dependencies.containsKey(eventInterface))
|
||||
{
|
||||
ArrayList<IDhApiEvent> dependencyList = this.dependencies.get(dependencyInterface);
|
||||
ArrayList<IDhApiEvent> dependencyList = this.dependencies.get(eventInterface);
|
||||
int indexToRemove = -1;
|
||||
for(int i = 0; i < dependencyList.size(); i++)
|
||||
{
|
||||
IBindable dependency = dependencyList.get(i);
|
||||
if (dependency.getClass().equals(dependencyClassToRemove))
|
||||
if (dependency.getClass().equals(eventClassToRemove))
|
||||
{
|
||||
indexToRemove = i;
|
||||
break;
|
||||
@@ -89,11 +114,20 @@ public class DhApiEventInjector extends DependencyInjector<IDhApiEvent> implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, U extends IDhApiEvent<T>> boolean fireAllEvents(Class<U> dependencyInterface, T eventParameterObject)
|
||||
public <T, U extends IDhApiEvent<T>> boolean fireAllEvents(Class<U> eventInterface, T eventParameterObject)
|
||||
{
|
||||
boolean cancelEvent = false;
|
||||
|
||||
ArrayList<U> eventList = this.getAll(dependencyInterface);
|
||||
// if this is a one time event, record it
|
||||
if (ApiEventDefinitionHandler.getEventDefinition(eventInterface).isOneTimeEvent &&
|
||||
!FIRED_ONE_TIME_EVENT_PARAMETERS_BY_EVENT_INTERFACE.containsKey(eventInterface))
|
||||
{
|
||||
FIRED_ONE_TIME_EVENT_PARAMETERS_BY_EVENT_INTERFACE.put(eventInterface, eventParameterObject);
|
||||
}
|
||||
|
||||
|
||||
// fire each bound event
|
||||
ArrayList<U> eventList = this.getAll(eventInterface);
|
||||
for (IDhApiEvent<T> event : eventList)
|
||||
{
|
||||
if (event != null)
|
||||
@@ -106,8 +140,7 @@ public class DhApiEventInjector extends DependencyInjector<IDhApiEvent> implemen
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// TODO log the failed event handler
|
||||
LOGGER.error("Exception thrown by event handler :" + e.getMessage(), e);
|
||||
LOGGER.error("Exception thrown by event handler [" + event.getClass().getSimpleName() + "] for event type [" + eventInterface.getSimpleName() + "], error:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.events;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Holds the API event definitions
|
||||
* so, they can be accessed without an
|
||||
* event instance.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public class ApiEventDefinitionHandler
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger(ApiEventDefinitionHandler.class.getSimpleName());
|
||||
// note to self: don't try adding a generic interface type here, the event dependency handler's constructor method won't accept it
|
||||
private static final HashMap<Class<? extends IDhApiEvent>, DhApiEventDefinition> DEFINITIONS_BY_EVENT_INTERFACE = new HashMap<>();
|
||||
|
||||
public ApiEventDefinitionHandler INSTANCE = new ApiEventDefinitionHandler();
|
||||
|
||||
|
||||
|
||||
private ApiEventDefinitionHandler() { }
|
||||
|
||||
|
||||
|
||||
public static void setEventDefinition(Class<? extends IDhApiEvent> eventInterface, DhApiEventDefinition definition)
|
||||
{
|
||||
if (DEFINITIONS_BY_EVENT_INTERFACE.containsKey(eventInterface))
|
||||
{
|
||||
LOGGER.warn("duplicate key added [" + eventInterface.getSimpleName() + "]");
|
||||
}
|
||||
|
||||
DEFINITIONS_BY_EVENT_INTERFACE.put(eventInterface, definition);
|
||||
}
|
||||
|
||||
public static DhApiEventDefinition getEventDefinition(Class<? extends IDhApiEvent> eventInterface)
|
||||
{
|
||||
if (!DEFINITIONS_BY_EVENT_INTERFACE.containsKey(eventInterface))
|
||||
{
|
||||
throw new NullPointerException("event definition missing for: [" + eventInterface.getSimpleName() + "]");
|
||||
}
|
||||
|
||||
return DEFINITIONS_BY_EVENT_INTERFACE.get(eventInterface);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package testItems.events.abstractObjects;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* A dummy event implementation used for unit testing.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-11-20
|
||||
*/
|
||||
public abstract class DhApiOneTimeTestEvent implements IDhApiEvent<Boolean>
|
||||
{
|
||||
public abstract void onTestEvent(Boolean input);
|
||||
|
||||
/** just used for testing */
|
||||
public abstract Boolean getTestValue();
|
||||
|
||||
|
||||
|
||||
//=========================//
|
||||
// internal DH API methods //
|
||||
//=========================//
|
||||
|
||||
@Override
|
||||
public final boolean fireEvent(Boolean input)
|
||||
{
|
||||
this.onTestEvent(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiOneTimeTestEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiOneTimeTestEvent.class, new DhApiEventDefinition(false, true));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiOneTimeTestEvent.class); }
|
||||
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
package testItems.events.abstractObjects;
|
||||
|
||||
import com.seibel.lod.api.methods.events.interfaces.IDhApiEvent;
|
||||
import com.seibel.lod.api.objects.events.DhApiEventDefinition;
|
||||
import com.seibel.lod.core.events.ApiEventDefinitionHandler;
|
||||
|
||||
/**
|
||||
* A dummy event implementation used for unit testing.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-9-13
|
||||
* @version 2022-11-20
|
||||
*/
|
||||
public abstract class DhApiTestEvent
|
||||
implements IDhApiEvent<Boolean>
|
||||
public abstract class DhApiTestEvent implements IDhApiEvent<Boolean>
|
||||
{
|
||||
|
||||
public abstract void onTestEvent(Boolean input);
|
||||
@@ -26,11 +27,21 @@ public abstract class DhApiTestEvent
|
||||
@Override
|
||||
public final boolean fireEvent(Boolean input)
|
||||
{
|
||||
onTestEvent(input);
|
||||
this.onTestEvent(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
private static boolean firstTimeSetupComplete = false;
|
||||
public DhApiTestEvent()
|
||||
{
|
||||
if (!firstTimeSetupComplete)
|
||||
{
|
||||
firstTimeSetupComplete = true;
|
||||
ApiEventDefinitionHandler.setEventDefinition(DhApiTestEvent.class, new DhApiEventDefinition(false, false));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean getCancelable() { return false; }
|
||||
public final DhApiEventDefinition getEventDefinition() { return ApiEventDefinitionHandler.getEventDefinition(DhApiTestEvent.class); }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package testItems.events.objects;
|
||||
|
||||
import testItems.events.abstractObjects.DhApiOneTimeTestEvent;
|
||||
|
||||
/**
|
||||
* Dummy test event for unit tests.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-11-20
|
||||
*/
|
||||
public class DhOneTimeTestEventHandler extends DhApiOneTimeTestEvent
|
||||
{
|
||||
public Boolean eventFiredValue = null;
|
||||
|
||||
@Override
|
||||
public void onTestEvent(Boolean input) { this.eventFiredValue = input; }
|
||||
|
||||
@Override
|
||||
public boolean removeAfterFiring() { return false; }
|
||||
|
||||
|
||||
// test (non standard) methods //
|
||||
@Override
|
||||
public Boolean getTestValue() { return this.eventFiredValue; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package testItems.events.objects;
|
||||
|
||||
/**
|
||||
* Dummy test event for unit tests.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-11-20
|
||||
*/
|
||||
public class DhOneTimeTestEventHandlerAlt extends DhOneTimeTestEventHandler
|
||||
{
|
||||
// all other code should be a duplicate of the parent
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@ import testItems.events.abstractObjects.DhApiTestEvent;
|
||||
* @author James Seibel
|
||||
* @version 2022-9-11
|
||||
*/
|
||||
public class DhTestEvent extends DhApiTestEvent
|
||||
public class DhTestEventHandler extends DhApiTestEvent
|
||||
{
|
||||
public Boolean eventFiredValue = null;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import testItems.events.abstractObjects.DhApiTestEvent;
|
||||
* @author James Seibel
|
||||
* @version 2022-9-11
|
||||
*/
|
||||
public class DhTestEventAlt extends DhApiTestEvent
|
||||
public class DhTestEventHandlerAlt extends DhApiTestEvent
|
||||
{
|
||||
public Boolean eventFiredValue = null;
|
||||
|
||||
@@ -3,34 +3,38 @@ package tests;
|
||||
import com.seibel.lod.core.DependencyInjection.DhApiEventInjector;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import testItems.events.abstractObjects.DhApiOneTimeTestEvent;
|
||||
import testItems.events.objects.DhOneTimeTestEventHandler;
|
||||
import testItems.events.objects.DhOneTimeTestEventHandlerAlt;
|
||||
import testItems.events.abstractObjects.DhApiTestEvent;
|
||||
import testItems.events.objects.DhTestEvent;
|
||||
import testItems.events.objects.DhTestEventAlt;
|
||||
import testItems.events.objects.DhTestEventHandler;
|
||||
import testItems.events.objects.DhTestEventHandlerAlt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-13
|
||||
* @version 2022-11-21
|
||||
*/
|
||||
public class EventInjectorTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testEventDependencies() // this also tests list dependencies since there can be more than one event handler bound per event
|
||||
public void testGeneralAndRecurringEvents() // this also tests list dependencies since there can be more than one event handler bound per event
|
||||
{
|
||||
// Injector setup
|
||||
DhApiEventInjector TEST_EVENT_HANDLER = DhApiEventInjector.INSTANCE;
|
||||
|
||||
TEST_EVENT_HANDLER.clear();
|
||||
|
||||
|
||||
// pre-dependency setup
|
||||
Assert.assertNull("Nothing should have been bound.", TEST_EVENT_HANDLER.get(DhApiTestEvent.class));
|
||||
|
||||
|
||||
// dependency setup
|
||||
TEST_EVENT_HANDLER.bind(DhApiTestEvent.class, new DhTestEvent());
|
||||
TEST_EVENT_HANDLER.bind(DhApiTestEvent.class, new DhTestEventAlt());
|
||||
TEST_EVENT_HANDLER.bind(DhApiTestEvent.class, new DhTestEventHandler());
|
||||
TEST_EVENT_HANDLER.bind(DhApiTestEvent.class, new DhTestEventHandlerAlt());
|
||||
TEST_EVENT_HANDLER.runDelayedSetup();
|
||||
|
||||
|
||||
@@ -60,8 +64,8 @@ public class EventInjectorTest
|
||||
|
||||
// unbind
|
||||
DhApiTestEvent unboundEvent = afterRenderEventList.get(0);
|
||||
Assert.assertTrue("Unbind should've removed item.", TEST_EVENT_HANDLER.unbind(DhApiTestEvent.class, DhTestEvent.class));
|
||||
Assert.assertFalse("Unbind should've already removed item.", TEST_EVENT_HANDLER.unbind(DhApiTestEvent.class, DhTestEvent.class));
|
||||
Assert.assertTrue("Unbind should've removed item.", TEST_EVENT_HANDLER.unbind(DhApiTestEvent.class, DhTestEventHandler.class));
|
||||
Assert.assertFalse("Unbind should've already removed item.", TEST_EVENT_HANDLER.unbind(DhApiTestEvent.class, DhTestEventHandler.class));
|
||||
|
||||
// check unbinding
|
||||
afterRenderEventList = TEST_EVENT_HANDLER.getAll(DhApiTestEvent.class);
|
||||
@@ -72,10 +76,56 @@ public class EventInjectorTest
|
||||
// check unbound event firing
|
||||
Assert.assertEquals("fireAllEvents canceled returned canceled incorrectly.", false, TEST_EVENT_HANDLER.fireAllEvents(DhApiTestEvent.class, false));
|
||||
// remaining event
|
||||
Assert.assertEquals("Event not fired for remaining object.", false, ((DhTestEventAlt) afterRenderEventList.get(0)).eventFiredValue);
|
||||
Assert.assertEquals("Event not fired for remaining object.", false, ((DhTestEventHandlerAlt) afterRenderEventList.get(0)).eventFiredValue);
|
||||
// unbound event
|
||||
Assert.assertEquals("Event fired for unbound object.", true, unboundEvent.getTestValue());
|
||||
|
||||
|
||||
|
||||
// prevent event handlers from being bound to the wrong event interface
|
||||
Assert.assertThrows("Event bound to a non-implementing interface.", IllegalArgumentException.class, () -> { TEST_EVENT_HANDLER.bind(DhApiOneTimeTestEvent.class, new DhTestEventHandler()); });
|
||||
Assert.assertThrows("Event bound to a non-implementing interface.", IllegalArgumentException.class, () -> { TEST_EVENT_HANDLER.bind(DhApiTestEvent.class, new DhOneTimeTestEventHandler()); });
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneTimeEventFiring()
|
||||
{
|
||||
// Injector setup
|
||||
DhApiEventInjector TEST_EVENT_HANDLER = DhApiEventInjector.INSTANCE;
|
||||
TEST_EVENT_HANDLER.clear();
|
||||
|
||||
|
||||
// pre-dependency setup
|
||||
Assert.assertNull("Nothing should have been bound.", TEST_EVENT_HANDLER.get(DhApiOneTimeTestEvent.class));
|
||||
|
||||
|
||||
// pre-event fire binding
|
||||
TEST_EVENT_HANDLER.bind(DhApiOneTimeTestEvent.class, new DhOneTimeTestEventHandler());
|
||||
TEST_EVENT_HANDLER.runDelayedSetup();
|
||||
|
||||
|
||||
// pre-bound event firing
|
||||
Assert.assertEquals("fireAllEvents canceled returned canceled incorrectly.", true, TEST_EVENT_HANDLER.fireAllEvents(DhApiOneTimeTestEvent.class, true));
|
||||
// validate event fired correctly
|
||||
ArrayList<DhApiOneTimeTestEvent> oneTimeEventList = TEST_EVENT_HANDLER.getAll(DhApiOneTimeTestEvent.class);
|
||||
Assert.assertEquals("Event not fired for pre-fire object.", true, oneTimeEventList.get(0).getTestValue());
|
||||
|
||||
|
||||
// post-event fire binding
|
||||
// the event should fire instantly
|
||||
TEST_EVENT_HANDLER.bind(DhApiOneTimeTestEvent.class, new DhOneTimeTestEventHandlerAlt());
|
||||
// validate both events have fired
|
||||
oneTimeEventList = TEST_EVENT_HANDLER.getAll(DhApiOneTimeTestEvent.class);
|
||||
Assert.assertEquals("Event not fired for pre-fire object.", true, oneTimeEventList.get(0).getTestValue());
|
||||
Assert.assertEquals("Event not fired for post-fire object.", true, oneTimeEventList.get(1).getTestValue());
|
||||
|
||||
|
||||
|
||||
// recurring event test
|
||||
TEST_EVENT_HANDLER.bind(DhApiTestEvent.class, new DhTestEventHandler());
|
||||
ArrayList<DhApiTestEvent> recurringEventList = TEST_EVENT_HANDLER.getAll(DhApiTestEvent.class);
|
||||
Assert.assertNull("This unrealted recurring event shouldn't have been fired.", recurringEventList.get(0).getTestValue());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user