Skip to content

Commit

Permalink
Split init/loop/shutdown phases into own methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ultraq committed Dec 28, 2024
1 parent 33771b6 commit 9442e8b
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ package nz.net.ultraq.redhorizon.engine
import nz.net.ultraq.redhorizon.engine.scenegraph.Scene
import nz.net.ultraq.redhorizon.events.EventTarget

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import groovy.transform.PackageScope

/**
Expand All @@ -33,6 +36,8 @@ import groovy.transform.PackageScope
*/
abstract class EngineSystem implements Runnable, EventTarget {

private static final Logger logger = LoggerFactory.getLogger(EngineSystem)

private Engine engine
protected Scene scene

Expand All @@ -49,6 +54,14 @@ abstract class EngineSystem implements Runnable, EventTarget {
return engine
}

/**
* Return the name of the system, for logging purposes.
*/
protected String getSystemName() {

return this.class.simpleName
}

/**
* Execute an action and optionally wait such that, if repeated, it would run
* no faster than the given frequency.
Expand All @@ -68,6 +81,43 @@ abstract class EngineSystem implements Runnable, EventTarget {
}
}

/**
* Controlled initialization, execution loop, and shutdown or an engine
* system.
*/
@Override
final void run() {

logger.debug('{}: starting', systemName)
runInit()
trigger(new EngineSystemReadyEvent())

logger.debug('{}: in loop', systemName)
runLoop()

logger.debug('{}: shutting down', systemName)
trigger(new EngineSystemStoppedEvent())
runShutdown()
logger.debug('{}: stopped', systemName)
}

/**
* Initialize any resources for the running of the system here.
*/
protected void runInit() {
}

/**
* Enter the loop for the system to continually work on the scene.
*/
protected abstract void runLoop()

/**
* Cleanup/free any resources created by the system here.
*/
protected void runShutdown() {
}

/**
* Set the engine this system is a part of.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package nz.net.ultraq.redhorizon.engine.audio

import nz.net.ultraq.redhorizon.engine.EngineStats
import nz.net.ultraq.redhorizon.engine.EngineSystem
import nz.net.ultraq.redhorizon.engine.EngineSystemReadyEvent
import nz.net.ultraq.redhorizon.engine.EngineSystemStoppedEvent
import nz.net.ultraq.redhorizon.engine.audio.openal.OpenALContext
import nz.net.ultraq.redhorizon.engine.audio.openal.OpenALRenderer
import nz.net.ultraq.redhorizon.engine.scenegraph.AudioElement
Expand All @@ -34,7 +32,7 @@ import java.util.concurrent.LinkedBlockingQueue

/**
* Audio system, manages the connection to the audio hardware and playback of
* audio objects.
* audio objects in the scene.
*
* @author Emanuel Rabina
*/
Expand All @@ -47,6 +45,9 @@ class AudioSystem extends EngineSystem implements AudioRequests {
private final BlockingQueue<Tuple2<AudioResource, CompletableFuture<Void>>> deletionRequests = new LinkedBlockingQueue<>()
private final List<Node> queryResults = []

private OpenALContext context
private OpenALRenderer renderer

/**
* Constructor, build a new engine for rendering audio.
*/
Expand Down Expand Up @@ -106,59 +107,54 @@ class AudioSystem extends EngineSystem implements AudioRequests {
})
}

/**
* Starts the audio engine loop: builds a connection to the OpenAL device,
* renders audio items found within the current scene, cleaning it all up when
* made to shut down.
*/
@Override
void run() {

logger.debug('Starting audio system')

// Initialization
new OpenALContext().withCloseable { context ->
context.withCurrent { ->
new OpenALRenderer(config).withCloseable { renderer ->
logger.debug(renderer.toString())
EngineStats.instance.attachAudioRenderer(renderer)

trigger(new EngineSystemReadyEvent())

// Rendering loop
logger.debug('Audio system in render loop...')
while (!Thread.interrupted()) {
try {
rateLimit(100) { ->

processRequests(renderer)

// Run the audio elements
// TODO: Split this out like the graphics system where we wait to
// be told to process audio objects instead of looping
// through the scene ourselves
if (scene?.listener) {
scene.listener.render(renderer)
queryResults.clear()
scene.query(scene.listener.range, queryResults).each { node ->
if (node instanceof AudioElement) {
node.render(renderer)
}
}
protected void runInit() {

context = new OpenALContext()
context.withCurrent { ->
renderer = new OpenALRenderer(config)
logger.debug(renderer.toString())
EngineStats.instance.attachAudioRenderer(renderer)
}
}

@Override
protected void runLoop() {

context.withCurrent { ->
while (!Thread.interrupted()) {
try {
rateLimit(100) { ->
processRequests(renderer)

// Run the audio elements
// TODO: Split this out like the graphics system where we wait to
// be told to process audio objects instead of looping
// through the scene ourselves
if (scene?.listener) {
scene.listener.render(renderer)
queryResults.clear()
scene.query(scene.listener.range, queryResults).each { node ->
if (node instanceof AudioElement) {
node.render(renderer)
}
}
}
catch (InterruptedException ignored) {
break
}
}
}

// Shutdown
logger.debug('Shutting down audio system')
catch (InterruptedException ignored) {
break
}
}
}
trigger(new EngineSystemStoppedEvent())
logger.debug('Audio system stopped')
}

@Override
protected void runShutdown() {

context.withCurrent { ->
renderer.close()
}
context.close()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package nz.net.ultraq.redhorizon.engine.game

import nz.net.ultraq.redhorizon.engine.EngineStats
import nz.net.ultraq.redhorizon.engine.EngineSystem
import nz.net.ultraq.redhorizon.engine.EngineSystemReadyEvent
import nz.net.ultraq.redhorizon.engine.EngineSystemStoppedEvent
import nz.net.ultraq.redhorizon.engine.graphics.GraphicsSystem

import org.slf4j.Logger
Expand All @@ -44,17 +42,10 @@ class GameLogicSystem extends EngineSystem {
}

@Override
void run() {
void runLoop() {

logger.debug('Starting game logic system')

// Initialization
// TODO: These phases could probably live in the parent EngineSystem class
var graphicsSystem = (GraphicsSystem)engine.systems.find { system -> system instanceof GraphicsSystem }
trigger(new EngineSystemReadyEvent())

// Game loop
logger.debug('Game logic system in loop...')
while (!Thread.interrupted()) {
try {
var currentTimeMs = System.currentTimeMillis()
Expand All @@ -71,11 +62,5 @@ class GameLogicSystem extends EngineSystem {
break
}
}

// Shutdown
logger.debug('Shutting down game logic system')

trigger(new EngineSystemStoppedEvent())
logger.debug('Game logic system stopped')
}
}
Loading

0 comments on commit 9442e8b

Please sign in to comment.