DarkEden Mod - For Fun / Testing Purposes

Hey!

I've started working on a DarkEden game mod (actually I have been for that last little while...) Just for fun and to further develop my game. The idea is to replace the 'place-holder' assets with real art later once I am ready to work in a team on my project - or otherwise just leave it as a mod... Anyway:

Here is the hospital level I've been working on:

CIty Level:

Hopefully I'll find some time to put up some gameplay footage as well.

Java Checked vs Unchecked Exceptions

Hello!

Today I have decided to write an article not so related to game development (yes, JevaEngine is coming along very nicely in-case you are wondering.) Instead I will be focusing on the difference between checked and unchecked exceptions, what the general consensus is on them and my opinion on them.

First, lets define quickly the differences between the two types of exceptions and what their intentions are, then I will go through my experiences with either one and where I rest my opinions now.


Checked Exceptions vs Unchecked Exceptions

NOTE: Before I begin, I should state that this conversation is from the 'ideal' usage of checked exceptions. Not all API designers take this approach! You will encounter frameworks/APIs that only use unchecked exceptions due to the development project's stance on checked/unchecked exceptions.

An unchecked exception is your conventional exception. It can be thrown from anywhere, and it can be declared in a try-catch clause anywhere. Some typical examples of this are (in the JDK) IndexOutOfBoundsException, IllegalArgumentException etc... These exceptions are designed to be thrown when the programmer is using a particular interface incorrectly. As per this logic, it would seem as though there is never an approriate circumstance to be catching unchecked exceptions. We'll find later on why it would still make sense to declare them in a catch clause.

For example, the following code will throw an unchecked NullPointerException, opposed to a checked FileNotFoundException.

String fileName = null;
try(FileInputStream fis = new FileInputStream(fileName))
{
			
} catch (IOException e) { }
		


Checked Exceptions are used to describe errors that may occur, and their ability to occur is entirely out of the hands of the programmer using the interface throwing them as well as the interface implementation itself. That is to say that even if the interface is used 100% properly, and its implementation is 100% free of bugs, it still may encounter an error performing its task. So for example, you could reconsider the FileNotFoundException shown above. Whenever you open a file, you must deal with the possibility that it does not exist. Whenever you open or read from a file, you must deal with the possibility that an IOException occurred when attempting to gain access to the files data. In essence, whenever you are dealing with an external device you need to appreciate that it could fail.

To reiterate, if an interface's ability to fail is out of the hands of the programmer and in the hands of an external source of information or device - then it should be a checked exception. If it's ability to fail is in the hands of the programmer (passing null as an argument to a method which states in its documentation that null not a valid argument) then it is an unchecked exception.

Where it gets interesting

Sometimes you will encounter situations where a checked-exception being thrown by an interface should be, in your very particular circumstance, interpreted as a unchecked exception. These are *rare* - and you should almost never do what I am about to show you (if you don't think checked exceptions are evil - otherwise you probably already do it all over the place...)

Consider the following code sample:

try {
	URI files = new URI("file:///a/b/c.txt");
} catch (URISyntaxException ex) {
	//This will never happen
}

In this case, we are providing the constructor of URI a valid syntactically correct URI, but we are still forced to catch the checked exception. In our particular circumstance, since the URI String is being defined by the programmer [and is not being provided by a source out of our control such as a text document or a user text field] it is actually an unchecked exception. As per our definitions above.

In that code sample, what we are doing is converting a checked exception to nothing. This is _very_ _very_ bad. This means that if someone comes along and changes that syntactically correct URI String to something syntactically incorrect, no one will ever know. They will get a NullPointerException when trying to reference the URI. Instead it is better to rethrow the exception as an Unchecked Exception.

try {
	URI files = new URI("file:///a/b/c.txt");
} catch (URISyntaxException ex) {
	throw new RuntimeException(ex);
}

Again, converting from an checked exception to an unchecked exception should be done with very careful consideration.

Now that I've made my point, URI actually provides a static convenience method for doing something very similar to this:

URI files = URI.create("file:///a/b/c.txt");
		


Going the other way

Sometimes you'll find some interfaces will assume the opposite to what is being assumed by URI's constructor. Namely, they will assume the arguments are being provided by the programmer and not the user. A good example of this is the valueOf static method of the class Integer. This method throws an unchecked NumberFormatException if the provided argument is not a valid integer.

If the argument being provided to valueOf is provided by an external source [text document, database, user interface] and cannot be guaranteed to be a valid integer then it should be caught and wrapped in a (ie FormValidationException) checked exception and be rethrown.


Leaky Abstraction

A popular argument _against_ checked exceptions is that they force/encourage a leaky abstraction. The reason people argue this is because they do not understand when you should stop throwing up a checked exception, and instead handle it or wrap it. They may also fail to understand one of the core abilities of an Exception [wrapping.] Lets start by describing the most common tools used for abstraction.

What is the core function of an interface? [not a Java interface - but an *interface.* Ie as per our definition, a concrete class also has an interface component, such as public members.]

Interfaces provide a means to communicate with an implementation (the specific mechanics of a solution.) They are _not meant to expose_ the mechanics or any details regarding them. If they do, then they leak details through the abstraction they mean to provide (Ie, the interface provides a _leaky abstraction._)

It is important to appreciate that checked exceptions are apart of your interface. In an interface they are meant to communicate the possible failures without exposing details regarding the mechanics of a solution. If you declare them incorrectly, then they too can be the cause of a leaky abstraction. Since error handling can be difficult, and abstracting mechanics can be difficult, you'll find a lot of programmers blame exceptions for their leaky abstraction. The trick to integrating checked exceptions into your application without leaking the abstraction is understanding when to handle exceptions caused by your implementation/mechanics, and when to wrap them & expose them to the user of your interface.



Exposing errors caused by your implementation through your interface

If you are have an interface that provides a particular abstract function, and an implementation of this interface encounters a error while performing that function, it should throw a checked exception that makes sense to the interface being used. For example:

You are contracted to work on an existing application that is a word processor. It currently has the feature to read documents from the local storage devices. It was well designed, so all of it's resources are accessed through a FileSystem interface. The FileSystem interface is designed like so:

public interface FileSystem
{
    InputStream open(URI name) throws FileInaccessibleException;
    
    public static final class FileInaccessibleException extends Exception
    {
        public FileInaccessibleException(URI fileName, Exception cause)
        {
            super("Unable to locate the file: " + fileName, cause);
        }
    }
}

The current implementation of FileSystem looks something like this:

public class LocalFileSystem implements FileSystem
{
    @Override
    public InputStream open(URI name) throws FileInaccessibleException
    {
        try
        {
            return new FileInputStream(new File(name));
        } catch (FileNotFoundException  e)
        {
            throw new FileInaccessibleException(name, e);
        }
    }
}

What we need to do is create our own implementation of this FileSystem interface that connects through a network and performs the same tasks. Lets assume that our implementation encounters an error opening a file due to it not being connected to a specific server from which to fetch these documents from. How would we communicate that error through the interface?

We could wrap a FtpFileSystemNotConnectedException through our interface by wrapping it with the FileInaccessibleException.

What if, in the middle of reading from a FtpFileInputStream, we are disconnected from the server? We can throw a FtpFileSystemNotConnectedException wrapping in an IOException.

Now presenting these errors to the user is another story. It is best to display the exception message, and then log the stack trace (for the developer to use if it was a logic error that lead to the throwing of the exception. [Your stack trace and your exception names is usually enough to resolve a logic error if the programmer needs to.]

Now you've only changed one interface, and you've added an incredibly complex feature. The application is inherently designed to deal with all the complex errors that can occur over a network communication etc.

When to stop propagating errors, and handle them.

Eventually you need to handle the checked exception. They are checked because they need to be handled. The way you can handle them can range from simply notifying the user that the service is not available due to X reason or provide a limited access to the component that depends on that service.

It is very important that when you are providing a limited service, or resulting to default (null) behavior, you log it & and the stack trace. Otherwise errors can be difficult to discover and locate. Here is a simple example of when you can provide null/default behavior.

The EntityFactory in JevaEngine throws a EntityConstructionException when it cannot sufficiently construct an entity for the game world. However, the factory tries its very best to construct the entity. If the only error occurs when attempting to evaluate the entity's associated behavior script, it is provided a default behavior.

Likewise, the WorldFactory will ignore entitys that cannot be constructed - rather than failing to construct the entire world. Of course it is important to log the exception that caused the entity to fail in construction, and the fact that the entity was excluded from the world. Otherwise it can become difficult to identify the reason behind its exclusion.

You could simplify the solution by simply throwing a WorldConstructionException as well, depending on how critical it the failed component is to the application.

My Experience with Checked/Unchecked Exceptions

Let me start by saying that I used to very much dislike checked exceptions. I would constantly let them propagate out and crash the entire system with a stack-trace to examine. That may work for very simple applications or very deterministic solutions. However, I found that as my game engine became more complex this behavior was simply unacceptable. For a lot of reasons, here are a a few I discovered over the 3+ years I've been expanding on JevaEngine:

- An interface's implementation should evolve, but using checked exceptions lets you be 100% sure the user of that interface is not receiving any unexpected exceptions it is responsible for handling. Ie, that there is a consistent contract between the user of an implementation and the implementation in terms of error handling. Remember that exceptions are apart of your interface's contract. Using checked exceptions appropriately assures that the contract is met.

- If you're building a framework, you should opt for checked exceptions. Why? Because using applications that don't cohere with your exception handling model (use of checked or not) is a huge pain in the ass - but if you don't use checked exceptions and a user of your framework does it has the potential of breaking their exception use model and creating an ambiguity between programmer error and natural failure due to some external source.

The victim's hotel room...

May be worth investigating the victim's hotel room.

Design your dialogue in JevaEngine using freemind.

I have written a custom XSLT (along with several changes to the dialogue system in the RPG base) that allows you to design your character dialogue in an mind-mapping utility called FreeMind. Here is quick demonstration (I'm short on time, and a picture is worth a thousand words...)

Note that the dialogue you are about to see demonstrated is meant to project a real murder case, and is thus graphic in nature.

A screenshot of Demo3

Demo 3 is getting really close to being completed. There are a few issues/bugs to resolve.

Demo3 uses PARPG assets to construct an "investigation" quest. Unlike Demos 0-2 which are more action rpg orientated using the FLARE RPG assets.

Imported PARPG assets for demo, improved rendering system a bit

As you may know, ISceneBuffer objects are responsible for handling rendering in JevaEngine. Today I've found some time to add a new ISceneBuffer object to JevaEngine's core. There are now two ISceneBuffers built into JevaEngine (it is very easy to use your own.)

- PaintersIsometricSceneBuffer which uses the painter's algorithm for rendering isometric scenes. This method is very quick but frequently fails if your scenes are not composed of strictly fixed sized blocks. It sorts based on the location of the entity - but ignores the containing bounds of that entity. Thus this makes it impossible to depth sort walls or gates that span across multiple tiles properly without breaking them into individually size tiles.

- TopologicalIsometricSceneBuffer is much more proper in terms of depth sorting scene components. It works with variable sized components and allows entities to be sorted properly on the Z axis. However, this sorting algorithm is much more expensive and has a complexity of O(n^2) That said, I have managed to get very large scene to be sorted in a manner of 1-2ms - which is perfectly acceptable.

Here is a test for the TopologicalIsometricSceneBuffer. You'll see the scene components and their respective AABBs.

There are three components visible in this image, the gas tank, the wind mill and the ground (which is a single component.)

In previous screen-shots, the ground was composed of many different components - each per tile. With this new depth sorting algorithm, the ground can be a single sprite (generated via tiled or rendered out of blender etc...) You can imagine that generating the meta-data on a per-tile basis would be a lot of work (especially if you have a lot of tiles) so it is much more optimal to import them into tiled, construct a tile-able surface texture 20x20 tiles in dimensions use that instead.

Demo 2 - Quest Demo

Demo 2 demonstrates how you could use JevaEngine to implement various quest using a combination of quest-controlled-NPCs, and area triggers to initiate character dialogue. It also demonstrates how to use the dialogue system implemented by the RPG Base.

Below is a layout of our world in the world editor:

In the bottom left corner, you'll see a named entity placement "player." If we look at its import declaration (which can be edited via the GUI in the world editor - but I will list the JSON for convenience.)

{
    "location" : {
      "z" : 1.0099999904632568,
      "y" : 44.0,
      "x" : 19.0
    },
    "direction" : 8,
    "name" : "player",
    "config" : "artifact/entity/zombie/zombie.jec",
    "auxConfig" : {
      "behavior" : "artifact/behavior/character/puppet.js"
    },
    "type" : "character"
  }

JevaEngine Update - July 24th, 2014

JevaEngine has been dormant for the last couple of months. The repository has also seemed pretty inactive.

Here is a sample of the current demo modules of JevaEngine and the world editor. They look the same (and admittedly could use some polishing) but they come after some major refactors on the engine. More details below the video.

I have been refactoring JevaEngine over the last month or so. These refactors come with some very important architectural changes that pushes JevaEngine towards a more flexible and powerful engine. I will be detailing the changes within the next few weeks once the refactored engine has been pushed to the repository. Below I will list some of the key changes to JevaEngine.

- All use of service locator pattern has been refactored out of the engine. The service locator pattern was used in JevaEngine to acquire an interface to the concrete implementation of Game, and to acquire an interface to the globally accessible asset factory (opening raw InputStreams to the game's filesystem.) This provided a convenient way for one to construct entities, open configuration files from anywhere inside of JevaEngine. However it also carried some issues, mainly allowing for global access to these resources (forcing factories to be thread safe) and hiding code smells that would usually become obvious.

- JevaEngine has now switched to an entirely Dependency Injection based model of passing around dependencies, using Guice to bootstrap the engine with the appropriate dependencies. This has allowed for more flexibility inside of JevaEngine. Including the ability to bootstrap JevaEngine with custom world, sprite, script, entity, physics and asset factories - allowing one to easily integrate custom file formats and scripting/physics engine seamlessly into JevaEngine.

- World projection has been entirely decoupled from the engine. Meaning one can implement various render perspectives into JevaEngine seamlessly. JevaEngine is no longer focused specifically towards Isometric Games, it can also focus towards platformers and top-down games. While no such implementations have been tested, it is theoretically possible to easily integrate these perspectives into JevaEngine.

- The world builder has been entirely reconstructed. The previous implementation was falling apart - mainly due to complications introduced by using the Swing UI subsystem so heavily. JevaEngine's new world builder is entirely based around the JevaEngine UI subsystem. This allows for a much more functional and cleaner implementation.

- JevaEngine now delegates Window construction to an injected Window Factory. The default Window Factory parses an external configuration file that defines the layout of the window and its style. The layout defines controls, their location and their respective properties (such as text, or width/height etc...) The constructed window is than injected with a behavior. This makes the task such as localization much more achievable. It also reduces the noise in UI relevant code by allowing the programmer to focus specifically on the behavior of the window rather than its layout.

- JevaEngine is now fully integrated with a physics engine (the default implementation is pure java Box2D, but it is very easy to bootstrap JevaEngine with a different physics engine.) Following this integration, JevaEngine now comes with some steering behaviors.

- These refactors have had a significant impact on the engine, and will also require some significant refactors to be applied to the client\server implementations. For the next few weeks, I will be focusing specifically on the rpgbase and the single player demos. The multiplayer implementation is being placed on the back burner for a few more weeks.

- JevaEngine now makes the appropriate use of checked and unchecked exceptions. This has made JevaEngine respond much more appropriately to errors. Developing with JevaEngine has become significantly easier. JevaEngine uses SLF4J to report errors (such as those that exist in entity scripts.) In the previous revisions of JevaEngine, when an error was encountered (such as one in an Entity's behavior script) an unchecked exception was thrown and eventually crashed the entire engine with an appropriate stack-trace. This is unacceptable and makes the job of a casual user of JevaEngine significantly more difficult. In the latest revision (in a scenario such as this) JevaEngine now logs the error in the script to the appropriate logger, and reverts to default behavior (such as that for an entity absent of a script.)

I now work full time (unfortunately) and have to work very hard to progress anywhere with JevaEngine. That said, I am very satisfied with the results of my work over the past few weeks.

Subscribe to JevaEngine RSS