Versatile Java game engine with pluggable backends (this was used in Rogue, I think)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
3.7 KiB

package mightypork.gamecore.core.init;
10 years ago
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import mightypork.gamecore.core.App;
10 years ago
import mightypork.utils.Reflect;
import mightypork.utils.annotations.Stub;
import mightypork.utils.logging.Log;
/**
* App initializer. A sequence of initializers is executed once the start()
* method on App is called. Adding initializers is one way to customize the App
* behavior and features.
*
10 years ago
* @author Ondřej Hruška (MightyPork)
*/
public abstract class InitTask {
/** App instance assigned using <code>bind()</code> */
10 years ago
protected App app;
10 years ago
/**
* Assign the initialized app instance to an "app" field.
*
10 years ago
* @param app app
*/
public final void bind(App app)
10 years ago
{
this.app = app;
}
10 years ago
/**
* An init method that is called before the <code>run()</code> method.<br>
10 years ago
* This method should be left unimplemented in the task, and can be used to
* configure the init task when using it as anonymous inner type.
*/
@Stub
public void init()
{
//
10 years ago
}
10 years ago
/**
* Hook for extra action before the main task action.<br>
* Can be overridden during app configuration to "bake-in" extra actions.
*/
@Stub
public void before()
{
//
}
/**
* Run the initializer on app.
10 years ago
*/
public abstract void run();
/**
* Hook executed after the "run()" method.<br>
* Can be overridden during app configuration to "bake-in" extra actions.
*/
@Stub
public void after()
{
//
}
10 years ago
/**
* Get name of this initializer (for dependency resolver).<br>
* The name should be short, snake_case and precise.
*
10 years ago
* @return name
*/
public abstract String getName();
10 years ago
/**
* Get what other initializers must be already loaded before this can load.<br>
* Depending on itself or creating a circular dependency will cause error.<br>
* If the dependencies cannot be satisfied, the initialization sequence will
* be aborted.
*
10 years ago
* @return array of names of required initializers.
*/
@Stub
public String[] getDependencies()
{
return new String[] {};
}
10 years ago
/**
* Order init tasks so that all dependencies are loaded before thye are
* needed by the tasks.
*
10 years ago
* @param tasks task list
* @return task list ordered
*/
public static List<InitTask> inOrder(List<InitTask> tasks)
{
final List<InitTask> remaining = new ArrayList<>(tasks);
final List<InitTask> ordered = new ArrayList<>();
final Set<String> loaded = new HashSet<>();
10 years ago
// resolve task order
int addedThisIteration = 0;
do {
for (final Iterator<InitTask> i = remaining.iterator(); i.hasNext();) {
final InitTask task = i.next();
10 years ago
String[] deps = task.getDependencies();
if (deps == null) deps = new String[] {};
10 years ago
int unmetDepsCount = deps.length;
for (final String d : deps) {
10 years ago
if (loaded.contains(d)) unmetDepsCount--;
}
10 years ago
if (unmetDepsCount == 0) {
ordered.add(task);
loaded.add(task.getName());
i.remove();
addedThisIteration++;
}
}
} while (addedThisIteration > 0);
10 years ago
// check if any tasks are left out
if (remaining.size() > 0) {
10 years ago
// build error message for each bad task
int badInitializers = 0;
for (final InitTask task : remaining) {
10 years ago
if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) {
continue;
}
10 years ago
badInitializers++;
10 years ago
String notSatisfied = "";
for (final String d : task.getDependencies()) {
10 years ago
if (!loaded.contains(d)) {
10 years ago
if (!notSatisfied.isEmpty()) {
notSatisfied += ", ";
}
10 years ago
notSatisfied += d;
}
}
10 years ago
Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied);
}
10 years ago
if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied.");
}
10 years ago
return ordered;
}
}