parent
2398a4ee6a
commit
8e9a658098
@ -0,0 +1,168 @@ |
||||
package mightypork.gamecore.core.init; |
||||
|
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.HashMap; |
||||
import java.util.HashSet; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import mightypork.utils.Reflect; |
||||
import mightypork.utils.logging.Log; |
||||
|
||||
|
||||
/** |
||||
* initialization sequence that takes care of task dependencies and ordering. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public class InitSequence { |
||||
|
||||
private final Map<String, InitTask> taskMap = new HashMap<>(); |
||||
|
||||
|
||||
/** |
||||
* Add a task. If a task with the name already exists, replace it. |
||||
* |
||||
* @param task task to add |
||||
*/ |
||||
public void addTask(InitTask task) |
||||
{ |
||||
final String name = task.getName(); |
||||
|
||||
// detailed logging
|
||||
// if (taskMap.containsKey(name)) {
|
||||
// Log.f3("REPL init " + Str.pad("\"" + name + "\"", 20) + " <" + Str.val(task) + ">");
|
||||
// } else {
|
||||
// Log.f3("ADD init " + Str.pad("\"" + name + "\"", 20) + " <" + Str.val(task) + ">");
|
||||
// }
|
||||
|
||||
taskMap.put(name, task); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get task sequence in proper order. |
||||
* |
||||
* @return initialization sequence |
||||
*/ |
||||
public List<InitTask> getSequence() |
||||
{ |
||||
final List<InitTask> remainingTasks = new ArrayList<>(taskMap.values()); |
||||
|
||||
final List<InitTask> orderedTasks = new ArrayList<>(); |
||||
final Set<String> loadedTaskNames = new HashSet<>(); |
||||
|
||||
// resolve task order
|
||||
InitTask taskToAdd = null; |
||||
do { |
||||
taskToAdd = null; |
||||
|
||||
for (final InitTask task : remainingTasks) { |
||||
|
||||
String[] deps = task.getDependencies(); |
||||
if (deps == null) deps = new String[] {}; |
||||
|
||||
int missingDeps = deps.length; |
||||
|
||||
for (final String d : deps) { |
||||
if (loadedTaskNames.contains(d)) missingDeps--; |
||||
} |
||||
|
||||
if (missingDeps == 0) { |
||||
if (taskToAdd == null || taskToAdd.getPriority() < task.getPriority()) { |
||||
taskToAdd = task; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (taskToAdd != null) { |
||||
orderedTasks.add(taskToAdd); |
||||
loadedTaskNames.add(taskToAdd.getName()); |
||||
remainingTasks.remove(taskToAdd); |
||||
} |
||||
|
||||
} while (taskToAdd != null); |
||||
|
||||
checkLeftovers(loadedTaskNames, remainingTasks); |
||||
|
||||
return orderedTasks; |
||||
} |
||||
|
||||
|
||||
public List<InitTask> getSequenceOldImpl() |
||||
{ |
||||
final List<InitTask> remainingTasks = new ArrayList<>(taskMap.values()); |
||||
|
||||
final List<InitTask> orderedTasks = new ArrayList<>(); |
||||
final Set<String> loadedTaskNames = new HashSet<>(); |
||||
|
||||
// resolve task order
|
||||
int addedThisIteration = 0; |
||||
do { |
||||
addedThisIteration = 0; |
||||
for (final Iterator<InitTask> i = remainingTasks.iterator(); i.hasNext();) { |
||||
final InitTask task = i.next(); |
||||
|
||||
String[] deps = task.getDependencies(); |
||||
if (deps == null) deps = new String[] {}; |
||||
|
||||
int missingDeps = deps.length; |
||||
|
||||
for (final String d : deps) { |
||||
if (loadedTaskNames.contains(d)) missingDeps--; |
||||
} |
||||
|
||||
if (missingDeps == 0) { |
||||
orderedTasks.add(task); |
||||
loadedTaskNames.add(task.getName()); |
||||
i.remove(); |
||||
addedThisIteration++; |
||||
} |
||||
} |
||||
} while (addedThisIteration > 0); |
||||
|
||||
checkLeftovers(loadedTaskNames, remainingTasks); |
||||
|
||||
return orderedTasks; |
||||
} |
||||
|
||||
|
||||
private void checkLeftovers(Collection<String> loadedTaskNames, Collection<InitTask> remainingTasks) |
||||
{ |
||||
// check if any tasks are left out
|
||||
if (remainingTasks.size() > 0) { |
||||
|
||||
// build error message for each bad task
|
||||
int badInitializers = 0; |
||||
for (final InitTask task : remainingTasks) { |
||||
|
||||
if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) { |
||||
continue; |
||||
} |
||||
|
||||
badInitializers++; |
||||
|
||||
String notSatisfied = ""; |
||||
|
||||
for (final String d : task.getDependencies()) { |
||||
if (!loadedTaskNames.contains(d)) { |
||||
|
||||
if (!notSatisfied.isEmpty()) { |
||||
notSatisfied += ", "; |
||||
} |
||||
|
||||
notSatisfied += d; |
||||
} |
||||
} |
||||
|
||||
Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied); |
||||
} |
||||
|
||||
if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied."); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,41 @@ |
||||
package mightypork.gamecore.core.init; |
||||
|
||||
|
||||
import mightypork.gamecore.core.App; |
||||
|
||||
|
||||
/** |
||||
* Initialize backend. The main point of postponing this is to make sure the |
||||
* init is logged properly. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public class InitTaskBackend extends InitTask { |
||||
|
||||
@Override |
||||
public void run() |
||||
{ |
||||
App.instance().getBackend().initialize(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String getName() |
||||
{ |
||||
return "backend"; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String[] getDependencies() |
||||
{ |
||||
return new String[] { "log" }; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getPriority() |
||||
{ |
||||
return PRIO_EARLY; |
||||
} |
||||
} |
@ -1,42 +0,0 @@ |
||||
package mightypork.gamecore.core.init; |
||||
|
||||
|
||||
import mightypork.gamecore.graphics.Renderable; |
||||
|
||||
|
||||
/** |
||||
* Task to init renderable screens (part of the main loop).<br> |
||||
* Resources must already be ready. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public abstract class InitTaskScreens extends InitTask { |
||||
|
||||
@Override |
||||
public void run() |
||||
{ |
||||
app.setMainRenderable(getMainRenderableImpl()); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Create a loader impl |
||||
* |
||||
* @return loader |
||||
*/ |
||||
protected abstract Renderable getMainRenderableImpl(); |
||||
|
||||
|
||||
@Override |
||||
public String getName() |
||||
{ |
||||
return "renderables"; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String[] getDependencies() |
||||
{ |
||||
return new String[] { "resources", "main_loop" }; |
||||
} |
||||
} |
@ -0,0 +1,51 @@ |
||||
package mightypork.gamecore.core.init; |
||||
|
||||
|
||||
import mightypork.gamecore.graphics.Renderable; |
||||
import mightypork.gamecore.resources.Res; |
||||
|
||||
|
||||
/** |
||||
* Task to init main renderable (UI).<br> |
||||
* Resources are already registered in {@link Res}. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public abstract class InitTaskUI extends InitTask { |
||||
|
||||
@Override |
||||
public void run() |
||||
{ |
||||
app.setMainRenderable(createMainRenderable()); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Create a loader impl |
||||
* |
||||
* @return loader |
||||
*/ |
||||
protected abstract Renderable createMainRenderable(); |
||||
|
||||
|
||||
@Override |
||||
public String getName() |
||||
{ |
||||
return "ui"; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String[] getDependencies() |
||||
{ |
||||
// main loop queues layout change events, would lose them otherwise
|
||||
return new String[] { "resources", "main_loop" }; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getPriority() |
||||
{ |
||||
return PRIO_LAST; |
||||
} |
||||
} |
Loading…
Reference in new issue