diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/Application.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/Application.groovy index 0ae1fd9f..3d47ef6c 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/Application.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/Application.groovy @@ -159,7 +159,13 @@ class Application implements EventTarget { engine.start() engine.systems*.scene = scene scene.inputEventStream = inputEventStream - applicationStart?.apply(this, scene) + + try { + applicationStart?.apply(this, scene) + } + catch (Exception ex) { + logger.error('An error occurred during application startup', ex) + } engine.waitUntilStopped() diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/Node.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/Node.groovy index a1ad6e8b..03fcefd1 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/Node.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/Node.groovy @@ -28,6 +28,7 @@ import groovy.transform.stc.ClosureParams import groovy.transform.stc.SimpleType import java.util.concurrent.CompletableFuture import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.TimeUnit /** * An element of a scene, nodes are used to build and organize scene trees. @@ -68,7 +69,9 @@ class Node implements SceneEvents, Scriptable { // Allow it to process var scene = getScene() if (scene) { - addNodeAndChildren(scene, child).join() + addNodeAndChildren(scene, child) + .orTimeout(5, TimeUnit.SECONDS) + .join() } var childPosition = child.position @@ -96,7 +99,7 @@ class Node implements SceneEvents, Scriptable { .thenRunAsync { -> scene.trigger(new NodeAddedEvent(node)) } - .thenCompose { _ -> + .thenComposeAsync { _ -> var futures = node.children.collect { childNode -> addNodeAndChildren(scene, childNode) } // Originally used the Groovy spread operator `*` but this would throw @@ -254,7 +257,9 @@ class Node implements SceneEvents, Scriptable { T removeChild(Node node) { if (children.remove(node)) { - removeNodeAndChildren(scene, node).join() + removeNodeAndChildren(scene, node) + .orTimeout(5, TimeUnit.SECONDS) + .join() node.parent = null // TODO: Recalculate bounds }