Jump to content
  • Advertisement

Project: Five Nations

PC End of October DevLog



RTS fans, we're coming at you with yet another DevLog entry!

New features are landing in this weeks version

  • Advanced AI updates to enhance how computers control their economy, production, and military in Skirmish mode.
  • Long-waited in-game menu where players can fine-tune how they interact with the gameplay
  • Visualization of workers returning to the station with the extracted raw materials.
  • Added new researches to the game
  • Improved fighters and carriers in-game behavior
  • Dozens of bug fixes


  • The updated and polished version of the Prequel Missions are coming out for PC this month
  • We're also releasing an HTML5 version onto Game Distribution this month


What are the possible ways to support the project? We highly appreciate any sort of help to deliver Five Nations. The best ways to do that are:

  • Preordering the game at http://fivenations.webellionlimited.com
  • Leaving some tips on GameJolt (https://gamejolt.com/games/fivenations/389358) or Itch.io (https://webellionlimited.itch.io/five-nations)
  • Joining our Discord channel where you can discuss feature requests, proposals, bugs \


Thank you guys, we're looking forward to hearing what you think!


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Advertisement
  • Blog Entries

  • Similar Content

    • By Ruben Torres
      If you plan on jumping into Unity Addressables Pooling, be careful. You better make sure the object pool is not empty.
      [The original post with its formatting can be found at Unity Addressables Pooling]

      In previous posts, I showed you how to load content in your game without limits.
      Well, sure there are limits, but you are not likely to reach them if you did a good job at implementing your asset content management system. And I'm pretty sure you'll get it right enough if you followed my advice.
      But so far, I can say we are missing one important piece of the puzzle, though. I mean, we're missing many, but today I want to focus on a very specific one: latency.
      What's latency?
      Latency is the time it takes between starting something and finishing it. It is some sort of delay that we usually want to avoid.
      You suffer latency when cooking your microwave popcorn, for instance. There, you start the microwave and have to wait for 3 to 5 minutes. And we want to eat popcorn right away, so this kind of latency is bad.
      When we get into the field of games, things get worse than cooking popcorn.
      In games, milliseconds matter. Everything above 20ms makes competitive multiplayer a bit more unfair.
      But in this post, we're not talking about multiplayer games. We will be talking about the latency we suffer when we load and display an asset using Addressables for Unity.
      And actually, we will do something about it.
      We'll implement a simple Unity Addressables Pooling System.
      Will you jump in the pool?
      Quick Navigation (opens in a new tab)
      Level 1 Developer: Simple Unity Addressables Loading
      Level 2 Developer: Unity Addressables Pooling
          1. Warm-up the asynchronous pool
          2. Helping our Gameplay: take an item from the pool
          3. Saving CPU time: return the item to the pool
          4. Freeing up memory: disable the pool
      Level 3 Developer: Smart Unity Addressables Pooling
          Automatic Pooling

      Level 1 Developer: Simple Unity Addressables Loading
      Yes, I know. We've done this several times.
      We take a prefab, mark it as Addressable and we assign it to a script that loads the prefab whenever it makes sense.
      And this gives you big benefits over traditional asset management workflows based on direct references. In short, using Addressables gives you...

      To read more on this, visit my introductory post on Unity Addressables Benefits: 3 Ways to Save Your Game.
      In this blog post, I'll stick to showing my tremendously complex sample project setup.

      Unity Addressables Simple Setup
      Oh nevermind, it was just a prefab instantiated through the Addressables API...
      This works most of the time just fine for any game.
      This loading and instantiation process has some latency to it. Unity has to fetch the required asset bundle, load the prefab and its dependencies and instantiate.
      The loading process should take well below 1 ms.
      But things get messy when we add more complexity to this object. If we add animators, particle systems, rigid bodies and such, Unity can surely end up stealing 10 ms away from us. Activating these components can take a significant amount of time.
      And if the asset bundles are served over the network and they were not ready, then we're speaking of seconds, even minutes.
      How terrifying would your game be if by the time your final boss is spawned the player already reached the end of the dungeon?
      This is my guess: as terrifying as profitable.
      A typical solution in Unity relies on adding object pools. 
      There're many object pools you can find online for Unity. The issue is, they're not Addressables-ready.
      But now, you'll get one.

      Level 2 Developer: Unity Addressables Pooling
      Let me warn you here: the needs for a pooling system greatly vary from project to project.
      Here I'll be giving you a simple system that you can tweak to match your needs.
      This is what you'll want from this pooling system:

      In case you were wondering: yes, I re-used the icons from the previous section. Busy times here.
      Before we jump into the code, I'll show you the test I prepared.
      1. Warm-up the asynchronous pool
      By now, the prefab and its content are not loaded in memory.
      The pool is enabled and loads the prefab based on Addressables.
      Then, it instantiates several objects and deactivates them all, paying the price of Awake, Start, OnEnable and OnDisable.
      By now, the prefab contents are in memory.

      Addressables Pooling: Warm-up
      2. Helping our Gameplay: take an item from the pool
      A user takes an item from the pool and puts it somewhere in the scene through the synchronous method Take().
      The user pays the activation (OnEnable) time, which depends on the complexity of their prefab.

      Addressables Pooling: Take
      3. Saving CPU time: return the item to the pool
      The user gets tired of their new toy and returns it to the pool.
      The pool deactivates it and puts it under its hierarchy, paying the price of OnDisable.

      Addressables Pooling: Return
      4. Freeing up memory: disable the pool
      After some time, we know we will not need this item anymore.
      We disable the pool and therefore it'll free up all the used memory, even though the indirect reference is still present in the pool.

      Addressables Pooling: Disable
      The strength of this method relies on memory management. We pay the memory price when we decide to.
      With traditional Unity Object Pools, we paid the memory overhead all the time, even if the prefab was never instantiated.
      Now, how does the code look like?
      01: public class GamedevGuruPoolUserTest : MonoBehaviour 02: { 03: [SerializeField] private AssetReference assetReferenceToInstantiate = null; 04: 05: IEnumerator Start() 06: { 07: var wait = new WaitForSeconds(8f); 08: 09: // 1. Wait for pool to warm up. 10: yield return wait; 11: 12: // 2. Take an object out of the pool. 13: var pool = GamedevGuruPool.GetPool(assetReferenceToInstantiate); 14: var newObject = pool.Take(transform); 15: 16: // 3. Return it. 17: yield return wait; 18: pool.Return(newObject); 19: 20: // 4. Disable the pool, freeing resources. 21: yield return wait; 22: pool.enabled = false; 23: 24: // 5. Re-enable pool, put the asset back in memory. 25: yield return wait; 26: pool.enabled = true; 27: } 28: } That's a pretty normal piece of code for testing.
      If there's anything relevant to mention is line 13. Why do we look for the pool passing our asset to GetPool?
      The idea behind that is that you might need several pools, one for each asset type, so you need a way to identify the pool you want to access.
      I don't particularly like static methods that access static variables, but you should adapt the code to the needs of your game.
      By the way, you don't need to copy all the code yourself. I prepared a repository you can access for free. Visit the GitHub Repository
      And how's the code for the pool itself?
      01: public class GamedevGuruPool : MonoBehaviour 02: { 03: public bool IsReady { get { return loadingCoroutine == null; } } 04: 05: [SerializeField] private int elementCount = 8; 06: [SerializeField] private AssetReference assetReferenceToInstantiate = null; 07: 08: private static Dictionary allAvailablePools = new Dictionary(); 09: private Stack pool = null; 10: private Coroutine loadingCoroutine; 11: 12: public static GamedevGuruPool GetPool(AssetReference assetReference) 13: { 14: var exists = allAvailablePools 15: .TryGetValue(assetReference.RuntimeKey, out GamedevGuruPool pool); 16: if (exists) 17: { 18: return pool; 19: } 20: 21: return null; 22: } 23: 24: public GameObject Take(Transform parent) 25: { 26: Assert.IsTrue(IsReady, $"Pool {name} is not ready yet"); 27: if (IsReady == false) return null; 28: if (pool.Count > 0) 29: { 30: var newGameObject = pool.Pop(); 31: newGameObject.transform.SetParent(parent, false); 32: newGameObject.SetActive(true); 33: return newGameObject; 34: } 35: 36: return null; 37: } 38: 39: public void Return(GameObject gameObjectToReturn) 40: { 41: gameObjectToReturn.SetActive(false); 42: gameObjectToReturn.transform.parent = transform; 43: pool.Push(gameObjectToReturn); 44: } 45: 46: 47: void OnEnable() 48: { 49: Assert.IsTrue(elementCount > 0, "Element count must be greater than 0"); 50: Assert.IsNotNull(assetReferenceToInstantiate, "Prefab to instantiate must be non-null"); 51: allAvailablePools[assetReferenceToInstantiate.RuntimeKey] = this; 52: loadingCoroutine = StartCoroutine(SetupPool()); 53: } 54: 55: void OnDisable() 56: { 57: allAvailablePools.Remove(assetReferenceToInstantiate); 58: foreach (var obj in pool) 59: { 60: Addressables.ReleaseInstance(obj); 61: } 62: pool = null; 63: } 64: 65: private IEnumerator SetupPool() 66: { 67: pool = new Stack(elementCount); 68: for (var i = 0; i < elementCount; i++) 69: { 70: var handle = assetReferenceToInstantiate.InstantiateAsync(transform); 71: yield return handle; 72: var newGameObject = handle.Result; 73: pool.Push(newGameObject); 74: newGameObject.SetActive(false); 75: } 76: 77: loadingCoroutine = null; 78: } 79: } I know, somewhat long, but I want to post it here so I can explain what's going on.
      Like I said before, in line 14 we're getting the right pool for you, as in this article we aim to have a pool per prefab. We use the runtime key for this matter, which is the string we use to identify our addressable assets. Other variations can include using generics and enums to use a single pool object instead.
      In lines 30-33, we take one object from the pool, we parent it and then activate it. You might want to add more arguments to this function, such as position and rotation.
      We do the opposite in lines 41-43. Like the child who rebels and leaves home only to come back after just an hour, we accept it back. We deactivate it and parent it back to our pool game object.
      And then it is time to warm up the pool and empty it in lines 52 and 60. We pre-warm the pool when it is enabled by instantiating and deactivating 8 prefabs. Finally, we call Addressables.ReleaseInstance to free up memory.
      The strategy here is clear: enable the pool when we suspect we will need it and disable/destroy it when we don't.

      Level 3 Developer: Smart Unity Addressables Pooling
      There are so many variations of Unity Addressables Pooling systems.
      It all really depends on your objectives for your game.
      You could, for instance, prioritize performance. If that is the case, you certainly don't want to activate/deactivate entire game objects on the pool's Take and Return calls.
      Activations are extremely expensive. What you want there is to enable/disable certain components instead, such as renderers, animators, canvases, etc.. You'd stop paying the draw calls while not paying activation times.
      Something you could also avoid is excessive parenting, as we also pay a high price for it.
      If this is your case, you might want to go for PerformancePool.
      Did you ever use Photon, PlayFab, Mirror or any other networking solution to add multiplayer possibilities to your game?
      If so, you might have noticed you often have to assign a prefab somewhere so these systems instantiate it when required.
      But what if your prefab is based on Addressables?
      Well, in that case, you can still profit from a more specialized plug and play pool version: NetworkedPool. 
      Automatic Pooling
      If performance is not required and you'd rather save time, you can also make your life easier and still get the benefits of pooling.
      You could go for the AutomaticPool component, which will take care of loading and unloading prefabs for you. What is more interesting, it'll free up its entire memory after a certain time has passed without users requiring the prefab.
      If you are interested in these Plug And Play components, you'll be happy to know they will be included in my upcoming Addressables for the Busy Developer course.
      Highly-skilled game developers and I will start a sprint to transform and level up the way we make games in Unity.
      Join us in the quest.

      What did you think of the article? Leave a comment to share your experience with Addressables.
    • By RoKabium Games
      Aura enemies – ”Murderia” is a crystal based life form that moves across any type of block at some speed. This creature cannot be killed by digging the block it sits on and therefore it makes the block it sits on impossible to mine. It fires projectiles in all directions if it feels threatened so kill from afar.
    • By iGrfx
      I tried to clear a RWStructuredBuffer<bool> by a CommandList->ClearUnorderedAccessViewUint call.
      I got an error like this:D3D12 ERROR: ID3D12CommandList::ClearUnorderedAccessViewUint: ClearUnorderedAccessView* methods are not compatible with Structured Buffers.
      However, I've searched on the internet but got nothing, I saw someone done this before, Does anyone know how to solve this problem? Thanks in advance!
    • By joetext
      Hey all, I'm at my wits end with this weird memory leak. My issue is with the small preview-render view that comes up on the Windows 10 taskbar when you hover over your application. I don't know the name of it, but it's the little thumbnail view that pops up when you have your mouse hovered over a minimized application. When I do this with my dx11 program, memory absolutely rockets up, I'm talking like going from 1 gb to 4 gb in a few seconds. I managed to find a single line that I can comment out and "fix" the leak, but it's not making any sense to me. The graphics portions of my program are somewhat fragmented between different abstraction layers so bear with me.
      // the code that actually handles the render calls // map buffers and copy data from cpu buffers m_context->copyDataToBuffer((void*)verts.data(), sizeof(Vertex) * verts.size(), m_vertexBuffer); m_context->copyDataToBuffer((void*)indicies.data(), sizeof(uint) * indicies.size(), m_indexBuffer); m_context->copyDataToBuffer((void*)uniforms.data(), sizeof(HuiUniforms) * uniforms.size(), m_uniformBuffer); // render ISamplerState* sampler = shaderSys->getSamplerState(); m_context->setVertexBuffer(m_vertexBuffer); // this is the line that is causing the leak m_context->setIndexBuffer(m_indexBuffer); m_context->setUniformBuffer(m_uniformBuffer, ShaderType::Vert); m_context->setUniformBuffer(m_uniformBuffer, ShaderType::Frag); m_context->setTopology(PrimativeTopology::TriangleList); m_context->setSamplerState(sampler); Texture2D** textureArr = &diffuseTexture; m_context->setTextures(textureArr, 1); m_context->drawIndexed(indicies.size()); m_vertexBuffer is an abstraction for a ID3D11Buffer. Here's the code for that setVertextBuffer call
      void D3DRenderContext::setVertexBuffer(IBuffer* buffer) { D3DBuffer* d3dBuffer = static_cast<D3DBuffer*>(buffer); ID3D11Buffer** d3dBufferResource = d3dBuffer->getBuffer(); UINT stride = sizeof(Vertex); // Vertex is a simple struct UINT offset = 0; m_context->IASetVertexBuffers(0, 1, d3dBufferResource, &stride, &offset); } And for completeness sake here's the copy buffer function
      void D3DRenderContext::copyDataToBuffer(void* data, int dataSize, IBuffer* toBuffer) { D3DBuffer* d3dBuffer = static_cast<D3DBuffer*>(toBuffer); ID3D11Buffer** d3dBufferResource = d3dBuffer->getBuffer(); HRESULT result; D3D11_MAPPED_SUBRESOURCE resource; result = m_context->Map(*d3dBufferResource, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &resource); memcpy(resource.pData, data, dataSize); m_context->Unmap(*d3dBufferResource, NULL); } A few things.. I removed like 15 ASSERTS to make the code shorter, so any pointer that could potentially be null, and the dx results are all checked in the actual code. Second, I have the dx debug output enabled and it has nothing to say. Third, I've tried flushing the context after every call to drawIndexed, to no avail.

      This leak is just beyond bizarre to me, granted I have no clue how the underpinnings of that preview window work. In the meantime, I'm going to figure out how to tell windows to disable it, but I'd still like to know why this is happening. Any suggestions appreciated!
    • By srphfthnd
      Hello, I apologise in advanced I'm not really good in English. I'm just new here and I don't know how to start. I'm a fourth year IT student and want to make my favorite old game into mobile game. The game I want to create is base from mmorpg Ran Online which was shutdown 3 months ago. I deeply in love with this game and I want to make it into mobile but I have no idea where to start. I heard about how to reverse engineer the game and create it by using Unity software. I also try to read other forums regarding about making mmorpg in mobile but they just gave me a vague general answer. Please help me I want to know where I should start in this project. I really want this game in my pocket and to be back. I'm not that good but I have knowledge in Java and C++. Any help will be much appreciated. 
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!