Getting started

So while working on my game spaceTradeSim I ran into a problem. This problem was "how do I make it easy to add space stations to the map". This is a problem I have been struging to come up with a soloution for for some time now.

But I found one. That soloution was an Entity Componet System(ECS). I tried to stay away from, not for any real reason other then I thought it would require a large code rewrite and I thought it was hard. Turned out I was wrong on both accounts.

It wasn't hard and I didn't need a large code rewrite. I thought it was hard mainly because I had never created one or used one before. Bouns was that I didn't need a large code rewrite. I think this was mainly because I already had an entity class. All I had todo to it was four functions to it and that was about it. So enough of this talk time to get in and explain some things. I think I'll start with the ECS.

Building the ECS

This is somthing that I had been advoiding as stated above. But I started looking into it while I was working on the space stations. I found this helpful video on YouTube. While I didn't end up implamenting the same system he used. It inspired me to take another look at it.

At the start the idea was that I would have a virtual class called EntityComponent that all other components would from and build off.

class EntityComponent
        {
        public:

        	EntityComponent();
        	~EntityComponent();

        	virtual void OnCreate(){}
        	virtual void OnDraw(){}
        	virtual void OnTick(){}
        	virtual void OnUpdate(){}

        	uint64 GetID() const { return m_ID; };
        	std::string GetStringID() const { return m_strID; };
        	void SetID(const std::string &id) {
        		m_strID = id;
        		m_ID = (uint64)djb2Hash((unsigned char*)m_strID.c_str());
        	}
        private:
        	std::string m_strID;
        	uint64 m_ID;
        };
        

So its pretty simple. A component inherits this class and just fills out the OnXXX() functions. This was a good idea at the time. Then came the, "How do I tell the game what component an entity has easily?" question.

This was easily done using my Json parser. I have a jsonpp wrapper that is handy for these things. I added the data needed to the json file describing the species that inhabit the world and added the required code.

All was working fine, until I thought "But how do I let modders change these?" Not just modders but me as well. That I felt was the point where I decided that I should add Lua back in. The component system was in that state for about an hour maybe two hours. Then I started with the Lua.

Adding Lua

Around 2013 Lua had been added to the code base, but it was removed due to me not being experienced enough to write a decent wrapper. Back then I didn't really need it and it was more of an experiment then anything.

But as time went on and the simulation turned into a game and I added Lua back onto the todo list. It was on the back burner but it was there. I guessed that I would implament it when I needed gameplay.

The first thing that I did was work out how I'm going to save the current lua state. I came up with the Lua instance.

enum LuaIncludeFlags
  {
  	INC_LUA_MAP = 1,
  	INC_LUA_MAP_MANG = 2,
  	INC_LUA_ACTOR = 4,
  	INC_LUA_ACTOR_MANG = 8,
  	INC_LUA_UI = 16
  };


  class LuaInstance
  {
  public:
  	LuaInstance();
  	~LuaInstance();
  	void InitLuaInstance(const int &flags, const uint64 &id);
  	bool LoadFile(const std::string &file);
  	bool CallLuaState();
  	void CleanInstance();
  	bool ReloadInstance();
  	std::string GetLastError() const;
  	luabridge::LuaRef GetLuaGlobal(const std::string &name);
  	uint64 GetInstanceID() const { return m_id; }

  private:
  	lua_State * p_lstate;
  	bool m_firstLoad;
  	uint64 m_id;
  	std::vector<std::string> m_files;
  	int m_flags;

  };
  

So some of the more eagle eyed of you might have noticed the luabridge:: namespace being used. Thats because I'm using LuaBridge for my lua c api wrapper. Personaly I think its great. Soloution to the largest problem I had with Lua and that was the api calls. I'm sure with time I could have worked something out but it wouldn't be anywhere near this good.

You might also notice the bool m_firstLoad. This is because I discovered you can load more then one lua file into a state. I don't know if this is not ok but it seems to work for now so yay for me. For this to work you need to call luaL_loadfile(lua_State*, const char*) on the first file loaded. Then for each file after that you call luaL_dofile(lua_State*, const char*). Once you have finished loading files you have to call lua_pcall(lua_State*, 0, 0, 0) for you to be able to access any of the stuff you just loaded. This is called in CallLuaState().

I think Lua will either throw an error when there are conflics or just over write what ever is already there. I tested this but I can't remember what it did. Either way something happens :D.

The LuaIncludeFlags enum allows me to control what classes and data the lua_State has access to. Not all states need access to the map, but others do. I have an update to this in the works already. I'm going to allow a callback in the Init function so its more matainable in the long run.

Loading Components

The last problem was how do I get all of this working together. That was an easy fix, use the json loader that I already have. For the engine to be able to find the conponents we first need to tell it where to find them.

{
      "components": [
      {
        "flags": [
          "Actor"
        ]
      },
      {
        "id": "component_basic_actor",
        "file": "lua/Components/ComponentActor.lua"
      },
      {
        "id": "component_health",
        "file": "lua/Components/ComponentActor.lua"
      },
      {
        "id": "component_move",
        "file": "lua/Components/ComponentActor.lua"
      },
      {
        "remove_flags": [
          "Actor"
        ]
      }
    ]
  }
  

Thats what this json is used for. It tells the engine which LuaIncludeFlags the components will need access too and also the name of the components. These flags can be nested as well. I am still experimenting with this system but I think it has potential. If im not sure what I need I can always just use the Everything flag.

The End

I think thats the basics of the system. But there is a lot more going on it the background when it comes to the LUA and the component system. But I think thats better left for another day.

Back to writtings / Home