From the Burrow

TaleSpire Dev Log 377

2023-02-21 20:02:25 +0000

Heya folks.

Since we last spoke, I’ve carried on with my main two tasks, slab upload, and symbiotes.

Slab Upload

Slab upload is going well. It’s always nice when something starts feeling like a feature and not a hack.

The progress isn’t exciting to show, though. It’s been things like:

  • Side-load the slab data into the cache, so it doesn’t have to be redownloaded
  • Show an hourglass cursor when the slab tool is waiting on a slab to download
  • Tuning camera behavior so that transitioning in and out of publish mode does what is expected.
  • Get tabbing between fields working as expected
  • Subtle visual changes to screenshot view to improve the experience
  • Add loading graphics to the entries in the community-mod browser to show that thumbnails are downloading

And so on.

I’ve still got a list of tickets to get through to get a good first version, but there don’t seem to be any show-stoppers.

The one (happy) distraction has been helping with the Symbiotes feature.

Symbiotes

Context: Symbiotes is an upcoming feature allowing community-made mods to dock on the right side of the TaleSpire window.

Our first version of this feature supports Symbiotes powered by WebViews[0].

We are providing an API that allows communication with TaleSpire. The messages between TaleSpire and the Symbiote travel over a simple interconnect provided by the WebView.

The code on either side of such a bridge needs to match and, from my experience, are places where simple user errors result in extremely annoying bugs. To deal with that, I prefer to write the API specification as a simple document, which is then used to generate the plumbing code for either side.[1]

And so that’s what I’m making. I have a JSON document specifying types, calls to TaleSpire, and the arguments and return types of those calls. I load that document, type-check it, and produce an intermediate tree of objects which describe the bridge.

Next, I’ll write code to walk over that tree to spit out the JavaScript and C# boilerplate code required.

Some of you may be asking, “why aren’t you using for this?". The answer is slightly dumb and slightly sensible, and it's "I can make this approach more quickly as I haven't used that library yet." I'm actually quite interested in [flatbuffers](https://google.github.io/flatbuffers/) for symbiotes and server communication. But that said, I am very used to writing these kinds of generators. I know how to make something that solves our exact problem and do it in a short amount of time.

Given that we are trying to ship mods quickly and that this approach doesn’t stop us from using a different serialization approach in the future, this is the way we are going for now.

Alright, enough rambling for today. Looking forward to sharing more with you soon.

Peace.

Disclaimer: This DevLog is from the perspective of one developer. It doesn’t reflect everything going on with the team

[0] In the future, I want to explore supporting other languages/environments. [1] This is exactly what we do with our server-side API. The API is represented as an erlang data structure, and from that, we generate C# and erlang plumbing code. It’s been a huge boon.

TaleSpire Dev Log 374

2023-02-10 16:35:56 +0000

Heya folks!

I’m away from my main dev machine today, so no gifs for ya, but there is some progress.

I’ve got to the point where I can select a region of the board, submit it as a slab to mod.io and bring it back into the game. So the essentials are there. It’s still janky, but I know what I need to do.

We’ve also continued working on Symbiotes (our mods that slot into the right-hand side of the game). We’ve got messages passing between mods and the game, so you can do things like send chat messages, set up dice rolls, and listen to the results.

We are busying ourselves experimenting with the API to work out what is clean and practical to get started with. We have more to show, but as that work wasn’t done by me, I’ll let that person write their own dev log about it :)

We definitely are pushing for mods to be out as soon as possible. Expect to see plenty of logs about this in the coming weeks.

Hope you’re doing well.

Peace.

Disclaimer: This DevLog is from the perspective of one developer. It doesn’t reflect everything going on with the team

TaleSpire Dev Log 373

2023-02-02 20:41:36 +0000

Heya folks!

Last week was spent on the backend. A lot is going on, but I want to save that update for when the governmental paperwork for our potential new hire is complete. It’s taking ages.

Work has continued on Symbiote, our modding feature allowing you to dock webview-based mods on the right-hand side of TaleSpire. Luis and I have been testing the web-view library under Linux (via Proton) to ensure we can provide the same experience across Windows, Linux, and Mac. So far, we’ve got it working if we disable sandboxing, which isn’t ideal but might be how we ship the beta.

Continuing with Linux, we have progressed in getting talespire:// URLs to work out of the box. Until now, we’ve been relying on a great script from community members, but in some cases, it requires user input [0]. This was because some execution flags[1] involved are system dependent.

Luckily for us, after a bunch of digging, Luis realized they were in the environment variables! So now we are pretty sure we have what we need to make this work. Hopefully, more on this soon.

From Linux to Mac we also have some good news. Unity has replied to Ree, saying that the bug he submitted (and that is blocking us from shipping mac support) has been fixed and is rumbling through whatever internal process is needed before it is released. When the fix eventually ships, we will have to upgrade our Unity version, which hopefully won’t be too painful [2].

I’m mostly done with a feature that allows you to only show the tiles/props you are currently selecting. This can be handy for precise selections, especially when working out what to upload to a slab repository. You can see it in action here:

a mode which isolates what you see to the active selection

You may also have spotted this icon:

the publish slab button

This is the “publish slab” button. Clicking it will take you to a mode where you can frame the screenshot for your slab and provide the required information. That mode will also be used for editing the info of the slabs you’ve already uploaded. It’s looking rough right now, but we have plenty of time to improve it. For now, I want to focus on shipping this stuff as soon as possible.

publish mode

I’m running a bit low on caffeine, so other things will have to wait for another dev log.

Have a good one folks.

Disclaimer: This DevLog is from the perspective of one developer. It doesn’t reflect everything going on with the team

[0] Also because it is run by Proton, so needs to be a Windows program. [1] ESync or FSync [2] There is a good chance that it will also fix the long-standing bug in the input system that stops us binding e to actions. That one is so weird!

TaleSpire Dev Log 371

2023-01-19 19:19:43 +0000

It’s time for a video dev log.

While I have you here, I’m going to abuse this reach I have to pimp something non-talespire, and even non-ttrpg related.

A good friend of mine released a game last week, and I’m so stoked for him. It’s called Kandria, and it’s a 2d open world hack-n-slash platformer, with celeste’esce smoothness of control, and a story laden post-apocalyptic environment. If that sounds at all interesting please give it a look here.

And with that I’m off, Cheers folks!

Disclaimer: This DevLog is from the perspective of one developer. So it doesn’t reflect everything going on with the team

TaleSpire Dev Log 369

2023-01-10 00:30:07 +0000

‘Allo again!

I was on the road most of today, but I have a little progress to show. Here is the first slab coming from mod.io directly into the game:

slab being spawned from community mod library

As mentioned in the last post, unlike chonkier mods like creatures and tiles, we want you to be able to spawn slabs without subscribing to them first. However, I don’t like the idea of waiting for the web request each time, so naturally, we’re doing some caching.

It works like this. When you first use a slab, it downloads it and saves it as a temporary file (that is deleted on exit). Once again though, loading a file does take a little bit of time, so we also keep the ten most recently used slabs strings in memory.

So when spawning a slab, TaleSpire can use the in-memory cache, fall back to the local file, or just download it.

In the gif above, you can just about see the timing difference between the first and second spawn of the slab.

While the code is still currently full of todos and stuff to clean up, I am going to switch to upload now as I want to start filtering by tags, and those are most easily added via the upload API. I’ll start tomorrow and see how quickly I can hack something in.

Until then, have a good one folks!

Disclaimer: This DevLog is from the perspective of one developer. So it doesn’t reflect everything going on with the team

TaleSpire Dev Log 368

2023-01-08 22:55:25 +0000

Hey folks,

In the last dev stream, we stated that we would start our foray into mods by making an official slab repository (along with an API for user-run sites to hook in too). This gives us some experience using mod.io’s API. As of a few days ago, I had this bit working:

showing a mod in the browser and inside TaleSpire

Since then, I’ve worked on the manager that handles downloading and caching slabs. It’s coming along well.

While I expect UX for creature, tile, and prop mods to be similar to our HeroForge integration[0], I think slabs should behave slightly differently. Rather than needing to link/subscribe to a slab to use it, I want you to be able to simply search, then click the icon to spawn the slab. If you want easy access, you can bookmark it to save the slab to your library for future use.

The way things are looking, I should have the manager working mid-week, at which point I’ll switch to working on the in-game slab uploader. Woop!

Right, that’s all from me for now.

Ciao.

Disclaimer: This DevLog is from the perspective of one developer. It doesn’t reflect everything going on with the team

[0] And also share a lot of the same code

TaleSpire Dev Log 367

2022-12-28 23:15:59 +0000

Hey again folks,

I hope you’ve had a good holiday season. I’ve finished Christmassing it up, so I am getting some work done before the close of the year.

I would have loved mac support to be wrapping up, but I’m waiting on news from Unity regarding the shader bug.

Instead, I got back to persisting initiative. I had it mostly working before Christmas, but trying to ship right before a holiday is a fool’s game, so I left it.

Today started suboptimally as the internet was down. Turns out a local distribution box[0] had frozen. Luckily the ISP was quick at getting out, so by mid-afternoon, I was back in business.

A little bug-fixing later and I have this:

initiative order persisting

Which looks pretty decent. I’ll prod it some more tomorrow and see if it’s ready to ship.

That’s all for today,

I’ll be back with more soon,

Seeya

Disclaimer: This DevLog is from the perspective of one developer. It doesn’t reflect everything going on with the team

[0] Or whatever they call them

Talespire Dev Log 366

2022-12-17 00:00:00 +0000

Heya folks!

I’m dropping in to let you know what I’ve been up to these last few days.

Hiding board list from players

I’ve done some work on the option for hiding the board list from players. I wired up the behind-the-scenes stuff and then handed it over to Ree as I was having some trouble with the UI portion.

All went well, so we expect this to be the next feature that ships.

Mac bug

In log 364, Ree talked about a bug blocking mac support and raised a ticket with Unity. I decided to spend a couple of days looking at it in case I could make a workaround. Spoiler, I couldn’t.

To trigger the bug, you have a light (which renders its volume without writing to depth buffer), and then you have something modify the depth in that area. What is extra odd is that it requires that you forward-render something for it to show up. It’s super weird. Check out this daft shit:

wat

Looking at the Metal frame trace in XCode, the most obviously wrong thing is that the GPU actions from later command-buffers seem to be executed in an earlier command encoder. I don’t know enough about Metal to work out why this is causing the errors, but it is feasible that it’s related.

Unity has confirmed the issue, so we are waiting to see what comes next.

Persisting initiative

Today I spent my time working on the code to allow us to persist data from board-wide systems. This is going well. It’s hard to write much about as it’s mainly me poking around to find something I like. I will need to make another pass on this sometime as patterns are emerging between the different managers that persist board data.

Once I’ve got this done (I’m thinking at least one more day of work), hooking up the initiative manager should be trivial. I’m currently expecting this feature to ship late next week.

And that’s ya lot

Despite the mac bug, it feels good to be making steady progress. I don’t foresee any issues with persisting the initiative list. I’ll get right on to the Mod.io slab integration as soon as that works!

I hope this finds you all well.

Peace.

Disclaimer: This DevLog is from the perspective of one developer. It doesn’t reflect everything going on with the team

TaleSpire Dev Log 365

2022-12-08 16:28:46 +0000

Heya folks!

It’s a short one today. Since the release of group-movement, I’ve taken a moment to relax. We are seeing a few crashes that we assume are group-movement related, so we’ll look into those asap.

I’ve driven east today to meet up with Ree for a catchup and the opportunity to work together in person. Our potential server/dev-op hire is also in the area, so we get to hang out and talk shop, which is lovely! [0]

My goal is to ship persistence for the initiative list and the option for GMs to hide the board list from players next week. Thanks to those server updates from earlier this week, this shouldn’t be too complicated.

And then I’ve gotta get cracking on the mod.io slab store integration. If all goes to plan, that will set us up perfectly for distributing creature mods!

Needless to say, I’m excited. Here’s to a productive run-up to Christmas!

Have a good one folks!

Disclaimer: This DevLog is from the perspective of one developer. It doesn’t reflect everything going on with the team

[0] We are still waiting on feedback from the Norwegian government on work status. Bureaucracy is a pain.

TaleSpire Dev Log 363

2022-11-28 00:30:29 +0000

Disclaimer: This DevLog is from the perspective of one developer. So it doesn’t reflect everything going on with the team

Let’s look at macOS

Work has continued at a good clip behind the scenes. I’ve got server updates ready for group move, new vertical controls, and the option to hide the board list from players.

Besides a few bug fixes, I’ve been working on support for apple silicon macs.

Apple Silicon

We have started our macOS support focusing on the new apple silicon macs as GPU feature support is spotty across older models, and the push towards the new architecture seems very strong. Steam’s hardware survey is already showing that over 49% of macs with Steam installed are apple silicon macs [1].

We are using the m1 iMac as our baseline for apple’s new lineup. If we can run well there, we can run well on the rest.

Final pre-show caveats

I remember an aphorism that goes roughly:

If you get a speedup of 100 or 1000 times, you probably didn’t start doing something smart but instead stopped doing something dumb.

While we are not seeing anything in the realm of 100 times speedups, we are looking at the “stop doing something dumb” category of fixes in this post.

“Dumb” code often arises simply from needing to implement something to discover what the feature would become. (But sometimes, it can also just be dumb)

Next, we are going to show timings in some parts of this post. While they were taken from an m1 iMac, they are intended to be purely illustrative. We are only showing timings from single frames and under specific loads. This is not a good representation of the performance in general.

With that said, we hope this is still interesting to some!

Part 1 - The start point

As I had recently been working on group movement, I decided to use some of the optimizations I had made for the lasso to improve culling for picking single creatures. This benefits all platforms.

I made a board with 600 creatures and got to work.

The picking code requires rendering the creatures into a buffer. With a mild amount of grief, we replaced the old code with one that culls the creatures and only draws the ones whose bounds intersect a ray from the camera.

This gave a 24x improvement for the code that dispatched the creature drawing for the pixel picker. It also reduces the amount of work the GPU needs to do, discarding irrelevant vertices.

Part 2 - Uploading data

Next, I had this fun one. In the image below, check out the timing differences between the green and red arrows for each platform.

The green arrows show when we start culling and dispatching render tasks to the render thread. The red arrows show when the render thread dispatches the render tasks to the GPU.

After a bunch of digging (and convincing XCode to let me profile a frame[2]), I saw that every call to ComputeBuffer.SetData was recreating the buffer. I changed the mode of the ComputeBuffer to SubUpdates, which had this effect.

Clearly, this has an effect.

However, with this setting, we can now write over data currently being used, which is not ok. So we have some work to do around here. This leads us neatly to…

Part 3 - The elephant in the room

I’ve been working heavily on speeding up CPU tasks. That’s all well and good, but the problem we really have is the time it takes to render things.

This is the scene I’ve been using for testing (ignore the graphical glitches, those are shaders that still need fixing and are unrelated to this case).

This is a lot to render. Currently, it’s taking over 25ms to do so, which is far too much. 30fps is playable, but we need to dig into how the shaders work if we hope to reach 60fps. XCode’s metal frame capture seems pretty temperamental, but I’ve got some captures we can work with.

Part 4 - Ignoring the elephant

That is not to say we shouldn’t work on the CPU side. By doing so, we can improve all platforms at once.

Given that rendering is always going to take some time, what can we do at the same time? By default, the answer in Unity seems to be “not much.” This is because their MonoBehaviours don’t expose a callback for all interesting points in a frame. However, Unity did add a low-level API to completely control the system that runs in a frame, which is terrific! [3]

With this new tool in hand, I decided to move the code that applies build changes to the data-model to just after render tasks have been pushed to the render thread.

This meant that, while we still needed to do the work, we hid it behind the work on the render thread.

Part 5 - What elephant?

While I’m pretty happy with hiding work, I was looking at this capture and thinking…

… what are these chunky jobs, and why are they taking so long?

The answer was that they are jobs that copy data from dynamic physics objects (like creatures) into the physics system before the simulation runs, and then copies the data back out afterward. The data came from managed objects, so the jobs could not be Burst compiled.

Instead, I moved this data into a native collection that our physics MonoBehaviour could index into when they needed the values. This probably makes main-thread access slightly slower, but this is not where bulk lookups happen.

This allowed for this change.

Pretty nice!

Part 6 - What next

The honest answer is “make the above work” :P

The ComputeBuffer data uploads aren’t safe, and the physics changes have some bugs. However, this feels tractable.

On the CPU side, some mesh generation code could be turned into jobs and burst compiled, which could give some notable wins. Also, creatures and dice currently take way too long to update, so I want to look into those too.

Really though, for mac, I need to look at rendering. Any improvements we can make to the shaders would be a big deal, and ideally, we would add LOD support to our batcher. I would love LODs to be a quick win, but because our code had to become so custom, this is not the case. I’ll take a look, though.

Anyhoo, that’s enough for tonight. I’ll try to post a few more dev logs this week, as I have fewer releases to do.

Peace.

[1] A huge caveat for this number is that Steam’s hardware survey is guaranteed to be biased due to the chicken-and-egg nature of gaming on mac. Without a big game market, game makers can’t afford to focus on mac, and without that focus, the market stays small. (In my opinion) Apple also doesn’t seem to care about games outside of gloating at conferences, which makes adoption harder. However, that’s a grumble for another day.

[2] No matter how long I work with XCode, it is still exhausting.

[3] You can find some ace articles about the PlayerLoop API here:

  • https://medium.com/@thebeardphantom/unity-2018-and-playerloop-5c46a12a677
  • https://www.grizzly-machine.com/entries/maximizing-the-benefit-of-c-jobs-using-unitys-new-playerloop-api
  • https://www.patreon.com/posts/unity-2018-1-16336053
Mastodon