Pretty epic rap battle with Michael Jackson against Elvis Presley.
I’ve been busy with too much work on everything else but my personal game engine project for the past few months. Now I’m back and expect more topics coming soon!
I love siomai
An idea came into my mind today. Why not just make an implicit(automatic) resource management system instead of having some kind of an external resource management system.
Ever since the way I did it was having an external resource manager that I would then use to create the resource I want. Take a look at this sample code below.
As you can see, we create a texture through a texture resource manager called TextureManager and once we’re done with the texture we go through the TextureManager again to remove that created resource. It’s not really much of a big deal but what if we could just hide the resource management code stuff yet still having all the benefits and convenience of managing your resources? That’s where I thought and said, “Why not just place the manager inside the resource class instead and handle the resource management creation and deletion through the constructor and destructor of the resource respectively?”. hmmm….
First of all, I wasn’t really sure if I wanted to write this post or not. The data creation framework I made is mostly hacked without proper/formal scripting architectural design. But if this article could help anyone out there in some ways in their programming tasks, even just a little bit, then this blog wouldn’t be a waste. With this in mind, this article will be very brief with very little explanation for its implementation.
This data creation framework I will present enables a data driven architectural design to deliver game data/assets to your game. Since this is a data creation framework, its main purpose is only to bring data; nothing more, nothing less. That means that although the script looks like a full blown scripting language, it is not. This is not like LUA or any other scripting languages that you can define procedural-scripting or gameplay code. This framework simply defines a set of data with an assigned values for the framework to easily read in the data.
If you take a look at the class definition, you’ll see lots of containers supporting each data type that the framework supports. Let’s say for example you have a sample script code that looks something like in Code listing 1.
Code Listing 1: An example of declaring a Vector3 data with a defined value of (1.0, 3.0, 2.578)
vec3, as Vector3 as its data type, will be stored in the Vector3Array container.
So this framework is very simple and straightforward. It doesn’t do anything else other than declare data and this will do fine for the system I’m currently working towards on. The main methods that does the main string parsing and reading are in the GetLine, LoadFromFile, ReadSection, and ReadValue methods.
Here’s the implementation for the framework. And a demo script on what the framework can do(Code Listing 2).
Code Listing 2: Sample data creation script. Download it here
3. Sample PulseScript script code, http://codaset.com/codesushi/pulse-tec/source/master/blob/Source/Engine/Demo/SampleScript.ps
A preview on a Data Creation Framework/Scripting System I’ve been working on the side. Not bad considering I only work on this on Sundays IMO. :p An article discussion will follow soon!
This system I will share today is roughly adopted from Guillaume Blanc’s Registrer(Registry) system. This Registry system is designed to keep track all registered classes and objects in an easy, global, and manageable manner. This system can easily send events such as initialization, shutdown, unit testing, or anything else that you can imagine and each registered systems/objects can react to a specified event. If this sounds very familiar to you, chances are you’ve already heard this in your Design Patterns class. Yes, this is the dispatcher-listener design pattern. An object or a system (aka listener) registers to the Registry(aka dispatcher) and when the Registry signals a message, it sends a message to each and every registered listeners.
There are two types the Registry accepts. One is a class (static classes) and the second is an instantiated object. An interface class will play a big role on these two types in order for them to be accepted by the Registry. Code listing 1 shows the interface class.
As you can see in Code Listing 1, the abstract base class needs the derived classes to define DoRegistryOperation(). DoRegistryOperation() method is the entry point for all the events sent by the Registry.
You may also have noticed that the constructor accepts two parameters named ERegistryPrimaryPriority and ERegistrySecondaryPriority. These enums defines the priority of the Registry Object from lowest to highest priority. These priorities are very important as they control the order of the registered objects to call. What you can do is probably set very important systems or classes having the highest priority without dependencies. Less important systems or systems that requires dependencies would obviously need to be set in a lower priority than the dependency it requires.
For registering an instantiated object, one would simply inherit the class with IRegistryObject then calling IRegistryObject’s constructor to automatically register it in the Registry.
For classes, it takes a little bit more of explaining to do. The problem with this is that, there are no actual objects to register in the Registry. So what we would do is create a class that encapsulates or connect the class in question in some way. Thus, we devised a macro to do exactly like that. Take a look at Code Listing 2.
Quite scary, no? Well, don’t be. These are just predefined preprocessors that basically replaces everything in code that finds the same name as the defined name. What these macro does is that it declares a new class, derived from IRegistryObject , and defines the DoRegistryOperation() method. The DoRegistryOperation() is actually empty and you’ll be the one to write code into it let be initialization, shutdown, or test code using the PSX_REGISTRY_ON…() macro declarations. Code Listing 3 shows a sample on how the macros are used.
Code Listing 3 shows registering a String class to the Registry and defining a Unit Test code for code testing. Please study Code Listing 2 and Code Listing 3 to fully grasp and understand what it is trying to do.
And lastly, I present to you the Registry class shown in Code Listing 4.
There’s nothing much really to discuss here. Registry objects simply register themselves by calling Registry::RegisterObject and they will be registered in the Registry. UnregisterObject removes them from the Registry.
Last Thoughts and Further Improvements
You may have noticed that the Registry class uses a SortedList (SortedLList). It is basically a sorted linked-list. That being said, it won’t be a good idea to register lots and lots of instantiated objects. This system is designed to handle application/game systems at best. Such systems would be a memory manager, Sound System, Input System, Grpahics System, etc… If you want to make it handle a great amount of instantiated objects then you may have to change a more capable container such as a vector, hash-table or a map for example.
Full implementation of the Registry system/class can be found here.
- Guillaume Blanc, Article source code, Registrer, Cross platform rendering thread, ShaderX7, 2009
- Pulse::String class, http://codaset.com/codesushi/pulse-tec/source/master/blob/Source/Engine/Include/String.h, http://codaset.com/codesushi/pulse-tec/source/master/blob/Source/Engine/Source/String.cpp
- Pulse::Registry class, http://codaset.com/codesushi/pulse-tec/source/master/blob/Source/Engine/Include/Registry.h, http://codaset.com/codesushi/pulse-tec/source/master/blob/Source/Engine/Source/Registry.cpp
Don’t forget a good dose of Mr. Louis Armstrong song!
This is more of an obvious avoidable problem than a necessary work/solution. But I needed this on how I was working on my own little “engine”. A couple of months ago, I was working on a Virtual File System. I later discovered that std::fstream has a 4GB limit. So I resorted to using the Stream I/O instead which can handle greater than the 4GB limit. The problem with this is that it isn’t structured in an Object-Oriented way. Yes we want everything to be Object-Oriented. That being said, I ended up wrapping the Stream I/O into a neat simple to use class.
Now I’m working on a new system which requires a generic way to input and output streams. What I mean is that I want my system to not care where the system is reading in or writing out data. Let it be reading in from an input peripheral, reading from a file, writing to a console or writing to a file. So I designed a very simple abstract I/O stream class. It is broken down into two classes, IStream and OStream, which is derived from a base Stream class.
These abstract classes are definitely far from complete. But it seems to serve well for my purpose. So I can at least say that this is a good start.
If you take a look at the implementations provided, you’ll notice that only the FileIO class is currently derived from it right now. I still have to add a bunch of derived classes to encapsulate cin, cout, and a bunch of others that I can think of which is currently in my TODO list that I have to do sometime in the future(no pun intended).
3. Steam.h – Stream, OStream, IStream – http://codaset.com/codesushi/pulse-tec/source/master/blob/Source/Engine/Include/Stream.h
Dashing Song to Listen to: