From the Burrow
TaleSpire Dev Daily 18
A tiny log today as I’m heading out to see some friends now.
Today I took a little break from engine work to look at server side. The main take has just been tweaking our the DB to store the data we want for campaigns and characters and supporting granular permissions for who can do what. Those controls may not all be exposed but it’s not hurting to have it there.
When the UI for the creating/editting campaigns lands I’ll expose this from the web server and hook it up.
Until tomorrow.
Peace
TaleSpire Dev Daily 17
Hi again, today has been a day of churn. We have known for a couple of weeks that the way floors have worked in the prototype was unsatisfactory. For context you used to be able to delete floors and insert floors below others, which sounds great and felt great to.. on small boards. However when you start making a whole village and want to add a floor to a single building then the problems quickly become apparent, you add a floor to the entire village!
So instead of that we will be replacing it with the ability to select a region and:
- delete it
- delete it and drop the tiles from floors above down
- push tiles up to the next floor (which pushes the ones above up etc)
This will give the level of control we had before but without the caveats. Of course this requires a little more work from the user, but it feels like a necessary inconvenience.
Also, in order to be able to support large board in the future we needed to get away from anything that operated on entire floors so chunking up the board has been on the todo list for a while (we already had started this for the fog of war code). This is where the churn came in as, as you can imagine, floors were pretty central in the codebase so changing that out has touched a tonne of code. Getting things to behave again after those changes took most of today but it’s creeping toward feeling solid again.
I’m not 100% sure what I’m working on tomorrow. I still have a lot of tidy-up work to do, I need to look into how to add ‘hill climbing’ to the octree fill (more on that another day) and I need to make some server-side changes very soon.
Guess I’ll see how I feel in the morning.
For now have a wee video showing the fog of war responding to the door opening. I have to switch between DM and player here as attempting to open the door will try sending a message to the DM.. who is on the same machine and the UI code gets a bit confused :)
Seeya
TaleSpire Dev Daily 16
Almost forgot this evening’s one so it’s gonna have to be quick. Today I worked on the import of the occlusion data from TaleWeaver I’ve got a couple of small issues left where Unity’s behavior mas left me a touch confused but no doubt I’m just being a dummy.
I have noticed a shortening of these dailys over the last few days but fear not, they’ll be getting a bit longer as things get exciting again :)
Peace
TaleSpire Dev Daily 15
Good-evening folks! Today was spent getting used to the profile, finding out ‘deep-profile’ is useless, finding out that some parts are pretty fragile and then making a few speedups.
Mainly it has just be reducing the amount of info that needs to be written into the octrees for each zone. This is kind of avoiding the real issues though so we will need to get back to actually reducing the time things take, but that is for another day. The main thing to tackle was rewriting the code that find which parts of a tile are solid and which aren’t. This was previously hacked into TaleSpire itself and happened on load, but this is daft as it never changes so I have moved this to the tile modding tools.
I’m now going through all the existing assets and adding extra info to all of the floors and reexporting the assets with their new collision info. Tomorrow will basically be finishing that off and using this new data in TaleSpire, which should tale performance back to where it was. I will also serialize the octrees for file/load and syncing floors as it could be a pretty quick win.
Seeya
TaleSpire Dev Daily 14
Today I got a bunch of thing fixed so the new fog of war is starting to behave itself. There is still a bunch to do so my 7 day estimate at the beginning of last week is looking dumber by the day, however it’s still a good day.
I can load boards again, walk my character around and see that the systems are communicating properly. The next things on the todo are (in no particular order):
- Make tile deletion work with the fog of war
- Improve performance of adding tiles (see below)
- Only add occluders (a special kind of tile) to the fog of war zones
- Only update tile visibility info for zones that are on screen or nearby
- serialize the fog of war (maybe)
Right now, when loading boards there is an expected but noticeable lag. I know it’s related to the fog of war system but I need to know which parts are causing the issue. I’m definitely doing that before serializing the fog of war data as that would just mask any issues.
Right, gotta go get ready for a stream
Seeya
TaleSpire Dev Daily 13
Another short update for today. I got the fog of war logic mostly hooked up but in a very dissatisfying ugly way. The job for tomorrow is to try and wrangle it into a more sensible form and then start testing and tweaking the fill.
The tiles are being revealed now but as we are replacing some parts of the projects others are pretty broken. An example side effect is that right now you can walk through hidden walls. This ends up being rather demoralizing as the harder you work the more broken things get. Of course the logic part of the brain knows we have done this shit plenty of times before and in a few days it’ll be good again, just gotta keep grinding :)
Until next time
Ciao
TaleSpire Dev Daily 12
Today has been spent replacing the old fog of war with the new code. This code has paths from and through many other systems so it feels like I’ve been pulling on threads to see what moves and then unweaving them.. flashbacks to running network cables in an old job :p
Like yesterday I don’t have solid stuff to show but it feels like it’s getting close. Tomorrow will start with testing followed by hooking the level loading into the fog of war stuff. This either means having each loaded asset write add themselves to the zone’s octree or (much more likely) we just serialize the octrees.
I also need to look into which zones are updated per frame. For a huge map you don’t want some zone a mile away updating things that don’t matter.
Thanks for stopping by, seeya next time
TaleSpire Dev Daily 11
Today I needed to take a little time to be a human so less coding was done.
Before that I did get flood fill working across subsections of the board (zones). The next task is storing the results for the given character and being able to switch between different character’s perception.
Those successes only appear as a couple of messages in the log right now, so instead here is a visualization of the octrees of different zones as the character moves through them
Peace
TaleSpire Dev Daily 10
I got less done than I’d hoped today but that’s alright. We had to plan out some finer details of how the fog of war should behave under different conditions and required a few changes in how we are storing places the character has already revealed.
I’ve hacked out the data structure for this and am writing on the worker that will run the flood fills.
Not really much more to say right now,
ciao
TaleSpire Dev Daily 9
I like these days. These days I get to give good news. And today’s news is that the constrained flood fill works!
Let’s start with the pictures. In the next picture the white areas are all the fog of war we want to reveal if the character was at the red crosses. We can see that it hasn’t flowed into the blocked off room (even though the search does work vertically) as we have told it not to search above the eyeline of the character.
We can see this more clearly for this scene
If we search from the green cross we get
And from the red cross we get
This satisfies the requirements we had so hooray!
My (albeit brief) googlings didn’t give me a guide to how to do flood fill on an octree so here is my approach. We are going to do it on quadtrees as that makes the diagrams simpler, but the extensions to 3d in this case are trivial.
We start with our quadtree. The green colored areas are solid and the white are empty. The red cross is the starting point
Our first step is to walk down to the deepest node containing our point. We will call the recursive function that does this WalkToPoint
. We take with us:
- a list called
faces
. We will explain faces soon but just know we can add things to this list and they will be processed later. - a list called
spaces
. We add the empty nodes we reached to this list
When we get to the deepest node containing the point we check if it’s solid. If it is then game over the flood goes nowhere. If not then we add this node to the spaces
list and then:
- starting at the center of the node pick 4 positions, one up, down, left and right from the center. The distance to the point must be the width of this node.
- add a
Face
to thefaces
list. The face contains the position, the depth of the current node (3 in our case) and the direction from that new position to this node.
So for the position we picked to the right we make a face this this:
{
Position: Vector2(),
Depth: 3,
From: Left
}
We add all 4 new faces
to the faces
list and return;
When we get back to the function that started the first step we go into a loop doing the following:
- take a
Face
out of thefaces
list - call
WalkToFace
on thatFace
- keep doing this until the
faces
list is empty. - the
spaces
list now holds all the reachable empty nodes
Clearly WalkToFace
is doing the bulk of the work so lets look at how it behaves for 3 of the 4 faces we enqueued in the first function. We are only looking at 3 as they cover this different behaviours our code has to handle
For the position on the right we start by walking towards the Position
in the Face
just like we did for the first point, however we are keeping track of what depth we are at and as soon as our depth matches (or exceeds) the depth in the Face
we change our behaviour. In this case we have reached the deepest node already so we do the same as we did for the point, namely enqueue the 4 Face
s, add the node to the spaces
list and return;
The point above the first is a little different as before we hit the depth in the Face
we reach the deepest node. No worries, just enqueue the 4 faces like the last 2 times and return.
Also note that in this case we have points outside the quadtree, what you do with those is up to you. In TaleSpire we have divided the board up into zones and each has it’s own octree so we pass those external points off the respective zone for processing.
In this last case we walk to the depth specified in the Face
, now we are here we still have more child nodes. This is where the From
information in the Face
is important. Remember that we said that once our depth >= the Face
’s depth we change the behaviour. Now we stop picking nodes by the Position
in Face
and instead recurse into each of the child nodes on the side stated in the From
field in Face
. Doing this gets us to the 2 nodes marked with blue lines in the pic above.
If that isn’t clear here is a different example. Here we are coming from the right so all the rightmost nodes (marked in red) are reached.
Anyhoo if we keep following the above steps we will flood to all the nodes we can reach from the initial point. Note the you mustn’t process any node that has already been added to spaces
, but other than that we are good.
Doing this in 3D simply means handling 2 more directions.
There are lots of little places the speed this up, for example:
- track when all child nodes have been added to
spaces
or are solid. Then mark the parent node as processed and never process again. - you don’t need to return all the way to the initiating function to process
WalkToFace
calls. Keep track of the position in thespaces
when you started processing a given node. Some of entries in the list after that point will be the children trying to reach other, neighboring, child nodes. - Calculate the max number of
spaces
that could we enqueued in a single walk and preallocate thespaces
list so that it doesn’t have to grow when things are added. Less frequent allocations are almost always a plus.
But that’s enough for now. Saturday I’m going to get cross zone flooding working and Sunday will be spent hooking this up to actually show and hide objects. I also need to rewrite how I capture the collision info and handle deletions. I really wanted to get this done this week so the next week can be dedicated to refactoring how characters get placed and handle computing max walk distances, but I can tell already this will need a couple more solid days of work. Ah well.
Peace folks