quarta-feira, 28 de setembro de 2016

Inversion of Control? Ok! Gonna try!

These past weeks a friend of mine has been sending me lots of links to videos, articles and posts about Dependency Injection and, naturally, inversion of control. It turns out that a week ago, I finished the very, very very minimal code needed to start Suna in c++:

  • A LocalHost class
  • A Channels class
  • An unreliable communication channel class
  • A wanna-be 3way handshake for starting connections on “application level”, by using UDP.


There’s enough stuff in there to start getting lost as I forget the code, but since it IS still small enough, I’ve decided to try to use a few of the concepts from inversion of control. Took a while to refactor nearly everything:
-       
  • ISocket, IEndpoint, IHost, INetworkPacket, Ietcetc. So many interfaces…
  • Constructor arguments, constructor arguments, constructor arguments….
  • Now it’s really easier to change stuff around.

      Overall, I’m liking the results even though I’m hating all the boilerplate code. It became clear that I need some kind of injector to spawn instances of my concepts, so later I’ll write some kind of abstract factory. Suna is meant to be a really small project, so probably a “poor man dependency injection” will be enough.

segunda-feira, 19 de setembro de 2016

“Posting only relevant stuff on the blog? You mad?!”

The title is the gist of it. I’ve always thought that I should only post stuff that seems relevant – to me, at least – around here. However, reading random things about devblogs, one comment made me notice one thing: it’s not about relevant contents at all. Actually, it is more about showing that we, the developers and teams, care about our projects, and are still working on them. Of course, relevant content is still better, but it’s not a rule.


That being said, it means I can post about anything that I do over the little time I have available to advance with the project. And that’s what I’ll start doing. I hope. Anyway, the c++ game engine now has a name: Nest. The game itself will be called Valsendor, probably. The network api has received the name Suna and has a mascot which I can’t draw. Naming things is hard, very hard.

quarta-feira, 1 de junho de 2016

Games in C++ can't be that hard, right? - YAML.

These last weeks I've been making some progress with the components and rendering system of the game engine. It is all so crude, but it's working and that makes me happy. I've managed to get a moveable first-person camera with a cube in the scene, reduce the amount of code needed to add a component to an entity and even got both orthographic and perspective camera projections!

Now, indeed, reinventing the wheel is totally unproductive. With the amount of code I've written here I could have doubled the amount of features in my last game prototype made in Unity. In this c++ project, I'm still at cube point.

Anyway, a friend has suggested me to try to make my rendering system in Vulkan – an idea that I grew fond of. But first, there are other things I want to do, and one of them is to avoid “rebuilds” every stupid test change such as screen resolution or, guess what, switching between OpenGL and Vulkan. As a starting point, it seems like a good idea to reduce “rebuilds” by tackling two areas:

- Components, which can be coded by scripting languages such as FalconPL or Lua
- Assets data.

Components scripting and FalconPL / Lua is too far away from me right now; I simply don't have any clue on how to set up them with my engine architecture and bind everything, and I can't tell if FalconPL is still alive as well. That leaves me figuring out only how to load assets data. It could be done with a scripting language, too, but the truth is that any kind of file reading technique will do.

In the past, in a restaurant simulator prototype, I've used JSON to store data for things such as food recipes or employees names. In that, there are many advantages like being able to store rules anywhere that allows storage of text, and they are readable enough to be written with any text editor. It'd be nice if these features were available for the engine assets information. If I write down what data I need, for example, to set up a texture and a material, I'd get something like the following:

Texture:
    - Name : HappyFace
    - File : HappyFace.png
    - WrapMode : Clamp

Material:
    - Name : UnlitHappyFace
    - Texture : HappyFace
    - Shader : TextureUnlit

It is really easy to write and to read, and it is also YAML. Sure, loading times will be way longer than if I were reading binary data, but then I can simply write a “stupid compiler” to make the binary files from the texts – if I ever come to need this performance. To read the files, I've used a small but elegant library called Yaml-Cpp. The rendering configuration file seemed a nice “hello world” practice. Here's how it turned out:

Video:
    - ScreenWidth : 800
    - ScreenHeight : 600
    - Renderer : OpenGL

The Yaml-Cpp is really easy to use. The code is clear and straight-forward, even with some (not all) error precautions. With some practice, the code should get even simpler.


void GameSettings::Load(std::string fileName)
{
    YAML::Node mainNode;

    try
    {
        mainNode = YAML::LoadFile(fileName);
    }
    catch (std::ifstream::failure e)
    {
        throw Engine::FailedToLoadException(std::string("Failed to load game configuration: file not successfully loaded."));
    }

    if (mainNode["Video"])
    {
        YAML::Node videoNode = mainNode["Video"];
        for (const auto& node : videoNode)
        {
            if (!node.first.IsScalar() || !node.second.IsScalar()) continue;

            if (node.first.as<std::string>() == "ScreenWidth")
            {
                m_ScreenWidth = node.second.as<int>();
            }

            if (node.first.as<std::string>() == "ScreenHeight")
            {
                m_ScreenHeight = node.second.as<int>();
            }

            if (node.first.as<std::string>() == "Renderer")
            {
                std::string renderer = node.second.as<std::string>();

                if (renderer == "OpenGL")
                {
                    m_GameRenderer = GameRenderer::OpenGL;
                }
                else if (renderer == "Vulkan")
                {
                    m_GameRenderer = GameRenderer::Vulkan;
                }
            }
        }
    }
}

Now I'll try to think in a way to store the assets meta data in disk. Again, I'll probably end up with something like in Unity 3d.


The code has been highlighted by hilite.me.

domingo, 8 de maio de 2016

Games in C++ can't be that hard, right? - Code refactoring already.

It's been some time since last post. I've been tying pieces of code together as I programmed a way of rendering 3d meshes with Open GL. One awful point of the “learning-as-you-go” way of thinking is that, even if each small part is simpler to learn and understand, binding everything together can become a real problem as the communication between classes wasn't properly analyzed and decided upon.

So, you get pieces of code like this:

auto entity = entityPtr.lock();
entity->AddComponent(std::make_shared<Engine::ComponentReferenceStoringFactory<Engine::Transform>>(compFactories->GetFactory<Engine::Transform>()->Instantiate(), Engine::Global->GetComponentTypeMap()->GetTypeId<Engine::Transform>()));
entity->AddComponent(std::make_shared<Engine::ComponentReferenceStoringFactory<Engine::MeshFilter>>(compFactories->GetFactory<Engine::MeshFilter>()->Instantiate(), Engine::Global->GetComponentTypeMap()->GetTypeId<Engine::MeshFilter>()));
entity->AddComponent(std::make_shared<Engine::ComponentReferenceStoringFactory<Engine::MeshRenderer>>(compFactories->GetFactory<Engine::MeshRenderer>()->Instantiate(), Engine::Global->GetComponentTypeMap()->GetTypeId<Engine::MeshRenderer>()));
entity->AddComponent(std::make_shared<Engine::ComponentReferenceStoringFactory<Engine::SimpleControlBehavior>>(compFactories->GetFactory<Engine::SimpleControlBehavior>()->Instantiate(), Engine::Global->GetComponentTypeMap()->GetTypeId<Engine::SimpleControlBehavior>()));

A lot of time has been used to tie things together, as the snippet above can show. And another good deal of time will be needed to refactor and create utility classes and functions so that the system itself does not become painful.


Lesson learned: plan (more) before you code. C++ can become quite verbose.

terça-feira, 22 de março de 2016

Games in C++ can't be that hard, right? - Handles: hey freak me out, I'm coding!

About fifteen days ago I've posted about smart pointers and ownership. After laying out the rules for a piece of the system I wanted to code – namely, a way to iterate over instances of a type, following some restrictions and demands – I ended up concluding that maybe I should try to use handles. With the little time I have to code side projects, this ended up being a heavier task than expected. Because of c++ stuff I didn't know, didn't remember, didn't understand, or any permutation of these, I had to throw way many attempts.

Soooooo… the truth is, things got too complex and I decided to fall back into KISS (Keep it Simple, Stupid). Planning a bigger scope set of rules and demands would take too much of the little time available, so I've used a set of rules for the containers themselves, with handles.

[r1] – Containers are the unique owners of the data stored there.
[r2] – Contained data must be created within the container itself.
[r3] – Handles to contained data are created only (and only when) with the storing of data.
[r4] – Handles must be encapsulated by smart pointers. They must know how to resolve their destruction, and of the data they point to.
[r5] – Iterators that "directly" point to stored data must be available. They are unsafe and should be used with caution.
[r6] – Data can be destroyed even when their handles are still alive. This will make the handles point to a specific "No Data" element.
[r7] – Containers must assume "non pointers" template data types.
[r8] – Containers must be inheritable from an abstract container.

I know some rules can be rather controversial, but I'll leave it as is for now. Actually, they'll force some restrictions on the stored data as well. The biggest problem probably comes from rule 8; there are reasons that I want a uniform representation of any possible container for the same data type, such as a list of containers to be used by factories.

A good name for the container might be StoringFactory. After researching for a while, it seems to be rather unusual to mix up a container together with a factory, as the separation in "container only" and "factory only" classes is desirable. However, for my needs, it seems to make more sense to simply merge them together, with a name to clearly show this mix of responsibilities. Am I deciding wrong? Don't know, but I'm really afraid of over-engineering this, right now...


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
template <class DataType>
class StoringFactory
{
public:
    virtual ~StoringFactory() {}

    // Deletes the data pointed by a handle. The handle won't be discarded,
    // so any holding handle to the same data will still be "valid", and
    // return noDataPointer.
    virtual void DeleteData(StoringFactoryHandle<DataType>& handle) = 0;

    // Deletes the data pointed by a handle, and the handle itself. Using the
    // same holding handle after deleting it will result in undefined behavior.
    virtual void DeleteHandle(StoringFactoryHandle<DataType>& handle) = 0;
    virtual DataType* Get(StoringFactoryHandle<DataType>& handle) const = 0;

    virtual DataType* SetNoDataPointer(std::unique_ptr<DataType> noDataPointer) = 0;

    // Returns the number of registered elements in this container. The name is not
    // size as it could be misleading.
    virtual int ElementsCount() const = 0;

    // Iterators for ranged-for loops
    virtual StoringFactoryIterator<DataType> begin() const = 0;
    virtual StoringFactoryIterator<DataType> end() const = 0;
};


The abstract StoringFactory class above is rather simple. Someone that is somehow reading this post will probably notice that there are no methods to actually insert or create data into this container. The reason for that is that I want to try using emplacement methods with variadic templates. There's a catch, though: they can't be virtual, forcing them to be in the child classes. How, then, can I insert data into the container when I have only a pointer to the base class? It turns out that it is indeed possible, by means of abstract factories or dependency injections, and some magic.

Next comes the dubious methods of DeleteData and DeleteHandle. DeleteData is rather dangerous and nonsensical, but I want the ability to remove data from memory without first needing to properly clean up anything related to its handle (such as every object that has a shared ownership of the handle). This can be useful in some very rare cases, as unloading low priority resources when in need of memory. The DeleteHandle probably shouldn't be public. Handles will call this method to destroy themselves, but I don't see any reason to not make this method protected, and the handles a friend class of the StoringContainer.

And what does the handle looks like?


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
using handle_type = unsigned int;

template <class DataType>
class StoringFactoryHandle
{
public:
    StoringFactoryHandle(handle_type handle, StoringFactory<DataType>* factory);

    inline DataType* Get() const;
    inline handle_type GetHandleValue() const; // TODO : restrict creation access



protected:
    StoringFactory<DataType>* m_Factory;
    handle_type m_Handle;
};


They're just a small container with enough information to refer back to the original data. I've restricted the handles to store handle_type (that is, unsigned int) as their "handling key". I could have used pointers, but ended up deciding on "indexes" or "keys" instead. This is a decision that'll probably be very hard to change later on... so let me pretend to be proud and sure of what I'm doing.

Finally, all that remain are the iterators types for the StoringFactory class. It is possible to make an abstract iterator type and then inherit as needed, for each storage desired, such as lists, maps, etc. This should work, by relying on Covariance, but soon many flaws of this idea would sprout everywhere. One of the problems, for example, is the need of casting between parent and child types of the iterator. Even if that is solved, templates and slicing would come right after with many other problems. The path I chose was to use the pimpl idiom, though I feel like I'm missing a bit of its point.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
template <class DataType>
class StoringFactoryIterator
{
public:
    StoringFactoryIterator(StoringFactoryIterator<DataType>& other);
    StoringFactoryIterator(std::unique_ptr<StoringFactoryIteratorImpl<DataType>> iteratorImplementation);
    ~StoringFactoryIterator() = default;

    DataType& operator *() const;
    const StoringFactoryIterator& operator ++();
    bool operator !=(const StoringFactoryIterator& other) const;



protected:
    std::unique_ptr<StoringFactoryIteratorImpl<DataType>> m_StoringFactoryIteratorImpl;
};



template <class DataType>
class StoringFactoryIteratorImpl
{
public:
    StoringFactoryIteratorImpl() {}
    virtual ~StoringFactoryIteratorImpl() {}

    virtual DataType& Dereference() const = 0;
    virtual const StoringFactoryIteratorImpl& PreIncrement() = 0;
    virtual bool IsDifferent(const StoringFactoryIteratorImpl& other) const = 0;

    virtual StoringFactoryIteratorImpl* clone() = 0;
};


The idea was to use a single iterator "interface" class to redirect operations to a real implementation, that is storage specific. Some problems with slicing still remains, such as making clones of the iterator implementation when the "interface" is copied around. Since the implementation is handled only by the "interface" class, methods such as clone are used. Casting is still a problem (i.e when the user try to copy or compare the iterator of one type of storage with one of another type of storage). I didn't decide on any special semantics for that, but later there'll be probably some assertions for debug builds.

Some methods are still missing, such as container sizes, but this is the basic for my storing with handles system for game components. I'm also implementing an ArrayStoringFactory class, that inherits from StoringFactory, but I don't think it's code has anything interesting right now.

Let's see what happens in the next 15 days. After finishing up theses classes and adding any new needed method to the base classes, I'll make some unit tests and then the Transform component. Maybe I'll have some thoughts to write in this blog again.

All code in this post has been pretty-printed by hilite.me

domingo, 6 de março de 2016

Games in C++ can't be that hard, right? - Shared Pointers and Ownership.

        C++ was my favorite language back then, at college, and even before. Fun were the days where Segmentation Fault wouldn't immediately translate to time or money wasted around, nor unhappy clients contacting the team. Right after graduating I've started using C# with Unity 3d and got into the Garbage Collected world – and I've stayed with C# from the very then.

        I've decided to start a simple C++ game on my free time. It can't be that hard, right? And the game will run a lot faster, right? Actually, both are wrong. C++ can be very hard if you aren't used to think in terms memory management, resources ownership and mapping, and even when and how their memory will be released. Even with smart pointers and RAII, everything can eventually go south. In fact, even in Garbage Collected environments with RAII and everything else, things WILL eventually go south... And about being faster, even if the compiled code do have raw speed in terms of execution time, a lot more often than not, slowness is caused by design, code architecture, algorithmic decisions and so on. The end result is that in hands of good programmers, it's possible that games in C# or Java run faster simply because they're easier to profile, debug and refactor – and refactoring is as time demanding as it is need for any project survival as it grows.

        Enough about that! I've decided to use c++ and so I've started searching around about what good practices there are when using the "new" standard smart pointers. "New" because they've already existed in Boost since like ever. Then I found this amazing stack overflow answer, by David (quoting here):

"
Personally, this is how I (more or less) do it:
  • unique_ptrs are for sole ownership
  • raw pointers mean whoever gave me the raw pointer guarantees the lifetime of that object to match or exceed my lifetime.
  • shared_ptrs are for shared ownership
  • weak_ptrs are for when a system wants to check if the object still exists before using it. This is rare in my code since I find it cleaner to have a system guarantee the lifetime of anything it passes it's subsystems (in which case I use a raw pointer)
By far I use more unique_ptrs than shared_ptrs, and more raw pointers than weak pointers.
"

        These guidelines are indeed very accurate and simple, as, in my opinion, smart pointers greatest virtue is showing intention over “simply” managing memory. There are, of course, exceptions where those guidelines can't be properly followed, but exceptions exists for everything in the coding world. Looking at smart pointers types, we can see that there's an immediate synergy between unique_ptr and raw pointers, and shared_ptr and weak_ptr. It's simple, right? Can't be that hard. Again, this turns out to be wrong. Not because of the guidelines nor the pointers, but because of the problem that came way before them: resource ownership.

        I've structure a simple Entity-Components-System for a game. I want Entities to have a list of components they hold, but I want actual components data to be stored somewhere else, in a ComponentsContainer class. The reason is that I want my systems to be able to iterate over all components of a single type easily.

        I bet that didn't make any sense, right? Well, I've imposed a few restrictions on each part of this structure:

Components:
  • [c1] Components can have methods, but "high level" methods such as "Update" or "Render" are desired to be in a System, which will iterate over all components executing their logic.
  • [c2] Components must be able to store references to other components, of the same or any other entity. They must have means of easily checking if that component still exists.
  • [c3] Components can be destroyed anytime, by any component or System.
  • [c4] Components should be automatically deleted if no one references them, if possible.
  • [c5] Components are owned by a single entity.


Entities:
  • [e1] They have a unique identifier
  • [e2] Must not have logic other than helping methods
  • [e3] They uniquely own their components


Systems:
  • [s1] Systems have the responsibility of iterating over components of a single type (the one that the system works with), executing logic, rendering, or whatever else it is supposed to do (i.e spatial partitioning for another system, such as collision testing)


        There are problems with [s1], [e3], [c2] and [c5].

        Because of [c2], it is desired that the entities own each component by means of a shared_ptr, even if they are the unique owners. With this, references to any component can be weak_ptr, and we can check whether they (the referenced components) have been deleted or not. Alternatively, using a unique_ptr would mean our references are now raw pointers. By the guidelines above, a raw pointer indicates that the resource pointed to will outlive the component, which is not guaranteed because of [c3]. With shared_ptr, actually, the solution for this is kind of straight away: entities must not ever allow another shared_ptr share the component, pushing us back to the original "unique" ownership.

        Now, [s1] says that we need means to iterate over all components of a single type. It is possible to achieve this by simply iterating over all entities, searching for components of a specific type. There are some ways of achieving this, such as storing a matrix of entities X components, etc, but I personally don't like the concept of checking if an entity has a component in order for us to update it, in a System. If I want to iterate over all components of a type, it does not mean I am also interested in checking if they exists. Checking for this in Systems might be made later, as a need for deep refactoring.

        Trying to not over-engineer, the components storing can be moved out of the entities, into a data container. A data container will also make some stuff a little bit simpler, such as factories and dependency injection, if I decide on them later. I want these characteristics:

  • [d1] They must work with ranged for loops. Come on, that's cool! Every iteration must be over a valid component (in the context of allocated and alive)
  • [d2] They do not need to worry about specific alternative accessing methods. For example, methods to allow accessing specific elements of an octree is too specific. The system will have to know the container type anyway, to do this effectively.
  • [d3] They must not force any specific type of structuring. This means that they might be used as vectors, lists, maps, trees, octrees, etc
  • [d4] They must be able to store data contiguously
  • [d5] Reordering elements should not break any references
  • [d6] Data not used by anyone should be deleted, to avoid leaks.


        The rule [d4] is a critical one. It is listed here to avoid the need of some refactoring later. [d4] together with [d1] permits intuitive (for the System) sequential access over contiguous memory data. Even if I don't want to implement this right now (and I dont), this will inevitably become an important optimization later, as it allows for cache-friendly access.

        With the data container, the components won't be stored in entities anymore, although entities still are their unique owners. Simple? No. There is a problem here. If the data is contiguous, then it's very likely that the components are stored by value in an array. We just can't delete it. However, were it in another data structure, such as tree of elements in the heap, then deleting would be a must. Fortunately, smart_ptr allows us to pass a function – better yet, a lambda - to use as deleting logic. We can pass this complexity back to the container, making it create the new component for us and returning a shared_ptr with the deleter set.

        However, it turns out that smart pointers aren't enough anymore, because of [d5]. If the container reorders the elements, how am I supposed to update the references in the entities? They need to point to something else, instead of the data itself: maybe a handle – and then now we have a smart pointer to a handle. It is kind of like de-referencing twice, to access the data we want.

        Since we have arrived at handles, now it is hard to let go of them. They can still exists even if the resourced they "handle" is not around anymore. If we can update a handle when the resource is deleted, we can make it either return nothing, or return something to expose the error. For example, a handle to a sound effect could return a default error-like sound when accessed after the original sound has been unloaded. This means allowing the data container being able to unload the components even if they are still being used by other entities. The use for this sounds dubious for components, but it is interesting if we can make the container generic.


        So, how to structure everything with handles? I have no idea. I'll be thinking about it and then make a new post in the future.

segunda-feira, 22 de fevereiro de 2016

Okay, time to try to become active, again!

        I'm back... again. Really, keeping a blog updated is a lot harder than I initially thought. And I still need to learn ways to improve this basic layout...

        I haven't been writing in english for a while, so I may have got a little rusty and so I say sorry in advance! A few years ago, I tried to go indie on mobile and failed. I'd point out two main mistakes:

- Failing to notice I'm an awful game designer.
- Throwing away many prototypes. Have you ever heard MVP? Probably some of those prototypes that haven't ever seen the real world had a chance. Who knows? I've never released them, so I'll never know – and sometimes, not knowing is worse than failing.

        Rants aside, I got a job and had to stop games development since there were so many things that I needed to learn in order to keep up with the team. Working in a professional team has really helped me to develop new ways of handling other people code and logic as well as how to behave in a project under the wings of Scrum (if you're a programmer, you probably understand how hard this could be).

        Now I've got some free time for side projects again, and went off using Unity 3d until I realized that on free time it's really hard to make a complete game – even in Unity – so I'll take this opportunity to go back to C++ that, despite being my favorite language, I've only used until graduation, and also learn C11. Don't know if I'll continue the "asm" series, but surely there'll be some posts about my frustations adventures with C++ in the near future. And yes, I'm very aware that if I wouldn’t finish a game in Unity 3d, its a lot more likely that I won't ever get even close to it in a lower level environment.

For great justice.