Difference between revisions of "AI War 2:Finalizing Multiplayer"

From Arcen Wiki
Jump to navigation Jump to search
Line 1,574: Line 1,574:
 
** Total compiler errors are now down to 117, which is... insane!  I was happy just to get to three digits today, after being in the high four digits for weeks.  Now we're almost down to two digits!
 
** Total compiler errors are now down to 117, which is... insane!  I was happy just to get to three digits today, after being in the high four digits for weeks.  Now we're almost down to two digits!
  
=== Looking For Runtime Errors ===
+
=== Hunting Runtime Errors, Part 1 ===
  
 
* The last of the non-fireteam compiler errors are now fixed.  Time to get the last fireteams bits fixed up and that will be that!
 
* The last of the non-fireteam compiler errors are now fixed.  Time to get the last fireteams bits fixed up and that will be that!

Revision as of 16:17, 20 September 2021

Contents

Known Issues

  • Any bugs or requests should go to our mantis bugtracker
    • If you need to submit log files, those can generally be found under your PlayerData folder in the folder your game is installed in. The most relevant one is called ArcenDebugLog.txt. You can send us the whole thing, or just strip out relevant parts.
    • In rare cases, mainly if your entire game crashes (that almost never happens), we will need your unity player log. That gets overwritten the next time you run the game after a crash, unlike the other log. These can be found here:
      • Windows: C:\Users\username\AppData\LocalLow\Arcen Games, LLC\AIWar2\Player.log
      • macOS: ~/Library/Logs/Arcen Games, LLC/AIWar2/Player.log
      • Linux: ~/.config/unity3d/Arcen Games, LLC/AIWar2/Player.log

What Does Multiplayer Beta Mean?

Please see this link for details on multiplayer. This wound up taking up too much space in this document, so all of the multiplayer-relevant bits have been moved to the other page.

What's this phase all about?

Multiplayer is fully playable at this point, but still has a variety of glitches and doesn't have all of the features that we intend to have in the long term. So hence it still being in alpha status. But we greatly welcome folks to play, and hopefully give us reports on what is going wrong if something does go wrong.

We expect to be to a fully-polished non-beta status for multiplayer in June or July, if things continue as they have.

Our second expansion for the game, Zenith Onslaught, has a whole heck of a lot of it completed, but still needs more doing. Badger has done all of his parts for it, and has retired like Puffin before him, so at this point we are down to basically a one-person show again (me, Chris) on bugfixing, finishing multiplayer, finishing my parts of DLC2, and finishing the last of the kickstarter obligations. So if the schedule slips some, it's likely because I had trouble juggling that, or wanted extra time to make things truly shine, whichever. But at the start of this phase, things are feeling very positive.

3.700

(Not yet released -- we're still working on it!)

  • Added a new is_immune_to_reconquest_waves="true", that can be used to make it so that a given faction won't have reconquest waves launched against them (other waves are fine).
    • This is also newly applied to both flavors of dyson sphere, which is new. This should let them get a lot less hassled.
    • Thanks to easytarget for inspiring this addition, and Badger for the notes on how to quickly add it.
  • The "A Tale Of Two Stars" quickstart has been removed, because with the Dyson Sphere changes coming in this build, that scenario will no longer work. Likely there will be even more changes to Dyson Spheres over time, so it would probably just get a bit more busted with time.
    • Thanks to Puffin for reporting.

Quick Starts Data Overhaul

  • Added a new ultra-micro format for "last lobby settings" and for quickstarts.
    • This isn't really so much for performance purposes as it is for forward-compatibility purposes.
    • I'm about to absolutely revamp the entire savegame format and how a lot of data is stored for basically every faction that exists, and I want quick starts to persist past something even that drastic.
    • Why the huge revamp of data? Primarily multiplayer, but honestly this is something that will likely yield performance benefits and added correctness in single-player, too.
    • We basically never do such huge revamps of data, because we absolutely loathe breaking savegame formats, but at the moment the time for half-measures is past. So we'll do it once, and make it really count.
  • Starting to recreate all of the quickstarts. The first one recreated is now Helping Hands, which is identical in form and function to what it used to be, but now part of the micro-save format so that it will survive the upcoming purge night.
  • All of the quickstarts from the base game have been updated to the new micro-save format that will be the only thing future-compatible after this build.
  • Fixed a bug with Helping Hands 2 from The Spire Rises, where it was not working if you didn't also have DLC2 and DLC3 installed.
    • It is expected that there were other similar errors in some of the other quickstarts in DLC, but I am just fixing them all as I move them to the micro-save format, so I can't say for sure.
  • All of the The Spire Rises quickstarts are now safely in the new micro-save format.
  • All of the DLC2 quick starts are now fully recreated in the micro-save format.

Make Your Own Quickstarts!

  • makequickstart, [folder name], [quickstart name]
    • Causes a new quickstart to be saved to the quickstarts folder in the new ultra-brief quickstarts format.
    • This quickstart format is required if you want to have future-proof data that does not break with future versions of the game.
    • Example usage:
      • cmd:makequickstart,1-Basic,Helping Hands
        • This would make a replacement for the basic helping hands quickstart.
    • Please note that you need to still add a .tooltip file next to any quickstart. You'll have to do that in your filesystem on your own, but it's just an ASCII text file with narrative information inside it about what the quickstart is about. Otherwise that tooltip will come up blank.
    • When you do this process, it also gives you a note telling you which dlc and mods are going to be required for someone to play that quick start. We had lots of cases in the past of accidentally requiring more than we meant to.

Bugfixes

  • Improved the handling of DoForPlanetsParallel() so that it can't spam errors when you're exiting the game, or exiting to the main menu.
  • Put in some extra debugging in DefinePlanetFactionDefenseTypesIfNeeded(), as it could throw exceptions in some cases.
  • Fixed things up better so that any DLC can use features from any other DLC without incident, despite mods being required to have the parent DLC installed.
  • Fixed what looked to be a bug in recent versions with outguard not actually spawning. This was based on code analysis, not testing, so let us know if something is off.
  • Fixed a number of potential cross-threading issues with nomad planets using the main thread context on a background thread.
    • And some with wormhole borers, though fewer of those.
  • Discovered and marked a bug where MP clients cannot cancel hacks in progress, but have not fixed it yet.
  • Been meaning to do this for a while: multiplier_to_all_fleet_caps has been removed from the game.
    • It was previously on all turrets, set to 0.2. It was only there for historical savegame purposes, and messed with the unit cap math badly.
    • There are other modifiers in place about weapons strength or hull or shield health, and those are used in a variety of cases and we're leaving those intact and in place.
    • The ship cap one being removed means that if you have a mod that is seeding turrets, you'll want to remove this multiplier and then probably divide your number of seeded turrets by 5.
    • This should solve a number of longstanding but rare bugs that we keep seeing with the TSS and other turret-granters, but we'll see. It certainly won't hurt.
  • Fixed typo in "ADVICE: Next Steps".
    • Thanks to Ben Parrish for reporting.
  • Fixed a few grammatical errors in EncirclingSpider and IrefulMLRSCorvette descriptions.
    • Thanks to Fenrakk101 for reporting.

Rip And Tear For ExternalData

  • All savegames and quickstarts older than 3.700 are now broken in the latest beta branch, and there is now a popup message explaining that any older saves you have should be finished on the older versions.
    • This is something that was not done lightly, and we're going to keep breaking beta-branch saves for at least the rest of this week as we refactor things to run in a high-performance, MP-friendly, modder-friendly, non-error-prone way. No more half measures.
  • The StatisticsSet class, which was mostly unused except for some small bits of data that were stored in a way that was hard to get at, has been removed.
    • The actual data about offline achievements has not been in here for years, for example. As has the info about achievements won during a given specific save.
  • Our ArcenExternalDataLookup class, ArcenExternalData class, ArcenExternalDataPatternTable class, ArcenExternalSubManagedData interface, and ArcenExternalSubSubUnmanagedData interface have all been removed. ArcenExternalDataPatternImplementationBase is also gone, and all the related stuff, really.
    • The generic "let's talk about external data attached anonymously to an object" concept that has plagued this game since our earliest versions is now going away.
    • For those who have coded factions or mods, please don't stress -- the vast bulk of your content will still work once I'm done rebuilding this in a more productive and direct way.
    • The problems with the old approach (of connecting the Core and External data parts together) were many, and reflect that it was originally kind of a prototype concept that never got refactored significantly enough because we didn't want to break savegames. I've spent the last year and a half trying half-measures to work with this stuff, but now it's time to go all the way.
      • Among problems with the old method: memory leaks, bad performance, inefficient data storage and transmission, no deliniation of data that we really consider central versus data that is just needed for host-only execution, and more.
      • There were also shifting and evolving standards in use over the years, leading to better and better code over the years, but still pulling along old bad code. Everything is getting a facelift out of this.
    • Last year and earlier this year you can see a number of cases of me trying to bring this to heel in a better fashion, but it's just crossing a line now where it's way too wild.
    • My one rule is generally "don't break legacy savegames," so you know this is serious business at this point. Time to get a lot done all at once to make this worth it.
  • Old concept being removed: you can have "externaldata" which has any amount of sub-data on it, attached to various objects.
    • The precise nature of how that connection is forged is actually something that exactly zero people fully understood, and at any rate it was a very ineffective method for gathering this data. There were three levels of pooled wrappers in there, it was nasty.
    • The types of objects that could have externaldata were World, Planet, PlayerAccount (never needed that, though), Unit (this was used all the time, but then much less over time), and Faction (this is the really meaty one that tends to matter, but even this is problematic in the extreme for older factions in particular).
    • Please note that PlayerAccount is permanently losing an kind of external-data analogue, since that was never actually needed. The new network-enabled personal settings actually are much closer to what we had once thought we might do with these, and those are highly organized data that works really well.
  • A LOT of code that was dedicated to maintaining old savegame compatibility has been removed.
    • This was thousands of lines of code that made the codebase that much harder to work with.
    • This alone is going to help performance for network transfers and savegame loads, given just how many versions there have been.
  • Stripped out some of the excess of paranoid canaries that I had placed in game units a number of versions back. There are still some in there, but it's more efficient having fewer, and the reduced count will be sufficient for our purposes at this point.
  • Previously, game units could only have a maximum of 15 systems, per their savegame format. This was very very sensible in a time before loadouts, but now this is being expanded to 63 instead.
    • This allows for us to have a great number of optional systems on a unit for loadouts. We still think 63 is an absurd number, but that's the sort of buffer zone we want to be in, really.
  • Removed DoomData, which hasn't been used ever but was kept as an example bit of code for a long time.
  • In our external code, right now we have some temporary classes as bases for things that will later be split off into other files and have their data style changed around.
    • Right now the goal is just getting things compiling, but having the external factions be braindead. The places where many things will change from the root up are marked with EXTERNALDATA_TODO for now.
    • It's going to be several days at minimum before we have a truly functional build again.
    • It's worth noting that a lot of giant gaps are there right now, like faction allegiances even being off once you load. This is because the config data doesn't have a pathway to the external data at the moment.
    • At the moment, however, you CAN load up the lobby and everything there is 100% functional. It doesn't actually kick off factions after the lobby is left, but that's not the point -- the point is nicely-siloed data that we understand the boundaries of.
    • At this point, after you load a quick start or click start from the lobby, it runs part of mapgen, but most of it is disabled. You then instantly win the game, and errors spam the world.
      • Here again, this is kind of the point... it's impossible for us to reliably have known prior to now what a client would or would not have on it in MP, and everything was very messy. These errors likely were the same ones that were going to show up on a client after getting a map from the host in the recent betas, but we would not have known until testing.
      • My work tomorrow is going to be centered around building in stable and clear data bridges between Core and External: this will have to be well-organized, easy to understand at glance, not prone to memory leakage, and equally as powerful as the tools that they are replacing.
      • The idea from that point on is to start getting the most-core data linked up, that stuff which is used by every faction, or by the human or AI factions in particular. And the idea will be to separate out that which is present for everyone, and that which only the host has, and that which the host automatically shares with the client as it is dirtied.
        • After that is done, and we have the basic factions running again, then it's a matter of going faction-by-faction and converting them to this new format. How much work that will be remains to be seen, but I anticipate being done with most of that this week.
        • To be clear, this should then have covered essentially all of the major things that multiplayer is currently lacking in data transmissions, and also have improved the performance of getting to said data in a single-player context as well.
  • The old ShipStats information had data on how many ships of each sort you had killed and lost, by mark level. This was actually stored on every faction.
    • This is not very interesting data, and is very very hard to show. We're going to track and show much more interesting data, in a completely different way. So this is being removed.
    • This was the data that was "experimental" when you right-clicked the metal view. For the moment that's blank, but soon I'm going to have actual graphs.
  • Adjusted all of the ExternalData serialization to no longer have the old data for deserialization logic. This was less to remove in the main game, but still several hundred lines of code.
    • The idea is making this cleaner and easier to read since we're in the process of breaking saves anyway, and it also makes it easier for me to move forward with splitting and cutting up the data.
  • Removed some ultra old rally point code that hasn't been used since fleets were added.
  • (Almost) all of our older code and folders and such which used to say "Mercenary" or "Merc" or similar have been updated to say Outguard instead.
    • This simply makes things more clear, particularly since we've been calling them both things in code for a few years now.
    • There are still a few references to mercenaries in a few files and filenames, but it's WAY lesser now, which is nice for avoiding confusion in the future in particular.
  • Removed old features that had been retained only for really really old savegames:
    • ship_cap_multiplier_strikecraft, ship_cap_multiplier_turret, ship_cap_multiplier_frigate. These were all tied to the IGC in older versions.
      • There was a LOT of related code for this, which is all removed now, hooray.
    • The deprecated custom-flagships xml.
    • FCE xml and a bit of related code.
    • supercharges_strikecraft_ship_cap_of_rest_of_player_fleet and related code.
  • Old logic for removing AI frigates has been removed. We no longer need to deal with those savegames.
  • Removed the HostOnlyAggregatePlanning background thread, which I added a week or so ago but never wound up needing.
  • Removed some FleetFormation logic and xml that had never been used and never been tested. It was an old prototype just clogging things up minorly.

Reconstructing ExternalData Links

  • FactionCenterColor and FactionTrimColor have been removed as direct variables from the Faction class. So has FactionType Type and and SpecialFactionData SpecialFactionData.
    • In place of these, ConfigurationForFaction Config is now always permanently on the faction, and it has a direct link to this data.
    • Previously it was frustratingly common to have two copies of various pieces of configuration data, or even three, and we want to avoid that. Trying to keep that in sync serves no good purpose, versus having one place where each piece of data can be queried is very useful.
    • However, it's nice to have nice wrappers around all of these so that the same code will work as always have, so this is what we've done.
    • This may also fix a bug we've had for a while with the "subsequent faction colors not being set on factions of the same type" for some subfactions, but if not it at least makes that easier to fix in the future.
  • The "MissingFaction" is set as the default entry for the factions table so that it will automatically be chosen in cases where a faction is, well, missing. Removes the need for some code.
  • Added in some more wrapper methods for looking up custom field data for factions in a direct sense, rather than potentially getting stale data from one of the secondary places it is stored. We never want it to be the case that the UI is lying to you while having a secret separate value behind it, so this is part of that. We had accidental cases of that above-mentioned problem before.
  • ArcenSimContextBase now has an abstract AmIAHostOnlySubContext on itself, and a ShouldThisMethodBeSkippedBecauseThisMachineIsClient() direct method.
    • This lays the groundwork for us removing some of the RNG divergences that were happening in multiplayer prior to now. This also serves as a guide for how we're going to be splitting our External dlls. Honestly it's making me review all the methods and make it really clear what can do what, which is pretty darn useful to have to do right in advance of that other surgery.
    • Added a new ArcenClientOrHostSimContextCore, and ArcenSimContext and ArcenSimContextBase are getting a TON of additions and changes. Way too many to note the details of in this format.
    • Added a new ArcenHostOnlySimContext that is for the host-only sections of the game.
    • QueueLogJournalEntryToSidebar and QueueChatMessageOrCommand no longer require contexts to be passed to them (they were not using it anyhow).
    • Lots of methods now either require a ArcenHostOnlySimContext, or a ArcenClientOrHostSimContextCore.
      • It is very rare to now require a root ArcenSimContext on a primary logic method, and this is part of how we're now controlling what methods run on the client or host (which we were already doing, but more haphazardly), AND controlling which random generator is used (this is the bit that is new, which will help stop that "units go over here and then zip back over on the MP client" bug).
      • That said, ArcenSimContext is absolutely still used on all the various worker methods that are called from a variety of contexts. Aka some code that might be used in any and all shared circumstances.
      • To make things even more clear, and prevent un-examined code from upgrading into this without examination, ArcenSimContext is now called ArcenSimContextAnyStatus to denote we really mean that.
    • ILongRangePlanningContext is now ILongRangePlanningHostContext.
    • ArcenSimPlanningContext is now ArcenSimPlanningCommonCoreContext_DoNotReferenceDirectly. It should never be used directly anymore, as it's ambiguous as to whether it's on the client or the host.
      • There are now intermediate ArcenHostOnlySimPlanningContext and ArcenClientOrHostSimPlanningContext classes that inherit from it. Mostly this is a formality, but it does add clarity and keeps consistency with the rest of the code.
    • A metric ton of code has been adjusted for all of this, in some cases removing things that were passing around some form of Context that had no business doing that. These are meant to stay in some reasonable sync, and sometimes even some UI choices could cause problems.
    • Because of the way inheritance works from classes in C# (single inheritance only, interfaces aside), there are a few methods that are duplicated across a couple of central classes.
    • THAT said, this leads to less duplicated code elsewhere in end-implementation classes, AND the inheritance tree of the "context" types makes it so that people literally can't call methods from improper spots.
      • If you're a modder and you find yourself trying to work around a method call that doesn't have a compatible context type, then either you just need to call yourCurrentContext.GetHostOnlyContext() and try that, or else give up and do something else because this would be a MP sync issue or other data invalidation issues would be caused. Or let me know, and I can always look into making something more permissive. But honestly other than people forgetting they need to call .GetHostOnlyContext(), I don't expect any troubles.
    • So what's up with calling .GetHostOnlyContext()? Isn't that kind of a waste of end-coder time? Actually... no! It's super important. The host-only context is used for parts of the code that only run on the host, and it has its own separate RNG that the shared clientAndHost context does not have. This means that all of what runs on the client and host has the same number of RNG calls, yielding a deterministic result. But peppered in there are some host-only calls, which previously were breaking sync but now just require a call to .GetHostOnlyContext() and sync is preserved while still keeping the same code structure you're used to.
      • This is round one of several rounds of fixes that could also be described as idiot-proofing (where all of us are equally idiots, and not meaning that in a pejorative way). The code is now demonstrably clear about when it cares what sort of caller is around, which is a big step forward for the next round of this, which will involve splitting things between dlls in order to separate out a new client-accessible layer of data from lots of host-only code that runs against it.
        • Put another way, this is getting around the problem of having to replace tooltip appenders with calls to the host, or doing all of the notification calculation on the host and then transmitting lots of complicated data. We're instead handling this in a much more tri-layered fashion, based in general on the MCV (Model-View-Controller) design pattern.
  • DoOnSelfBuildingCompleteLogic has been moved from the scenario to the faction class, so that it's able to properly do its job. Before, this would have been a mighty big annoyance for any modders who made a new faction.
    • Same deal with DoOnInternalConstructionCompleteLogic, although nothing actually uses this one yet.
  • The "ExternalCode" project, which is the main open-source AI meat of AI War 2, has been split into two parts.
    • One part remains in the existing dll, which is the most "permissive" part.
      • Anything in this dll is stuff that we're intending the client in multiplayer to have access to. (That is a statement of design intent, but I have a lot of work to do before that part is actually fulfilled.
      • Also, anything in this part can be freely examined by the UI, on the host or the client. I mean, thread safety aside, the UI is allowed to know about these things, and these things exist on every computer in multiplayer (again, talking about design intent, not current status).
    • The new part is called "AIWarExternalDeepProcessingCode," and is meant to be only things that the host has access to. Also, the UI cannot directly query these things.
      • Right now we have moved the faction processing logic, "on death effect" code, the main mapgen code, the "hacking is happening" code, and the "long term planning" code in general.
      • Please do bear in mind! Right now there's data mixed up in many of the files that were moved, along with the logic that was moved. Some of this data is meant to be host-only, but a lot of it is not. The next job will be splitting up all of these files and restructuring how the data is found, and that goes hand in hand with also re-teaching the Core code from AI War 2 how to reach these new split-up forms of data and code.
    • Please note that all mods will be required to follow this same double-dll format, which we will be enforcing by a quick scan of your mod code as it is first loaded. More on this will be available when this conversion process is complete.
      • The goal with this structure is to make things multiplayer-safe, and separate the data from the code a bit better, and separate the host-only code a bit better from "everybody runs it" code.
  • Updated our build scripts so that when we build an external project from within visual studio, it will now properly set them into ReliableDLLStorage. Prior to this point, any compile-breaking changes needed to first be copied there by running the entire command-line build script.
  • My external code loading framework is being put to new use in terms of helping ensure data-correctness.
    • For classes that will go into deep processing or the client-safe data processing, they will all inherit from either IExternalDataAndSimCode or IExternalDeepProccessingCode.
    • The game now checks to make sure two of these same things are never in the same dll, and additionally, that no dlls that have deep processing code are referenced by any classes with DataAndSimCode in them.
    • This is really important for preventing errors that would affect multiplayer clients, among a few other maluses, and so by doing this very quick check on startup we can make sure that all of our own code, as well as any mods, all conform to the standard that prevents the most common MP-only issues from happening.
    • Put another way: if you've just coded a mod, and it works for single player, you want to be pretty darn sure that it "just works" in multiplayer without having to go test it there. It's the same with any changes we make to the core game, or in DLC. All of this code restructuring, along with these checks, are how I ensure that is the case at a very low level. If MP has a problem that is unique to it, I want that to be something that's my central problem to solve, not something that faction designers or modders are chasing on their own stuff.

Restructuring The Upwards Link From Core To External, Part 1

  • Previously, we had a thing called "ExternalDataPattern," and some of the DLC content had to be included in the base game or else beacon factions would mess up the ability to load quickstarts. And last-settings would get messed up if you disabled a DLC and went back into the lobby, too.
    • Thankfully, now we don't have this problem at all because of the new "micro save" format that is now used for those two purposes as of this build. Therefore, the new equivalents of this old sort of data are now able to be stored in each DLC properly (this has the same implications for mods, so this is a good thing for mods being usable for sure).
  • Added the following two sets of data/code pairs:
    • ExternalDataAndSimCode, which is for clients to know about and the ui to be able to see and use.
    • ExternalDeepProccessingCode, which is only for hosts and single-player, and contains all of the deeper logic and working variables and whatever else. We don't want this to accidentally get sent to a client at any time.
    • It is worth noting that the above things can have 1:1 pairs (faction data in the sim code that the ui can also see, and then deep processing for said faction), but in many other cases we don't need a faction to be involved at all, or have several sub-parts to a faction (unit data, etc), or whatever other designs we want.
    • As part of the two above sets of data/code pairs, added the following three categories:
      • World. This is something attached to the world, and it can run whatever logic you want to, kind of like a faction would have a chance to but without the faction.
        • Internally, some of the logic that we have very confusingly on "Human" right now -- there can be many human factions, and we generally want to run this stuff once for all of them -- will move here. This is also for the things that are human-faction-type agnostic.
        • Externally in mods, we expect to see the FakeExecutorFaction from AMU move into this. We should never need to have a fake faction again, as there is now a clean and fully supported method for doing that same sort of thing here.
      • Faction. This is where the meat of the game logic lives for anything that isn't just the autonomic style of unit AI.
        • Internally and externally there will be some swapping back and forth of what is loaded where, and the SpecialFactionLogic class in general will be subsumed into this.
      • Squad. This is data that goes on an actual individual ship/structure for whatever reason. Some factions are designed where this is needed, others are not.
        • Having deep processing available for individual ships is now possible, although that would be a little bit on the strange side. We have a way of handling it with efficiency, but it's an oddity for sure if you structure it that way.
    • ExternalDataPattern used to be loaded very early on in the load process, and these new ones are loaded only slightly later. Other xml will be referring to these.
    • So far, each of these is just blank slates, but they'll all have unique methods on them, and be the vessel through which most communication happens between Core and External and ExternalDeepProcessing.
      • It is worth noting that these all implement time-based pools that are incredibly direct and also centrally handled, so we can avoid the memory weak worry that was everpresent with MP clients in the past.
    • Oh, another thing to note: all of these are individual object data holders that can also contain code. None of them are singletons.
      • So for instance, if a faction defines a FactionDataA class that goes with itself, then if there are 3 instances of that faction TYPE, there will also be three instances of this faction data. This is very useful, because you can therefore store faction-specific working data in the deep processing in particular, or use static variables if you want to share across factions. This is very similar to the ethos behind ISpecialFactionImplementation, which will be leaving us before too long.
  • Experimented with a new method of serializing data for objects. The data is really really sparse, though, because of "all the things that can be on a ship," for example, usually only one or two actually are. It's much the same for faction and even world.
    • I spent a goodly while coming up with wrapper classes to manage arrays based on the length of how many external linkages there are of any given type (which is based on how many DLC and/or mods you have installed), and was going to have some sort of very high limit (so that if you run with 100 mods on, someday when there actually are 100 mods), you don't have a problem.
      • However, that has many many drawbacks, because we wind up iterating a ton of arrays that are almost universally empty, or have a single item or two in there. And there is a finite limit on the number of mods you could have, even if it is very high.
      • The other big drawback is just how long it will take to iterate all of that, and for squads we have issues of how timely we can get those data updates from the host to a client after there's some change. Also, we have some order of operations questions with things like fast blast data potentially arriving before the external data, or vice-versa. Either way, it's not a good model.
    • The solution will to take this "vertical" approach and make it horizontal, and instead serialize on-the-fly in a more centralized fashion. This keeps our amount of iteration very very low. The downside is that I then have to make it very fast to link back and forth between the data and the thing it is attached to, but that's not the worst problem in the world. I was already potentially going to have to find a row index and then index into an array and then cast to the proper type. Instead we're likely looking at a concurrent dictionary lookup, which is at least a single operation rather than multiple (admittedly cheaper) ones.
    • Well. At any rate, my code for the old vertical method is not complete and does not compile (I was in the middle of it when I had this realization). I'm checking it in in case it is ever needed in the future, though. Next step will be to convert it to the horizontal format.
  • Some rather mind-bending code for horizontally serializing and deserializing all of the external data for any world data, faction data, and squad data, all at the central faction level, has now been put in place.
    • This differs from a lot of our serialization code in that it's very... reactive... to what it finds. Essentially what happens is it iterates over every possible piece of data that can be sent (hey, macrophage ships can sometimes have data attached -- are there any in this game? If so, send those that are there). It's clearing out stale data as it goes, and as-before it gives the details of the serialization itself to the actual External code classes.
    • One of the chief differences this time around is that we don't have to serialize any table or row names -- we are using central indices that are synced from the client to the host -- and we're also using smaller ranges of integers for the PKIDs for factions and squads based on the differential between the largest and smallest ID in the particular list at any given time.
    • This will require testing once we can run the game again, to make sure that I didn't make any typos, but it uses a lot of generics and type inheritance in order to minimize code, so whatever problems are there should be of the "fix once, don't think about it again" variety.
    • At the moment, what is in the codebase is kind of impressive, but also kind of baffling. Here we have six identical tables and classes, all serialized using some very complicated code that is very centralized... but there's nothing different about any of these classes or tables. They're all super identical.
    • Where the magic really is going to come from is the fact that we can have all manner of different methods on each of those distinct six classes, and so we can set, retrieve, and manipulate data without having to do any type casting at all.
    • This a much more elegant solution than the old solution we had, but it strays slightly close to "clever code" (the sort of thing that is showing off for no reason, and thus is super hard to maintain and nobody else can read it).
      • That said, the reasons for this solutions design are pretty clear: keeping the guard rails on, not mis-identifying data (often happened before during load issues), minimal steps to get from Core to External, the ability to have lots and lots of very direct methods that we can can directly call, and pooling that is NOT in the hands of the External programmers, but instead is controlled by Core. There's also a goal for having substantially less code, and substantially clearer code, on the External side. That will start becoming evident tomorrow as I start wiring this up to them. On the Core side it takes some extra complexity in order to create more simplicity on the External side.
    • That's the idea, anyhow. I have long considered myself a code architect in terms of programming sub-specialties, and I've done a few dozen refactors of major programs, ranging between languages and business software and games. This one has so far been, to my surprise, the most complicated one I've had to do. There's a lot of pleasure in that, but at the same time: wow complex.
    • The main good news from today is that there is really a small amount of code (all things considered) where I could have made mistakes. So once I start this up, after connecting to the External code where I CAN start this up, any errors should make themselves apparent immediately and then be gone forever.
      • The old way of doing things was something I was never able to wrap my brain completely around because it had three layers of indirection that also required bidirectional communication and reading of the code. In other words, to understand that code, you had to read the entire path of it from Universal, through Core, all the way to External, and then follow a further chain back down the other direction. That was... code that worked, but was very very hard to be sure was not secretly broken. It had some arrays of objects in the middle, hitting the GC in a way I didn't like, and it was particularly hard to tell what it was doing o =n MP clients.
      • But the new code? It flows one direction, you can follow it clearly, there's no GC hits in the middle, and despite the code being a little bit odd syntactically (generics really can look odd), it's fairly straightforward to follow.
    • Tomorrow will be the real test, where I start wiring up the various pieces of External code to these new pieces, get them compiling again, and then eventually transform it all into the simplest possible version of itself that will be as error-free as possible in MP and SP as we want. It won't all happen in one go, likely, and I expect several more major refactoring passes next week to clear up various perennial bugbears like linked factions, the strange combined fleets/cities of the fallen spire, the odd (and not architecturally wise) way we have "faction common data" and similar structural oddities that make some of the externaldata have a larger learning curve than we'd prefer. Hopefully we have a working SP game this weekend, and hopefully we have a refactor-complete game by next weekend. We'll see how quickly things move tomorrow.

Restructuring The Upwards Link From Core To External, Part 2

  • Okay, all that "clever" code yesterday? I said in my release notes that it was pushing the edge of being too clever for its own good (when programmers of a certain experience start talking about how "clever" code is, it's not a compliment -- if a professor tells you your code is clever, that's a compliment, but if a colleague does, they are worried about ever having to maintain it. Smart and cool and elegant are always compliments.).
    • The code was indeed the simplest possible implementation with the least amount of code for doing the sort of many-to-many relationships that I was assuming some of our data might have. But thankfully, no actual data is structured that way.
    • The old code that we used to have was allowing for many-to-many relationships between many kinds of objects and data, but thankfully everyone was sensible in both internal and mod code, and instead what we wound up with was a lot of one-to-one code. THIS ship has THAT data and no other, etc.
    • So! After talking to the folks who have been working on the bigger mods and the external factions and verifying that my sudden suspicion was correct, that means it was time to strip out pretty much most of the work I did yesterday (sigh, but it was a good intellectual exercise I suppose) and implement something new.
    • This new approach treats all of the World data as being singletons (aka only one copy of that external object, ever, period), and it even queries them "hey, you want in on this?" to which they can contextually say yes or no.
      • This is super duper useful, because you could actually have some sort of helper code turn itself on for a while to manage some process in the game, and then relieve itself of duty and stop using any bandwidth or CPU cycles. Or it could start out as off, but turn itself on once some situation happens, etc. Handy!
      • In general, one of the larger problems with external data assignments like this is "when do they get attached, and how do we know to do it?" In the past, a lot of that was "when ships are created in externaldata, we'll assign it contextually then, and hope we miss no cases. If found we did, then backfill." We may keep to that, but will also try to formalize it a bit. But for the world, simply asking the objects "you want in, or you good sitting out for the moment?" is feasible as well as most performant in this instance.
    • Factions and squads are still pooled, and so a lot of what was done yesterday (the easy parts) still apply for these.
  • Map generation code is now flagged as deep processing, so it will be disallowed from being in any dll with the base data and sim code.
  • ISpecialFactionImplementation, which has for so many years been the absolute centerpiece of faction and AI code, has been removed from the game.
    • It's functions are now being split between base-data-and-sim faction code, and deep-processing faction code objects, which has been one of the chief aims from the start of this rework.
    • There is no longer an "Implementation" object on the faction at all. Instead, there is now a "BaseInfo" and a "DeepInfo."
      • These objects serialize data to disk (like externaldata used to), as well as contain whatever logic we want them to. That's not quite an MVC philosophy, but it's following a similar and useful OOP design.
        • It's worth noting that the deep info ONLY ever serializes to disk, and never across the network to MP clients. It's also worth noting that the UI should not be trying to get any data out of the deep data unless it's purely for literal debugging purposes.
  • For the first time, squads themselves now also have a BaseInfo and a DeepInfo, which mirrors what you're used to with the factions.
    • This doesn't replace anything on the "big logic processor side," but will probably fold in things like "description appenders" later. However, this replaces the notion of ExternalData that used to exist.
    • It's worth noting that this external data is no longer a collection of things, unlike before. There's only a single item attached to each squad, or zero items attached to it (if it's not some special faction other than humans or the AI, it's probably zero items).
    • Before we had a many-to-many relationship, but that was hyper inefficient and something you are better off handling with data at the faction or even world. There are no known cases of any internal or mod code actually needing that, though.
  • Added ParallelDoForAllActiveEntries() onto TimeBasedPool, which gives us a comparably-quick way of doing some action VERY completely against all live objects in that pool.
    • Quick is a relative term in this one, but it is multithreaded, at least. This shouldn't be used in most cases for during-game things, but rather is for times like "when we reload all the xml" or things like that.
    • We also added a ParallelDoForAllEntriesEverEvenInactive, since that actually seemed kind of warranted for the xml case.
  • GameProgramIsAboutToReloadExternalXmlAndSimilar() is now a thing that exists on all the external objects, rather than being limited to the faction data.
    • This is mainly as a courtesy to mods that may have different structures from our code. We don't actually use it, but it's useful as a thing that can be called for those that do.
  • ExternalDataExports is now functional again, and lets us dump out all of the new-style external data.
  • Everything that was called "ExternalXDataAndSimCode" is now called "ExternalXBaseInfo"
    • This is a lot easier to type, and is way easier to read at a glance.
  • Everything that was called "ExternalXDeepProccessingCode" is now called "ExternalXDeepInfo"
    • Again easier to type and read.
  • There was also kind of an awkward convention between the tables and rows describing the external data, and the external data itself.
    • That has now been clarified into the tables and rows being called "InfoSources", while the actual things themselves are "Info." Logical and straightforward at a glance.
  • Faction xml (aka from the SpecialFaction folder) no longer wants or accepts a dll_name and type_name.
    • Instead, it now requires a base_info_source (referring to an entry from ExternalFactionBaseInfoSourceTable).
    • And then also a deep_info_source (that refers to ExternalFactionDeepInfoSourceTable).
  • Squad xml now has the OPTION of specifying base_info_source or deep_info_source as a way of automatically attaching these types of external data to all entities of the type in question.
    • This is actually a really clean way to handle things, and then the data can be populated later by the external code as desired. Nobody HAS to use this, but it can be a nice thing.
    • Do note that this IS inherited via copy_from, so if you are copying a ship that happens to have base_info_source set, then on any that are being copied for use without that, you need to set base_info_source="None" on any direct children to blank that back out.
  • Actually, it looks like the DescriptionAppenders and the AlternativeMoveOrderHandlers, and the EntitySpecialPerSecondLogic all can just stay as they are.
    • They are being flagged as IExternalBaseInfo so that they have to go into that dll rather than the deep dll (otherwise these would all break on MP clients), but that's about it.
    • These are a great example of something that can just stay flexible (no need for a rigid structure here), but now have a proper place to live that also guarantees what data access they have access to. Previously, these things would maybe work or maybe not work on MP clients, depending on the status of things. But generally trending towards not working. Now they can be verified to function just by testing them in single player, since they're in the dll where clients also get access to all the info.
  • At this point, the Core dll has had all of the changes made to it that are required in order to handle the upwards-facing communications that the Core dll has with External code.
    • This means that the work of actually translating over the External dlls can now begin, and some things can be redone in passes, but not all things have to be.

Restructuring External Base Info, Part 1

  • Started the process of transitioning some data from the Deep dll into the Base dll, with the idea being to separate out the running of things from the actual viewing of data related to those things.
    • Also, of course, wanting to isolate the sort of background and working data off in Deep away from the UI and any temptation to try to show that data, which would be explosive on the MP client and just a bad idea on single player or the host.
    • Moving over HunterFleetBudgetType and its related stuff is straightforward enough, and matches with the sort of thing I have in mind. That's just a copy-paste job, and hey I'll make new files for these for easier location of them in the future.
    • Then I turned my attention to HunterFleetType, and immediately hit a hard stop: it has something on it called IHunterFleetTypeImplementation Implementation, which defines both data (Base type) and logic (Deep type).
      • This is a bit of a conundrum, but not a crisis. Ultimately this mirrors the same sort of setup that I have going on in Core, and I'll need to split these things out in some fashion.
      • Right now my brain is feeling quite tired, so maybe I'll wait a bit on that problem, but essentially this is where we get to the "dream within a dream" level of inception, and this is actually more important than it might look on the surface.
        • First of all, modders and general faction designers need to be able to create new data tables in a subordinate fashion like this, and there needs to be a really central way of handling it. I can't idiot-proof it like I can with things coming out of Core, specifically because as the "dreamer" of the first dream, the modder/faction-coder has full control over how they structure their inner dream within a dream. That's both neccessary, and something I don't want to take away.
        • This actually does get at the generalized need to formalize that as much as I can, however. I can't make it idiot-proof, but I can give the proper tools to standardize dreams within dreams (going with that metaphor), AND also to make sure that they serialize in a way that does not cause a memory leak on MP clients. It's this last part that is the most challenging, and if I could make that one part idiot-proof, that would make me very happy. That's the one bit of power (accidental memory leaks) I'd like to take away from the dreamers in the top level dream.
        • Further compounding this is that I might actually need to support more depth, aka dreams within dreams within dreams -- three levels, or even four, or some arbitrary recursive number. I sure hope no-one has structured their data like that, but I guess we'll be finding out. First, though, I'm going to take a break and focus on some other compiler issues that need to get sorted out anyway.
    • Overall when it comes to looking at this, I have factions and squads which presently have a very similar -- but slightly different way of serializing. The faction MUST always have both Base and Deep info, and it serializes with that in mind. The squad may or may not have Base or Deep in any combination or none at all, and it serializes with THAT in mind.
      • The world, meanwhile, can have a great many base and deep infos attached to itself, but they are all singletons and are also all loosely, voluntarily attached.
      • The question will mainly be if I can formalize these relationships in a generic and encapsulated format that can be attached to arbitrary objects. The huntertype seems to be a singleton processor-type class, and the other classes that I've run into are similar.
  • Added a new ArcenLongTermIntermittentPlanningContextBase in the BaseInfo dll.
    • This is going to be used in some of our "dream within a dream" data management cases.
  • Fireteams have been partially moved into the BaseInfo dll, but parts of their code is clearly DeepInfo code.
    • That has been commented-out for now, and will be grafted back on in the DeepInfo dll once we can compile BaseInfo again.
    • Additionally, FireteamUtility has been split into one part that is FireteamBaseUtility that can run anywhere, and then the other part that stays behind in DeepInfo.
  • In Universal, split up the interfaces that contribute to the external BaseInfo and DeepInfo so that we can have ones that are singletons and ones that are multiples properly denoted.
  • All thirty-seven "Decription appenders" have been moved from their files in the DeepInfo dll into their own individual files inside the BaseInfo dll.
    • There were two old description appenders (hacker and science) that were not used and thus have been removed.
  • All of the IAlternativeMoveOrderHandlers have been moved from their files in the DeepInfo dll into their own individual files inside the BaseInfo dll. There was only one.
    • In recent versions of multiplayer, clients were not going to be able to order spire relics around. Nice that we're doing this overhaul, as that was not on my radar and would have been a huge pain...
  • FrenzyFleets from the nanocaust have been removed, as fireteams have far far replaced those.
  • FactionUtilityMethods has been partially moved into the BaseInfo dll, and it is now a singleton rather than a static class.
    • Thanks to it being a singleton, this means that we can also add extension methods in the DeepInfo dll and not have to worry about having two classes with similar names that we wonder which item is on which.
  • The "SpecialForces" faction has been fully renamed to Warden in the code. It was old legacy naming from 2018 or prior, and getting rid of that makes things a lot more readable.
  • EntitySimLogic has been split into EntitySimLogicBaseInfo and EntitySimLogicDeepInfo.
  • Moved over the bulk of the data that should be in BaseInfo rather than in DeepInfo.
    • There's still more that needs to come over, but it's part of larger classes that will need to be split.
    • At the moment, I've still got a lot of things commented out or using fake connections to mimic the old style. It's not functional, but it's hitting the point where I can compile again and thus move towards getting it working.
  • A variety of new methods have been added to FactionUtilityMethods to make checking for faction types easier and more reliable.
  • Current status: lots of things are moved around to be in a better spot, but a lot more work needs to be done.
    • There's still a lot of temporary code linking to the old style of doing things so that we can compile the main ExternalData dll (the base info one). That actually does compile now! But it's not linked up yet, and won't function yet.
    • The new deep info dll doesn't compile yet, and will require a lot more splitting of data into multiple classes before it does.
    • There are still some things that need to move one direction or the other, and then other things that need to be moved around or restructured so that data is grouped properly and can be accessed properly.
    • This is... quite a bit more tangled-up than I had expected, to be honest. But this is a really super good thing to be doing, and if this past week is any guide, it should be less than a week of work left to get this functional again.

Reconnecting External BaseInfo to Core, Part 1

  • There was a "does nothing, but helps things compile" set of code that we had in the ExternalData (BaseInfo) dll since making the intial rip and tear changes to ExternalData as a whole.
    • This code has now been removed, which creates hundreds of errors but allows us to start replacing those hooks with new ones. Doing a massive code shift like this is an iterative process, and sometimes you just need "somewhere to plug things in for a bit so you can work on another part," if you think of it like working on a physical piece of machinery.
  • The base and deep infos on factions are automatically created just like those ISpecialFactionImplemenations used to be, so that's not something that you ever have to worry about creating as an end programmer/modder in this game.
    • Similarly, the ones for the world are created as singletons and are never really attached to the world. The world just asks your code "hey, you can see what's up, do you want to run?" And if you say yes, then the world will run your code and serialize it, etc.
    • On the other hand, squads are a bit different. Historically we have added things to them as we went, as we wanted to, but that doesn't mean we can't centralize some of it. There are two modes of operation for the squad, therefore:
      • If you specify the xml for it, then it will automatically add them when the squad is created. This is not a bad idea! But this does assume that every unit of that type EVER will have this external data, and there are potentially cases where that is not true.
      • For those sorts of conditional cases, you can instead manually call CreateExternalBaseInfo() or CreateExternalDeepInfo() on a squad, and pass in the type of data you want it to initialize for you.
        • If this is already initialized to something else, then it will throw an error, since that is in fact an error and you need to take a look at what's going on.
        • If, however, this is already initialized to the same type you just asked for, then it just returns the existing item it has. Basically if there are cases where we might accidentally call the same method here more than once with the same code on it, then this doesn't hurt anything with the extra calls.
  • Okay, here's a description of the pattern for changing things over from the old format to the new. This is mainly for modders to know, but also anyone working on the codebase it's useful to see.
    • We previously stored Wormhole Invasion Data (which goes on a squad) like this:
      • WormholeInvasionDataExternal was the outer wrapper that inherited from ArcenExternalDataPatternImplementationBase_Squad.
        • Structurally, this was clunky code, and very rarely had actual data of its own in there (in terms of general ExternalData for whatever function). There's no real analogue for this anymore in the new system.
        • IF you were doing the extremely old-school thing (for our codebase) of storing multiple sub-objects in here, you will have to choose one to become your new primary BaseInfo, and all the others will be sub-objects of that. Easy-peasy.
      • ExtensionMethodsFor_WormholeInvasionDataExternal was an optional (but always-used) convention that made it easier to get the wormhole invasion data sub-ojects from externaldata.
        • Structurally this was also a bit of a pain, even though it wasn't much code. A small typo, and dealing with the annoying patternindex (which no longer exists) could really foul things up. We can safely remove this, also.
        • If you really want some extension methods for THAT easy of access to BaseInfo or DeepInfo in the new system... then honestly instead maybe think about just how frequently you're calling such methods, and instead call it fewer times and pass the result around. Player CPUs will thank you.
      • Finally we come to the actual meat, which in this case was WormholeInvasionData, which inherited from ArcenExternalSubManagedData (which no longer exists). This is what will become BaseInfo.
        • The reason that this is BaseInfo instead of DeepInfo is that this is information that both the client and the host might like to see, in terms of it affecting the UI for both of them. In the event that there are some parts that are truly host-only, and never get shown on the ui except for maybe debugging purposes, then consider moving it to DeepInfo in a separate class IF it's substantial enough data to actually care about (why tell the client about things it never cares about?).
        • This class is now going to inherit from ExternalSquadBaseInfo, since this is what it is (base info, squad-attached). Let's talk about what THAT means separately, in a moment.
    • In terms of translating things over, for this type of data this is all you need to know from a bird's view.
  • So now let's talk about details of what it means to handle this ExternalSquadBaseInfo, starting with WormholeInvasionData -- which let's rename to WormholeInvasionBaseInfo.
    • Trust me, it's worth it to rename this just to save yourself confusion later. Remember to do a global search and replace from old name to new name in both the BaseInfo and DeepInfo dlls (the DeepInfo almost always acts on BaseInfo).
    • Now that we have this class inheriting from ExternalSquadBaseInfo instead of ArcenExternalSubManagedData, there are some immediate things to change. (This will be identical for DeepInfo, and for faction and world data.)
      • DeserializeIntoSelf and SerializeTo both no longer are passed a SerializationCommandType SerializationType, so you can just remove those and those methods will then be happy. You can probably just run a global replace in your BaseInfo dll for ", SerializationCommandType SerializationType" and replace it with nothing and it will save you time (we had 226 instances that were replaced in our own innternal BaseInfo code).
      • We need to implement the base method Cleanup, which gets called whenever an object is being pulled back out of the pool.
        • This may or may not be important to actually fill, depending on your class. If you were previously setting some values in the constructor, and your code always expects that to be the starting state, then you should probably move that initialization code to Cleanup and have your constructor also call Cleanup(). You'll note that this is what we've done with WormholeInvasionBaseInfo.
    • At this point we have translated things over such that they CAN connect up, but there isn't an actual linkage being created yet. It's time to address that.
  • Since we did a global search and replace in both projects, we can search for WormholeInvasionBaseInfo in both the BaseInfo and DeepInfo dlls.
    • In our case, there are no other references to this in BaseInfo -- that's just where the data is stored. (This is temporary and wrong, actually! We're going to move the notifiers over to BaseInfo to save processing and data, so later that will actually be there).
    • At any rate, there are two ways we might want to use this data now. We might want to get a reference to it, to change it or just write about it.
      • Previously that would have been done with the GetWormholeInvasionBaseInfo() extension method, or something similar.
      • Now this is done by calling GetExternalBaseInfoAs<WormholeInvasionBaseInfo>() on the squad, which will give you back a WormholeInvasionBaseInfo that already exists or give you an error. For DeepInfo, you can call GetExternalDeepInfoAs<YourTypeHere>(), and it works the same.
      • It is worth noting that if the base or deep info here is null, then these will just return null, so your end code should be prepared to handle that if you think that might be a possibility. In the past, most of the time our code just returned a new instance of the data type, which... well, that could have hid a LOT of code errors. We have no way of knowing. If someone calls these things on the wrong kinds of unit/squad/structure, we actually do want this to error, because that is almost certainly a logic error that then would lead to strange behavior. It's possible we will find some "new" bugs that are actually existing ones that had been hiding, in the coming weeks. This in turn would likely fix a lot of other rare bugs that were downstream from this problem, if that's actually something that happens.
    • In the old code, after changing some data, you'd MAYBE have to call SetWormholeInvasionBaseInfo(). There is no longer any such analogue.
      • Technically in the old code, this was not required for this particular class. But if you were using certain kinds of data, in certain situations, it was VERY much required. So end-coders wound up just calling it uselessly after making any changes in general, and thankfully now that's not a thing anymore.
    • Lastly (though technically firstly), there's the creation of this data. This would, presumably, happen when the squad itself is actually created, and in practice that is what the code does.
      • This can be handled two ways.
        • Option 1: You can set it up so that all of the units with the "ExogalacticWormhole" tag have this data linked via the new xml tabs, since that's apparently the criteria we're using.
          • Pros: the xml will be nice and clear about what is linked, and there's no code path where you might accidentally forget to add it.
          • Cons: properly transferring the existing code to hit all the proper entities is slightly tedious, and also introduces the possiblity, of errors.
        • Option 2: You can take what was a call to GetWormholeInvasionBaseInfo( ExternalDataRetrieval.CreateIfNotFound ) and turn that into a call to CreateExternalBaseInfo<WormholeInvasionBaseInfo>( "WormholeInvasionBaseInfo" ).
          • Pros: this keeps the same structure we had before, so there's fewer errors of short term errors in conversion. Requires no xml work. Can be used to add BaseInfo data onto units in a conditional manner -- for instance, usually just when they belong to a specific faction.
          • Cons: in general, if you forget to do this on all possible code paths that are expected to lead to the result you want, then the game is going to have new errors popping up where it used to not have that. In the vast majority of internal cases, there's only one central method that creates these things in the first place, so that's usually less of a risk, but sometimes a consideration.
      • Before anyone asks: yes, you CAN handle it "both ways." It won't complain if it already has the type you're asking to create. It will just return the type that is already there.
      • Also worth a thought: there isn't any sort of initialization callback on these right now, so if there's linkages you need to make on setup, you're going to need to at the very least call the GetExternalBaseInfoAs<WormholeInvasionBaseInfo>() method and then assign some stuff. So this again creates as situation where you must be sure to always catch every possible code path that could generate this sort of entity, though we may work on solving that in a couple of ways in the very near future. Probably before this build is out.
    • Okay, now that the process is outlined, it's time for me to repeat this another few hundred times on the main game code.
  • Previously, there was some information stored on every faction. To get at this data, you would have to call GetCommonExternal() on the faction object.
    • This data has moved onto the BaseInfo object for factions in general, in Core.
    • There is a new IPlanetPathfinder in Core, which lets us handle a lot of this centrally now.
  • Made some updates to methods in FactionUtilityMethods to use a more efficient way of finding the highest AI difficulty in various situations.
    • Also got rid of some duplicative methods of this from MapGen_Base.
  • SpecialFaction_Human had a lot of random stuff on it that is moving elsewhere:
    • The audio cue suppression stuff, which was complex but is only really used for the king unit being damaged, has been moved to nonsim in the base game.
      • This is local data for a client or a host, and we don't use this in such a way that it warrants nearly the intensity it is generating.
      • Similarly, the data from HostOnlyAudioTracking has moved onto the planet itself and is no longer host-only (that was an error on my part a week or two ago).
      • The function is identical to before, but it's now far less code.
    • GetMaxPossibleStrengthOfAllHumanFlagships() has moved to a new StrengthHelper class in Core.
    • GetPathingModeForLocalPlayer() has moved to a new PathingHelper in External (BaseInfo).
      • Similarly, a bunch of stuff like InnerFindPath_Raw(), InnerFindPath_RawSinglePathfinder(), FindPathFreshOrFromCache(), and FindPathFreshOrFromCache_ShortTermPlanningOnly() moved to that PathingHelper out of BaseFaction.
  • Also previously, there used to be a ExternalData_MinorFactionCommon.Primitives, which you could get from most factions via calling Ex_MinorFactionCommon_GetPrimitives().
    • This is now gone as well, with SOME of its data wrapped into the BaseInfo root just like what we did with the CommonExternal stuff.
    • The rest of this data is currently sitting (as of this writing) in a Temp.Historical class, and will have to be properly distributed to various classes that actually need this information. Right now there's a lot of junk in there that is not used at all, and a bunch of stuff that is faction-specific in a way that doesn't need to be central (the HRF intensity is not needed on every faction in the game, etc).
    • One thing that is moving is the Intensity being directly on any faction. This should instead be per-faction where needed (AIs don't use this, they use AIDifficulty, same with Wardens and Hunter and PG, for instance, and many others use nothing at all).
      • Instead, when trying to quickly get the intensity for a faction in general, which before was Ex_MinorFactionCommon_GetPrimitives( ExternalDataRetrieval.CreateIfNotFound ).Intensity, the code that should be called instead is BaseInfo.GetDifficultyOrdinal_OrNegativeOneIfNotRelevant(). This was by far the most common usage of primitives.
    • Actually, for the moment nothing has moved data-wise from here! The Allegiance field would be the one to move, but for now I've implemented a string get-only property called Allegiance on BaseInfo, which is just a wrapper around calling directly into the config file on the attached faction. This is getting back to (from last week) only having one copy of certain data.
    • HasPlayerGainedIntel has been removed, as there is a HasBeenSeenByPlayer on the core faction object now. This was only used by the devourer golem for one notification, anyhow. That now uses DoOnFirstSightingOfFactionByPlayer(), which was added long after the devourer golem faction was coded.
    • TotalMetalMetabolized has also been moved to the roof faction object in Core.
  • Got rid of an old GetFactionIntensity() method from Scenario_BaseScenario. The proper code is now BaseInfo.GetDifficultyOrdinal_OrNegativeOneIfNotRelevant().
    • There was a pretty large bug in there that returned -1 for the intensity of any faction that actually used the central intensity settings (aka not AI or its subfactions).
    • This was causing achievements to not fire for beating other factions in general, or at least it should have been doing that.
  • The "SpawnAnimationData" and "DespawnAnimationData" data classes have been entirely removed.
    • This was vaguely like the despawn info, which the game DOES use, but it was not actually ever data that was used!
    • It's vaguely possible that a few parts of this were actually functional, but it's honestly very hard to tell. If that turns out to be the case, then we'll have to implement that as more centralized data. The way it was handled before was super confusing.
  • The "InstigatorData" faction info is our first example of a faction that needs to be converted to have BaseInfo and DeepInfo.
    • The SpecialFaction_Instigators class would be the basis of the DeepInfo, while the InstigatorData that inherits from ArcenExternalSubManagedData is the basis of our BaseInfo, but really we're going to be pulling both code and data from both of these for our new setup.
    • First off, let's rename "InstigatorData" to instead be InstigatorFactionBaseInfo.
    • Next we need to implement the Cleanup() method in the exact same fashion that we had for the squad baseinfo.
    • Also, because there is some wrapper data also being saved, you must rename DeserializeIntoSelf to DeserializeFactionIntoSelf, and SerializeTo into SerializeFactionTo.
    • IF you have any usage of ModdableGameCommandExecution() on your old SpecialFaction class, then you should port that over.
    • Again, IF you have any usage of DoOnSpecialEvent_OnMainThread_ClientOrHost() on your old SpecialFaction class, then port that over here.
    • You must implement GetDifficultyOrdinal_OrNegativeOneIfNotRelevant() now, even if that's just to return a -1. Ideally you would return a number between 1 and 10, unless your faction has no concept of a difficulty level (or intensity) associated with itself.
      • This method no longer has a faction object passed in. Use the AttachedFaction property to know what faction you're talking about.
      • This method was widely incorrect in the prior version of the game, so this should fix bugs like the "OnLoad: AI faction: X had a difficulty of -1, which is not helpful for setting overlord difficulty level."
      • Instigators are a great example of one with nothing like that.
    • IF you need a nonstandard implementation of FindPathFreshOrFromCache(), then be sure to migrate that over from your old SpecialFaction class. We use this on the hunter, warden, and similar, but not much else.
    • IF you used DoPerSimStepLogic_OnMainThreadAndPartOfSim_ClientAndHost in your SpecialFaction class, then move that over. Otherwise ignore.
      • Same with DoOnPerSecondWhilePausedNonSimUpdates_OnMainThread if you use it.
      • Also DoOnLocalStartNonSimUpdates_OnMainThread if you use it.
      • And WriteTextToSecondLineOfLeftSidebarInLobby if you need something beyond the defaults.
      • And GetShouldAttackNormallyExcludedTarget() if you use it.
      • And finally, SetStartingFactionRelationships() if you deviate from the defaults, which is the most likely out of this list.
    • Whew, that's everything. A lot of stuff had to be adjusted in order to get this first one working, but now future ones are pretty straightforward.
  • Removed GroupTargetSorting (it's some random ExternalData), since that is not in use. It was some very legacy vestigial code from pre-pivot.
  • Status time: at this point "all" that's left for the BaseInfo dll is to translate the remaining faction and squad data over. If there's any world data we run into during that process, that will also need to be ported over.
    • After that, there's going to be a needed conversion for all of the SpecialFaction_Whatever data from DeepInfo, but that is going to be a way more direct item to tackle.
    • Also todo is to move notifications back into BaseInfo where the client can generate them all, and turn back on a lot of things that were disabled for being-able-to-compile purposes when the data was not all in the correct place.
      • Some of that will then also probably involve moving some data from DeepInfo classes to their BaseInfo counterparts.
    • This is probably another 2-3 days of work. After that I can run this for the first time and see how badly things are broken. Hopefully that is less than one day's further work of fixing, and then we're back to actually having beta releases. That would put us at Friday, if the general estimate here holds.
    • I did previously have a worry about data-within-data, but most of that is (knock on wood) not an issue. There are still some interfaces in a few spots where a Base class wants to call a Deep class, thanks to SurrogateTables (this is things like the Warden Difficulty, etc). I don't have a firm solution for that yet, but at worst I can use the surrogate table itself to manage that. It's also possible that this form of nesting might not be problematic in the first place.

Reconnecting External BaseInfo to Core, Part 2

  • There are now GetExternalBaseInfoAs() and GetExternalDeepInfoAs methods on the faction, to mirror those that are on the squad.
    • This helps us have a more orderly error if something goes wrong, and it also allows for the code to look that much more consistent, too.
    • It's fine to talk about the BaseInfo or DeepInfo directly on a faction, and if you want to then cast that to a specific implementation type that can also be done. But if you need to move from the base implementation to the specific implementation, the most robust way that errors would be reported is by calling these methods.
  • LazyLoadSquadWrapper and SquadWrapper have both been updated to hide more of their internals, and thus have fewer bits of confusion.
    • Because these are structs, there's definite risk of confusion on the part of some end programmers, but now there is not. There is also now a Clear() method on both.
    • Related, also removed the SquadPrimaryKeyID_Neg1ToPos serialization variants. People should instead use SquadPrimaryKeyID_PosDef0.
      • In all cases a squad ID of 0 means null, and anything less than 0 will be saved as 0.
    • There are REALLY some notable cases in the external data that need to be using these two structs, specifically because without that the usage of ship pooling might cause some very strange artifacts.
  • Fixed up a whole lot of references in the UI to be properly matched to the new format.
  • Faction BaseInfo now has a virtual AppendStateForDebugDisplay() method, which does a much more efficient version of what GetAstroTrainsStateForDisplay() and similar used to do.
  • All of the external base and deep infos now have a AppendStateForInterfaceDisplay() virtual method on them, and they both seal the ToString() method, fill it with an error, and mark it as obsolete.
    • The idea is that we should never be calling ToString(), as that's confusing and wasteful on the GC. Instead, we pass in a buffer in an ordered fashion.
    • The fact that it is now sealed and obsolete will in both cases help us automatically convert older code to the newer format, since rather than it being invisible (that was one problem before) it is now a compiler error.
  • Updated the following squad data into the ExternalSquadBaseInfo format, usually with a rename on top of that:
    • AIReservesPerUnitData is now AIReservesPerUnitBaseInfo
    • NebulaGuardiansPerUnitData is now NebulaGuardiansPerUnitBaseInfo
    • AstroTrainsPerDepotData is now AstroTrainsPerDepotBaseInfo
      • AstroTrainData has been renamed to AstroTrainBehaviorType. If you didn't already know what this was (I did not), it was incomprehensible in the code until you looked in the xml.
      • Fixed a minor issue with TrainsSpawned being serialized twice.
    • AstroTrainsGuardData is now AstroTrainsPerTrainGuardUnitBaseInfo
      • This now uses a LazyLoadSquadWrapper and also uses better serialization. This should solve several rare issues, and is also slightly more efficient during gameplay.
  • Updated the following faction data into the ExternalFactionBaseInfo format, usually with a rename and some movement of functions from the old SpecialFaction class.
    • AIReservesData is now AIReservesFactionBaseInfo
    • NebulaGuardiansGlobalData is now NebulaGuardiansFactionBaseInfo
      • Fixed some pooling issues.
    • AstroTrainsGlobalData is now AstroTrainsFactionBaseInfo
      • A variety of data has been ported over from the SpecialFaction, and part of that also involved decoupling some of the settings data from the loading of xml. It was messy and prone to potential errors the other way.
  • ExoData is... an interesting challenge. This is technically first-level faction subdata, but just something that can be run from a variety of different facions.
    • I don't think that pooling these would give us any notable benefit, so instead these should really just become... a secondary data structure that the game doesn't manage at all, and that is a readonly variable on the faction classes in question. That keeps them implicitly pooled with those factions (there are X ExoData classes if there are X faction classes in pools that have ExoData on them as a readonly property (readonly means the root object can't be reassigned; the data inside it can be changed all day long).
    • In other words, the best way to think about this as if it were just directly data on the faction objects. But of course, we don't want to LITERALLY do that, because then we're repeating code, so instead we have a readonly object that has the fields insde it. Handy!
    • The actual TLDR of this is that it's a challenging concept for a moment, but then has a deceptively simple solution. Hooray.
  • Added a new DoGeneralAggregationsPausedOrUnpaused() virtual method on faction BaseInfo.
    • The idea is that there's various lookup information we might need to use from the front-end and the DeepInfo, and this is data that we can simply aggregate from other existing data.
    • This should be done asap on load to make sure the UI is correct from the start. Therefore, we call it right after we call DoOnLocalStartNonSimUpdates_OnMainThread, which is another vritual method you may or may not have a use for.
    • This also needs to stay up to the second accurate even when the game is paued, so it gets called right BEFORE we call DoOnPerSecondWhilePausedNonSimUpdates_OnMainThread() (so that method can use its results if need be).
    • Finally, this also needs to be up-to-the-sim-step accurate when the game is running, so it gets called right BEFORE we call DoPerSimStepLogic_OnMainThreadAndPartOfSim_ClientAndHost() (so that method can use its results if need be).
    • Reworked AstroTrainsFactionBaseInfo to use this, and it should be a lot more efficient as well as providing a better pattern for other factions in the future. The code also is more brief.
  • Added a new DoubleBufferedList<T> to ArcenUniversal, which is a lot like a SwizzleList<T>, except easier to use and based around List<> rather than an array of T[].
  • Added GetFactionBaseInfoOrNullAs_Safe<T> and GetFactionDeepInfoOrNullAs_Safe<T> onto squads, for quick acquisition of the faction external info as its native type.
    • Fixed an issue with Dark Spire Vengeance Generator description appenders, where in multi-DS games they would likely all show the information for the first DS, or something else equally wrong. Now they properly show the info for the DS faction of the actual VG you hovered over.
  • Updated the following squad data into the ExternalSquadBaseInfo format, usually with a rename on top of that:
    • FallenSpirePerUnitData is now FallenSpirePerUnitBaseInfo
  • Updated the following faction data into the ExternalFactionBaseInfo format, usually with a rename and some movement of functions from the old SpecialFaction class.
    • FallenSpireGlobalData is now FallenSpireFactionBaseInfo
      • Updated the way that FallenSpireDifficultyTable stores its rows by intensity so that we can look them up more efficiently.
      • All of the various lists of cities, debris, and so forth have been updated to use the new DoubleBufferedList<T>.
      • Additionally, rather than having a simple DarkSpireEnabled boolean, this faction now keeps a double-buffered list of all the dark spire factions.
      • And finally for now, SpireDebris_ForUI and SpireDebris_ForUI have both been removed, as the new double-buffered lists that controls the central SpireDebris and SpireCities is now sufficient for our purposes here.
    • DarkSpireData is now DarkSpireFactionBaseInfo
      • DarkSpirePerPlanet is the first example of external data within external data. This really should be pooled, but we can't do that centrally.
        • The methodology for this is going to be up to individual modders and faction designers. I don't have a central solution for this, but I can provide code to replicate. On the worst case, if you do nothing but Clear() the list that is incoming, you could just throw the data away and it might be a memory leak, or the GC might take care of it. Deviating from the approach outline below by too much can introduce an MP-client-only leak, so please just follow the approach below. ;)
        • The better case is to add a new pool that is just for your object type, and then use a ProtectedList or ProtectedArcenSparseLookup where you need to centrally store these. That way when you clear, it goes right back in the pool instantly.
          • To copy this code, simply copy the Pooling section from DarkSpirePerPlanet and, replace "DarkSpirePerPlanet" with the name of your class. Additionally, make sure it inherits from the same interfaces as DarkSpireData does.
          • Next, PerPlanet on DarkSpireFactionBaseInfo was previously a ArcenSparseLookup<Int16, DarkSpirePerPlanet>. It is now a ProtectedArcenSparseLookup<Int16, DarkSpirePerPlanet>. That means that whenever it has entries removed or cleared, it will pop them back in the pool.
          • Finally, Clear() calls need to be Clear( true ) for that list, and anything that would call new DarkSpirePerPlanet() should instead call DarkSpirePerPlanet.GetFromPoolOrCreate(). Congratulations, you now have a leak-proof, MP-friendly, pooled, high-performance piece of sub-data.
      • By the by -- there used to be a method called World.Instance.GetDarkSpireFactionBaseInfoExt_AndCacheAfter(). There's no such thing anymore. That was designed as if there could only ever be one dark spire faction, and would cause problems if there were more.
      • Similarly, some faction helper methods like GetDarkSpireFaction() are now renamed to GetFirstDarkSpireFaction(), and honestly potentially they should not be used at all.
  • Vast amounts of the fireteam data has been brought back to life and converted over.
    • It has also been split into three files, for now. One which has text export bits, one which has DeepInfo bits that currently live in BaseInfo (but might move), and then the core stuff.
      • Actually, for the parts we could go ahead and move into Deep, those are now in a FireteamExtensionMethods class in the Deep dll. All but about 80 lines of the deep-type code were able to be moved there. I'll circle back around later. Please note that from the perspective of calling code in the deep dll, there aren't any real differences here (other than the things to do with strings and the one method split below).
    • Additionally, the UpdateNonSerializedFields() method has been split into two parts: one that is run on clients, and one that is not.
    • A bajillion string concatenations have been turned into double character buffers for the sake of efficiency. So has the ShipsByPlanet_ForUI field.
  • Added TryGetExternalBaseInfoAs<T> and TryGetExternalDeepInfoAs<T> on squads, along with TryGetFactionBaseInfoOrNullAs_Safe<T> and TryGetFactionDeepInfoOrNullAs_Safe<T>.
    • The idea here is that in a few pieces of code, mostly some of the central Fireteam handling code, it says something like "hey if you've got some scourge data on you, then also do this." But in the event there is no scourge data on the target, or the target's data is some other type, we don't want to complain or have errors!
  • On the World BaseInfo, added in DoPerSimStepLogic_OnMainThreadAndPartOfSim_ClientAndHost as an abstract method, and Safe_DoPerSimStepLogic_OnMainThreadAndPartOfSim_ClientAndHost as a wrapper method to call it.
    • The various things alongside this which let us see any error data, and clear any error data.
    • This will allow us to handle things like notifications to being a client-and-host activity.
    • While I was added it, went ahead and added the host-only equivalent per-sim-step items on the world DeepInfo. Namely, DoPerSimStepLogic_OnMainThread_NonSim__HostOnly and Safe_DoPerSimStepLogic_OnMainThread_NonSim__HostOnly.
      • This will allow for things like autosave handling, which is host-only.
  • Added a new LocalPlayerWorldBaseInfo, which is our very first ExternalWorldBaseInfo.
    • The logic from SpecialFaction_Human that has to do with hovering over planets and finding paths between them has been moved into this.
  • Split things up so that we can once again call the ArcenLongTermContinuousPlanningContext.RunAllContexts_ForUnpausedOnly() from the simulation, even though that's a host-only thing and thus moved.
    • Further added a new ArcenLongTermContinuousPlanningClientOrHostContext, and moved PerSecondNonSimPlanning back into BaseInfo and have it now descending from that.
  • DoPerSecondNonSimUpdate_OnBackgroundNonSimThread_NonBlocking_HostOnly has moved from faction DeepInfo and is now DoPerSecondNonSimUpdate_OnBackgroundNonSimThread_NonBlocking_ClientOrHost on BaseInfo for factions.
    • Same thing with DoPerSecondNonSimNotificationUpdates_OnBackgroundNonSimThread_NonBlocking_HostOnly, and it becoming DoPerSecondNonSimNotificationUpdates_OnBackgroundNonSimThread_NonBlocking_ClientOrHost.
  • The seven notifiers that were still left in the old SpecialFaction_Human class have now been moved into their own files in BaseInfo, and are filled from the LocalPlayerWorldBaseInfo world BaseInfo class.
  • All of the code for generating intel tab entries (internally called objectives) has been moved back to being run on the client and the host.
    • Sigh. This was a lot of work to make host-only, and the host was going to have to periodically share that data with clients, but at least that no longer has to happen.
    • This is now non-serialized data, as it always had been in the past, and doesn't go in savegames or across the wire to clients.
  • Added a new DoPerSecondNonSimNotificationUpdates_OnBackgroundNonSimThread_NonBlocking_ClientOrHost onto ExternalWorldBaseInfo, which we can now use to generate notifications that are not faction-specific.
    • This is really important for purposes of things like players who are not human empires (solo ark, necromancer, etc). Some notifications would be shared across human player types, others would not, and now we have the choice to actually set that up.
    • Also? If you're a modder and you want to add a notification, and it's not connected to a faction of your own, then this now gives you a way to do it. Previously there was not a way other than adding a fake invisible faction or something else wasteful (but required) like that.
  • Added DoPerSecondLogic_Stage1Clearing_OnMainThreadAndPartOfSim_ClientAndHost and DoPerSecondLogic_Stage2Aggregating_OnMainThreadAndPartOfSim_ClientAndHost on the BaseInfo for factions.
    • We still have the host-only versions on the DeepInfo, and that won't change. The host-only version also has Stage0, Stage3, and Stage4. The client section only ever gets its version of Stage1 and Stage2.
    • A lot of factions do aggregations that need to happen in Stage2 on the client and the host, so simply moving those over to BaseInfo while still having the option of having things split is a good idea.
  • Updated the following squad data into the ExternalSquadBaseInfo format, usually with a rename on top of that:
    • ScourgePerUnitData is now ScourgePerUnitBaseInfo
    • AstroTrainsPerTrainData is now AstroTrainsPerTrainBaseInfo
  • Updated the following faction data into the ExternalFactionBaseInfo format, usually with a rename and some movement of functions from the old SpecialFaction class.
    • ScourgeGlobalData is now ScourgeFactionBaseInfo
  • A bunch more of the Astro Train faction data has been split over to BaseInfo, partially to go ahead and get some of the notifications relating to them able to function. This really makes things more legible and organized, I have to say. It's still a mess because it's not done, but there's no more wondering which variables are available when, which is really nice.
  • Status update! Another day done, and... well, a lot of framework and structure has been implemented today, and SOME data has been transitioned over.
    • In a lot of respects, I was underestimating just how much additional framework work (additions to BaseInfo to make things convenient and quick, and make the cross-talk work) there was when I gave my three-day estimate yesterday.
    • At this point I don't really have a good sense as to how much more framework refactoring there is going to be, but I have a couple of the simpler factions to the point where their BaseInfo is done, and the squad-level data is easy. And the world-level data is also off to the races now, so that's also good.
    • The main problem is that I still have at least a full day of more work on BaseInfo before I can fully start on DeepInfo, although I am making many DeepInfo changes as I go to lessen the impact of that later. I can't imagine that DeepInfo will be less than a day, but it could be two. BaseInfo could be 1-3 more days on its own, which really really stinks.
    • On the other hand, the code is looking GOOD. I can actually understand what's going on, and aside from the truly most complicated factions, I have all of the general relationships figured out. The AI itself is one of the nastiest things remaining, but I plan to try and be as literal of a straight-port as I can, get that working, and then later potentially improve its structure further.
    • Even so, I haven't been able to run the game for something like two weeks now, so we'll see how many runtime errors have piled up once I even get everything to compile, which is somewhere between 2-5 days of work left before I hit THAT point. I had been allocating a day-ish to get it functional enough to share with players again, but I wonder if that's optimistic thinking. We shall see.
    • Another bit of good news is that many MP issues that I was going to have to tackle, some of whcih were multi-day problems that were going to be super error-prone, are just... no longer a worry. And as I've been doing this, I've also been doing a systematic code review and have fixed a number of bugs that were affecting SP at least some of the time. So this is paying dividends all over the place, it's just... really long.

Reconnecting External BaseInfo to Core, Part 3

  • Added a new GetDoesThisImplementInterface() on ExternalData_AbsoluteBase, which means that all of the new BaseInfo and DeepInfo classes are able to use this.
    • This is something that allows for a new form of generalized expansion of code capabilities from just the external dlls, without having to update Core.
    • This is useful for purposes of mods in particular, letting them add discoverable methods without having to have access to Core (or without having to alter it if the modder does have access to it).
    • Internally, this method checks to see if the end type that it is (for example, some Faction's BaseInfo type) ALSO happens to inherit from some interface of your choosing. It caches the results, so it's very efficient.
      • Please note, simply calling the normal "BaseInfoClass is YourInterface" to see if that is true will not always return true for interfaces, particularly if they are not directly assigned on the most recent class, or if you are checking for an interface that is a parent or grandparent of the interface which is directly assigned to your class.
        • Confused by that? Doesn't really matter -- just use this method to avoid any funny business with "is" or "as" keywords. Then when you get a true back from "SomeExternalData.GetDoesThisImplementInterface( typeof(YourInterface) )", make sure and do "(YourInterface)SomeExternalData" to get a YourInterface, NOT "SomeExternalData as YourInterface" in order to properly get the interface.
        • If you're curious, then calling "(YourInterface)SomeExternalData" when "SomeExternalData.GetDoesThisImplementInterface( typeof(YourInterface) )" returns false will give you an InvalidCastException. Technically you could wrapper a try/catch around that and use that to direct your code, but this is rightly considered very bad code and also is comparably very very slow.
    • So what can we DO with this?
      • Well, let's take ExoData as an example. As mentioned in yesterday's notes, sometimes there is an ExoData that is now directly assigned to a class (like FallenSpireFactionBaseInfo). Let's break down how this works.
        • If you know that FallenSpireFactionBaseInfo has ExoData and you want to look at it, you can just call faction.GetExternalBaseInfoAs<FallenSpireFactionBaseInfo>() and then immediately access the ExoData. Well that's simple!
        • But what if you DON'T know what type the BaseInfo is, for instance if you're iterating over a list of BaseInfos for various other factions for whatever reason. Maybe they are from other mods, even. Who knows?
        • Well, in that case we need a generalized way to ask ANY BaseInfo "Do you have an ExoData?" In the past, we could just call faction.GetExoDataExt( ExternalDataRetrieval.ReturnNullIfNotFound ), and what we want is an equivalent to that. So that's what we're creating here.
      • First of all, we need a new interface. In the file where the ExoData class exists, I have defined a new interface called IExoDataHolder, and gave it just a single method, called GetExoData(). See code for details, but it's super duper simple.
      • Secondly, any class that has ExoData on it that I want to expose in this generic fashion should now inherit from IExoDataHolder. For the moment, that's just FallenSpireFactionBaseInfo, but later it will be two others once I port them in.
        • Now on thos classes, I have to implement the very very simple GetExoData() method that I designed in IExoDataHolder. This is one line of internal code, just returning this.exoData.
      • Now, back in some other code where I would have previously called faction.GetExoDataExt( ExternalDataRetrieval.ReturnNullIfNotFound ), I can call the following:
        • "if ( otherFaction.BaseInfo.GetDoesThisImplementInterface( typeof(IExoDataHolder) ) )"
        • then: "exodata = ((IExoDataHolder)otherFaction.BaseInfo).GetExoData();"
    • And that's it! It would have been possible for me to make this code slightly less verbose, BUT that would have been at the expense of flexibility for faction designers and mod designers.
      • With the current approach, you can implement ANY arbitrary data-holders on any subset of classes you choose, and Core never needs to be altered in order to do so. The power of that is really useful.
      • Please bear in mind that for most sub-data, we don't remotely need to make use of this. We don't always CARE what factions use what feature. But for cases where we want to loop over all the factions and ask "which of you can give me this kind of subdata?", this new pattern lets you do so.
  • NanocaustPerUnitData has been retired from the game, since it was noted as deprecated in 2019.
    • ConstructorData for the nanocaust was not marked as deprecated, but it sure was unused, so it's also gone.
  • Added a new AllegianceHelper static class, which has things like enemyThisFactionToAll and such moved into itself.
    • Fixed a couple of small bugs in here that could lead to strange allegiances. One of which was related to multiplayer allegiances with players beyond the first.
    • Beyond that, there was a lot of special-case type code that was looking for specific factions and making choices about that. Those instead need to be triggered by xml data or this is not future-proof and mod-friendly.
      • Added allegiance_should_always_be_neutral_to_all="true" as a new option for factions, and this is now on the nebula guardians and territory dispute factions.
      • Added allegiance_should_always_be_friendly_to_all="true" as a new option for factions, and this is now on the Zenith Trader.
        • Fixed several ways in which factions could become hostile to the Trader in particular.
      • Also added allegiance_factions_i_always_hate="Faction1,Faction2" and allegiance_factions_i_always_ally="Faction1,Faction2".
        • This lets us centrally define some relationships that should always be friendly or enemy, using the name (InternalName) field from the factions in question.
        • Key note: these faction names are not checked, so they can be from mods or dlc that are not installed without problem. But if you have a typo, it may be hard to notice for that same reason.
        • This is not only more flexible (for mods and otherwise), but it also prevents the AllegianceHelper from accidentally overwriting entries if things like MakeEveryoneAnEnemy or whatever are called.
        • At present this is used to make Nebula Guardians and Champions hate one another, and Necromancers and Templars to always hate one another as well.
    • Also moved SetDefaultStartingFactionRelationships() into there, so that the defaults can be seen in External code (it had recently moved to Core) as well as changed as-needed.
      • Bear in mind you can override the defaults at a faction level via a mod, but you can't do that over what is in this helper class for ALL factions. But you can certainly rewrite faction alliances however you want via a mod.
    • As part of this, made it so that we never can override (via larger faction alliance methods) team affiliations (for the minor faction teams of three colors) or always-hate or always-ally settings. There were definitely some cases where someone could break off previously.
  • Updated the following squad data into the ExternalSquadBaseInfo format, usually with a rename on top of that:
    • MacrophagePerSporeData is now MacrophagePerSporeBaseInfo
    • MacrophagePerHarvesterData is now MacrophagePerHarvesterBaseInfo
    • MacrophagePerTeliumData is now MacrophagePerTeliumBaseInfo
    • OutguardUnitData is now OutguardPerUnitBaseInfo
      • Made OutguardGroupDataTable serialize by index, and thus improved the data transmission of this.
    • MarauderOutpostRaiderSpawnData is now MarauderOutpostRaiderPerUnitBaseInfo
  • Updated the following faction data into the ExternalFactionBaseInfo format, usually with a rename and some movement of functions from the old SpecialFaction class.
    • MacrophageGlobalData is now MacrophageFactionBaseInfo
    • NanocaustMgr is now NanocaustFactionBaseInfo
    • OutguardGlobalData is now OutguardFactionBaseInfo
    • DysonData is now DysonSphereFactionBaseInfo
      • DysonAntagonizerData has been removed, and merged back into DysonSphereFactionBaseInfo. There was always a 1:1 ratio of these existing, and there is no benefit to having them separated at this time, while there are several downsides.
    • HRFData is now HumanResistanceFighterFactionBaseInfo
    • MarauderData is now MarauderFactionBaseInfo
      • The marauder UpdateAllegiance has been updated to be more robust and use the AllegianceHelper.
      • Eight constants from the marauders xml were messily being saved into the savegame, which was mildly wasteful and moderately confusing. This is all cleaned up now.
    • RiskAnalyzerData is now RiskAnalyzerFactionBaseInfo, and is on the risk analyzer faction rather than on a human faction (that was super confusing and likely led to errors).
      • It is now our second example of an IExoDataHolder.
  • Updated the following squad data into the ExternalSquadBaseInfo format, usually with a rename on top of that:
    • DarkZenithPerUnitData is now DarkZenithPerUnitBaseInfo
    • ZenithMinersPerUnitData is now ZenithMinersPerUnitBaseInfo
    • ZenithArchitravePerUnitData is now ZenithArchitravePerUnitBaseInfo
    • TemplarPerUnitData is now TemplarPerUnitBaseInfo
    • TerritoryDisputePerUnitBuildData is now TerritoryDisputePerBuilderBaseInfo
    • SappersPerUnitData is now SappersPerUnitBaseInfo
  • Updated the following faction data into the ExternalFactionBaseInfo format, usually with a rename and some movement of functions from the old SpecialFaction class.
    • GlobalCPALogic is now AICrossPlanetAttackerBaseInfo
    • ScourgeFactionBaseInfo is actually fully set up now, apparently I got distracted in the middle of that one.
    • DarkZenithGlobalData is now DarkZenithFactionBaseInfo
    • ZenithArchitraveGlobalData is now ZenithArchitraveFactionBaseInfo
    • ZenithMinersGlobalData is now ZenithMinersFactionBaseInfo
    • TemplarGlobalData is now TemplarFactionBaseInfo
    • NecromancerGlobalData is now NecromancerFactionBaseInfo
    • TerritoryDisputeTeamData is now TerritoryDisputeTeamFactionBaseInfo
    • NomadPlanetsGlobalData is now NomadPlanetsFactionBaseInfo
    • SappersGlobalData is now SappersFactionBaseInfo
    • MigrantFleetsData is now MigrantFleetsFactionBaseInfo
  • Went ahead and removed the champions and nebula guardians factions and their related data.
    • The history of them is available in svn, but as has been discussed elsewhere, necromancers and templars replaced these.
    • At the moment, the time cost of translating the rest of these over was going to be a waste of several hours.
    • EnableChampionResponse is now EnableNecromancerResponse, although that setting is not yet hooked up to do anything, so it's commented-out for now.
    • A lot of the central code that was related to champions has been renamed to SoloArk, and converted slightly in preparation for that kind of faction later on.
  • We're now to the point where the only faction info remaining in BaseInfo that has not been converted is stuff relating directly to the AIs themselves!
    • There will still be a flood of other things needing to be adjusted after that, but that's a milestone that is approaching (and a milestone that has been hit, as well).
  • The concept of ProcessFactionConfigCustomFields has been removed from the game.
    • This was something that was previously running right after you left the lobby and translating the settings from your "soft settings" into permanent saved data on the actual factions.
    • As of a few days ago, I made it so that we're now pulling much more directly from the "soft settings" in the first place, which is useful for making sure that the game always has your latest settings even after making changes in the post-lobby settings areas.
    • It also lets us avoid having to save the data a second time for the factions, so that the "soft settings" location is instead the only place the data is saved -- which is good, because when you save the same thing two places you are at BEST wasting some bandwidth/disk space (less than a kilobyte, but still), and at worst you secretly have an accidental disconnect from what front-end shows and what the back-end is working from.
    • In place of this, there's a new convention -- not enforced -- of DoRefreshFromSettings() on factions, where we can get the settings on a small random interval, called from the chain of DoGeneralAggregationsPausedOrUnpaused(). This keeps the CPU usage down, things nice and responsive, and the settings super up to date, all at once. It's also easier code to read.
  • We now generate a completely random FactionRandomSeed on each faction when we're starting the game. This allows us to do things like random AI types that are unpredictable, but still deterministic per-campaign.
    • Actually we wound up not using this right now, but it might be useful in the future, and it's very little data, so what the heck; let's keep it.
  • Serializing a table entry no longer confusingly takes two string variables, one optional and one not, when deserializing while taking only one for serialization. It now just requires one for both, which is the same one.
    • Additionally, that FieldNameForErrors is no longer optional for these.
  • Work is ongoing with getting the AI and its sub-factions set up. A lot of this is coming together quite well.
    • There were a few surprises, like the way that I need to cache the AI Type after randomly choosing it, but that's not something you can change once the game starts, anyway (or if it's adaptive, it changes itself in the one spot here). Differentiating this from the other settings was not hard. Now it's just a matter of doing the rest, carefully.
    • There's a solid chance that this will implicitly fix some bugs that were recently reported about things like "individually chosen sub-difficulties not working properly when universal difficulty is off." That was likely an artifact of the order of operations craziness that was part of the older way of using ProcessFactionConfigCustomFields. Once it's ported over, it should be order-of-operation-independent.

For Modders: How To Handle Lists Of Sub-Data In Multiplayer-Friendly Way

  • Added a new extension method to List<> and ProtectedList<> that makes deserialization into an existing uneven list waaaay simpler.
    • This is what needs to happen, over and over again, on clients when they are getting certain kinds of external data.
    • PlannedWaves are one of the many that needs this sort of logic, so formalizing it so that it isn't prone to errors (and is easier to read and understand as end-coder) is a win.
    • Basically, you use this when:
      • You have a list of stuff that is variable length over time, and the client is going to be getting a deserialized copy of it pretty frequently... AND
      • You don't want to just clear that list (because what a waste on the one hand, or other code might be having references to objects in it)... AND
      • You do want to refill the list with the most up to date data in host-order, and then discard any leftover husks that were on the client.
    • Example 1:
      • Client has a list of 10 incoming waves. Host sends an update that includes 7 waves for whatever reason.
        • Result from this process: Client deserializes those 7 into its first 7 slots (overwriting whatever is there), and then discards the last 3. If it's a ProtectedList<>, then those 3 are headed back to the pool automatically.
    • Example 2:
      • Client has a list of 1 incoming wave. Host sends and update that includes 5.
      • Result: Client deserializes the first 1 into the existing one it has, then adds 4 more.
    • Example 3 is simply when the number of waves match, whether or not the data in them does, and it just overwrite-assigns each one as it goes.
    • The idea is to handle all of that logic without having to write all of that code every time (and to avoid the typos and confusion that are inhernt in copy-pasting such code all over the place).
  • Okay! Time to handle the first of the sub-objects that are pooled properly. Let's look at PlannedWave as an example.
    • We're going to want to have it inherit from the following: PlannedWave : TimeBasedPoolable<PlannedWave>, IProtectedListable<PlannedWave>
      • This sets us up to let us have it go in a variety of kinds of pools, as well as also function inside "protected lists" (where when you clear the list, it goes back in the pool for you automatically).
    • There is then a "#region Pooling" section, and you basically should copy that whole bit over and change and references to PlannedWave to be whatever your class is (same as with the inheritance bit above, of course).
      • In this section there is a DoAnyBelatedCleanupWhenComingOutOfPool(), which you can usually leave blank, but essentially it's helpful if there are some object references that might briefly be in use still when this gets put back into the pool, that you don't want to cause nullref exceptions from.
      • In this section there is also a DoEarlyCleanupWhenGoingBackIntoPool(), which tends to happen on background threads instead of one that is more busy, so anything you need to blank out that you can, should probably go here. You want to make sure and reset EVERY variable and list and so on that is a sub part of this object in this.
        • In this example case, to keep things simple and also consistent, I've got a SetDefaults() method that is being set in the constructor as well as on the DoEarlyCleanupWhenGoingBackIntoPool(). This is a good pattern to keep.
          • It is SUPER important that absolutely every property or variable on your class (PlannedWave in this case) is reset to its default value in SetDefaults(). Otherwise the next wave will have some stale data and act strangely when this gets pulled back out of the pool.
      • Please also note that there's a private constructor in here, and then no other constructors anywhere else in the class! We don't want any way of creating new objects of this sort other than calling the static method GetFromPoolOrCreate(). Anything else we call would be bypassing the pool and causing at least a mild memory leak.
    • At this point we have a poolable object that can only be retrieved from a pool, but we're not doing any retrieval or ever putting them back. So now let's do that.
      • On AISentinelsFactionBaseInfo, I would normally have a List<PlannedWave> WaveList. Instead we're going to use a ProtectedList<PlannedWave> WaveList, and it pretty much works identically.
      • This is a case of this list being the truly master list. If it's in this list, it's meant to exist. If we take it out, it's meant to be gone back to the pool. So, based on that, we don't ever have to think about calling ReturnToPool() manually on the PlannedWaves. That's handled for us. Sweet!
        • On Clear and Remove from this list, just be sure to pass in true as the required parameter, and it will do that handling for you. In the event that you wanted to use a protected list without it automatically sending stuff to the pool on removal, you could pass false... but that is not advised.
      • In that case, that means that the only thing we need to change beyond this is wherever we were previously calling "new PlannedWave()". That simply changes to "PlannedWave.GetFromPoolOrCreate()", and boom we're pooling. And we're done.
    • In the case of PlannedWave, I am using a ConcurrentPool, by the way. This is something that can be written to from any thread, and it has some nice advantages. But there's not "time out" cooldown before waves are reused from the pool. Because of the nature of how waves are created, this is not a problem.
      • In the case of a piece of data where you might have lingering references for a while, you might be better served using a TimeBasedPool instead. That works exactly like ConcurrentPool except that you can specify a cooldown time that the objects must stay in the pool before they can come back out. 2 intervals of 30 seconds each are enough for all long range planning to complete for every faction in a super pessimistic case, if that's what you want to base it on. Otherwise just give it a couple of seconds of delay. At any rate, PlannedWave doesn't need that.

Reworking Subfaction Relationships And The AI and Beacons, Part 1

  • Added a new AISentinelsFactionBaseInfoExtensions class, with GetAISentinelsBaseInfo() on it as an extension of the faction class.
    • The reason I'm doing this for the sentinels and not any other factions is because of all its many subfactions, and their constant need to get the info of their parent.
    • I'm also planning on storing all of the meaningful subfaction data of any note on the parent itself, to further tighten these things together.
  • Removed GetPrecedingAIFaction() and GetNextFactionOfSpecialFactionData() from the Faction class in Core.
    • Now that I'm working on the AI and its subfactions, the current situation with how they are linked is just really untenable. It was unreliable before, and would not always properly link the factions together exactly as expected. Time to change that.
  • Just like we have FactionIndicesIAmHostileTo and FactionIndicesIAmAlliedWith, factions now also have FactionIndicesOfMyChildren and a new FactionIndexOfMyParentIfIHaveOne.
    • These let us keep track, explicitly, of which subfactions are linked to what parent faction, in a bidirectional sense.
    • There is a new MakeChildOfOtherFaction( OtherFaction ) method on the faction class that makes this a one-line call to initialize.
    • You can then just call the new GetParentFactionOrNull() on factions to get a reference to the parent faction if there is one.
    • Part of the idea here is to make it much simpler for our AI factions and subfactions, sure, but also the other part of the idea is to make it so that mods can now set up compound-factions like this if they need to. Or us with other related factions if need be.
  • General improvements to some of the serialization code have been made.
    • Among these, planets and factions no longer have a serialization gate calculated for them. They are simply now capped at 511 for planets, and 255 for factions. These limits were already well enforced elsewhere.
    • Fixed a minor new SpecialFactionData serialization issue from it getting mangled in all the ripping and tearing. It would have been fast to find later, but this saves time.
  • Getting rid of some other methods that we no longer use and so just clutter things up:
    • On faction: GetDoesThisFactionHaveBaseInfoType(), GetDoesThisFactionHaveDeepInfoType(). That new FactionRandomSeed.
    • On squad: GetFactionBaseInfoType_Safe(), GetFactionDeepInfoType_Safe().
  • Split the BaseInfo and DeepInfo serialization out of the main faction methods for serialization into new SerializeExternalFactionData() and DeserializeExternalFactionData().
    • This is actually a pretty huge deal, because now we'll send the externaldata at the end of any transmission, and at the end of any savegame.
    • This means that factions, squads, planets, etc, all already exist when externaldata starts getting loaded. Previously a lot of that was not loaded yet, so externaldata had to use indices during deserialization rather than looking at real objects. This will simplify code, and speed up some bits of code, and reduce coding errors.
    • Same for BaseInfo and DeepInfo on squads, which is now based from SerializeExternalSquadData() and DeserializeExternalSquadData().
  • The multiplayer fast-blast sync code has now been updated to handle the BaseInfo from host squads needing to be synced over.
    • The faction BaseInfo sync in multiplayer via PeriodicFactionExternalSyncDataThatJustOverrides has been updated to the new format, which was very simple.
  • Split SerializePlanetFactionEntities and DeserializePlanetFactionEntities out from the core PlanetFaction serialization, since that was rather confusing code the way it was before.
    • Also, CurrentAttackMultiplier and CurrentSpeedMultiplier are no longer serialized at all (it's recalculated every frame).
    • And the shipgroups are no longer serialized, even in super-brief form, except for AI factions (they're the only ones who use it).
    • Uh, also a lot of other stuff moved around. It's more efficiently organized, less likely to cause errors, and easier to extend.
      • The really big one is that this completes the move of all the externaldata to the very end of a network transmission or a savegame save. For factions, squads, and the world. That way the external data can always freely talk about the Core data without worrying if it's been loaded or not yet.
  • For the sake of clarity, the factions that are auto-added-always-there-but-only-one have been moved into one file, and the "factions that are auto-added-per-AI" have been moved into another.
  • On factions, auto_add_one_of_faction_if_missing_on_save_load="true" has been changed to should_always_have_exactly_one_of_these_in_every_game="true"
    • This has been removed from several sub-factions of the AI, and instead is just on the things like Outguard, AI Reserves, Instigators, and the zombie factions.
  • There was then an actually_seeds_multiple_so_do_not_complain="true" that was an answer to some of the factions that had must_be_at_most_one="true" on them but were not supposed to complain.
    • Those factions were erroneously marked that way in the first place (because of a long history of evolution of the game, it's complicated), so that actually_seeds_multiple_so_do_not_complain="true" has been removed.
  • auto_add_one_of_faction_per_ai_if_missing_on_save_load="true" and remove_if_more_than_one_per_ai_prior_to_this="true" have both been removed, as they were kind of funky.
    • Instead, added a new is_a_subfaction_of="OtherFactionName", which lets us define the relationships directly, and which causes them to get created one-per-such faction, call MakeChildOfOtherFaction() on said factions, and disappear if that faction is not present. All speaking here about on the lobby load, or savegame load.
    • The warden, hunter, PG, CPA, relentlesss wave, and border aggression are now marked as subfactions of the AI.
    • The territory dispute teams are now marked as subfactions of the parent territory dispute faction.
  • takes_on_color_of_the_first_ai_faction="true" is being left alone -- that's useful for instigators and so on -- but takes_on_center_color_of_the_preceding_ai_faction="true" is being removed.
    • We now instead have a takes_on_center_color_of_the_parent_faction="true" as an option which can work for any faction that is a child of another. For now it's just used with the AI subfactions: warden, hunter, PG, CPA, relentlesss wave, and border aggression.
  • is_considered_visible_part_of_the_ai_faction_for_what_can_own_purposes="true" is removed, as it was not actually used at this point.
  • takes_on_current_general_mark_level_of_the_ai_factions="true" has been renamed to takes_on_highest_current_general_mark_level_of_any_ai_faction="true", because that's what it does.
    • This is now used by the instigators, AI reserves, astro trains, and risk analyzers, but is no longe used by the AI subfactions.
  • Added a new takes_on_current_general_mark_level_of_parent_faction="true" that is now used by the AI subfactions.
    • Previously if you had many AIs of different strengths, their subfactions would all be the mark level of the strongest AI, which was wrong.
  • The way that "beacon factions" work is being completely reworked under the hood.
    • The user experience was never great (people didn't realize they could configure said factions prior to hacking the beacons but that it got more limited after that).
    • And there was a nontrivial performance drain, and some bugs, from having lots of these. Macrophage picking up spire shards when not in the game except in beacon form, etc.
    • In the next few weeks I will re-code the hacks for the beacons so that you can configure all the aspects of the beacon faction as you are summoning them. The beacons will from now on belong to the NaturalObjects faction, however.
    • In the meantime, all of the stuff related to a faction being present but "needing to be awakened" is being removed.
      • MustBeAwakenedByPlayer, MustBeAwakenedAndIsAllied, ShouldBeRetainedIntoLobbyLoadEvenIfMustBeAwakened, and HasBeenAwakenedByPlayer.
  • auto_remove_faction_on_lobby_load_and_mapgen_when_other_faction_present="FactionName" is also being removed, as we don't need it anymore.
  • auto_add_one_of_faction_when_other_faction_present has been converted into auto_add_singleton_of_faction_when_any_count_of_other_faction_present, to be more clear.
    • This is still used on tamed and enraged macrophage, but is also now used by the antagonized dyson sphere. This is also still used by the templars in response to a necromancer.
  • When you load up a savegame into the lobby, or old lobby settings, or a quickstart into the lobby or for generation, it now strips out all the following:
    • Any subfactions of other factions. Any that should always have exactly one per game. Any that are automatically added when some other faction is present.
    • This is mostly equivalent to what we did in the past, but the general idea is we never want to see things like a dormant tamed macrophage with no main macrophage present, or extra hunters due to having fewer AIs present now, etc.
    • The only time these things are added BACK is when a full generation of the map happens (aka moving from the lobby into the game, or from the quickstart into creation of the game proper). Then all the magic fills out the relationships and should have exactly the faction list as desired.
    • We had half a dozen idle factions clogging up every savegame in the past, and sometimes more, which was potentially a waste of bandwidth and performance. It was also a barrier to adding beacons for more factions, since there was such a performance hit with each one.
    • All of the various code paths that do these sorts of things now seem to function, which is awesome.
  • Removed GetDefaultFactionConfigurations() from the Scenario definition, since now most of our code is much more xml driven.
  • One thing that isn't fully xml-driven, but nonetheless is now part of the Expert campaign type, is that you must have a minimum of two AIs to face.
    • A lot of the complexity of the game is lost when you only have one AI, because you don't get that ramp-up in challenge after defeating the first one, and have to figure out how to still deal with the second one.
  • The seeding options for a couple of DLC2 factions that were "Only From Beacon" have been removed.
    • These will get beacons in the near future, along with some other factions that never had beacons, but they will work the new way.
    • Worth noting that this didn't play well with the Enable Beacons setting, and so could get kind of funky in Expert mode because of that.
  • Also stripped out more code that was based around the concept of a faction being present as a beacon but not enabled.
    • Later, the logic will be that the beacon is present as a NaturalObject, and the only time the faction will arrive is after a hack adds them (letting you clearly choose settings for it before you complete the hack, too).
  • Added in a new HasDoneInvasionStyleAction to factions, which is false by default.
    • Previously, we had a HasBeenAwakenedByPlayer which was used one way sometimes (for beacons) and another way other times (for delayed invasions). That had led to various bugs in the lobby.
    • Now we just have HasDoneInvasionStyleAction, which is used for invasions or not at all. Most factions ignore this one bool and just go about life.
      • This is primarily used by the nanocaust, but in theory other factions could use it later.
  • Simplified some of the PlanetFaction data. FInts are the largest data format that we have for casual use, and each PlanetFaction object had three of them (AIPLeftFromControlling, AIPLeftFromCommandStation, and AIPLeftFromWarpGate).
    • In an 80 planet game with 21 factions under the hood (remember, one AI is a compound faction that is 6 under the hood alone), that would have been 5,040 FInts. Those each require somewhere in the ballpark of 64 bits to store, which would be a total of 40 kilobytes in a savegame that is maybe 200-600kb in total in the early stretch (so, that's as high as 20% of our entire data storage in the early game, for context. Granted, things get adjusted around a lot to avoid this, but I still wanted to minimize what is on PlanetFactions, and the above is a good enough example to show why.
    • We no longer have AIPLeftFromControlling at all, since that could be inferred from the other two. The other two are now stored as integer values, and specifically AIPLeftFromCommandStation is serialized as a 17-bit format, and AIPLeftFromWarpGate as a 9-bit format.
      • Assuming no other changes (ha -- there already were improvements elsewhere, but let's ignore those for this example), this would be 5.74 kilobytes of data now, instead of 40.
      • This matters much less in savegames than it does in multiplayer, where we are frequently sending things like the planetfactions from the host to each client just to make sure that things are synced up.
    • The bandwidth use by the game prior to this whole rewrite of the game's structure was pretty darn alarming (though still lower than a poor-quality youtube video, for instance). But that bandwidth usage made higher player counts harder for people to do, and put an extra strain on people who had a lot of packet loss or were physically very far apart.
    • This is just one of those "low hanging fruit" ways to reduce transmission amounts, but the whole rewrite of all this is aimed at least partially in that direction (other than bandwidth reduction, the rewrite is aimed at code correctness, client functionality parity, and ease of coding for modders with the game having to send less self-correction data.
  • Added TryGetExternalBaseInfoAs() and TryGetExternalDeepInfoAs() on faction, mirroring the versions that are on squad.
    • Added a new TryGetAISentinelsBaseInfo() in AISentinelsFactionBaseInfoExtensions as an extension on the faction class. This more or less mirrors the "get or return null" style.
    • Essentially, in your mods you can do a global search and replace for "GetSentinelsExternal( ExternalDataRetrieval.ReturnNullIfNotFound )" to "TryGetAISentinelsBaseInfo()"
  • All of the AI subfactions are now going to have sub-objects that are shared on the central AI's object. This greatly simplifies how they can access each other's information, but lets us still keep things ordered. As with ExoData, these will be readonly subobjects that we can then edit at will without ever replacing them, and so they don't need to be pooled, etc.
    • AISentinelsExternalData is now AISentinelsBaseInfo. This is now a readonly sub-object of AISentinelsFactionBaseInfo, which makes it really convenient for any sentinels faction or subfaction to get at the data. I'll be following the same pattern with the other data of this sort.
  • TimeBasedPoolable now does the thing where it seals and obsoletes ToString(), and has a virtual method called AppendStateForInterfaceDisplay().
    • We really want to avoid having classes that are calling ToString(), because that's pretty much always GC churn and a waste.
    • EntityOrder now uses AppendStateForInterfaceDisplay instead of ToString(). It's a case of not even knowing it was a problem until it was made a compiler error.
    • PlannedWave also has been updated in this way, as has EntitySystem.
  • ArcenCharacterBuffers of all sorts now support passing in an ArcenPoint and having that serialize nicely.
  • ExtragalacticBudget has been updated to be poolable in the same pattern that was implemented for PlannedWave.
    • Fixed an issue that would cause deserialization errors in ExtragalacticBudget on MP clients. This was a longstanding issue, looks like, and very rare and confusing if it happened.
      • The fix for this was switching to the new DeserializeUncertainNumberOfEntriesIntoExistingList(), which is a great example of just why this new thing is so darn useful.
    • ExtragalacticBudget is an interesting case, because it was very complex with multiple constructors. But those simply are turned into static Create() methods, and then suddenly the complexity is gone and the program flow is the same. There are many similar examples in Core, but this is the first one in external code.

Reworking The AI And The Last Of BaseInfo, Part 1

  • AISentinelsBaseInfo is now AISentinelsCoreData, because that naming was HYPER confusing. Naming anything BaseInfo or DeepInfo when it's not actually that is a really bad idea, turns out.
    • The other sub-classes of AISentinelsFactionBaseInfo are now being set up as well. Bear in mind that these are part of the sentinels faction data, not part of the sub-data of the sub-factions. They do have their own sub-objects, though, to keep things organized but accessible.
      • AIWardenExternalData is now AIWardenCoreData
      • HunterFleetExternalData is now AIHunterCoreData
      • HunterFleetExternalData is now AIHunterCoreData
      • PraetorianGuardExternalData is now AIPraetorianGuardCoreData
  • AICommonExternalData is now GlobalAIWorldBaseInfo, which is something that I am attaching to the world object, because it's thing that is truly global between all of the AI factions that might exist.
    • This is slightly more efficient from a data standpoint, and is simpler to use. Any faction can do this sort of thing, particularly if there are going to many of that faction.
    • This also declares a singleton, so it's really easy for any code anywhere to now just go GlobalAIWorldBaseInfo.Instance.AIProgress_Effective or whatever.
  • AIPChange is now being treated like PlannedWave, with the new TimeBasedPoolable and IProtectedListable inheritance.
    • This is probably now the simplest example of this pattern in use, because it's a fairly low-data-and-methods class to begin with.
    • There was some logic in GetAIP that previously was setting the AIP to the highest version based off of any AIP. The coder had been note the code as being a bit hacky. I've move that over into GlobalAIWorldBaseInfo, and it calculates those things now on that method.
  • Added a new EnumIndexedArray in Universal, so that we can get rid of all those class-specific versions and add more functionality to them.
    • In particular there is a new ClearTo method. But there's also a reference tracker, so that we'll know how many there are in the game if we do a data dump. And there's just no longer a bunch of duplicate code all over the place so much.
    • Then removed the following classes, converting them to instead use this new EnumIndexedArray:
      • Universal: ArcenEnumIndexedArray_PerformanceSegment, ArcenEnumIndexedArray_FourDirection
      • Core: ArcenEnumIndexedArray_CoreFunction, ArcenEnumIndexedArray_EntityLineHardcodedType, ArcenEnumIndexedArray_MetalFlowPurpose, ArcenEnumIndexedArray_SpecialEntityType, ArcenEnumIndexedArray_OtherSpecialEntityType, ArcenEnumIndexedArray_EntityRollupType, ArcenEnumIndexedArray_FactionType, ArcenEnumIndexedArray_PlanetFactionBooleanFlag, ArcenEnumIndexedArray_EntityOrderType, ArcenEnumIndexedArray_FactionStance, ArcenEnumIndexedArray_ResourceType, ArcenEnumIndexedArray_EntityBehaviorType
      • External: ArcenEnumIndexedArray_AIBudgetType, ArcenEnumIndexedArray_HunterFleetBudgetType, ArcenEnumIndexedArray_PraetorianGuardBudgetType, ArcenEnumIndexedArray_AIWardenBudgetType, ArcenEnumIndexedArray_Code, ArcenEnumIndexedArray_ClientConnectionStage
    • Tip for modders: you can use a simple global search and replace for each type you remove, in this fasion: "ArcenEnumIndexedArray_AIBudgetType<" with "EnumIndexedArray<AIBudgetType,"
  • The external data for factions and squads now has a virtual method that you can override called DoAnyInitializationImmediatelyAfterSquadAssigned() and DoAnyInitializationImmediatelyAfterFactionAssigned(), respectively.
    • On AISentinelsFactionBaseInfo, I am now using this to call "this.WardenInfo.InitializePathfinders( this.AttachedFaction );" and the same for the other subfactions.
  • It turns out that ExoData is the perfect model for how to handle the AntiMinorFactionWaveData, so that's the pattern I'm going with, including having a IAntiMinorFactionWaveDataHolder.
    • MarauderFactionBaseInfo and NanocaustFactionBaseInfo have been updated to hold an AntiMinorFactionWaveData WaveData object.
  • And that's the last of converting old style ExternalData over to BaseInfo!
    • At the time of this writing, there are 195 errors still remaining (newly revealed now that all the types are converted over) in the BaseInfo dll that need to be resolved before I can start truly working on DeepInfo.
    • There's also 85 "//EXTERNALDATA_TODO" tags where I commented out some code in BaseInfo to let it compile at one point last week. I'll have to uncommented those and get that all compiling, and then BaseInfo will be done-enough-until-DeepInfo-forces-more-changes, but at least I'll be able to compile it.
  • Uncommented out all 85 of the //EXTERNALDATA tag sections, and now I'm up to 385 reported errors in the BaseInfo dll. Time to get cracking on those!
  • Removed the PreferredAIFactionIndex from faction external base data.
    • This has been made obsolete by FactionIndexOfMyParentIfIHaveOne on the Faction object itself.
  • BaseAIFaction.ChangeAIP() should now be GlobalAIWorldBaseInfo.Instance.ChangeAIP(), which has been converted to the new format.
  • SpecialFaction_CPALogic.cpaDelayTime is now AICrossPlanetAttackerBaseInfo.CPA_DELAY_TIME.
  • Rather than ever using factionExternal.AIProgress_Effective, it should now always be GlobalAIWorldBaseInfo.Instance.AIProgress_Effective.
    • Same with AIPChangeHistory and things like that.
  • GetPrecedingAIFaction() should now be GetParentFactionOrNull().
  • I've improved the way that we're able to call in and get faction configuration data. You can have it error when you ask for data from a field that does not exist on that faction, or just return the default value.
    • Most of the time you'll want it to error, because that's probably a glitch in your code that will cause unexpected behavior. It's the sort of thing where a small typo can just wreck your whole day, but now it's actually going to tell you about it and therefore it's super quick to fix.
    • Then again, there are other times where we're scanning past lots of factions, and saying something like "hey, do you have an intensity? I'll show it if so. Got an allegiance field? I'll show that, too, if you got one." And if the answer is "no I don't have one," that's not an error at all. Those are the cases where you'd pass in false to having it error on missing data.
  • Added some extension methods where you can call faction.CustomData_GetSpawningBooleanOne(), and a variety of others that start with CustomData_[Whatever]
    • Many references to Ex_MinorFactionCommon_GetPrimitives have been expunged, with most being converted using the above, but others just directly referencing some variable in a new place. Still more to go.
    • This also pulled out a ton of code from ProcessFactionConfigCustomFields() that was very specific to just that one method, and now that's more formalized and something that can be called from more than just that one place.
    • The complete difficulty settings for the AI and all of its subfactions now get pulled out properly, and should be far more accurate (there were some reports before of univesal difficulty not being handled properly when disabled)
    • Also as part of this, many of the generic names for things (like "SpawningBooleanOne") have been renamed to actual sensible things (like "EnableFimbulwinter").
      • Side note: it was a huge pain in the rear to even try to add new proper field names before, so this is not a criticism of faction coders in the past. It was an archtectural challenge that no longer exists.
  • Added a new DevourerFactionBaseInfo, which tracks the TimeLastExisted for that faction, as well as some other info that was in the DeepInfo dll but needed to come out.
    • Also added a new LoneWandererFactionBaseInfo, which will act as the underlying basis for handling both the Devourer and the Zenith Trader.
    • Please note, this is actually a great class to look at if you're thinking of doing something similar. It has a TON of extra comments in there, mostly about how to properly use DoubleBufferedList<>.
    • I am going to start having a habit of putting "TEACHING_MOMENT:" in the code anytime there's an example class with a lot of things that are explained. That way coders can search for "TEACHING_MOMENT" and find anything that I (or someone else) has put in there.
      • There are two teaching moments in this particular file. One for double buffered lists, and the other for Sealed methods and abstract submethods.
  • Updated my DoubleBufferList so that the swap and clear actions are two separate things.
    • The reason for this is that at swap-time, it's very likely that another thread has a hold of the expiring display list. So clearing that would cause an exception.
    • By the time we loop back around and are ready to construct a new list, any other threads are fairly certain to all be using the new display list, so clearing that other list won't bother them. There's a much larger gap between list constructions than there is any display-list-accesses, by design. This is a common feeder pattern.
    • It's something I had realized the other day, and had just put on my long list of to-dos, but at this point I need more of these to use for things like keeping track of the Devourers running around, etc.

Reworking The AI And The Last Of BaseInfo, Part 2

  • A variety of code translations to the new format that are not worth detailing, and finished the work of getting rid of Ex_MinorFactionCommon_GetPrimitives.
  • Fixed an issue where we had apparently wished for the Macrophage to have the same "Seed On Nomad If Possible" option that the Dyson Sphere had, but the setting was partially missing.
  • The central AI BaseInfo now has direct references to all of its subfactions in the form of handy names like SubFac_CPA and SubFac_Warden and so on.
    • This doubles as a self-checker to make sure that an AI faction is in proper health with all the expected subfactions and no extra subfactions hanging around.
    • This then lets us get rid of a lot of things like GetCPALogicForThisAI(), happily.
  • Added a new AISubFactionBaseInfo, which acts vaguely like the LoneWandererFactionBaseInfo class.
    • This is now the base class of all of the AI subfactions, and it makes the act of finding the parent faction and its data super trivial, and also ensures proper linkages or it has a centralized freakout about that.
  • All of the various factions in the game and DLCs now have proper BaseInfo classes, and the xml is all linked up for BaseInfo and DeepInfo.
    • As part of this, the three types of zombie factions now share a common base class, like how the lone wanderers and the AI subfactions do.
    • Also, the Svikari have become a subclass of DarkZenith rather than using DarkZenith quite so directly.
  • All of the ISpecialFaction classes from DeepInfo have now been renamed to their new proper names, and inherit from ExternalFactionDeepInfo.
    • This leaves a lot of other fixing to do, but it gets things in proper place at least. This is things like SpecialFaction_Human becoming HumanEmpireFactionDeepInfo.
  • The above two items also involved splitting a number of files, and setting up some template empty files for various factions, etc.
    • This gets all of the major objects into place, but just not yet with the correct formatting and linkages and so on.
    • It was about an hour and a half just to get things organized like this, and would have taken a lot longer if I did it in small stages. There are still probably tens of hours left on this conversion, but having things working by next weekend is looking increasingly feasible.
  • At this point, there were still 374 lines in BaseInfo and DeepInfo that referred to ExternalDataRetrieval, which no longer exists.
    • A targeted set of 64 global search and replace commands got all of those fixed up. (Yeah, it was odd to me that it was exactly 64, too.)
    • Total errors reported by the compiler in BaseInfo are now down to 224, but this was fixing up a lot of others that had not been reported in that number yet, or which are in DeepInfo. The IDE tells me there are 3269 errors in all at the moment, but that's both overcounting and undercounting at the same time. It's progress, anyhow!

Reworking The AI And The Last Of BaseInfo, Part 3

  • All of the general cases where I could update "Implementation is" or "Implementation as" in a global search and replace way are now fixed (I didn't count how many it took, but a couple dozen operations to get about 140 items corrected). I'll get the rest as I go through files in more detail.
    • So this leaves me with 220 errors reported by the compiler for BaseInfo. I spent a lot of the morning doing payroll, so let's see if I can knock out the rest of BaseInfo by the end of today. That really would be nice.
  • All of the BaseInfo objects for factions that are only allowed to have a single version now have a static Instance on them for quick access.
    • Worth noting: if those factions are not active in the current game, those instance variables will be null! This is by design.
    • These classes also now all inherit from IExternalBaseInfo_Singleton, just to make it a bit more clear again what the intent is.
    • This applies to: Dark Spire, Fallen Spire, Astro Trains, antagonized dyson sphere, HRF, Risk Analyzers, tamed and enraged macrophage, naturalobject, ai reserves, instigators, all three zombie factions, outguard, zenith miners, dark zenith (which has had its class split from its core, for later benefit because of svikari), nomad planets, territory dispute parent, necromancer, and templars.
    • Might as well have a consistent pattern, and this makes converting a lot of other code easier.
  • All of the "WAVES_TODO" markers are happily able to be removed, as they will now work properly on clients without any further effort thanks to this general restructuring of data.
  • Spire relics can now be moved around properly by multiplayer clients. That was something I hadn't even realized was broken by my changes in July, but it was -- a great example of why this much more intentional split, as time-consuming as it was, is so much better in the long term. I can clearly see in the code itself when something is wrong, without having to wait for testing an exception to pop up.
  • The ClientSafeExternal namespace has been removed, and its contents returned to External, because the separation is now in between dlls rather than just namespaces.
    • This is something that is no longer needed at all, and was a half-measure where now a full measure is being taken.
  • Marauder outpost descriptions will now have proper info after you load a save and before you unpause the game.
    • Right now I'm making dozens of code changes that are not really worth detailing since they are just tidying things from one format to the other, so instead I'm mentioning things that happen to get fixed along the way.
  • Added a new DoubleBufferedDictionary, which works just like the DoubleBufferedList does. Turns out this is needed for various factions, marauders among them.
  • Fixed up some code from UpdatePowerLevel() in a ton of factions to keep them from having values that flickered for a few microseconds at a time. It probably wasn't a problem, but why tempt fate.
  • The scourge now use vastly less GC every frame in general, and also less when showing their details for the UI.
    • Several minor formatting issues were fixed with scourge being displayed on the UI, and additionally it now shows the list of spawners like it does for armories. Before it meant to, from the look of it, but it only actually showed the count.
  • Added a new DoubleBufferedArray, which is now used by various factions, including the scourge.
  • Ported over a huge amount of the scourge data and the logic for its data aggregation.
  • Added a new DoubleBufferedValue, which is basically like the other double-buffered things but just for a single integer or similar. This is also now used on the scourge data.
    • There are many other ways to handle this same problem, the simplest of which is a working variable. But in looking at the scourge class, where there was a mix of local variables and naked assignments, it's easy to see that that's hard to maintain properly.
  • At this point, down to 191 compiler errors reported in BaseInfo.
    • It's worth noting that the bug count in DeepInfo falls dramatically with each of these checkins, too, but those are not numbers I'll ever actually see as high as they are, since I can't attempt a true compile of DeepInfo until BaseInfo works.
  • Macrophage turns out to be a really complicated class in terms of how the base, tamed, and enraged variants relate to one another.
    • There were a number of parsing things that I don't think were quite right, and probably led to things like the enraged version always having an effective intensity of 0.
      • I've adjusted things so that tamed still has the intensity of 10 that someone put in there (wow, nice), and the enraged version has the intensity to match the highest regular macrophage now.
  • Also to support the macrophage, because they do this sort of cross-faction aggregation to fill what used to be called SporesPerPlanet, but which I'm now calling CrossFaction_SporesPerPlanet, I've had to make a number of new little things.
    • For one thing, the way that this data structure gets filled across faction lines is now vastly more efficient (blind Add calls and one-way caching, versus expensive Contains lookups).
    • This then required me to added a new Stage2APostAllFactionAggregating method, though, that lets me run the final SwitchConstructionToDisplay() on the DoubleBufferList array that is CrossFaction_SporesPerPlanet. That needs to happen once per cycle, after all of the other factions have done their stuff.
  • While I was at it, I noticed that the central logic had not yet been set up to actually call the BaseInfo Stage1 and Stage2, they were just calling DeepInfo Stage1 and Stage2.
    • Now it calls both, although I'm unsure if I'll keep Stage1 and Stage2 on DeepInfo. I see pros and cons to that, but it will likely just remain, but be empty for all of our built-in factions. I could see some modders needing the feature.
  • Added a DoubleBufferedArcenSparseLookup, because I know how fond some programmers are of the ArcenSparseLookup's extended capabilities.
    • I'd prefer not leaning on this too terribly much, because it comes at a bit of an extra cost compared to a regular Dictionary, but such is life. Sometimes we need those capabilities.
    • As an aside, I built some of the "freedom to call into keys that don't exist without error and get a default value back" capabilities into all of my DoubleBuffered structures. It's one of the favorite advantages of ArcenSparseLookup over Dictionary, and it's something you can use with DoubleBufferedDictionary without having to go all the way to DoubleBufferedArcenSparseLookup.
    • In my opinion, the only real good reason to go to DoubleBufferedArcenSparseLookup is if you need it to be a dictionary but also have the ability to sort, like ArcenSparseLookup has.
      • I almost switched the list of Telia to being a DoubleBufferedArcenSparseLookup because of how it is used in SporeDescriptionAppender, but then realized that I could accomplish what I wanted just by using a foreach rather than a for statement if I kept it DoubleBufferedDictionary. This will be a tad more performant, so that's what I went with.
  • Also, I'm no longer keeping any concept of "Wilds" for macrophage. That seemed to be a mix of enraged and normal macrophage for some reason.
    • I now have a singleton for both tamed and enraged, and then a full list of the regular macrophage. They can be queried separately or in series. Sticking the enraged in with the regulars didn't sit right with me, it felt like a problem waiting to happen.
    • Unlike pretty much every other faction I've seen so far, Macrophage is having to have a bit more surgery to parts of its actual logic, partly because it's just that old, and partly because it's been maintained by a revolving list of programmers over the years. Please let me know what issues you find once we're back to being able to play on the new builds again.
  • And with that I'm down to 161 stated compiler errors in BaseInfo. But once again, the day has had lots of progress on DeepInfo, so it's not going quite as slowly as it seems to by that error count number alone. My hope, knock on wood, is that DeepInfo will just fly by fast after BaseInfo is all finished up.
  • A bunch of fallen spire stuff got moved over into BaseInfo. That was the easiest yet because it's more or less my code, most of it.
  • Same with the Zenith Architrave, mainly because they're just a really modern faction in terms of their code.
  • Also the same with the Migrant Fleets faction, which is very well done from what I see so far.
    • One thing I fixed was converting cachedMovementTargets from an ArcenSparseLookup into a ConcurrentDictionary, because both the UI and the long-range-planning threads use this, so a cross-threading conflict was otherwise just a matter of time. Now the existing logic will work fine.
  • Down to 147 reported compiler errors in BaseInfo.
  • Some more general fixes and translations, getting the error count lower.
  • Fixed a variety of xml filenames that said BaseInfo instead of DeepInfo. It didn't hurt anything, but was confusing.
  • Trying to get the host to trigger SharkB (which must happen in DeepInfo) in response to something that happens in a gamecommand that the client also needs to execute (in BaseInfo) is an early and interesting test of a pattern that is not very common thus far.
    • Overall most of the control code is in DeepInfo, and so we don't need to "call up" like this. Instead, deep just calls down and can see everything, which is the idea. But these exceptions do exist, and so having a formalized way of handling them has always been part of the plan.
    • In this particular case, we're getting our first DeepInfo world-attached object, which I'm calling GlobalGeneralDeepInfoCommandHandler. It's just for a variety of general things, over time.
    • Additionally, the ExternalData_World base object now has its first method of interest, which is called DoAfterEntityDeath(), and lets you pass in a string ActionCode to specify one or more types of things.
      • The flexibility of this is that we can have more than one thing handled in our central library, but also modders can set up their own objects of this sort and also call them. We don't need one object per type of on-death call, since that would be excessive.
        • It's important to know that these are called manually, from the bottom-up, when the sim code detects something it wants to react to. This is the same pattern SharkB was already using.
    • There's another "TEACHING_MOMENT" piece of code in there (I've added several of those today, as well as flagging some comments of Badger's that were teaching moments as being such so people can search for them).
  • Imported a bunch of Dark Zenith logic (the stage 2 aggregation). This was more complex because it was having to do way more work since it did not have double-buffered collections in the past.
    • Some things also were able to be simplified because of the new architecture where you can actually get planets and squads and such immediately on deserialization, whereas before this version you would not. So for instance, serializedFimbulwinterEligibleTime is able to be ditched, and we just write straight to FimbulwinterEligibleTime, saving ourselves some hassle.
    • Same with OriginalPlanetIdxs going away, and just having OriginalPlanets, instead.
  • Okay, that's it for today. Down to 134 errors in BaseInfo. It took a while to convert over the Dark Zenith, mainly because it's such a big complicated class. But thankfully, the newer logic (double buffers, mainly, but also the deserialization order) really make the code a lot more legible and cut down on extra work.
    • I'm sure it's going to be mildly frustrating to Badger that he didn't have those tools when he originally coded this faction, but I wouldn't have thought of adding them without seeing the same patterns over and over again and realizing I could simplify it based on that.

Reworking The AI And The Last Of BaseInfo, Part 4

  • GameCommands used to be all in one giant monolithic file. They have now been split out into a variety of files, by loose purpose or association. This makes it a lot easier to find a specific GameCommand, or to look at several GameCommands that are related to one another.
    • As part of this, and because I needed to, two of the GameCommands (both dealing with changing the galaxy map, as part of ZO) have been moved to DeepInfo, where they will only be run by the host, and where they can access data and methods that only the host would have.
  • The dyson antagonizer faction logic has been ported properly between base and deep info now.
    • Same with the the main dyson sphere faction, including wiht the ability to handle multiple spheres around the galaxy, now using the same pattern for that which macrophage are using.
  • All the cheat codes work again (yeah that was a thing).
  • All of the description appenders work again.
  • The central faction processing code is now split out fully into DeepInfo, which is excellent. It's still kicked off from logic in BaseInfo, but the actual execution (only on the host) is in DeepInfo now.
  • A number of faction methods that used to be FOR UI ONLY and very problematic if used otherwise are now using ThreadStatic internal markers on their lists to make themselves threadsafe. These are now labeled as being threadsafe, and can be used by the UI, main thread, LRP, whatever -- all at the same time, even!
    • The various notifications that used these ui-only versions of the methods have been updated to point to the new ones, and a TEACHING_MOMENT flag has been put in next to a comment about ThreadStatic at one point.
  • The HostOnlyJournalsAndAutosaveAndSimilarHandler has been moved into DeepInfo.
  • AIUtilityMethods has been moved from DeepInfo into BaseInfo.
  • Fixed a likely bug where nanocaust intel entries have not been shown ever since frenzy fleets were removed (back around the time of fireteams).
  • Imported some various things from deepinfo and sappers and such into BaseInfo that were going to move here soon enough anyhow.
  • Okay! Well, BaseInfo now compiles, which means that I'm able to get going on DeepInfo properly.
    • There's a lot to translate over there, but I've been steadily doing that as I went, too, so we'll see how long this really takes.
      • There's a fair number of things which are kind of mindless search-and-replace things, like a lot of the ExternalData faction methods no longer have the faction being passed in. That's now handled as AttachedFaction as an embedded field in the class itself.
      • To trick the IDE into fixing over 800+ references that would otherwise have to be done by hand, I simply did a search and replace for the methods in question, which then made them have references to (typically) "Faction faction" that no longer exists. So I made it exist, in the base class. Then used the IDE's rename function (F2) to rename that to AttachedFaction, and presto. Then just delete that temporary variable you made. You can do the same in your mods, if you wish.
      • The reason for gettting rid of Faction as a property on this methods is that it creates ambiguity and the potential for errors. It's just cleaner not to have it.
    • At the moment, I have about 200 compiler errors in DeepInfo, and 2934 errors in visual studio, which is probably vaguely accurate. It's several thousand lines that need correcting or adjusting in some fashion. There's still over 240 references to SpecialFaction_[Whatever], and those will take a mixture of search and replace (when it's checking is or as again), and manual adjustments as I link up the base and deep infos of each faction in particular.
    • Based on the speed of things lately, and the somewhat unknown volume of code that has to be corrected, I think this will easily take me another 2-3 days. I worked through almost all of last weekend, and I hope not to do that again. The picture will become more clear tomorrow and the day after as I get further along.
  • Okay, I couldn't quite leave it for the night. I got autosaves working there's a new AutosaveHandlerDeepInfo class in DeepInfo which replaces what used to be there.
    • Really, all the code is the same, but it just doesn't have any chance of going to a client, and isn't attached to any random factions. The translation of this was literally under five minutes, nice.
  • Got a little over halfway through setting up quick-links between the DeepInfo objects and their BaseInfo counterparts. This includes setting up the DeepInfo objects as singletons where need be, for handy access.
    • As I was doing this, I also made various other corrections and shifts to code as I saw it, and in all the number of errors in DeepInfo are plummeting. There's still plenty there -- visual studio says 2400, which seems about correct at this point -- but the code is thinning out thanks to being better organized (data and data access in one place, logic in another place, and in consistent order and consistently organized in both).
    • I don't want to get ahead of myself, but after a few weeks of being overly optimistic on schedules (or is that just a terminal case for me, one could wonder), it actually looks like I was -- potentially, and majorly knock on wood -- overly pessimistic, this time.
    • THAT said, assuming I do come in ahead of what I was projecting, that's still just going to be leaving more time for me testing for runtime errors and fixing those. It's not like as soon as this compiles it's good to go. I've been coding for almost three weeks now on very long days and over weekends without testing any of it -- because I couldn't -- and if you're a programmer, you know how horrifying that is. All things considered I think I've been very clean with my work in this time, but I expect to find some major gaffes.
    • There's a vague, outside possibility I could have this compiling tomorrow. At the current pace I have observed, it's not outside of the realm of possibility. It's not hugely likely, either, but it's what I'm going to shoot for. I want those two days prior to the weekend for testing and fixing the runtime.
  • Removed some probably-unused-and-unworking code for ships warping in and out over distances. As Badger notes, we have way cooler things to look at these days, and we haven't noticed this actually functioning for a few years now. It was taking up data space, though, and eating some CPU processing, so out it goes.

Moving Into DeepInfo, Part 1

  • ModdableGameCommandExecution has been moved out of BaseInfo and into DeepInfo, after seeing a bit more how it is used and thinking about it.
    • Some nice comments have also been put in there, with two TEACHING_MOMENT entries: one about what the moddable game command things do, and another about how to get data from the host to clients in general.
  • Thinking of trying to minimize multiplayer bandwidth, I decided to make a second Stage3, which does happen in BaseInfo and thus on clients.
    • We want to be relatively careful what logic we put in there, to not make MORE desyncs. But for simple logic in particular -- like zombies attritioning -- it's going to be way more of a desync if this DOESN'T happen on the client.
    • There's a TEACHING_MOMENT note in there for one of the zombie factions.
  • I also changed my mind and am removing DoPerSecondLogic_Stage1Clearing_OnMainThreadAndPartOfSim_HostOnly and DoPerSecondLogic_Stage2Aggregating_OnMainThreadAndPartOfSim_HostOnly from the DeepInfo.
    • We just don't need it, and I don't think any mod that would need that is structured properly. These methods are specifically design around working on the data that is held in BaseInfo, so we don't need a DeepInfo version.
  • Somewhat related, Stage0 -- aka DoPerSecondLogic_Stage0Clearing_OnMainThreadAndPartOfSim_OncePerFactionTypeEvenForFactionsNotInGame_HostOnly -- has been removed from the game.
    • That was simply not something that was ever needed at this point. We have better ways of handling similar things, and the new Stage2A is part of that.
    • Specifically, also a lot of the double-buffered lists and similar make this completely unneeded.
  • The remaining 16 factions (of of 37) have now been fully linked up from DeepInfo to BaseInfo. I was feeling really happy and motivated last night and got the first 19 out of the joy of it.
  • Down to 141 direct compiler errors at this point, and 1782 visual studio errors (which is likely to be pretty close to accurate). There's still a chance I can knock the rest of this out today, but if not then tomorrow is pretty much a certainty.
  • Added a new ExternalFactionBaseInfoRoot, which now sits under all of the BaseInfos for factions.
    • It was becoming really clear that there were some commonalities that needed to become shared, plus a few things that needed to be able to happen on a schedule that is centrally controlled (to avoid some mapgen errors I suddenly realized were possible thanks to a comment by StarKelp in one of his faction files).
    • First of all, we now are ensuring that DoRefreshFromSettings() and DoGeneralAggregationsPausedOrUnpaused() get called from mapgen.
    • Secondly, something that was just an optional convention that I had been using (that being DoRefreshFromSettings() itself) is now a required part of faction base info. It allows for great flexibility without overtaxing the processor.
    • Next, the base implementations for GetRaidDesirability() and GetRaidTraversalDifficulty() now have somewhere appropriate to live.
    • Lastly (for now), this allows us to implement a proper GetFireteamById() rather than just GetFireteamBaseById(), mirroring how faction code used to work.
  • The call to link the faction externaldata into the factions, and also to call DoAnyInitializationImmediatelyAfterFactionAssigned(), has been moved around substantially.
    • The idea is that we want more of the data available as we're deserializing savegames, but when it comes to mapgen we also need to be after-all-factions-but-before-actually-doing-any-mapgen.
    • This should save quite a few headaches for me from after I get this compiling again (I would have had to make these order of operation changes in general).
  • GetFireteamById() has been moved over into BaseInfo where it belongs.
  • All of the pathfinding logic has been adjusted to be where it should or call the new locations of relevance.
  • Added a new AIRelentlessAndBorderAggressionFactionBaseInfoRoot, which is a common ancestor now to AIRelentlessWaveFactionBaseInfo and AIBorderAggressionFactionBaseInfo, mirroring the setup we have in DeepInfo.
  • Stage2 logic was still hanging around in DeepInfo for the following factions and has been migrated over (along with a bunch of other data):
    • Cross Planet Attacker AI subfaction.
    • AI Relentless And Border Aggression root.
    • AI reserves
    • six more to go, at the moment, but AI reserves took... a lot.
  • The AI Reserves faction no longer has dual lists for "sim" and "lrp." It just calculates their data with double-buffered lists, instead.
    • This also includes a new teaching note, and some code that has been adjusted to exist in DeepInfo only, along with some guidelines on why exactly it works this way versus some other way.
    • In other words: how do you know which place a variable or collection should go? This lays it out, with the example of DeepstrikeEligiblePlanets as a guide.
  • Added a new SortThreadsafeCopyOfDisplayList() to double buffered lists, along with an optional TryClearThreadsafeSortedCopyOfDisplayList().
    • See, the problem with the double buffered lists is that normally you sort them ONCE right before you finish constructing them and flipping them active.
    • However, after they are the display list, any number of threads might be reading from them, so to sort then would not be threadsafe in the slightest.
    • To work around that, this method allows any thread to sort a copy of the display list, in a perfectly threadsafe way.
    • This will create some extra data in RAM, very small amounts, which you can clear with TryClearThreadsafeSortedCopyOfDisplayList() if you feel like it. Or it will just be cleared the next time you call SortThreadsafeCopyOfDisplayList() on the same list from the same thread. Either way.
    • This is another addition that has been made thanks to AI Reserves and some of the complicated things they want to do. Their list of eligible planets gets sorted over and over based on distance from other planets they are thinking about, but this is all on a super low priority background LRP thread, so it's fine... except for the need for thread safety.
    • Yep there's another TEACHING_MOMENT in the code about this.
  • Split out some of the waves logic into a new WavesHelper static class that variable factions can use. AI Reserves needed it.
  • "Set the preferred AI faction" logic has been removed from the remaining locations where it existed, since that is now obsolete and handled as parent/child factions. There were over a dozen copies of the same lengthy code all over the place.
    • That then left me with 21 references to PreferredAIFactionIndex, which have also now been converted over.
  • Four instances of DoOnFirstSightingOfFactionByPlayer needed adjusting, and have gotten it.
  • Rather than being a static class, WavesHelper is now a singleton.
    • This allows us to extend that singleton in DeepInfo, and add DeployComposition into there where only DeepInfo can reach.
    • We use the same pattern for FactionUtilityMethods, if you're curious.
  • Necromancer stage 2 and various data has been ported to BaseInfo properly.
    • Good grief this was complicated. It provides a couple of TEACHING_MOMENT items, too.
    • This also shows one of the examples of how we no longer need to precalculate a string (and hit the heap when we do), by instead changing a ToString() method to one that takes in an ArcenDoubleCharacterBuffer and writes to that on-demand.
      • A lot of other classes also do this exact thing now, but SkeletonVariantPercentagesByFleet_ToString() and similar provide a great example of it in action.
  • The necromancer faction is mostly working again in general, but it has uncovered a bit of a problem in my logic with hacking in particular.
    • Right now, hacks are only scheduled to run on the host, but there's a lot of info about "can we start a hack" and such that the client needs to be able to see. I'll have to deal with that.
    • The necromaner sacrifice unit hack in particular is also problematic, because it executes on all clients and the host (well, or just on the host), but is using local-to-one-machine data (selection info). That's going to require some refactoring on my part to figure out how to handle cases like this.
    • I have a similar problem coming up with the sub-types for the sentinels, warden, hunter, and PG. They essentially need some of their stuff in BaseInfo, and some other bits in DeepInfo. I mentioned this last week actually as a concern point that I didn't know how to solve at the time. At the moment, I have a fairly decent idea of a way to handle it, but I need to examine the code a bit more first.
    • I'm down to 2009 errors at this point. Not sure if I'll finish tomorrow or not, at this rate. Which really bites, but it's the nature of the beast, I guess. At the moment I'm fixing some things that were always going to work incorrectly in multiplayer anyhow, so it's not just architecture for the sake of nothing.
  • Moving hacking back into BaseInfo. I'll build in hooks into DeepInfo as needed, but the vast majority of this code really needs to be run as part of the sim.
    • One thing that is interesting about this whole revamp process is that the way that data is available to the UI or where it needs to be is really becoming increasingly clearer, even to me. I knew in pretty great detail what I wanted to do, but there have still been many cases where my intuition was wrong. This is one of them.
  • The necromancer "sacrifice" code and hacks has all been removed. That was going to be complicated, but Badger noted that was deprecated in favor of the Rift hacks. This saves a lot of time! But still helped to identify a problem with how I was handling hacking in general in DeepInfo, so was useful.
  • Now that hacking has been moved back to BaseInfo, there were several hundred errors that needed to be fixed (they were going to need to be dealt with anyway, but now they prevent BaseInfo from compiling again until I fix them).
    • As part of this, moved around a lot of things that are not really worth detailing, and fixed a number of references that were still old-style. It's hundreds of lines of code, but there's nothing really surprising in this batch worth reporting in detail.
  • TerritoryDisputeTeamFactionDeepInfo has had its Stage2 merged into BaseInfo properly. This was needed for some of the hacking stuff, but also just required in general.
  • Added ConstructionContainsKey() to DoubleBufferedDictionary, and ConstructionHasKey() to DoubleBufferedArcenSparseLookup.
    • This is needed to support some of the territory dispute logic.
    • Ah, and it turns out we also need versions for the display dictionary, so those were also added.
    • And it turns out that we also need DisplayContains() and ConstructionContains() on the DoubleBufferedList, so that's also in now!
  • Added a new table called ExternalDeepLink, which lets us define singletons in BaseInfo, which can then be initialized via xml, and then assign their reference back to BaseInfo from DeepInfo.
    • Essentially, this answers the question "how can a modder or faction designer add arbitrary code calls from BaseInfo to DeepInfo without modifying Core code?
    • I actually already use this sort of pattern all over the codebase, and have since 2018. Lots of external classes register themselves with more information than the raw table that loads them has access to.
      • This is kind of complicated to explain in a written note like this, so it will be much better to show examples. I'll have some teaching moments in there, too.
    • The first and simplest example is ExoGalacticDeepLinkRoot / ExoGalacticDeepLink.
      • ExoGalacticDeepLinkRoot is an abstract class defined in BaseInfo. It defines what methods it has, and has a static Instance.
      • Xml states to load ExoGalacticDeepLink, which is in DeepInfo. In its constructor it assigns itself to the Instance variable on ExoGalacticDeepLinkRoot.
      • After this, any BaseInfo code can just call ExoGalacticDeepLinkRoot.Instance.YourMethodHere(), and that will be directed straight to DeepInfo and do whatever it is you want it to.
    • Ultimately it's a really simple pattern, but it's just hard to explain in text like this.
  • We now also have a DysonUtilityMethodsDeepLink, for supporting a number of hacks.
  • Fixed an old and undiscovered pooling issue with ZenithArchitravePerUnitBaseInfo, where it would get into a funky state after being hacked.
  • There's also now a NecromancerDeepLink. And a MacrophageDeepLink.
    • These are stupidly simple to add (just a couple of lines of code), and allow for full control of how you can talk from BaseInfo to DeepInfo. Really pleased with how this turned out.
  • Stopping for the night. At this point, all of the hacking stuff should work now, and is back in BaseInfo but using DeepLink calls where needed to call into DeepInfo-only areas.
    • There are presently 92 compiler errors reported for DeepInfo, which is getting pleasantly low, and last I saw the visual studio error count it was just under 2000 now.
    • This is definitely a tense schedule, but there's a substantial chance I could get this done tomorrow -- to the point where I can start running it and finding all the runtime errors on Friday, anyhow.
    • We'll see how it goes. Honestly there is deceptively high numbers of things that need attention or conversion, but the new DeepLink tool solves a HUGE number of the problems that I was otherwise having trouble figuring out a graceful solution to.

Moving Into DeepInfo, Part 2

  • BuildTerritoryCollection() was called a variety of times in the territory dispute faction classes.
    • This basically just made a lookup, by faction, of what territory each faction controlled. This sort of thing used to be required, but now we can access the factions so easily and they all have double-buffered territory lists already. So we can, happily, skip this and use data we already have.
    • Getting rid of this sort of thing (which previously existed because of either threading concerns or because of difficulty finding the correct other classes' data) is a major win of the new framework. Saves a lot of CPU, and in many cases also some minor RAM GC churn.
    • Note that I'm not particularly calling out the territory dispute faction anymore than I've meant to call out any other faction. They're all coded very well in the limitations of the old architecture. But at various points, various factions illustrate different benefits of the new architecture.
    • Added a new DoForAllTeams() method to TerritoryDisputeParentFactionBaseInfo that also helps offset the need for this method, and methods like BuildTeamCollection().
    • GetColonyShipTargets() and similar are also now a great example of how to reduce CPU usage and GC churn by using threadstatic lists. These are thus also threadsafe methods. Please see the teaching_moment related to threadstatic if you want more info.
  • The "Stage4 Advanced Allegiance Code" that I added a while back to support the territory dispute faction has now been moved into BaseInfo.
  • Added an extension method for DoFor() to Dictionary, giving it that handy same method that ArcenSparseLookup contains.
  • The territory dispute factions (both the parent and the subfaction) are now fully ported over, including its notifications.
    • This was a very interesting use case, because it's very modern and written very well, but also has some unusual stuff like the sub-teams. It's probably pretty obvious, but the architecture has been continually expanding as I see what each faction author wrote in detail and how I need to improve my central tools for them to do their same work in less code.
    • There is a "StarKelp_Question: hey, I was unclear on this logic." note in there at one point, which StarKelp you should feel free to either correct or confirm whenever you like.
  • Down to 63 compiler errors in DeepInfo, and 1818 errors reported errors in visual studio. I'm determined to get through this today so that it all at least compiles!
  • Stage2 logic has now been moved over for the last four factions that needed that pulled out of DeepInfo and into BaseInfo:
    • Dark Spire (also got rid of some ForUI variants of lists, and some list variants "for all factions" when there can only be one dark spire).
      • This also has a great example of some of the old-style codebase stuff, where it had to have a count of spire cities for itself. That's been removed, and it just asks the spire, which is able to say that really clearly now.
      • Also removed the pointless FactionIndex, which was just referring to itself it turned out; that was actually hard to be sure of for a bit. This faction is _really_ old. At one point we probably legitimately needed that to know how the external data connected in to its faction.
    • Templars (also got rid of some ForUI variants of lists).
      • A teaching_moment has been added in there, along with a bit of logic shifting on how rifts are spawned, essentially working around a cross-threading error that would happen but rarely, and it explains how to notice it. The double-buffered lists make it a lot more obvious, since you should not be calling add to a construction list outside of the construction process, and you should NEVER be adding to a display list.
    • Zenith Architrave (removed many ForUI variants, also made serialization of territory and planets ever taken direct now rather than first sent to IDx).
      • Also got it so that their BaseInfo now properly cleans itself up before pooling. (When it was originally coded, it wasn't meant to be pooled.)
      • The way that territory is calculated, and a number of other things beyond that, have been simplified a lot, and hopefully not mangled in the process. Before there were some _severe_ order of operations constraints across multiple passes that these revisions aim to make just happen in order, 1, 2, 3, much simpler.
      • Gah, this one was really a cluster. This is new top prize for hardest faction to transition over. I don't think I messed anything up, but Badger will have to review it, sigh. The logic is probably easier to follow now, though, on the bright side.
    • Nanocaust (okay, this one was shockingly easy).
      • Got rid of yet a bit more really super old deprecated code, and repointed a few variables and it is what it is.
  • Moved over more notififications logic from DeepInfo to BaseInfo, which is one of those really lovely things that lets us have functionality that works properly in multiplayer:
    • 2 from Dark Spire.
    • 2 from ZA.
    • There are still 10 more I need to grab.
  • Many various other redirections from old code spots to new, nothing terribly exciting with most of that.
  • Dark Spire faction is now fully compiler-error-free.
    • Same with nanocaust and Zenith Architrave, and a bunch of other factions.
    • We're down to 44 compilter errors now, and 1594 in visual studio.
    • The Zenith Architrave and the Territory Dispute factions were both way more challenging than I had expected, and the largest faction of them all, Dark Zenith, still needs a lot of translaton work, as does the AI. We'll see what I can do...
  • AI Reserves notifier moved over from Deep to Base.
    • The last bits of the AI Reserves DeepInfo errors are also resolved.
  • Many various other random small improvements all over the place. This is going to last well into tomorrow, sigh.

Moving Into DeepInfo, Part 3

  • Many various cleanups and fixes to the new format.
  • Added a new DoFor on GamEntity_Squad that works on a List<>, like the one that works on ArcenLessLinkedList<>.
  • Added a new HasSimStepRunSinceGameLoad on BaseInfo for each faction, which is set after Stage4 has run on each of them.
    • This is really useful, because Nanocaust had some stuff that it really didn't want to do on long-range-planning threads (it would make wrong choices) until at least one sim frame had elapsed.
    • While looking at that, it became really obvious that this is a problem that other factions would now share, if they didn't already (most already probably did).
    • So now the long range planning threads are blocked from running at all until the first sim-step pass has happened since the game was last loaded (savegame load, quickstart, game start, whatever).
    • To be clear, this is a delay of about 100ms, so it's not really noticeable. But it will make it so that the initial run of long-range-planning is never acting strange because of a lack of data.
  • Nanocaust data is now properly cleaned up when it goes back into the pool.
    • Also removed yet more old frenzy variables that are not used since the advent of fireteams.
  • The nanocaust now uses double buffered lists in place of the linked lists or other formats.
    • Also, the nanocaust has some cross-faction lists, along the lines of what the dyson spheres do.
  • The way that the nanocaust aggregates its data has been converted into the modern format. Well, the NEW modern format, but also the modern-since-DLC1 format, where Stage2 is used for aggregations.
    • Whoof, some of its logic in general, such as for attrition or for constructor upgrades, has been moved to baseinfo and converted a bit.
      • I had to go back and check the older versions of the code on some of this, because the constructor upgrade logic applies to non-constructors and that is how it was coded. I'm leaving it because that seems to be what has been the historical function even if that's not what the code names would seem to indicate was intended.
    • The nanocaust faction is now fully up and ready to run (or at least compile). Ultimately the surgery was not too bad, and things should be more clear than they were before when looking at that code.
  • Moved the remaining notifications over from DeepInfo to BaseInfo, along with the code for generating them:
    • 5 from Fallen Spire.
    • 2 from Dark Zenith.
    • 1 from Nomad Planets (that's the last of any compile errors with nomad planets gone!)
    • 1 from Zenith Miners (and with about six other corrections, all compile errors with the ZM are gone also!)
    • None from sappers, but some outer scaffolding that was prepping for them has been moved.
    • At this point, notifications should again work properly on multiplayer clients, which was one of the sticking points that led to this whole overhaul in the first place.
  • HasSimStepRunSinceGameLoad has been renamed to HasPerSecondSimRunSinceGameLoad.
    • This is already what it did, but it's now correctly named. It's important to note that the long range planning threads won't start for an entire second, not just 100ms. This is of no gameplay significance from a player point of view, but it keeps the data and the factions happen.
    • Both marauders and HRF had nanocaust-style "have I loaded yet?" checks to enforce this sort of thing in an ad-hoc manner. As suspected, this affected a lot more than just the nanocaust.
  • FireteamRegiments have been moved out of the BaseInfo and back into DeepInfo.
    • After consultation with Badger, it became clear that this is purely host-only information, and not something that would need to be seen on the ui in a non-debugging fashion. Therefore, into DeepInfo it goes, to avoid confusion.
  • A number of things on the Marauders faction that had been keeping an index of planets now keep the actual planets since that is now possible. Makes for some added simplicity.
  • After quite a number of changes, marauders now fully compile.
  • The HRF now also compile, with the changes to make them use planets directly rather than planet indices.
  • IPraetorianGuardTypeImplementation, IHunterFleetTypeImplementation, and IAIWardenTypeImplementation have all been removed.
    • This was a really funky way of setting things up in general, and Puffin had already made a todo in the code stating that we should move this into xml long ago. As he noted, it took him forever to find these balance levers.
    • In the more recent short term, this whole design just really wasn't fitting with the new setup anyhow, so it was doubly time to adjust this stuff.
    • AISubFactionDeepInfo now also has been dismantled, since this was just a vehicle for the three above.
    • Xml for all of the above are now present, and you can change a lot of things very easily now that were previously very hard to do! As a modder, this can majorly let you change how the hunter, warden or praetorians act.
    • A lot of the code that was tied to this whole set of structures needs to be reconnected, but I have to get some other things in place first.
  • Lots of other random minor fixes and rearrangements. That got rid of the last of the low-number compiler-blocking errors... revealing a further 1446 errors. That's about what visual studio had been predicting. Woo...
  • Got rid of the last 5 references to "is SpecialFaction_", down from hundreds initially.
    • That left 8 more references to "as SpecialFaction_", also down from hundreds initially. Those are also gone now.
  • The AI type implementations have been moved back into BaseInfo rather than DeepInfo (sigh), and split out into multiple files so that they are easier to keep track of.
    • Technically this stuff is only used from DeepInfo, but it's a real pain to try to sequester it there, and there's nothing about the data of this that would break any of the client/host rules, so... fine. BaseInfo it is.
    • The ability to add per-sim-step or per-second logic on AI types has been removed, incidentally. That was never used.
  • A bunch of the AI Sentinels DeepInfo methods were static for some reason, potentially because we thought we might want to cross-call from other locations or something.
    • Thankfully we were not actually doing that (that would have been a nightmare), so these have been made regular methods and are already private, so they have quicker access to the data of the AI they are dealing with.
  • The way that AI spending ratios are assigned to budgets no longer generates a bunch of garbage for the GC to take care of.
  • DoOnAnyDeathLogic_HostOnly on factions has been renamed to DoOnAnyDeathLogic_MyFactionUnitsOnly_HostOnly, because honestly it was not clear if that was how it works or not.
    • There's another method called DoOnAnyDeathLogic_FromCentralLoop_NotJustMyOwnShips_HostOnly which runs on any unit, so it's vaguely implied that the above one is only for its own ships if you see that, but it's not clear enough for my taste.
    • Because of that, there's a number of cases of indirection (that existed prior to this rework) that I'm able to simplify away. Just working more directly with object references makes things faster, and makes the code more readable.
  • Fixed what seems to have been a bit of a glitch with macrophage not getting any metal income from them killing enemies in some circumstances -- maybe if they did not have a spire telium?
  • Zenith Trader now fully compiles.
  • The way that the macrophage keeps track of its entities has been updated to a more modern interpretation.
  • Added a new UniqueNameForFactionToAvoidThreadConflicts, which defines intentional collisions for "don't run these faction's LRP threads at the same time."
    • This allows us to ensure thread safety even amongst factions with inheritance chains, like the macrophage, lone wanderers, dark zenith, and so on.
    • We had something kinda like this in the past, but it wasn't as good and didn't cross types like this. It had made it so that rare LRP cross-threading issues were possible, that now are not.
  • The macrophage code now compiles, and is a real showcase of how a complicated (but understandable) faction should work in the new code framework.
    • There are a number of teaching moments, and a number of threading things that get explored here.
    • There are also two "BADER_TODO / STARKELP_TODO" entries with questions where I was curious about the logic that was pre-existing, and woudl like more clarity myself.
    • This one is a great one to look at to understand the new format better, albeit with something that is on the more middle-complex side
  • At this point, I'm down to 1124 compiler errors. This is taking MUCH longer than expected, as everything seems to have with this process, but it's worth it.
    • There are some things related to hunter, warden, and PG that are just commented out right now, which I'll be re-enabling later as I get their patterns fixed up to hook them back in.

Moving Into DeepInfo, Part 4

  • Got rid of the visual studio solutions that had the base game and dlc xml in themselves separately. Instead, combined both into a single solution that has the separate projects from each of them in it. This makes searching and replacing a lot easier, and I don't know why I never did this before.
  • The death effects have been fixed up in DeepInfo:
    • Zombificiation of all sorts.
    • Metabolization and Necromancy were already fine.
    • Nanocaustation.
  • The AI Sentinels DeepInfo class is now down to 5 errors (from hundreds), and uses its new structure to the fullest. It should be much easier to read, and it doesn't have to do subfaction lookups and such nearly so often.
    • The remaining 5 errors are related to parts of subfactions that I have temporarily disabled, so I need to get those subfactions all fixed up and then those 5 will go away.
    • Total error count is now down to 1090.
  • Set up a new AISubFactionCoreDataRoot to live in BaseInfo under the sub-data for Warden, Hunter, and PG, since those all have a certain type of data involved.
    • This makes it so that they can now reach back out and talk about their parent faction with ease, rather than having to have a faction passed in and then fumble around to find it on the faction like was the case in the old architecture.
    • This actually pulls in pretty much all of the code that used to live in IndependentFleet, and translates it into the new format. It is vastly more brief code now, and I put like five different TEACHING_MOMENTS in there.
      • In particular there's some great teaching moments about the threading model of the entire game, and the System.Threading.Interchanged class and how to use that, and cross-thread-safety concerns in general.
    • This section of code (and the three subfactions that ride upon it) was the one I was most worried about coming into the weekend, so I'm glad to see it looking so well.
  • Warden logic that was previously on IAIWardenTypeImplementation has now been moved to AIWardenCoreData.
    • ReceiveDonation is a really straightforward copy-paste from where it used to live. Now it's in BaseInfo.
    • The rest of those other things now have migrated over to live on top of the framework that AISubFactionCoreDataRoot has built. It's wonderfully simple by comparison to what it used to be, and the code is also much closer together and doesn't have an interface in between the definition and the implementation.
  • Added a new MapgenDeepLink, which lets me handle things like seeding the base-oriented warden secret ninja bases. See how handy this pattern is? It literally can be used for anything.
  • The "HunterFleetHelper", which I had created only for a little time, has gone away. This is what was on IHunterFleetTypeImplementation at one point.
    • The translation across for this was a ten minute job, after spending hours getting the general framework up to make this and warden and such actually work. Nice.
  • The Praetorian data went even faster than that, excellent.
  • The SetSpecialTargetPlanet command has been removed from the game, because it existed just to send data to the client which was basically host-only (and which is set in a different threadsafe manner now from the host).
    • There's several teaching moments in the code related to this, but essentially it was a pointless game command that just increased complexity a bit without actually solving any issue in the way multiplayer and the faction logic actually turned out.
    • Speaking of, in this check-in the CurrentTargetPlanetIndex moved from being a core thing on every external faction's BaseInfo, to only being a thing that the hunter, warden, and Praetorian share. Nothing else uses it.
  • The UpdateFireteams() method on factions has been removed, because it was possible for someone to unknowingly just directly set NumFireteams.
    • Numfireteams is now a property whose setter does the logic that UpdateFireteams() used to do.
  • The UpdateFireteamSizes game command has also been removed.
    • On the surface, this might seem a bit like bad form for multiplayer. We are changing something sim-affecting, after all... kinda.
    • But the fireteam logic all pretty much just runs on the host, and -- again -- the faction data is transmitted very frequently to the client, anyway.
    • It's more economical in all senses to just directly set the NumFireteams on the faction directly from the external code that used to call the gamecommand.
  • Those last errors in the AI sentinels faction code that I mentioned earlier today are now gone, and the hunter faction code is now also error-free.
    • Praetorian faction code is now zero errors, and so is the warden.
  • Also, while I was at it, in the xml for the warden I took their default multipliers for how they gauge enemy strength and their own strength and moved those from being 1.5x enemy, 1.0 self, to instead being 1.0 enemy, 1.1 self.
    • This will make them considerably more willing to help out, even on planets where they may be outmatched. We've had off and on comments for a long time about the Warden being a bit too passive, and this will change that. If it's too much, we can tweak the xml, or make variants, or whatever else.
    • Since this is controlled by xml now, end users can experiment with it with just a text editor, or modders can make their own versions of the warden who act differently, etc. No code required.
  • Stopping for the evening and my total remaining compiler error count is now 935. That should be pretty accurate, and is the first time we've been sub-1000 errors since starting this whole process a long while back. At the height it was over 7000.
    • I still have some pretty heft factions to deal with (Fallen Spire, Dark Zenith, Scourge, and Sappers are the big ones, with Dyson Sphere also clocking in a lot of errors right now as well). A few other factions have a handful of errors (Migrant Fleets, Astro Trains, etc), and some mapgen code also needs a few fixes. But it's definitely feeling like the downhill slope now.
    • The AI cluster of factions was the thing I was most worried about working on, and I commented about my worry about the Subfaction interfaces a couple of weeks ago when I ran into those and remembered them (they were my doing, I believe, but I had forgotten about them). As of today, that part is all done, which is a giant weight off!
  • Fixed up how the AI Start Sizes for AI empires work in mapgen now that the code for getting their settings has been adjusted.
  • The other handful of compiler errors in mapgen are also now fixed.
  • A handful of errors in various factions that were otherwise okay are now fixed, leaving mainly the big factions to deal with.
    • Also two small errors in TargetListPlanning.
    • And nine in EntitySimLogicImplementation_DeepInfo.
    • Six from FireteamUtility.
    • Four from FireteamExtensionMethods.
    • Two in SpecialFactionPlanning.
    • One in ExternalFactionDeepInfoRoot.
  • Okay, now actually it's time to deal with some Fireteam change that are required, because they give funky results on the clients.
    • TargetPlanetIdx is gone, just leaving the actual TargetPlanet. The only reason for TargetPlanetIdx was because of the order of serialization in the past.
    • Same deal with TargetID, LurkPlanetIdx,
    • Also, DoEarlyCleanupWhenGoingBackIntoPool() and InitializeToDefaults() have had their code merged to make them not duplicate one another.
    • Made a few of the serialized variables that are stored here more efficient, too, since there are a lot of fireteams being transmitted around.
  • FireteamRequiredTarget has been made more efficient to serialize, and on the CPU. It requires fewer lookups during runtime, and has the data it needs on demand.
    • In order to fully make this work for the AgainstSquad, that now uses a LazyLoadSquadWrapper, but for the factions and such that's already handled.
    • This in turn prevents us from having to cache some information on the Fireteam itself that was just kind of copies of this.
      • Those fields on Fireteam are now instead properties that wrapper the FireteamRequiredTarget. This will actually work properly on MP clients without having to have them run UpdateNonSerializedFields(), which was a problem up until now.
  • Whew, okay, fireteams are really problematic. They have a lot of host-only stuff that gets fed into the UI, and it's really hard to tell the parts apart.
    • I've improved things quite a bit so far, but there's nothing there that will keep the problem from recurring at the moment (it's a case of easy to shoot yourself in the foot when adding functionality to fireteams, right now).
    • I'm currently checking in what I have on this front so far (with 904 errors left, incidentally), and then seeing what I can do to actually split this out so that not all of the Fireteams functionality exists in BaseInfo. There are parts that frankly just need to exist in DeepInfo so that we don't do this foot-shooting thing.
    • Right now it's mainly a matter of the MP clients are going to be incredibly spotty in what they show properly in their tooltips about fireteams; the actual gameplay of them acting properly is fine for MP and SP.
  • The hunter and warden types now properly load again from the settings in the lobby. This was just one of those things I had not ported over.
    • Vassal status now also loads properly, and centrally for all factions in an optional way, which is nice.
  • The starting fleets and battlestations and such for human empires now load properly again. This again was a matter of porting over the existing stuff.
  • And finally, the last of the lobby fields, the trim colors for AI subfactions, are also now ported over.
    • There's a slight chance they may be a bit janky either in the lobby or after, but I think it will work this way, and it's more efficient. I have a couple of lines commented out that will fix it (but do more CPU work) if it's actually a problem.
  • Fixed a few more things here and there, Devourer and some exogalactic bits.
  • The Scourge faction has been mostly updated, except for the parts where the LRP thread does some things that would violate the normal double-buffering pattern. I'll deal with those when I am feeling more fresh.
    • For now, got rid of several hundred errors in the Scourge for compilation, and now there are 4 left. One of those is related to some fireteams changes I still need to make (I have a great idea on how to do it now, but I'd like everything else cleaned up first so I can see my work more easily).
    • Overall error count now down to 613. That's really it for me tonight, now.
  • The Sappers collection on the Sappers faction is now DoubleBufferedConcurrentList. All the others were fine without the concurrency.
    • Oops, no, actually FloweredCrystals also needed that.
    • Okay, the sappers are fully compiling and ready to go. That's us down to 73 compiler errors.
  • Hjarnum on Dark Zenith is now DoubleBufferedConcurrentList. It seems to be the only one there that needs that pattern!
    • Sigh. That said, it needs to be sorted, which is incompatible. So we also now have a SortedHjarnum that we build at the same time and sort. This is apparently only used in the UI, which is handy at least.
    • Almost all the errors are out of the Dark Zenith faction now, but there are a few things that I still need to look at in the morning when I am more fresh. I was working until 1:30am last night, and then back at it at about 8:30am this morning, so I'm not the most fresh.
    • That said, the total compiler error count is now... 6.
    • Tomorrow morning I'll need to sort out these last issues with the DZ, and then get the fireteams split I have planned done (it shouldn't be too bad, knock on wood), and then correct a couple of vis-dll errors that should take under 30 minutes, and then I'm on to actually... runtime testing!
    • This whole process has taken enormously longer than I ever expected, but the end is finally in sight. If I don't have at least a compiling version tomorrow, then something is very very wrong. Honestly if there's not one by lunch I'll be shocked.

Moving Into DeepInfo, Part 5

  • Removed the ConcurrentDictionaryExtensions class, and merged that into the general DictionaryExtensions class.
    • Added a new DoFor() extension to ConcurrentDictionary via extension, the same as we had previously added that to Dictionary<>.
  • Astro Trains had a few enough number of errors in its file -- 63 -- to actually have them shown properly in visual studio.
    • Oof, but its BaseInfo was not using double buffered lists, and the way that it was aggregating train guards was... fraught. So let's fix all that up, and also serialize less while we're in the process.
      • AstroTrainsPerTrainBaseInfo now has a pair of double buffered collections, which is the first time we've used that on per-unit data, but it's actually a great way to store things in the new framework. I haven't needed this before now, but it's a very useful form to use.
      • We also no longer have DeployedGuardsPerTrainSim on the BaseInfo. That's now being handled on the actual trains, rather than via an indirect lookup. This solves a lot of code complexity and chances for orphaned data. It also uses less CPU to calculate in the new format, though in the old format of the game it would have been debatable.
      • This actually has turned into a rather fascinating study of nested data. It's quick and easy to understand and a pattern to be emulated. This is actually kind of a great showpiece for the power of the new system.
      • This turned out to be SO useful that I've put a teaching moment in there.
      • Improved the description appenders for trains to be a bit more informative now that they are able to be.
    • Okay, back to the astro trains deepinfo file, how many errors do we have now? 71, okay.
      • Well, we can safely get rid of DeployedGuardsPerTrainLRP, StationsLRP, and TrainDepotsLRP.
      • TimeLastDepotSpawned was not consistently called, so it has been moved into SpawnNewTrainDepot. Same with AstroTrainsPerDepotBaseInfo being created and attached to it.
      • initializeDepotData has been removed and made part of the depot creation process.
    • The guards code was really confusing because things were not named very clearly. The guards on the train are now called StoredGuardsInsideThisTrain and DeployedGuardsOfThisTrain, so that it's clear that's how this works.
    • The way that guards are stored for finding lost guards, and the way that they attrition, has been moved into BaseInfo (and thus runs on the client as well as the host, which is good), and is also a lot simpler to follow now. Same general logic, but it won't miss anything by accident.
    • StoredGuardsInsideThisTrain was an ArcenSparseLookup, which was a cross-threading problem waiting to happen, but it can't use the double-buffered style collections because that's not what it is (it's actual stored data). So this is now a ConcurrentDictionary, and there's a teaching moment in there explaining why.
  • Silly me, I thought that Astro Trains were going to be a very easy faction. But it turns out there was quite a lot going on there that was really really out of date for the codebase, so... here we are.
    • Down to 551 compiler errors left.
  • Okay, let's see what's going on in the Fallen Spire deep infor class. I see 85 errors at the moment, mainly so low because I've been in here before quite a bit, but not with my full attention.
    • Most of that melted like butter in under five minutes. There was a funky thing with the journal logging that wasn't very clear, but that was something that the svn history let me clear up and then document pretty easily.
    • Transceiver needed to be converted into a DoubleBufferedValue. From the look of this class, this was before I added that specific item (in the distant memory of last week).
    • Oh... wow, what an error on my part. Coding while tired, I guess. This was also one of the earlier factions I started the conversion on, and then I had set it aside. All the BaseInfo Stage2 stuff was in DoFactionGeneralAggregationsPausedOrUnpaused instead, which runs WAY too frequently. Talk about a performance drain. Glad that code never released.
      • I also untangled the double-buffered clears and switches from the logic that fills them, which is what all the other classes I've done more recently were like. It's amazing how that takes this from unreadable to really nicely legible.
    • Okay, even so with all the oddness in BaseInfo, this gets me down to two errors remaining in the DeepInfo class... and they are the same sort of nastiness that I've seen in several classes when working with my nice new double-buffered lists. They just... aren't sufficient for a lot of the code that exists in actual DeepInfo classes. I'm particularly unhappy with the butchering that I did to Zenith Architrave; I think I may revert back out that entire class to before my last pass on it, and redo it more nicely. But before that, I need a double-buffered collection that supports concurrency; one that is used for spire cities and debris (thus solving my last two errors here), and which then is also used on Zenith Architrave (thus returning its logic to what it used to be). What I had expected to be an edge case actually turned out to be a really common case, so new data collection it is.
    • I'm down to 468 errors, but I'm going to pause on forward-progress for a bit, add my new data structure, and then undo all of the likely damage I did to Zenith Architrave.
  • Added a new Engine_Universal.DEFAULT_CONCURRENCY_LEVEL, which is set to 4. This should be passed into every ConcurrentDictionary in the program as the default concurrency level (and then choose yourself what the starting capacity for that dictionary should be).
    • Why does this matter? https://blog.getpaint.net/2017/06/30/concurrentdictionary-allocates-a-lot/
    • Engine_Universal.DEFAULT_CONCURRENCY_LEVEL is the default level of concurrency that we are likely to need in AI War 2, based on my designs for threading. If more threads than this are accessing a ConcurrentDictionary at once, then performance will suffer slightly, but not much.
    • The default concurrency level is actually 4x the logical processor count, which is... insanely too much, and wastes RAM and performance when it comes to high-CPU computers. I only have 8 phyical cores with hyperthreading for 16 logical processors, but that means that it is creating (for me) literally 16x more RAM usage and locks than are needed. In the future, as computers advance, the design of this program is such that it will still use plenty of processors, but not on an individual dictionary basis.
    • So we'd start seeing MAJOR performance degredation and memory spikes if 128 logical processors were ever a commonplace thing, etc. Now we won't. Yay futureproofing. And honestly, it helps for performance NOW, too.
  • Added a new DoubleBufferedConcurrentList. This is a lot like DoubleBufferedList, but less efficient in some ways, and more powerful.
    • This one also needs to support the display list taking additions and working as a working list for background threads. This tends to be a case where something says "oh hey, let me look at what is there, and also let me add this one," and then the rest of that background thread needs to have access to thing that was added RIGHT NOW.
      • For example, this sort of thing could happen on Stage3 or in LRP or both, who knows or cares. Either of those is still happening while the UI is using the same DisplayList as the others.
    • There's no way to handle that without using a concurrent list, and you might think that would be enough to avoid flicker in the UI, but it's not. The flicker would come when the construction list is torn down and then rebuilt, since that is often on a (different) background thread.
      • So we need to always have persistent lists, and support ad-hoc additions to the display one as we go, while also supporting the common cycle of construct-clear, construct, flip-to-display.
    • Sidebar: Internally, we are using a ConcurrentDictionary to power this. What... the heck?
      • Well, there is no "list" class in the .NET Concurrent collections, because the idea of an ordered list is antithetical to cross-thread ad-hoc addition and removal. They have ConcurrentBag and ConcurrentQueue and a few other things. ConcurrentQueue is vaguely ordered, but the main point is that it supports the foreach operator, and also supports direct removal and additions. Throughout the codebase, I have preferred ConcurrentQueue to ConcurrentBag because of profiling work that various other programmers have done, demonstrating that Microsoft's implementation of ConcurrentQueue is slightly more performant. That said, neither of those classes -- nor ConcurrentStack -- support the Contains operation. There isn't any equivalent of a ConcurrentHashSet, either. The only collection that really supports all of what we want to do is ConcurrentDictionary, which has some performance drawbacks, but not too severe to be worth it.
      • If you CAN use DoubleBufferedList<>, then of course use that instead. That thing flies. Start with DoubleBufferedList<>, and if you find you need to graduate to DoubleBufferedConcurrentList<>, then do so.
    • Implementation notes:
      • You will notice that there is no GetDisplayList() like you are used to seeing all over the place with DoubleBufferedList<>. Instead, you must use DorFor on it to do the equivalent of a foreach loop (which you can break out of as-needed).
      • There IS a Contains method, but there is a (very very) low chance that it will return false when the answer is really true.
        • Because of that, there is an int TimesToRecheckIfSeemsLikeNotThere = 0 parameter to this method. If you REALLY need an accurate Contains, you can set that to something larger than 0, but be aware that has a peformance impact that is equal to calling the Contains methods however many extra times you say.
      • Since this is a dictionary under the hood, you can't put the same item in the list more than once. Or rather, if you do, they will just collapse down to the unique set.
        • This is actually useful, since typically adding something repeatedly is an error anyhow. We specifically have some things like AddPlanetIfNotAlreadyInList(), but you do NOT have to do that. That's implicit in this structure. For goodness say, definitely do NOT call "if not contains X, then add X," because you just wasted some CPU cycles for nothing in that case. Just add it.
      • Since we are specifically wanting to be able to modify the display list on the fly (that's why this variant of DoubleBufferedList<> exists at all!), there is of course also a new AddToDisplayList() method.
      • As a consequence of this being a concurrent collection, you can forget about any sorting methods. The normal DoubleBufferedList<> supports sorting, but this version does not. You'll have to feed the results of a DoFor operation into some local working list and then sort that if you really must combine sorting with this sort of list. But in general, I haven't seen any cases where that would be relevant.
      • You may have noticed that none of the DoubleBuffered collections suport IEnumerable (so you can't do foreach on them). This class is no different. The reason is because that would be a highly ambiguous call. Someone might do a foreach while thinking they are doing list construction, or they might do it while thinking they are looking at the display results. Lack of clarity like this is very bad, because a second programmer following behind you can't even tell with ease if you made a mistake or are doing what you mean to. So instead we have the DoFor variants.
  • Went ahead and added a Display_DoFor onto DoubleBufferedList<>, so that it has the same style of functionality as the concurrent one from that angle.
  • Added a new Display_GetRandomItem() on both DoubleBufferedList<> (just to save code, and it's very efficient), and to DoubleBufferedConcurrentList<> (this is not very efficient at all, but it works; and in most cases of relevance in our codebase, these lists are so small that it's plenty efficient ENOUGH).
    • Normally you can't index into a dictionary in the way we would want to in order to get a random return value, but our code would often need to do this on the LRP in particular with DoubleBufferedConcurrentLists, so now it's possible.
  • For Astro Trains, they are now the pilot for DoubleBufferedConcurrentList, with TrainDepots and TrainsEnRoute now using them.
    • This was definitely a major diversion off to the side, but this keeps the code for the end product of the game as close as possible to what it was in the past, and thus lowers our risk of new logic errors or just incomprehensible code. It's time for me to completely redo the travesty of what I visited upon the Zenith Architrave a few days ago, now that I have this tool.
  • Reverted the Zenith Architrave to svn revision 14224. Ugh I hate undoing work, but that was really a hash. This brings me back up from 468 errors to now 539 errors.
    • My goal this time is to use the double buffered concurrent lists to accomplish keeping the logic of the ZA intact, rather than trying to rewrite it and hash it up like I did on Thursday night. I had noted even in my checkin notes on Thursday that it was a hash, which is never what you want to see in your checkin notes.
  • Fixed all of the non-controversial errors with the Zenith Architrave, which took only 20 minutes by my reckoning (I'm getting much faster!). I had temporary working variables to quiet certain errors related to the central lookups that are now going to need to change.
    • I am first checking in this version that has all those changes in place before I start changing the bits that need the new collection types. With the temporary variables back out of there, I'm back up to 75 errors from this file, so that's quite a lot related to them.
    • Also worth noting is that I'm not messing with the LRP collections at all. This class is complicated enough that they may as well just keep doing what they do. I don't really want Badger to have to come in here and review this code like I had asked him to before, and at this point I don't see a reason why he should have to.
    • 543 errors in total for now.
  • Okay, got the next batch of ZA fixes in place. All of them except the WarpingInSpawners and the Castra are able to use the normal DoubleBufferedList. That's easy enough.
    • If I were to extend this to the LRP variables, which I think I did before, then that would cause some need to use the concurrent version more. But that would be a net negative in terms of performance, so I'll just leave LRP doing its own thing, giving more room for the sim and UI to share work/benefits with one another.
    • At this point there are 17 remaining ZA errors, and those will be solved by me converting the Castra and WarpingInSpawners to the concurrent double buffered list.
    • This time around, the flow of logic is preserved exactly as Badger wrote it, and there's no longer a need for a code review of this faction.
  • WarpingInSpawners and Castra are both now DoubleBufferedConcurrentLists.
    • WarpingInSpawners previously was sorting itself after the initial creation of its list, but that's no longer a possibility with the new collection format.
      • The logic that was relying on this sorted list was kind of complicated, so it was easiest just to implement a secondary SortedWarpingInSpawners that we feed from the concurent list and then sort like we did before.
    • That's a wrap on ZA. They are now error-free, and no longer in need of a code review any more than any other part of the codebase now is.
    • Back down to 468 errors.
  • Clearing "two" errors on the fallen spire took 35 minutes and generated tons of other things that had to be converted. But nevertheless, the fallen spire is now error-free:
    • Spire Cities and Spire Debris are now using a DoubleBufferedConcurrentList.
      • However, because spire cities in particular ALSO need to be sorted half the time (sigh), there is now a SortedSpireCities that is built for mostly UI purposes.
  • GetScourgeStateForDisplay now includes information on fortresses. Previously it just had armories and spawners.
  • The three kinds of "warping in" collections on scourge now all use DoubleBufferedConcurrentList. This was about a 10 minute job for "three errors."
    • Other than one fireteam-related error which I am intentionally leaving to the last (it's a structural thing that I need to be able to see in isolation to fix), Scourge are now error-free.
    • Total error count now 463.
  • Fixed right about 60 errors that were remaining in the migrant fleets faction code (22 were obscured from the compiler until I fixed the ForEach they were in.
    • This was jolly easy and pleasant, nice. 425 errors remaining.
  • Fixed what was reportedly originally 38 antagonized dyson sphere errors, but wow that was kind of a mess in general. They're all fixed up now, and probably for the first time ever we're not mixing up data of the antagonizer and the dyson spheres themselves, which makes the whole thing a lot easier to follow. Previously they had kinda-sorta shared an external data object, but not fully, and that made it a bit confusing to untangle.
    • Anyhow, I happened to also notice that AntagonizedDysonDescriptionAppender is not actually used on dyson spheres at any point from what I can tell. Maybe this was deprecated on purpose, but it would be functional if someone wants to attach that to a dyson sphere that's being antagonized.
    • Error total is now 394. Other than the fireteam stuff that will be at the very last (and some vis-layer stuff that is incredibly minor), this is down to mostly the Dark Zenith and the Sappers. Oh, and apparently the Dyson Sphere proper has 63 errors, too, I now see.
  • Well, that was again pleasantly straightforward: dyson sphere faction is now error free. New compiler error count is 332. Time for the last two big guys.
  • Decided to make the safe changes first, and hit low-hanging fruit, in case I make another mistake again like I did with the Zenith Architrave.
    • Sappers are down from 119 errors to 45, and what remains to be done with the rest of them is a lot more clear.
    • Dark Zenith are down from 211 errors to 71. It looks like Sappers and Hjarnum will need to be concurrent, but none of the other lists, which is excellent. Additionally, a couple of methods need some adjustment based on working lists, but that's not too bad. All told, this faction was less intimidating than it had seemed, thanks to judicious search and replace. Zenith Architrave was the more challenging one structurally, even though Dark Zenith is more complicated in general.
    • Total compiler errors are now down to 117, which is... insane! I was happy just to get to three digits today, after being in the high four digits for weeks. Now we're almost down to two digits!

Hunting Runtime Errors, Part 1

  • The last of the non-fireteam compiler errors are now fixed. Time to get the last fireteams bits fixed up and that will be that!
  • The text-export portions of fireteams are being merged back into the main file of Fireteams.
    • A new FireteamHonoraryDeepInfo object has been created, which exists as an immutable sub-part of every fireteam. On MP clients, this sub-part is ignored and unfilled.
    • There are detailed teaching moments that explain the thought process behind this, and how to mimic it for other data if you ever need to (as a main developer or a modder).
    • PreferredSpeed has been moved to be a serialized field, so that it can be shown on the UI on clients and hosts.
    • Removed some string construction that was happening overly-frequently on fireteams even on the host/singleplayer cases. It now only happens if you're actually looking at the debug menu in question.
    • For the first time since it has existed, our DeepInfo dll (AIWarExternalDeepProcessingCode) actually compiles!
  • The 23 errors from the external vis dll are also all now fixed.
    • Running our complete build scripts to verify that everything compiles... yep! We are officially on to runtime errors now. Time to start up the game for the first time in three weeks (time for that to be possible for the first time in three weeks, internally).
  • Fixed a bug in GetIsDescendentOfInterface() that was causing false positives.
  • Corrected GameEntityTypeData to not require BaseInfo or DeepInfo for units. Most of them will have neither, and so far no units have needed DeepInfo.
  • Fixed a couple of xml typos that were preventing proper parsing.
  • For the sake of clarity, IArcenExternalClassBase has been renamed to IArcenExternalClassRoot.
    • We don't want this to get confused with BaseInfo, because that's not what it is (but it was sort of what it looked like).
    • ArcenCachedExternalTypeBase is now ArcenCachedExternalTypeRoot for the same reason.'
  • Verified that my logic is working for checking if BaseInfo and DeepInfo (true DeepInfo, not honorary) are living together in the same dll.
    • As I had kind of expected, it's tripping on my own code at the moment, which mostly means I have some things miscategorized.
    • This exception checking is here to prevent accidental mixing of this data that is supposed to be separate, including dlls referencing dlls that they should not have access to.
      • Essentially this sets up a boundary where it tells programmers (modders, later, but for the moment myself) "hey, you're either arranging this wrong or you've tagged things wrong, but either way fix it because bad things would happen in multiplayer if you do not."
  • Now that I have verified that the above works, a whole bunch of debugging output that was related to that has been turned back off.
  • Fixed all the map definitions still pointing to the wrong dll from their xml.
    • Ditto for the TargetEvaluators.
    • Ditto the AIDefensePlacers.
    • And DeathEffects.
    • And GuardpostAndCommandPlacers.
  • Fixed an issue where the xml tag multiplier_to_all_fleet_caps="0.2" was still being used on a variety of outguard units, which I don't think had any relevance for that at all.
    • Also some sappers turrets, and a ZA turret, etc.
  • Then there was an unexpected multiplier_to_all_fleet_caps="1.34" on:
    • Golden Wasp Drones, which made their cap 536 instead of 400. Let's make that 540 just to look tidier.
    • Queen Bee Drone, normal and Dark Zenith versions, ditto.
  • Milestone: I can get to the main menu without any errors at all! It took just over 1 hour from the point of being able to compile at all to get to that point. Now I'm going to break for lunch, but it will be interesting to see how long it takes to get the rest working. It's nice to see the main menu again!
  • Fixed an issue with the Source not being properly linked to each of the four PrototypeObjectForGlobalLobbyClearingOnly objects for the new externaldata, which led to an immediate exception when trying to start a game.
  • Fixed an one-line code error that broke the new sub-faction linkages for the AI. They needed to be after a loop, not inside it, and it was one curly brace too early.
  • Fixed another one-line error that mixed up relentless wave linkages from DeepInfo to BaseInfo.
  • Fixed an exception where Outguard mistakenly thought they were supposed to have an Intensity (they are not).
  • Fixed a minor issue with order of operations with the lobby partial-map-generations not linking up parentages properly.
    • This was technically working by design, but this was from a few weeks ago before I knew the shape of things to come. It needed to be changed a bit in light of the final design.
  • Fixed another issue with Allegieances, where every faction was expected to have one (but many invisible ones don't, in particular).
  • Milestone: I can now open the lobby without errors. I took a long lunch and ran an errand, so this was about 1 hour of work since I got things working to the main menu.
  • Fixed up how the faction external data was linked to its "attached object" (faction or squad).
    • Previously it did it way too late, and therefore some errors were resulting.
  • Started tracking the way that faction external data is linked to its attached faction, because I am getting some strange nullref exceptions.
    • By assigning cross-thread-safe unique IDs, I can see that the version of the faction data that we have in the lobby for use is very different from the one that previously had itself assigned. Curious!
    • Stuff like this is central and breaks every faction, and is just part of the framework itself being tested out for the first time. This is the sort of thing I was hoping to see, and not a thousand little per-faction errors. I may yet see a tide of those later, but at any rate this current part is just a normal part of unit testing after coding for three weeks without being able to test any of it.
    • At this point, I can see that we have a minor memory leak of factions again, without having to even look the memory dumps and diff them (which I will do, later, when all of this is working better). Nice to find this out sooner than later.
  • BaseInfo and DeepInfo on factions and squads are now carefully-managed and sent back to their pools more aggressively.
    • ...That did nothing, unfortunately, to help my actual problem. It does make the code easier to read, and it's hard to say beyond that.
  • Fixed things up so that BaseInfo and DeepInfo actually get put back into their pools when they are supposed to.
    • This helps a little bit, but there's still a central leak with my pooling framework, which is a surprising thing to learn at this point. I thought I had established that as solid a while back.
    • Then again, back when I was establishing it as solid, I had noticed that it would increase to about twice what I expected, and then stop. So it was using extra memory, but not infinite endless memory. This may be related to what I'm seeing now, which I am going to fix because it causes problems for me on several levels.
  • Added a new GetItemsWaitingInPoolRightNow() and GetItemsInTheForeverList() onto TimeBasedList, to help me see what's going on as the factions are pulling external data out of their pools (right now they create too many objects, and I want to know why; after that I'll still have to deal with the problem of improper item teardown, but one thing at at a time).
  • Discovered that a variety of pools were not using their original entity (the "creator entity") for actual data storage. For the larger objects, where there are just one or two per type, this is very wasteful. Read: factions.
    • In the past, I've always just really cared about things like entity orders, or squads, or whatever else -- and the difference of literally one object is super stupidly negligible. For a faction, it's an extra 100% usage of RAM, by comparison.
    • These pool types now include the creator entity as a normal object to use, just to remove this confusion and slight waste (it can still do its job as an object factory no matter what else is happening): TimeBasedPool<>, BetweenMapGenPool<>, and ConcurrentPool<>. I think that's all the major ones of relevance.
  • Immediately after that, started having some exceptions in Recalculate_PreSystemRecalculate() on initial game load (before getting to the main menu), which is curious but not completely out of character with some OLD issues I've seen off and on sine 2018. Let's get that fixed.
    • For now, Recalculate_PreSystemRecalculate is being instrumented.
    • Based on this, fixed an issue with AIWar2GalaxySettingTable.GetFauxFIntValueFromSettingByName_DefaultOne_DuringGame() and all similar methods where it would give an error if those were called prior to the game being fully initialized.
    • Based on this, also fixed an issue with GetResourceProductionBeforeAnyBonuses() where it would also error if called prior to the world being initialized.
    • Same with GetFrameSizeMultiplierAsDoubleNonSim().
    • Did a further bunch of hardening of a bunch of other places, several dozen; mostly windows.
    • Worth noting that none of this code was changed during this refactor. This is an old issue that is only triggered by certain rare circumstances that -- for whatever reason -- become common during this pooling shift.
      • On the whole, this is not the sort of issue I was expecting to chase today at all (something unrelated to the work of the last three weeks), but there's always the chance that this has been secretly breaking for a rare subset of players, so let's make sure it works.
  • I think that the world is actually being set to null for some reason, possibly because of the world itself being pooled in a funky way...
    • So let's fix THAT: The three pool types noted above all now have a CreatorEntryIsAddedToThePool parameter. Now it's up to the calling code to decide how to handle it.
    • True on everything except: PlayerAccount, World (the first entry in that is a "dummy world!"), ConfigurationForFaction, EntitySystem, SpeedGroup, PlayerAccount_AIW2, and World_AIW2.
    • The game now loads just fine to the main menu again.
    • Also, the lobby faction tab no longer spams errors about a missing faction link! So I DID solve the problem I was originally chasing, but just in a really roundabout way.
      • This made me suspect that entering the lobby multiple times in a row, or otherwise serially regenerating map types would be a problem. But nope, those work great also.
      • Adding multiple AI factions works great, and adding extra human factions also works.
      • However, after adding two extra AI factions and then another human faction, I did get an error where the AI subfactions were not linked to their parent AI faction in the case of all three AIs. So I'll have to look into that, after I can duplicate it more.
      • Also, reading last-lobby-settings seems to be broken at the moment, but that's fine. Just adding that to my list.
      • Starting a new game from the lobby is also broken, but this is probably unrelated to anything I've done thus far; this is the first time I've tried clicking that button today, and the place it errors looks like a sensible place for a one-line typo.
    • So, I'm going to call this current line of investigation complete, and move on to the new list of errors that I have accrued to look into. (As kind of an aside, I was fully expecting to have serialization be broken in the new version, as that's really hard to do completely correctly en-masse. I built in tools a couple of years ago that makes it trivial to find those errors, generally, but it's not my top priority right this second).
  • Milestone: I can click around the lobby, add factions and such, with very few errors (though not zero yet).
  • The game now does a handy dump of all the faction basics when it runs into parentage issues.
    • See, back when I was originally designing the parentage stuff a few weeks ago, I had not wanted the subfactions clogging up the lobby for very good reason -- it's the reason I'm having some exceptions now, in fact; old stale sub-factions get left around. Having the subfactions earlier than later is actually better overall, I just need to have them clean themselves up between mapgens now, basically.
  • Using the above, the game now properly removes and adds all the various factions and subfactions. No more errors on that front, or mis-parenting of factions, or duplicate factions, using any routes that I can tell.
    • I do see there is still an issue with null attachedfactions sometimes on factions added via the lobby, but hitting the map regeneration button fixes it. Still needs to be fixed to not happen at all.

Beta 3.605 Code Will Change

(Released August 27th, 2021)

Player Settings For Multiplayer

  • Switched our internal fields for personal settings storage to regular dictionaries instead of ArcenSparseLookups. Since we never need to iterate over those internal lists, this other data format was extra CPU work for no gain. It's a miniscule savings, but I was right there and it took longer to type this note than make the change.
  • Added support for the game to skip some rows for serialization purposes, in order to make it so that we can opt-out some rows with bits that are more efficient.
  • Expanded support for serialization efficiency by having a new serialization_name="yourtexthere", which can be used to shorten really long InternalNames.
    • Bear in mind that we usually want a name that is as descriptive as possible AND which is unique in the table it is in (that acts as a primary key in a database sense), but for serialization purposes it's actually much better to be brief, cryptic, and unique.
    • The brevity is not super over mega important, but it does matter to savegame sizes and transmission of data, and that problem would only get worse as mods proliferate, so this is a way to head that problem off at the pass.
    • Currently we only store each string once in a save file and then look it up by index, but storing a shorter string is a notable way of cutting down on transmission if it's ever a problem.
    • We probably won't make extensive use of this right now, but it's nice to have as a general feature, and can be used in particular by modders in the future.
    • It is worth noting that this data is presently a really giant portion of the data in savegames, something like 100kb as of DLC2 with no mods installed, compared to something like 300kb total for an early-game save. So this isn't really a trivial thing, especially when considering mod proliferation in the future, although in the scope of late-game saves it probably wouldn't be too awful.
  • Added support for the game to serialize ArcenSettings (aka personal settings) into savegames by index.
    • However, it will only do so for any that are marked with is_network_and_game_synced_setting="true"
  • Added new extension methods to the built-in .net dictionary:
    • GetEntryOrSpecifiedDefaultIfMissing() and GetOrDefaultIfMissing().
    • These provide analogues to something that the ArcenSparseLookup used to handle for us on the settings in particular, but it gives us the freedom to use actual defaults from the settings.
    • There has LONG been a fairly rare bug where if your game errors out at just the wrong time and you have to kill it, it writes all your settings to 0 and similar. This will fix it to writing them to the actual defaults per field, which is pretty cool. No more coming in to a very dark, black and white game after the saturation is turned all the way down, etc.
  • It is now possible to query NetworkAndGameSynced settings directly from PlayerAccounts in the world object, and to store their data there, as well.
  • The game now automatically saves any personalized game settings to the PlayerAccount related to the local player if they are marked as network-and-game-synced.
    • What happens here is that on the host or client, it compares the current version on the PlayerAccount to the version that is in the local settings. If it doesn't match, it generates a GameCommand for each one that does not match.
    • It will only send corrections for things that don't match on a 1-second interval, so there's time for the data to get integrated back and thus not get into a cycle of resends.
    • The proper way to use this when it comes to code that wants to check personal settings that affect gameplay (this will always be on the host) will be demonstrated in code shortly, but right now it's about automating the transport and storage of these.
    • Please note that when it comes to settings types, you can use any. Bools are very efficient, integers are efficient and reliable. Strings are sent in the condensed ascii format, so they're not the worst. Floats will suffer from potential precision issues and so should be avoided if possible, but will work if you must. FInts are fine, but bulky.
      • Most data is inherently bool or int for this sort of thing, so that's great.
    • Please bear in mind that it will only send non-default data, so this really is minimal footprint. The defaults will come back out when anyone queries an empty field, so that's more or less invisible but is something you'd notice as seemingly-missing data when looking inside a savegame data field log.
  • The above from today has now all been tested and is verified to work, including with the new serialization abbreviated names. Various minor improvements to world deserialization were made in the process.
  • All of the built-in automation-tab personal settings are now network-synced for multiplayer, and also use unique very-brief serialization names.
    • If you are a modder, it is strongly recommended you have a brief unique signifier for your mod and then your settings to avoid conflicts with other mods in the future but still keeping data small.

Multiplayer Rip And Tear Continues

  • The faction class now has a GetFirstAssociatedPlayerAccountOrNull() method, which will either return null, or the first of any players controlling it.
    • This is so that the host can query per-player settings easily (those ones we're syncing automatically across the network now, anyhow).
    • Bear in mind that if there are multiple players controlling an empire together, then the settings of the first one will be the ones that are in effect.
      • Tip: if you want to switch who is the first player, just remove players until one is left, then add everyone else back. If this ever remotely comes up, which it likely won't.
  • Added a new AudioAndSimilarHandler for handling certain kinds of audio alerts and such that should happen on the client or the host, but which don't need access to externaldata, and which we can safely calculate on the background threads.
    • These things also specifically don't run for spectators, as they are all about the local player's experience.
    • The UpdateStrengthByTechLine() code now also runs in here, which gets it off a main thread (yay!) and also makes it so that it works in multiplayer for clients for the first time in a long while (yay!)
      • This also lets us remove some bits that were having to run separately for the necromancer faction, and fold it all into one tidier function.
  • In-game audio cues, for things like planets under attack, now work for all players in MP (not just planets of the host), and will work for necromancers and so on.
    • Same for if you're low on metal, etc.
  • Added a HostOnlyJournalsAndAutosaveAndSimilarHandler that is actually just for running on the host, but once only and on a background thread, and specifically not tied to any faction type.
    • I had to move a ton of code into here, specifically because it was going to have lots of nonfunctional cases in both single player and multiplayer scenarios of various sorts in the old status.
    • Solo ark factions with vassals in single player would have not worked.
    • Spectator host with human empire clients in multiplayer would not have worked.
    • And a bunch of other variants, like the host being a necromancer and the clients being human empires.
    • This also makes it so that forcefields will move back into position after being bumped, even if you're in one of those situations.
    • Also a bunch of achievement checks now will work properly that wouldn't have in those same sitautions. We also check for those every cycle now, rather than every other second, since these cycles can be longer and it doesn't matter.
    • Since all of this stuff just creates GameCommands, we are actually saving some pretty notable potential CPU cycles off the main thread, but it depends on the game paramaters, really. Mods should definitely mimic this for max performance, though.
      • All of the "autobuild such and such" code has moved into here as well, which is actually quite convenient because it is agnostic about what type of player faction is involved. If we care to check for a setting, we can, but it's not built in with prejudice like before.
    • A number of cheat codes are now MP-safe and will work on clients as well as hosts, incidentally. Before, only the host could run the player potluck and similar.
    • Ha! Clients were able to take planets without incurring AIP for their planets, at least in the last month or so. The beta may not have been functional for MP since this has been true, not sure. Fixed now in the restructuring.
  • The "Helper Tips" setting is now network-synced, and the way that it checks things is now being split up so that it is not so host-centric.
    • Until now, it would only give any sort of notices based on how the host was doing, and not any of the clients. What if the host was a necromancer, though, and the clients were human empires? They would never have gotten any useful tips for them.
    • This has now been split into a host-centric version and an on-host-but-examines-each-faction version. This is basically the model for how all automation and other central settings should be handled from now on.
    • Those that only run on the host, thinking about the host's faction, are now:
      • Too Much AIP
      • Finding the best planet with an ARS or fleet near the players now is done only on the host but considers all human empire factions, not just the host faction's planets.
      • All lore-based journals are still host-only and don't need a faction to look at in general, those already were great.
      • For the "you can watch fleets" message, it now runs if any player account attached to any human empire faction isn't watching one. It ignores necromancers, spectators, etc.
    • Those that only run on the host, but run against every player faction whose controller has said okay to beginner tips:
      • Combat And Planets
      • Those From Player Encounter Of Thing (AI Eye, whatever)
      • If someone hasn't unlocked any techs yet.
      • If somebody is poor in metal and didn't do any upgrades.
      • If somebody has 3+ planets but hasn't hacked a TSS yet.
      • If too much threat is around in general.
      • The "did you know you can queue unload commands?" tip that just comes after a while.
      • The "turrets, fool! Do you speak them!?" if any specific someone isn't building any turrets.
      • The "you, your flagships keep getting wrecked and you haven't upgraded them" message for anyone who might be having that problem.
      • The "there are warp gates living next to your king, and it's been a while and you've got at least two planets, do you think that might be an issue?" (Can you tell it's been an exhaustively long day and I'm slightly loopy?)
      • And finally, the "hey friend, are you hoarding your science for some particular reason, or you just like getting pilots killed?" special.
  • In general improved the efficiency of checking for tips that already have been triggered, by not checking to see if they meet the criteria again.
  • Implemented a better fix for the "PlanetsHavingScienceExtracted" tooltip flicker bug that will work on MP clients and not rely on external data like the old fix did. The list of planets was going to be too long on clients most of the time.
    • Wow that was a fix from long ago, probably 2017 or 2018. We have a better way of handling that sort of thing now. We also have them sorted by name now, whereas until today they might have flipped around in order a bit every 2 seconds.
  • All of this is well-commented and well-organized now, and can easily be mimicked by mods or expanded by our own developers as we need to.
    • The things that go in each category are fairly obvious (how many factions are involved?).
    • The places we're calling these from is not always obvious, but you can search the code by some pretty obvious keywords and then it's well-commented when you see it, explaining why it does things the way it does.
    • None of this makes any progress on the notifications work that I started on yesterday, but this was another giant giant thing that needed to be refactored, and it wasn't until talking to SirLimbo about his own mods that I realized just how much there was in the main game that needed updating also for this.
  • Observation: AIP is invisible on clients right now, as are things like the AI Difficulty. We'll need to have a nice way of handling that better that mods can mimic. Siiiiigh. Heh.
    • But at this point, I'm just happy my stuff is working, and this track came on and I'm rocking out to it: https://youtu.be/CGwH6rZk7VM?t=78
    • There's more to do, but progress is happening. I'm still getting the tips properly in single player, which was the short-term worry, and this should translate over perfectly to MP. This is also a GIANT performance buff on older computers in particular. This stuff was happening in Stage3 of the sim for factions, and that was not a great thing.

Beta 3.604 Puppy Proofing, Part 1

(Released August 26th, 2021)

  • Adjusted some of the parameters for the new line types so that they can now be controlled via xml.
    • Made it so that the "reload select xml" function that we used to tweak visual effects now controls these as well, so that we can tune on the fly.
  • Discovered that the chain lightning effect was actually an out of date one from prior to finishing work on it a few days ago; I had not applied my scene changes to the prefab, so they didn't get added to the game itself.
    • With some further strategic tuning of variables, it now looks awesome again, while being vastly better performing than the old style was.

Rip And Tear For Multiplayer

  • Starting the process of splitting notifications (those placards at the top of your display during the game) into parts that can be generated locally (on the client or host), and those that can only be generated on the host (because of the use of external data, which now will be only on the host).
    • Right now it's a matter of just splitting the existing-function stuff out, then once that process is far enough along, then the whole host-client-communication thing can happen for those we can't split.
    • We have a new PersonalNotificationGenerator in the Core dll, and a new limited-function ArcenCoreUIUtilities class in there to support it.
    • The attack notifications on planets relating to you are now moved into this, and will be one of the chief kinds of notifications that the client can calculate without having to ask the host anything about it. This makes them react quicker, reduces bandwidth, keeps that part of the code simpler, etc.
  • SpecialFaction_Champions.Champions_AllFactions has been moved to World_AIW2.Instance.Champions_AllFactions.
    • The notifications relating to any and all kinds of hacking have also now been moved to the Core dll in the PersonalNotificationGenerator. Yay yet more stuff that the host doesn't need to tell the client!
    • Got this working for necromancers as well as regular humans.
  • Brownout notifications (which can be about yourself or allies) have also been moved to the any-client-or-host part of the code.
  • Added a new ExternalPersonalNotificationGeneratorTable, which is generally modeled on the ObjectiveGeneratorTable.
    • This allows for mods to generate client-or-host personal-style notifications that work in multiplayer without the host having to send any extra data.
    • Please do note that we can't completely idiot-proof these, though (pardon the term).
      • If you make any references to ExternalData stuff that is stored only on the host... well, that's going to a an exception that happens in your mod, but only on multiplayer clients.
        • If you should find yourself in such a situation, then simply re-code that "personal notification" to instead be a "host-driven notification," and you'll be all set. (Please note that host-driven notifications are still not in place at the time of this writing, but by the time you can test MP and have an error they would be).
  • As an in-main-game example of how to use ExternalPersonalNotificationGenerators, there is now an entry in there that is used to generate the counterattack notifications for players.
    • This is the sort of thing we could have moved into PersonalNotificationGenerator in the Core dll (and in order to verify we were not calling any code that is disallowed, we actually tested copy-pasting to there to make sure there were no bad references.
    • However, as an example case of how to handle this sort of thing for mods, it's preferable to have this where it now is.
    • The "abormal hackers" in AMU were going to be the second example of doing this in a simple way, but for now actually those have to just stay on the host and later be converted into a kind of strange hybrid. We'll show how it works in the code when it's ready. But at any rate, AMU won't be broken in single player for now. At present, the only negative effect is that the abnormal hacker notifications from AMU will only appear on the host in MP.
  • Notifications about both AI Eyes and Raid Engines have been moved into the CorePersonalNotificationGenerator "example" class.
    • These required only the slightest change in order to be client-agnostic.
      • Previously, they were looping over all factions and checking to see if the implementation was a SpecialFaction_AI. That's not a good idea, but MIGHT work, on an MP client.
      • A better way to handle this sort of thing now, when you just want to know "is this a main AI faction" is to just iterate over World_AIW2.Instance.AIFactions rather than World_AIW2.Instance.Factions. It's faster (not that we care, on this non-urgent background thread, but still) and also will definitely 100% work on MP clients.
  • Zenith Trader and Ceasefire notifications also moved over, since again these don't rely on any External data.
    • THAT said, the code "otherFaction.Implementation as SpecialFaction_ZenithTraitor == null" had to be swapped out for "otherFaction.SpecialFactionData.InternalName == "ZenithTrader"" instead.
    • The Zenith Trader is actually a great example case, too, because it only alerts you when there is a trader on one of YOUR planets. So that is quite nice that we do not to have to generate that notification on the host for every player and then split out only to relevant ones. Some other factions that rely heavily on external data will not be so fortunate in the future.
  • Oh, here's a handy idea! To make SURE that nobody slips up and references the wrong thing that a client would have, CorePersonalNotificationGenerator is now in a namespace called Arcen.AIW2.ClientSafeExternal.
    • Part of this means that the Arcen.AIW2.External namespace needs to NOT be included using a "using" reference, or else we're just right back to square one. We want references to Arcen.AIW2.External stuff to error out, with a few exceptions.
    • Dang, you know what? Some of those classes that we had moved into the Core dll earlier today can now be moved back out, making them open-source again. That also means we can ditch ArcenCoreUIUtilities.
    • For the two classes that we frequently legitimately need to use, we can make that trivial to do with the following aliases:
      • using ArcenExternalUIUtilities = Arcen.AIW2.External.ArcenExternalUIUtilities;
      • using Window_AtMouseTooltipPanelWide = Arcen.AIW2.External.Window_AtMouseTooltipPanelWide;
    • C# features that are not usually that useful ftw, in this case.
  • The "macrophage are attacking me" logic was also able to be moved over, which is good since it's -- again -- about you-personally as a player.
    • In this particular case, it needed to check (via switch statement) for three different SpecialFactionData.InternalNames, rather than the base class of the implementation. Less efficient by a bit, but again this is a background thread with no real ticking time clock on it (at a ms or ns scale), so that's very much fine.
    • Also of note with this one, it needs to use a hardcoded string constant (specifically MacrophageBaseSpecialFactionClass.EnragedHarvesterTag), and so punching through with a direct reference as "Arcen.AIW2.External.MacrophageBaseSpecialFactionClass.EnragedHarvesterTag" is just fine, since that will be the same on the host and client. A note has been left to that effect.
    • As you may note, it is really impossible for me to idiot-proof the notification-generation code as much as I'd like. The good news is that if someone makes a mistake, the errors on the client should be clear enough that the coder in question can go "wait, you got THAT error on a client?" and fix their notification code. Being easy to trace back and know why it's broken is kind of the second place to being idiot-proof to begin with.
  • At this point in the process, we are left with 7 notifications in the Human.cs class, and all of those are broad information (not player-specific), while we've moved 11 classes to run directly on the client or host, including all of those that are player-specific.
    • That's actually a really heartening ratio for the base game content. Some of the DLC content, and mod content, and other more complicated content will have to be dealt with separately, but we've isolated a lot of code that really doesn't need to
  • Moved these over, since they can actually just run on the client and host just the same!
    • Dyson Antagonizer x1
    • Nomad Planet x1 (moving; that uses no externaldata)
      • Also moved the color for move time into ArcenExternalUIUtilities.GetColorForNomadMoveTime() instead of where it was.
  • Marked the following with NOTIFICATION_TODO entries, where I'll have to make it host-centric with data being passed to the clients:
    • AI Reserves x1
    • Dark Spire x2
    • Dark Zenith x2
    • Fallen Spire x5
    • Human items x7 (removed a duplicate nomad move class that was not being used!)
    • Nomad Planets x1 (Crashing -- and this had a bug and was not being run at all, turned out!)
    • Territory Dispute x1
    • Zenith Architrave x2
    • Zenith Miners x1
    • And then finally, the waves and such against human worlds are marked as WAVES_TODO, which need to be moved into Core so that a whole lot of stuff becomes visible to clients.
      • Actually, the way that waves are added in belatedly is a great model for how to handle some integration from personal data and from-host data on MP clients, but that will come hopefully tomorrow.
    • There are some other bits, in mods, but the above is the remaining scope of work for the big notifications overhaul when it comes to the base game and DLCs.
  • A new CurrentHackers concurrent dictionary now exists on the main World_AIW2 instance object, which lets us check any and all hackers for notifications.
    • This makes it so that if any mod or other source has atypical rules for hacking, the hacking will still show up in the central notifications.
    • This list is self-managing, so no faction or mod authors need to think about it. The worst case is that it might have stale data for part of a second after a hack has ended.
    • This let us greatly simplify several parts of the code in the central game, and also some in AMU.
    • Thanks to NR SirLimbo for the implicit suggestion in how he was working with this in his own code. It was a great idea.

Bugfixes

  • Could not find to fix the error "Exception in entity tooltip text generation at stage 5460", as it was covering too broad a spectrum of code by accident. That code has been instrumented further, so we'll get a better and more informative error next time this happens.
    • Thanks to Zweihand for reporting.
  • Exceptions inside of parallel planet loops or parallel fleet loops are both now vastly more clear in terms of what they show to the error log.
    • Additionally, ThreadAbortExceptions, which are valid cases of the game saying "I'm going to the main menu, stop now" are now properly ignored.
    • Thanks to Zweihand for reporting.
  • Fixed some invisible error spam that could happen on certain older savegames (thus slowing them down and also causing them to have a braindead Praetorian Guard subfaction). Essentially if we can't find the proper PG difficulty, it will now use the default PG difficulty instead.

Beta 3.603 Last of the Recent Known Regressions

(Released August 25th, 2021)

  • Added a new Onslaught Fleet to ZO (DLC2).
    • A fleet designed to adapt to the Zenith Onslaught, using all new technologies.
    • Thanks to Zweihand for adding this for us from his More Starting Fleets mod into the main game instead!
  • Added BACK a concept of "UnpausedTimeSinceStartForVisualEffectsF" (which now in its name mentions it is only for vfx), but are now using it purely for purposes of beam weapons and chain lightning and such.
    • This makes it so that now you can pause the game while a beam weapon is active, and it will remain "caught in the act" like explosions and shots and such do, rather than continuing on as if you had not paused.
  • Tested and works (and these are the definitions of how they are supposed to be):
    • Load a savegame: Galaxy map, paused, centered on last planet you were at.
    • Generate a map in lobby: galaxy map framed in the view, not centered on your planet.
    • Start game from lobby: on planet view of your home planet, but galaxy map is nicely centered on your planet when you tab out. Game is running, not paused.
      • Ditto this for loading a tutorial.
      • Ditto this for starting a new quickstart (it always started paused before, this was strange and not on purpose).
      • And lastly, same here again for the test chamber.

Bugfixes

  • Regression fix: Fixed a trio of boolean inversions in the prior version that made the lobby settings not work and the in-game faction options window throw errors.
    • Thanks to Zweihand for reporting.
  • Internally, UnpausedTimeSinceLastRestartF has been replaced with NonSetupGameTimeSinceLastLoadOrStartF, which is more complicated but now accurately measures the sort of time we want it to.
    • Essentially, we want to know about how much realtime has elapsed, network-related-delays-notwithstanding, since certain things happened.
    • By using an internal accumulator that is actually per-frame, and then dealing with the accumulation during that part of the simulation that checks for network delays or proceeding with the sim, we get an accurate picture now.
    • This fixes various bugs, like the "inactive threads" warning on game start after being in the lobby for a while, or the threads window (left click the timer in the bottom left) not showing actual activity as it should while the game is paused. Some of those threads do in fact run during pause.
    • This in turn does make it accurate when threads are running or not running during pause, which means some extra controls in there to make it show the pause-skips process correctly and not alert when those are not running.
  • Regression fix: Reversed the animation direction of all the ship to ship beams, which were backwards in the prior version.
  • Internally, our SecondsPerFrameSim_GlobalOnly_NotForPlanetsOrCombat has been split into two versions: one for paused-only, and one for paused-or-unpaused.
    • This then required a bunch of similar changes all over the place, and a lot of new selective logic for certain things to be calculated when paused, but not actually executed (like how much metal you will gather, or science extraction, etc).
    • This solves a lot of longstanding issues, like "metal flows can't be seen accurately until you unpause the first time"
    • It also solves the regression from the prior build where engineering assistance lines and similar were not drawn when the game was paused.
    • And finally, it solves some issues related to energy usage when paused, most notably to do with gifts between players in multiplayer but not exclusively limited to that.
  • Fixed a longstanding issue where we could see extra copies of engineers helping things self-construct or build at a factory.
    • When this happened, it was accelerating the construction of those things, and charging you way more metal than you'd expect, but you were still getting what the UI showed and the value for the metal spent. It was both... an unfair advantage to you, as well as a source of MP desyncs, as well as making the economy fluctuate around unpredictably. Anyway, this has been a bug for a really long time, or at least suspected, and it is now slain. It has been around for years, likely.
  • ALSO fixed an issue where certain circumstances with factories being assisted would cause them to overspend to a really drastic degree, which could tank your economy fast. This is something that was new as of the engineer rework a few months ago, probably, although it might predate that. Anyhow, this is also fixed.
    • Here again, this was sort of to your advantage, but also sort of not when it came to planning. You weren't losing any money or getting cheated out of value, but it would deplete your coffers unexpectedly fast.
  • Removed a bit of faction data that was being serialized to disk and across the network, which is now calculated per-sim-frame and doesn't need to be saved at all.
    • The energy production and consumption totals are still saved, despite seeming like that might not be needed, because we don't want to get into confusion about brownouts.
  • Fixed a longstanding oversight where if you paused the game it would still count down your brownout timer. If there's anything else like that, please let us know!
    • Thanks to NR SirLimbo for reporting.
  • Regression fix: Fixed a bug in the prior build that let the game pretty much insta-build anything for you from a factory, for free, so long as the game was paused. Folks really missed out by not playing that more. ;)
  • Slightly improved the accuracy and efficiency of the metal flows window when it comes to reporting how much metal is being spent on what. Some free actions were being reported as metal expenditures, from what we can tell, although that's not for sure.
  • Fixed a bug in the prior build that was causing lines between ships (beams, that is) to be drawn in a really choppy manner. They were accidentally only updating at around 10fps rather than your actual framerate.
  • Exit to Desktop now works again, and is also faster. It also does not confusingly seem to be taking you past the main menu briefly before you go.
  • "HasDoneFirstUnpauseSinceLoadOrGeneration" has been removed, as it really is not needed in any way. This is a fundamentally flawed concept.
    • If you were going straight into the game, then it can do those things in DoFinalBitsAfterMapGenerationOrFixingSavegame().
    • If this is some sort of thing that is supposed to center you nicely, then if you are starting out paused there is no good reason for this as you may have wandered quite far off. It can do that for you in HandleLocalWorldStart().
    • A bunch of related code got stripped out or shuffled around.
    • Regression fixes that resulted:
      • The game once again remembers what planet you were viewing when you return to a savegame, rather than just centering you on your home planet.
      • Unlike the prior build, unpausing for the first time after loading no longer jumps you to the planet view of your home planet in a disorienting way.
  • Put in some other fixes in the outer camera system so that the game now properly centers the view on your planet at the start of a game or after loading a savegame, versus being randomly located way off somewhere.
    • Not sure how long that has been broken from working, but it was really annoying and wasn't just the last day or two. Sometime during the beta period, this broke.

Mod Updates

  • More Starting Fleets by Zweihand has some added content!

Beta 3.602 Linesanity

(Released August 24th, 2021)

  • Known issues: centering is wrong (still) on the galaxy map after a variety of the above things.
    • Also (new) it probably selects your home planet rather than whatever planet you were at when loading a savegame, which is annoying and also temporary.
    • The pause state seems to be correct in cases in general, although that does need further testing.
    • Unpausing the game for the first time seems to take you to the planet view.
    • Metal flows are still not quite properly calculated when you are paused. This also means that engineering beams disappear while paused right now.

Balance

  • Pulled down the AoE target cap of Electric Bomber a bit in response to effectiveness with shot compression in play. Cap of hits per shot reduced from 15 to 9.

QoL

  • The way that mouseover is handled for wormholes is a bit improved in general.
  • When you mouseover a wormhole, for the first time in AI War 2 it now has a tooltip.
    • The tooltip shown is the same as that of the galaxy map, but minus any special galaxy view mode changes that might be in force on the galaxy map itself.
    • Thanks to UncleYar for suggesting.

Bugfixes

  • Fixed an issue that has arisen in the last month or so on the beta branch related to icons and how those are batched. Thanks to the fact that they are now batched, their order of the sprite dictionary in the unity hierarchy is a more complicated matter. We of course want things like overlays to always appear over top of the actual ship icon, but that wasn't reliably happening anymore.
    • Some new capabilities have been put in place in our customized version of TextMeshPro in order to get them so that they can do this.
    • The bug had been notable before in various tooltips for ships, but also in the C-clicking for ships. It's now fixed in a highly efficient manner that uses no extra CPU or GPU processing.
  • Previously, there was a HasEverBeenUnpaused that we were using -- incorrectly -- to mean a couple of different things.
    • The only thing that truly actually meant was if you had unpaused the game after a load or after starting from the lobby. Coders can now query that via HasDoneFirstUnpauseSinceLoadOrGeneration for the super rare cases where that's something you actually want or need to check.
    • Instead, now coders should sometimes be querying InSetupPhase, which tells you if you are in the lobby or not.
    • But truly, now most of the time coders really should be calling an all-encompassing IsOutsideOfNormalGameplay, which handles things like mapgen, loading, the main menu, the lobby, and so on. This is almost always what was previously meant.
    • This change is likely to cause a lot of new bugs, but also to fix a number of existing ones. So... that's fun. At least we're already in beta branch, sigh.
      • Some of the bugs that will be fixed by this are MP-specific ones.
    • Most things broken or fixed by this are related to what happens the instant you get into a new game as client or host, a tutorial, the lobby, existing save, quickstart, quickstart to lobby, and so on. So there are only a dozen or so cases, and we should be able to sort those out.
    • One "fun" bug that was fixed was the chat window not being allowed to open until you unpaused the game for the first time since this session started. Random little things like that.

Major Overhaul Of Ship To Ship Line Drawing Premise

  • The ENTIRE set of code for how we were rendering ship-to-ship lines has been recoded from scratch, and now uses opaque geometry in the style of how shots do.
    • Previously it was using unity LineRenderer components, which are CPU-expensive, wasteful of overdraw on the GPU, and have many other problems.
    • Now these properly use zwrite and ztest and render more nicely and with full GPU instancing support.
    • We also now use a completely new (still stupidly complicated) methodology for actually queuing these draw commands, and thankfully they do not require pooling or object reuse.
      • There is a slight tradeoff in how we are recalculating certain variables per frame while certain lines are drawn, but most of that is on background threads and should be faster than before.
      • If anyone has any saves with tons of tractor beams in them, it would be super duper interesting to see what your performance like is like in the prior build (most_recent_stable_beta) versus the current beta.
    • This should be the final solution for a lot of beam weapons and engineer lines and hacking lines not appearing, or causing lots of performance headaches.
      • However, this has not been widely tested beyond basic engineer lines, so there may be other changes needed before this is fully done.
      • Also, it's worth noting that effects like beam weapons and chain lightning have been completely recoded from scratch (from a visual standpoint), and so we need better test cases for them, too, to make sure it all looks okay.
    • Also also, it's a known issue that the ends don't quite line up right now. That's a minor adjustment that needs to be possible via xml per line type.
    • However, these do now scale up in thickness the further out you zoom, making them look nice at every distance. Shots have been doing this since the dark ages.
    • Also also also, the line animations might be backwards, not quite sure. Either that or some code has them backwards. Engineers should push, tractors should pull, etc. Saves with demonstrations of this being wrong would be welcome.
    • This whole thing was stupid complex. We now have a cross-thread swizzle list, for example, among other new data structures and patterns. Bugs are to be expected, but long-term this is simpler than what it used to be.

Beta 3.601 Tuning Before A Respite

(Released August 18th, 2021)

Note: I'll be out with some family functions until Monday the 23rd, after which updates will resume as normal.

QoL

  • The SetCurrentlySecondaryHoveredOver and similar on planets has been removed.
    • There is now a World_AIW2.Instance.FocusedPlanetForMapDarkening as of the prior version which should be used instead.
    • We've gone ahead and updated things so that all of the notifications now do proper focusing of the map when you hover over them (it's SO hard to play when they don't do that).
    • All code mods have also been updated to support this.
    • This has also made the need for a multi-hover (multiple planets hovered at once from a notification) clear.
  • Guard posts and fleet leaders of non-friendly factions now show up on your sidebar even if they are cloaked.
    • Previously it could get very hard to find cloaked guard posts.
    • Thanks to Carl Dong for reporting.
  • On the "at planet" sidebar, it now shows the ships that are inside guard posts, as well as those ships that are in your own transports.
    • It shows them with a little orange "GP" or little blue "T" to help you see at a glance what is happening, and then the tooltips also mention it when you hover over them.
    • The idea is to be able to fully understand what you are looking at when you're coming to a planet you are attacking, or when you are considering a planet to defend.
    • Heck, this can even be useful for realizing that you forgot to deploy a transport if an attack is incoming.
    • Thanks to Asteroid for suggesting.
  • When you are viewing the contents of an ARS, TSS, ODSS, or similar, it now doesn't act like those units are already part of some fleet. It says hack to choose one, or whatever the appropriate terminology is for the case in question.

Bugfixes

  • Quieted some logging from nomad planets. So far as I know, all is well with them. The log lines are just commented out, so if we need to re-enable them as a toggle setting we always could, or they can just be uncommented.
  • Fixed several funky issues that have been around likely since we started using the FakeEntity for tooltip construction, or maybe even slightly prior to that in the tooltip redo.
    • At any rate, the faction that units were attributed to be when shown via tooltip has been correct in build mode and when hovering a unit directly for some time, but when looking at things like the contents of an incoming wave, or the contents of a guard post, it was sometimes showing these things as being part of the human player fleet instead of whatever they actually were.
  • Fixed a bug that was new as of the addition of the "border aggression" feature that we are testing out (it's not fully released yet).
    • Essentially, we reused the relentless wave faction logic for the border aggression, and that meant that tests for "find the next relentless wave faction" would (sort of by luck of how a savegame was set up, the order of factions) sometimes come back with border aggression instead of relentless waves.
    • This meant that waves would spawn as border aggression sometimes, but not always -- but always the same in a given save.
    • This has been fixed by making these classes split, so that they have a common abstract core class with the real logic (which was the point -- not duplicating code), and then having unique actual end classes so that this confusion doesn't happen any more.
    • This new design does mean that we can't use any static variables in the base abstract class unless they are also threadstatic, but we already were not doing that, so there's nothing more to change at this time.
    • Thanks to Daniexpert for reporting this incarnation of the bug.
  • Now that the contents of AI guard posts are showing correct factions, the prospective ships you could get from the ARS, TSS, etc, were showing the wrong faction. Now that's fixed to again show you.
  • Removed some old logic that was very confusing that was related to "local ui values" for various fleet stats. This was stuff that was for the ui when it was a fleet that had not yet been captured but that you could capture.
    • This logic got kind of wrecked in the prior release, and there are more efficient ways to calculate this now when we need to for rollups, tooltips, C-clicking, and so on.
    • When you look at a fleet that you have not yet captured, but which you could capture, it now properly shows the mark levels and stats for those mark levels (unit counts correct, etc), unlike in the prior build.
    • Thanks to Zweihand and Daniexpert for reporting.
  • Put in a number of potential fixes for the inactive threads issue. Essentially, when they are being shut down because of exiting from the game, they are now sure to mark themselves as complete, etc. They were previously potentially (in theory) able to get stuck in an indeterminate state.
    • Please note that multiplayer clients probably will have lots of inactive threads reported at the moment, but those threads are not meant to run on the MP client, so it's a false warning on those.
    • If this is still something people see on MP hosts or in single player, any added info, exceptions, or steps to reproduce would be super welcome. We have yet to be able to duplicate it.
    • Thanks to Daniexpert for reporting.

Beta 3.600 Multiplayer Sprint

(Released August 17th, 2021)

QoL

  • Completely reworked how the "map darkening when hovered over something" code works.
    • Previously it had a pretty wicked flicker in a lot of games when you hovered over units on the sidebar.
    • We now have very explicit control over when we want to set the darkening, including for specific entities when need be, versus entire entity types.
    • Thanks to UncleYar for reporting.
  • On the at-planet sidebar, when you hover over ships, it now properly highlights all planets on the map that have ships of that same type.
    • On the at-planet and fleet sidebars, when you hover over fleets, it now highlights the planet where the centerpiece of that fleet is (how did we ever live without this? This is incredibly helpful).
  • The build menu now also does the same highlighting thing that the at-planet view does.

Multiplayer Work

  • A variety of our world sub-classes now have reference tracker data on them to see if we are leaking memory with them.
    • This might seem trivial, since we are demonstrably not leaking substantial data now between saves and loads of single player games, but these particular classes could leak HARD on multiplayer clients, so it's more important than it might look at first glance.
  • Split out a few more classes from the world object files so that we can make them pool properly for MP purposes.
  • The type of pool used for journal entries has been switched from between-map-load (which makes sense for single-player) to a general concurrent pool (which is what we need for MP, and it's just as good for SP).
  • Journal entries are now fully synced for multiplayer in a way that should now ensure that they don't desync.
  • There is a new background thread for the host only called HostOnlyAggregatePlanning, which will be in charge of a bunch of frequent aggregation of data that is meant for hosts and clients to share, after being generated on the host.
    • This is also run, once, on hosts from their per-second non-sim thread right after load, so that you don't have to unpause for this stuff to be correctly in place.

Outguard Consistency

  • The central mercenary/outguard lookup data has been moved into Core from External, because we need to be able to talk about this stuff more directly for purposes of syncing from the host to the client.
    • This is one of those core game mechanics that drives a whole sidebar tab; in the end, this is not the sort of thing that is a moddable mechanic, despite how we originally treated it.
    • This also means that its surrogate table entry has been removed.
  • SingleMercenaryGroupState has been removed from the external data, and is now OutguardInfo.
    • This also means that MercenaryGlobalData.Instance.groupStatesByIndex is replaced by World_AIW2.Instance.OutguardStates.
  • Outguard beacon data has been moved into Core from External, again for the sake of making it function properly in multiplayer.
    • This is all now automatically synced to multiplayer clients, and at this point the experience for outguard should be identical on the host and the client.

Intel Calculations

  • Some of the crustier parts of the generation code for the intel tab have been smoothed out, and it now runs the full objective generation code every time it runs, rather than ever just counting how many objectives there would be.
    • This is because this will need to (soon) be serialized from the host to the client as items change. That said, what is here is not serialization-ready just yet.
    • A side effect of these changes is that the host is doing a bit more work on the background threads (but assuming you have multiple cores, this is not really that much extra), and a side effect of THAT is that when you first click to the intel tab (host or client) after not viewing it for at least half a second, it's now a lot faster for showing itself.
  • There were SIXTY different types of intel that you could be granted. Well, were and are. All of those have been converted to a new format that relies less on direct code references and instead uses xml to direct things.
    • All in all, this new structure lets us make the intel tip behavior more consistent (and to do so by just looking at xml), while at the same time also making them take just a fraction of the data to send across the network.
    • There's no way I didn't make some typos in there somewhere; there were dozens of dynamic subcategories, too, goodness. If folks flip through them and see something off, please let me know!
  • The ZPG and ZMC have moved from Other Capturables into the Resource Gathering category. They make a lot more sense there, since they are all about energy or metal.
  • All those extra intel categories for finding more of various kinds of units have been made more brief so that they don't wrap anymore.
  • It is worth noting that in multiplayer, right now we are not yet actually transmitting the intel info to the clients, so that part will be blank for them until we get that implemented.

Less CPU Use On MP Clients

  • DoPerSimStepLogic_OnMainThreadAndPartOfSim() on factions has been split into two parts:
    • DoPerSimStepLogic_OnMainThreadAndPartOfSim_HostOnly, which is where anything that relies on external data -- that's most logic -- should be.
    • DoPerSimStepLogic_OnMainThreadAndPartOfSim_ClientAndHost, which is very rarely going to be used, but is sometimes useful for things like calculating path dangers on both the client and the host.
    • This same setup is also cascaded onto a few other classes, such as Scenario.
  • Pretty much all of the on-faction methods have been adjusted so that they are now only run on the host, and also specify that they only run on the host.
    • Most of these things rely on data that we are going to be stopping sending to the clients.
  • All of the externaldata should now be blocked from being synced to network clients. This is going to need some testing tomorrow on my part to make sure things work at all with that, but once the initial bugs are settled out, then we should see the following:
    • Lower bandwidth to the clients, and lower processing of network data on the client and host.
    • Lower CPU processing on the client, and no chance of esoteric memory leaks.
    • Temporarily intel and notifications are going to be invisible on the client, and description-appenders will either be invisible or throw errors. Those are just in-progress bits, although the worst of the intel part (which is the single worst bit in general just due to its scale and scope) is done.

Bugfixes

  • Fixed a bug where if you loaded two different savegames with macrophage in them, the second one would throw a bunch of log errors because of some pooling that was not being cleared.
    • Also fixed it so that log errors from the macrophage are no longer infinite if they find bad data; they cull the bad data after complaining and then move along.
  • Fixed a number of nullref exceptions that could happen in rare circumstances because of cross-threading issues in DoForSelected() variants.
    • Thanks to Daniexpert for reporting.

Mod Updates

  • The Reprocessors mod now works again, having been updated to the latest code standards.
  • Fixed the AMU mod to work again; it had been broken by changes in the prior build.
  • All of the code mods have been updated to work with the latest code changes.

Beta 3.510 Threads And Science

(Released August 16th, 2021)

QoL

  • Improved a keybinding gripe: the old method was that if you were selecting a fleet by pressing the 1 key (for instance), then it would select it the first time, and then start cycling though centerpieces every subsequent time. The reason this was annoying is that this was different from other strategy games, and you could often accidentally recenter your view with this if you were just making sure a fleet was selected.
    • Now it takes a single-press to select, and a double-press to center.
    • Thanks to Mayheim for suggesting.
  • The "Are you sure?" function from the tech tab now also applies on the hacking tab.
    • This includes the ability to disable it via the same option in the settings, and also the ability to hold the same hotkey (by default X) to bypass the prompt.
    • For those hacks that actually open up a sub-window first, their tooltip now instead says "This hack will open a sub-window with more options before doing anything."
    • This should help folks no longer feel anxious about clicking buttons in the hacking interface.
    • Sub-windows of hacks all need to have this individually applied to them, as well.
      • Hacking for more ships or turrets now supports this.
      • Hacking for outguard supports it now.
      • Hacking for ship upgrades.
      • Ships hacking themselves.
      • Hacking enemy targets at a planet.
      • Champion hacks (probably needs tweaks).
      • Nomad planet crash hacks.
      • Choosing a specific planet for some other reason.
    • Thanks to UncleYar for suggesting.
  • For faction fields that were added in the same DLC or mod as the faction itself (this means any basic fields, including things like Allegiance), it no longer shows the DLC next to those.
    • This makes it more clear when something is truly a new addition, like the vassal option on a bunch of factions in DLC3.
    • Similarly, options inside a dropdown for a faction are now only shown as being from a DLC or mod if they are different from the DLC/mods of the faction AND the field itself.
      • This makes it so that when an option is added -- such as the Zenith being added by the ZO DLC to the Scourge First Armory options in TSR.
    • Thanks to Ovalcircle for reporting. This had been bugging me, too.

Ship Counts And Lists Relating To Techs And Science

  • Added a new CalculateMarkLevelForShipLine() that does the comprehensive logic for calculating the mark level for a ship line at a fleet.
    • Before some of this data was a bit embedded in other logic, making it harder to read as well as impossible to get at any way other than by actually having a ship line of the specific type in a fleet.
  • The way that estimations of how many ships and how much strength you will gain from upgrades has been redone heavily.
    • This takes into account the differing levels of units in your various fleets, for one thing.
    • Additionally, if you have fleets with different levels and you C-click into a tech, it will show you the various levels with those total counts.
    • This may fix the turret count thing? Not sure yet.
  • Added a new CollapseFromFleetsForTypeDownToTypesByMarkLevel() to ship lister utils.
    • Previously, we were only ever able to see the global player average mark level of things, and not the actual marks that differed based on fleet upgrades. Now it breaks it out when it needs to.
  • The way that fleet ship caps are calculated is now very slightly different when there are units that use MultiplierToAllFleetCaps, such as for turrets.
    • This multiplier is now used at the very end of all other multipliers, rather than at the start, which means we can now calculate differentiate caps properly without having to know the starting ship cap.
    • The overall impact to gameplay probably will be slight, but will affect the number of turrets that are in each cap somewhat.
    • Unless the math was done wrong somehow or there was an implication we missed, in which case let us know how many extra or fewer turrets you have...
  • When you have completed a tech line, its tooltip is now more correct in that it is clear that no more upgrades will happen.
  • When you're on the refund screen for techs, C-clicking and tooltips no longer say things about upgrading, they only say things about the refund. Minor confusing text details, essentially.
  • A variety of windows talking about techs of ships now show the tech roman numeral after the ship name. This is a help for new players in particular, and makes it so no-one has to perfectly memorize those colors.
  • The tech tooltip actually breaks out ships and defenses seprately for the line items, same as it does for the tallies and total strength counting.
    • In general, there is better seperation and formatting now so you can see what the heck is going on.
  • C-clicking in the science retrieval window finally shows the proper fleets and totals.
  • The totals for the ship lines were indeed fixed by Badger recently, but the number of defensive lines increased was still a bit off, showing the defensive TYPES, not lines.
    • The strength totals for both were accurate, though. And honestly, because of the funky way that turrets and such work, it makes more sense to show the types. So the tooltips have been updated to say that those are by type. Since they are and that makes sense.
    • TLDR: ships and defenses are just handled differently because they work differently. But the strength totals are the same and are accurate either way, and the details are now correct in the tooltips and C-clicks.
  • Fixed the "Retrieve Spent Science" text being offset low on its button for some reason.
  • Thanks to Ecthelon, Metrekec, Daniexpert, RedPine, and Exlium for reporting many various issues with all this.

Bugfixes

  • The start of some extra sync-safety with the random number generators used in multiplayer is in place. It's not finished yet, but there's an interesting approach taking shape. The goal here is to lead to proper deterministic simulations on the client and host with fewer needs for data correction sends from the host.
    • That has always been the goal, but with how multiplayer has evolved there now has arrived a situation where a lot more code than expected just gets run on the host, in some cases even just on the client, and figuring out the simplest code idiom to deal with that is an interesting challeng.
  • In the event that outguard data is messed up on trying to load a savegame, it will now give more informative errors and also not block the load of the save, if possible.
  • Adjusted the thread manager class so that we now have threads initialized a lot earlier, and tied to their related sim contexts where needed, and then they are simply initialized in the future.
    • The should prevent an exception that was reported by Badger and StarKelp and Zweihand that could occur in SetWorkDone(). I never could actually duplicate it, though.
  • Threads are now connected in a better way to their sim contexts, and we have extra debugging info on both ends in the event that either end thinks it is stuck.
    • Additionally, we can now see idle threads (those created for games with more factions but then later a lower-faction-count game is loaded so the game has nothing to do with those threads), and we no longer complain about them.
    • On top of that, all threads now kick off as promptly as they should on save load #2 in a game session (before it could sometimes have a 20 second delay for anti-AI zombies, as one example).
    • And lastly, the issue where time in the lobby was causing threads to look idle upon exit is now fixed.
  • Fixed a dropdown annoyance where when you were clicking and dragging the dropdown item list, it would disappear if you released the mouse cursor over the scrollbar itself.
    • Thanks to Ovalcircle for reporting.
  • Fixed a typo in the text that tells you cheats are disabled because of cheats or sandbox.
    • Thanks to Ovalcircle for reporting.
  • Fixed it so that units that have drone guns should no longer use that as part of their kiting distance.
    • Also, fixed it so that non-melee units should do better about using their smallest-ranged gun for kiting rather than anything else. Previously there was some notable oddness in how it was working for multi-weapon unit kiting.
    • Please note, these fixes have not been tested, but they should work.
    • Thanks to StarKelp for reporting.
  • Fixed an issue where when you were looking at the effect of direct upgrades for a fleet, it would not show you anything that did not have an explicit ship cap. So for instance, the command station and the metal harvesters, which are a "what you have here is what is there" sort of count were being omitted from that view.
    • Thanks to Metrekec, Daniexpert, RedPine, Exliumm and Ecthelon for reporting.
  • The game now generates the hacking tooltips in a vastly more gc-efficient manner.

Beta 3.509 De-Apocalypsing The Code

(Released August 12th, 2021)

Bugfixes

  • Removed a ton of code that was marked as obsolete but which had been left in place for mod compatibility. Any mods under remotely active development have been updated to work with the replacement methods by now.
    • There were some cases where an obsolete method was being called from lower down in the codebase through an interface method, and rooting those out was a good idea for making sure we didn't have unexpected code running.
  • Civilian Industries and Macrophage Histiocytes have been updated to work with the revised codebase again, and in the process also fixed a number of minor GameCommand memory leaks that both had.
  • Improved the ShipStats object on all factions so that it is using threadsafe collections internally, and also accessing them in a more efficient manner.
    • After getting an odd exception in there, that seemed prudent, and since ships are killed and die a lot, making it so that it does far less work to log each one is not a bad idea.
  • Fixed an exception that could happen when serialization was messed up and it was trying to read ship stats. The exception still happens, but is way more clear now.
  • Also fixed an exception that would happen on any savegame load fail (this was new since pooling) where there had never been a galaxy loaded yet this session.
  • Units with ancestors can no longer be stacked. Data would be lost.
  • Updated the game so that the list of mods and expansions that are enabled are no longer directly accessible. Something has been clearing them when it should not have been.
    • There's a faster-in-CPU-time method for finding out if one or more mods or expansions are enabled, and that's used now in AMU to show how that's done.
  • Fixed a bug that could happen when trying to save the last decollision time for units in certain unlucky cross-threading circumstances.
  • Fixed a bug where after you first started a new campaign, it would not know which expansions and mods were in use.
    • It wouldn't show them to you in the escape menu, and it wouldn't save them into savegames.
    • Was hoping for a more interesting smoking gun here, but no dice.
  • Put in some code that will give us more informative errors when something goes wrong inside of DoPlanetPerStepLogic. There was an exception in a log, but it told us nothing about what was going on, unfortunately.
    • Thanks to Ecthelon for reporting.
  • Added in a variety of more places to check for the FakeEntity infiltrating the main simulation. We're still not sure yet how it's getting in there, but the errors that we were getting before were coming from the targeting code. So this was fully immersed in some faction (or multiple??), from the looks of it. Since that morphs all around, it's highly likely that would cause all sorts of problems. With some of the rare strangeness that people report, perhaps more than a bit of that is because of this one thing, so this narrows it down more (hopefully).
    • Thanks to Ecthelon for reporting.
  • Fixed a variety of exceptions that could happen in PrivateModdedDevourerNotifier.
    • This checkin has a good example of the sort of code defensiveness you need to use in notifiers in order to avoid random cross-threading exceptions.
  • Put in some very strict debug checking for ship systems being set up wrong in any way, and hit the jackpot on things going off the rails. Will have to make it self-correcting, but also find the original source of it.
  • Fixed an extremely severe bug in the recent versions of the game that was essentially playing "scramble the systems" on all units/ships in the game whenever it was a load beyond the first. That could be loading a savegame after playing in a campaign, or maybe a few other scenarios. Anyway, everything went nuts.
    • The core problem was one bool on the pool of systems needed to be false instead of true.
    • Essentially, units are slow to give their systems back to the pool -- on purpose -- because that causes fewer cross-threading problems. However, with that bool set to true, then on a map clear the pool was automatically pulling everything back into itself. This then led to a situation where multiple entities were using the same systems, because -- mainly for MP networking purposes -- entities reuse systems they already have attached to themselves rather than pulling from the pool. That is in fact way faster. Except that all those things were forced back into the pool, so that became a double use.
    • This should fix a LOT of random bugs that people have been seeing since version 3.500, but it's hard to know just how extensively it will fix them.
  • On the first sim step after being created, units now do a check of all their systems. This is a nice compromise between checking it every frame (which we did for a bit while hunting this bug down) and not checking it at all (which is probably not a good idea, just in case, for performance reasons).
  • Fixed an issue with MySpecialFactionImplementationIndexNotForSim where it was not truly being set uniquely in a multithreaded environment. This was an old issue going back to 2020, and isn't relevant except for in debug hunts, but now we're in a debug hunt.
  • Reworked how our external data class tracking is handled.
    • We no longer accidentally create lots of extra duplicates, and we now have the capability to put items from that back into the pool at will.
    • For many other objects, like those attached to factions, the world, the ui, or squads, they no longer automatically go into the central pool; those are attached to the object they are with, so going back into the pool was winding up with double-assigning.
    • It's super duper hard to really know how many strange errors were caused by these things, but it was definitely nonzero.
    • One thing that was notable was that this may have been affecting things like special effects and ship to ship lines. So a report of invisible spire beams from recently might have been caused by this.
    • This notably does NOT fix the territory dispute factions being given the same object over and over on second loads of a savegame, but we're getting there. This fixes a number of other very important things in an adjacent area.
  • Fixed a MAJOR bug in the external-data tracking pooling classes that were introduced in version 3.5. Essentially, on subsequent loads when it could actually pull from the pool, it just returned the first object over and over again while marking the real objects as busy. This led to all sorts of chaos.
    • To be honest, it's a wonder that much functioned all with a bug like this one, and a few of the other recent ones.
    • Huge thanks to StarKelp for a setup that let us repro this reuse issue really straightforwardly. We might be out of the woods now with the worst of these beta bugs, knock on wood!

Beta 3.508 Hotkey Heaven

(Released August 11th, 2021)

  • Updated AMU, Devourer Chrysalis and Kaizers Marauders to recent changes in the Vanilla codebase.

Balance

  • Implemented a new speed cap on units to prevent various forms of abuse.
    • If the unit has a speed of more than 1000, then their max speed will be their normal speed + 2000.
    • If the unit has a speed of 1000 or less, then their max speed will be their normal speed + 1000.
    • The idea is to cut down on the worst abuses of speed buff stacking.
    • Thanks to CRCGamer for suggesting.
  • Raiders, etherjets, and a few similar things have had their speed nerfed from 1600 to 1400. This makes turbo raiders in particular no longer a lie when they are buffing a 400-speed unit.
    • Thanks to CRCGamer for reporting the issue.
  • Buffed move speeds of Tesla Corvette and Zapper by one step. This adjusts the last remaining player usable ship that moved at sub 400 speed.
    • Tesla Corvette now move at 500 instead of 400.
    • Zapper now move at 400 instead of 300.
  • Made it so that the absolute speed cap only applies to player ships. Other factions sometimes need extra-speedy boosts for various reasons, and it's intentional rather than an exploit when they do it (it's not a constant thing, and it's not abusable at will as with players doing it).
    • Thanks to Badger for suggesting.

Improved Key Combos

  • Major quality of life improvement! All of those hotkeys that have, since October 16th of 2020, required you to use [Key] to enable and Ctrl+[Key] to disable now work as a simple toggle again. Aka, press [Key] to turn it on or off, and [Key] again to do the opposite.
    • This was a really hated change (Ctrl+ for disable), and I hated it as much as anyone else. But the problem it was solving was that these keys very often did not work as advertised prior to that.
    • The old logic (pre October) was "if all of the units selected are in the mode, then the toggle means turn off the mode. If any of the units selected are NOT in the mode, even just a single unit out of 5000, then it means enable the mode." The result was that, for reasons that are still not clear to me, the modes would often get stuck enabled. I think it was related to ships dying rapidly during battles more than anything else, but that doesn't explain it all.
    • The new logic, implemented fresh today, is "if more than half of the units selected are in the mode, then the toggle means turn it off. Otherwise turn it on." Although actually it's a bit more complex than that. In some cases, equal counts of units defaults to off, others it defaults to on. But either way, it pretty much behaves as you immediately would expect when you use it.

Tooltip Updates

  • Fixed a couple of pieces of information on the tooltips for factories assisting fleets. Previously if you were in energy brownout, or otherwise blocked from building fleet members for a fleet, it acted all happy like it was done. Now it explains the problem. This should hopefully avoid confusion for new players as well as old hands.
  • Orbital units now show themselves as having an orbital speed in place where the normal movement speed would be. This is present only for units that otherwise have no movement speed.
    • It's possible for a unit to have a movement speed and an orbital speed around a planet, and in that case it would show the normal speed there.
  • The full orbital information is now shown just below where the speed group information would normally be shown in the tooltip.
  • If a unit has a parent, it now shows that in the tooltips. It also specifies if it dies with the parent or not.
    • And parents talk about how many children they can make, and what types they are, and how much of each type they are.
    • In the UI, the terms used are:
      • Progenitor: to refer to a parent that can create children.
      • Descendant: to refer to those children.
      • Ancestor: to refer to the parent of a given child.

Bugfixes

  • Fixed an exception that could happen if you tried to launch the test chamber without first entering the lobby. This was new since 3.5 and pooling-related. It's possible that this might have affected multiplayer clients or tutorials or something as well, but it's hard to be sure.
  • Fixed any possibility of the multiplayer client accidentally prematurely declaring victory (or loss).
    • That was happening because of various sync issues, but won't anymore.
  • When in the test chamber, it now says campaign type: test chamber.
    • If it says something else, then it's not in the correct mode for some reason.
  • Fixed a bug in last night's release where the new "children of ships" feature threw an exception when used. It now works properly.
  • In the event that your campaign name is blank for some reason when you get to the save menu, it now will set it.
    • If you're in the test chamber, it sets it to Test Chamber.
    • If in a tutorial, it sets it to Tutorial.
    • Otherwise it just uses General.
  • Changed things around a bit so that some stance data is not copied to units that are stationary or orbiting in a way that they can't use it.
  • I was going to try to fix some desyncs that happen in multiplayer (turns out there are a TON) related to the random generator on the Context objects, but the initial approach was a bust and so I'll take another crack at it tomorrow.
    • Those various changes are all reverted, so that the new approach can be tried fresh.

Orbiter Work

  • Rather than just warping instantly to the point they "should be at," orbiters now calculate the angle they should be at, store that, and calculate their desired point. They then move towards that point without teleporting there.
    • This solves most of the strangeness with the orbiters, and turning off all collision logic for orbiters with other units helps keep them even more in line.
  • There is a new attempts_to_reach_orbital_point_at_speed="number" in DLC3, and this defaults to 5000.
    • This defines how fast an orbiter will try to get into their desired orbit. It must be a number greater than 0, and really anything that is very low is likely to lead to some very strange results.
    • When they are trying to board a transport, they will move at 2x this speed.
    • The further units are away from their target point, the faster they will go in order to try to catch up to it, as well, which helps them sort themselves out after the flock is disturbed.
  • This pair of items solves most of the strangeness in the orbital mechanics.
  • Rather than trying to move orbiters to the closest point to themselves, which was for some reason making it so that they only used about half the angles on the ring of angles that were calculated (seriously that code did not look wrong), they now just get assigned in a list around the ring.
    • The new behavior causes kind of a repeated bloom and rearrangement every time a new descendant emerges form a progenitor or from the flagship, but it's at least smooth.
  • Fixed some issues where orbiters could be given inherited movement orders from their flagship, which would just muddy things up and not actually accomplish much.
  • Adjusted the base orbiter AttemptsToReachOrbitalPointAtSpeed to be 3000 rather than 5000, since that lets the ring of orbiters deform more when their focal point moves around. Now that they're capable of reforming properly, the deformation is nice.
  • Weakened the amount of boost that orbiters get when they are further from their target. This lets them still correct themselves, but at the same time lets them deform more during movement, which keeps everything feeling more organic.

Beta 3.507 Spare A Moment For Your Orbitals

(Released August 10th, 2021)

  • A LOT of extra data has been added to the thread tracking details, most notably when you right-click the timer in the the bottom left of the main view.
    • So far what this seems to reveal is that threads are running more frequently than they should be, and some of the reporting on them may be incorrect.
    • Badger and I have both noticed some threads reporting failure to run for a long time, but it's intermittent, and that is one thing that is also meant to be investigated by this, but it's not happening since this bit was added.
  • Per a request from StarKelp, there is now a DoPerSecondLogic_Stage4AdvancedAllegianceCode_OnMainThreadAndPartOfSim, so we now have four stages of faction sim code, rather than just three.
    • This is useful for some DLC3 content, but potentially for mods down the line, too.
    • This is completely untested so far, but should work.
  • Mat.GetPointFromCircleCenterOppositeOtherPoint() added for StarKelp's use. Untested so far, but math should work.

Bugfixes

  • If the game is failing to find missing graphics (because of not-enabled expansions or mods), it now gives a more concise error message about that.
  • Some improvement to the tech window code to provide a more accurate count of upgradable ship lines. It does not fix problems with the turret count though.
    • Reported by a ton of people
  • Fixed an issue where immobile objects that were pushed around would look "jerky" as they moved from space to space.
    • This was something you'd see in rare cases of immobile objects being pushed by a forcefield or whatnot, and it was also affecting orbital units.

DLC Requirements Work

  • "VenatorGuardians" no longer complains on game start if you don't have DLC3 installed.
    • Thanks to Ecthelon for reporting.
  • The following mechanics now require DLC2/ZO to be installed in order for them to be useable:
    • beam_chains_out_to_targets_x_times, beam_chains_out_to_targets_x_range, beam_chains_out_to_target_min_range, beam_chains_out_to_max_targets_from_each_source.
    • inflicts_state_of_matter_on_target_for_seconds, state_of_matter_for_target_to_become, cannot_inflict_state_of_matter_if_target_has_any_shields_up, cannot_inflict_state_of_matter_if_target_has_energy_usage_of_at_least.
    • care_about_state_of_matter_to_be_enabled, must_be_this_state_of_matter_to_be_enabled, is_invisible_in_tooltips_if_not_a_match_by_state_of_matter.
    • returns_this_percentage_of_damage_when_firing_retalitatory_shot
    • state_of_matter_to_become_on_wormhole_exit
    • These were added specifically for that expansion, and we want to be sure that any mods that make use of these things also require the player to have DLC2.
  • Same deal with DLC1/TSR and these mechanics:
    • city_sockets, added_city_sockets_per_mark, city_socket_cost
    • ship_type_name_to_grant_more_of_in_custom_fleet, ship_type_count_to_grant_more_of_in_custom_fleet, ship_type_names_required_to_exist_in_custom_fleet, ship_type_counts_required_to_exist_in_custom_fleet
    • minimum_required_city_level_for_construction, base_ship_cap_in_custom_city, added_ship_cap_in_custom_city_per_city_level, added_ship_cap_in_custom_city_per_city_level_above_level
  • And DLC3/NA for these mechanics:
    • necromancer_science_to_grant_on_death, necromancer_hacking_to_grant_on_death
    • skeleton_tag, skeleton_type_percent, bonus_skeleton_percent, skeleton_cap_increase, skeleton_cap_increase_per_mark.
    • wight_tag, wight_type_percent, bonus_wight_percent, wight_cap_increase, wight_cap_increase_per_mark.
    • CanBeAVassal
  • The following require either DLC1, DLC2, OR DLC3 to be installed to work:
    • use_alternate_rate_of_fire_after_x_shots, alternate_rate_of_fire, use_alternate_rate_of_fire_for_x_shots_before_reverting.
  • The base game burst-fire rockets on the Raid Frigate are now Rapid-fire rockets with a slightly different balance, because of the restrictions on burst-fire mechanics requiring DLC2 now.
  • Fixed a problem where if you had DLC2 but not DLC1, you'd get an error about Makeshift Drones on startup, and the makeshift turrets from some of the outguard would not function.
    • Same deal with DLC2 and the drone automated construction bots, and again another outguard group.
  • The overall goal of all this is to make it so that each DLC can function independently, but also keeps its unique identity.
    • For modders, there is frequently the question "can I use X mechanic without the player having X DLC installed?" And now we have a clear answer on that versus just leaving it at the honor system. This will matter more into 2022 and beyond, really.

Features For DLC3: Orbits

  • Added a new is_blocked_from_transporting="true", which can be used to block any unit type that normally is transportable from being transportable.
    • Thanks to Zeus for requesting.
  • Units can now have a new orbits_flagship_at_range="number" on them, but only if DLC3 is enabled.
    • This can be paired with a new degrees_to_orbit_per_second="float", which should be a nonzero number that is betweeen -360 and 360. It can be as small as 0.001, positive or negative.
    • The negative or positive status determines the direction of rotation.
    • By default these CAN be transported, so use is_blocked_from_transporting="true" if you don't want them to be.
    • Note that this CAN also be applied to command stations if anyone wants to. Those are fleet leaders, just like any other flagship.
    • Thanks to Zeus for requesting.
  • There is a new build_points_per_second="float" that is for DLC3.
    • This lets any unit passively build children, kind of like a drone. It uses the same build points system as viral shredders or similar, but works differently. You can't combine a viral shredder with this type of per-second construction of stuff on a single unit.
    • There is also a new build_point_cost_for_per_second_construction="number" field that goes with it. This is how many build points must be reached in order to build a new item in this list.
    • There is also a new personal_ship_cap_for_per_second_build_point_construction="number" field, which is also required. It defaults to 1.
      • This is how many child ships can exist at a given time for a unit that builds children in this fashion. These could be orbiters, or just not-drones.
    • Finally, there is a new tag_to_spawn_from_for_build_point_for_per_second_construction="tagname", which specifies what tag will have a random unit built when this per-second process ends. So UNLIKE every other form of drone, you can mix and match like crazy here.
      • The unit capt that is noted above is the personal unit cap for the parent's children. So if the parent is able to spawn random children from a tag that happens to have 5 types in it, and it has a personal cap of 3, that parent will only ever have 3 children, chosen at random from the 5 types in the tag. That could be 3 identical ships, or any mix.
      • It's worth clarifying that the parent itself might be part of a line of ships that has a cap. It might be a turret, or a strikecraft, or a frigate. If it was a frigate line with a cap of 6, then each of the 6 would have a personal cap of 3 direct children (with the example above), and so you'd wind up with a random grab-bag of 18 children in all.
      • It's also worth clarifying that this CAN be daisy chained. So if each child had the same setup where it could self-build children from a different tag that has 3 other types in it, and it has a personal cap of 2, then you could wind up with 32 grandchildren. That's assuming all 5 of the child types each had 2 children of their own, which is in no way mandatory.
      • Final note: it's probably not a good idea to recursively have children and grandchildren from the same tag group. Yes it will work, but you'll create an infinite cycle of generations that will eventually swallow the game whole. If every child can have children, in a loop on down, then it's only a matter of time before the galaxy is nothing but nth-generation children grinding the simulation to a halt.
    • There is also a new dies_if_parent_dies="true". This only affects units that are built from a parent via these build points per second. This is a good idea to have on any orbiters of that sort, but it's not mandatory. They'll just stop moving where they are if their parent dies, otherwise.
    • Units that use any of these mechanics will not stack, so be careful when it comes to tons of small units.
  • There is also now a new orbits_parent_at_range="number" that is for DLC3.
    • This does nothing unless the unit was produced via the per-sim-step child build process noted above.
    • If it's produced in that fashion, then the orbiter will be locked to its parent, which could itself be orbiting another parent.
    • If there are multiple children of the same parent and they have the same orbital distance, they will all be redistributed around the parent evenly when a new one is created.
      • In the events that one parent has a lot of children with many various orbits, only ones that match one another will line up. They can be whatever types, the only thing that matters is the orbit distance itself.
      • In other words, it's possible to have recursive orbiters via the recursive parenting methods above.
  • There is also now a new orbits_gravity_well_center_at_its_current_radius="true" that is for DLC3.
    • Units that use this will orbit around the center of the planet they are at based on a fixed spin speed based on their current distance from the planet center.
    • These units do not sync up with one another, and units that are further out will orbit faster than those closer in (as with a record or CD) since there is a constant angular spin speed being applied here.
    • This CAN be used on units with traditionally-mobile units, unlike the other types of orbital mechanics. However, it might be impossible for ships with this applied to reach target points near the edge of the gravity well.
      • All other ships that use orbits are forced to only orbit whatever their parent is, and of course they move in an orbit and also move as their parent moves; but they don't fly of their own volition.
      • Most units that use orbiting around the grav well center should also probably be set up that way, but you CAN set them up so that their actual engines work and they are fighting against the power of a gravity well. Probably best only for NPC units, as it may be hilariously frustrating for these units to reach a goal position, and/or impossible at times. Those sorts of uses are outside of the intended scope of this; it's just a fun side thing.
  • A ParentGameEntityID is now on units, which can be used to link them up for the sort of parentage mechanics above.
    • We also serialize this into the savegame and across the network now, along with buildpoints at the individual unit, which previously were not serialized (that was just used by hydra heads, not viral shredders, so it was not a common problem).
  • There is now a DoEntityStepLogic_Ship_Late() method that gets called for ships with orbital movement, as well as ships with children.
    • This lets children link up with parents early, and other movement happen early if need be.
    • This then lets us late process orbital motion (which is not subject to engine stun, paralysis, being disabled, or any other factor).
      • Also worth noting that orbiters CAN be hit by tractor beams, but tractor beams do nothing to hold them still. This has a few ramifications:
        • If you flood a tractor beam area with orbiters, then the tractors may uselessly grab them, leaving room for other ships to pass through.
        • If a reverse tractor beam (like the mosquito mechanic) grabs an orbiter, it will be pulled in the orbital path along with the orbiter.
    • And also late process the building of new children, after we're sure how many children we already have if we're a child-builder.
  • Added a new Mat.OrbitPointFromCircleCenterAtSpeed(), which handles all of our orbiting code.
    • One interesting feature of this is that we're not actually remembering the intended angle between an orbiter and the thing it is orbiting, so if the parent object moves very fast away from the orbiter, that will adjust the angle of the orbiter as if it is experiencing drag.
      • Conversely, if the unit that the ship is orbiting moves very fast toward it, then it will accelerate the orbit, almost as if it's being slingshotted.
    • This should look very interesting in terms of visual effect, and we're not trying to simulate actual orbital mechanics here in the first place.
  • Added a variant of Mat.FillRingOfPointsAtDistance() which allows for a specific starting angle to be passed into the ring.
  • Previously, it was possible for some units that are not allowed to stack to build straight into a stack. Fixed.
    • Similarly, it was possible for some units that are now transportable to be built right into transport mode when the flagship is in transport load mode. Fixed.

Beta 3.506 Setsuna Notices A Lobotomy

(Released August 9th, 2021)

SirLimbo Fixes

  • Shot Compression fixes:
    • Fixed an error that would occur when a suicide weapon (such as Tesla Torpedoes) would hit a target with revenge shot mechanic (such as an Adaptive Matrix Fortress. Parts of the hardening against multi-threading exceptions caused the code to return 0 possible hit events since the attacker technically had already died.
    • The debug info for this now also shows which weapon system and how many compressed shots were used.
      • Thanks to Ecthelon for reporting and offering a very helpful save.
    • During the review of that code, found a huge bug that would likely cause AoE shots to overestimate how many hit events they could get on a stack of ships, as it used the AoE range instead of the maximum amount of targets possible to hit. This had likely caused a large amount of AoE units to deal way more damage than they should have.
    • After the other bugs, found that AoE units were not correctly applying shot compression to their AoE hit count, which in many cases would have caused them to deal way less damage than they should have.
    • Found out that the AoE hit calculations were using an entirely false method. Fixed this, and made the debug info a bit more clear (there were variables named deceptively wrong, which can cause all kinds of havoc while trying to debug).
      • In other words: AoE was totally broken most of the time. Now stack of ships with AoE shots vs stacks of ships has once again been tested, manually recalculated and confirmed to be working (so far). But keep your eyes on the lookout for other bugs - it's imposible to test every possible situation.
    • Fixed a number of exceptions due to missing null checks in the debug printouts for Coilbeam and AoE shot math if the target was null (most likely this only happened when it just died). This would only show if these debug options are enabled during gameplay.
    • Also hardened the AoE and Beam damage dealing code against potential unexpected results.
  • Fixed a bug where entities under construction would already cost energy if they had negative energy production. This fixes AJEA (Auto-Juggle Energy Assistant) being confused because it's mechanism reverse-engineering the actual energy capacitates of the player no longer matched the actual processes.
  • Adjusted AMU, Kaizers Marauders and Devourer Chrysalis to changes in the Vanilla codebase.
    • Kaizers Marauders and Devourer Chrysalis now also have their Visual Studio projects included - for more interested players who might want to see how they are coded, and in case anything ever happens to the local copies on my computer.

Threading Improvements Across The Board

  • The "Suppress Normal Multithreading" debug option has been removed. It is long-since past time where that was really a valid way to run the game.
  • "QueueGameCommand" was ALMOST a threadsafe call at this point, but not quite. From very long ago, we've been working around it as if it was not, and that has had various slightly unpleasant effects.
    • Let's start by making it threadsafe:
      • The NumberQueuedForExecutionSinceGameStarted on game command types is now incremented via System.Threading.Interlocked.
      • If we're not on the main thread, we do not make a call to ReactToOrderJustIssued() (hey, this is excellent anyhow since an algorithmic decision of some sort just happened, and you don't want any sound effects from those anyway).
      • Beyond that, this is being added to a ConcurrentQueue, and thus has been threadsafe since Julu 2020 when we made those changes.
    • Now that we're threadsafe for adding commands to the central queue, there's really no reason not to do that as soon as possible.
      • Previously, we were adding to a separate list of commands on each background thread, which ITSELF had to be threadsafe in case that thread spawned sub-threads, and then when the main thread was done it would add all the commands from that collection to the main collection. What a waste of CPU time! Not egregious, but it's quite old-school in its implementation. This is how we rolled in AI War 1.
      • One of the concerns here is that the commands from the secondary collection might not get added to the main thread for some reason, particularly given how the final chain of events saying "this thread is now done" were handled.
        • That chain of events has changed a bit recently, becoming simpler and nicer so that it can kick off faster, and it's possible that this was a negative side effect of those changes. So by bypassing any sort of global "must happen at the end of this thread or major things go wrong" type logic in the first place, we avoid edge cases... and gain slightly better performance in the process, since those edge cases might not actually have been happening.
        • "Better performance" might not sound impressive for something that really is just a few CPU cycles, but we're talking here about thread synchronization, which is a bit up to the OS and can take surprisingly long to happen (on a nanosecond/microsecond type scale). Since we have so many threads, its a really great idea to not borrow trouble with this sort of thing. It's harder to read such code, too, anyway.
    • Our background sim contexts thus no longer have the ForceImmediateQueueOfMyCommands() method (that was used to space out commands between sim frames that are 100ms apart and avoid flooding them after a big processing chunk), and no longer has its own QueuedCommands.
    • Similarly, the QueueCommandForSendingAtEndOfContext() that was used up until now has been marked as obsolete, with it instructing programmers to call World_AIW2.Instance.QueueGameCommand( command, false ) directly, which is what it now does. But the translation layer is there already for mods.
    • This also means that we're able to completely avoid having a QueuePlanningCommands() method, which was slow, on the main thread, and sometimes had to wait on joins from other threads. The older your CPU, probably the more this helps performance.
    • Also also, this means that we could get rid of the HandleEndOfIntermittentLongRangePlanningCycle GameCommand, which was something that we used to have to try to have synchronization between hosts and clients, but now was just wasted bandwidth (like a few kb an hour, but still). Actually it was always wasted bandwidth, because LRP threads only happen on the host in the first place. Oops.
    • This cumulatively now means that we can have serial commands to SetWorkDone() from a couple of parts of the threading code, and it won't hurt anything if it gets called more than once. Previously there was a vague risk of deadlocks, or more likely just a performance hit.
      • With that change, again this lets us shorten the number of microseconds between thread changeovers.
        • This also lets us call HandleEndOfIntermittentLongRangePlanningCycle() about 100-200ms faster than we otherwise would, which means that those threads turn over that much faster AND entities can be removed from the game more quickly. That shouldn't matter a whole lot in any reasonable use case, but it's still nice.
    • Several other threads now get cleaned up a bit better than they previously did, but it probably doesn't really matter.
  • Okay! Now here's the REAL thing that I've been building toward with all of these changes.
    • We're now able to track, at a thread level and at a faction level, when certain pieces of logic have not been run in a reasonable amount of time (and it does take into account when you pause the game, etc).
    • Essentially, for regular threads, they are expected to be in some sort of emergency status if they haven't run after 10 seconds since they last ran. For those that are faction-long-range-planning-based, those are considerably more relaxed (they have a lot more to think about, and actually think on the scale of seconds rather than milliseconds in many cases). So we give them 30s before we consider it an emergency.
    • Normally the only way for something like this to turn off is because of an exception on a background thread. But some of the changes I made recently to make factions of different types that use the same external-code-implementation not run at the same time seems to have made some factions not run at all, or only some of the time.
      • That led to really strange things like the Zenith Trader stopping moving because its LRP thread went braindead, and we also see instances of the Warden or certain groups of zombies or all sorts of other things doing this.
      • It's most dramatic with the Zenith Trader, because all it does is move between planets. Most ships also get some short-term orders on what to shoot and where to move, and that doesn't require higher brain function. So you might be fighting a lobotomized AI but not know it, in a lot of these bugs from recent versions.
        • At any rate, now we can SEE all of that, which is really great. And so can you! Rather than some faction just mysteriously acting strange, you now get a little thing in the right of the screen informing you that it hasn't run that code for X amount of time, and warning you about that.
        • This is doubly useful because we track both factions AND threads. So if a thread is run, but only for one out of several valid factions that are supposed to share that in turn (time-slicing), you'll see that.
  • GetEverShouldRunAnyLogic() on the special faction implementation logic was only worthwhile when we were not running massively parallel faction threads. Since then it's been useless, but it does add some complexity and a potential for bugs. So it has now been removed.
    • Same as above with a EverNeedsToRunLongRangePlanning override variable in each external class. It's no longer needed at all, and was just confusing things. The miniscule performance gain from not kicking off a few background threads from another background thread is nothing compared to the confusion that this can bring, but that was not apparent when I was originally structuring the design for this part. Such is life; sometimes we realize the requirements more fully as time goes on and we see real life examples.
    • We also had a ArcenLongTermIntermittentPlanningContext.WaitingForMyCommandsToBeExecuted variable that seemed to be controlling some logic, but hasn't been for a really long number of years. It has been removed, affecting nothing except making the code simpler.

Fixing The Occasional NPC Faction Lobotomy

  • Found a MAJOR bug, finally, after recoding so much of the threading model and such. We couldn't figure out why some threads seemed not to run sometimes, but now we know.
    • Essentially, there was a LastStartedAtGameSecond field on the thread itself, which was bad juju.
      • Firstly, if you ran that in a game 3 hours in, then saved and loaded and went back to the main menu, it would not run because you are now "in the past" for that field, and it thinks it doesn't need to run for a long time. Restarting the game would make it run, though.
      • Secondly, if two factions in a single game use it, then faction 1 sets the variable, and faction 2 winds up never running, ever ever at all. This is because it moves to the next long term processing cycle when nobody is ready to execute, and faction 1 always goes first, and faction 1 and 2 were sharing the countdown timer. So faction 2 could never possibly execute.
    • Thus we have now moved this to a proper field on the faction itself, where it should always have been, and it's called LastIntermittentLongRangePlanningStartedAtGameSecond. It resets to 0 properly when the game is reset, and all is well.
    • HUGE thanks to Setsuna for her invaluable help in identifying what this was likely to be. It was a very strange and intermittent bug.

Beta 3.505 Long-Term-Thread Efficiency

(Released August 6th, 2021)

Bugfixing

  • Shot Compresion work:
    • Fixed a huge bug in Shot Compression that prevented stacks of ships from factoring in how many entities actually shot, thus limiting stack damage in most cases to only doing 1 unit worth of damage instead of simulating up to all stacks shooting.
    • Shots now also store how many stacks of the shooter were present, which is used in the calculations of how many hit events are actually valid. This fixes shots doing less damage if the entity that shot had stacks die off it between shooting and the shot hitting.
    • Thanks to NR SirLimbo for updating.
  • Updated 40-some "externaldata" classes. They all had EXTERNAL_TODO notes on them that it was time to take care of.
    • There are a number of hyper-funky gameplay bugs that are related to stale pool data, so here we are.
      • I tried reverting the external classes in general from being pooled, and almost our entire memory leak came back. So that's just not going to be a feasible option. The memory leak has likely gotten worse over time because of the extra data that modders and faction designers have been adding, and the way that the data is interconnected and thus can't fall to the garbage collector.
    • Right. In this particular case, for the "externaldata" classes, these things honestly get their data reset in InitializeData() even if we don't properly do a ClearAllMyDataForQuitToMainMenuOrBeforeNewMap(). So there's not a likely cause of any problems here unless we later discover that InitializeData() is not called after pooling events or something. Which, if that's the case, we'd start getting nullrefs now and be able to fix it.
    • There's another 45 EXTERNAL_TODO entries, and the problems that are leading to stale data must be in there.
    • Thanks to Setsuna and Zweihand for instigating this latest dive.
  • The externaldata in MacrophageHistiocytes and SKCivilianIndustry have both been fully updated, with the parts that matter and the parts that don't.
  • Went through all of the EXTERNAL_TODO entries that were remaining.
    • It's hard to say that much was accomplished with most factions and such, but the review was good.
    • The hunter was almost certainly broken by pooling, though, so this fixes that.
    • The core AI maybe had a bit of something, but it's hard to know if any of it mattered.
    • AI reserves had some bits cleaned up, but again dubious benefit. By which I mean it may have already been working just fine.
    • A bit on the dark spire, but honestly it all seemed fine.
    • Devourer and Dyson Sphere getting the treatment. Not sure how much it helps.
    • Fallen spire had a number of pooling errors, and one error that was old and unrelated and which was causing a UI list to just become a reference to a working list. Fixed that same bug in necromancer.
    • Fixed a very few minor things in the human faction class, but mostly just one bit of garbage collector hit.
    • Marauders seemed pretty okay, but defensively fixed some suspect stuff. Same with HRF.
    • Corrected a definite stale data issue with instigators. Not that I wanted to have a huge number of problems, but with so much code review it's gratifying to at least find something definite.
    • Some more of the same general updates with relentless ai waves, nomad planets, a bunch of others. Hard to be sure how much these matter.
    • Minor funky bug in sappers that came from list assignment over lists and could lead to unpredictable behavior, but beyond that class is clean. Defensive code just in case. Same in templars.
    • Found that the scourge would have another case of super severe stale data after pooling, and fixed that.
    • ZA updates, mostly minor, as it seemed in good shape already for pooling. Bear in mind that any classes called out were not coded in error; the pooling stuff is new, and this is just evaluating them for that purpose.
    • General diagnosis from all this: a big bunch of nothing, with a few rare exceptions.
      • THAT SAID, if you've coded a mod that includes a new faction, you really should give the same sort of once-over to your own member variables and properties.
        • If it's directly on the main special faction class, and it doesn't get cleared either in ClearAllMyDataForQuitToMainMenuOrBeforeNewMap() or every frame, then it's going to be stale data after pooling. So be sure and check what idioms you used in each class, as you might not have been consistent over time (we were not).
  • Helper_SendThreatOnRaid() now uses threadstatic variables that keep from having GC churn and also uses memory a bit more efficiently in general.
  • Fixed an issue with ProjectedMultiPathData where it could potentially be busted up because of not having enough room to pathfind for the number of planets in a given galaxy.
    • This might have been messing with the ability for units to pathfind in general, sometimes, in the last couple of versions.

Efficiency And Correctness For LRP Data

  • We previously had two sets of strength-counting data. One for long-range planning threads, and one for short-range ones and the main thread.
    • These have been combined down to use just the short-range one.
    • This majorly cuts down on some CPU time costs, and using my newer cross-threading techniques we can maintain the speed and also as much correctness as we needed.
    • For cases where in the past we might have to return null because of missing data, we now have a dummy result that we just hang back (this is all read-only in usage style) that prevents exceptions from happening.
    • It was actually possible that some of the LRP data of this sort was not being updated properly recently, but that sort of thing is hard to check.
  • Previously, IncomingStrength and WaitingStrength were only available for long-term planning threads, and this was incredibly expensive to calculate on a thread that blocks the simulation.
    • These variables are now available to ALL threads, and are calculated quite safely on the background strength counting thread. The counting is far more efficient this way, and available to more code.
    • This was a pretty big porting job, so a review would be appreciated by someone who will recognize the difference in correctness from looking at live data dumps (is that just Badger, or someone else also?)
  • The LongRangePlanningData objects for both planets and units have also been removed.
    • The idea here was to do a traditional multithreaded approach and have a stable copy of the data while the rest of the simulation moved on, but this was SLOW and we moved away from it in many ways.
    • This is mainly severing the last ties of that, and has new built-in methods on planet and gameentity_squad to replace these functions.
    • This is for performance, partly, but also since I have some seriously broken code of unknown location at the moment, I may as well reduce the surface area to search on it while I can.
  • Thanks to Setsuna and Zweihand for the bug reports that led to this refactor, and to Badger for suggesting the area in which parts of this could be hiding in relation to the Zenith Trader in particular.

Mod Updates

  • AMU:
    • Made the Dynamic Averaging Ring deserialization more clear by removing some unused variables and calculations.
    • Made the Get() function of the ConcurrentList class more clear and easy to use, returning the object in question instead of requiring it passed with an out reference.
  • Kaizers Marauders:
    • Finally committed to serializing the Dynamic Averaging Rings, after confirming ingame that they do indeed work properly.
      • This should fix issues where the extremely advanced but also complex spawning Kaizers Marauders do on very well fortified planets can stop the entire game sim for multiple seconds with ease.
    • Fixed a very misleading and false debugging readout with one of the notifications of Kaizers Marauders.
  • Devourer Chrysalis:
    • Added some more direct links a debugging clarity to the notifications.
  • Both Macrophage Histiocytes and Civilian Industry have been updated to work with the new version of the "game without long-term data separate" code.
    • This is not a slight change for most code mods, but it is a very formulaic one and it makes everything faster and smarter and less prone to data errors.
    • All other code mods will need similar updates.
  • AMU has now also been updated to use the new "game without long-term data separate" code, and at least one minor bug (boolean inversion) was fixed in the process of doing that.
  • cml recompiled AI Shield Generators again. It wasn't working as of the last update but this seems to have fixed it.
    • Chris note: and I probably broke it again, blah, sorry about that.

Beta 3.504 Multiplayer Achievements

(Released August 5th, 2021)

  • Your cursor now follows you smoothly around the ring of the interior of the gravity well, so if you try to give any out-of-bounds orders, it now clamps them to that location.
    • It was previously possible to give super invalid orders by clicking out of bounds and thus giving units impossible orders that also would complain on serialization.
    • As part of this, added some new efficient math functions, and also extended the area of our colliders for the play field so that there's no longer this deadzone out of a nearby square area.
    • This should also fix a really longstanding issue where the game would not let you build in the outermost 5% of the gravity well, but that bit is not 100% certain.
    • Thanks to Daniexpert for reporting.
  • Added 44 more achievements to Steam, bringing the total up from 154 to 198.
    • These achievements are all tied to Zenith Onslaught.

Multiplayer Achievements On Clients

  • The "api key" for achievements is now checked for conforming to the condensed string format, for multiplayer purposes.
  • The achievements specifically won during a given campaign are now tracked, and are passed from the client to the host.
    • Additionally, MOST achievements are now checked only on the host, not the client (except for a few client-specific ones), and the host decides when those are won.
    • This takes into account achievements that the host might already have won, but one or more clients might not have.
    • This should put an end to strange and spurious achievement-granting on the clients, and it moves us one step further to having even less data to transmit to the clients in some other areas.
    • This is not well-tested in multiplayer yet, but we'll be handling that soon.
  • Achievements that are based around total kills or losses are now explicitly calculated for all players combined in multiplayer.
    • Those that are based on territory controlled are also now counting all player territory together in multiplayer.
    • Same deal for accumulating resources of various kinds.
    • Same for those about killing a certain number of a specific unit.

Ship And Turret Visual Rotation Options

  • Our internal structures for angles by degrees have been updated with a more efficient variant of serialization (rounded to the nearest degree).
    • Our structures for radians have been updated to not support serialization, since you really should use the degrees version for that, given the precision of how we serialize data.
  • Units now keep track of what their rotation is, for the first time in a super duper long time (since probably 2018 or even earlier).
  • A new nonsim_rotation_speed="number" has been added to units. This can make a unit visually rotate, though that will have no effect on the sim (which is good!)
  • visual_squad_rotation_speed, which no units used, is now replaced by rotational_speed_to_reach_target_angle.
    • This defaults to 5, and expresses how quickly units can rotate in the vis layer to match their underlying sim angle. 5 is quite fast. If you want something more stately, you can do that.
  • A new nonsim_rotates_to_face_targets="true" can be added to units. This can make a unit turn to face wherever it was firing, when it fires, before then returning to whatever its natural rotation inclination was.
    • Ships that are moving will go ahead and keep rotating back to whatever direction they were traveling after a moment, so this will usually be best-used on turrets and other stationary structures.
    • If anything has is_turret="true", then it will automatically now also have this set on it.
  • Added a new nonsim_random_rotation_when_placed="true" option. Anything with this will have a random rotation when it is created, rather than always facing north.
    • This is automatically applied to all stationary objects, now.
  • Please note that we are discussing the Y rotation of units. Anything that has the rotation_x_of_ship or rotation_z_of_ship set will still function on those other two axes.
  • angles_offset_from_start_to_add_or_subtract_when_facing_target="number" has been added, but defaults to zero.
    • When turrets in particular turn to face their targets to fire upon them, many of them don't turn quite correctly. All of our ships that move are set up so that their starting angle is exactly forward, but for many turrets they were set to a jaunty angle off to the side.
    • By setting this value, folks who are inclined to do so could correct turrets with offsets so that they face properly forward. As it stands, it's a fairly minor cosmetic thing when you zoom in quite far.

Bugfixes

  • Making assignments into ArcenSparseLookups is now notably more efficient, and also no longer carries the risk of an exception in SetItemForKey().
    • That said, anyone who got an exception in SetItemForKey() probably had a threading issue as well, so it's not an exception that was hit frequently.
    • Thanks to Daniexpert for reporting.
  • The "Parallel Faction Processing" option, that was added long ago to the performance section for the CPU, has now been removed.
    • This was on by default, and works great when it's that way. It's been the default for years now, and if it's disabled then actually you're at risk of having very stupid NPCs and AIs.
  • Previously, if two factions had the same SpecialFactionType, then they would not run their long-range-planning at the same time. This has been sufficient until now, but was an accidental programmer trap at the same time.
    • If there were two different SpecialFactionTypes that used the same external code implementation (there are many valid reasons to do this), then they WOULD run at the same time, on two threads, and wreak a ton of problems.
    • Now this is based around the type of the externa code implementation rather than the SpecialFactionType, since that is more exclusive and solves the issue.
    • Thanks to Daniexpert for reporting.
  • Hardened a bunch of methods in EntitySystem against having cross-threading exceptions.
    • The original one with an exception reported was GetIsTargetValid().
    • Then also fixed another dozen or so. It's a lot of code!
  • After completing the above changes, decided that this was still too free-form and not adhering the principles of encapsulation enough.
    • Specifically, there were a lot of places in the code that had to worry about if the ParentEntity, TypeData, or DataForMark of a system were missing or wrong, and would try to fix them.
    • This has all been taken internal to EntitySystem itself, and other code is now restricted from trying to fix it. It's also more robust in that it keeps even wrong data until it has new non-null data to replace it, which means that we can't get wrong data from this being in the pool and still accessed by some random piece of distant code.
    • This change will require all code-based mods to be recompiled at the very least, and if there were and attempts in there to protect against stuff like DataForMark being null by reassigning it, those reassignment bits need to be taken out.
    • To modders: even if your code compiles without complaint, be sure to send in the new dll. We changed a number of direct variables into properties, so your dll will update its references appropriately even if you have no code complaints.
    • TLDR: yay less code, and it's more self-maintaining. This was becoming a rabbit warren of ongoing bugs over the last week, so it was time to nip that before it kept going.
    • Thanks to Daniexpert for the most recent report on this subject.
  • Macrophage Histiocytes, Civilian Industries, and AMU have all already been updated, since I had the code to those in the official repository.
    • cml also recompiled AI Shield Generators, so those are good to go.
  • Somehow it is still possible to get references to the FakeEntity added into commands. Really not sure how yet!
    • The most obvious theory is "a savegame that was loaded in versions 3.500 through 3.502," but potentially stuff started fresh on 3.503 still has this error somehow.
    • Since we have very little information at the moment right now, we have it give a better that starts out "Oi! Tried to serialize a reference to the FakeEntity! How did this even get into the GameCommand queue?" and then gives the full details of the GameCommand. So that way we can at least figure out where those are coming from.
    • Experiencing this exception should have no negative consequences other than the error log spam. If something else happens (spiraling ship counts, whatever), then that might actually be a separate bug, or it might be related to "what the heck is the FakeEntity doing over there in the first place?" We'll find out as folks duplicate this in the next version.
    • Thanks to Zweihand for reporting.
  • Fixed a new bug since 3.500 where it was impossible to change your campaign type to anything other than Humanity Ascendant.
    • Thanks to Daniexpert for reporting.

Beta 3.503 Multiplayer Sound

(Released August 4th, 2021)

Bugfixes

  • Turns out we had left behind some async calls to unity asset bundles. Those have all been switched to be synchronous, instead. These were not the calls where the game was deadlocking, but with the async call stuff happening you never know on what frame a callback might be coming back in.
    • In the prior version, Badger was able to get it to deadlock with about 1 in 15 frequency, so maybe this will solve that. Fingers crossed.
  • 967 separate load calls for icons are now combined into 8 central dictionaries.
    • This then allows us to load them faster, and to create text-embeddable dictionaries that are more efficient and also load faster.
    • This then ALSO allows for the UI to batch these together, so there are many fewer draw calls when showing something like the planet sidebar or the build submenu. This helps for performance on weaker GPUs in particular, but really on all of them.
    • The other idea behind this is that this reduction in load calls gives us fewer chances to deadlock, so it's a win-win-win.
  • Fixed an issue where CustomBaseMark was not being reset to 0 on units when they were put back in the pool. This may have led to occasional random units of higher marks.
    • Thanks to NR SirLimbo for discovering.
  • Fixed some minor variables that were not being properly reset when entities of any sort (shot, wormhole, unit) were put back into the pool. These ones were so minor they likely had zero effect, but it's better to be sure and we're doing a systematic check for units in particular right now.
  • On units, IsAfterANonHumanTeam_NonSim was not being reset (so lots of random units said they were "not after you," often including your own units!
    • Thanks to NR SirLimbo and others for discovering. It's time for a systematic review.
  • Split the GameEntity_Squad class into three files, to make searching the fields and the clear methods actually feasible.
  • All of the frameplan and BG working threads of units are now cleared or reset in DoAnyBelatedCleanupWhenComingOutOfPool() rather than DoEarlyCleanupWhenGoingBackIntoPool(), just to make sure that they get cleared AFTER any background threads have forgot about the unit.
    • It's possible this could have caused all sorts of minor issues that were frustrating but almost impossible to individually see, or it might have done nothing.
  • Reviewed another 175 variables on units that were needing to be reset when going back into the pool, and found the following additional problems beyond the two above mentioned ones:
    • BuildPoints (minor effect on some random units)
    • despawnVis (almost not effect)
    • ForceRepairImpossibleFor_Max15 (could make things non-repairable randomly when they are first created).
    • FramePlan_CloakingPointDelta_CacheForUI (probably no effect)
    • HackingSeed (basically no effect, except for a few extra bytes -- literally like 7 bytes) in the savegame here and there.
    • HullPointsLost was... strange in how it was set. It was probably fine, but we've made a better-safe-than-sorry adjustment to it.
    • LastSimFrameCalculatedMetalFlowFor_ClaimMe (maybe no effect?)
    • LastSimFrameCalculatedMetalFlowFor_HullRepairMe (maybe no effect?)
    • LastSimFrameCalculatedMetalFlowFor_ShieldRepairMe (maybe no effect?)
    • Network_ClientOnly_RequestFullSyncFromHost (saves some bandwidth, but no substantial effect)
    • Network_ClientOnly_SimCyclesSinceLastHostUpdate (likely to cause sync issues right at the start on clients)
    • Network_ClientOnly_SuspectedOfBeingGhost (likely to cause extra explosions and disappearance on clients, this is a bad bad one to not have cleared).
    • Network_ClientOnly_TimeStampLastRequestedFullSyncFromHost (not a big deal)
    • Network_ServerOnly_ForceFullSyncToClientsJustInCase (saves some bandwidth, but no substantial effect)
    • Network_ServerOnly_GameSecondLastFullySyncedNonSim (no effect of notice)
    • NonSim_NetworkSend_ExtraShips (Wrong data sent to client from host, with a fairly severe effect.)
    • NonSim_PlanetaryEnergyBoostFailedFromOthersBeingPresent (minor effect, if any)
    • NonSim_PlanetaryMetalBoostFailedFromOthersBeingPresent (minor effect, if any)
    • ReasonIterationRemoved (maybe a debugging visual effect?)
    • ShipGrantsList (this could have had rare gameplay consequences, and it explains one minor leak we never could explain before).
    • TimeStartedWaitingAsGhost (likely to cause extra explosions and disappearance on clients, this is a bad bad one to not have cleared).
    • WorkingDebugLogSyncDataExtra (likely no effect).
  • The temporary logging to "ArcenDebugImmediateModLog.txt" that we added in the previous version has been removed. Hopefully it will not be needed anymore, and it's very very unlikely to provide us with actual new information at this point.
  • Fixed an issue from the last few versions where the camera was off-centered the first time you entered the lobby.
  • Setting your desired starting planet no longer causes a regeneration of the map view when you do so. This is particularly nice for multiplayer, but in general just works better.
    • Thanks to Zweihand for reporting an issue related to this, but only partially caused by it.
  • MapRandomSeed has been removed from the world object, and we now instead use World_AIW2.Instance.SetupStoredLongTerm.Seed.
    • World_AIW2.Instance.SetupStoredLongTerm.Seed in general is handled more consistently in general. Before we were trying to sync these for no good reason.
    • Recently, and possibly further back, there were a lot of cases that could involve MapRandomSeed being zero.
      • On the one hand, this would lead to the first regeneration of the map to completely give you something different (and that might be when you actually went into the game!).
      • On the other, it could lead into a scrambling every time certain other changes were made in multiplayer, like the changing of starting planets.
    • All of that seems to be fixed now. This was affecting single player and multiplayer.
    • Thanks to Zweihand for reporting.
  • Fixed a tip of the day about TSS and ODSS that said capture them rather than hack them.
    • Thanks to Setsuna for reporting.
  • Split the EntitySystem class so that it would be capable of having a systematic review of it done like we did for units. There are some variables not being cleared properly for pooling in here.
  • Did a systematic review of the 22 fields on EntitySystem for pooling errors, and found the following:
    • Put in an extra safety valve for CurrentFRDTarget, although it was probably fine.
      • Same with targetPriorityList. Essentially, there was the chance it was being written to after death but before being pulled back out of the pool.
    • The latter in particular seems to have been happening, as kind of a cross-threading error. Beyond that, all of the fields look good.
    • Thanks to Zweihand for reporting.
  • Fixed a piece of debugging text that got left in place from 7/15 of this year, which said "HasNotYetBBeenFullyClaimed: True giving the ok"
    • Do bear in mind that even if the wording seems like it should not have applied, this was stale saved data from previously when it had not yet been captured. It was just a really incomplete part of a debug log.
    • Thanks to Setsuna for reporting.
  • GetRandomHumanHomeCommandStation() will now return null if it has no entries to find, versus throwing an exception. This is relevant for post-loss in single player, and could be useful in general in the future in various ways.
  • The message that starts out like "To properly be stored, the value of each combat space coordinate must be between -262,143 and +262,143 but the coordinates" was previously showing wrong values for what the actual x and y were (they were shown as clamped), so that was not very helpful. Now it shows the actual values.
    • Thanks to Badger for reporting.
  • PrivateCounterattackNotifier.RenderContents now has better error reporting, but the error that was seen there in 3.500 is we THINK fixed. If not, we'll get a better error from it next time. We were seeing this in both solo and MP play, so it should be fixed.
    • Thanks to Badger for reporting.
  • Fixed a variety of cross-threading issues that could now happen during TargetListPlanning and spam errors at you, if you were unlucky, since the new betas.
    • Thanks to Zweihand for reporting.
  • Fixed an exception that could happen during serialization when there was a system with a null type.
    • This was most likely bad data from some other problems with the way entities were being mangled in the prior couple of builds in pools, but it's good to be on the safe side at every level anyhow.
    • Thanks to Zweihand for reporting.

Corrected Drone Construction

  • Removed all the old code for calculating drone construction internally for ships.
    • It doesn't have much to do with other metal flows, and thus just does not belong there.
      • Specifically it doesn't cost any metal, nothing should be able to boost it to be faster, and so on.
    • Also the code was really confusing and has been broken in a lot of strange cases (but not all) ever since the July revamp of metal flows.
  • Added a new DoForFleetsParallel() set of methods on World which let us do rapid parallel processing of fleets where needed.
  • There is all-new drone construction logic (well, a lot of it was ported over) that runs in parallel for each fleet, and which calculates itself super efficiently and correctly.
    • One thing among many that was funky in the old drone construction math was that if a fleet had multiple drone types it would give diminishing amounts to each one beyond the first.
    • Another strange thing with the old drone construction logic was that it constructed in fits and starts, unlike other kinds of construction, and it was really not clear why.
    • Now so long a the game isn't paused, and the flagship/centerpiece is not crippled, drones should construct at a steady rate. You're not charged metal for this (never have been), so it's simply handled in the quickest way possible.
    • This also fixes several bits of error spam that folks were able to get in July.
    • Thanks to GreatYng, Daniexpert, Exlium, Tzarro, Setsuna, CrusaderKhan, and slake-moth for reporting.

Major Sound Effect Bug From 2018 Fixed

  • People have complained for some time that there could be odd delays in sound processing if there was a lot going on. With that in mind, we have converted the central collections that hold those sorts of things into concurrent collection types that work across threads better.
    • It's entirely possible -- but not a definite thing -- that these were having some issues for some people as-described because of multiple threads queueing sounds at once and the non-threadsafe collections not handling it properly.
  • Fixed a bug that has been present sinece (cough) April 8th, 2018 where some sound effects that were supposed to play in a delayed fashion would play REALLY delayed, or maybe not at all.
    • The root of this was a boolean inversion. My first part of the code says "hey don't play this until at least half a second has passed, okay?" My second part of the code would reply "No problem. I'll play it only in the next half second, or never."
    • This caused various forms of issues, but we don't use enough delayed sound effects for it to have been caught prior to now. I only found it today because I was rewriting the code to work with concurrent collections to try to bypass what I thought was the problem (likely it was PART of the problem).
  • If you are suspicious that there is still a backlog building up, there is now a display in the escape menu down at the bottom of the memory profiling section that says "XX Queued Sounds"
    • If that number is higher than 10, it will be in red as a warning. It should not stay at any large number for very long or something may be wrong.

Multiplayer Improvements

  • Sound effects now have a random seed passed into them for deterministic playback, rather than it being truly random.
    • It's still random wherever the deterministic seed is calculated, but in multiplayer that means the host so everyone hears the same thing.
  • A variety of methods that involve generating voice lines or doing other after-death stuff now only happens on the multiplayer host.
    • This keeps the client from generating various kinds of errors from only having part of the data, and from playing (or missing) voice lines.
  • There is now a SoundPropagation that gets specified for every sound effect. There are those that just play locally based on context (battle sounds, mainly), and then those that are played in a host-directed manner (aka voice lines, etc).
    • This latter category is a new style of data for the host to pass to the client, but it's one of those things where the host will always calculate it correctly and the client often won't, so it's better to just pass it over.
  • We have a new NetworkSoundPlaybackRequest that can handle delayed and immediate style requests, and which network hosts pass to clients as well as themselves.
    • This is a case where we want the experience on the client and host to match as closely as possible, so if audio is dropping out the host will also know about it.
    • We have various data that the server "fast blasts" to clients, so for this we are "omni blasting" to clients and the self.
    • This is absolutely completely untested, but only affects multiplayer. We'll test it tomorrow hopefully, but since this is the beta branch you get first crack at it if you want.
      • If the AI ever taunts both the client and the host, you know it's working. Same if there's ever a warning about science exhausted at a planet on the client and host.

Tooling Improvements

  • Added some details to how we load assets from asset bundles, to make it super duper clear if we need to load a copy of the cached object or if we can use the direct object.
    • There were some cases where we were making a copy but did not need to, and that just added slightly to the loading time.
  • Revised how thread safety is handled for stacks of units.
    • Instead of having a stackLock that we lock to set values with, we now use System.Threading.Interlocked.
      • extraStackedSquadsInThis_DoNotAlterDirectlyEVER had to become an int32 rather than an int16 for that to work.
    • This actually will have numerous benefits of data correctness on multiplayer clients, as well, which is good. Before they had not been using the lock, since it put them at risk of deadlock.
  • Added a new IsValidForCondensedFormat() string extension, and are using it to check if the SFXItem name is valid for multiplayer use or not.
    • Right now they all should be, but this keeps us from having nasty surprises.
  • Split up the fast blast and omni blast code into their own files for easier organization.
  • Added some handy overloads on our custom serializer to make it very slightly easier to use.

Beta 3.502 Input Salve

(Released August 3rd, 2021)

  • If you try to ctrl+click a wormhole and send units through, it now gives you a text warning if any can't because they are immobile, station-keepers, loading into a transport, or on another planet.
    • This is a nice minor QoL thing that came out of developer confusion.

Bugfixes

  • Fixed a bug in the prior version where "Unknown surrograte table - RandomFactionType" was thrown when you started the game if you did not have DLC3 installed. This was also preventing Random Factions from working in the prior version if you did not have DLC3 installed (they were moved from DLC3 to the base game).
    • Thanks to Setsuna for reporting.
  • Fixed a cross-threading exception that could happen on GetMarkLevelOfContents().
    • Thanks to Badger for reporting.
  • Fixed a really irritating bug from July 21 where, in an attempt to gain an infinitesimal amount of performance gain from the UI, I had the game start hiding the canvas of tooltip windows rather than just the window itself. This caused really random and sporadic display of many kinds of tooltips, but it was more noticeable when trying to hover over units on the galaxy map. Some patterns did seem to be trying to emerge (it's it mainly capturable units? etc), but they were all coincidences.
    • The performance gain was so tiny, and clearly has not been critical for these past four plus years, so it's just been removed.
  • Added code to InitOnceOnlyEverOrBadThingsHappen() that will freak out if it's ever called from not the main thread. Just in case.
  • Inside GetOrCreateSpecialEffectGroup(), we are now locking on the SpecialEffectGroups dictionary. It doesn't seem likely that we were running into a deadlock with it, but we are having a rare deadlock somewhere in a nearby code chain at the very least, and this costs next to no CPU time given how it runs. So, why not.
  • Just to be on the ultra paranoid safe side, GetShipInstanceRendererByName() and GetShotInstanceRendererByName() both now lock on their internal dictionaries when they are doing additions or calls. Again this is very little CPU cost, but would in theory prevent a deadlock. But no deadlock should be possible from this, so...
  • Got rid of AllItemsEverAsync, which was probably wasteful though probably not our deadlock. Instead we now just have a simple counter, since that's all we were using it for anyhow. And that counter does use System.Threading.Interlocked to be threadsafe.
  • All of the ship icons and death effect materials are now loaded synchronously, rather than asynchronously. These are tiny files, there are very few of them, and having this spin up asynchronous unity threads was probably more of a slowdown than a help on some machines, aside from the possibility of something going wrong.
  • All of the async unity object load calls are now synchronous instead.
    • We weren't actually saving any time at this point during loading, and on slower older CPUs may actually have been extending the time.
    • In ArcenGameObjectResourcePool, we are also now being overly cautious with our internal pools there and using locks to make sure that we don't do anything unexpected. All of that should be on one thread anyhow, because those things largely don't function on background threads already, but again better safe than sorry.
    • It's expected that the occasional deadlock that has been coming up more recently should now be fixed, but it's hard to know without giving it more time and seeing if anyone runs into it again.
  • Fixed a really stupid error in FixAnyOverlordsOfWrongType_OnLoadOnly() where it was throwing an exception about not being able to find the difficulty of the AI type (it being -1), because we just forgot to assign the variable.
  • Added a new CountDownPerSimFrameIfNeeded() that can execute some code 10 sim frames after the game is unpaused (that's 1 second after first unpause). This is not currently used, but any coder who needs it now can use it. Just search for the code "Anything that you want to run a bit late, after the game has started, can go here!!"
  • We are now temporarily writing a ArcenDebugImmediateModLog.txt file, which is helping us to debug the hang that we get on load of the game program sometimes.
    • If the game hangs for you, then after you kill it please send us that file. It has no personally-identifiable information at all in it (well, a couple of path names that could be installed in your user folder on osx and linux, but that's it).
  • All of the icons used in the game are now read/writeable, as that was potentially an exception that was causing some of them to hang on load.
    • This did not solve the hang, but it did speed up loading slightly and might be related to a fix for that.
  • We removed a ton of Camera.Play classes that were not in use, and which would have been making lots of Resources.Load calls IF they were actually initialized (which they were not, but it's good to be sure).
    • There are some reports of Resources.Load() and loading from asset bundles clashing in older versions of unity, and that might be a regression that has returned.
    • The one bit of camera.play that we were using did have a Shader.Find() and a Resources.Load(), but it was a Chris-based version of the fade in and out shader. This has now been made to work a different way that just uses central data, so no more resources.load.
  • FBX Exporter has been removed from the main project since we don't use it often from there and it had a Resources.Load call.
  • Almost a hundred camera filter fx pack filters have been removed, as we were not using them anyhow. The five that we do use have been customized to start more efficiently and no longer call resources.load() or shader.find().
    • At this point there are still 70 calls to resource.load() left, and 55 calls to shader.find(). Whether it's practical -- or required -- to cull all of those remains to be seen. For now it's at least harder to get the frozen game on start.
  • Fixes for Energy and Metal Consumption:
    • Fixed a bug in GetFullyMultipliedMetalToProduce and GetFullyMultipliedEnergyToProduce as well as GetFullyMultipliedMetalToProduce and GetFullyMultipliedEnergyToProduce where it prevented negative values, which essentially meant entirely free energy converters.
    • Fixed another bug with Energy Converters not actually costing their metal upkeep.
    • Entities with negative energy production now are displayed in the "Current Energy Production And Consumption" window.
    • Fixed said window displaying 0 unit and 0 energy cost for every entry. This was an UI-only bug.
    • Thanks to NR SirLimbo for fixing these!

Input Handling

  • Vastly updated the input code once again.
    • First, there's no time limit related to single-clicks anymore. Mouseups, that is.
    • Second, we now once again use mousedown for detecting when you click, rather than mouseup. That just feels way more responsive.
      • This does mean that, definitively, you can't bind something like the grab and pan to the right mouse button without it also triggering the right mouse click. You'll need to use the middle mouse button, or mouse4 or 5 if you have those.
    • Third, In the mouse event handling code in particular, we now handle ALL of the events that come in a frame, which includes double-clicks and single-clicks from either button, all at once if needed. This is something that has a lot of common with the central windows pipeline pump, and should keep certain things from otherwise being blocked.
    • Third, the way that we activate bandbox selection mode is a bit different now, and more responsive. There were some funky bits in the code in general that just needed to get ironed out.
    • All in all, things just feel a lot more responsive now, and the double-clicking logic still works just fine.
    • Thanks to Zweihand, Exlium, RedPine, and others for reporting.

Mod Updates

  • AI Shield Generators can now be chosen as a random faction by the Pure Random and AI Empowerer random types.
    • Thanks to cml for adding for this mod!
  • Mod Updates:
    • AMU:
      • Fixed a bug with the new loading event chain where all allegiances were out of whack.
      • Fixed another bug with the new loading event chain where all external data would reset to default, causing major issues.
        • Both of these bugs affected Kaizers Marauders and Devourer Chrysalis.
    • Kaizers Marauders:
      • Missed change from before: Superstructures, if the planet is not explored, will no longer reveal it when clicking onto it.
      • Fixed an error on startup with Kaizers Marauders, due to the new chain loading data.
      • Put in hardening against another error game loading.
    • Devourer Chrysalis:
      • Fixed an extraordinarily stupid chain of loading error that would break the faction entirely after loading a save.
      • Removed a bit data written upon loading a save to the debug log for no more reason.
    • Exotic Ships:
      • Some of the destroyers are now correctly gated behind The Neinzul Abyss, identifying as DLC 3.

3.501 Shot Compression And Bugsmashing

(Released August 2nd, 2021)

Still too many bugs to be truly the fully playable version, but things are improving rapidly.

  • The main menu no longer has four DLC logos. Echoes of the Ancients is being retired as an expansion idea. Many concepts from it are instead being merged into the upcoming The Neinzul Abyss.

Random Factions

  • Random factions have been moved out of DLC3 (The Neinzul Abyss) into the main game! Definitely an exciting new feature.

"Shot Compression" Feature, by NR SirLimbo

  • Created Shot Compression:
    • Effectively Shot Compression replaces the old "extra damage per stack" and "extra shots per stack" as well as "damage multiplier to stack" mechanics and replaces them with what is effectively stacks for shots.
      • For modders: Note that this may require your mod to be adjusted if you artificially created shots, or directly applied damage to entities.
    • Each weapon with more than 1 shot per salvo can also define a "shots_per_target" (default 1) and "added_shots_per_target_per_mark" (default 0).
    • Per-salvo and per-target interact like this: Per-salvo defines the maximum amount of shots for each attack this weapon does. Per-target defines how many of these shots can be fired at the same target. Note that stacks on the target entity increase this limit.
    • So to achieve AIWC-multishot the per-target shots must be at least equal to the per-salvo shots. This allows for a very fine definition of how shots interact:
      • 10 per-salvo shots with a per-target value of 3 fired at single ship will fire 3 of its 10 shots at that one target.
      • If the target is a stack of 3 ships, up to 9 shots may be fired at that target.
      • This multiplies with the stacks of the shooter: If it is a stack of 5 ships, then up to 45 shots may be fired at the target.
      • When hitting the compressed shot count acts as a multiplier to the damage inflicted, and sets the limit on how many stacks can be killed by this shot alone. This means that a fully upgraded Artillery Golem shooting at a stack 100 weak ships will only ever kill a single ship per shot.
        • The "dealable" damage estimation has been updated to think of how many stacks it can kill, if any, and thus big weapons that can't also kill many stacks should no longer aim to attack big stacks.
      • AoE and multi-hitting beam weapons factor into this as well, dealing as many damage instances to the targets as their shot limit allows: A Grenade Launcher Corvette with up to 9 targets for it's AoE grenade shooting at a stack of 9+ ships will deal its full damage to that one stack (but nothing else).
      • The maximum amount of stacks killed for one hit is effectively compressed shots times now, though weapons can still have a number of extra stacks killed per single shot such as Ion Cannons. If a limit to the amount of stacks killed per shot exists, it is multiplied by the compressed shot count.
      • Multiple parts in the code where ships could kill unlimited quantities of (revenge shots, electrotoxicity, etc) are now limited to the compressed shots, potentially multiplied by their weapon's hit stack kill count.
      • Flat Acid damage applies per stacked shot, so when a single shot worth 5 compressed shots inside hits a target that receives 10 bonus damage per incoming shot, the total acid bonus (before damage multipliers) is 50.
      • As these shots will be the same GameEntity_Shot entity, this should actually increase the game performance, as less actual shots are created. Furthermore, as AoE calculations can be avoided using this performance especially in large fights with lots of (stacked) entities should go up even further.
    • A few extra mechanics to note:
      • Ships will aim to fire as many shots at the same entity as possible, so say a stack of 3 MLRS Corvettes, 8 shots per corvette, only 1 per target allowed, when facing 2 stacks of 5 VWings each will fire 15 out of its 24 shots at the first stack and the remaining 9 at the 2nd stack. Visually, at least for the moment, only 2 shots will be fired at all.
      • Retaliatory shots calculate the least amount of theoretical ships hit to see just how much many retaliate. As the damage is fixed, based of the actual amount of damage received, this is only important to see how many ships may be killed off a stack when a revenge shot hits:
        • Say a stack of 5 MLRS Corvettes with 8 shots, 1 per target each, fires 16 compressed shots at a stack of 5 Dark Mirrors. The least amount of ships required for the MLRS Corvette stack to shoot this many shots the Dark Mirror's way is 2. Thus only 2 of the 5 Dark Mirrors will retaliate, dealing half the total incoming damage across 2 compressed shots, and in theory being allowed to kill up to 2 of the attacking MLRS Corvettes with it.
        • So, when an Artillery Golem hits a stack of 100 Dark Mirrors with 125% revenge shot damage, effectively dealing 21k damage (because it killed only one ship) even though its shot could do 100k damage, it is hit in return for 26,250 damage instead of 2.625m damage from 100 Dark Mirrors shooting back.
    • Backend programming:
    • GetAttackPowerAgainst() now also calculates how many compressed shots are fired at the target, and how much damage can potentially be done when factoring in how many stacks can be killed.
    • It seems before there could've been a bug where if a shield was hit protecting the target of the shot, that target could fire revenge shots instead of potentially the shield. Not sure if that happened, but it certainly shouldn't happen now.
    • ArcenPoint now has a GetSquareDistanceTo() method. By calculating the square of a range and comparing it to the square of an allowed range (= AoE, weapon ranges, beam lengths, etc) the choice between less precise math and costly square roots is eliminated.
      • For now this is only used in AoE calculations.
    • AoE now no longer shuffles the targets hit if there's too many targets for the AoE hit limit, instead it sorts them by range and hits the closest ones first.
    • Created a new logging option for AoE math, and changed the name of the coilbeam math setting to clarify that it debugs all multi-targeting line beams (= no point beams or chain lightning).
    • As a result, the majority of AoE math has been rewritten and unified to be a single code path instead of two different ones.
  • The maximum shots per target and stack is now displayed in the weapon tooltip.

Bugfixes

  • The game is no longer set to use HDR displays in HDR mode (that was new in the prior version). This has questionable benefit for this game, and in some cases could make things overly dark or bright rather than just looking neutral like you'd expect.
    • Thanks to kmunoz for reporting.
  • In the prior version, because of the new pooling it was possible to get stale outguard data or to have outright exceptions related to outguard if you started loaded more than one game in a session. Fixed.
    • Thanks to Daniexpert for reporting.
  • Provisionally fixed an issue where it could complain "Could not find EntitySystem with name '[Whatever]'" at various points in single player or multiplayer. This will need more testing, but the code is a lot more robust and has different expectations now.
    • Thanks to kmunoz and Badger for reporting.
  • Fixed several bugs that could randomly still happen during PostProcessingBehaviour.OnGUI(), particularly when shutting down the game or swapping modes. These were harmless and just took up log space.
    • Thanks to John Zebra for reporting.
  • It's hard to say how or why this is able to ever happen, but it has been persistent, so we put in a safeguard for it.
    • The maximum amount of energy able to be produced by a single producer is now 10 million. Even with the crazy spire units, those only produce something like 1-5 million each.
    • In the even that we somehow have an integer overflow that leads to negative produced energy (not negative net energy, that's different!), then the game just now acts like you have 100 million energy.
      • This should at least keep games going, and let people give us savegames with repro cases versus them not being able to save properly.
    • It is also worth noting that the "extra free energy production from older saves" now also corrects itself to never give negative energy (just in case), and will never give you more than 10 million energy (again just in case).
    • Thanks to John Zebra for reporting.
  • The error "Astro Train Depot Event: Could not find faction for [X]" is no longer silent just to the log (it now pops up in front of you), and it is no longer allowed to repeatedly spam itself.
    • Additionally, when the game is reset, astro trains now properly clean up at least the bulk of their data for being used again in the pool.
    • Thanks to John Zebra for reporting.
  • The "Potential bug: planet [X] has no metal generators. This is unexpected" exception that could come up from the macrophage is now removed. It's entirely valid for planets to not have any metal generators. Usually because of something like the Zenith Miner. The macrophage will no longer give errors when they find something like that, but will instead just work around it.
    • Additionally, kind of alongside this, a lot of the macrophage stuff is now properly cleaned up when it goes back to the pool.
    • Thanks to John Zebra for reporting.
  • All sorts of bonuses were not being properly counted in the per-planet metal incomes for units in the detail window for that. This was not a new bug, but is more evident recently.
  • The energy and metal production amounts that are central were already double-buffered to keep away any UI flicker, but now so are the per-planet and per-fleet costs.
  • The "EnergyConsumedPerFleet_ForUIOnly" is now only calculated for the local player, not for every faction, which is far more efficient. That's how the per-planet data was already calculated.
    • Additionally, the way that this data is sorted is now substantially more efficient in really large games in particular.
      • Okay, wow, we found even more spots where this could be way more efficient, and fixed those also.
  • Both ProtectedList<> and ProtectedArcenSparseLookup<> now support GetEnumerator(). This lets us run foreach on them like normal.
  • A number of places in the interface have long been incorrectly noting values for energy or metal between one another, and this is all now fixed.
    • We have renamed the central method GetResourceProduction() to instead be GetResourceProductionBeforeAnyBonuses().
    • We have added a new GetFullyMultipliedMetalToProduce() for metal on entities, which gives the fully correct result that should always be used if this is actually a unit for a given planet.
    • Same deal with a new GetFullyMultipliedEnergyToProduce().
    • This has allowed us to correct the display of energy on the specific planet tooltips.
      • We are also using it to make the hunter fleet and a few others a bit more smart in terms of what they are after.
    • This also let us remove some duplicate code (that was partially incorrect largely because it was duplicated) so that when you are hovering over an entity it will now definitely show you how much metal and energy it is producing, bonuses included.
      • On top of this, if you're in build mode at a planet, the amount of energy and metal production for the theoretical units now takes into account bonuses for the first time ever.
    • The galaxy map display modes relating to energy and metal production also are now correct in terms of taking in the multipliers.
    • Thanks to John Zebra for a report and save that made all this easy to track down. We've had some other various reports in this area over the last few months, and this should solve all of them at once.
  • Fixed a number of exceptions that could be triggered related to notifications about entities that were dying while you clicked or moused-over the notification.
  • Fixed several bugs with Astro Trains where they were not doing various things because they were looking for the warden fleet with the internal name of "WardenFleet", when the actual internal name they should have been using was "AISpecialForces".
  • Fixed another raft of notification exceptions that could happen during mousing over them when events were ending.
  • Fixed the issue from the prior build where notifications along the top bar had a wicked flicker.
  • Put in some protections for exceptions in EntityOrder.CalculateStrengthCountingData(), and then made it so that if such an error happens it won't completely halt the game from loading. There may still be an exception possible in there, though.
  • Finished fixing the EntityOrder.CalculateStrengthCountingData() error, along with an error in general where the stats for the mark level of systems were not being set quite quickly enough on deserialization when the objects were retrieved from a pool.
  • Fixed a new exception that was possible in DelegateHelper_AreaBoostPlanning_CheckAttractsShotsAgainstAllies as of the prior version.
  • Fixed another whole raft of exceptions with DataForMark being null on systems when pulling them back out of a pool.
  • Hardened TractorPlanning against the same form of bugs.
  • Also fixed the same darn issue in gravity planning and tachyon planning.
  • Fixed a cross-threading issue that could happen in GetMaxGatheredHacking() on planets. This also would have been a bug with pure-champion style player factions in the future.
  • Fixed the true root of a lot of our recent problems in this particular build, which was that the "fake entity" for tooltips was getting pulled back into the time-based pool. It now gets generated and kept outside of any pooling.
    • This prevents errors from all over the codebase, plus probably will help solve the tooltip bug as well.
  • Fixed it up so that when you have darkened a planet, the battle status indicators, and the status indicators behind it (like being fimbulwintered) also darken.
  • Correctly made it so that galaxy map icons dim when you are mousing over them.
    • This was taken out a long time ago, for reasons that are unclear. It's now so much more responsive-feeling, since you can see what you've hovered over.
    • Bear in mind that this just even further emphasizes that tooltips don't always appear for these elements, but we'll be working on that next.

Mod Updates

  • SirLimbo Mod Updates:
    • Updated all distributed mods to no longer have any "stack_damage_multiplier". If your mod still uses it somewhere game will throw an error, though it should not be game-breaking.
    • AMU, Kaizers Marauders, Devourer Chrysalis:
      • SmartFactionImplementationBase now uses the new SetUpAllMyDataForNewObjectAttachment() method to set up. This trickles down into Kaizers Marauders and Devourer Chrysalis. So far no errors have been recorded.
      • All of the factions in these mods now actively use SetUpAllMyDataForNewObjectAttachment() in the faction implementation to clear out any potentially stale data (hopefully).
      • Kaizers Marauders use SetUpAllMyDataForNewObjectAttachment() in the external data implementation to clear out any potentially stale data there (hopefully).

Beta 3.500 Data Integrity And Game Tech Upgrades

(Released July 31st, 2021)

Wow this is a lot of changes. There are some known issues noted way down below, but most are not serious. However, the sheer volume of what has changed is larger than perhaps any other release in the last few years when it comes to the technical side of things. So we are expecting oddities. We'll stay on a beta branch until this blows past. But in the meantime, this is also a huge improvement in a wide array of areas, which is very exciting.

Major Engine Upgrade

  • Updated Unity from 2019.4.18f1 to 2020.3.15.f1.
  • Slate Cinematic Sequencer is updated to 2.0.3.
    • This is used for the ships flying on the main menu.
    • We had a variety of custom bits of code in that, mostly to make it be quiet in the unity editor, and we got those integrated back in.
  • Updated TextMeshPro from 2.01 to 3.06, and then re-integrated all of our (many, many) customizations. Wow that was a lot of customizations.
    • This is used for text throughout the game, and icons in text, etc. (Our customizations mostly relate to icons in text and adding extra features there).
  • Updated Shapes from 2.3.2 to 4.0.2.
    • This is how we draw range circles and a few similar things along those lines.
  • Updated IMDraw from 1.4.2 to 1.4.3.
    • This is how we draw lines like movement orders or attack orders in particular. It's not how we draw ship to ship lines.
    • They note that they fixed something that might have been a memory leak from the sounds of it in this update, so that's handy.
    • We also let a most of our own customizations of this lapse, so that we use more of what is central to this. We are now drawing high-radius circles with Shapes, so we no longer have any need for IMDraw being able to draw circles with more than 48 vertices. (In the past, we had customized it to allow for this). All of the things that use circles right now from IMDraw are things like the battle notifications on the galaxy map, or some debugging displays, and those all already used the lowest-poly version, so the functionality is identical. It's just one more piece of external code that we don't have to manage quite as many custom differences with.
  • Dynamic batching is now enabled for the game again. Normally we use GPU instancing, but there are some cases in the GUI and the galaxys map where it turns out dynamic batching instead is the way to go.
    • The great news is that this basically just increases framerate from those areas, and reduces the draw call count in general
    • The reason for disabling it in the past is just HOW much we use GPU instancing, and dynamic batching itself does use some CPU cycles figuring out what to batch. So why have it on if it's not used? Thankfully, in our case the things that are instanced are generally not going to even be visible to the process doing dynamic batching, so these days it's the best of both worlds.

Mac OSX Silicon/M1 Support

  • Now that the version of the engine that we use supports it, we are building in such a way that it should work for Intel 64 or the newer "Silicon" hardware chipset natively.
    • We don't yet have a Silicon machine, so please let us know how it goes!

HDR Monitor Support

  • The game now supports HDR output for HDR monitors. It uses a bitdepth of 10, for now.

DirectX12 and Vulkan Support on Windows

  • On windows, if you open the game without selecting a runtime type, it will now default to DirectX11 rather than OpenGL. This gives much better performance.
    • As in, specifically, you might see a boost of 30% fps or more.
  • Added both DirectX12 and Vulkan support to Windows. Both of these should perform better than DirectX11 does, and FAR better than OpenGL does. For now we've left in OpenGL as an option, though.

Main Menu Quality And Performance

  • Updated the reflection probe on the main menu scene so that it is now once again time-sliced a bit, making it lower impact on the GPU and GPU.
    • Also adjusted its position so that it now provides a more realistic angle to the reflection of the ships passing out, while not having any of the prior problems we had experienced with this. This also is no longer using box projection.
    • Thanks to marty651 for suggesting the position below the floor and a bit to the side.
  • The game now supports GPU-accelerated skinning of character animations. This is now relevant for the four characters standing around on the main menu.
    • This only works on DX11, DX12, and Vulkan (the latter on Windows and Linux). Metal on OSX doesn't seeem to support this.
    • This gives a slight speed boost, not that they were that heavy to begin with.

UI Performance Improvements

  • Various UI performance improvements have been added.
    • A simpler version of the TextMeshPro shaders is now used, which has all the features we were actually using (so it looks identical but does less work).
    • In various places in the sidebars and similar we are now using a RectMask2D rather than regular Mask, as that is a lot more efficient. Visually this looks the same almost everywhere (it removes the rounded edges on the notifications in the top part of the screen, but that's it), and it's more efficient.
  • Wormholes in the planet view no longer render using TextMeshPro on canvases, but instead just pure TextMeshPro, which is more efficient for these purposes.
    • Same for the planet names, and the text next to planet names, on the galaxy map.
  • Several of the new ship-to-ship lines from the past version or two are now rendered using substantially less RAM.
  • Our internal UI middle-layer now disables sub-canvases and graphic raycasters when a window is not showing.
    • A lot of things that were previously exposed as public variables on our internal windows class are also now self-contained in such a way that we can avoid programmer errors or misunderstandings.
      • A number of these now cache the last known value when that wasn't done before (mostly it was done before, but not always). This prevents us from accidentally over-dirtying a canvas by setting it back to some value it already has anyway.
  • Fixed issues with the following canvases staying active even when they were blank and should have been hidden.
    • This was a performance leak, as well as potentially something that could block random parts of the screen from getting clicks (in theory, maybe, possibly not really, and only under certain circumstances but we'd rather not tempt fate).
    • The list: Window_DebugInfo, all the variants of tooltip (there are seven overall), and the center screen popup bar/window.
  • The following locations now use a Rect2DMask instead of a traditional Mask in the UI, granting them way more performance in general and lower draw calls:
    • All the sidebars, Selected ships list, notifications at the top of the screen.

Bugfixes

  • Fixed a bug where Helping Hands 2 from TSR had Scourge mistakenly set to be your enemy instead of ally.
    • Thanks to OzoneGrif for reporting, and Daniexpert for fixing.
  • Fixed a typo when the strength in response of an hack was not calculable.
    • Thanks to M42 for reporting.
  • Fixed a typo in the 32k gravity well description and one in the debug settings.
    • Thanks to Daniexpert for reporting.
  • Fixed two typos in the journal when completing a spire transceiver.
    • Thanks to GreatYng for reporting.
  • Turns out it was possible to get some very-invisible errors in the ClearAllTraceOfExistingGame() code. That has now been made more robust so that errors will be more visible, as a start.
    • Secondarily, it also is set up so that an error in part of it will only affect that part of it, and so that the most likely potential errors would not happen.
    • These are something that could have been a memory leak.
  • Fixed an exception that could happen in tooltips now. Not sure if this was ever possible before, but now it's fixed.
  • Fixed an issue from the last few versions where if you switched what expansions or mods you were using, during the reload it would not show the text status and instead showed a very high-bloom view.
  • Cleared out some extra debugging that was in there since the main menu redesign that noted if expansions were disabled or enabled on the wall in the hangar.
  • When we are loading external dlls, we no longer even bother trying to load their pdb/mdb files. That has never worked properly, and requires a conversion tool, and we've found ways around it so why bother looking for it or loading extra data?
  • If someone saved a quick start with a faster-than-normal (or slower than normal) game speed, it should now load with the default game speed instead.
  • Multiplayer should no longer freak out when the host does a Reset To Defaults button in the lobby. Previously that would cause the client to be forgotten. This still needs more testing; if it is still broken, it's at least closer to being fixed.

Reworked External Data Loading Pipeline

  • There has never really seemed to be a problem with loading external dlls from background threads, but it can introduce some cross-threading issues on faster machines given the data types we're using. Better not to take chances.
    • The game now yells at any programmers that try to do this off the main thread, which mostly means yelling at Chris to fix the central classes up to that new standard.
  • The game now defines a IArcenExternalClass, which is an interface that is now to be at the root of all classes loaded externally.
    • Anything that doesn't inherit from this will wind up no longer functioning. So that is a few code-based mods need to implement this properly.
    • This has a method on it called RunOnFirstTimeAssemblyLoaded(). This is, as you might expect, run just a single time when the entire dll that this method is in is loaded for the first time. This lets modders in particular set up some one-time things that they'll never disable until the game is restarted.
      • This replaces IInitialSetupForDLL, which has been deprecated. The new method is a lot more efficient, as we don't have to examine every type in a dll we are loading; just the ones the modder or developer tells us about.
  • In general we now have a central registry of all of the external assemblies and types, and a really tight leash on how we generate those and how they are kept track of.
    • This is important so that we don't wind up creating multiple copies of the same thing, or a bunch of things that won't be garbage collected, depending on how you look at it.
  • Fixed a bug where the background darkness behind some windows was instantiating some random class as a controller for itself. No idea what sort of effect that had in the past, but it was not welcome.
    • There is now a is_intentionally_without_controller="true" that lets us avoid that.

Memory Leak Work

  • Fixed a small(?) memory leak in the galaxy map planet links, where any that were animated or which had a wave incoming warning were creating an extra material copy per frame, every frame that they were animated. This was a phenomenally large waste of resources, potentially, if you had a long game with a lot of waves, and would not reset until you restarted the game program. Just going back to the main menu was not enough.
    • The programmer that had implemented the wave warnings and specialized lines was not familiar with unity's API enough to know this would happen with the method they used, and we unfortunately didn't catch it in code review. It's pretty subtle. This bug goes back to October 8, 2019.
  • The keybind "Dump Squad Data" now dumps its data to a fresh log in [InstallLocation]/GameData/SquadDataExports/DateTime.txt rather than into the main debug log.
  • A new keybind has been added: Dump External Heirarchy Data
    • Output a bunch of data about all 'external heirarchy data' that the game current has loaded into a fesh log in [InstallLocation]/GameData/ExternalHeirarchyDataExports/DateTime.txt.
    • Default bound to F15.
  • Discovered that were creating a silly number of ShipInstanceRendererPools, each of which had a ton of objects in the,
    • There is now just one such pool, shared between ship types.
    • This was previously a memory leak between loads of the xml files (changing expansions or mods), but not entirely sure about if it was a leak between loads of the game itself.
  • Fixed an over-initialization error with the contents of notification pools, where we were creating 30 copies of each possible one, including lots that only ever show once.
    • Further fixed a memory leak where the pools themselves for these notifications would get lost in RAM after exiting to the main menu and coming back into the game. This would all but ensure that they stayed in RAM until game shutdown, since the pool and sub-objects referenced one another.
  • We have long had a BasicPool<> class that is used for various things. However, the end programmers (even the designer of said pool) did not always use these correctly.
    • To enforce correct usage and save us from accidental errors, a few changes have been made:
      • First, you can no longer create a BasicPool<> directly. You now have to call BasicPoolOfPools.CreateAndReturnBasicPoolOrGetExistingOneByName<>() instead.
        • This will create it and register it, or if it already exists (that happened just one bug ago), then it will reuse itself.
        • This method should still be used sparingly, because it does have to do cross-threading locks. It should be used like we used the constructor before, not as a quick lookup for dictionaries in general (because it's not quick in that way).
      • Secondly, you must now specify a BasicPoolAutoClearFrequency of either EveryFrame or Custom.
        • The new problem we were having is that notifications were leaking all over the place, causing dozens of extra entries in memory per second, and eventually very crowded lists. This is because the end programmers forgot to call Clear() before resuming use of them. Now they can auto-clear and we don't have to think about it. If you choose "Custom" as the clear frequency, you're responsible for managing that yourself.
        • Hmm, turns out the original attack notifications did the clear, but nothing else. That said, because of double buffering their clear should have introduced a flicker. It probably wasn't great either way, but it's nice to see we started out doing it mostly correctly.
  • Okay, so the problem with the notifications was actually NOT solvable even with the nicer BasicPool<>. Since we double buffer the lists, and there are multiple that needed to be chained together, that means...
    • Added a new DoubleBufferedPool<> class, which can be chained into arbitrary trees of unlike inheritance if needed. We only need one level of unlike inheritance (one parent, many children), but multiple levels (grandchildren unevenly or evenly) are possible with the structure.
    • This internalizes all the complexity of the chain of double buffers, and we use it for the notifications as a whole (what are shown) and then all the many pools of things that can fill them.
    • Any mods that use these will need to have a look at the base game code and update accordingly.
  • All of the external objects loaded through our central system now have ClearAllMyDataForQuitToMainMenuOrBeforeNewMap() called on them properly when the game world is cleared.
    • This makes it so that these objects are pooled, and we no longer throw away any of those external data structures, but instead reuse them again if you launch another game without quitting the game program. It prevents some substantial memory leaks, as well as leading to faster performance.
    • We do still have more objects that we need to pool to prevent memory leakage between game loads, but this is a notable chunk.
  • The SpecialFactionData implementations now have SetUpAllMyDataForNewObjectAttachment() called on them, with the faction passed in as the object, when they are initially assigned.
  • Made some MAJOR performance improvements to our TimeBasedPool in general.
    • Previously it was only able to store objects in intervals of once per second, so storing them for long times was really inefficient.
    • Additionally, previously it had a huge overhead for the number of internal seconds there were, with however much data was in there.
    • Now it has been adjusted to be very efficient (a constant CPU cost) regardless of how many queues there are, and it also supports queues that last a longer time but don't move ahead every second.
    • This lets us safely isolate items for longer periods of time before bringing them back out of a pool, but also immediately flip to "everything is ready for use now" when we exit a game and look to start again.
    • This lets us use these for more things in the near future to help with memory leaks, and it also improves the performance of loading and quitting games in the short-term, too.
  • Added a new BetweenMapGenPool<> class that is specifically for handling cases of things that get created during a game, then never destroyed or reused until the map has been cleared and it's time to create them again.
    • There's a fair number of things in this category, and it's by far most efficient to handle them in their own way.
    • This class has been coded to be aggressively threadsafe despite using a central index, so it's also chiefly for things that are created on just a few threads (like what happens with most of mapgen).
  • PlanetFaction was previously using its own custom form of pooling (because there was no central pool appropriate to it), but now thanks to our new reference tracker code we can see that this was not working at all.
    • Was this ever working? Who can say! Doesn't really matter except that we know now it was not.
    • With this fix now in, we can verify that we're no longer leaking planetfactions, which also solves a few things related to them right away!
  • Fixed a really pointless memory leak in ShortRangePlanning_StrengthData_PlanetFaction_Stance.
  • Improved the efficiency of getting and setting LongRangePlanningData_Planet.
  • Planets and galaxies are now pooled via the new BetweenMapGenPool<>, and that solves a lot of our memory leak right there -- although not remotely all of it! It's still possible with repeated reloads to leak a whole bunch of other things.
  • The ArcenExternalDataPatternTable table now loads from all mods and dlc that are installed on the system, but just doesn't activate any that are not needed at the moment.
    • This lets us keep these from needing a reload during runtime, and have an accurate count for our ArcenExternalDataLookup side of things.
  • The World, and World_AIW2 objects, are both now pooled, and both do a nice and intentional full wipe of all the data related to them.
    • In the past, it was expected that the data would be all interconnected in an island that the GC would be able to carry off, but that island is far to interconnected now. We must keep it, and we must reuse it.
    • This is a pretty hefty change, but a very needed one, and there may be some bugs as side effects for a little while because of this (hence the beta branch).
  • TimeBasedPool<> and ConcurrentPool<> have both been updated to prevent multiple copies of the same object from being added to themselves.
    • This has required a change from the interface ITimeBasedPoolable<T> to have some new functions, and so we also added the default abstract class TimeBasedPoolable<T> that can be used to automate that logic if the class in question is not already inheriting from another class.
      • We would have removed the interface and just had the abstract class, but that doesn't work with things that already have levels of heirarchy.
    • This adds one last critical bit of thread safety that could have been messing with certain things on very-good-threading computers.
  • WorldSetup used to leak, but now these are just grafted onto the world objects that are pooled, versus needing to be pooled on their game.
  • ConfigurationForFaction is now fully pooled and no longer memory leaks.
    • The way that random factions are assigned might need a look, but honestly we probably fixed some bugs with it rather than the other way around.
  • Squads (ships/structures) now once again are pooled. They go into an extremely long-form queue that only lets them back into the game after 3 minutes (360 seconds) seconds of waiting.
    • Technically because this is 360 seconds split into 12 sections, it could in theory be as short as 331 seconds before one re-enters.
    • At any rate, the window of 331-360 seconds should be sufficient for any background thread to fire several times and notice that the unit they have on hand is dead.
      • If they don't notice within that time period, that's on the developer of the faction or mod in question. They'll later wind up with a reference to some completely other unit, like a fireteam not realizing that it can't give orders to some unit that is now a player unit.
      • Let's really hope we don't have any "fun" bugs like this, in mods or otherwise. It should be very straightforward for any faction designer to check for stale references, though. If a unit has HasBeenRemovedFromSim as true, then it's in this 2.5-3 minute period and needs to be culled.
  • EntitySystems on squads are also now pooled, separately from squads because of how that whole dynamic works.
    • They are added to a simpler pool (no time delay) after the squad is coming back OUT of its pool, super late so it can't hurt anything by going through quickly.
    • Also improved some sub-leaks that this one had.
  • StatisticSet is now really used much anymore, but it's pooled for those cases where it is, at least.
  • PlayerAccount and PlayerAccount_AIW2 now both pool properly, even though they were a pretty small amount of data. Still nice to do it properly.
  • EntityLineTypeData now uses ConcurrentPool<> rather than TimeBasedPool<>, since that is now something that would be more efficient for it and allow for less extra wasteage.
    • Same deal for PlannedMetalFlow.
  • The ExternalData class is now being tracked, and also now being pooled. It is linked against a sub-list on each ArcenExternalDataPattern.
  • Fleet.Memberships are now being tracked properly, and also now being pooled.
    • Same for TransportedShips.
  • Fleets themselves are also now pooled.
  • ShipLineEntries is now fully pooled.
  • ArcenThread isn't pooled, but instead is initialized and managed with unique names that live for as long as the program does.
  • A variety of SimContexts, mostly used for loading savegames and generating maps and such, are now reused rather than being generated over and over again. This was a slight memory leak, but also will now perform better.
  • All the various levels of SimContext now track themselves separately so that we can tell where there are ones leaking.
  • The planning contexts and threads for factions are now properly pooled.
    • There are still more memory leaks, but this is one of the last super duper substantial ones in terms of how much memory they hold onto.
  • Updated ShipLineEntry so that it is now pool in a ConcurrentPool rather than a map-clear based on.
  • Created a new ProtectedList<> class that allows us to manage pooling in a more automated fashion.
    • Even with a number of changes to ShipGrantsList to attempt to handle any accidental cases, that just was not catching all the leaks or even close.
    • This is a general-purpose class that might be useful for something that has more significance when it leaks, but it's also just nice to be tidy where we can.
    • The AMU mod has been updated to no longer leak ShipLineEntry objects.
  • SpeedGroups are now properly pooled and no longer leak memory. Additionally, to aid in that the faction object now uses the new ProtectedList<> to manage that aspect of them, which works very very well.
  • MapConfiguration is not pooled, but no longer leaks because we have refactored it to be an immutable part of the WorldSetup objects.
    • Interestingly, this does solve a random potential bug that we found in WorldSetups and how they copied themselves between one another.
  • A variety of private and internal data on planets is now properly cleared for pooling purposes, thus fixing some bugs that we had in there.
    • Same for the world objects, planetfactions, and galaxy.
  • HistoricalData has been set up in a non-pooled-but-subordinate fashion for both the world and faction objects, which again prevents memory leaks.
  • Factions themselves are now pooled, which was another one of the single largest remaining issue areas.
  • PlannedFlows_ForUI on factions has been converted to the more-efficient PlannedFlowsByPlanetIndex_ForUI.
    • It also has a few other supporting lists and such. It's more complicated now, but much more efficient at every stage and should not leak anymore.
  • Added a new ShipAssistanceData class, which is now used in place of a RefFourTuple that we used to use in part of the simulation logic for engineers and such.
    • This new object is pooled and handled way more gracefully than the old one was, thus also not generating work for the garbage collector.
  • A liberal use of ProtectedList<> around PlannedMetalFlow, ShipAssistanceData, and ShipLineEntry is our new strategy for attempting to keep them from leaking.
  • Lowered the range of the thread locking in ConcurrentPool and TimeBasedPool in order to make them less likely to deadlock.
  • For whatever reason, when we tried to implement per-generic-variant pooling via ConcurrentPool in ArcenOverLinkedList and ArcenLessLinkedList, we ran into infinite deadlocks. However, this was a major source of leakage (or at the very least, GC churn).
    • In the end, after experimenting for quite a while, we simply inlined a simpler version of ConcurrentPool directly in those linked list classes, with ConcurrentBag at the root rather than ConcurrentPool. It performs great, and the lack of leakage and deadlocks is confirmed.
  • Fireteams are now pooled. They are specifically a time-based pool, since there could be lingering wrong references to the disbanded fireteam for a bit, and we don't want to reassign the fireteam too quickly and confuse everything.
    • It takes a total of 61-90 seconds for a fireteam to come back out the other side of the pool and be reused, or instantly if the game is being restarted.
  • Added a new KeepTrackOfEveryItemEverAndRefillTheMainListWithThatOnGameRestart option to both ConcurrentPool<> and TimeBasedPool<>.
    • This option basically lets them act as usual DURING the execution of the game, but then lets them act differently during the same time a BetweenMapGenPoolBase<> would act.
    • This is useful for a number of cases, but Fireteams are the easiest to demonstrate.
      • During gameplay, there are absolutely times when a fireteam is retired, and it gets added back to the time-based pool and then pulled out in a while. If you have a ton of fireteams going on, or are playing for hours in one session, this is great news for you.
      • However, when the game is quit to the main menu, what happens to the background threads? They do get a quick courtesy notice of impending death (I think?), but ultimately they're just trashed. So if there were a bunch of fireteams in use in collections and such, those are now lost to time and won't ever be put back in the pool. Memory leak.
      • When those other background threads are resurrected for their next use when the player loads up another savegame without quitting the program, all of their lists and such are supposed to be cleaned out anyway. Any sort of data that is there is consider just something to bin. Old fireteam data, whatever. But the rest of the save has already been loaded, and any needed fireteams were already pulled from the central pool.
      • Therefore, using this in a hybrid manner like this, all those fireteams are recalled to the main pool and cannot possibly leak because we kept central references to all of them forever (until game stop). We have already pulled them back into the main body of their pool for use in the new savegame, and when these things are encountered as stale data on the background threads starting back up, those background threads should just completely ignore them.
    • Honestly, this is so stupidly useful as a fallback that we're now using this for pretty much every ConcurrentPool<> and TimeBasedPool<> except those used for the player account data. There were various things like PlannedMetalFlows and ShipLineEntries and such that kept having perplexing minor leaks between saves, probably again because of interrupted background threads. And while most of the other locations were no longer leaking, this is a nice safety valve just in case.
    • With this change in place, most of the ArcenExternalData that we were seeing leaking is also now fixed! There is still some unexplained growth in ShipLineEntries, but honestly that could be valid data that is changing during gameplay. At any rate, it's such a tiny amount of data (a few kilobytes per reload) that it's not worth chasing if it is a leak (which is is likely not).
  • Improved the pooling a bit on ArcenDelayedDeserializationBurst, and added more instrumentation. This is only for purposes of multiplayer. We'll see soon if it needs more work.
  • HackingEvent is now pooled between games. These are not reused or discarded during a given game, since they are logged permanently in a save, so this is a pretty simple one.
    • Same thing with tech history events.
    • Also journal entries / tips.
  • Fireteam history items are now pooled.
  • All of the various kinds of planet pathfinders are now pooled between games, and no longer leak.
  • At this point, when we repeatedly load a game and then quit to the main menu and then reload the game and let it run a bit and restart and so forth, we are leaking very little data. Less than 1MB on average at the moment, if that.
    • Previously, we were leaking somewhere between 20MB (when very fortunate) to 100MB (on average) to far far more (several hundred MB, or in some unlucky cases closer to a GB).
    • The solution here isn't super perfect, because mods in particular and other external factions can still leak and that's not centrally managed (well, not all of it is). However, there are a few mitigating factors there:
      • Firstly, if anything is leaking badly in those areas, the tools now exist to VERY easily track that (the ReferenceTracker is used all over the place in the codebase now and can be implemented with 3 lines of code and costs basically no CPU to implement). So if someone is suspicious of their code mod, or we have a faction that is misbehaving, we can easily identify that.
      • Secondly, anything that needs to be pooled can be, even from mods. Simply by registering as the proper kind of pooled object (there are several to choose from, and the code is very clear on those when compared to what it could be), this problem can be solved in a couple of minutes for any place that actually has a problem.
      • Thirdly, when it comes to external data that is "leaking" at the moment, honestly that is pretty likely to get picked up by the garbage collector. Things that don't get picked up by the GC are things that are referenced by other things. The outermost stuff tends to have very few references to it, and our central code intentionally severs those relationships, so in most cases those should just be garbage collected anyhow.
    • Overall this whole thing leads to faster loading times for savegames, faster map generation times in the lobby, MUCH faster loads of games after the first run in a program, and actually better framerates as well.
      • This also gives us the tools we need to check for multiplayer client performance issues, which we'll be doing soon.
  • Added in some more logging to some blind spots we had.
  • Fixed a during-game leak of ProjectedMultiPathData, and consequently also ArcenTwoDimensionalFlexibleList.
    • This was one of those things that would not be causing extra data on savegame load, but just steadily the longer you played.
  • Added a new ProtectedArcenSparseLookup<>. This is now used for EnergyConsumedPerFleet_ForUIOnly.
    • This was leaking a looot of data during actual gameplay. At best it was hammering the garbage collector.
    • For context, there were four thousand plus of these generated in five seconds of play. Now it generates and reuses just 170 (in a specific test case).
  • ThreatChunk is now handled like EnergyUsageData. This was generating thousands of extra entries on the GC per second before.
    • ThreatChunkCollection is now handled like EnergyUsageDataHolder. This was generating about 2000 of itself per five seconds before.
  • Decreased the generation of ArcenDoubleCharacterBuffers over a 5 second span of gameplay from about 3,000 to about 1,200. These do get garbage-collected anyhow, but they do go on the heap and it's far more efficient to reuse them rather than toss them away and create a new one.
  • Okay, re-coded the way that notifications are shown at the top of the screen from pretty much the ground up.
    • The DoubleBufferedPool has been removed from the codebase, as it only did one convoluted thing and possibly not correctly.
      • It's really difficult to achieve multiple layers of double buffering in sync, which is what that was about. For something less interconnected, our existing SwizzleList is the way to go.
    • These now use a completely different set of data structures, however, and their data is a lot more compact in terms of where you have to put information. You can also safely add hacking notifications from other locations other than the Human.cs class.
    • There's overall a singleton, and two pooled bundles of information that intersect with a pool of visual buttons, so this is still quite complex, but it's... better. And it gives the correct end result, which is what is most important of all.
  • Updated civilian industries to use the new kind of notifications, and fixed a major performance problem with those notifications while doing so. Those would churn the GC with almost two dozen extra lists of planets, and that many times as many wormholes were being raided (so 24 multiplied by wormhole count) calls to get the wormhole by ID. Perils of having a property that self-constructs itself on every call, because then using that property causes unexpected amounts of load.

Anti Memory Leak Tool For Developers And Modders

  • Updated our internal ReferenceTracker class so that it is extremely lightweight now and only tracks the number of objects created, not actually keeping WeakReference references to them (WeakReference is a way to make it still be GC collected but let us check on it).
    • Now we've got this in use in 80-something files, which (through class inheritance) hits several hundred overall object types.
    • In general, we can now see exactly where our memory leaks are simply by attaching one of these to a class, going into the game, hitting F15 (by default), then out of the game and back in and hit F15 again, then diff the two exports and you can see exactly where there are problems.
    • This is super duper hyper easy to use, and if you're a modder and wonder if any of your own classes are leaking, you can use this to find out.
    • Please bear in mind that this data CAN be misleading if you don't know how to read it.
      • Just because a number goes up doesn't mean there was a leak for sure. It might have been just needing more entries for a pool of objects, for instance.
      • Additionally, there are some classes that will get properly garbage-collected. You can create those over and over again and remove all references to them, and they'll show an increasing count in here but really the garbage collector is collecting them just fine.
        • Even though this would be "working fine," if the numbers are going up rapidly, that's just making the garbage collector work more, and hoping that it can keep up with things and doesn't think they're still linked. It's still better practice to pool those objects even if it's not technically a memory leak.
      • That said, if you see certain numbers go persistently up every time you reload the game or something along those lines, then you can be pretty darn sure that this must be a memory leak. Past a certain point, in large volume when we're talking about pooled objects, the only reason to create new objects is because we have discarded the old one. Do you trust that it was garbage-collected okay, or not?

Work On Regressions After Memory Leak Overhaul

  • New regression this build: Did a bunch of work trying to keep the notifications at the top of the screen from flickering, but they still do. The new method is at least more efficient in terms of not dirtying that UI canvas as frequently, and it uses clearer and more common sorting terminology as well.
    • The notifications were also prone to errors on clicking or on mouseover, and that seems to be solved now by these changes. The flicker itself is as bad as ever, though. Will need to look into that more, but will opt not to hold up this release for that.
  • Fixed an exception that could happen when entering a savegame or the lobby if by some magic accident there was no AI faction in there.
  • New debug setting in personal settings: Write Log Of Faction And Map Changes
    • When generating a new map in the lobby, or loading a savegame, or starting a quickstart, this will write details of when and where factions and other central mapdata is being added or removed into the main debug log. The only real reason to turn this on is you're missing a bunch of factions or you're surprised by the order they are in or something like that.
  • Solved a minor heap allocation for when finding the most annoying faction to another faction.
    • Also another one when getting the sorted list of factions for display in various places in the game.
  • Added a new ListWithLogging<> that can be used with game settings to help us debug when things are going in and out of them.
  • Quick starts can be loaded again, including into the lobby. The reasons for why they were messed up are pretty complicated and have to do with cached but cleared data. The way that we're handling this is still not ideal, and hitting custom game still breaks at the moment. I have an idea on a better way to handle this, though.
  • It would appear that quick starts, tutorials, the lobby, and so on all now work again, in addition to savegame loading working. This was hard-won, and I don't really trust it yet. But it seems to work so far!
    • Known issues:
      • Centering is off when going into the lobby usually the first time.
      • Still have the flickering going on with the notifications.
      • Unknown factor: not sure if we are clearing playeraccounts the proper amount, in multiplayer in particular. Will need testing by me.
      • Unknown factor: who knows what else is wrong. This has been a tectonic shift for the game. But those are the known issues, at least.
  • Fixed the issue with wormholes getting stale and acting super strange. They now behave completely properly. This was one of the more annoying regressions from the new caching stuff.
    • It is probably going to be important to check that things like the Zenith Miner Mining, and any other units with particle effects (Zenith Miner Probe, etc) all are properly working and not getting stale, too.
    • Same deal with some of the special effects, like lightning blasts and such. Those haven't been tested yet, and are at a minor risk of having the same problem, although the code review looks good so far.

Mod Updates

  • Both macrophage histiocytes and the civilian industries mods have been updated to work with the new code patterns required by this release. Any other code mods will error out when trying to load the game, but most mods are xml so this is not a common problem.
  • AMU has also been updated to support the new coding standards.
  • Also Chrysalis Devourer and Kaizer's Marauders.
  • The only known code mod that is currently incompatible is The Reprocessors.

Beta 3.313 Input, Selection, And Flagships

(Released July 16th, 2021)

There are a lot of very core changes in here, so we want to make sure to get all that fixed up before inflicting it on everyone!

  • Non-friendly (neutral or hostile) cloaked ships are now invisible on the planet sidebar. It shows them in the unit counts, so you know something is there, but it does not show any icons for them.

Selection Improvements

  • You can now right-click units on the planet sidebar to have your selected ships do whatever it was that would normally happen in such a situation. (Attack, assist, etc.)
    • Thanks to Ithuriel0, Daw11, and mahisev350 for suggesting.
  • It is now possible to select units of other factions, even enemy ones, if you directly click on them. Drag-selecting will not select them, and you cannot give them orders.
    • However, this can be a really handy way to left-click some enemy group on the sidebar and suddenly see all of them with selection circles, for instance.
    • This also allows you to select things that you have not yet claimed, and pause them before the claim process even starts, if you wish.
    • Thanks to Apthorpe and others for inspiring this change.
    • This also solves a problem where if you had a pauseable object that dies to neutral status, and it was paused when it died, you could never unpause it. Now you can.
      • Thanks to John for reporting this one.
  • New feature: if double-clicking any unit on the galaxy map, switch to that planet and focus on it.
    • Also you can right-click enemies on the galaxy map to have your selected units go attack it.
    • Thanks to UncleYar for suggesting.

Expansion of Stationary Flagship Mode

  • Okay, stationary flagship mode.
    • Historically, this means that if you are in that mode with a fleet, then all orders to that flagship are ignored, but passed to any fleet members. This is very useful!
      • As part of this, you can cut through the stationary nature of your flagship by holding Z and having the flagship still follow a given order.
      • HOWEVER, until now, any orders that you were to give with it in this mode that were meant to cut through after orders that were not would be in stasis forever. First change is that now those later orders are processed.
    • Secondly, now for flagships in general, if you wish to hold down Z while giving an order even when it is NOT in stationary flagship mode, that order will be treated as if it is in stationary flagship mode for that order only.
      • This lets you have a flagship in normal mode, but quickly exempt it from some orders that you want the rest of the fleet to keep up with.
    • Additionally, since this keeps looking for more orders that are valid in general, it will find the ones that can never be blocked by stationary mode (directly), like load and unload transport orders. Previously it was possible for those to get stuck behind a bunch of ignored orders.
      • Thanks to Zer0h1nder for reporting this problem with loading and unloading.
    • Thanks to aliyah and Zweihand for suggesting this extension of stationary flagship mode.

Input Underlying Overhaul

  • Pretty much completely re-coded the bottommost layer of our input handling controls for the game.
    • Essentially, the way we detect button presses, double-presses, and such has been rewritten mostly from scratch.
    • The way that we detect button combos and things like that has been kept intact for the most part, but expanded a bit so that we can now specify when a combo should be blocking or when it should be ignore any conflicts. For instance: range displays need to block lower combos, but holding Shift or Ctrl does all sorts of other things that should not block each other.
    • Among these changes are that if you move your mouse substantially (more than the 60px on 1080p, and the equivalent on larger or smaller resolutions), then any mouse clicks of any button are ignored (you moved the mouse that much from pushing it in to letting it out).
      • This specifically keeps things like the right mouse button from triggering movement orders to units if you have rebound your camera pan to that key, as an example, because even small camera pans will be on the order of more than 60px. Normally mouse pan is middle mouse button anyway, but this does solve an issue for those who want to rebind.
        • Thanks to [SQ UA] k1r0ck for reporting this one.
    • Another thing that this now does is, for double-clicks of a mouse button, you must be even more precise. If you move your mouse more than 20px on 1080p (or the equivalent on other resolutions), it treats it as just two single clicks, not one doubleclick.
      • This is very useful when you are clicking around selecting lots of enemy (or your own) units fairly close together on the galaxy map, as one example.
    • Overall the rest of the math has just been simplified, and it should hopefully use less CPU to calculate, not that it was a huge load in the first place.
    • One notable change is that various things used to be triggered on key DOWN. That's something we are never ever doing, now. We do still check for keys being held down (of course), but actual key presses as a discrete event should always be on key UP.
      • This change makes it so that when you do something like submit on a chat box it only sends one key press instead of an arbitrary number of them based on how many milliseconds you held down the key and what your framerate is. At any rate, this is something that we already did for a lot of our keys, but we now do for all of them.
      • Actually, for double clicks / double presses, we were measuring the time from the end of the first up event to the start of the next down event. Now we measure up to up, which again helps to measure intentionality.

Bugfixes And Tweaks

  • The game is now much more efficient when checking for cloaking on units. Since most units don't have cloaking, it's now able to early-out a lot faster.
  • Fixed a bug when clicking units that could potentially have made the modifiers not work properly when you were directly clicking units rather than drag-selecting.
    • It's unclear if anyone ever experienced this, but the code was wrong.
  • If you have already won the game (or lost it), then up at the top of the screen it normally says if it is paused or not there. But instead it is only showing that the game was won or lost.
    • It's worth noting that you could always already look down to the clock and see that the game was paused or running.
    • But now in the ongoing messages window on the right of the screen (where chat and such comes from), it now shows orange text with whether or not the game is paused IF you have already won or lost (that way there's still an obvious place to see it).
    • Thanks to... someone? For reporting this.
  • When the game does not have focus, and thus the keyboard and mouse should be ignored (because nothing is worse than giving orders to your stuff while you're tabbed out), it now SHOWS that it has no focus with a red message on the sidebar.
    • This is a perfectly valid state for the game to be in at times, when you're clicking in and out or when the game is windowed and you focus another window to type, etc.
    • The risk is, of course, that the game might ignore input if you've come back to it and the unity engine didn't tell us properly. With recent versions of OSX, sometimes there's a bug where fullscreen games have the dock sticking around in their way at the bottom until you alt-tab in twice after certain times alt-tabbing out, too.
    • In any of those cases, you no longer have to wonder if input isn't being registered or not. This only shows in-game, not in the lobby, as mouse clicks register all the time either way, so buttons will be functional but typing, hotkeys, and hovering would not.
  • If you have the frequency of autosaves set to 0, it now actually properly disables those (as the tooltips say it should) rather than running them constantly.
    • Thanks to Sigma7 for reporting.
  • The game now throws an error if there are missing icons associated with any ships or structures.
    • These behave incredibly strangely, and may cause a memory leak on top of that.
  • Polarizers were missing their icon being assigned to themselves, although they had icons created for them. They now use them properly.
    • Thanks to Darkshade, Timerlane, and Chuito12 for reporting.
  • Fixed an exception related to the recent line changes that could happen in GameEntity_Squad.ClearForReturningToPool(). Also put in defensive code against a few other things that were working fine, but you never know.
    • This was likely also a bit of a memory leak, with it not properly clearing some units.
    • Thanks to Daniexpert for reporting.

3.312 Hotfix

(Released July 16th, 2021)

  • Fix a threading problem with the Dark Zenith that could cause errors when you had multiple Dark Zenith and/or Svikari factions on certain CPUs.
    • Since Badger is the only person to notice this it must be rather hard to hit?
  • The "Show Destination Point" in the unit hovertext now matches with how ArcenPoints in other debugging code
  • Add some debugging code for the EntityOrderCollection which was handy for chasing down some engineer order problems.
    • This code is currently unused, but I bet someone else will need it down the road
  • Fixed a bug where the game was complaining in the prior build about missing ArcenNetworkLib. It was a compile chain error at the last moment before release that didn't get caught.
    • Thanks to andreykl, donblas, StarKelp, Zweihand, and Strategic Sage for reporting.

3.311 Engineer Multitasking

(Released July 15th, 2021)

  • Fixed it up so that invalid move orders (orders to move to the null location) are now ignored when they are issued via gamecommand. This is likely a faction or mod making a mistake, or some sort of funky UI interaction, but either way it's something to ignore as invalid input.
    • Thanks to dEAdOnE77 for reporting.
  • Updated ambush carrier descriptions to explicitly state the launch of raptor drones. Buffed raptor drone count to scale with mark (0.3 per mark added).
    • Thanks to Zweihand for updating.

Further Engineer And Line Improvements

  • The terminology for the metal flows, and engineers building things, has been improved in the tooltips and the menus.
  • Fixed an issue in the prior version where metal flows that were for the purposes of assisting a factory were not drawn at all.
    • In general this now means you can see all of the assistance lines, which really clears up what engineers are doing. Sometimes they seemed to only be doing one thing, not what you said, but really they were doing three things, but two of them invisible, and one of those was what you said.
    • The multitasking of engineers is not new and has been around since the dawn of the game, but now you can actually see that happening for the first time. It's vastly more clear (and quite satisfying) to see what they are doing.
  • Fixed a couple of issues in the prior version with some extra metal flows being reported, but not actually being on.
  • In the tooltips, behind the various types of metal flows that a unit can do, it now shows you what it is actually doing with that flow, if anything. So if it's repairing something, or building something, or repairing shields and hull both at once... it shows all of that.
  • Spire Shipyards now have a construction priority of 200.
    • Shard reactors 150.
    • Galactic capitol and city hub 400.
    • Neural nets now 100.
    • Great-shield now 380.
  • If you have the debug output on for the tooltips, you can now see details of the outgoing lines when you view the full tooltip. (Before it just showed the number of outgoing lines, not any details.)
    • Additionally, if you have the debug info on, you can now see metal flow details for any ship that you're hovering over, with a similar level of detail to the outgoing lines.
  • When metal flow validity is calculated, it now includes the radius of the two units when determining how far apart they are.
    • Previously, the assister had to have its center within range of the center of the thing it was going to help.
    • Now the assister has to have its outer edge within range of the outer edge of the thing it is going to help.
    • Most assisters are quite small, so on that side it doesn't change much. But if they are assisting something very large, they no longer have to crowd up on it.
  • Improved the efficiency of units doing repairs a bit when it comes to CPU calculations during the simulation. It now leans a bit more ones from the background thread.
  • A variety of logic on the engineer metal flows thread is now better about listening to your explicit orders to an engineer even when it has no valid targets in range.
  • All of the ship to ship lines have been updated in terms of how they draw. Most of them (all but chain lightning) now use the geometry queue rather than the transparent queue, and are based around additive math.
    • This gives a really dramatic performance boost while having almost identical visuals. But while we were at it, we also made the visuals nicer.
    • Tractor beams are a nicer texture, repair and starved repair lines are nicer (they were kind of tacky before), and there are all-new lines for assistance to factories or to self-building. Claim lines are now gold rather than green or white, and have a nicer pattern.
  • Added a new DoForFactionsParallel() method. This has limited uses, but certainly some.
    • Added a new way that our metal outflows are calculated, especially when it's helpers across factions. This gets even more accurate and prevents helper factions from running themselves into negative metal.
  • Fixed a number of misleading things in the metal expenditures on the UI, such as repairs to personal shields that were free or engines showing up as costs.
  • Fixed some bugs with the benefits of cross-faction repairs not always showing up, at least not in the last build's version. Not sure if it worked prior to that.
  • Fixed up yet MORE ways in which the target you had selected for an engineer might be ignored if no targets were in range.
  • Fixed an issue where if you gave an explicit assist order to an engineer, sometimes it would stop too far out of range of actually doing that assistance.

Mod Updates

  • More Starting Fleets update:
    • Updated mod description. Updated mod by buffing carrier fleet with additional ramifier frigate and adding the destruction fleet. The destruction fleet is a siege + splash focused fleet meant for destruction.

Beta 3.310 Engineering Intelligence Injection

(Released July 14th, 2021)

  • New setting under the network category in personal settings, under a new privacy subsection: Hide IP Address In Lobby And Esc Menu
    • Normally we show your IP Address in those windows in case you need them. However, if you are planning to stream the game, this is not informmation you would want visible in your stream, so this lets you turn it off.
    • Please note that you would still need to obscure the actual connection screen with your streaming software, because we can't really hide that IP while still making the screen useful to you.
    • Thanks to Meggertroll for suggesting.
  • Put in defensive code in the unity post processing stack v1 code so that it can't spam the player.log while trying to see if some unused components should be turned on. This was new in the prior build, and contrary to being a minor annoyance, it was actually something that was a memory leak and a major performance degradation from how much it was invisibly flooding things.
    • Thanks to Daniexpert for first reporting how severe it could become.

Simulation Improvements

  • The "Guarding" field on units been renamed to GuardedUnit.
    • This may or may not mess with some mods, but we're trying to clear up some semantics and also verify where everything is being used, since misuse internally was leading to some bugs.
    • The "GuardingOffsets" list field on units has been renamed to GuardOrPatrolOffsetPoints for the same reason. This has multiple uses, and in the end we are keeping those, but making some other changes.
    • The NextGuardingOffsetIndex field on units has been renamed to NextGuardOrPatrolOffsetPointIndex, which again makes that way more clear.
  • Various cleanup and fixes related to guarding units and so on:
    • When serializing a guarded unit, it no longer serializes dead or missing ones.
    • When deserializing a guarded unit from disk, it therefore now complains about dead or missing ones. When deserializing on an MP client, it no longer overwrites the ID with blank if it can't find it, though. This is an order of operations thing, potentially.
    • When guards are freed by an alarm, it is now more explicit about freeing patrollers that have no central unit they are guarding, if that's even possible (it may not be, but no chances).
    • When AddToNewPlanet() is called, it now clears all of the guard and patrol information. Badger had discovered that this was the source of some insanity with engineers running off to places they should not.
    • There is a new IsMobileAndHasRepairOrAssistConstructionFlowsOrIsMobileMeleeUnitfield used for things that would need a "return to" point during pursuit mode. Mainly engineers and combat factories and similar. The GuardOrPatrolOffsetPoint is now only set for units where that is true when the player gives a move order. This is more efficient in general, and leads to not having some strange data in there for other types of units.
      • It turns out this is also needed for mobile melee units belonging to players.
    • During decollision orders, it was assigning the engineer "return to" point, which was a very strange thing and was probably the root of the original problem with them returning to a decollision-like coordinate in the first place. Of course we don't want that in there in general with them moving between planets (and that was already taken care of above), but this certainly didn't help and might have let some issues squeak through, just more rarely.
    • Added moves_back_after_being_norrised="true" as a replacement for the tag "MovesBackAfterBeingNorrised". This is a lot more efficient to check on units.
    • Overall things here were not as dire as they could have been, but this should correct some of the issues that people were observing with engineers being a bit looney at times. And if there were other really rare edge cases, this should also catch those.
    • Thanks to Ryulong, aliyah, and others for reporting.
  • Fixed a longstanding issue from the last few months where ship to ship lines were sometimes not drawn. This had to do with how we were pooling them, and whether they noticed they had out of date information or not.
    • Overall the fix was to just structure this so it was more clear, and that sorted out the issues on its own.
    • Thanks to Strategic Sage, trigorin, Isiel, Darkshade, Gdrk, Daniexpert, and others for reporting.

Engineer Logic And Metal Flows

Please note. While engineer logic seems to be better than before, we are still observing them making choices contrary to the new rules, as well as sometimes running back and forth in strange ways. Those bits are under investigation, but we figured we'd do a beta release anyhow in the meantime.

  • Fixed a longstanding bug in engineer move code that made them move in fits and spurts toward distant targets.
    • Rather than moving gracefully from spot to spot (and going all the way there without being indecisive), their movement orders were instead "go 8/10ths of my assistance range and then reconsider who to even help." That... is not logic that makes sense or that is helpful.
    • The logic was an accidental inversion. We calculated the angle from the engineer to the target, and then a point at that angle from the engineer that was 8/10s of the assistance range of the engineer. The engineer was told to go there. This is wrong/
    • Instead we now calculate the angle from the target to the engineer, and then a point at that angle from the target that is 8/10ths of the assistance range of the engineer. This properly gets the engineer to go in range, and then actually help the target.
    • Engineers greatly prefer to help targets in range of themselves, so the odds of them getting indecisive like before is very very low. The problem was when they stopped in the middle and rethought things.
    • Why 80% of their range? Well, because there are usually a clump of them. This gives them room to decollide without going back out of range. Them moving in a clump is actually one of the more efficient ways to get things up and running as fast as possible, so making room for that was always a good idea.
    • Thanks to Daniexpert, Detlef, and others for reporting.
  • Added a new construction_priority="num" field for units.
    • This is by default 0 for everything.
    • Engineers now have priority 600, since engineers helping build other engineers first is wise for getting things off the ground.
    • Command stations now have priority 500, since engineers helping build those is the next most important thing.
    • Forcefields now have priority 400, since that's the next most important thing.
    • Factories now have priority 200, since getting them producing ships sooner than later is good.
    • Metal harvesters / asteroid mine and powerplanets now have priority 150, since that's economically a very fast need.
    • Tractor arrays and turrets now have priority 50, to get them up sooner than later.
    • This is all configured in xml, so it can be adjusted by modders or volunteers or otherwise.
    • Normally these construction projecets will be the first things that engineers do on their own, unless there is an emergency repair that is required.
  • Added a new emergency_repair_priority_if_below_percentage="num" for units, with an optional emergency_repair_only_if_engineer_modulus_of="num"
    • The former is set to 70% for all command stations at the moment, and 90% for the home command. They often go down fast once they are targeted.
    • Forcefield generators are set to 70% on the former, BUT a modulus of 4 for the latter. Essentially what this means is that roughly 1 in 4 engineers will break off to repair forcefields that are this damaged. The numbers will never be even close to exact, because it's based on their PKID, which is not linearly distributed between them. So it could be grossly different from 1/4; anything from 0% to 100% of them could do it.
  • Essentially, engineers will now:
    • First do any emergency repairs. In some cases, only some engineers will be diverted for emergencies based on the definition at that target.
    • Then do the construction of all sorts, based on priority.
    • Then sort for the highest priority flow, and if there are multiple of those, then the closest.
      • Flow priorities are something that have been in the game forever, and they have always been quite useful, but now we're overriding those with some better logic for multiple passes, essentially.
    • Also players can give overrriding orders and they'll do that thing until it's finished (for instance if you want some on factory assistance from early on in).
    • Thanks to various folks for suggestions, including yupyip and Wuffell.
  • Several efficiency improvements have been made in the code for engineers figuring out which targets they can repair.
  • Remains rebuilding now works for allied units, not just your own. This is probably only relevant in multiplayer, but would work with NPC factions if any started using that mechanic.
    • We didn't make an option for this, because it's so cheap to do (flip the remains back into a to-construct state) that it's not going to bother anyone. The actual repairs that would happen after being flipped from remains back to normal would only happen if you have Repair Allied Units on, and that's where the costs are.
  • A new "Assist Allied Factories" setting has been added in the galaxy map options, under allies economics.
    • As with "Repair Allied Units", this works with both NPCs and other players. In this case it is about helping with boosting factories, though. This defaults to on.
    • Previously, player engineers would never assist allied faction's factories at all.
    • Thanks to Chthon for suggesting.
  • Also added "Factories Build For Allies" to the same location:
    • With this enabled, your factories will build ships for the fleets of allied factions. Note that specialized factories (like Spire ones) will always build for allied fleets of their sort, regardless of this setting.
    • This also defaults to on.
    • Thanks to Chthon for suggesting.
  • Previously, the list of fleets that a factory was building for was calculated separately on the main thread and was inaccurate.
    • It's now calculated right where the actual assistance logic happens, on a nice background thread for extra speed, and thus also gives fully accurate results.
    • Additionally, this no longer includes fleets that are empty or where all the ship lines are disabled from construction, or where the fleet can't build anything in a factory style.
  • Added a new "is_ignored_by_factories" option to units so that we can mark things like metal harvesters that don't self-construct but also don't get built by factories.
    • This helps us limit down the list of fleets where there's actually something for a factory to help. Previously this wasn't visible in the UI, but was wasting a very minor bit of time on the backend (and with the other recent changes, now it was visible in the UI).
  • Split "Repair Allied Units" into two settings: "Repair Other Player Units" (defaults to on) and "Repair NPC Allied Units" (defaults to off).
    • Thanks to Zeus for inspiring this change.
  • The internal logic for how construction assistance is calculated as desirable has been adjust a bunch to make it smarter.
    • There were a number of funky things that could happen in there before, but the logic has been streamlined and now matches the above logic described.
    • It was also possible for engineers in pursuit mode to invisibly help other units beyond their actual assistance range, and that was only detectable based on the metal flows pane. That's also fixed.
    • The revised method for this allows for engineers to have targets that are out of their range (and then decide between them in the moment), but not to magically boost things that are extra far away.
      • Thanks to Daniexpert for reporting this latter problem.
  • In multiplayer, if your engineers are helping to claim something on the planet of another player, then when claimed the unit or structure will belong to the planet owner instead of you.
    • These units can be freely swapped around anyhow, but generally this sort of claim-sniping is accidental and frustrating.
    • Thanks to Tzarro for reporting.
  • Structures under construction should no longer complete themselves if it would put you into negative energy balance.
    • Brownouts are already more forgiving, but in general this is good policy.
  • The way that metal is spent by engineers assisting construction of units, or assisting factory production of units, is now completely different.
    • Now rather than showing as excess construction costs on the target (in the metal expenditure details), it now shows as an engineer expense separately.
    • This also fixes an issue in that it was charging the other faction rather than you. So if Alice has engineers help Bob build a thing, Bob was paying for those engineers, which is kind of missing the point. Now Alice pays for the work of her own engineers.
      • This pretty much only comes up in multiplayer, and has just been on our todo list for a long while. Engineers doing repairs has always worked properly (so if Alice was allied to the Dark Spire and repairing their ships, it would charge her and not them, etc. Same with Alice repairing Bob ships).
  • Previously we had a single "AssistConstruction" metal flow purpose (action) for engineers and otherwise, and that was problematic for a lot of reasons.
    • Essentially, helping build a structure or helping a factory churn out units are two different actions with different code needed to really have the intelligence work properly, so we have AssistSelfConstruction and AssistFactoryConstruction now.
    • You can still define ships in xml as having "AssistConstruction" and it will give them the same benefit to both of those things internally. So this won't break mod xml.
      • However, we are making the deliberate choice to make it so that, for instance, the Engineering Factory cannot assist the construction of other factories (just structures).
  • We have also had to add a new "Assist Allied Construction" option, since this is now distinct.
    • With this enabled, your engineers will assist the construction of allied faction structures.
  • Added a new personal setting in the debug category: "Include IDs On Targets In Metal Flows Window"
    • When this is on, any targets of metal flows (left click the metal indicator in your HUD) will include the IDs so that you can tell when there are referrals to the same unit versus different ones.
  • Fixed an issue where if you had given a direct order to an engineer to assist something, it would do some or all of the following:
    • Not go repair that thing because it was out of range.
    • Go and do lots of other kinds of repairs that were completely invalid, but charge you for them (aka, don't just boost the factory, but also self-build it when it's already built, and repair its hull when it is at full hull), in addition to whatever it was you intended them to do.

Visual Improvements

  • The shaders for the characters in the background on the main menu hangar scene are now more traditional. They no longer look glistening and metallic, and the rolling normal maps that caused an aliasing-like distortion is no longer there.
  • The scaling of the expansion logos on the main menu has been adjusted so that none of them are cut off, and all of them have a similar font size (before, shorter titles wound up taking up the same amount of horizontal space, making their font much larger).
  • Adjusted it so that ship to ship lines do not disappear when you pause the game.
    • It was still decrementing their time to live timers, when really it should not have been while the game is in a paused state.
  • Fixed a super mega ultra longstanding issue from the last five years where shots would gradually ease in and out of motion when you paused the game.
    • Also, things like explosions, lightning blasts, and most other special effects now pause when the game is paused. So does the planet rotation in the background.
    • Things that are purely vertex animations, like stationary structures rotating, or forcefields pulsing, do not pause.
  • Individual ships now do a better cleanup pass on themselves if they think they might have had lines associated with themselves.
    • If those lines are not related to themselves, then it's time to remove the references.
    • If those lines ARE related to themselves, but are on a different planet or have timed out, then they delete them and remove the reference.
  • Found an issue where we were resetting our line IDs back to zero at various points making indexing them a massive problem.
    • This in turn was probably what was leading to some lines getting left over on the screen from time to time.
  • ArcenGameObjectResourcePools now keep explicit track of every item they have ever created. These are in both managed and unmanaged memory, so that's kind of a wise idea.
    • Added a DoForEveryIArcenGameObjectResourcePoolable() on that class for us to be able to iterate these from code.
    • There is now a DeactivateAndReturnToPoolAnyIArcenShipToShipLineIfActiveAndMistakenlyEnabled() that is run every frame, looking for invalid lines.
      • Overall it should be pretty efficient, because there's only a pool of a thousand or so lines to begin with, and almost all of them are dormant most of the time.
      • We have tested this and found that it is actively clearing some lines, potentially those that were not quite yet to the point of clearing themselves from some other context (since this particular action can only happen on the main thread). The CPU impact is negligible, and this should make it impossible for lines to hang around even a single frame longer than they are supposed to be.
    • Thanks to ZeroTheHero and others for reporting.
  • The Spire Repair Center now has a proper shortname for the sidebar, instead of still saying Spire ENG Center.
    • Thanks to Darkshade for reporting.
  • Random "UnityEngine.PostProcessing.EyeAdaptationComponent.get_active ()" exceptions should no longer ever happen. They didn't hurt anything, but were annoying.
    • Thanks to Badger, Daniexpert, and Strategic Sage for reporting it. Chris was also seeing it.
  • Stinger bolts and certain other weapons previously had text that read along these lines: "If the target has a max bubble forcefield strength of more than [10,000], then the above weapon does [4x] damage to the target's shields (personal or bubble-forcefield)"
    • This has been corrected to say "If the target has a max bubble forcefield strength of more than [10,000], then the above weapon does [4x] damage to the target's bubble-forcefield."
    • Thanks to GreatYng for reporting.

Mod Updates

  • Kaizers Marauders:
    • The Fortified Forceshield Generator now uses moves_back_after_being_norrised="true" instead of the tag "MovesBackAfterBeingNorrised".

3.309 Hangar Staff

(Released July 12th, 2021)

Hacking Estimate Improvements

  • Hacks against planets (weaken turrets/guardposts) now have a strength estimate
  • The following minor faction hacks now also have estimates
    • The DZ Library hack to get ship lines
    • The "Get Scourge Allies" and the "Cause DZ to appear" hacks
    • The Contact Outguard hack as well
      • Like all hack estimates, these are ballpark at best.
      • The hacking history now also records the approximate response to your hacks when appropriate
        • From a discussion with an anonymous newbie dunce wearing a silly hat

Battle Indicator QoL tweaks

  • The goal is to make the indicators more likely to be useful indicators of important battles that you care about
    • Indicators no longer appear on unexplored planets
    • Indicators no longer appear on Dyson or Nomad planets unless you have forces there (these indicators tend to be Always On)
    • Indicators are now allowed to appear on AI planets if you have forces there.
    • Very small battles that don't involve your forces won't appear
      • Prompted by a discussion with Metrekec and Evil Bistro

Main Menu Hangar Scene Visual And Performance Improvements

  • The shaders used for the ships and walls and such on the main menu have been completely reworked.
    • The logos on the wall have been made a lot more efficient. The DLC ones were causing many extra draw calls, while the Arcen one was 400% more polygons than it should have been ugh!
    • The main menu now uses the Deferred rendering pipeline, which is more efficient when you have a lot of light sources, rather than using the Forward render pipeline. This is something we did in our title Release Raptor, and other unreleased titles, but it never seemed to have relevance in AI War 2 until now.
      • At this point, the main menu was doing double or triple work a lot of the time, according to our investigating with the Frame Debugger, because it had multiple light sources hitting many large objects that each had lots of draw calls.
    • Now that this is in deferred rendering path, the overall visuals of the main menu hangar scene are a bit different. The lighting is different, and overall blends differently.
      • The first thing that needed to be adjusted was the ships themselves. They're now darker and more menacing, fitting better with the theme here.
      • The second thing is a few of the materials which were overly reflective when in the Deferred path. Those have been adjusted.
      • Thirdly, we were already using Screen Space Ambient Occlusion (SSAO) on this scene to make it look nicer, but that has been made much more substantial so there is more of a feeling of contrast between light and shadow, and because otherwise some of the background elements seem to otherwise be disconnected from their surroundings based on how their materials were.
    • At this point, it's clear that one of the remaining MAJOR sources of load on the main menu is the Reflection Probe, which is running in realtime. It's time-sliced to do all the sides at once every so often, so essentially it causes a quadrupling of load every few frames.
      • But just what exactly are we meaning to reflect? The dramatic skybox is really what we want to see from this reflection probe that we can't get any other way. In the past, with the reflection probe doing all the work, it was impossible to do more time-slicing or anything else to make it more efficient or it would look jerky. But now that we're in the Deferred pipeline here, we have a depth buffer (beyond the basic zbuffer) and way more info.
      • With that in mind, the first step was to disable the reflection probe and see if we could get that to work. Short answer: not really. The scene is super dark and strange without the reflection probe at all.
      • The next step is to implement Screen Space Reflections (SSR), which again is something we've used in other projects many times. We just went with the basic Unity implementation, as we don't need something super fancy.
        • The initial results from THAT are actually quite impressive. Most notably, it makes the reflections from the emissive light sources a lot more dramatic. That's cool! But, of course, since the skybox is a very small part of the screen, it contributes very little light to it. So overall the scene is very dark and doesn't have that periodic bright lightness to it like before.
      • Next step is turning back on the reflection probe, but time-sliced to only update one side at a time (previously this caused things to look jerky). Since we're now blending two layers of reflection, the jerkiness is entirely gone!
      • But even so, now it's time to turn our attention to what the reflection probe is reflecting. It simply needs to reflect the sky. Not the walls, not the floor, not the ships -- the SSR already takes care of those things, and in a none-frame-jittery way. Those are the bits that jitter even now. PLUS, it's drawing all that geometry for the reflection probe that makes it take so long. What if it... skipped most of that?
        • Therefore, we moved the skybox into its own layer, and two blocking planes as lighting mats to prevent certain kinds of unrealistic light bleed. It's like a movie set, the lighting gets bounced how we want by stuff just off camera. At any rate, now the reflection probe just reflects those dark mats and the sky, and it blends perfectly with the SSR at a teeny tiny fraction of the processing power, AND it's time sliced. Major win.
    • Finally, by using Mesh Combine Studio, we were able to split the main hangar itself into more sub-objects and also batch them a bit more efficiently. Overall this is a lot more efficient than sending a ton (12) of submeshes to the GPU all at once. For weaker GPUs in particular, or weaker GPU buses, this was probably the main bottleneck. Overall we also were able to scrape out even some more polygons with this.
    • Oh yes, and we also no longer draw the loading screen and all its special post processing effects behind the main hangar scene. That was a real waste of processing.
    • The final result is a scene that looks very similar, but actually more grounded and dramatic, plus way more efficient. Draw calls are down from the 300s to the 120ish range, and total vertices drawn are now about 60-something thousand rather than over 400 thousand. The actual UI part is still drawn with a Forward camera and is still as sharp and normal as ever. Because of the revisions to how the reflection probe is integrated, more of the scene actually gets lighting contribution from the outside sky, which also looks even better. Chris's machine went from about 100fps on it to closer to 140fps.
  • Okay, another round of major changes to the main menu scene. The prior version that we had completed for this build was very high performance, but... bland. The lighting was not reflective at all, and so there was this odd flatness and dullness to things. That's no good at all.
    • Then also we lost some of the combination work, and had to recreate it from better-looking originals that actually turned out to be quite low-poly. So that completely reworked the roof rafters and the front door area.
    • We then added in a ton of uv emission animations and uv normal map animations, which are things that make static surfaces seem to come alive in various ways. We added more details in various points, too, to continue to break things up.
    • The reflection probe is back and no longer time-sliced at ALL, but this winds up only sacrificing 6fps on the really old OSX machine because of the layer mask used for it, and that helps bring the scene back to life more.
    • But even so, it would be great if this felt more alive in general, so we added distant lights in the rafters, lights along the launch strip, and so on. There's also a new robotic arm that can be animated later, but for now it sits still.
    • Another longtime request was to have some people moving around in here. At first I added just two folks fully suited-up talking to one another by the door. Their conversation is randomized and all in body language.
    • After discussions on discord, I also added a third guy standing nearby ignoring the first two and looking really impatient with the door. He swings his arms, checks his watch, stomps his foot, crosses his arms, and a variety of other things over time. There's also a fourth guy who sits way over by himself amongst some machinery he is probably not supposed to be in. He just kind of sits there bored, looking around a bit.
    • The launch animations had a few problems that were apparent now with the revised exit doors, and so those all have been updated slightly to make them more smooth and so that there is no "pop out" period in terms of the reflections.
    • With two characters, fps on the ancient mac was 30 fps. With four characters, it's 29. But it's still far more smooth than it used to be on that machine, while also way more visually interesting. In other words it's not a laggy 30fps, unlike before (where it was 24fps anyway). On my nicer machine, I get around 75-90 fps still, and the fan doesn't even turn on. Hopefully that will be the case for more people, although that machine is running a GTX 1070 M.
    • After more discussion on discord, a small transparent safety barrier was added on the side where most of the characters are. It would not meet OSHA guidelines, but it will keep them from the worst of falls.
      • We temporarily experimented with characters that were having floating conversations, but there's no way to make that look fully natural because hand motions would normally impart a spin, and that would devolve quickly. You can see videos of all these intermediate versions on discord, if you're curious! It's in the watch_chris_art subchannel.

More Visual Updates And Additions

  • All of the wormhole graphics have been updated to a new particle effect that is a bit more funnel-like, and which shows brighter colors for the various types of planet you might be looking at through it.
    • It still doesn't have a mouseover effect, which is a bit odd and something we plan to improve at some point in the future.
    • Thanks to nas1m, NR SirLimbo, and Evil Bistro for seeing some of the particle work I was doing and suggesting it be adapted to the wormholes.
  • The metal harvesters, and the empty asteroids when they are not yet built, now have improved graphics (base game).
    • Essentially, the rocks look like they have better lighting and look more rocky.
    • And instead of the domes just glowing like a lunatic, they look like they have subsurface scattering (it's a paint effect, not math), and the entire structure looks more weathered and beat-up.
  • The Swarm Cruiser (ZO) has been updated to now have 3 LODs rather than none.
  • Various units from ZO with new art:
    • Lockdown cruiser, Ethereal Cruiser.
    • Minelayer frigate, Gravitational Rift, Spymaster, Ambush Post, Unstable Gravity Generator.
    • Starburst (weapon), Gridlock (weapon device), Deadlock (weapon device).
    • Ambush drone, Hoplite drone, Murderfly, Reclamation drone.
    • Disabled nomad nexus, Hacked nomad nexus, Crashing nomad nexus.
    • Demeter's Cornucopia.
    • Zenith Miner Probe (complete with scanning visual effects)

Tweaks And Fixes

  • FixedResourceTextStats now requires a name for the resource, and has a string for the resource name in its color. This way it's always accessible.
  • For Spire Relic Trains, I have rewritten the hovertext for this notification for improved clarity, and also improved the "pick next planet to for relic train" logic to help it find some better planets
    • Thanks to Evil Bistro for reporting
  • Renamed our "SelectionManager" class to "PlanetViewSelectionManager," since that was conflicting with a built-in unity class otherwise.
  • Put in some code to prevent larger damage from anything InitializeSquad() gets wrong, as well as more info to let us know what happened if it does go wrong.
    • Such as when, for instance, the test chamber is instructed to initialize a ship that does not exist.

Mod Updates

  • AMU:
    • Created the utility functions getHopsToAnyAIPlanets() and getMaxHopsToAnyAIPlanet().
    • Created multiple new rollups for upcoming mods...
    • GameCommand_MoveAllToPlanet now has an optional destination location where ships will aim to move at.
    • Added a new GameCommand_MoveToPosition which can be used to simply move something to a position, no questions asked.
    • When PseudoTransformEntityType_ReturnNullIfClient now copies the seconds until repair is possible and the game second the planet was entered over from the old entity into the new entity.
      • This fixes transforming entities in AMU-derrived mods from being susceptible to ambush damage modifiers, or potentially having their own damage modifiers apply anew, as well as immediately regenerating shields (most notably and annoying when a Devourer from Devourer Chrysalis became enraged).
    • The DrawingBagBase class and its children can now use AdjustWeightBy and AdjustWeightTo functions.
  • Devourer Chrysalis:
    • Adjusted to AMU changes.
    • More fixes for the Hydra Devourer type:
      • Put in another fix for the Hydra Devourer heads having hacks. This required a fix from Vanilla code.
      • The Hydra Devourer head icons are now much smaller.
      • The artillery on greater heads can now target down to 7 tx units, and the artillery on lesser heads can go down to 6 tx.
      • The spawn frequency of heads was reduced to 20% of what it was.
      • The heads no longer grant science on death. Gaining 50k science from slaying a single head at the frequency those were appearing could be farmed for near infinite amounts of science.
    • Added instrumentation for an error in the enraged transformation code. It's unknown where it came from, everything looks fine, but if it appears again next time there should be more info.
      • Thanks to Isiel for reporting.
  • Kaizers Marauders:
    • The player variants of all Marauder Raiders are now bigger and have no more icon overlays, freeing the overlay up for the ship count contained.
  • The Reprocessors: Fixed spawning outside of gravity wells. If there is a bug then please message me on Discord.
  • Updated the Macrophage Histiocytes mod to not have too-long names for the sidebars.
  • Devourer Chrysalis:
    • Fixed some bad wording in the mod description.
  • Devourer Chrysalis:
    • The Hydra Devourer lesser heads don't spawn themselves in an infinite, ever-increasing loop any more.
      • Thanks to Lord Of Nothing for reporting.
  • Devourer Chrysalis:
    • Removed all hacks from the Hydra Devourer heads.
      • Thanks to Lord Of Nothing for reporting.

3.307 Art Overload And The Devourer Chrysalis

(Released July 3rd, 2021)

  • More Tooltip Work:
    • The first line of tooltips with the metal and energy readouts no longer compares it to the current metal and energy if insufficient. This shortenes the line significantly and gets rid of useless clutter, since the build stats already show resources in red if insufficient.
    • Fixed units that can be claimed always showing 0 metal cost to claim.

Art Updates

  • The Dregil unit for the DZ has had its shader updated, and a reflection cubemap as well as second diffuse layer is now applied. It's a lot fancier now, in one respect, while still being the same model and same general idea as before.
    • Same with the Metal Harvester for the DZ.
  • The AI Command Station (the ones used at regular planets or at reconquest planets) have been completely redone visually.
    • The now look a bit like they have some inspiration from the ISS, and Apollo, and in general seeem more like communications relay objects (they are), rather than housing or a true space station like the humans would build.
    • The human command stations will get their own rework soon, but they won't have any relationship visually to the AI kind. The two groups are building them for entirely different purpsoes beyond the global "controls this system" purpose.
    • The old version of the command stations were some of Chris's earlier art for the game, and attempting to hit a sense of large scale without having insane texture map requirements led to a really subpar result. On discord, there's a pretty cool discussion in the watch_chris_art section:
  • Two turrets in ZO would not have loaded properly for people who did not have TSR:
    • Ragnar's Makeshift Turret and Ragnar's Blitzkrieg Turret. It seems like these would have resulted in errors on start, but apparently not.
  • Two further turrets in ZO just looked like MLRS turrets. However, they now have the proper art ported over from DLC1:
    • Potent Acid Turret and Pacifying Jammer Turret.
  • The version of the hive golem that has been the default since 2017 is now only used for The Monarch ouguard unit in DLC2.
    • There is a new version of the hive golem in the newer more-detailed golem style for the base game. Similar to how the Zenith Trader was updated a bit before ZO came out.
    • The Queen Bee and Golden Wasp Golem variants that are available in ZO now also have their own versions.
    • Those were something you could see as they were completed on discord here: https://discord.com/channels/240637654717300736/825178033500848149/859899718590267423
  • In ZO, the Corruption Minefield, Reactive Dummy, and Implosion Minefield now all have new unique graphics rather than reusing older graphics.
    • Same with the Cyborg Ambassador, Trojan Horse, Ship Compactor, and Cargo Container outguard units.
    • Same with the Phantasmal Host Frigate and its decoy.
    • Ditto the Polarizer strikecraft and Polarizer Guardian, and Electric Bomber strikecraft.
    • Ditto the Chain Lightning Eye (and alerted variant).
    • And the Trebuchet, Void Catalyst, and Mosquito Drone.
    • Lastly, (for now) the Swarm Cruiser, Blackguard Cruiser, and the Radiant Cruiser.
  • ZO now contains a Assets/_DLC2/Outguard/CyborgAmbassador/CyborgAmbassador_AltUnused_EnjoyModders.prefab file that we don't use, in the visuals_bundle="exp2_zenith_onslaught"
    • Feel free to use it in mods.

Mod Updates

  • Kaizers Marauders:
    • Fixed the Defense Schematics hack reading it can also be hacked by transport and officer fleets when it actually can only get hacked by battlestations and citadels.
      • Thanks to Darkshade for reporting.
  • AMU:
    • Hacks using the ExtendedHackingImplementation base class must now define HackableByPseudoCenterpieces which makes it (im)possible to be hacked by spire city centerpieces.
    • The ShipOrTurretGrantingHackingImplementation now only allows hacks by pseudo-centerpieces if the hack grants something other than fleet lines, i.e. a centerpiece itself. This trickles down and fixes Kaizer's Marauders ship line hacks seeing spire city fleet centerpieces as eligible hackers.

New Mod! Devourer Chrysalis by NR SirLimbo

  • Added the distributed mod "Devourer Chrysalis".
    • NOTE: The mod requires both AMU and DLC 2 installed.
    • This mod adds a new minor faction, an overhauled and improved Devourer Golem faction that is vastly superior to the Vanilla one.
    • It evolves, behaves like an animal that can be manipulated and chased, but behaves vengeful and dangerous if provoked.
    • This Devourer exists in two stages:
      • Normally it roams around the galaxy, seeking out suitable fleetballs to feast upon. In this state its behavior can be altered by hacks, allowing the player to pacify, antagonize or entice it.
      • When defeated, not only does it grant a good amount of science it also goes into chrysalis. During this phase it can be analyzed for ship designs, weakened, hacked for metal income and more. After emerging from chrysalis it becomes a new, higher-tier and much more dangeorus Devourer.
      • Beware that most hacks increase the Devourer's progress towards the next mark level, and reversing progress is only possible while its in chrysalis.
    • In essence: Hunt this beast at your own peril and beware for the consequences. Do not let your thirst for power drive up its mark and tier to a point where it becomes too much to handle. At Tier 4 there may not be any other way left to destroy it except for throwing hurling planets...

3.306 Tweaks

(Released June 29th, 2021)

  • Added AI versions of the Rail Frigate and Rail Destroyer for the Spire Hammer AI. (DLC2)
    • These are significantly weaker than player versions given how the AI gets so many more of them. Thanks again to Lord of Nothing for allowing me to "lift" the basic setups of the two units before adjusting them to fit AI usage.
    • Thanks to CRCGamer for adding.
  • Multipliers for incoming electrotoxic, revenge shot and attrition damage are now ensured to never be below 0.
  • Tooltips now show when an unit has multipliers for incoming electrotoxic, revenge shot and attrition damage, and when an unit cannot be put into another state of matter by enemy weapon fire.
    • Thanks to NR SirLimbo for updating.
  • AMU mod update:
    • Fixed an exception when loading a save with no living AI left (= the player has already won).
      • Thanks to Isiel for reporting.

3.305 Fruits Of A Snipe Hunt

(Released June 26th, 2021)

Tooltip Improvements

  • More Tooltip Work:
    • Fixed the range buff color being extremely dark - it is now a brighter, more orange-ish red.
    • Fixed CPA and Relentless Wave factions not displaying the AI type in front of them.
    • On the highest detail level now no longer show icons for most things - instead they show text such as "Hull", "Shield", "Strength" etc.
    • On medium or lower detail levels they now display icons for most resources instead of the text, making them much more readable.
    • To do this, updated a large number of ArcenCharacterBufferBase extensions.
    • Shield percentages on medium and highest tooltip detail levels now shift from cyan to red instead of from green to red. It was strange to look at a green hull min/max value, and green to red percentage of hull health, and directly behind cyan shield min/max value, yet still green to red percentage.
    • Thanks to NR SirLimbo for this work!
  • New single-color icons have been introduced for the various ship stats. We may refine these over time, and/or work on their scaling. But they are a major step up over the messy full-color ones (which looked amazing at full scale and terrible when tiny and in proper context).

Balance Changes

  • removed melee pursuit from Light Minelayers. This variant does need to have default kiting behavior unlike the other 2, which performed poorly until given melee
    • Thanks to Darkshade for pointing out this issue, and Zesuf for making the updates!
  • Flenser armor 180mm -> 500mm
  • Flenser, Mothership, and Planetcracker now have Norris and Harmonic feature, so these will not be deterred by bubbleshields at all
  • Mother ship and Planetcracker now also stop ceasefires. These are tier 4 after all
  • T3 Jackalope gains Harmonic feature, it can move through shields
  • T3 Mothership gains Norris effect, it can push shields
  • T3 Hunter/Annihilator now cancels out ceasefires
    • Thank you to Crawlers and GreatYng for pointing out this silliness about the elite exagalatic ships, and Zesuf for making the updates.

Bugfixes

  • Put in a further fix to savegames with unsupported characters in them still giving a disk exception.
    • Thanks to UFO for reporting it was still happening.
  • Fix a bug where the beacon scourge might be allied to the AI
    • Thanks to Jack Trades for reporting.
  • (Coil)beam Math:
    • The state of matter is now required for GetEnemyEntitiesIntersectingInstaFireConicalShot(). This should give later functions less targets to work with, and improve performance slightly.
    • Created the DoMultiHittingBeamAttack() function for unifying all types of beam weapon hits in the same code. If something breaks here it breaks everything, and in reverse if it works here it'll work everywhere.
    • Upgraded the logic for more efficiency and fixed the coilbeam math. At the end I didn't find out where the bug was, but with all these corrections it simply... started working correctly in tests.
    • Thanks to NR SirLimbo for this!

The Loading Snipe Hunt

  • After 12+ hours of work trying to make the game loading more asynchronous (and mostly succeeding, minus some very odd niggles like UI windows refusing to go anywhere near the right part of the screen)), that work has been thrown aside and I'm going to approach the whole "certain things don't load right for some people" from the prior build via another avenue. Secondary benefits scavenged from the giant mass of scrapped work include:
    • The uniterm console, which is an ancient thing from alpha we were using, has been removed from the codebase. We have our own console now, and have for years.
      • This actually speeds loading up external dlls quite a bit.
    • Also made improvements to our internal ObjectDumper, so that it is more robust when it has a failure due to us needing to update some internal code, etc.
      • We use this tool to programmatically verify that data has not changed when we change the parser that loads in data.
    • Our "delayed log messages" from background threads are now ordered in the precise order they were logged.
      • This is possible thanks to using System.Threading.Interlocked to add ordered IDs to them, since the data structures we must use across threads like this are unordered.
    • In general, our debug logging has seen a number of upgrades and improvements, including making all of the general log-writers go to the delayed channel (so they definitely show up) when being written-to from background threads.
    • Since multithreading is being done more and more casually in here even by modders -- which is great! -- we needed extra robustness in here. Also, for general purposes, there are too many places now that might run on one thread or many at once, so there's also that.
  • Simply reverted a change from June 23rd which was intended to fix a (very very) rare exception with how xml reloading could throw an error.
    • The fix that I had implemented caused some processors not to be able to load the game at all, and the 12-hour snipe hunt resulted.
    • The 12 hour snipe hunt was in many respects a waste, since it almost all had to be reverted, but it did provide some really interesting data on what matters and what does not matter in terms of load speed improvements. So some further minor improvements will certainly result from that.
  • Further fixed up some bits of code to keep certain invalid filenames or campaign names from causing errors.
  • A bit more of performance improvements in UI windows (even those not showing), plus ability to output debug information in a new way, as been added back in from the 12-hour snipe hunt.
  • One result of the 12-hours snipe hunt was that we realized that certain things could be done in parallel for a faster loading experience with fewer statuses flying by. As it happens, we can do those linearly in most cases with the same resulting speed increase. If your processor and disk are both very fast, you may see a 2 second improvement out of 10 or 12 total. If your framerate is low or you are set to have Vsync at 30 or similar, then you should see larger gains than that. If you're having a very slow load that is taking 100+ seconds because of loading things off of asset bundles on disk, then likely thing won't improve much from this (though you never know -- and that is mostly a case where the next time you run it, it will be faster due to caching).
  • Redid the various attribute tags in classes throughout the codebase to avoid objectdumper going into endless loops when we use it. We just hadn't been needing it for a while, so things got a bit wooly with it.
    • This is one of those things we don't even need right now, but if we ever need to do data integrity verification in the future, we want to have this working and verified BEFORE we get 6-8 hours into the process of trying to update the schema.
    • This again was done during the snipe-hunt, but is better re-done now.

Mod Updates

  • AMU:
    • Adjusted AMU to the most recent Vanilla changes.
  • Kaizers Marauders:
    • Adjusted KM to the most recent Vanilla changes.
    • Further divorced Kaizers Marauders from Vanilla Marauders: Kaizers no longer overwrites a number of Vanilla Marauder entities. This may result in Kaizers Marauders not (fully) working, but should be savegame compatible.
      • If you have trouble with Kaizers Marauders, please finish your current games with the "v3.303 - Last version before the Kaizer's Marauders split" beta build in Steam.

3.304 Coilbeams No Longer Tickle

(Released June 23rd, 2021)

QoL

  • New hotkey: Assign Fleet Group (Defaults to control key)
    • Hold this modifier key down and then press one of the fleet selection keys above. Any fleets that have you have selected will be immediately assigned to that fleet number (the entire fleet; you cannot assign part of a fleet to a number).
    • Any existing fleets that are not selected and which have the same fleet number will be assigned to no fleet number.
    • Thanks to lots of folks for requesting this for a long time.
  • New helper command (like a cheat code but not a cheat): rename campaign,[New Name]
    • Rename the current campaign Whatever you enter after the comma -- including spaces and capitalization -- will be the new name of the campaign.
    • It helpfully removes any starting spaces you might have added in there, and any invalid characters become underscores.
    • Example usage:
      • cmd:renamecampaign, My New Campaign Name
      • This example would make any further saves go in the campaign folder "My New Campaign Name".
    • Thanks to Ecthelon for suggesting.
  • Officer fleets -- Arks and Golems -- now always default to Flagship Roaming of "Roam if Instructed." Same with fallen spire fleets.
    • This only applies to new campaigns, but should lead to less confusion on the parts of players.
    • Strike fleets (aka transports), battlestations, citadels, and support factories all still default to "Stay Put Unless Direct Order."
      • The idea is that their mode is primarily for purposes of the units they create. But if you prefer to change this setting, you can go in and do so.
    • Thanks to Zweihand and many others for suggesting.
  • Updated the first row of tooltips to once again include the AI type and player fleet name.
    • Requested by defekt and BadgerBadgerBadger on Mantis.
    • Thanks to NR SirLimbo for this work!
  • More tooltip work:
    • Fixed the Range buffs using the color of speed instead of range. For this purpose, added a whole lot of functions to range formating extensions to the ArcenCharacterBufferBase.
    • Fixed a metric ton of bugs with the AddNumberMoreReadable() function when it came to values below 1000, let alone below 1 or even negatives.
    • Cloaked units now show that they are cloaked in the buffs row, and if they are decloaked will display the same in the debuffs row.
      • In addition, on high tooltips they display for how long they can sustain the cloak with the current incoming tachyon radiation, and if no tachyon rays are incoming how long it takes until the ship replenishes its cloaking points.
    • Thanks to NR SirLimbo for this work!

Bugfixes

  • Spire Flagships can no longer hack ARSs
    • Thanks to Evil Bistro for reporting and others for discussion
  • Under the hood, we no longer sort the fleet member groups. It's possible that this was causing some various issues in both SP and MP. It may have also had some performance impact.
    • We now instead have a new DoForMemberGroupsSorted_NonSim() method on fleets, which does the same sort but only when it's needed for something in the UI.
    • MemberGroups are also now private, so that we need to use one method or another.
    • Code mods will now be forced to choose between looping over these sorted but not for simulation use, or unsorted for simulation use. Unless you're showing a tooltip or other ui element, always use the unsorted one.
  • Fixed the issue with when you switched fleet leader types, it would often then show at the bottom of the list in the fleet management window.
    • Thanks to several players for reporting.
  • The Swap fleet leader no longer actually swaps fleet leaders. This is problematic for a whole lot of reasons (upgrades from techs, upgrades from hacks, history of the fleet leader, drones, and many other things).
    • Instead it swaps all of the non-fleet-leader, non-drone lines in the two fleets, thus bypassing this problem.
    • There's a bunch of minor interface changes and improvements to get this working fully as well as showing clearly.
    • Thanks to Darkshade, CRCGamer, UFO, and Ranamar for reporting the bugs with the other approach.
  • Fixed a bug when swapping fleet lines around where it would show empty lines that no longer existed (usually from a type change on that fleet).
  • Fixed a variety of "blank data" exceptions that could happen when setting up the game from an old save or a quickstart, among other circumstances.
    • First of all, the way that missing factions are added is more careful now, although that turned out not to be the problem.
    • Secondly, CPALogic and RelentlessWave subfactions are added in a better way for each AI in multi-AI games, to lead to less confusion with them.
    • And lastly, if there was explicitly blank (or otherwise old) data, it was not previously reading in the current-game default. This has been corrected so that it now chooses default values.
      • This was the reason why often certain quickstarts had errors with the Praetorian Guard immediately after starting, and things of that nature.
    • Thanks to Chuito12, Alivaril, Darkshade, and Rune for reporting, and to the former for giving us detailed reproduction steps for the bug.
  • Using unsupported characters in filenames (or names in general that get serialized) will now use underscores rather than question marks as replacements. This keeps from having filesystem errors if the text is for the filesystem (question marks are not valid in filenames).
    • Thanks to UFO for reporting.
  • Fix a bug where dropping below the Wormhole Borer AIP threshold could prevent any active borers from being updated
    • Thanks to Ecthelon for reporting
  • Hopefully fix a typo in the aip log about instigators
    • Thanks to GreatYng for reporting
  • Fix a problem with marauder outpost descriptions
    • Thanks to novellus for reporting
  • Added a new debug settings toggle: "Log Coilbeam Math"
    • When this is on, any coilbeam weapons fire will log its details so that it can be examined and/or debugged.
  • Fixed a bug that could happen when reloading all the xml from disk after changing mods or expansions that are installed.
    • Essentially some of the central collections were not concurrent, but were being handled from multiple threads and so needed to be.
  • Fixed some general broken logic with beam weapons, because we had some variables named in a confusing way. This naming has now been fixed.
    • Most recently, this has been causing coilbeam shots to do something like 93 damage when their base was 75k and they were supposed to be doing 18.7k damage per correct math. This is fixed now.
    • But in general, this was causing certain non-coilbeam beam weapons to also do similarly way-too-low amounts of damage. It's hard to know if we had any ships using that particular other code path or not (it's possible not), but those ships were either doing way too much or way too little damage, and will now work properly. So if some other beam weapon seems way off, then this is likely because we had tuned it wrong because of this longer-standing bug.
    • Thanks to Chuito12, Wuffell, Histidine, Lord Of Nothing, and others for reporting.

Mod Updates

  • AMU:
    • Adjusted the mod to changes in the Vanilla codebase.
  • Kaizers Marauders:
    • "Divorced" Kaizers from the normal Marauders. It is now possible to have both in the same game at the same time.
    • This also fixes a few minor issues like Kaizers Marauders inheriting a few faction fields such as the intelligence (that enables/disables fireteams), which doesn't do anything for Kaizers Marauders since they always use fireteams, and redundant invasion time settings.
    • Kaizers Marauders now also have an unique faction description.
      • At the request of Chris and BadgerBadgerBadger, and in retrospect for the better. Most of it was due to Kaizers Marauders starting as something else than what they turned out to be.
    • This will break existing savegames that have KM in them. To finish those games, you can temporarily use the "v3.303 - Last version before the Kaizer's Marauders split" beta build in Steam. You may have to exit and restart Steam before this appears.

3.303 Tutorial Hotfix

(Released June 22nd, 2021)

  • Fixed some mapgen oddities that had crept into affecting tutorials, specifically making a lot of AI forces spawn on your early planets to kill you nearly instantly. Wow.
    • Thanks to Nygmus and others for reporting.
  • In running through a test of all the tutorials, we discovered it was STILL possible for waves to spawn against the player even when those were turned off.
    • Or maybe it's newly possible again, it's hard to say. Either way, it's a very hard wave even if the players had all of their normal kit, which they do not. It's a death wave, either way.
    • The UI itself is now being used as a last line of defense. This is a strange way to do things, but it's the ultimate final safety net. If you're in a tutorial that says no waves, and you aren't an MP client, then when the UI would tell you about waves it instead deletes them all.
  • There is a new "Go For Perfect Symmetry" option on the X map type, which defaults to true, which gives the old perfectly-symmetrical map logic.
    • If you leave this on and turn off all other options, you have the X map of a few weeks ago.
    • THAT said, this generates too many nodes per number of planets requested, and that part has been fixed by just offsetting internally.
      • Previously if you asked for 160 planets, you would get 180. Now you actually get 160. And so on down the line.
      • This does mean that the old 80-planet experience is the new 100 planet experience.
      • This does also mean that partial planet requests (like 52) give the same as 50.
    • Anyhow, this is the best of both worlds. You get the old style X map as an option (as the default, in fact), but with more options on how to configure things and the option of other cross-connections.
    • Thanks to Khan for requesting the classic X make a return.

3.302 Clarified Invincibility

(Released June 21st, 2021)

QoL

  • When you try to attack a target but cannot, there are now actually some local messages that show now (finally).
    • Apologies this took so long, it was really a confusing thing for some folks, and a big oversight on my part.
    • In the event that you have some ships that could attack a unit in the current circumstances, but not the specific one you clicked, it says:
      • None of your selected ships can currently damage [this unit]. Check its tooltip for invulnerabilities.
    • In the event that your selected ships can't do anything in the first place, it says:
      • None of your selected ships are ready or able to attack this. They are all in loading mode, or unable to leave another planet, or lack weapons, etc.
    • In the event that you have no units selected, or only planetary units on another planet, it simply says:
      • Please select some ships before trying to attack.
  • For the various "tall" popup windows that show text, there are now also "tall wide" and "tall ultrawide" options.
    • We use various of them, as appropriate, throughout the game now. Any place that is showing details of ship lines should be using the wide version so there is room (but not ultrawide as that turned out to be way too much room.
    • Thanks to NR SirLimbo for inspiring this addition.
  • Hitting the escape key now clears a bunch of other windows that were "ok popups" that you could only click the button on previously.
  • The window header for tips now shows the sidebar text, which looks far nicer and is also more informative.

Bugfixes

  • Fix a bug with some Ship Groups for unreleased features not being filled, and giving a harmless error message at game start time
    • Thanks to a number of players for reporting
  • Fix a bug where the ZO achievements exceptions were causing exceptions on games without the ZO enabled
    • Thanks to Exilium for reporting
  • As a player, if you right-click on "empty space" that has a cloaked enemy there, it now treats it as if there is truly nothing there.
    • No testing for enemy mines or whatever by clicking around, heh.
  • Fixed a bug we were never aware of until now where if you double-right-clicked... anything really... it would give a huge spam of duplicate commands.
    • This didn't break anything in the game, but it was a definite performance drain, particularly in multiplayer. If someone has the habit of double-right-clicking for whatever reason, metric tons of extra data calculations would happen. That is no longer the case.
  • Fixed an error in the factions window screen during the game where in recent versions it was often showing a nonsense bit of text rather than the chosen option.
    • Additionally, fixed it having an exception when you viewed the advanced settings for an AI faction in this screen.
    • Thanks to Smidlee and Darkshade for reporting.
  • Another round of bugfixes against Hunter or AI ships targeting Nomad planets or neutral factions or the like

Mod Updates

  • AMU:
    • Fixed a lot of wrong math around metal and science in/out of bounds with hacks that grant or cost metal or science per second.
    • Fixed the hack ending in an exception if a hack ran out of metal or science and was forced to end.
    • Improved the GameCommand_AllAttackTarget to include the option to set a behavior to all units.
  • AMU:
    • Created a new AllMobileDevourerIncludingEnragedRollup for the upcoming Devourer Chrysalis mod.

3.301 I Always Wanted To Be A Ghostbuster...

(Released June 19th, 2021)

  • Fixed ships with any resource gains in Distributed Economy mode and gains of other resources in non-Distributed Economy mode being unable to gain these other resources at all.
    • This fixes being unable to extract science and hacking points from planets in Distributed Economy mode.
    • Thanks to Vivisector 9999, Exohydra, Darkshade, Democract, and whimsee for reporting on Mantis, and a number of others on Discord. And to NR SirLimbo for fixing it!
  • Fixed the build stats on minimum detail levels overlapping each other.
    • Thanks to defekt for reporting, and NR SirLimbo for fixing.

Multiplayer Bugfixing

  • Added a new "Short-Term Planning Debug Log" to the debug section of personal settings, which allows us to write sub-info from that to a new ShortTermPlanningLog.txt file.
    • Also added "Planet View Mouse Handling Debug Log", which writes to PlanetViewMouseHandlingLog.txt.
    • Chasing down a bug related to multiplayer client performance dropping off in battles in a certain savegame (and probably other contexts also, but at least we can duplicate it in this one).
  • Added new MP stats on the client and host.
    • Host: "Srv Ships Needing Sync Fix" (usually is zero, but if it spikes into the thousands we have a problem).
    • Client: "Cl Ships To Del" (grows into the hundreds, which is problematic right now), "Cl Ships To Ask" (usually zero, spikes a bit at times, no problem), and "Cl Ghosts Waiting" (this spirals into the thousands pretty fast and seems to be the roof of the performance hitching that then comes in.
  • Okay, a lot of rewriting of the ghost handling logic once again.
    • In particular, ghosts are much better at noticing when they have been told "hey you're okay, you're alive!" and also "hey, you died, get out of here, sorry."
    • There's also a backup timer added back in, where if something is still in limbo as a ghost after 10 realtime seconds, the client just tells them to die. This is what caused the self-deleting fleets on clients, and all that other chaos, in the past. But now it's... well, it's the same concept, but way different code. It seems to be killing far less, and actually killing what it should and not what it shouldn't. But more testing is needed.
    • Overall these changes are hot off the presses, so we'll see what happens, but initial indications are that this solves the following issues:
      • First, an excess buildup (still smaller, but present) of extra ghosts on the client.
      • Secondly, a large buildup of hitching and performance problems on both client and host. To a really severe degree lately by some accounts, and months ago by others.
      • Thirdly, smoothness of the simulation in general and number of corrections needed (not having ghosts around, yeah that checks out).
    • Thanks to Peons, Mission, and Zweihand for reporting.

3.300 Mapsplosion

(Released June 18th, 2021)

QoL

  • In the lobby, "Number of Planets" is now called "Desired Planets," and it shows how many actual planets there are after that.
    • Various map types give slightly more or fewer than the amount you request, so having this be something you can see is relevant. It's not a bug if you ask for 80 and get 83 or 75; it's likely just the nature of that map type. So this helps make clear what you're actually getting into.
  • Map options that are specific to the map type now show up with their text in blue, with the word "Customize:" next to them, making it way easier to keep track of what is that versus what is global to all map types.
    • Also in general the map sidebar is more vertically condensed so that we can now easily show six custom fields without having to scroll the map sidebar to see alll the controls.
    • There is a maximum of 10 custom fields for a map type in general, but honestly over 6 is a bad idea just from the standpoint of confusion.
  • Additionally, on the map tab, it now shows the default option in yellow with (Default) behind it when it is the default. This makes it way easier to know what the default is without having to hunt around.
  • When you change your map type in the lobby, it now resets any custom options to the defaults rather than keeping the arbitrary offsets related to the prior settings.

New Map Type Options

  • The Bubbles map type, originally by Draco18s, now also supports a new "number of planets per bubble" field, which generates wildly new kinds of maps depending on what you select.
  • The Clusters Microcosm map type now allows you to edit the spacing and radius of the clusters, which gives you various different effects.
  • The Concentric map now has a new "Extra Rings" option, which lets you make it more dense than usual if you wish.
  • The Spiral Snake map type has been deprecated (though old saves with it will work fine). This was always just a variant of Concentric.
    • There is now a new "Spiral Snake?" option under Concentric, which lets you turn it straight back into Spiral Snake, but with whatever other Concentric options you wish to use also applied.
  • There is a new "Random Extra Connections" that defaults to ten on Concentric. You can choose as few as 0 or as many as 30.
    • This helps really change up the dynamics of these maps, making them more connected in various interesting ways.
  • Both Clusters and Clusters Microcosm now also support the "Random Extra Connections" custom field, with the default number of additions on these now being 5. These can range from 0 to 30, though, at the player's choice as well.
  • The "Random Extra Connections" is now also supported by the Bubbles map, which kind of makes it a bit crazy. So it defaults to having no extra connections at all, but it supports up to 30.
  • Now that we can actually set defaults other than the first item in the list for map custom options, we're definitely going to choose the best default experience for each type!
    • The default type for the clusters map type is now Fractured rather than Large.
    • The default type for the Simple map type is now Dreamcatcher rather than Simple.
    • The default center for Compass (ZO) is now Large rather than Small, and the default connections per ring is 2 rather than 1.
    • The default for Maze is now Maze D (Angles, Extra Links) rather than Maze A (Straight).
  • The Grid and Maze map types now support extra connections as well. Grid defaults to having 30 extra connections, while Maze defaults to having none.
  • The honeycomb map now has a new Solar Snake option that was coded by Keith long ago.
    • This is another ultra-hard super-unbalanced option, and it is labeled as such. But it is interesting, so why not.
  • The honeycomb map now has a new "Dissonance" option, which lets it start coming apart more or less, in some quite intereseting ways.
    • The default for this is now the new "A Bit Extra" rather than the old (only style) of "Normal." This produces more varied and interesting maps without going too crazy.
  • "Random Extra Connections" is now also supported on the honeycomb map, and this combined with solar snake actually is a playable map.
  • The Linked Rings map, originally by Draco18s, type was frequently generating fewer planets than requested, by a fairly large degree (often 10% too low). This is adjusted to now fill in with extra satellite planets.
    • Actually, this is now controlled by a new "Extra Satellites To Hit Target?" option, which defaults to on. So you can turn that off if you prefer.
  • The Octopus map, originally by tadrinth with some help from Badger, has been updated to support more numbers of arms in between two and eight. The default is also now four arms.
  • The X map now does a better job of not having too many planets (when you ask for 80, getting 100).
    • The X map also now supports "Random Extra Connections", and defaults to now having 2.
    • Some adjustments to X have been made that make it now more symmetric while trying to not pass the target planet count. This means it generally gives you 73 planets when you ask for 80.
      • There is thus a new "Extra Satellites To Hit Target?" option that defaults to on which also adds extra clumps of planets to get you back up to your target.

Bugfixes

  • Fixed a bug in the last couple of versions where the "most recent lobby settings" were not saving in a way that they could be reloaded.
  • Fixed a bug that could happen in rare seeds on the Encapsulated map type with it not always being a fully-connected map. It now runs the process that fixes that, as do a ton of other map types now just in case.
    • Thanks to Vrishnak92™ for reporting.

Mod Updates

  • AMU:
    • The SetEntityPath() method now accepts an optional PathingMode.
    • Created 2 new game commands:
      • GameCommand_AllAttackTarget will make all units attack the target. If the units need to move to the target's planet first, they will do so, but there is no guarantee that the target will still be there once they arrive, or mechanism to redirect the units again.
      • GameCommand_AllClearBehavior will make all units clear their current orders. It can be specified whether that includes decollisions or not.
        • This is both used for the upcoming Devourer Chrysalis mod.
    • Also simplified the GameCommand_MoveAllToPlanet code slightly.
    • The Spire Great Shield Emitter and Zenith Architrave Spawner (NOT home warp point!) are now in the NastyCriminallyUnvervaluedStructuresToAvoidRollup instead of the NastyStructuresToAbsolutelyAvoidRollup. This means that Kaizers Marauders will no longer absolutely avoid planets with these on, and should fix Marauders not openly engaging with the Zenith Architrave on their worlds.

3.203 More Bugfixing

(Released June 18th, 2021)

Bugfixes

  • The way that map generation secondary options are defined in code and xml is now VASTLY simpler and cleaner.
    • This solves a number of things that made it difficult for modders to make maps, or for us to alter maps cleanly. It also makes it easier to find and correct errors.
  • Fixed a longstanding issue where if you changed a secondary option on a map within 5 seconds of just having regenerated the map, it would not update with the new map result.
    • This was notably confusing if you were cycling through different linking flavors or similar, since sometimes it would not respond to actually show you how it was different.
  • Fixed the balance_distance_after_which_ships_will_not_chase_targets being only 280k (with default 80% range resulting in 224k, enough to cover the gravity well but only if a ship is in the middle). Increased it to 610k (with default 80% range resulting in 488k, plenty range to cover even the biggest gravity wells from the edge of the system).
    • This should fix a lot of ships behaving like snipers, never moving into the shortest weapon's attack range when should.
    • Thanks to NR SirLimbo for fixing.
  • Further fix to the "Client_SendAnyFullSyncRequestsToTheHost" error in MP.
    • Thanks to Peons and HossPorkchops for reporting.

Mod Updates

  • Starting Fleet designs (both versions) updated to have the new style of UI prefixing.
  • AMU:
    • Added a new function: Starter Fleet AIP Balance in the advanced Galaxy Settings in the AIP Balance section.
    • Some modded starter fleets may have centerpieces or fleet lines that cost AIP when claimed and/or hacked. This function provides AIP at the start of the game equivalent to the AIP cost of the starter fleets players have.

3.202 General Bugfixing

(Released June 17th, 2021)

  • For the galaxy options window (but not faction options at the moment), we've added:
    • default_value_if_below_campaign_harshness_but_not_sandbox="somenumber" for bool and int fields.
    • default_option_if_below_campaign_harshness_but_not_sandbox for string and table fields.
    • This is useful if we want to have the defaults of something be... something different on Humanity Ascendant and down, but still let them make choices. As one example.
    • This MUST be combined with still_allow_editing_below_min_campaign_harshness="true", which is also new and a part of this same thing.
  • For Humanity Ascendant and downward, Compact is now the universal standard for all planet sizes except for the Dark Zenith (which are set to be Cramped).
    • However, players can still change this around. When you move to Challenger or higher, the defaults change to something more varied. So far there is no standard being enforced on Expert or Deathwish.
    • Thanks to Strategic Sage for suggesting.
  • You can now see your economic mode (centralized or distributed) in the escape menu directly.

Bugfixes

  • Fixed a number of tooltips that were missing information in the lobby because we internally now have a centralized GetDescription() method and no longer use the (older, less efficient, and worse in a bunch of ways) GetTooltipString() method.
    • This has now been corrected for all of the core game tables that were affected, like AI types, AI difficulties, and things of that nature.
    • It's worth noting that any mods that used to add to their tooltip by GetTooltipString() should now do so via GetDescription(). However, don't include a header line or you'll get that doubled.
    • Thanks to Darkshade for reporting this absence.
  • Fixed a bug with distributed economy mode that was causing it to go back (mostly -- except for which asteroid types had been seeded) to centralized economy after loading a savegame.
    • Additionally, this mode was not working properly on the visuals of MP clients until now.
    • Thanks to DEMOCRACY_DEMOCRACY for reporting.
  • Coil beam math is tricky! Reworked and simplified some of the beam weapon calculations in a couple of ways:
    • First, if these things would hit everything in a line, but hit nothing, then assume we still hit the target (it likely is just at the outer range, but we wouldn't have shot if a different form of calculation had not already declared it in range). I'm not aware of this actually impacting anyone, but it was a distinct possibility.
    • Secondly, if these beam weapons that normally hit multiple targets only hit one (and that one is the intended target), then just have it use a bit simpler math to save time.
    • Thirdly, if these beam weapons hit 1+ targets beyond the primary target, then make SURE that the primary target is the first one hit, so that it gets its share of damage if it should.
      • The older logic for this part was a lot more complicated and not as effective (and could have led to you doing 10% more damage than intended to a line hitting 20 targets of which 10 could share damage, for instance. Although that over-damage effect would only have kicked in if the older math actually worked, which it did not. In practice, this means it will definitely actually hit the target, instead.
      • Fourth, fixed an issue with secondary targets taking less (or more) damage than their primary. Not sure if any beams were using that, but if so then there was a multiplier that was causing this damage to be amplified 100x too much. So for example if you had configured a beam weapon to deal normal damage to the primary target, and 14% of the normal value to each target it hits along the way, it would actually have done 1400% damage instead of 14%. Ouch.
    • Thanks to many players reporting spire coil beams not being able to hit certain stationary targets, including Sergie, Lord Of Nothing, Ithuriel0, and Zweihand.
  • If you are on the galaxy map and giving ships orders between planets (say, a group of ships from planet A to planet B, and they are all on planet A right now), then previously if you were to give a conflicting order to the planet they are already on (hey you ships on planet A, go to planet A), then they would just ignore those orders and keep going to planet B.
    • Now, in the even that these ships are planning to leave the planet, all of their orders get cleared. So the example ships above would stop doing anything and stay on planet A.
    • There's a third category of ships -- those on planet A, but that were never planning on leaving planet A in the first place, and which you told to do something else, like shoot some guy. These ships will carry on shooting the guy, because they are both already on the planet you said, and have no travel orders to go elsewhere, so they may as well disregard what you said since it has no meaning.
      • The fourth sub-category of ships who have some other orders and THEN a move order (hey you ships on planet A: shoot that guy, then go to planet B) WILL have all their orders cleared, including the non-travel-related ones, when you order them to the planet they are already one. This seems excessively niche.
    • In testing, this now works as one would respect, is the TLDR.
    • Thanks to Ecthelon for suggesting.

Multiplayer Fixes

  • Fixed what seems to be an old MP error finding new expression in some cases now when ghosts are being killed. Essentially it wasn't being triggered before because we weren't finding the ghosts properly, but now it's being triggered because we are. But only if you have ghosts in the first place, which I still can't directly replicate, but at any rate this does seem to suggest that the fix for finding ghosts is at least working better.
    • At any rate, this was basically a UltraEfficientStyle for a list of unit IDs using a prior value from what the server had just told the client about, rather than the client recalculating its own format that is sure to fit all the entities it wants to ask the server about. This would thrown an exception that included "ClientSidePKIDMismatch" in the name,
      • Actually, long ago, this was probably correct logic. We could only ask the server about things it just told us about, so reusing that UltraEfficientStyle rather than recalculating it was... fine. Not a bug, but probably not optimal, although you could actually make a case for it being somewhat optimal. Anyhow, now that the client can ask questions wholly unrelated to what the server just told them about -- aka about ghosts -- the client needs to calculate this for themselves.
    • I just ran a multiplayer session fine, but this doesn't mean much since it is only affecting a subset of players in the first place, or only on certain conditions, or after time, etc. The fix should be good, but it's hard to be positive just yet.
    • Thanks to Peons and HossPorkchops for reporting.

3.201 Location Hotfix

(Released June 17th, 2021)

  • Fixed two deserialization bugs introduced last build with the new variable-size gravity wells. These only affected existing savegames (versus new games or saves from new games), and so long as you didn't save over an existing save from an older build, they'll now load properly again.
    • First bug was everything loading in completely randomized in each grav well from older saves. Well, this is inspiring a new AI type sometime in the future, at least.
    • Second bug was engineers and a few other units wanting to run off to the bottom left of the map.
    • Thanks to Ecthelon, emabrad, Bob, Mr W, ElOhTeeBee, easytarget, and Strategic Sage for reporting.
  • The Dark Zenith tooltip now properly says that it default to Cramped rather than saying Grand, which is outdated info.
    • Thanks to Ecthelon for reporting.
  • This is not tested yet, but hitting Reset to Defaults should no longer disconnect clients in the multiplayer lobby.
  • When you use Reset to Defaults in the lobby, it now adjusts you to be on the Map tab if you were not there, or on the Factions tab if you were on the Map tab.
    • This way any stale data that might be cached will be reset no matter what.
    • As a side benefit, this also makes it more obvious that something happened if you are hitting this serially.
    • Thanks to Ecthelon for reporting some stale data.

Mod Updates

  • cml: Updated AIShieldGenerators mod to account for new GetSafePlacementPoint methods.
  • SirLimbo: AMU:
    • Fixed some leftover debugging code producing messages about AI hunter fireteams with destroyed but not null targets being in that state for over 120 seconds.

3.200 Variable Planet Gravity Well Scales And QoL

(Released June 16th, 2021)

Variable Gravity Well Sizes

  • Combat coordinates can now be stored between -262,136 and +262,136, which gives us a larger range in which to work. This costs an extra 3 bits per coordinate part, or 6 bits per coordinate pair. The base number being stored was previously a pair of 15bit integers, but now they are being stored as 18bit integers.
    • Overall this won't make savegames that much larger, but it does allow for us to have genuinely larger gravity wells without having to try to fake it and then math down all the movement speeds or whatever (THAT would have been very very slow by comparison in terms of CPU usage during gameplay).
  • The internal CombatCenter value has been changed from 200k to 400k.
    • This again does not impact accuracy, and also does not impact savegame size since this is subtracted out before units are saved, anyhow.
    • However, what this does is allow for gravity wells with the full 262,136 radius, quite comfortably, if we want to have something that stupidly large. Before the limit was going to be 99,999 even with the new data format. Which is probably plenty big, but why artificially limit things?
  • There are now "Planet Grav-Well Schemas" as a concept, which define the randomized (or not) assignment of gravity well sizes to planets. The ones defined so far are:
    • Chaotic Random:
      • Gravity wells will be completely randomized from the full range of 10k sU to 200k sU. This is extremely chaotic, so not something you'd usually want to do.
    • Random With Extremes
      • Gravity wells will be completely randomized from the full range of 10k sU to 200k sU, but those extremes will be quite rare.
    • Colossal
      • All gravity wells are 200k sU in radius. This is large to the point that sniper shots might dissipate before even reaching their destination. Travel times are extreme, and battles are likely to be protracted.
    • Vast
      • All gravity wells are 127k sU in radius. This is so large that you may need to play on accelerated timing. No battle can remotely cover the entire battlefield, and snipers are all but gods. Travel times are very, very long.
    • Reasonable Random
      • Gravity wells will be range from 18k sU to 74k sU, with most being somewhere more in the middle.
    • Grand
      • All gravity wells are 74k sU in radius. This is very, very large. Battles have a ton of room for maneuvering, and snipers are going to be overly power. Travel times are extended, and forget about getting full turret coverage of wormholes.
    • Extensive
      • All gravity wells are 52k sU in radius. This is quite large. Battles have a lot of room for maneuvering, and snipers are going to be overly powerful. Travel times are high, and turret coverage of wormholes will be problematic at times.
    • Spacious
      • All gravity wells are 38k sU in radius. This is large enough that travel times are increased a bit, and it's harder to cover a high number of wormholes. Battles have more room for maneuvering, but travel times are not too bad yet.
    • Modest
      • All gravity wells are 32k sU in radius. This is still small enough that a group of turrets can often cover several wormholes. Travel time within the system is a bit larger, but still quite quick.
    • Compact (Legacy)
      • The classic gravity well size that was used in AI War 2 for all planets until June 2021. It can get a bit claustrophobic.
      • All gravity wells are 26k sU in radius. This is small enough that a group of turrets can often cover 2-3 wormholes. Travel time within the system is minimal, for better or worse.
    • Cramped
      • All gravity wells are 18k sU in radius. This is small enough that a group of turrets can probably cover the entire gravity well. Travel time within the system is very low, and it is hard to isolate plabets.
    • Miniscule
      • All gravity wells are 10k sU in radius. This is so tiny that any enemies on the planet are pretty much in range of one another as soon as they arrive.
  • The very helpful method GetSafePlacementPoint() was being used in several different ways, and especially with planet-specific gravity well sizes, we now had to define this differently:
    • GetSafePlacementPointAroundPlanetCenter() is the most common, and uses the size of the gravity well to put something somewhere in the gravity well.
    • GetSafePlacementPoint_SpecificPoint() is rare, and is used to put something pretty close to a specific target point, with explicit distance ranges that it can be around that.
      • These ranges are usually calculated from the radius of ships, or things of that nature. It shouldn't have anything to do with current or former grav well sizes.
    • GetSafePlacementPoint_AroundDesiredPointVicinity() is also rare, and is used to put sometihng pretty close to a specific target point, but with some wiggle room that is defined as FInt percentage of the OLD fixed grav well size.
    • GetSafePlacementPoint_AroundEntity() is very common, and is used to put sometihng pretty close to a specific target entity (unit or wormhole), but with some wiggle room that is defined as FInt percentage of the OLD fixed grav well size.
    • Using the above, fixed the following issues (as well as generally prevented ourselves from introducing any new ones):
      • Fixed a bug where Dark Zenith defensive structures were often seeding much further away than was desirable from the things they were to defend.
  • There is a new "Planet Grav-Well Sizes" section in the MapGen section of galaxy options.
    • Human Homeworld Planet Grav Well Size
      • Choose how large (and/or variable) home homeworlds are. Too large can make the game overly easy, and too small can make the game overly hard. Defaults to Modest.
    • General Planet Grav Well Size
      • Choose how large (and/or variable) the bulk of planets out in the galaxy are. Defaults to Reasonable Random.
    • AI Bastion Planet Grav Well Size
      • Choose how large (and/or variable) AI Bastion worlds are. Too large can make the game overly easy, and very small can make the game close to impossible. Defaults to Modest.
    • AI Homeworld Planet Grav Well Size
      • Choose how large (and/or variable) AI Homeworlds are. Too large can make the game overly easy, and very small can make the game close to impossible. Defaults to Modest.
    • Dark Zenith Planet Grav Well Size (if you have DLC2 installed)
      • Choose how large (and/or variable) Dark Zenith world are, if the Dark Zenith are to be used in this game. These are meant to be pretty large and imposing. Defaults to Grand.
  • In-game, the gravity well sizes are now shown as the diameter, not the radius, as this is easier to keep track of.
  • In-game, it now shows you the gravity well size of each planet on the planet tooltip.
  • LODs in the game are now calculated properly based on the scale of the planet gravity well. Mostly this doesn't matter much (better performance in a distant sense on super huge planets), but it prevents some units from being oddly under-detailed on very SMALL planets (since the apparent size of ships is larger than the LODs would normally account for).
    • The LOD details that can be shown in tooltips now show this information as well as what nonstandard values are being used if there are any in use.
    • The test chamber is also now forced to always use the old standard gravity well size, as that's where we typically will set up art LODs and we need it to be on a consistent basis for everything else to multiply or divide from.
  • The planets in the background now scale up or down in size based on the apparent scale of the gravity well, like everything else. This helps to ground the size of the scene a lot. The asteroids are the same in any event, and the nebulas are infinitely far away so of course have no change in perspective. But this essentially completes the grav well transformation.
  • The Dark Zenith planets now default to Cramped rather than Grand, because this actually is a lot harder (for players going in there), and more imposing and scary in general.

QoL

  • Added a new debug option in settings under tooltip additions: Show Entity Location Coordinates
    • Mainly for debugging, but shows the coordinates for any entity you hover over. Note that the center of a gravity well is normally 400k by 400k, but we are offsetting that to 0,0 for this display.
  • In the settings menu, and settings that you have put to something other than the defaults now shows with yellow name text to make sure it is more obvious.
    • Additionally, if you have altered an advanced field, but the advanced field is not on, then it will show you that despite it normally being hidden in advanced.
    • This now also works in the Galaxy Options page.
      • In addition on that page, if any options are locked down to specific options because of the game mode, those now show with the text (ALTERED BY CAMPAIGN MODE) under them.
    • This same coloration pattern is now applied to faction options, to be more clear what is happening with their various options.
  • In the escape menu, it now shows if your achievements are on, or if they've been disabled in that campaign because of either sandbox mode or cheats used.
  • In the mod and expansion tabs in settings, there is now a whole lot more color being used. Each mod or expansion's color and abbreviation is introduced here and used consistently.
    • The colors for all of the expansions have been updated to be prettier.
    • The mod tab shows the author of each mod next to its name and abbreviation, now. This seems like important information to really have prominent, both for purposes of credit but also for players to get a sense of who is doing things they like and thus what they might want to try more of.
    • All of the mods that are distributed with the game has been updated to include author names, colors, and abbreviations.
      • The abbreviations and colors were not chosen by the mod authors in question, so those may change in the future. But this is a good start.
  • If settings or galaxy option categories are added by a mod or expansion, or if their actual settings or options themselves are added, then they now have a little tiny second line with the color and indicator showing where it came from.
    • Same with actual settings themselves. The tooltips then have the colored full name (and abbreviation) specifying what the mod or expansion was, and who the mod author was if it's a mod.
    • This makes it DRAMATICALLY easier to tell when something is official content or something from a mod, which lets you make informed decisions.
  • The galaxy options tab now has proper tooltips for any items in sub-lists. This wasn't really used prior to the gravity well size schemas.
    • Same for the factions tab, etc.
    • This means you can now see which starting fleets or battlestation setups or whatnot came from which expansion or mod.
    • It's so easy to not realize just how much of the battlestation designs come from TSR (DLC1), by the way.
  • You can now see what mods or expansions factions came from, when you are in the process of adding factions.
  • The list of factions in the factions tab now shows what mods or DLC they came from in their tooltips and with small letters on the second line.
  • Quickstarts now show what DLC or mod they are from, which is one of those things that people were really frequently asking us!
    • For instance, it is vastly clearer now why there is a Helping Hands 2. It's from TSR and has differnet options.
  • Last expansion/mod related display item for now: The actual units having a little note about it as their very last thing.
    • Once again one of those things where people undervalue DLC1's turrets, as one example. If you don't memorize the store page, how are you supposed to know?
  • New "Metal Harvester Counts" galaxy map mode for the non-distributed economy. (The asteroid counts are already there for the distributed economy).
    • Shows which planets are more valuable in terms of how many Metal Harvester spots are present. More metal harvesters means more metal income regardless of what kind of command station you put there. Six is considered the average baseline count for metal harvester counts at a planet. Shows the same icons as the Normal view.
  • New "Gravity Well Sizes" galaxy map mode.
    • Shows which planets are larger or smaller in terms of buildable space. Larger planets are easier to defend and harder to attack... unless you have snipers. Small planets are very hard to defend, but also very hard to attack if the enemy outnumbers you enough. It's realy the combination of size plus other factors that leads to the end result.

Balance

  • Buffed Micro Concussive Missile Turret (DLC1) base damage from 300 to 425 per shot.
    • Note that as this turret fires salvos of 8 shots this is actually a bump from 2,400 to 3,400 base damage per salvo at Mark 1.

Bugfixes

  • Hacking an ARS for a ship line should trigger the achievement again
    • Reported by a lot of people, most recently soulcandy on steam
  • Fixed "Zombify Everything" to no longer be forced on in Expert mode. It was supposed to be forced off. This will affect existing Expert games.
    • Thanks to Crabby for reporting.
  • Fixed "Strikecraft Attack Power" to be 1.5x properly on Expert, whereas previously it was accidentally forced to 1x. This will affect existing Expert games.
    • Same thing with "Strikecraft Hull And Shields" needing to be 2x instead of 1x.
    • Thanks to Smidlee for reporting.
  • Fixed an error in the new "Seed AI Civil War Triggers" field that was causing that to actually turn on the civil war when it was on. This was very much nonideal. It was essentially a copy-paste error.
    • Thanks to Misfit, Vadatajs, Fire Woven, Timerlane, Crabby, and Chuito12 for reporting.
  • Fixed what looks to be a longstanding issue (but it's hard to be sure) where fleet lines with an effective cap of 0 would be shown in the "ships you have" lists, for things like C-clicking a tech.
    • This was happening more often recently because of changes to add empty fleet memberships for purposes of the "fake entity" that we use in drawing the improved tooltips (that's a long story), but the core of the issue was not all that new.
    • Thanks to UFO for reporting.
  • Fix a regression from the Asteroid Count Assignment Logic code that wouldn't actually set the asteroid count on planets created after the start of the game. This was causing the DZ planets to not have any metal harvesters, crippling the DZ economy.
    • Thanks to Democracy for reporting
  • Added some extra hardening against cross-threading exceptions in various parts of the vis layer.
  • Fixed an exception that could happen in various settings windows if you had multiple subcategories with the same number of hidden rows in them.

Multiplayer Ghost Hunting

  • Made some dramatic simplifications to the ghost check code on MP clients, which was not seeming to work. The new approach should work consistently, is easier-to-follow code, and hopefully will be the end of the ghost problem. Fingers crossed.
    • Thanks to Badger and a variety of others for reporting, and giving ideas on where the problem might be.

Mod Updates

  • Update for CRZGatecrcuhser's Reprocessors mod. it now works again.
  • Updated the civilian industries mod to be compatible with the latest code updates.
  • A new "ModDetails.txt" is now supported for mods. This should have multiple lines with various things in them.
    • Line 1 should be the nice display name.
    • Line 2 should be the author of the mod.
    • Line 3 should be the abbreviation (3-4 letters max).
    • Line 4 should be the hex color code for the mod, without a # (pound sign).
  • There is a new BuildAcronymByCapitalization() that will auto-create acronyms for mods if the above file is not specified.
    • Additionally, "ffd48a" is used as the color for any mod missing the above file.
    • And finally, the nice display names for mods will continue to be created for any mods that don't have the above.
  • An abbreviation text field is now provided for expansions as well, in their xml.
  • Normally when a faction is edited by a mod or expansion with a partial record, we don't consider that faction to now "be from that mod or expansion." This makes sense, because a lot of times the partial record only exists so some new sub-data (which will be marked as being from a mod or expansion) can be added.
    • There is now a expansion_or_mod_status_overridden="1" that is in place so that you can override this from a mod or expansion.
    • This can be used by any type of xml element that is being altered substantially enough that you want to flag it. Right now it's being used for the Kaizer's Marauders faction, which otherwise would show up as a base game feature (since they are a substantial re-edit and replacement of a base game faction).
  • For the first time, it is now possible to have new quickstarts defined in mods!
    • Simply place them in the "QuickStarts2/" folder inside the mod folder like what you see with the expansions.

3.104 Option For A Distributed Economy

(Released June 11th, 2021)

Balance

  • Ship hull techs were too expensive previously to be attractive in a lot of scenarios. They also varied in cost by the type of human hull tech. These have been standardized more, to make them more attractive.
    • Light Hull went from 7k/10k to 4k/6k.
    • Medium Hull went from 5k/8k to 4k/6k.
    • Heavy Hull went from 7k/10k to 4k/6k.
    • On the flip side, the turret hull is stupidly inexpensive given it affects potentially half of your units for just a single tech.
      • Turret Hull went from 3.5k/7.5k to 5k/9k.
    • Thanks to Strategic Sage for suggesting.
  • Player ships can no longer be dragged into unexplored planets by enemy tractor beams. This was allowing for extra scouting by virtue of enemy tractor beams.
  • Outguard fixes
    • Fixed several of the vanilla Outguard that didn't have the right tech and/or starting mark
    • Adjusted AIP costs of several DLC2 to be more in line with the others.
    • Hades Mirages now use expatriate tech and start at mark 2
    • Ragnar's Breachers now have the standard expatriate tech and start at mark 2 like the others
  • DZ Javelin have strength_multiplier="0.05" so they don't totally skew strength
  • Replaced Void's (made by Voidpiercer Cruiser) previous invulnerability feature with immune_to_all_damage="true"
    • I think this should fix this particular issue, but need more feedback for these edge cases with electroxic

Idle Transport Bonuses

  • The "idling transport" boost to economy used to stack, so if you had 5 unused transports you could put them all on one highly-economic planet and thus reap way too huge a benefit. It's the sort of thing that is impossible to balance when you start getting multiplicative like that.
    • Now the idling transport bonuses will only pick the highest bonus for each metal and energy at a given planet. So if you stack 5 idle transports on your best economic planet, that's now a waste. Instead you should spread them around your 5 best economic planets.
    • Advanced players note that this has some added benefits to being able to fleet-shift units around if there is desperation, as well as being able to use these transports more actively as bait.
    • Thanks to CRCGamer for suggesting this new restriction.

"Pinned" Command Stations

  • The game now remembers MostRecentPlayerNonHomCommandStationType on each planet, which is the most recent type of command station that existed, in human hands, on a given planet.
    • This is useful for a variety of things, and it's data that is not erased when you scrap a command station, or when it dies, etc.
  • The game now has an IsWaveIncoming bool on planets, which is really useful to be able to check without being in the external code area.
  • Player planets now get "pinned" when there is a wave incoming at them, or when there is at least 1 enemy strength on the planet at this time.
    • When a player planet is pinned, you cannot switch what kind of command station is build there.
    • You can still scrap your command station (to avoid aggro, or to move its position by rebuilding it if you want), but you cannot build any other type other than the type you just scrapped.
    • Once the planet is no longer under assault, then you can swap the command station type again.
    • This basically prevents some command station juggling exploits where folks would run a suboptimal command station type for a planet until it was under attack, then switch to something for better defense. Or where they would bait in enemies with a weak command station and then switch it up during the middle of the attack. You have to actually commit to your choices at least a bit now.
    • Since this is something that really only affects some edge cases and exploity type behavior, we're just making this a part of the main game itself. It's not limited to Expert mode or above. It seems highly unlikely to negatively affect anyone playing Humanity Ascendant.
    • Thanks to Strategic Sage, CRCGamer, and others for inspiring this change.

Campaign Type Work

  • On Deathwish and all other campaign types, it now leaves the options alone for the Nanocaust allegiances.
    • If you want to have 5 allied nanocaust, go for it. We'll assume you know what you're doing. That sort of limitation is not what Expert or Deathwish or similar are supposed to be about.
    • The actual feature that allows for this is still useful for things that are balance-style configuration on the player, or purely meant for sandbox mode.
  • If you're playing in sandbox mode, achievements are now properly blocked.
  • "Experimental: Ally with AI" has been renamed to "Sandbox: Ally with AI"
  • "Sandbox: AI Civil War" has been renamed to "Chaos: AI Civil War", and has been moved from the Sandbox subcategory of AI Behavior to instead be in the Advanced Dangers section.
    • This is now allowable as an option all the way up through Challenger, and is forced off only on Expert and up.
    • Thanks to Strategic Sage, Atomikkrab, and Ovalcircle for weighing in on this feature and how it should be classified based on how people currently use it.
  • New Scouting option, under Fog of War: Revealing Map Details Is Considered Cheating
    • Information management is a big part of this game, and if you reveal the entire map from the start, you get flooded with information overload. Also it makes certain things a bit too easy to plan.
    • If you go a step further, and set all the planets to Watched, then you can see all enemy movements all the time, which completely negates any need for Spies and other core mechanics like how Logistical command stations can watch a large area around them.
    • For most people, therefore, using those sorts of tools is clearly a cheat that circumvents a nontrivial part of the game. On the other hand, there is a subset of players who simply prefers to focus on other things in the game, and who view this as a lifestyle choice: they get up to plenty-complicated games without this on.
    • Below the Expert campaign type, we thus leave it to you to decide if you feel like this is a cheat or not for your purposes (that mainly impacts ability to get achievements). On Expert and above, you'll have to manage your intel fully.
    • This has been a perpetual thorn in Chris's side for a long time, so being able to have this fully demarcated now is a really nice thing. It now defaults to thinking of it as a cheat, whereas before it always called it a lifestyle choice.
  • Under Mapgen, Extra Seeded Items, there is a new option: Seed AI Civil War Triggers
    • Defaults to seeding them. If there are multiple AI factions, and you find and destroy one of these triggers, then all of the AIs will change.
    • Note that, until now, Communication Nodes (the triggers) have been seeded in EVERY game with multiple AIs, no matter what.
    • We're leaving that as the default behavior up through Challenger (hey, it's a nice way to discover a new game mode), but then barring these as an option at all on Expert and up.
    • Thanks to Ovalcircle for the reminder that these needed to be gated.
  • Added a new setting to Balance -> Human Balance: Humans Can Tractor Enemies Through Wormholes
    • Defaults to on. Normally if you have an enemy in your tractor beams, you can drag them through wormholes. And the enemy can do the same to you. If this setting is disabled, then your ships will drop their prey when they transit wormholes.
    • This is mainly something specific to quite advanced play, where some clever players were able to set up 'Reverse Beachheading' in a bit of an exploitative fashion.
    • This is forced to Off on Deathwish. It's an option to turn it off on any mode lower than deathwish, and defaults to On on them.
    • For most modes, let's see how some of the other changes shake out before we really figure out how "overly powerful" (which is subjective and tricky to pin down) strategies fare. If we introduce some cool new things that are more effective than reverse beachheading, then it falls out of use and isn't even a problem worth trying to balance. We'll see what happens.
    • Thanks to Strategic Sage for suggesting.

Optional Tech Cost Overrides

  • Added a new cost_override sub-node that can be added to tech upgrades. This lets you entirely replace the costs of tech upgrades, or even the number of times a tech can be upgraded.
    • This is something that is meant to be used sparingly, but it's a nice new pattern for xml swap-ins in general, and really has a ton of flexibiltiy to it.
    • As far as the core purpose of this specific one goes, it really should be used super sparingly because we are not trying to diverge the game modes that much.
    • That said, the current thinking is that things like Battlestations may be quite a bit too cheap to upgrade for purposes of the high-level meta. That's a pretty specific subset of the game, mostly centered around beachheading being a bit OP at the moment in the top meta. We don't want to nerf this for everyone, though.
    • This also has an optional atribute of only_applies_if_setting_is_on, which lets this sort of thing be optional based on a setting (which, yeah, that's a good idea when you want to communicate that it can happen, versus it just being invisibly part of the new mode).
    • One example sub-node looks like this: <cost_override min_campaign_harshness_to_apply="0" max_campaign_harshness_to_apply="9999" only_applies_if_setting_is_on="BattlestationDirectUpgradesCostMore" science_cost_per_time_unlocked="1000,2000,3000,3500,3500,3500"/>
  • Added a new "Battlestation Direct Upgrades Cost More" galaxy option to the Human Balance subsection.
    • This is dynamically tied in with a custom cost structure for both the citadel and battlestation direct upgrades.
    • The costs (for now) move from: 500,1500,2000,2500,2500,3000
      • To: 1000,2000,3000,3500,3500,3500
    • This cost adjustment is a wild guess, so please feel free to tune it, those with source access who are also expert players. Right now it's more about the core feature being possible and you folks being able to test what feels correct.
    • This new option can be on in any mode, from sandbox on up through HA. However, it starts being forced on at Expert.

Distributed Economy Mode

  • New galaxy option in the Balance -> Human Balance section: Humans: Use Distributed Resource Generation Mode.
    • This is not flagged as an advanced option, because we want this highly visible for anyone who wants to use it. It's an option up until Expert mode, where it is forced on.
    • This is a feature with HUGE impact on the overall flow of the game. It's required for Expert mode and up, but you can use it at any level.
    • In this mode, your Metal Harvesters become Asteroid Mining Powerplants. The bulk of your metal and energy will be generated via this mines, rather than your central command stations. However, what kind of command station you choose will either give bonuses or penalties to asteroid mines.
    • A lot of fairly straightforward things happen as a result of this, but it makes the game more complex (and interesting). High-asteroid planets are worth far more to your economy than low-asteroid ones. Economic command stations suddenly aren't easy to just stick anywhere for maximum effect.
    • And perhaps most notably, the AI has a number of places at which to attack your economy now, on every planet. The Metal Harvesters have a very low priority for the AI, because they are rebuilt quickly and you lose little from them being down. Asteroid Mining Powerplants are slower and more expensive to rebuild, and can put a strain on your metal or energy generation while they are gone. This gives the AI way more chances to be clever.
  • The existing Metal Harvester unit has been updated with the following description to help explain it better:
    • Metal-rich asteroid with attached mine and refinery. Low stakes to defend, as they can be rebuilt quickly and cheaply and are a small-ish part of your economy.
  • Added a new "Asteroid Mining Powerplant" unit, with the following description:
    • Metal-rich asteroid with attached mine and refinery, plus an onboard energy powerplant. High stakes to defend, as these are expensive and slow to rebuild, as well as being the bulk of your economic output on a planet. The type of command station you place on a planet has an enormous impact on how much each of these asteroids generates for you.
    • These are basically a Metal Harvester, but with the following differences:
      • Each one generates 14k energy, with an extra 6k energy per mark level.
      • Each one generates 50 metal per second, with an extra 20 metal per mark level. Before it was 75 and 50.
      • They have hull points of 9k now, rather than 75k. (For reference, hull points of an econ command station is 7.5k).
      • They have shield points of 6k now, rather than 0. (For reference, shield points of an econ command station is 20k).
      • These now have a metal cost of 50k (which affects rebuild costs), as well as a claim cost of 50k. The metal harvesters originally only cost 40k metal to claim, and nothing to repair. Econ command stations cost 45k to build, for reference.
      • The enemy priority for killing these is now very high, since it will affect players a lot more.
    • These are only seeded in the new "Distributed Resource Generation Mode" that is a more interesting/challenging toggle for players to use.
  • In "Distributed Resource Generation Mode", the following changes are made to metal production from various command stations:
    • Home are down from 2200 metal per second, plus 400 per mark level, to:
      • 800/s direct metal, plus 100 per mark level. Plus 6x multiplier to output of Asteroid Mines in the system.
    • Economic are down from 400 metal per second, plus 220 per mark level, to:
      • 150/s direct metal, plus 75 per mark level. Plus 3x multiplier to output of Asteroid Mines in the system.
    • Logi are up from 90 metal per second, plus 50 per mark level, to:
      • 140/s direct metal, plus 70 per mark level. Plus 1.5x multiplier to output of Asteroid Mines in the system.
    • Mil are up from 50 metal per second, plus 20 per mark level, to:
      • 130/s direct metal, plus 60 per mark level. No extra output of Asteroid Mines in the system.
  • In "Distributed Resource Generation Mode", the following changes are made to energy production from various command stations:
    • Home are down from 350k, plus 25k per mark level, to:
      • 150k direct energy, plus 10k per mark level. Plus 2x multiplier to output of Asteroid Mines in the system.
    • Economic are down from 500k, plus 180k per mark level, to:
      • 300k direct energy, plus 100k per mark level. Plus 4x multiplier to output of Asteroid Mines in the system.
    • Logi are down from 175k, plus 50k per mark level, to:
      • 80k direct energy, plus 25k per mark level. Ouch, though. Asteroid Mines only get 0.6x of their normal output in this system.
    • Mil are up from 70k, plus 10k per mark level, to:
      • 70k direct energy, plus 10k per mark level. Ouch, though. Asteroid Mines only get 0.25x of their normal output in this system.
  • Thanks to CRCGamer for suggesting that on the more advanced mode, Logi stations should have about 70% of the energy output as previous.

Viewing Asteroid Counts Per Planet

  • Added a new "Asteroid Counts" galaxy map display mode.
    • Shows which planets are more valuable in terms of how many Asteroid Mining Powerplants are present. You will want to strongly consider using economy-focused command stations on those with high counts. Six is considered the average baseline count for asteroid counts at a planet. Shows the same icons as the Normal view.
    • Only appears when the Distributed Economy is turned on.
    • Thanks to Zeus for suggesting.
  • In general, added the ability for galaxy map display modes to only show up when they feel like it actually matters.
    • This can let us exclude certain ones from the view of a Champion or Necromancer, or add new ones, or whatever we want.
  • The number of asteroid mines (or metal harvesters) is now shown on the planet tooltip in general.

New Asteroid Count Assignment Logic

  • The way that asteroid counts are assigned to planets has been completely rewritten.
    • Existing logic we're keeping:
      • All Human Homeworlds still have exactly 6 asteroids, never more or less.
      • All Dark Zenith worlds still have exactly 6-10 asteroids, completely randomized.
      • All AI Bastion worlds still have exactly 9-11 asteroids, completely randomized.
    • Adusted Logic:
      • AI Homeworlds now give exactly 10 asteroids, rather than exactly 8. More of a reward for multi-AI games.
    • New logic:
      • The game then looks at the planets around each human homeworld, for a target number of not-yet-asigned-worlds.
        • If it's 1 player, then ideally 10.
        • If it's 2 players, then try for 7 per homeworld.
        • 3 players, try 6 per. 4 player try 4 per, 5+ players try 3 per.
        • Bear in mind that it looks at the closest planets to each homeworld... but if they are clustered all in a corner, that will mean further out. The game will only look up to 10 hops out, so if it's an exceptionally narrow corner and tons of players are in there, that's just going to give you fewer nice planets of this sort. That seems fair, given the insane defensibility you now have anyway.
        • First of all, one 9-asteroid planet is seeded somewhere in this range.
        • Then one 2-asteroid planet is seeded somewhere in this range.
        • Then up to two 6-asteroid planets are seeded somewhere in this range.
        • Then if there is room: 1 7-as, 1 5-as, 1 8-as, 1 4-as, 1 10-as if we got this far, and then 1 3-as if we got that far. If we still got further, it should do 1 11-as, an then one 2-as, although we should never hit that really.
      • The above gives a consistent value to the planets in the general neighborhood of the players, to keep things from being too harsh on them.
      • At this point, we now make a list of all of the remaining planets that do not have assignments as-yet.
        • First we assign 6-as to a full third of the remaining planets.
          • Well, if that number of planets would be more than 10, however, we take that number over 10 and divide it into 2. The first half of those will be 7-as, the second half 5-as.
          • The idea is that a third of the map is thoroughly average, or hovering right near it at least.
        • The next third of planets is divided between 8-as planets and 4-as planets.
        • The next third of planets is divided into thirds as well. First third of that third is 9-as, second is 3-as, and then the next third of a third is divided into two parts: 2-as and then 12-as.
        • If there is a remainder at this point (that's likely because of integer math), then those are all randomly assigned to something in the 7-11 range. So very desirable planets if there's this remainder.
    • This whole setup is designed to give overall more consistent games in terms of asteroid counts and distributions (now that it matters), while still having quite a bit of randomness in there.
    • If you want to see all the calculations and such as they go into any given map, then in the debug section of your personal settings you can turn on Mapgen Logging, and it now shows this.

Bugfixes

  • Fixed a variety of places in ProcessFactionConfigCustomFields(), which happens during mapgen primarily, where old or outdated settings could lead to exceptions when trying to read new values. Essentially if your last settings were old enough, or blank, you could have a rough time until you hit Reset To Defaults in the lobby.
    • Thanks to Chromatism for reporting.
  • Fixed an issue introduced in the last couple of versions where fallen spire flagships could seed as officers to capture out in the galaxy.
    • This was due to the shifts in lone wolf fleets, but now they are barred from seeding in that way.
    • Thanks to Wuffell for reporting.
  • Added a new causes_parent_fleet_to_not_allow_ship_line_swaps="true" that can be assigned to specific flagships/centerpieces to prevent their fleet from being able to do member line swaps.
    • This now applies to all of the fallen spire cities/fleets, to prevent all sorts of odd abuses with them that became possible in the last version or so.
    • Thanks to supamat and Vadatajs for reporting.
  • Fix a typo in economic cc tech upgrade
    • Thanks to crawlers for reporting
  • Covert Science Extraction is no longer listed as available in the AI command station
    • Thanks to Strategic Sage for passing on a report from steam

Mod Updates

  • MSF
    • Added several new fleets, bringing the total amount to about 20. Rebalanced or reworked several older fleets + updated ship counts in order to make them more synergistic and consistent with base game starter fleets.
    • Added the SOF fleet, a raid frigate focused fleet for quick offensive operations.
    • Added the Conqueror's fleet, a heavy frigate fleet designed for offensive operations and assaults.
    • Added the Siege Fleet, a fleet composed of heavy frigates with slow speeds but high firepower, exceptional against structures.
    • Added the Riot fleet, a defensive fleet focused on suppressor and forcefield frigates, emulating Riot Starships from AIWC.
    • Added the Ranger's Fleet, a fleet focused on striking hard and fast at all ranges, a bit on the fragile side.
    • Rebalanced the Imperial Fleet, Democracy Fleet, Barrage Fleet, Escort Fleet, Carrier Fleet, Assassin Fleet, to have more synergistic ship lines and updated their ship counts.

New Mod: More Starting Fleets Plus

  • The Omega Fleet (Thanatos Fleet), Emperor's Fleet (Assault Frigate only fleet), and the Cruiser Fleet are all considered cheat fleets, and have been moved to their own mod: MSF+, for those who want to play with random fleets and not want to use cheat fleets.
    • These were previously directly in the More Starting Fleets mod, by Zweihand.

New Mod: Capturable Dreadnoughts

  • New mod by Zweihand: Capturable Dreadnoughts!
    • Spire Dreadnoughts, Battleships, and Cruisers are now capturable on the map for owners of DLC1.
    • This was inspired by a bug that allowed all flagships to seed, even uncapturable ones like Spire capital ships.
    • These bad boys cost a lot of metal, energy, and raise the AIP considerably, but are very well worth it.

3.103 Reality-Bending Tooltip Hotfix

(Released June 9th, 2021)

  • Fixed a rather severe bug in the prior version that was introduced in regards to the "fake entity" that we use for tooltips. It was accidentally set up to actually overwrite data that is unrelated game data at times, although it wasn't consistent exactly how to cause it. Generally hovering over the build sidebar, or sometimes just having a tooltip drawn in general, was enough to do it.
    • The result was things like all the factories being removed from a fleet, all the turrets of a type being blown up from a fleet, all the turrets of one sort converting to another kind, all the buildings of one kind turning into engineers before exploding, and duplicate copies of certain ship lines in funky ways. In short: chaos.
    • Thanks to General Frost and various others for reporting.
  • The new "Humans: Metal/Energy Discounts For Lower-Mark Units" are no longer forced-off on any campaign types. This has been around for so long (on quietly for 2+ years) that having it suddenly off on the other modes is likely to cause problems. The ability to turn it off right now is just a personal choice, until we get a lot more feedback.
    • Thanks to swizzlewizzle for suggesting.

Mod Updates

  • Fixed the Civilian Industries mod to work with the latest code version in the prior build.
  • Both "AI Shield Generators" and "Macrophage Histiocytes" mods have been recompiled to avoid the "missing method exception errors" that they were having in at least the prior version, if not more.
  • "The Reprocessors" mod is currently broken (same missing method exception issue), and has been disabled from any use until it can be updated by its mod author.
    • Any existing savegames with it are unlikely to work until such an update is made.

3.102 The Start Of Multiple Campaign Types

(Released June 8th, 2021)

Please note that this was temporarily rolled back to just be on the beta branch, as it had at least one strange bug. Please use the current_beta branch to play it until we release a hotfix.

  • Some improvements to AI-allied factions to make sure they don't inadvertently shoot eachother
    • Thanks to a number of people for reporting, including ussdefiant and Darkshade
  • Add some defensive code to GetWormholeStatus
  • Shark Exos now say "I am a shark exo" in the announcement text

Balance

  • Took the over the top power level granted by self-hacks to golems down a notch. Hacks now have a higher initial cost and aren't quite so multiplicative in total overall value.
  • Added a new cannot_be_supercharged_when_in_supercharged_fleet="true" option for ships, to allow for certain ones to be invalid for fleet-wide bonuses (from the FRS).
    • The intent here is mainly to use this on certain golems and things that were Lone Wolf ships. This is currently applied to all of the golems in the base game, and likely should cascade over to the variants on those in DLC2.
    • In the tooltip, you will see "FLEET BONUSES DO NOT APPLY: Fleet-wide bonuses don't help this particular unit no matter what."
    • Thanks to CRCGamer for suggesting, as we did have some runaway crazy combos possible with these. It also does help Arks remain more unique in another way.
  • Adjusted Raijin Golem (DLC2) to not benefit from FRS buffs same as baseline non-lonewolf officer golems. Additionally gave it a boost to base health in compensation.
    • Raijin Golem base hull value 1,000,000 -> 1,600,000. This means with the hacks it can reach 25.2m hull value. Which is still less than the 32m+ it could previously reach with a Tutelar Pulsar Tank FRS unit in fleet. But much more called for than the health cap of 15.75m it would have otherwise.
  • The concept of "Lone Wolf" fleets no longer exists.
    • The Hive Golem, Botnet Golem, Frenzy Golem (DLC2), Retribution Golem (DLC2), and Spire Lost Frigate are the only units affected.
    • These are all now just regular officer fleets, however these all have the new "cannot be supercharged" flag on them.
    • This means that they can hack like normal fleet leaders can, and they can have other units in fleets with them. In general it changes little except for removing some annoying restrictions on how to use them in moment to moment battles and hacks.
    • It also used to be that these specific units only spawned in really limited numbers way out in the galaxy. They can all now seed anywhere a regular officer fleet can.
    • This also means the "Lone Wolf Fleets To Seed" setting is now gone. And in general there is one less officer (which was a lone wolf) in the galaxy compared to before. But you have more chance of more powerful ones in the middle distance, so that should actually even out almost.
    • In the fleets sidebar, this also moves them into the same category with other officer fleets.
  • Fixed a display-only issue with DPS being over-reported for units that have aoe_spreads_damage_among_available_targets="true". It was acting like the Siege Frigate could do a range of x to 10x damage, for instance, when really it can only do x damage divided different ways amongst targets.
    • This had no effect on the actual strength estimates or similar.
    • Thanks to CRCGamer for reporting.
  • Fixed inconsistencies between direct upgrade costs for people with DLC2 and without DLC2, as direct costs were updated after DLC2.
    • Thanks to Zweihander for fixing.
  • Corrected an oversight on Siege Frigates, where their strength was being reported as 2x what it should have been,
    • There is a strength_multiplier="2" (or whatever number) that we use in the case of AOE and other special-bonus (or special-penalty) units to account with hand-tuning for units that have an un-quantifiable amount of extra power based on AOE.
    • For instance, how do you mathematically calculate a strength number for an ion cannon that does infinite damage to lower-mark ships. Is it infinity strength? Is it half-infinity because it doesn't do that to ships the same level as it? Half infinity is still infinity, anyway. There's no actual math that works for this.
    • For a seemingly-easier example, what about a unit that has some major damage buffs, but only on a tiny subset of ships? Should we calculate out proportionately how many ships there are in the game that it could have a bonus against, and give it a buff to strength that is multiplied by that? Well, that might in theory work, but we have no way of knowing how many would actually be in a given game. So we need to use a soft multiplier, instead.
    • For a last one that is seemingly super easy, AOE in general. If there's a ship that does X damage, but can hit up to 50 targets, then... what is the best strength? It's unlikely to hit 50 targets with every burst it fires. But it's no more likely to hit 25, or just 1, either. We run the calculation as if it just hits 1, and then allow for the strength_multiplier="3" or something to come in as a way of making it look a bit more accurate. And we can tune that much further up if it still feels too low. But it's very much down to feel, and kind of has to be because of the nature of AOE damage. Which should be the most straightforward from a mathematical sense (and is), but is so context-bound that even the simple math has no actual answer because the inputs vary so much.
    • All of this is to say, originally at some point, Siege Frigates were given a 2x multiplier because of their AOE. However, then at some point later, they were adjusted to have a maximum of 10 targets that they can hit, AND they were adjusted to divide one pool of damage amongst the targets they do hit. So this is actually incredibly simple math: they do x damage, whether they hit 1 target or 10. It's just divided differently. So in this case, this is a great example of an AOE unit needing... no strength multiplier at all. That has been returned to 1.
    • Thanks to Aliyah for reporting that 100 strength of Siege Frigates felt more like 66. Technically it actually should have felt like 50, and in this new update would show as 50.
  • With the removal of the strength multiplier from the base Siege Frigate a couple ships that were copying from its stat block have been directly handed those multipliers.
    • Devestator Frigate given multiplier of 1.5
    • Ion Disruptor Frigate given multiplier of 1.5

Campaign-Type Work

  • Added in new xml entries for Sandbox, Challenger (aka Sub-Expert), Expert, and Deathwish game modes (aka campaign types).
    • Each of these note that they are incomplete, compared to Humanity Ascendant.
  • Added a new harshness_rating integer on campaign types.
    • For most features, we will use this to gate features, rather than explicit mode linkages. This will allow for mods and similar to add their own custom campaign types, if they wish, or adjust which features show up in which campaign types.
    • These are additive modes, so the harshness is being defined as follows (with plenty of space for intermediate needs if desired):
      • Sandbox = 0
      • HA = 100
      • Challenger = 500
      • Expert = 1000
      • Deathwish = 5000
  • Also added is_considered_sandbox="true" for sandbox mode in particular, which will allow for us to disable achievements in that mode as well as make special things that change ranges or add in new items for sandbox mode in particular.
  • The campaign type is now saved into each savegame, and is also shown at the top of the escape menu.
  • On "galaxy options," there has long been a min and max for the various integer options. It now has a new sandbox_min and sandbox_max, which are optional but let us override to larger ranges for sandbox mode.
    • Also there was a default value. There is now also a corresponding sandbox_default optional field. This last one also works for boolean fields, which can thus turn something on or off by default if in sandboxmode
  • There is a new min_campaign_harshness_to_display="0" value, and a new max_campaign_harshness_to_display="9999", which can be used to restrict various fields from appearing at all in different game modes.
  • In general, the lobby settings (integer-style galaxy options, specifically) now clamp themselves to allowed values if they are being read, rather than potentially being some old data that is now out of range.
    • This is particularly relevant when being able to switch between modes back and forth in the lobby right now.
    • When new integer values are being written, this also now applies the clamps for the same reason.
  • Galaxy options now have a GetHarshnessWindowRelation(), which returns an enum saying Sandbox, BelowButNotSandbox, InWindow, or Above.
    • This is all based on the min and max campaign_harshness_to_display. That min and max creates the window, but anything flagged as sandbox is just separate in general.
  • Added a new fixed_option_if_below_campaign_harshness_but_not_sandbox="string" for all string fields.
    • And then also a new fixed_option_if_above_campaign_harshness="string ".
    • This lets us clamp to an exact option (including different ones) below or above various campaign harshnesses, with fields that are hidden or displayed.
  • For integer and boolean fields, added fixed_value_if_below_campaign_harshness_but_not_sandbox="int" and fixed_value_if_above_campaign_harshness="int"
    • This serves the same purpose as above.
  • Rather than ever hiding fields if your current campaign type does not include that field in its harshness range (or forces it to a specific value for that mode), it now shows those fields in a non-editable format that you can hover over, and it shows you at what campaign type you can start editing it.
    • This will also be useful for people who are considering moving from Humanity Ascendant to Challenger or higher -- being able to see options that are there but not available to them in their current mode (so long as they turn on advanced settings), versus having to notice the campaign type itself.
  • Updated the custom fields on factions to have all of the various new functionality that Galaxy Options have in relation to campaign types, sandbox mode, etc.

New Galaxy Options!

  • New setting to allow us players the option to disable something that was already there: Humans: Metal Discounts For Lower-Mark Units (in the Human Balance section)
    • In a fleet with wildly divergent mark levels, the ships with a lower mark level will become much cheaper to construct and repair. Does not apply to drones.
    • A ship that is 1 mark lower than max is 90% of the cost. A ship 2 marks down is 75%. Three down is 55%, four is 35%, five is 25%, and six is 10%.
    • This defaults to on in both Humanity Ascendant and Challenger modes, but makes the economy much more trivial in some ways. Then again, it also provides more value from using all your ships, so that's kind of nice. This is forced off in Expert mode and above.
    • Thanks to NR SirLimbo for discovering that this old logic was even still here, after all this time.
  • New setting to allow us players the option to disable something that was already there: Humans: Energy Discounts For Lower-Mark Units (in the Human Balance section)
    • In a fleet with wildly divergent mark levels, the ships with a lower mark level will become much cheaper to operate. Does not apply to drones.
    • A ship that is 1 mark lower than max is 90% of the energy requirement. A ship 2 marks down is 75%. Three down is 60%, four is 45%, five is 30%, and six is 20%.
    • This defaults to on in both Humanity Ascendant and Challenger modes, but makes the economy much more trivial in some ways. Then again, it also provides more value from using all your ships, so that's kind of nice. This is forced off in Expert mode and above.
    • Thanks to NR SirLimbo for discovering that this old logic was even still here, after all this time.

Galaxy Options Per Campaign Type

  • Various galaxy options changes:
    • Max Planets To Scout At Once: defaults and main game values all same; sandbox min is 0, sandbox max 30, max_campaign_harshness_to_display="500". Aka this forces 8 when in Expert+, but is configurable on Challenger.
    • Minimal Fog of War: now only available up through Challenger mode. Forces false when in Expert+.
    • Reveal Factions From The Start: now only available up through Challenger mode. Forces false when in Expert+.
    • Wave Advance Warning: now only available through Expert mode. Forces None (no warning) when on Deathwish.
    • Allow Cross Planet Waves: now only available through Challenger mode. Forces it to true on Expert+.
    • Allow Direct Waves: now only available in Humanity Ascendant mode. Forces it to true on Challenger+ (it's on by default even in HA mode).
    • AI Can Retake Planets: now only available in Humanity Ascendant mode. Forces it to true on Challenger+ (it's on by default even in HA mode).
    • Guard Aggro Distance: now only available in Humanity Ascendant mode. Forces it to the default of 3000 if on Challenger+.
      • The range of this is normally 3k-10k. In sandbox mode, the new range is 0k to 50k.
    • AI Reserves Grace Period: now only available in Humanity Ascendant mode. Forces it to 0 (no warning) if on Challenger+. Default is normally 60 seconds.
    • Reduced Distance Restriction For Any Items: now only available in Humanity Ascendant mode. Forces it to 0 if on Challenger+. Default is normally 0 even in HA mode.
      • Normal max here is 6, but in sandbox mode it's now 50.
    • Beacons Enabled: now only available in Humanity Ascendant mode. Forces it off if on Challenger+. Default is normally on in HA mode, but this is for purposes of learning and exploration. Balance often gets funky if you introduce these later.
      • Random factions will be coming for the game in general in July, and for folks on Challenger+ mode, that would be the sort of thing they'd want to add in place of beacons.
    • The entire Capturable Density section (well, all of the ones expresses as a multiplier) is now only available in Humanity Ascendant mode. On Challenger+, it forces the default seeding volumes.
    • Tech Vaults, in general, are now only in Humanity Ascendant mode. Yes it's nice to have lots of capturables even in the more advanced modes, but these are pretty darn powerful, and there's already soon going to be some exciting new stuff you (must) capture in Challenger+ modes.
    • Max Normal Data Centers: now only available in Humanity Ascendant mode. Forces it to 5 if on Challenger+. Default is normally 6 even in HA mode. Before you worry about this, please wait and see the Major Data Center changes. :)
      • The range in HA mode is already 0-9. In sandbox mode, the new range is now 0-20. Crazytown.
    • Max Major Data Centers: now only available in Humanity Ascendant mode. Forces it to 4 if on Challenger+. Default is normally 2 in HA mode. Prior to now, the maximum ever allowed was 3.
      • The new range for these is now 0-5 in HA mode, rather than the old 0-3. In sandbox mode, the range is now 0-10.
      • There are, in general, now more data centers total in Challenger+ mode than in the old HA defaults (9 rather than 8). However, 4 of those are now the much more costly and complicated Major Data Centers, so that's a lot more challenging to navigate.
    • Max Distribution Nodes: now only available in Humanity Ascendant mode. Forces it to 4 if on Challenger+. Default is normally 6 in HA mode. Prior to now, the maximum ever allowed was 12.
      • The new range for these is now 0-12 in HA mode, rather than the old 0-9. In sandbox mode, the range is now 0-20.
    • The entire Unit Style Relative Strengths is now only available through Challenger mode. On Expert+ it is forced to the default 1x.
      • This is a prime example of where sometimes folks want the ability to play in a really different balance scenario, but also want to have the Expert-style gameplay flow, and Challenger is meant for that sort of middle-ground to be possible.
      • Suffice it to say, this field is a tool to completely rewrite the balance of the game if you want, so on Expert+ it is Right Out. It already has such a broad range that it didn't need any extra range for sandbox mode.
    • Scrap Refunds On Friendly Planets: now only available in Humanity Ascendant mode. Forces it to 15% if on Challenger+. Default is normally 15% even in HA mode.
      • Normal max here is 50%, but in sandbox mode it's now 200%.
    • When Crippled: Bail Out To Nearest Friendly Planet: now only available as an option through Challenger mode. Forces it on if on Expert+. Default is normally off in HA and Challenger mode, but for Expert you need to start learning how to deal with this.
      • As Sage notes: "Without bailout, territorial considerations in terms of how the player moves through the galaxy can be/are trivialized."
    • When Crippled: Bail Out To Nearest Home Planet: now only available as an option through Expert mode. Forces it on if on Deathwish. Default is normally off in all other modes, but for Deathwish this makes things even more of a penalty when they die.
      • Note that there's going to be some much more strict death conditions in Deathwish anyhow, so this is just the tip of that particular iceberg. Your nice shiny golem will later become a really junky basic transport during this kind of death, but that's not in yet.
    • Cost Of Repairing Crippled Transports: now only available as an option through Expert mode. Forces it to 4x on Deathwish. Default is normally 2x in all other modes, but you can go as low as 1x.
    • Lost Hacking Points When Unit Crippled: now only available as an option through Expert mode. Forces it to 10 HAP on Deathwish. Default is normally 0 in all other modes, but you can go as high as 20.
    • All Ship Attack Ranges: now only available as an option through Challenger mode. Forces it to 0.8x if on Expert+. Default is normally 0.8x in HA and Challenger mode. This is another of those "wow this gets too powerful" options, even though it affects all units. It's good for Challenger mode since some people may just prefer this style, but it's really preferred to be in sandbox in an ideal world.
    • Permadeath for Metal Harvesters: optional in every mode. Not required on any of them.
    • Permadeath for Zenith Generators: only an option up through Challenger mode, now. On Expert+ it is forced on. This already defaults to on even in HA mode, so it's tempting to force it on in Challenger. But no, that's the mode for compromises.
    • Sandbox: AI Civil War: this is now only an option in Sandbox mode. In all other modes, it is forced off and invisible.
    • Experimental: Ally with AI: this is now only an option in Sandbox mode. In all other modes, it is forced off and invisible.
    • Share Allied NPC Vision: only an option up through Challenger mode, now. On Expert+ it is forced off. This already defaults to off even in HA mode, but this is the sort of thing that would be particuarly desired with Vassals and such in the future, so letting it remain even through Challenger makes sense.
    • Allied Factions Generate AIP: only an option up through Challenger mode, now. On Expert+ it is forced on. This already defaults to on even in HA mode.
    • Allow Everything To Zombify: only an option up through Challenger mode, now. On Expert+ it is forced off. This already defaults to off even in HA mode.
    • Instigator Bases Spawn: only an option up in HA mode, now. On Challenge+ it is forced on. This already defaults to on even in HA mode. This makes things way too easy even for Challenger.
  • Various galaxy options we don't know what to do with yet, so are continuing to allow players to freely customize in any mode (for now):
    • Tsunami CPA
    • Shark A (AIP on Human Cmd Death)
    • Shark B (Attacks on Human Cmd Death)
    • Planets To Randomize: Marks 2-6
    • Planets To Randomize: Marks 1-4
    • Extra Allowed Distance For Adjacent-Seeded Items
    • Extra Allowed Distance For Middle-Distance Items
    • These ones are ostensibly for performance purposes, so limiting them feels odd, but we might have to:
      • Num NPC Units To Start Stacking
      • Num Player Units To Start Stacking
      • Advanced: Coarse-Process BG Planets
      • Max Ship Systems To Calculate Per Targeting Pass
      • Max Targets Per Ship System Per Targeting Pass
      • Extreme: Shots All Insta Hit
      • Max targets Fireteams can scan in one iteration
    • These ones feel like they are mostly a personal choice at any level of play (any mode), but it's hard to be sure:
      • Concentrate Unit Firepower
      • Ships Attack Methodically
      • Defensive Zombies Only
      • Repair Allied Units
      • Allied factions destroy command stations
  • Ironman mode (to be released later in July) will be required-on for Deathwish mode.
    • Reminder: if you want "Deathwish minus parts you dislike," then just play Expert mode and turn on some of the extra options to get the parts you want. Any mode in Challenger-and-up can be configured upwards into the modes above it (or worse).
  • Tech Vaults are incredibly powerful, but a great draw for new players. For the last while, they have defaulted to 1 per galaxy, with a range of 0-3 that you could configure.
    • They now default to 3 per galaxy, with a range of 0-5. In sandbox mode, the range jumps to 0-20.
    • In Challenger mode and up, these still are forced to zero now. Normally we don't bar something outright from Challenger (usually it's optional on challenger but then barred on Expert), but these feel like they cross the line into just being too powerful for any of the Expert areas, and there already will be other capturables around.
    • Thanks to Metrekec for suggesting the extra TVs for HA mode.
  • Extragalactic War: Ignore Minor Factions (and the two other "ignores" of this sort) now start with the text "Basically a cheat code." They are also now only available in Humanity Ascendant and Sandbox mode.
    • Thanks to Badger for clarifying.

Ability To Limit Or Add To Dropdowns In Galaxy Or Faction Options

  • Added a new use_alt_options_if_harshness_above="number" to both galaxy options and faction custom fields.
    • This is then paired with an alt_arbitrary_options, which can include different values.
  • The options cache that is used on faction custom fields is now cleared once per second and rebuilt, so that any changes of relevance can be applied properly.
    • On the galaxy options tab, it actually uses a cache now for the first time, and also gives more details for them than it used to. Tooltips and such are possible for the sub-options now.
  • Fixed a general issue where if you changed things that changed what dropdown options were available in a faction tab or galaxy options tab dropdown, it would not refresh the list until you changed sub-tabs or main tabs.
    • This just never was relevant until now.
  • All data tables in the entire game can now have hidden_from_lists_above_harshness="number" and hidden_from_lists_below_harshness="number" set on them, though it won't do anything unless they're used in a faction option list or galaxy option list.
    • These default to 9999 and 0, by default, so that they will normaly all show in every mode. A specific table can be altered to adjust these defaults, if desired.
    • At the moment, we are using this to exclude the Sniper Fleet from Expert mode and up, but that's mostly as an experiment. There are some fleets that folks on discord were suggesting might be too powerful for Expert and up, but we'd still allow those on Challenger unless they are pure cheese/
      • Right now, it's nothing personal against the Sniper Fleet except that it combos uncannily well with certain other fleets, so this was a good one to test with. We're hoping other folks working on these fleets (and that includes modded fleets) will help set limits on them.
      • Essentially on each fleet definition (or starting battlestation or support fleet definition), just add:
        • hidden_from_lists_above_harshness="200" if you want it hidden from Challenger and up.
        • hidden_from_lists_above_harshness="700" if you want it hidden from Expert and up.
        • hidden_from_lists_above_harshness="1500" if you want it hidden from Deathwish.
    • On the flip side, if you want things to only be on higher harshness levels, you can also set that. If you have some mega-difficult starting fleet idea that you would never want a new player to run into by accident, you can do that. It would still come up in the Random option on the modes you did allow it in, so I guess watch out for that.
  • Looking at faction options to limit:
    • All Nanocaust options seem like valid things for any mode, even them being allied to you. We're assuming you're fighting with them as allies against some other team. None of that is something to gate by mode.
      • Okay, for the sake of argument and for the sake of experimentation, we've made it so that on Deathwish mode you can no longer have them be allied to yourself.
    • All AI options are also for just configuring various circumstances and scenarios. There's nothing in there that's... cheaty.
    • For the rest of the factions, we're going to skip a review of their options for the time being. If you have suggestions about things that should be limited, please let us know.
  • Looking at options on humans, specificallu:
    • Number of Cryogenic Pods: this is normally a range of 0-30, default 25. This can no longer be configured on Challenger+, and is locked into the default of 25. On sandbox mode it now lets you have 0-50 of these.
      • This is one of those cases where the economic imbalance is so huge that, again, this is practically a cheat code when raised too much. These do also represent a weak spot on your homeworld, though, so having a certain number makes sense.
    • Number of Home Settlements: this is normally a range of 0-5, default 4. This can no longer be configured on Challenger+, and is locked into the default of 5. On sandbox mode it now lets you have 0-15 of these.
      • Same notes as above on the cheat-code-ness of this option.

New Mod: More Starting Fleets, by Zweihand

  • This mod adds 16 more starting fleets to spice up your gameplay, please contact the mod maker on the Arcen discord if you wish to request a fleet to be added.
    • This particular mod requires both DLC1 and DLC2.

3.101 Buffs, Fixes, And Quickstarts

(Released June 7th, 2021)

  • Experimental change: When units go through wormholes, they spread out a bit rather then all just cramming together on the same spot. When the AI sends a large force through, it looks much better visually. For feedback.
    • Thanks to Badger for adjusting.

Balance

  • Adjusted ticket value for Artillery Golem and Cursed Golem to make the AI less likely to reach for them first when filling certain exostrike waves.
  • Grenade Launcher Turret
    • Mark 1 damage per target hit 1,650 -> 1,500
    • Reload time 8s -> 6s
    • Max Mark 1 DPS 1,856 -> 2,250
  • Blaster Turret (DLC1)
    • Mark 1 damage per target hit 1,200 -> 950
    • Now fires twice per reload instead of only once
    • Effective Mark 1 DPS 1,200 -> 1,900
  • AI Ion Cannons given a hefty set of buffs
    • 90% Damage reduction against anything attacking it from beyond 10,000 range.
    • 10% Vampirism healing based on the damage it is dealing.
    • It gains an extra shot per mark level. So a high mark Ion Cannon can be firing up to seven shots per second.
    • Base hull raised from 20,000 to 30,000.
    • Base shield raised from 40,000 to 90,000.
  • AI Orbital Mass Drivers buffed as well
    • Damage per shot raised from 6K to 15K. Your average frigate over a year ago was unlikely to get over a million health. With a 7.7x maximum over base instead of 4x... these days its a lot more common. Plus durability upgrades to golems and other officers have also exacerbated the issue of the previously scary damage not being that high anymore. So now against proper targets that Mass Driver will be hitting for one and a half million damage per shot.
    • Base health of hull and shield doubled. 50K -> 100K Hull and 100K -> 200K Shield. Peacemaker version health raised to old values.
    • Vanilla version now takes a minimum of 10 attacks to destroy. No attack can deal over 10% max health in one shot. Peacemaker version which is a lot more common for that particular AI instead has a minimum of 5 attacks taken to destroy.
  • Golems are now 50% less likely to lead Exogalactic Strikeforces, to hopefully allow Dire Guardians to shine in that role
    • Thanks to Badger for adjusting.

Text And Tooltip Work

  • Edited descriptions of Expatriate and Alien techs to make it clear that only ships under your command + outguards are affected, and not any other factions.
    • Thanks to Zweihand for making this change.
  • More unit tooltip work:
    • Fixed using the AddNumberTruncated() function for integers rounding down quickly, displaying something like "2k/3k" if there is only 2999 out of 3000. Now it instead calls the FInt variant if the integer is over 1000 (or below -1000), which changes this to "2,99k/3k"
    • Fixed only the last order being displayed instead of the first.
    • Fixed entities getting claimed always stating that the player is browning out - except for when they actually do.
    • Command station states (the AI blocking claims, or a planet requiring the player to control the planet first)
    • Behavior and Orders now only show on medium and full tooltips, and on full tooltips the first 3 will show instead of just one.
    • Slightly shortened the text for wormhole pathing when the next hop isn't the destination from "Go to [next hop], final target is [destination]" to "Go via [next hop] to [destination]" in order to shorten this.
    • Wormhole pathing with multiple hops is now shortened: It will no longer show each individual hop as a "go to -> towards" as specified above, and instead only show the first instance and then the total amount of hops to the destination.
      • Example: No longer "Go to Planet A, final target is Planet D, Go to Planet B, final target is Planet D, Go to Planet C, final target is Planet D + 1 more" but instead "Go to Planet A, final target is Planet D (4 hops)".
    • Thanks to NR SirLimbo for all this work!

Quick start rebuilds

  • Quick starts available within the base game (no DLC active) reported as broken by Badger.
    • The five scenarios within 1-Basic in the base game have been rebuilt. These are: Helping Hands and Scenario 1 - 4.
    • The three quick starts within the base game 2-Moderate have been refurbished. These include: A Tale of Two Stars, Security Alert, and Time Is Running Out.
    • All three choices within 3-Harder for the base game rebuilt. These are: Backdoor, Betrayed Hope, and Uprising.
    • Thanks to CRCGamer for updating these. It makes them more efficient and small anyhow, and helps with future compatibility.
  • Fixed a regression in the prior version that was causing older quickstarts to not be loadable unless you had DLC1 installed, or sometimes also DLC2.
    • Essentially, some of these quickstarts were saved with those DLC enabled, which normally would be a failure state for loading the quickstart in general. However, our central code tries to maximize compatibility (and hassle on anyone creating and distributing a quickstart), so we normally are able to load those games in and strip out the DLC-related parts for purposes of actually starting a new game.
    • Because of some unrelated improvements in the prior version to make xml parsing give fewer errors if there is a typo, this wound up messing up the ability to load quickstarts that include non-enabled DLC or mods. It was less a traditional bug, and more of a... highly nondesirable reaction in a complicated system.
    • Anyhow, it's fixed now!
    • Thanks to Kayron, Bleak, and others for reporting.

Mod Updates

  • AMU:
    • Actually included the changed source code. This was forgotten in the last update.
    • Fixed the Destroyer base unit still being gated behind the DLC "3_The_Neinzul_Abyss", when it now is "4_The_Neinzul_Abyss"
  • Kaizers Marauders:
    • Now that faction fields can be overwritten got rid of the "true invasion time" and instead altered the default one.
    • Fixed being able to hack theoretically infinite amounts of turrets because it was not counting up the GCA-like and TDS-like hacks. Essentially after a few hacking changes I forgot to actually make them keep count.
  • Extended Ship Varaints:
    • Removed an unintentional 10 AIP from claiming all the support fleets. This unfortunately trickled down from changes within AMU.
    • Fixed some ships still being gated behind the DLC "3_The_Neinzul_Abyss", when it now is "4_The_Neinzul_Abyss"
    • Reduced the Metabolizing MLRS Corvette's damage bonus against enemies with low hull from 3x to 2x, since it also inherits the anti-strike craft bonus from the base MLRS Corvette.
  • Exotic Ships:
    • Increased the weapon range of the Immortal Cruiser and added a good number of tractor beams.
    • Fixed the Hammer Heads being called Thunder Bombs
    • Fixed the Hammer Heads and the actual Thunder Bombs being swappable fleet lines.

3.100 Commander Vision

(Released June 4th, 2021)

  • Zombie ping-pong reduction
    • The game now tracks how many times a unit has been zombified (or nanocausted). Each time after the first the new zombie will come back with 15% less health.
    • So the first time you zombify a unit, it has full health on resurrection. If the AI zombifies your zombie then it starts with 85% health. If you zombify it again then it will come back with 70% health, and so on.
    • Zombie ping pong is a neat mechanic, but if you can just play ping-pong forever it can be unfun, especially if there are two Nanocausts just trading fleets back and forth constantly.

Quality of Life

  • Added a new HUD Scale setting: Central Popup Text Scale
    • How large should the text inside of any center-screen popups be? This doesn't affect the size of the window itself, just the text inside it (so you have a lot less scrolling to do. Default is 0.9.
    • Thanks to a stephen dedalus and a variety of other folks for pointing out this oversight and requesting an option to adjust it. The default used to be 1, so this also makes it way less overwhelmingly large in general.
  • We have worked to shift from never specifying inline font sizes in pt format (<size=12pt> or whatever), but instead only to use percentages. This allows things like the font scale to be adjusted in the main text without some parts staying overly large or small.
    • If we've missed any places, then those won't react properly, and we'll need to hear about those bits to fix them. But so far the main things seem to work great.
  • Changed intensity tooltips for most base game factions (except Nanocaust). This gives a more useful clue as where to put intensities for minor factions.
    • Thanks to ArnaudB for updating.
  • Changed intensity tooltips for all DLC1 factions: Fallen Spire and Scourge.
    • This makes Fallen Spire much more clear as to how difficult it's supposed to be at a given skill level.
    • The description for the Extra-strong mode for Scourge has been reworked to incentive players to use it more.
    • Thanks to ArnaudB for updating.
  • Showing weapon activity details (if you have that on) now gives you more information in the tooltips on medium detail, not requiring full detail to be on.
    • Thanks to ArnaudB for suggesting.
  • When you are hacking for a new ship line, it now shows the icon for the ship on each line item.
  • When you adjust the scaling of the central screen popups (by default it is now already adjusting to 90% of what it was before), it now properly adjusts any column-based data in things like ship details (those have some columns that also need to be scaled down properly, and since the entire window is not scaled down -- unlike the tooltips -- this had to be handled separately).
  • The "Open Chat Window" hotkey has been moved from the Sidebar section of controls to instead being under Critical, and has this updated description:
    • Opens the Chat and Message log window, which can be used in multiplayer or which is for seeing a log of certain kinds of messages in single-player. You can leave notes to yourself here if you really want to, as well.
  • There is now a new Multiplayer section of the controls window, and all of the things related to pings are now in there rather than being in Other UI.
  • There is a new "Switch To Controlling Next Human Faction" hotkey in the Multiplayer section of the controls menu, default-bound to F4.
    • Pressing this button will switch your control from the current human empire (or Champion or Necromancer or whatever) to the next one. This is useful to quickly help out allies in multiplayer, or if you want to play multiple factions by yourself (for instance, a regular human empire plus a champion).
    • Thanks to Badger for requesting. This is ludicrously useful.
  • Added a new abstract ArcenCharacterBufferBase class, which is now the base underlying both ArcenDoubleCharacterBuffer (commonly used) and ArcenCharacterBuffer (less commonly used).
    • This creates more standardization for how the two are used, and for the various handy extension methods that exist, those can all now extend ArcenCharacterBufferBase and be available to both classes. Similarly with any utility methods that previously only took a ArcenDoubleCharacterBuffer -- they can now work with both kinds of character buffer.
    • This provides some standardization (and in the case of the double buffer class, we now directly support Int64 and UInt32 formats, which we previously did not), and makes certain types of extensions a lot easier to do for the future with tooltips and such.
    • Thanks to NR SirLimbo for inspiring this change.

Major Unit Tooltip Improvements

  • All of the units in the game now create text-embeddable sprites for their normal GUI sprites. This means that we're able to include them, with full colors and overlays and all that, in text in arbitrary ways -- at long last!
    • For now, this means that now in the unit tooltips, in the upper left corner you now see the icon and color of the unit that you are looking at. Depending on your scale of various things, this is probably the largest it is ever shown anywhere in the game, actually.
    • As part of this change, the place where the metal cost is shown on tooltips (outside of the build menu) has moved from the top row to be down after the mass of ships, right under energy cost. This is only shown in the full tooltip, not medium or short.
  • The tooltips are all now 10% wider, to make things wrap just a bit less, and have a bit more room for things.
  • A fairly large addition has been made that lets us use a "fake entity" for the build menu tooltips (internally) to give more accurate build information (basically: considering any fleet buffs properly) for ships you are planning to have.
  • Fully integrated NR SirLimbo's pretty mega-awesome much-more-readable upper tooltip rework. This basically replaces the first few lines of the tooltips for ships with something that is a lot more informative and concise, and it pulls out a few bits of data that had been scattered down below in the big blob of unformatted text stuff.
    • This is by no means yet a full tooltip rework, but this is a very solid chunk of one. This was a major undertaking by NR SirLimbo, and the work on this really improves readability and usefulness of tooltips to a degree that is even more notable in context as you play -- screenshots alone don't do it justice.
    • This has a bunch of new formatting consistencies, as well as improved abbreviations, among a host of other things. It's also just frankly better organized.
  • Work towards overhauling tooltips:
    • Created a few more rounding and percentage-focused methods in the FInt class.
    • Created a lot of extensions to the ArcenCharacterBufferBase to more easily format tooltips.
      • Both of these were in AMU for now, but have been put into the AIW2 codebase.
    • Thanks to NR SirLimbo for these changes.

Tooltip Responsiveness And Delays In General

  • There is now a new Tips subsection of the Game tab in the settings menu.
    • There's also a new Accident Prevention subsection of this tab, for purposes of things like the tech upgrade prompt (and later other things if we want.
  • There is now a new Tooltips subsection of the Game tab in the settings menu.
    • The items from the Tooltips subsection of Display have moved there, because this is more about behavior than something like HUD size, etc.
  • The maximum number of autosaves you can configure the game to track is now 200, rather than 50. Some folks have been asking for this for a while.
  • New setting in the tooltip section of the game settings tab: Main View Tooltip Delay
    • When you are moving your mouse around the main view, how long should it wait before it shows a tooltip for the planet or unit or wormhole you are hovering over? Default is no delay.
    • It is worth noting that this setting does not affect UI elements, by design. Being able to control those separately is nice.
    • Thanks to Strategic Sage and many others for suggesting this.
  • Adjusted things on the galaxy map so that they are more properly reactive to when you STOP hovering over something, thus leading to the tooltips feeling more responsive in general. The degree to which this feels improved, even with no changes to the tooltip delay, is really palpable.
  • Now the planet view also has the same responsiveness to hovering over units and wormholes and such. This feels really really nice.
  • Improved the way that tooltips disappear, throughout the program, so that it now feels more responsive all over the place. Initially this was something that seemed like it might take an entire recode of how some of our tooltips are triggered (it's majorly complicated in that it comes from three separate coordinate systems, raycasts that have to be run only on certain non-display-frame physics cycles, coordinate checks that are run on normal display frames, and so on; modern games are horrifying in their complexity sometimes, but a lot of that comes down to the move to multithreading as well as to hooking into systems like PhysX for standard things like determining what UI element your mouse is over, and things like that. It adds a lot of capabilities, but 10 years ago this was not really how we would have set things up, so it's been an adjustment).

Tooltip Snapping And Position

  • A new tooltip variant that is a bit less wide than the new default wide tooltip is now implemented. This one prefers to move to the right or left of the screen depending on your mouse cursor, and prefers being a bit lower than the thing you are hovering rather than being above it, too.
    • The general idea with this is that it still keeps the tooltip kinda-sorta close to the mouse cursor, but distinctly out of the way when you are looking through lists of things in particular. This is most notably needed for things like setup screens, where the tooltips could be frustratingly in the way before. As part of implementing this, initially things were frustratingly out of the way and off to the side, so this is a nice compromise that keeps your eyes from having to move too far without you actually having things obscured.
    • Thanks to LOTS of players for requesting this. Please note that we have to switch to this new tooltip style on each window that would use it, so if you see places that we should be using it and are not, or places where we turned to this style but it would be best to use one of the others, please let us know.
  • New snapping tooltip now on for the following windows:
    • Faction tab in lobby and faction window in escape menu.
    • Map tab in lobby.
    • Galaxy options in lobby and in escape menu.
    • Profile list.
    • Main menu.
    • Escape menu.
    • Load and save windows.
    • Quickstart and tutorial start windows.
    • Personal settings window, and controls bindings window.
    • Tips window (main menu, not the tips sidebar).
    • Note that pretty much everything to do with the sidebars is NOT using this, and a lot of things related to popups of list options also do not use this.
  • Thanks here again to Strategic Sage in particular for bringing up this general issue. It was bugging all of us, though.

Sidebar Tips

  • There is a new is_for_the_tips_tab="true" flag available for putting on journal entries that are actually for being a tip, rather than being lore or other information of that sort.
  • Fixed the "Element 0 was null! In PopupScrollingTwoColumnButtonList" error that was harmlessly in the log for the last few versions.
  • The header on the hacking sidebar is now "hack targets at planet" rather than "hack the enemy."
  • All of the tips-style journal entries are now moved out into their own separate tab on the sidebar.
    • This tab can be activated with the hotkey F1, which is the old-style windows help hotkey.
    • F1 was being used for "ping mode" in multiplayer, but that has been reassigned to F3.
    • Overall the goal of the tips tab is to make it way more obvious when there are gameplay tips, AND to separate that out from the lore, campaign event info, and other such things.
  • The journal tab is no longer green on the far left, and if it has some entries that are unread those are now shown with a pale greenish-blue number rather than bright red.
    • The tips tab also shows as white normally, but if there are any unread tips it now does a flashing color-shifting thing to make itself super noticeable.
  • On the tips tab, we are not showing the timestamp directly, as it's not as relevant. You can still see it in the mouseover.
    • Additionally, the tip text itself is larger in that tab.
  • Thanks to Strategic Sage for suggesting this, after lots of discussion with various players.
  • The tip sidebar entries no longer start with "Tip" or "Tips", since those are all now tips.
    • A number of them have been reworked a bit in terms of the title that is shown on the sidebar, and they all have different colored prefixes that indicate the type of tip. These range from:
      • Advice is specific strategic advice based on your current circumstances (hey, your stuff keeps dying, maybe upgrade it; hey we found a specific thing you should hack, etc).
      • Concept is advice that is more fundamental, and may be specific to your circumstances but also is very broadly applicable to every game in some fashion. (Pay attention to AIP, use transports, here's what to do with the citadel you just got, etc).
      • Hack is advice when you generally encounter a thing you can hack to get something good (The ARS is a thing, the TSS is a thing, etc).
      • Capture is advice when you generally encounter a good thing that you can capture to use (here's a fleet, there's a citadel, etc).
      • Enemy is advice for when you run into a particularly troublesome unit that might require attention (watch out for that Raid Engine, the Overlord Phase 2 is tricky, AI Eyes are not to be overlooked, etc).
      • Info is advice that is not critical, but the sort of thing that people frequently wish they know (hey there are automation settings, did you know you can watch fleets on the sidebar, did you know you can queue unload orders, etc).
  • When tips are added to the sidebar, there is now a center-screen banner that pops up letting you know this for 3 seconds. It makes it a lot harder to miss, especially because this is paired with the chat message which now says "New Tip" rather than "New Journal Entry." The fact that tips were journal entries was definitely hugely confusing.
    • There is a new setting in the Game tab that allows you to turn off the central banners if you don't like them.

Balance

  • For performance reasons, the following units are no longer allowed to spawn in waves (or as part of a hacking response, exo, etc):
    • Tractor Guardian
    • Dire Paralysis Guardian
    • Persuader
    • Pulsar Punk
    • Etherjet
    • Thief
    • Thanks to swizzlewizzle for reporting.
  • Added forced_to_bail_out_on_cripple_any="true" and forced_to_bail_out_on_cripple_deepstrike_only="true" as options for designs on flagships.
    • When crippled, will use bail-out function to a friendly planet. Or alternatively, only when in deepstrike territory.
    • The deepstrike territory version is now applied to the Retribution Golem (DLC2).
    • The tooltip for these units informs you of this aspect of their function.
    • Thanks to CRCGamer for requesting this feature.
  • Nerf to corruption minefield's acid effect. Acid now caps at 105 at mark 7 (from 200)
    • Thanks for CRCGamer and Zwei for pointing out how effective these were
  • Updated the AI MLRS guardian and dire guardian variants to use the same damage bonuses the MLRS Corvette received a while ago. This means instead of having 4x damage bonus against things below 30% health they instead have an always on 1.5x versus things without shields and an additional 2x versus anything below half health.
  • Gave Combat Factory a more applicable niche in being the fastest moving support factory. While it may not have the same level of utility as other factories it can keep up with fleets far more effectively.
    • Combat Factory speed 800 -> 1400
  • The game now seeds a 3 cruiser construction facilities per galaxy, rather than 2. This should help them have more impact. (DLC2)
    • Thanks to Zeus, Metretek, crawlers, and others for suggesting.
  • Added a new grants_stuff_to_be_added_to_player_fleets_remove_overlapping_techs="true" tag, which can be used for things like the Cruiser Construction Facility.
    • It is important to understand that while this will work any ARS-style hacking granter, it will not do a good job if you don't apply this only to units that can only be hacked once.
    • In other words, if you use this on an ARS, which can be hacked 3 times, it would not work for any hacks beyond the first.
    • This is now applied to the Cruiser Construction facilities, and seems to work well. Essentially it means that no two cruisers in the galaxy should share the same tech. This has very narrow applications as an xml attribute, but for both cruisers and destroyers if they all follow that single-tech path, that will handle it.
    • Thanks to Zeus for requesting.

ZA Balance Changes

  • ZA at all intensities has access to more defenses per mark of its portal/spawner. The amount per mark scales with difficulty where it was previously flat. This should be noticeable at 5+ and at 10 its more than triple what it used to be
    • Furthermore, the ZA has a larger metal income for defenses scaling with intensity, so it will rebuild faster
  • Civil war now requires more territory for higher intensities. This means that it will take longer for a civil war to occur but higher intensities will be expanding more quickly so this should compensate for this. The aim here is to make the ZA more expansionistic but give players more agency in curbing its expansion beyond its base territory.
  • ZA has more metal reserves, scaling across intensities. This means the ZA will be able to field a larger defensive response from the get-go even when its at peace
  • ZA Spawners warp in faster across the board, scaling with intensity. They were taking forever to warp in, even at 10
  • ZA Quiesce now lasts 45 minutes instead of 15. This hack was widely viewed as a waste compared to the others. Hopefully, the extended break will allow for more interesting decision making, such as a late-game strategy to get an otherwise inaccessible map control

Art

  • Created a number of new shaders for things like triplanar projection in a few different styles.
    • Also fixed a few shaders that, over the past few months, lost their rotational component because I saved over them, not remembering that they had custom code that Amplify Shader Editor couldn't detect or keep.
  • Improved the Tempest Cruiser LODs so that it shows nicer detail longer, but then goes lower-poly faster after certain zoom (DLC2).
  • Added unique art for the Trailblazer Cruiser and Trailblazer Barge (DLC2).
  • Added unique art for the Dark Mirror strikecraft and Darker Mirror frigate (DLC2).

Bugfixes

  • Custom fields on factions are now something that you can add to via partial record definitions in mods or DLC. This means that you wind up adding in an entry or two to a set of options, for example, versus completely replacing the entire list.
    • This is now being used for the Scourge in DLC2, to add the Zenith first armory option without having a duplication of the First Armory field.
  • Added one small correction to the destroyp cheat code.
    • Also added a new destroycurrentp cheat code, which destroys the planet the issuing player is currently looking at.
  • Fixed an issue where the ZA Castra (in DLC2) could not properly be hacked to get ships out of it in recent versions.
    • Thanks to Darkshade for reporting.
  • Fixed a longstanding minor issue in the settings menu where the count of expansions incorrectly included non-installed expansions as being enabled. Now it properly only counts them if they are both installed and enabled.
    • This has no material effect except the count in the sidebar of the settings window.
  • Fix a bug where external invulnerability was not working for units trying to use tags. It did work correctly for non-tag invulnerability like Dire Guard Posts protecting Overlords.
    • The affected units are the Spire Buttresses, Zenith Architrave Spawners, and lots of Scourge Thoraxian Hybrid types. This is a buff to the scourge.
    • Reported by a large number of people
  • Fixed up the TagsDict on units so that it is null before initial fill. This way, if something tries to call it prior to it being filled, we'll get an error and know about it.
    • Also updated this to be filled sooner rather than later, so that things like invulnerability granter checks can use it, plus anything else we would have in ComputeBalanceStats_OneTimeOnly. There were a couple of other less-critical things using that.
    • Thanks to Badger for discovering the core of this problem.
  • Removed the auto-on for vertex-animated phasing for most ships by type, since the effect was subtle to begin with, and also tended to bug out on random units and hunting those down was not going to be a fun game of whack a mole. Unless you zoom in really close and stare at phased units, this matters zero in the first place (other than when it's bugging out on a specific model), so this was definitely not a worthwhile way to spend time.
    • Thanks to Bummeri and Darkshade for reporting.
  • Fixed a longstanding bug in multiplayer where marking journal entries (or now tips) as being Read would not properly save for clients, and was also shared among all players (not ideal).
    • It now is properly different for each player in the campaign, and each one gets properly saved individually, as well.
    • In existing savegames, any that the host had marked as viewed are now marked as viewed for everyone; and in single-player, this has no impact at all.
  • Fixed a bug where if your science was some five-digit number -- for example exactly 20,200 -- then it would sometimes cause it to wrap in the top bar.
    • Thanks to General Frost for reporting.
  • Fixed a funky visual error that could happen when ships were in the process of dying or getting into transports where they could appear in the opposite quadrant of the gravity well from their current one for just a moment or two. This was more evident at some framerates, from what we could tell, but we were able to duplicate it.
    • Thanks to General Frost for reporting.
  • If you have an xml error of some sort, then it no longer spams a bunch of further errors about unrequested attributes. Those secondary errors could make it really hard to actually read what was happening.
    • Similarly, it no longer runs DumpBalanceStatsToCSV() if it had an error during parsing of xml. This was only one error line rather than hundreds, but it was still one too many.
    • When the code is set up incorrectly to try to load a non-enum as an enum, it now also gives a more clear error message to the programmer.
    • Also also, when Xml is unable to be parsed in a more limited way (aka a specific field is not read properly) it no longer throws an exception that causes a cascade of other errors. The cascade will now only happen in a more limited fashion if something was relying on that malformed data in a really specific way (there aren't too many fields like that, but there are some). This dramatically cuts down on the number of error cascades as well.
    • Thanks to Badger and Zeus in particular for requesting this sort of update. This should save time for all of us when there are xml typos.
  • If an ARS or similar has too many lines, then remove the extras now.
  • In the event that you somehow have two centerpieces for a fleet (for instance, from hacking to get a new kind and the old one is still there), it now self repairs by deleting the extra unit (the old one), and leaving a little note in the log.
    • Thanks to firespier for reporting.
  • Added a new "must_be_at_most_x" that defaults to 20 on factions. This means no more than 20 copies of a given faction in a game, though that can be customized.
    • For the AI sentinels, there is must_be_at_most_x="10", however.
    • Additionally, if more than 200 internal factions are to be added in general, it will now stop the player from adding any further ones. Beyond 255, they are unable to be saved properly into savegames, and performance would be just horrible in general.
    • Thanks to Setsuna for pushing the limits of what was possible and making us realize where we needed to put some limits.

Technical Additions

  • Added a new immune_to_all_damage_from_players_invisibly="true" xml flag that is applied to the ARS and similar and the TSS and ODSS, and things like the Cruiser Construction Facility.
    • That makes these completely unable to be targeted by players even when they are owned by enemy factions. These are not hostile structures, and are not meant to ever be attacked by the player (the player loses out on something if they do).
    • Thanks to Democracy and Zweihander2021 for reporting.
  • Added a new always_counts_as_zero_strength_including_any_contents="true" xml flag that is applied to the ARS and similar and the TSS and ODSS, and things like the Cruiser Construction Facility.
    • This might be something we need to put on other structures as well, to keep the AI from looking like it has more strength than it does when there's just some harmless goodies left behind.
    • Thanks to Zweihander2021 for reporting.
  • Added new faction xml for auto_add_one_of_faction_when_other_faction_present="OtherFactionName"
    • This is much more flexible than auto_add_one_of_faction_if_missing_on_save_load="true", which would instead be turning on factions in saves that really don't need them.
  • Added new faction xml that is auto_remove_faction_on_lobby_load_and_mapgen_when_other_faction_present="OtherFactionName"
    • This should largely be on the exact same factions as are auto-added. This cleans things out from quickstarts, last-settings, and "I added the faction for a bit in the lobby, then removed it" situations.
  • Tamed Macrophage now use both of the above flags in relation to the normal macrophage.
    • Same with Enraged Macrophage. They have both just been in every game, silent and useless, until now.

Mod Updates

  • Updated Spire Railgun Shop so that it's Spire ships are more in-line with the newly buffed maingame one. (Lord of Nothing)

3.006 Rising Spire

(Released May 31st, 2021)

  • Updated all of the asset bundles that the game uses to properly support OpenGL on OSX. This was an oversight in the prior release that caused the OpenGL OSX version to still not work properly.
    • Thanks to abjohnsonzz, MM12, and Lictuel for reporting.
  • Added warning text that you can only build 1 of each of the special drone station keepers (DLC2) on a planet regardless of how many you have hacked for.
    • Thanks to Zweihand for adding.

Balance Updates

  • Adjusted lifetime of anti-player Zombies to be 25 minutes instead of an hour and forty minutes.
    • Thanks to CRCGamer for updating.
  • Adjusted Combat Factory drone allotment. At mark seven the estimated strength rating of the combined drones is 9 instead of 4.8 at full counts.
    • V-Wing Drones count is now 25, up from 20.
    • Bomber Drones count is now 25, up from 20.
    • Added 20 count of MLRS Drones.
    • Thanks to CRCGamer for updating.
  • Cost nerf to Bulwark Turrets. If you insist on spam rebuilding them its going to cost your metal balance a lot more now. Construction cost raised from 30K to 90K each.
    • Thanks to CRCGamer for updating.
  • AI Golems buffs:
    • Base game: Health increased to 4x health and 4x damage from 2x health and 3.6x damage, with 1x being Mark I stats for player golems. This makes them effectively Mark VI player golems for most intend and purpose.
      • AI Cost for all golems increased by 50%.
    • DLC2: Health increased to 6x health and 6x damage compared to above, as player golems and lone wolf scales better in DLC2. This makes them effectively Mark VI player-golems (in DL2) for most intends and purposes. Most AI golems don't have updated weapons that player gets in DLC2, so enjoy that while it last.
      • AI Cost for all golems increased by 33% of base-game increased cost.
    • Do remember AI golems don't get FRS-buffs or hack-buffs. This means the player still gets significantly better golems if you're willing to invest in them. For both base game and DLC2.
    • Thanks to ArnaudB for updating.
  • Adjusted the AI Raijin and Retribution golems to follow the same stat rules Arnaud applied to other AI golems. Word of advice, don't let the AI Retribution run away it will have full health no matter what in 20 minutes.
    • Thanks to CRCGamer for updating.

Fallen Spire (DLC1) Buffs

  • Fallen Spire ships buffs
    • Increased speed of all spire ships to 1000 (not AI ones)
    • Increased damage and health of all spire ships by 20%
  • All non-AI spire ships gain 25% health and damage, speed increased from 600 to 1000.
    • This should make them more useful as they felt "weak". They didn't have a buff since FRS changes and buffing hacks for golems and arks.
  • Spire Shipyard production output increased from 2000+1000 per mark to 5000+2500 per mark. It felt a bit silly to have them be exactly as efficient as human factories... which you get multiple of per planets.
    • This should make it much easier to rebuild spire fleets without engineers spam. Especially with 5+ spire cities.
  • Spire Reactor health doubled. Since it can't mark up, it falls behind others buildings.
  • Spire Great Shield energy cost reduced from 2m energy to 1m. Hull increased from 400k to 4m.
    • It wasn't updated in a long time. It doesn't mark up and don't have the enormous stats increase of forcefields, so a buff was fine.
  • Spire Lesser and greater Spy Cradle energy cost reduced to 500k from 2m.
    • A logistical station with hack boost was much, much more cost-efficient. Now it's more useful.
  • Spire Buttress health doubled and socket needed reduced from 2 to 1. It already cost 2m energy. It was wayyy too expensive.
    • Now also gains Beam and Laser Lulse weapons that others Spire buildings have.
  • Spire transceiver health increased to 4m hull and 4m shield, from 900k and 400k. It clashed with others spire buildings for little reason.
    • Now also gains Beam and Laser Lulse weapons that others Spire buildings have.

Various changes to Spire defensive options, so they're actually useful rather than depressingly weak.

  • Spire Plasma Driver replaced by Spire Beam Cannon.
    • Metal cost decreased to 500k from 1,5m. Energy cost increased from 150k to 500k.
    • It fires 2+ 1/mark beams with 10x damage against 5+ tx. This makes it significantly more powerful.
  • Lesser and Greater Spire Fortresses changes
    • Beams weapons replaced with a similar version to the Spire Beam Cannon, with bonus 10x bonus dmg against 5+ tx. Come with increased shot per mark and the same planetary range that Spire Beam Cannon has.
    • Energy wave weapon now has 48+24/mark shots instead of 24+4. Greater has 96+48/mark.
    • Laser Pulse weapon now has 60+30/mark shots instead of 40+0. Greater has 120+60/mark.
    • Greater Spire Fortress now takes 3 slots instead of 4. Even with buffed stats, it wasn't worthwhile over the lesser fortress. Now it's a significant buff.
    • Thanks to ArnaudB for updating all of these!

Fixes

  • Reworked portions of the Outguard code
    • Can now specify a new tag on an Outguard group to make it not be randomly seeded
      • can_be_randomly_seeded
    • Can now contact any Outguard group by calling a new function
      • Should only be used by other factions that wish to enable an Outguard group related to themselves, Beacon logic is more complicated and nuanced
      • SpecialFaction_Mercenary.ContactOutguardGroup_NonBeaconSource
    • Fixed a few bugs related to the 'spawn beacon on homeworld' debug option
    • Allow Outguard groups to not scale with AIP cleanly.
    • Allow other factions to modify the number of times Outguard groups can be summoned
    • Thanks to StarKelp for implementing!
  • Fixed typo in difficulty description
    • Thanks to ArnaudB for fixing.
  • Hackbot now has the proper function to target only mobile targets.
    • Thank to Limbo for finding the function, and ArnaudB for fixing!
  • Adjusted a tag on the no longer allowed to seed original Frenzy Golem (DLC2) that should resolve an issue where it could not be claimed it games it was already seeded in previously before the changes.
    • Thanks to CRCGamer for fixing.

3.005 Radeon Returns

(Released May 29th, 2021)

  • OpenGL support, which we removed from Mac OSX a few months ago on our beta branch, has been returned.
    • In almost all circumstances, you should not use this -- Metal will perform better, is more modern, is a better use of RAM, etc.
    • However, because of driver issues with Radeon cards on OSX, at the moment OpenGL will be needed for compatibility purposes with that specific hardware combo.
    • Please note that, from now on, Metal is used by default, or you can force it to be used by adding -force-metal at the command line. To use OpenGL, you can add -force-glcore to do that. There are of course also start options in GOG and on Steam for making this happen without you having to fiddle with the command line.
    • Thanks to abjohnsonzz, MM12, slake-moth, Lictuel, xaid, congorilla, and deltadawgs for reporting.

QoL Improvements

  • Added a new "Main Menu Hangar Scene Self-Disables At" that now defaults to 25 rather than 35, and can be adjusted all the way down to 5 if you really want.
    • If the main menu hangar scene is causing performance below this FPS level, then it will turn itself off.
    • Thanks to nas1m for suggesting.
  • The "no intel" camera effect now defaults to once again being on.
  • When subcategories have advanced fields in the settings menu, it now mentions the count for those under each subcategory that is shown.
  • The settings menu now tells you how many advanced fields are hidden in any given subcategory that you can see, if there are any such fields. It makes it faster to notice that and to be able to click them.
    • This has also now been done for the galaxy options tab in the lobby, and in the game once you are in play. Again this helps with discoverability of specific advanced options.
  • A handful of overly-handy debug functions in the personal settings menu have been made non-advanced, so you can click to that tab more easily and then see those and expand to the rest if need be.

Bugfixes

  • Previously it was possible on the settings and galaxy options screens for the "X advanced fields" warning to be below the scrollable area and cut off. Fixed.
  • Previously, Battlestations and Citadels were not allowed to use transport mode or pause construction of their interplanetary engineers. However, there was a slight bit of transport mode that would work, where if it was put into the mode, the engineers could get stuck in there.
    • These now fully support transport mode, in the same way that support fleets (combat factories) do. It's pretty much just for interplanetary engineers right now, but if we ever added some drones or similar, then this would also be equally useful for battlestations/citadels of that sort.
    • Thanks to Zweihander2021 and Metrekec for reporting.
  • Summoning the Zenith Trader outguard (new in DLC2) previously did not actually have them with their wares for sale until you saved and reloaded the game. Fixed.
    • Additionally, in either DLC2 or the base game, the Zenith Trader wares should now always say "Zenith Trader" in the build sidebar, whereas that was not always the case before.
    • Thanks to Zeus and other for reporting.
  • If a hack cannot be done on a unit because it has already been done the maximum number of times, it now says how many times that is.
    • Fixed a bug that followed from this where we could see that the maximum number of times that the Zenith Architrave Portal (DLC2) was allowed to be hacked was zero instead of one. It can thus now be hacked properly.
    • Thanks to Darkshade and Apthorpe for reporting.
  • When you have not yet claimed a unit, it now shows their max health and max shields in the tooltip.
    • Additionally, if you have not yet claimed a unit, or if you have the full tooltip open for ANY unit, it now shows their metal cost (useful info for metabolization and other purposes).
    • When you have not yet claimed a unit, it also now still shows you what techs upgrade that unit; this mostly applies to citadels or golems or other standalones, since anything you could hack for already showed it.
    • Thanks to Smidlee and Metrekec for suggesting.
  • Fixed a kind-sorta memory leak where ships that had ship-to-ship lines (like engineers repairing things) would wind up with essentially unlimited extra references to the same line, adding 10 per second as they went. This wasn't a memory leak of the lines themselves, but of references to the lines, but even so this is the sort of thing that would lead to a simulation slowdown over time.
    • This would affect beam weapons, tractor beams, engineers, claiming of units, chain lightning, and a variety of other things.
    • Alongside this performance degradation, most likely this was related to why sometimes certain beams could be left behind until you tabbed to the galaxy map and back. Those were an annoying fleeting visual artifact, but not a true leak since they get cleaned up. If you still see those happening, then please let us know, and we'll also keep an eye out. The one that was eating performance is at least dead.
    • Thanks to Badger for reporting the climbing line counts in the debug view of ship tooltips, as this would otherwise be hard to notice, as the central line counts were correct.
  • Self-Hacks for hull, shield and damage can now be done by lone wolf officer fleets. This fixes some Lone Wolf centerpieces being unable to self-hack their own stats without another viable hacker (i.e. a Transport) present.
    • Thanks to NR SirLimbo for fixing.
  • Fixed a typo in makeshift turret's description, where it stated "spawns drones if present enemies" instead of "if enemies are present"
    • fixed typo where zenith miner increasing gravity stated an increase in ship speed, when it should be decreasing
    • Fixed typo in scourge builder, where solely was sorely.
    • fixed a typo where the bomber drone was written as V-wing drone
    • Thanks to Zweihand for fixing all of these.

Mod Updates

  • AMU:
    • Fireteam logic updates (in the hopes of not breaking anything):
      • Fireteams now when assigning and targeting should respect only going after a specific faction. This both highly experimental and entirely untested.
      • Units now do 3 checks when trying to assign themselves to a team: First it'll check for teams on their current planet that need more ships to activate. Then they'll check for teams on their current planets even if they are activated. Then they check for everything.
        • This should improve teams going online and becoming sooner, and avoid them pathing before joining teams if at all possible.
        • The mechanic existed, but was only unreliably enforced and for the most part the weighting on fireteams to join took care of this - but now there is some more strict rules in place.
      • Additionally the fireteam assignment method has more debug printouts and is easier to follow.
      • Also, Fireteam targeting can now be set to not attack or not defend, based on preference.
  • Kaizers Marauders:
    • Recompiled the code against the most recent version of AIW2 because of some people seemingly getting Missing Method Exceptions.
    • Fixed 2 "Fireteam Content Trace" settings existing. One now correctly names itself "Fireteam Individual Content Trace".
      • Thanks to Magiik for reporting.
    • Reworked the Defector logic:
      • Defectors can no longer spawn as part of invasions.
      • Raiders can now become defectors even on planets the player has no command station on, and the player and their allies no longer need superiority on the potential defector's planet for this to occur.
      • The chance for a raider to become a defector they calculate the "pressure" on them in a radius of 3 hops. The more strength (for the planet the defector is on this includes planet-bound strength, otherwise mobile only) the player(s) and their allies have over the Marauders and their allies, the more likely.
      • Additioally a planet the player controls must be within these 3 hops.
      • The hacking description has been updated slightly, and the evacuation hack has been updated to no longer (incorrectly) state that it's random, as it allows the player to choose the ship line hacked, as well as specifically note that upon hacking a type of Raider that type will never again be able to become a defector.
      • Additionally Raider Arks can now be hacked: The Seeker variant can gain improved weapon damage and hull health, the Carrier improved hull and shield health and the Blaster variant improved weapon damage and shield health.
      • Raider Arks are now visible on the galaxy map.
    • Kaizers Marauders now gain +0.04 ship tech level per intensity for each Cruiser and Destroyer Construction Facility on any of the planets they own.
    • Kaizer's Death Cannon no longer can target only entities with 700k or more health, and the player variants once again have the damage bonus upon Kaizer having low health.

3.004 Post Processing Options

(Released May 28th, 2021)

  • Improve fireteam escort support
    • For StarKelp for DLC3 work.

Balance

  • Alright so this is something of a more significant change. First off this will only apply to new games created after this patch. I cannot change the already existing Frenzy Golem without potentially breaking existing saved games so that version still exists for those saves. Old version will no longer be seeded. Instead the replacement Lonewolf version of the Frenzy Golem can occasionally grace newly created games.
    • Lonewolf version costs 30 AIP to capture instead of the previous 20.
    • New version caps out at 78.75m health instead of 47.25m. And doesn't require a Tutelar Pulsar Tank to do so.
    • Wrath Lance is usable from 40% missing health instead of 60% missing.
    • Wrath Lance base damage 5000 instead of 12000, but gets 3x damage bonus against targets closer than 6000.
    • Wrath Lance range is 12000 instead of 8080.
    • Vampirism healing rate is 10% of damage dealt instead of 5%.
    • Zenith Raging Shotgun base damage raised from 2000 to 2500.
    • Thanks to CRCGamer for adjusting.
  • Improved the shields of all Riot Cruisers a bit. But with a larger bonus to the Bastille version which is reliant on its shield for its unique bonus.
  • Bastille Cruiser given a few extra shots per salvo on its main weapon.
    • Thanks to CRCGamer for adjusting.

Bugfixes

  • Remove some leftover debugging code
    • Reported by Oval
  • Fix some ZA civil war bugs where they would spawn an impossibly large number of ships
    • Reported by a number of people, but particular thanks to Magiik for astute observation
  • Fix a bug where the nanocaust could spawn on dead planets (leading to them not doing very much)
    • Thanks to Strategic Sage for reporting
  • During hacking or other AIP reductions, the AIP floor message is no longer sent if you're not actually at the floor
    • Thanks Pladdicus for reporting!
  • Fixed a slew of tip-related typos reported by LaGrange on Mantis (and made a few adjustments of my own).
    • Thanks to Tzarro for fixing.
  • Some typos dealing with the Strikecraft Hangars were slain.
    • Thanks to CRCGamer for fixing.
  • Fixed a bunch of typos
    • Thanks to LaGrange for reporting and Dominus for fixing.
  • Fixes occasional null reference from the Two Column Button List prefab
    • Thanks Badger for reporting, and Dominus for fixing.
  • Updated description to include nanocaust allies as the presence of the nanocaust but without any mention in the description caused confusion as to whether or not they are friendly.
    • Thanks to Zweihand for updating.

Color Grading And Visual Updates

  • The main menu cutscene has been updated to have a better color glow to the landing strip lights, and for the arcen logo to be more natural in how it is inset in the scene. The light on the left wall is also a bit nicer.
  • The initial loading screen looks nicer, has more interesting bloom effects, and is no longer has banding in it.
    • This is largely thanks to Beautify 2, which we are now using to make everything look sharper and nicer in general.
  • Overall the game has a bit richer contrast and sharpness and brightness thanks to Beautify 2.
  • We are no longer using the "convert to LDR" camera and post processing effect prior to our gui camera, since we can now do the sam ething with Beautify 2 and get a prettier result for less CPU/GPU cost.
  • Removed one layer of color grading that was washing out... most everything. It made a lot of the final ships, especially for DLC2, look way less nice than they did in our in-engine setup tests, which had been quite confusing. But this also was washing out planets in the base game, all sorts of ships, etc. It just generally made things look worse.
  • Added a new "Twentieths" rounding option for settings that are floats (in addition to the existing Tenths). This lets you have ticks between things like 0.4, 0.45, 0.5, etc, versus just 0.4 and 0.5.
    • For some reason this doesn't work yet, and chasing through the code we can't figure it out yet. Oh well, it's not a crisis for now.
  • Fixed an issue where horizontal sliders in settings windows did not go all the way to the right when they were full. This was just a visual thing, but it was mildly confusing at best.
  • The font over wormholes, in planet view, has been improved to Audiowide instead of Orbiton Black. Additionally, it no longer has the white background around the letters.
    • This is a lot more attractive, but there may be some cases where readability is lower than before because of team colors being similar to the background color. The general sentiment of most folks who have weighed in was that they prefer to occasionally have slight trouble with color blending versus the awful white outline all the time. Do let us know if it's a problem, though!
  • The two settings "Galaxy Map: Hide Background Hexagons" and "Galaxy Map: Bloom Intensity" have been moved to the "Fullscreen Effects (Post-Processing)" subcategory, out of the "Color Grading" subcategory.
    • In general, we are going to allow a lot more control over the post-processing effects that are used, so this makes sense to collect them all now.
    • Also, for the sake of not using inverted language ("hide is on, so thing is turned off" -- what?), we have change "Galaxy Map: Hide Background Hexagons" to being "Galaxy Map: Show Background Hexagons" and defaulting to on, rather than the other way around.
  • Added a new "Galaxy Map: Bloom Effect" that allows you to completely turn off bloom on the galaxy map if you want (or if you have problems with it).
  • Added a new "Planet View: Bloom Intensity" and "Planet View: Bloom Effect" that allows you turn adjust bloom during battles or turn it off.
    • Turning it off would be something that would be a good idea for those OSX Radeon hardware combinations to try, as that might be what is causing the crazy fullscreen glitch effects for that one hardware/OS combo.
  • Added a new "Anti-Aliasing" subcategory on the display menu, which allows players to adjust these effects for the first time.
    • In this subcategory, there are now settings for disabling FXAA on either the planet view or the galaxy map, or both, as you wish.
    • Turning this off would be something to experiment with for thos OSX Radeon users who are having strange artifacts, but it seems very unlikely that these are the culprit.
    • Beyond that, turning these off would just be for folks who prefer brighter stars in the background, or who find that it is taxing their CPU/GPU more than they want (probably a below-spec machine if that's the case, or an extremely high 4K+ screen resolution in combination with midrange hardware).
  • Added a new "Draw Main Menu Hangar Scene" setting to the Visual Load section of the Performance tab.
    • This main menu scene is actually one of the most visually-taxing in the entire game. If your machine is below-spec or otherwise struggling to keep up, then disabling this can make your main menu experience much more pleasant. Please note that if your computer is failing to maintain 35fps on the main menu for 4 seconds, it will automatically disable this for you and will not re-enable it until you reload the game.
    • That auto-disabling feature is also new.
  • There are now settings under post-processing in the display settings that let you turn off bloom or color grading on the victory and loss screens. Should only be done if you specifically have a problem.
    • These are under advanced settings, since it's not super common to need it.
  • There are now settings under post-processing in the display settings that let you turn off GUI Glow effects (a form of bloom), as well as turning off the newly-added Beautify 2 if you would like to.
    • With these, it is now possible to disable every form of post-processing effect that the game has (minus a few things that should be truly harmless, like the HSV adjuster that lets you adjust the saturation of the game in the color grading section).
    • For users who are having visual artifacts with AMD Radeon cards on OSX Metal, disabling some combination of this (probably either the UI Glow or else Planet View Bloom or both) should now be a workaround to the problem. No other OSes or hardware combos have problems with this to our knowledge.

Nebula Background Upgrades

  • There was a strange effect happening with our starfields on some of the planets and the galaxy map when FXAA in particular was turned off, but it was still there but more subtle even with it on.
    • Essentially, all of the stars in the starfields would seem to jump around rapidly and insanely, on our skyboxes that are not of the traditional sort (using our custom nebula shader). It turns out the problem was that we were not using mipmaps for the starfield texture, which was causing this artifact. Trilinear filtering also helped to eliminate it.
    • This wound up making it so that we'd have to fix the starfields on 84 of the nebula backgrounds that we have, and as part of that we wound up actually completely reworking... a solid 50 of those. They're much more dramatic and colorful, without being a circus. There's a lot more variety in the feel of various planets now, which is really nice.
    • We could have just stuck with fixing the starfields themselves, but it was definitely much more satisfying to improve all the backgrounds so that they all reach the maximum quality bar that we've been setting lately.
    • As part of THAT, there were several that were too low-quality for us to use in the past, and those have been fixed up and now are in the rotation (and look great). The number of dark zenith planet nebula backgorunds (for DLC2) has doubled, as part of that. You'll only see that effect in new campaigns.
  • Added a new adjust_exposure_traditional_skybox="4" (or whatever number) for skyboxes that use traditional skyboxes, so that if they are under-exposed right now we can fix that. Certain ones were just showing up as black, which is quite strange. It seems to be vaguely related to the post-processing stack, but at any rate we can fix it with this.
    • Fixed _Black5 and _BlackHole to have improved exposure so that you can actually see them. It's not clear why these were so dark, but at least we can adjust it. If you see others that are off, please let us know and include savegames!

3.003 Continuing To Refine

(Released May 24th, 2021)

  • Most factions can now kill DSAAs; it was disrupting their logic (ships would sit around endlessly because they detected the DSAA as an enemy but couldn't shoot it)
    • Most recently reported by Lord Of Nothing
  • Scrapping a command station that's under attack now triggers the Shark B exo
    • Otherwise you could just always scrap your command stations before the AI could kill them during a battle.
  • Fix some exceptions in Astro Train LRP
    • Thanks to Darkshade for reporting
  • Added a 5 min cooldown weapon timer (Glacial)
  • Dyson sphere hacks are now actually capped at 3. Nerf their responses a bit (but they are still really really high for the second and third hack).
  • Dyson Spheres are allowed to kill reconquest command stations on their home planet again
    • Thanks to GreatYng for reporting
  • Relentless Waves can now tachyon blast planets, since civilian cloaked defensive structures were confusing them
  • Fix another potential bug where Waves could sometimes incorrectly target friendly units.
    • Thanks to Ranamar from discord for reporting
  • AI Eyes can no longer be hacked while alerted. Losing the hack attempt when one changes to being alerted is expected. Being able to just restart the hack like nothing happened while it was alerted pretty much invalidated them. If you must hack it leave the planet for a minute and let it turn back off.
  • Updated name="Returning_GCAs" display_name to remove the reference to GCAs and replace it with one for TSSs.
    • Thanks to Tzarro for fixing!
  • The Safe_DoOnSpecialEvent_OnMainThread() threads now also fire with a new SpecialEventType.IngameGalaxyOptionsSavedAndAppliedFromGameCommand as event type when, well, the new settings have actually been applied on both clients and the host. This was not the case with SpecialEventType.IngameGalaxyOptionsSavedAndApplied.
    • This fixes being unable to access the new settings in the thread that is meant to fire when the settings were updated.
  • When transforming a mobile fleet centerpiece that had self-hacks done the game will now try to apply the same to the new centerpiece.
    • If for some reason it can't (the new centerpiece can't do the same self-hacks, or can't do as many, or the new hacks are more expensive) it will try to sink in as many hacking points as possible into the same hacks and respec what it couldn't spend and display a message.
    • It will never overspend what already was spent on the old centerpiece.
    • This way it no longer is a trap for new players who upgraded their ZO Golems with self-hacks before discovering they could make them even more powerful with transformations - and losing their previous investments.
    • Thanks to NR SirLimbo for updating!
  • Updated tutorial 4 to modern standards, utilizing current icons/assets, fixing grammatical errors, and a slight rewrite to introduce concrete tips (Upgrading a Citadel/Battlestation upgrades all turrets/engineers assigned to it, but upgrading a mobile/officer fleet only upgrades the flagship).
    • Thanks to Zweihand for updating!
  • Fixed a comma in Tutorial 3 - Basics of Fleets And Building.
    • Thanks to Zweihand for updating!
  • Raid battlestation no longer has makeshift turrets, making it have 3 turrets like every other starting loadout.
    • It used to have all four and being monotech because raid turrets were much worse before and paired badly with a number of loadouts. This has partly changed. It's still monotech so remains good, but no longer has that "extra"
    • Thanks to ArnaudB for updating!
  • Corrected an issue with the awakened Chain Lighting Eye having a viable sabotage hack. (Active eyes shouldn't be hackable.)
    • Also updated the base game eyes.
    • Thanks to CRCGamer for updating!

Hacked Alien Ships Balance

  • Discovered a oversight in the ships that can be hacked for from Dark Spire. Simply put the player versions were copied from the NPC version stat blocks which use classic scaling. This actually was a problem for the frigate class Specter potentially granting up to 28 ships per hack. So simply enough we are fixing things so they use the better hull and shield values of the designated player strikecraft and frigate scaling. Which give better stats but much saner cap progression. Unfortunately this fix will likely only be fully effective for new games.
    • Hacked Dark Wraith maximum cap 64 -> 69 with strike scaling. Base cap reduced to 16 from 18 (starting cap in game is actually 35)
    • Hacked Dark Phantom maximum cap 43 -> 43 with strike scaling. Base cap reduced to 10 from 12 (starting cap in game is actually 22)
    • Hacked Dark Specter maximum cap 28 -> 6 with frigate scaling. Base cap reduced from 8 to 6. Maximum stats per ship increased by nearly double however.
  • Double checked the Dyson hack ship grants and discovered same issue. Players are not supposed to be getting 28 frigates off a single ship line hack.
    • Dyson Sentinel maximum cap 107 -> 113 with strike scaling. Base cap reduced from 30 to 26 (starting cap in game is actually 58)
    • Dyson Defender maximum cap 107 -> 113 with strike scaling. Base cap reduced from 30 to 26 (starting cap in game is actually 58)
    • Dyson Bulwark maximum cap 28 -> 6 with frigate scaling. Base cap reduced from 8 to 6. Maximum durability 7.7x instead of 4x though.
  • Raised science cost of Alien technology upgrades to match Expatriate costs. With the re-balance of Dark Spire and Dyson ship hacks to use player scaling on the ships (making the strike choices hit max unit caps within two ranks for a mere 1500 under previous costs) and the plethora of good options within DLC2 this tech line was too cheap and thus too valuable as an automatic max rank when it was remotely applicable. Still will be really good value for the first couple ranks (3500 total cost for first two ranks) but not auto-pick level.

Zenith Onslaught (General)

  • The missing basic QS for the DLC2 should now be available!
  • New Items from Zenith Trader!
    • Impending Doombomb from the Dark Zenith. 5 planetary cap; 40 galactic cap. Expensive and energy-intensive, but these beauties can take out giants
    • Mirrored Tractor Arrays from the Zenith Architrave. 10 planetary cap; 80 galactic cap. These tractors reflect 50% of damage they receive back to the source.
  • Spartacus Cruiser creates more phased cestus by default (still increasing 5 per mark). This should help it synergize better with itself and other ZA hacked ships
  • Mosquito drone buffs. Hardening from 25 ->15 (dies in 7 shots instead of 4); has a new bonus x3 multiplier to >= 5tx but tractor multiplier reduced to x3 (from x7)
    • These are intended to annoy big things, but they were dying too fast to function appropriately
  • Blackguard Cruiser nerfs. Both weapons have a 50% damage reduction
  • Drone Reclamator metal from 15K to 1.5M. This was always supposed to be a very expensive purchase that should take 15 min+ to pay for itself
  • Fixed description of Drone Stockade to remove mention of it having a movement speed -- it hasn't had this for a while
  • Fixed the Monarch outguard (the viceroy, specifically) from causing the faction from shutting down. Removed the starburst from it so it doesn't trigger drones the outguard faction can't handle

Dark Zenith

  • The DZ are now more able to build structures despite lurking cloaked enemies
    • Thanks to Alivaril for reporting
  • Fix a typo in the svikari description in the game lobby
    • Thanks to DarkShade for reporting
  • Zeus's balance changes
    • Barbed Tractor hits less targets, from 17gx -> 14gx
    • Nerfed ROF of the javelin/net launchers for DZ units
    • Barbed net/Javelin now have the correct version of self-destucting when attacking
    • Added the mine overlay to the doombomb to make it more clear what this unit is
    • Increased AOE of the DZ concussive field generator
  • Fix a DZ bug where we weren't using the right Difficulty for minor faction-allied DZ

Zenith Miners

  • Damage to mobile miners now sticks through the transformation
  • Add some defensive code for zenith miner notifications
    • Thanks to ZeroTheHero for reporting
  • When a Miner is killed, it now properly generates wreckage for the player to mine
    • Reported by zeusalmighty
  • Some tweaks to the zenith miner notifications. Fix a problem with miners making planets nomadic. Miners can now actually make ships on a planet slower
    • From a problem reported by Zero the Hero

Zenith Architrave

  • Fix a bug where pioneers wouldn't take nearby undefended planets
    • Thanks to Darkshade for reporting
  • Fix a bug where the ZA could fail to expand if they had enthusiastic allies
    • Thanks to Ovalcircle for reporting
  • Zeus's balance changes
    • Phased Castra have double hull/shields, spawns units every 5 minutes (from 30), and releases a golem-tiered Bustuarius upon death
    • Mirrored Tractor array buff: 25% ->50% retaliation damage.
  • Fixed a bug on external faction data where SpawningBooleanOne and SpawningBooleanTwo were not being tracked correctly over the network or to disk. Not sure how much impact this had on any existing saves, but it would be wrong behavior at worst (basically these always just being false).
    • Edit: actually, this should solve the "ZA Civil War not happening" bug.
    • Thanks to Badger for discovering.

Mod Updates

  • Additional updates to bring More System Defenders up to current balance standards.
    • Made the Stormfront Ark cost 100K energy instead of 7K to match base game balance. (This is so it plays nice with phasing weapons used by the Zenith within DLC 2)
    • Improved damage output and durability of the Stormfront Raid Frigate pair used by the Stormfront Ark.
    • Slightly improved the damage output of the missiles on the Stormfront Raiders used by the Stormfront Ark.
    • Escort Carrier Frigate given added_shots_per_salvo_per_mark="0.3" so it gains an extra shot per reload at mark 5.
    • Flypaper Frigate granted added_shots_per_salvo_per_mark="0.4" to its Charged Shells weapon granting an additional shot per salvo at marks 4 and 6.
    • Made Bomb-Pumped Laser Mines available within More System Defenders have an associated weapon tech same as the standard within DLC2. (Splash)
      • Was reminded by user ussdefiant60 of the newer standard set by DLC2 for mines.
  • AMU:
    • Fixed 2 files that were accidentally not pushed with the most recent changes.
  • AMU:
    • Adjusted the Shark B default settings to the same values as Vanilla now uses.
  • AMU:
    • Fixed an error in the custom debug popup logic where it didn't display the error that occurred.
    • Fixed a potential integer overflow in the GetSquareDistance() method, though this is unlikely to have caused exceptions in this very method.
    • Fixed an exception in the Auto-Construct Sniper Ring game command when building new sniper turrets and some were already on the planet (i.e. switching to a military command station and having more turrets, or already having placed some manually).
    • The Auto-Construct Sniper Ring now guards against potential issue from having command stations destroyed, crippled or switched at bad times when a client might be lagging behind and still thinks the station is fine.
    • In addition it also tries to avoid placing turrets close to command stations.
    • Fixed changes to AMU's galaxy settings only applying at best once after saving new galaxy settings. In addition settings will no longer update in the background each second, but whenever changed now. This means less CPU use for AMU in the background.
  • Kaizers Marauders:
    • Actually used the instrumentation in the DoSpawningLogic() method to display a debug step if the error repeats.
    • Fixed the Defense Augmenter hack on the Capital not working at all. This was likely broken since the inception of TDSSs and ODSSs.
    • Fixed the turret hacks for Marauders being hackable at mark 1 already. The Capital now requires itself being Mark 3 to get hacked, and the Outposts Mark 2 (which is down from also Mark 3 which was originally done). This likely a leftover from reducing the requirements to debug or test these hacks.
    • Fixed ships that are supposed to retreat immediately being assigned to fireteams again and going back into the fight even though they should not.
  • Updated AI Shield Generators mod as changes to AI Overlords meant that Homeworld Shield Generators were not spawning.

3.002 More Tweaks

(Released May 21st, 2021)

  • Player-Allied Marauders can spawn more Raiders
  • A new debug menu has been added that allows music tracks to be disabled or enabled. Simply double click on an entry to move it to the other side.
    • Thanks NB_FlankStrike for the idea and Dominus for implementing!
  • Shark B is now more powerful.
  • Balance adjustment to Blitzkrieg Turret (DLC1) where base damage was increased to be 2.5x previous. However drone counts per salvo slashed by two thirds. This is so the turret is more valuable being placed where it can shoot its now much stronger main gun rather than being hid in the back like a bootleg drone carrier.
  • Additionally added missing guard-post ignore tag to the Interceptor and Counter-Sniper turrets to match other sniper style entities.
    • Thanks to CRCGamer for updating.

High-Difficulty AI buffs

  • The goal is to buff the AI only at high levels (most of these affect difficulty 10 most severely). Lower difficulty AIs are in a decent state.
  • Wormhole invasion buffed to occur at 155 AIP on Diff 8, 120 on Diff 9, and 75 on Diff 10
    • Thanks to Zweihand for updating.
  • The AI generates Exos (a la sharkB) when it kills one of your command stations. These exos should now be much larger for difficulty >= 7.
    • At 7 the exo is now 12 strength + 20 per 100 AIP, and at 10 the exo is 35 strength + 60 per 100 AIP
      • The goal is to make losing a command station actually have a cost; especially if the AI breaks past your front line to some undefended command stations, this can now just outright lose you the game
  • Hacking waves on difficulty 10 are larger
  • Wormhole Borers for difficulty 10 now start spawning sooner
    • This is for DLC2 only
  • This section brought to you courtesy of Metrekec

DLC 2

  • Zenith Miners now always spawn in the center of the planet, regardless of where their probe had been.
  • Additional multi-shot values for a couple DLC2 player usable frigates.
    • Phantasmal Host gains 0.4 per mark and thus gains an extra shot per salvo at Mk4 and Mk6.
    • Darker Mirror gains 0.5 per mark and thus gains an extra shot per salvo at Marks 3, 5, and 7. Note this is for its basic laser and not the reflected revenge shots.
    • Thanks to CRCGamer for updating.
  • Fix to AI version of Raijin Golem within DLC 2 having woefully low durability for some reason.
    • Thanks to CRCGamer for fixing.

Bugfixes

  • Corrected a incorrectly targeted copy_from reference. Outguard Paralysers were being copied from base Stingrays instead of the correct Paralyser unit.
    • Thanks to CRCGamer for fixing.
  • The change music debug menu now properly displays the current song and no longer plays a song twice.
    • Thanks DEMOCRACY_DEMOCRACY for reporting and Dominus for implementing!
  • Fixed the Superterminal on Difficulty 10 having no hack to subvert.
    • Thanks to Sorrydough for reporting and NR SirLimbo for fixing.

Mod Updates

  • AMU:
    • Fixed AJEA (Auto-Juggle Energy Assistant) being default-on. It should now be properly disabled for new players, but the 100k energy that was the old default may even extend to players who are installing the mod for the first time.
      • Thanks to crawlers for finding.
    • Put in an experimental fix for a cross-threading exception in the FireteamPrecognitionMap, used by Kaizers Marauders. Essentially when planet links changed and certain paths were no longer possible it could fail and throw an exception.
      • Now when such a thing happens it will clear all current data and try again from scratch, up to 3 times. If even then it fails it'll display an error log, clearly something seems off. It will, however, not block the execution so at the next LRP it should try to find targets again.
  • Exotic Ships:
    • The Flameblade Light Frigate now includes a few instructions to get it to work correctly.
  • Extended Ship Variants:
    • The Attack Carrier drone variants of the VWing, Fusion Bomber and Concussion Corvette now share the same techs as the Attack Carrier (Core - Medium).
  • AMU:
    • Added the new Auto-Build Sniper Rings function (default off) in the Personal Settings -> Automation tab.
      • Sniper turrets are defined as all turrets with at least one weapon, all weapons must have a range greater or equal to 1 gravity well diameter, and if they have tractor beams those must also have the range requirement.
      • In practice this relates to Tritium Sniper and Spider turrets (Vanilla), and Holocene Missile, Interceptor and Counter-Sniper turrets (DLC 1). Any modded turrets fulfilling these requirements such as Beam Sniper Turrets (Kaizers Marauders) also automatically apply.
      • When enabled AMU will automatically build all sniper turrets on all planets in a ring around the gravity well, with some distance to all wormholes if possible.
      • This makes it so that enemies with insufficient range will need to move once around the gravity well in order to destroy all the turrets, which can be very time-consuming.
    • Fixed a terrible bug in the PlacementCondition framework. Essentially it uses square ranges for many calculations to be faster, but this lead to integer overflow on high ranges and could cause any number of freaky issues.
    • Added a new getIntSquareRoot_NonSimSafe() function. This relies on floatin point math which means it may end up with different results on different machines.
  • Exotic Ships:
    • Reduced the gravitic core strength on the Gravitic Drainer Corvette from -50% speed to -10% speed. With overlapping gravitic cores the slow as simply too powerful.
    • Ditto to the Anti-Gravity Destroyer, going from -80% to -60% speed debuff.
  • Minor update to More System Defenders
    • Removed mobile fleet lines grant from Stormfront Ark to match base game standards. Note this will only apply to new games created after this update.
  • Minor tweak to Frigates Focus so the ARS wasn't offering more options per hack than the base game is.

3.001 The Onslaught Continues

(Released May 19th, 2021)

  • Added a warned to all starting battlestations tooltip that picking the same starting battlestation twice will result in the second one being randomized.
    • Thanks to ArnaudB for adding.
  • Change weight of goodies in the ODSS
    • Chances for Tachyon Array reduced from 40 to 15
    • Chances for Sentry Frigate reduced from 100 to 25
    • Chances for Gravity generator increased 30 to 40
    • Thanks to ArnaudB for updating.
  • A small change to Dark Spire hack so their interval is 10s like Dyson instead of 30s. It made more sense when the ship hack lasted 300s instead of 120s.
    • Thanks to ArnaudB for updating.

Bugfixes

  • Put in some added protections against "debug code 3400 during update fireteams," and more instrumentation.
    • Thanks to donblas for reporting.
  • Fix a bug where Dark Spire Vengeance Generators would explode after the third time you hacked them for ships
    • Thanks to a number of people for reporting, most recently GreatYng
  • Add a missing newline to the Esc menu display of factions.
  • Update Tips with corrections and typo fixes.
    • Done by Tzarro.
  • Fixed Tabloid Starting battlestation (DLC1) to no longer mention "exotic" in its description . As it doesn't have turrets of that technology.
    • Thanks to ArnaudB for updating.

Hunter Intelligence Improvements

  • Improve fireteams's abilities to kill high-health targets without weapons like Dark Spire Conquest VGs
    • Thanks to Daniexpert for reporting.
  • Fix a bug where the AI could spawn hunter threat against another dead AI.
  • Improve fireteam unit gathering (especially for hunters).
    • Thanks to Darkshade and Metrekec for reporting

DLC 2

  • DZ Fimbulwinter processing no longer happens on clients
    • Thanks to Rifi8 for the bug report
  • Fix a bug where sometimes ZA ships would fail to kill command stations
    • Thanks to ussdefiant for reporting
  • Fix a bug where sometimes ZA ships would fail to do anything at all
    • Thanks to Ovalcircle and ussdefiant for reporting and zeusalmighty for figuring out the problem
  • DZ Transports are now less likely to suicide their Transports into enemy planets
    • Thanks to LordNSR for reporting
  • DZ terminii and epistyles no longer have bubbleshields and have longer reload
    • Thanks Chris for pointing out the shields were unnecessary; Zeus went a head and nerfed damage as well -- the DZ has had a static Defense buff last patch that made their damage overkill
  • The Zenith Onslaught hovertext in the Expansions menu now is updated to reflect the release
    • Thanks to Breach for reporting
  • If an epistyle loses access to some resources it needs to finish building something, it will try to build something else instead
    • Reported on discord
  • Nomad planets will now move a bit further each time
    • From a discussion on discord
  • Fixed names for DLC2 drones being V-wing for bomber drone and gangsaw drone
    • Thanks to ArnaudB for updating.
  • Reduced tractor range for Widowmaker from 70k to 30k, as the range was so huge it caused errors.
    • Thanks to ArnaudB for updating.
  • Fixed hackbot multiplier.
    • Thanks to ArnaudB for updating.

Display Options

  • Historically, we have relied on the unity engine with this game to tell us what fullscreen resolutions a given machine supports. Unity in turn relies on the OS's reporting. However, there are times where something is amiss at either the engine or the OS level, especially when it comes to very small or very large resolutions, particularly anything larger than 4K or the top-range-a-year-or-two ultrawide resolutions.
    • Given that when we run the game in fullscreen mode, it is generally borderless windowed mode (on windows and linux -- I think it's a bit more complicated on OSX), technically we should be able to use whatever resolution without the hardware itself freaking out.
    • With that in mind, we've added explicit overriding support for all of the common resolutions in all the common and uncommon aspect ratios of monitor ranging from 640x480 up to 5120x1440 (this last one was the one that seemed to be unsupported; it looks like 3840x1080 and down were all showing up fine).
    • With all of this said, please bear in mind that the various post-processing fullscreen effects normally are very lightweight, but when you push the resolution to be very high, they get far more expensive to run on your GPU (and CPU). 1920x1080 can fit in a 2k texture. Anything under 4096px wide can fix in a 4k texture. A 4k texture requires, at minimum, 4x the processing power of a 2k texture. If you go all the way up to the 5120x1440 resolution or similar, you are now working with 8k textures. These require 16x -- at the very least -- the processing requirements of a standard 2k texture.
    • If you're running the latest and greatest GPUs, and your machine laughs at this sort of post processing, then go for it! It's probably just fine. Some sort of fancy RTX or similar, you're just fine.
      • That said, if you're instead on OSX and you have Retina support (a very high possible resolution without the GPU support to help it out), then it's highly recommended that you drop your resolution to something lower. You'll have visuals that are just as sharp in most cases, but without the extreme extra processing requirements.
    • Big thanks to Hyper on discord for reporting the lack of support, and supplying the list of resolutions.
  • Also added explicit support for the common OSX retina resolutions, which are a different set.
  • Added a new "Fullscreen Effects (Post-Processing)" section to the Display settings tab.
    • Adjust things related to screen-wide post-processing effects in the game. Whether these are related to personal preference, hardware compatibility, or otherwise.
    • We'll allow more control over bloom, and turning off bloom, shortly. But it didn't make it into this release.
  • New advanced setting under post-procesing: Show 'Stale Intel' Camera Effect
    • When you are on a planet where your intel is out of date, show a full-screen fuzz effect. Defaults to on. Beware that it may be hard to tell if you're looking at outdated intel without this effect on. However, it does say 'Old Intel' at the top of the planet tab of the sidebar, so there is that other cue.
    • If you've been having trouble with things going too colorful on OSX with a Radeon GPU, please try turning this off.
  • New advanced setting under post-procesing: Show 'Stale Intel' Camera Effect
    • When you are on a planet where you have never even explored it at all, it shows a really severe wave distortion pattern like an old TV. Defaults to off. This would have been unlikely to actually ever be triggered these days, as you cannot click through into unexplored planets.
    • Note that, until this release, it defaulted to on, but again was impossible to hit since... some time in 2019 or 2020.

Mod Updates

  • Extended Ship Variants:
    • Removed the accidental Attack and Stealth carriers from the Repairing Support Starter Fleet.
  • AMU:
    • Fixed a bug in the More System Defenders autobuilder script. It was still using the DoForPlanetsParallel instead of single-thread.
    • Updated the exception logging to display better in the ArcenDebugLog.

3.000 Begin The Onslaught

(Released May 18th, 2021)

  • Base game credits have been updated to properly credit Badger in the #2 spot, and as the lead AI and faction designer (well, and coder also, but only so much fits).

Bugfixes

  • Some additional typos smitten
    • Thanks to daniexpert and tzarro in some unclear combination
  • Add a bit of defensive code to GetIsEitherControllerOrInfluencerHostileTo(), I saw a NRE.
  • Fix a bug where doing a planet hack (like 'neutral science extraction') could trigger a player-allied faction to try to respond to it.
  • Fixed an issue where any units beyond the first that were using a given model and under construction or in single or multi phase would not render properly.
    • The fix for this is fine, but really we could be doing this more efficiently, so I need to recode these shaders from scratch when I have time. It has to do with vertex offsets and the way the existing shaders are coded, so I'll need to just revise those effects completely again at some point soon. Maybe I can make them look even more cool.
    • Right now because of the vertex offset stuff, in this particular way that this shader is coded, it has to be a maximum batch size of 1, rather than the usual 1023. So that's more draw calls than preferable, but not the end of the world on even midgrade hardware from 5 years ago.
    • Thanks to GreatYng for reporting.
  • Fixed a bug in last night's release that was related to the MP fleets fix, but which broke all savegames and quickstarts older than 2.131 (this is sometime last year).
    • They are all now working again.
    • Thanks to Kallor for reporting.
  • Fixed an exception that could happen in ProjectedMultiPathData.AddConnection() if null planets were passed in by accident (usually a cross-threading thing).
    • Thanks to Vellsi and GalateanGemmate for reporting.
  • Fixed an exception that could happen at "Exception in entity tooltip text generation at stage 555"
    • Thanks to LordNSR for reporting.
  • Fixed an exception that could happen at "UpdateDataForPlanning Exception in Entities Loop B, debugStage 900"
    • Thanks to LordNSR for reporting.
  • Potentially fixed a bug with the Usurper at "DoEntitySecondLogic for Usurper debug code 100"
    • Thanks to Zweihander2021 for reporting.

DLC 2

  • Change the ZA default colour
  • The ZA is now slightly better at clearing its early planets
    • Thanks to Oval for reporting

Dark Zenith

  • Minor economic tweaks.
    • DZ and Svikari's D. Guardian and Golem tier units have about a 25-35% cost reduction
    • DZ and Svikari turrets don't cost black or red resources anymore
  • The DZ will prefer not to attack ZA territory.
  • The DZ increase their power level based on how many planets they've captured
    • On larger galaxies, they must take more planets to increase their power level
      • The AI was being too aggressive against the DZ
  • The svikari don't get the free bonus turrets

Mod Updates

  • Extended Ship Variant:
    • Fixed an error all players without DLC 2 would get because 2 entities (the Bomber Host and Decoy Host Frigates' decoy ships) were missing the tag to not load unless DLC 2 is installed.
      • Thanks to Recursive Optimization Exit for finding!

2.999 DLC Eve

(Released May 17th, 2021)

  • add overlays to the drone ODSS structures to help emphasize their connection to their respective command station tech
    • Thanks to Zeus for implementing.
  • Fix typo in MetalGeneration description.
    • Work done by Tzarro.
  • Fix HackToGrantShipLine_TSS_All typo.
    • Done by Tzarro.
  • Fix a typo in the hacking menu reported by tzarro
  • The AI will now try harder not to drop Exogalactic War Units directly on their enemy factions

Major Multiplayer Fix

  • Fixed a cluster of three issues that were combining to make one of the most tricky MP bugs in recent memory, and which were also making the game fairly unplayable for MP clients for a week, or a week and a half (time is hard; it may have actually been a bit longer, this has been a crazy time and a crazy bug).
    • The short of the problem was that lots of ships and even fleets would disappear for clients periodically. I could never really duplicate that on my own machine, but it turns out that loading and unloading transports would cause it instantly to happen. It also happened for other seemingly-random reasons.
    • So, overall, there was a three-pronged strategy to fixing this:
      • Firstly, ships that are suspected of being ghosts on the client are never allowed to just delete themselves if they don't hear back. They now add themselves to a new form of central registry, and do a better job of getting killed -- or updated -- by the host if the client requests a ghost check (hey, is this ship dead for you?).
        • This is probably good for some edge cases, some of the harder to track down ones, but it didn't help the core problem here much.
      • Secondly, we recently added sorting to the fleet member groups. When those were sorted by strength, then it would cause an order mismatch on the client and the host, which led to all ships in that fleet line (and probably then a cascade of others) being deleted.
        • This was something that was more periodic rather than happening absolutely every frame, and fixing this definitely fixed some errant client explosions, but was not the core issue that was making MP unplayable. It would have been more noticeable if it was not for the third issue.
      • Thirdly, and lastly, I added in a rapid-sync function for fleets a few releases back (around when this all started). The goal was to have it update fleet data faster after a load or unload of transports, to keep strength numbers accurate. And this was working... kinda.
        • But the problem was, this was a general-purpose fleet sync tool that normally synced ALL fleets for a faction. So it had logic in there to delete any fleets that were not included in the update data (since those clearly did not exist on the host). That normally is fine... except with the fast sending of partial data. If we had 3 fleets out of 200 that needed to get quick updates, it was deleting 197 fleets and all the stuff in them. Of course this would cause massive lag and other problems.
        • This was easily triggered by making transports load or unload, but other things could also trigger it. In the end, just making it so that the host sends a message of "I'm sending them all, or I'm just sending a few" is enough to make it so that we can only run the delete method when it sends them all. And that then solves the problem.
    • Thanks to a huge number of folks for reporting the problem, and bearing with us while we tried to figure this thing out!

DLC2

  • Final version of the DLC2 credits are now in place.
  • New DLC2-specific cheat code: "cmd:zeus cc", which spawns all of Zeus's cruisers in one fleet.
  • Documented an existing DLC2-specific cheat code: "cmd:zm here", which spawns a Zenith Miner probe at the planet you are currently at.
  • Zenith Miners now do a better job of conveying how long until they eat a planet by the colour in the tooltip (and in the planet name)
  • The 'reroute miner' hack against a zenith miner probe now allows you to pick which adjacent planet you'd like to see the miner on.
  • Added two new quickstarts.
    • Thanks to Zeus for implementing.

Balance

  • Miner mass from 12 -> 26 tx. This thing is huge.
    • Thanks to Zeus for implementing.
  • ZA hackable units reworked as separate entities. Start at mark 2 to get to mark 7 with full alien tech. The guardian tier now properly load but they had to be treated as strikecraft. Stats for these units adjusted to reflect this scaling
    • Thanks to Zeus for implementing.
  • DZ invasion initial budget at 5+ increased. Watching Demo play, Zeus saw that he nerfed the initial invasion too hard so this should be more balanced.
    • Thanks to Zeus for implementing.
  • Svikari nerfs to their resource collection rates. They were teching up too quickly watching Democracy play the other day
    • Thanks to Zeus for implementing.
  • The AI will not send Exos against the DZ if the DZ is not doing well
    • The goal is that for balanced DZ-AI situations (ie similar difficulties), the AI shouldn't be able to kill the DZ without player intervention and the DZ shouldn't take over the whole galaxy without player intervention
  • The DZ now get free defensive structures when they build an economic structure
    • The DZ's planets were too easy for the hunter to hit-and-run
  • The DZ now spawn some defensive turrets when they create a new terminus or epistyle. The Hunter was feasting on undefended dz economy
  • Zenith Onslaught has a higher intensity DZ now that it's considered a harder QS

Bugfixes

  • DLC2 fix, made AI version of Raijin Golem use correct assets.
    • Thanks to CRCGamer for updating!
  • Fixed the ludicrous number of shots on the hacknet golem (DLC2)
    • Thanks to ArnaudB for updating!
  • Fix a bug where DZ planets would link into the galaxy early if a nomad planet moved
    • Thanks to Democracy for reporting
  • Fix a typo in the DZ faction description
    • Thanks to Mac for reporting
  • Fix a typo in the Crashing Nomads Notification hovertext
    • Thanks to Democracy for reporting
  • Fix a bug in the ZA when you destroyed its Portal
    • Thanks to Democracy for reporting
  • The DZ now properly generate a hacking response when their units are hacked
    • Thanks to democracy for reporting
  • Add some defensive code related to fireteams and destroyed planets
  • Phased Castras now spawn correctly when you hack a Castra to death
    • Thanks to zeus for reporting
  • The Jormugandr should be less prone to indecision now
    • Thanks to democracy for reporting
  • ZA portal shouldn't be able to be hacked more than once.
    • Thanks to Zeus for implementing.
  • If a Zenith Miner has been fighting for more than 10 minutes without transforming, it will just transform
    • Thanks to Zweihand for reporting
  • The AI now spawns the correct number of anti-DZ dragons
    • Reported by zeus

Mods

  • Kaizers Marauders:
    • Fixed a bug that would make Marauders crash shortly after loading a game.
    • This most likely happened when a Marauder outpost was destroyed in the same second as the game was saved. Upon loading the code would no longer find an outpost to work with, because it's gone, but wouldn't remove it unless it was recognized as destroyed. Now it simply sees an outpost no longer existing as a reason to remove it too.
      • Thanks to Magiik for reporting with an extremely helpful save.
  • Extended Ship Variants:
    • Even more extended now. For Vanilla adds 2 more ships:
      • The Stealth Carrier and Attack Carrier are variants of the Ambush Carrier. They are available for everyone.
    • Added content exclusive if Zenith Onslaught is enabled:
      • Included 8 more Strike Craft variants:
        • Electric Blaster, Static Bomber, Polarazer, Polaraider, Shrike Fighter, Shrike Seeker, Dark Splitter, Toxic Mirror
      • Included 4 more Frigate variants:
        • Darker Gravity Mirror Frigate, Darker Echo Frigate, Bomber Host Frigate, Decoy Host Frigate
      • Added the Hardened Transport Flagship, which has the "Sturdy Fleet" as starter fleet.
      • Added the Repairing Combat Factory and its starter fleet.
      • Updated the description to reflect these changes, include the new stuff and no longer wrongfully refer to DLC 1 as "Fallen Spire". Instead it now correctly is called "The Spire Rises".
      • Updated a few other things in the description that were off or simply outdated.

2.910 Onslaught Approaching

(Released May 15th, 2021)

  • There is now a way to draw a planet that does not exist in the grav well.
  • The dyson sphere (base game) has gotten a facelift, and looks fancier now, as well as having a slightly fancier rotation.
  • Some of the per-planet per-frame code has been moved around to really be per frame, rather than per sim-step. This can make a difference in how quickly it responds to things like... well, like being blown up, among other things.
  • Added a variety of per-planet effects in our asset bundles that we're not actually using. Some intense particle effect variants, and some crazy lightning, among other things. Modders sometimes pick up things like this and use them. Check the manifest files for the effects_and_lines file.

General Balance Changes

  • Player Adjustments
    • Cloaked transport's income boost now needs 5 miniutes to kick in instead of instantly (like the other transports)
    • Battlestations now consume energy! All versions use 15K (half of a citadel); mass 5tx -> 6tx
    • Citadels (all variants) Mass 7tx -> 8tx
    • Black Hole Machine (including AI) Energy 10K -> 20K
  • AI Factions
    • Overlord Phase 1 armor 300mm -> 350mm; Mass 7tx ->13tx; energy 25K ->250K
    • Overlord Phase 2 armor 300mm -> 350mm; Mass 7tx ->13tx; energy 25K ->250K
    • Command stations Energy 0 -> 150K
    • Warp gate Energy 100 -> 15K
    • Dire Singularity Guardian stat adjustments. Mass 10tx -> 7tx; energy 35K ->25K; armor 90mm->210mm
    • Dire Guardposts all have energy usage increaase from 25K -> 50K
    • Ion Cannon Energy 300 -> 20K
    • Mass Driver Energy 300 -> 20K
    • Alerted Eyes (all) Energy 300 -> 150K
    • AI Fortress Mass 7tx -> 8tx
    • AI Super Fortress Mass 7tx -> 11tx; Energy 50K -> 150K
  • Astro Train Faction
    • Astro Train stat adjustments (all versions): Mass 6tx -> 8tx; energy 10K -> 30K
    • Fenrir armor 150mm -> 245mm; energy 10K ->100K; Mass 7tx ->9tx
    • Reanimator armor 150mm -> 245mm; energy 25K ->100K; Mass 7tx ->9tx
    • Umbra armor 150mm -> 245mm; energy 25K ->100K; Mass 7tx ->9tx
    • Shellshocker armor 150mm -> 245mm; energy 25K ->100K; Mass 7tx ->9tx
    • Custodian armor 150mm -> 245mm; energy 25K ->100K; Mass 7tx ->9tx
    • Warspite Artillery armor 150mm -> 245mm; energy 25K ->100K; Mass 7tx ->9tx
    • Warspite energy 25K ->50K
  • Dark Spire Faction
    • Vengence Generator/Locus Energy 0 -> 100K; Mass 2tx ->5tx
    • Wraith Mass 5tx -> 1tx. Player cap 20->18
    • Phantom Mass 5tx ->1tx; Energy 2000 -> 2,250; Player cap 14->12
    • Spectre Mass 6tx->5tx
    • Hackable DS ships now start at mark 2 so they can reach mark 7 if players invest in alien tech
  • Dyson Sphere Faction
    • Added a cosmetic energy cost to their portal
    • Antagonizer Energy 0 -> 50K
    • Bastion Energy 9K -> 50K
    • Bulwark Player cap 6 -> 8
    • Hackable Dyson ships now start at mark 2 so they can reach mark 7 if players invest in alien tech
  • HRF nucelophilic defender starts at mark 2 like the others (was mark 3)
  • Macrophage (and enraged) Energy 500 -> 25K
  • Nanocaust Faction
    • Cosmetic energy costs to Hive/Centers
    • Mutation Energy 25 -> 100
    • Anomaly Energy 25 -> 100
    • Deviant Energy 25 -> 100
  • Adjustments to the AI Warden Sniper Guardian
    • Broke off from being a copy_from into its own entity to finally remove some erroneous weapon bonuses that were not desired.

DLC2 Work

  • The visuals for the zenith miner doing its mining are now able to properly scale and coexist in the world of the game. Some of this was just adjusting the particle effects to be more responsive to changes in scale and view orientation.
    • The planet layer is now pulled forward when the zenith miner is mining, so that it is drawn in the main layer along with the miner itself This allows us to have the miner pierce the planet visually while also properly occluding objects behind it (it looked very strange otherwise).
  • Fixed a nullref exception that would happen if you were mousing over the Zenith Miner notification right when it exploded.
  • We have a new code structure that is able to have various defined effects on planets in the background background, either things like them exploding (a singular event), or ongoing items like a status effect (being a nomad, being near death from a miner).
    • This is now used both for planets that explode, and planets that are nearing death from the miner. You can see the sequence for that here (spoiler warning for DLC2!): https://youtu.be/7eRuGLyTa5A
  • Fixed two tooltip typos with the Zenith Miner.
    • Thanks to LordNSR for reporting.
  • Nomad Planets and Fimulwintered planes both now have visual effects that come onto their planets. These can be combined with other things, like a miner drilling them or it being a dyson sphere or whatever.

Balance

  • Fortress golem has reduced shot per salvo to 30 from 40.
  • Miner stat adjustments (both forms): Mass 11 tx -> 12tx; Energy 150K -> 500K
  • ZA Castra (and Phased form) start an mark 7 so they spawn appropriate units when aggro'd.
  • Updated CRC's nasty picks's stats to be consistent with Zeus's general balance sweep.
  • Hacking costs and response adjusted for a couple of the ZO hacks
    • ZA Quiesce is shorter, stronger response to compensate
    • ZA/DZ Cruiser hack has strong tertiary response. Made sure DZ cruiser hack limited to one
    • DZ library hack for non-cruisers has cap at 5 hacks. Hacks cost 25% more and generate 50% response per hack
  • DZ now has 20 possible hackable ships (4 units x 5 variants)
  • DZ cruiser library has sidebar name corrected

Bugfixes

  • Fixed an exception when viewing the high-detail tooltip info of ship types with Attrition damage limits when no actual ship and its stats but only the general information was displayed.
    • Thanks to LordNSR for reporting, and to NR SirLimbo for fixing!
  • Fixed a couple of rare nullref exceptions that could happen in GetHackingLevelMultiplier().
    • Thanks to slake-moth for reporting.
  • Fixed a bug that has been around for a few months where whenever you hack a non-ARS/TSS-style structure (usually alien stuff or other minor factions), it was not properly re-rolling the potential rewards that you could get for hacking a second time. This affected the dyson sphere in the base game, and a variety of things in DLC1 and 2.
    • Thanks to Zeus and others for reporting.

Mod Updates

  • Kaizers Marauders:
    • Fixed an improvidence where Marauders were calculating their exogalactic power response level in a bad way.
    • Before Marauders would reduce the final result (which depending on intensity could in theory be as high as 5) by 2 if allied to either a player or AI, and then again by the number of AIs. This would mean that Marauder empires allied to the player could get incredibly powerful, but face a disproportionately low response from the AI.
    • Now the required strength of Marauders to go up a power level is increased by 2x if allied to a player or AI, and then multiplied again by the AI count.
    • This means that it will correctly take Marauders longer to climb the power level ranks, but even in games where they are allied to players or AIs and/or face a high number of AIs they will be able to reach the upper ends of their response levels instead of getting capped.
      • Thanks to LordNSR for reflecting on their response levels in crazy high power games.
    • All the warping-in Marauder Outposts, Capitals and Superstructures now use warping-in effects.
  • AMU:
    • Fixed a couple of absolutely atrocious bugs in AJEA (Auto-Juggle Energy Assistant) claim-energy-cost calculations:
      • First of all it was only checking natural objects factions for things to claim, not also the player faction.
      • This padded a bug where it was not checking whether something was already claimed, which would've lead AJEA to free up energy for all energy-costing centerpieces the player owned, even those whose energy already is actively used.
      • Furthermore there was a bug where the loop going through all the potential capturables was using a false skip condition. It would only skip if the entity both had 0 or less energy cost AND not be on stand-down, which makes no sense whatsoever.
      • Furthermore there was a bug where the inner parts of that loop were also using wrong another, outer loop's index variable. In the best case this would've lead to wrong calculations. In the worst case it would've thrown an index-out-of-range exception and killed AJEA.
      • In this test case it now works and calculates properly.
        • Accidentally discovered in a save from LordNSR for an unrelated issue, but many thanks for that!

2.909 The Hunt Intensifies

(Released May 15th, 2021)

  • Buff Dire Gravity Guardian damage 1500 -> 2500 (royal variant 3000 -> 5000)
    • Thanks to Democracy for the suggestion.

Hunter Changes

  • Hunter Fleets now starts at 1 fireteam for difficulty 1, and goes up to 10 fireteams for difficulty 10.
    • This will allow them to focus their efforts more effectively, since previously you might have 20 fireteams and 3 teams just sitting around waiting to hit a really strong target. Better to let them focus their efforts.
    • Also, the hunter at lower intensities should be much more brute-force-only
  • Hunter is better at detecting when it's allocated resources are enough for one battle and and they should focus other units elsewhere
  • Improve the logic for Hunter Fleets getting lurk planets to be more efficient
  • Hunter fireteams now prefer to give units based on which fireteams are closest (and need units to activate)
  • Hunter Fleets unlock Dire Guardians a bit earlier on difficulty >= 7 (same for Warden Dires).
    • Slightly buff the Dire Guardian income ratio for hunters

Fireteam intelligence improvements

  • Fireteams now do a better job of realizing when they have enough strength to attack locally, and are more willing to attack early (even without all their ships) if they think they can win
  • Fireteams in 'assembling' mode will now run away if attacked; this should make it harder for players to snipe ships preparing to attack them
  • If fireteams are attacking a player planet, that faction's other fireteams become more willing to attack other planets owned by that player.
    • The hope is that this will allow for multi-front battles if the conditions are right.
  • When selecting fireteam targets, take only one target per planet. This costs a bit of memory ineffeciency, but it shortcuts a lot of work we might do so it should be a net performance boost.
    • If a planet had (say) an Economic Command Station, a Lost Energy Reactor and a player-allied scourge spawner then there might be a separate fireteam target for each of those generated by the selection code; this was causing the target analysis code to do extra work, and could wind up with fireteams overly focused on certain planets
  • add a game command to reset all the fireteams for a given faction. Intended for testing
  • Fireteam and Hunter improvements were motivated by a discussion with Strategic Sage

Visual Updates

  • Units that are in the process of warping in (this is in the base game and both DLC1 and DLC2, for various NPC factions) now have new visuals that they display during this period.
    • Any regular visuals that they have (shape) can be combined with the new warping-in effect simply by adding is_drawn_as_warping_in="true" to their unit xml. That has been done for all of the existing units.
    • This gives them a clear view that they are still warping in, and along with the icon status effect is a reminder to you to kill them before they finish arriving, if you can!
  • Ships that are phased out in either solo-phase or multi-phase now have unique graphics for during that state. They look shadowy and animated and intense, not mysteriously missing like they used to be.
    • This should hopefully help with confusion on the overlord phase 2, among other things. Certainly it's also relevant for the Zenith Architrave in general.
    • There were already tooltips and icon overlays and such, but this is the final piece to really make that come together.
  • There are now vertex-animated (wobbly, in other words) versions of the phasing materials, and still versions.
    • To make sure something absolutely will use the still version, set barred_from_vertex_animated_phasing="true" on it. This overrides anything else.
    • To ask something to use the animated version, use uses_vertex_animated_phasing="true". Various large ships and structures automatically set this behind the scenes, too. However, anything that is barred from using it will skip it no matter what.
    • Basically, some models will respond to this shader poorly and look very psychedelic. Those ones we simply bar from using it when we find them.
    • Thanks to NR SirLimbo for being so enthusiastic about this that we couldn't resist.

Major New Graphical Subsystem

  • We have a new "Assets/_FinalGameMeshes/BlankShipSoOtherAddonsCanDrawAlone.prefab" low-poly object that can be used for ships or units that are based on addons can instead draw in place of them.
    • The object actually is not invisible on its own, despite our attempts with the shader. Not on all hardware, anyway. So you can technically use any model, and then just use the new ship_skips_traditional_rendering="true" instead to make the ship not render the traditional way.
    • This is highly useful, because while for the vast majority of ships our DrawMeshInstanced dyanamic approach is far superior, there are certain things (particle effects, mainly) that just can't be done with that approach.
    • For those other effects, which are comparably rare, our goal is to blend those in as efficiently as possible -- and we've actually be doing that exact thing since the earliest days of AI War 2. Forcefields already use this approach, but a less-flexible one in terms of how the art is loaded and unloaded.
    • The addons framework can work with or instead-of existing types of art (and actually, our wormholes already use a particle system, too, but that's a bit of a different style in terms of how those work).
  • addon_object_or_particle_field="Whatever" and addon_object_or_particle_field_scale="3.5" (or some other floating point number) now allow us to add in these extra bits on arbitrary units, either in place of them (by using the blank thing), or in addition to them).
    • It's worth noting that ships that are drawn in this way take more CPU time to render, and so should be done sparingly. They also can't automatically work with status effects that would change their visuals, like phase changes, etc. Mostly this should be use for non-ships.
    • The whole point of this approach is that it is extremely unorthodox, and set up to work "however," and so it's very flexible in that regard.
  • Defined the first 10 "addon objects or particle effects," in a mix of the base game and DLC2.
    • So far it finds them and loads them appropriately into the complex new pooling structure that has been coded for them, but it doesn't deploy them yet.

New Warp Gates

  • New graphics are now in place using the addons and particle systems for the following units/structures:
    • Warp Gates (for the AI, base game). Super fancy now.
    • AI Reserves Spawn Points (again the AI, base game). Super fancy now, first time they have had graphics of their own.
    • Dyson Sphere Warp Gate (man it was ugly before, it was base game). Even more fancy now.

DLC2

  • Graphics for the Raijin golem in DLC2 are now integrated!
  • Voids, which are dropped by a thing dropped by the Voidpiercer Cruiser, now have their graphics fully integrated.
    • Voidpiercer Cruiser is now also fully integrated with its graphics. The Void Catalyst that it directly drops is not graphically in there yet, though.
  • Tempest Cruiser art integrated.
    • Also Riot Control Cruiser.
  • The Zenith Miner wreckage art is now integrated. It's super huge.
  • The traveling version of the Zenith Miner has also been integrated. It's even more huge.
  • Using the new "addons and particles" toolkit, we now have for DLC2:
    • A very large and menacing ZA Warp Point, which they mostly use in civl wars.
    • The ZA home portal is even larger.
    • The hacked version is super duper intense, but the same size.
    • The Zenith Miner that is actively mining a planet is kinda-sorta here, but it's not animating properly, scaled properly, or inserted into the planet as far as we want it to go. Investigation will continue on this tomorrow.
  • We now also have an addon_object_or_particle_field_y_offset="int" that lets us adjust the addons up and down as needed.
    • This doesn't yet work, for some reason.

ZO Balance

  • Miner's stationary range doubled
  • Major adjustments to the DZ difficulty tables
    • Low intensitites have relatively strong invasion but poorer economy
    • Moderate intenstities have medium invasion and economy
    • High intensitities have relatively weak invasion but richer economy
    • Skivari have a slightly different version of this change

Bugfixes

  • Fix a bug where scourge units would fly into your choke points heedless of their own demise
    • Reported by donblas
  • Suppressed a harmless error message (BUG: AnalyzeFriendlyToHostileBalance called with null targetPlanet) that could nevertheless cause an AI faction to shut down. The way the method returns is proper for basically sending the AI into a holding pattern until it gets a target planet.
    • Thanks to Zweihander2021 for reporting.
  • Put in one potential fix in GetAddedToFleetsForEntity() against an error that Strategic Sage experienced, and then instrumented the rest of that method so that if it happens again, we'll know where the problem is.
    • Thanks to Strategic Sage for reporting.
  • The nebula backgrounds and planet backgrounds now happen the same way each time on planets, versus being different between different runs of the same savegame (which was offputting and confusing).
    • Additionally, the planet visual status now gets applied properly even when the players have not yet unpaused the game.
    • This also properly now carries over to MP clients.
    • Existing saves must be unpaused for 1 second before it applies, but then after that it will stick properly.
  • The PrimaryInfluencingFaction is now saved into the planet's serialized data, even though this is "only" cache data.
    • This helps make sure that clients are as up to date as possible on the visuals that go with this.
    • This also makes it so that even when you load a savegame, you don't have to unpause and wait 1 second for territory of secondary factions to show up properly.
  • Deep-Space Anomaly Analyzers now always seed as AI structures
    • Previously they could sometimes seed as belonging to other factions (like the Dark Spire), which meant the AI would kill them and increase AIP
    • Thanks to a number of people for reporting, including Metrekec and ussdefiant60
  • Disabled the vertex animation part of the ship under construction and similar effects. On ships with very low poly counts (and so this would include distant LODs even for large ships), it went absolutely nuts in terms of just having too few vertices to work with.
    • We later brought that back in a limited fashion (see above).
    • Thanks to Democracy for reporting.
  • Fixed a bug with forcefields not disappearing after their shields were down in the last version.
    • Thanks to Democracy for reporting.
  • Fixed a bug from the last few versions (since the ship to ship lines rewrite) where various engineering lines and similar would not be visible properly after being added into the pool once and then the next time they should have been used they would be invisible. Was a good old fashioned case of forgetting to finish the code when very tired. Sigh.
    • This probably also affected tractor beams and similar, and claim beams, but it did not seem to affect beam weapons.
    • Thanks to donblas, RocketAssistedPuffin, Darkshade, and GreatYng for reporting.
  • Fix a bug where the 'prevent energy balance changes from wrecking old save games' code was kicking in on any game the first time you went into an energy deficit
    • This would be eligible to re-trigger each time you saved/reloaded

Huge Amounts Of Preemptive Code Hardening Against MP Client Errors

  • Updated dozens of places in the code that were either already prone to having MP-related cross-threading issues on clients, or which could in theory have those sorts of issues at some point in the future, or which could have those issues in even more-rare cases on AMD machine hosts/singleplayer.
    • Some of these were being hit, others just fit a pattern where it was just a matter of time, but these have all been updated to use new methods (with the word Safe at the end, and descriptive) that don't change the meaning of the code and don't require end-programmer defensive code.
    • Thanks to Tzarro for the most recent reports.
  • All references in the entire game that went directly from a ship/squad to FleetMembership.Fleet have been adjusted to use the newer cross-thread-safe methods. In total, this made changes in about 200 (maybe?) files, and probably over a thousand lines of code. Some of them never would have been a problem, others were just waiting for the wrong kind of processor/OS combo and just plain bad luck to set them off, almost but not entirely exclusively on MP clients.
    • This is a preventative measure that should cut down on future random MP errors drastically.
  • Hardened a couple of gnarly pieces of logic in ShipListerUtils that had not errored yet in MP for any clients, but it was only a matter of time.
  • Fixed a number of cases where a hack might verbalized a harmless error on an MP client, thus getting in the way of its execution and confusing matters, when really the host will just finish taking care of the hack and the client can just ignore those temporary lapses and carry on.
  • Further updates to any code that matched the pattern of ".FleetMembership." (minus the quotes) to finish hardening it all against cross-threading exceptions. With the other bits already hardened, this was down to just a few dozen instances left.
  • More code hardening, this time in the direction of ".PlanetFaction.Faction." and anything related, plus ".PlanetFaction.Faction,".
    • This is overall around 500 lines of code in over 100 files.
    • These were less common to error than the fleet stuff, but were certainly extremely common as a source of errors on MP clients and as cross-threading errors in general.
  • Fixed over 100 cases where code was too-optimistically referencing the results of GetControllingFaction() or similar on planets.
    • This was almost never a problem, but did lead to some cross-threading error possibilities, particularly on MP clients.
  • Fixed over 400 lines of code in 61 files where we could get nullref exceptions from trying to find the names of planets associated with various things. Most of these were extremely null, and may not have even been a possibility in terms of truly generating an error, but the revised code makes absolutely sure (mainly relevant for highly performance multithreaded MP clients).
  • Further hardened the code against some more cross-threading issues that were theoretically possible when drawing specific units.

DLC 2

  • Spawn a DZ Library variant that one can hack for a unique cruiser
  • Make SaveScum a bit less effective against zenith miners. There are still some save-scummable aspects, but they are a bit reduced
  • The Spire Hammer AI Type now has much more of a focus on spire ships.
    • Thanks to Zweihand's comments that there weren't enough spire ships
  • When doing the 'crash nomad planet hack' the game now provides a popout asking 'Which planet would you like to crash me into' and lets the player choose.
    • You can pick any non-player-owned planet. Crashing a nomad into a bastion/homeworld planet produces a full strength response; any other target produces a 1/2 strength response.
  • Add a new Journal for the Nomads explaining how the crash works.
  • Crashing a nomad into a planet now correctly triggers AIP increases
  • Drone Reclamator no longer comes with the hw command station -- meant to remove that after debugging it
    • T hanks Democracy for pointing this out!
  • "A Dark Alliance" QS no longers starts at x5 speed enabled. Didn't realize that would be saved
    • A few ZO testers encountered this, don't recall all but thanks!
  • Updated all QS to have custom faction colors instead of random. This makes a non-trivial difference to seeing what's going on, actually
    • Thanks to Marty651 for pointing this out!
  • Anti-DZ Dragons (and anti-fallen-spire dragons) no longer count as threat against the player
  • Fix a bug where ZAs would incorrectly flag themselves as Civil War Enabled in the esc menu

Mod Updates

  • AMU:
    • Fixed a bug in the Serialization of AMU's WrappedPlanetFaciton. The code was set up to serialize a bool whether it was null or not, and only if it was not null it would also serialize it's planet and faction indices.
    • However, it actually did the opposite: When it wasn't null it would serialize nothing more, and when it was null it would have tried to serialize -1 and -1 in an UltraEfficientStyle of 0-1023, which would cause it to fail.
    • Unfortunately since this is a bug introduced to Serialization and the data required to fix the bug was never saved this cannot be reconstructed. The erroneous saves are lost forever.
      • Thanks to Vaos for reporting.
  • Fixed another bug in AMU's FactionAllegiance base class where, after loading a save, it would cause the faction applying it to become friendly to literally everyone.
    • This trickled down into Kaizers Marauders and made a faction that's supposed to be the kings of piracy and scumbaggery pacifists. Blaaarrrggghh!
    • Luckily this time the bug was very simple and easy to fix, and it will not break any saves.
      • Thanks to Vaos for reporting.

2.906 Journaling Along

(Released May 13th, 2021)

  • Spire Engineering Center (in DLC1) is now called Spire Repair Center, as it otherwise implied it assisted construction like engineers. This caused a lot of confusion.
    • Thanks to ArnaudB for updating.
  • Add "The Swarm" quickstart to DLC1, an idea kicked around today in Discord.
    • 3 lower difficulty AIs with a powerful scourge, and a macrophage for the "bio" theme.
    • Thanks to donblas for adding!

Journal Entries

  • Add beginner journal entries for:
    • Low Threat
    • High Threat
    • Discovered AI Eye
    • Outnumbered
    • Discover Guards
    • Discover Citadel
    • Discover TSS
    • Discover ARS
    • Thanks to donblas for writing these!

Visual Updates

  • The temporal filter on the Amplify Bloom effect that we use in the game has been disabled. It was possible in rare cases (more common recently) to be able to essentially "overload the virtual optical sensor" with light data and get into an invalid tinted state.
    • Thanks to GreatYng for reporting it initially, and then we started seeing it shortly after repeatedly with work on the new content for DLC2.
  • The "under construction" shader for ships that are building is now updated to be more efficent (using the geometry queue rather than transparent) as well as being more noticeably animated.
  • The AI Dragon from DLC2 that gets spawned after Zenith stuff now has its own unique graphics separate from how dragons from DLC1 look.
  • Added a lot of code for attaching and removing and pooling and displaying "addon objects or particle fields" to ships, so that we can display things like the Zenith Miner eating a planet. This hasn't been tested out yet, but it also isn't being activated yet.
    • That will come tomorrow, as the art for that stuff is ready. This is a new general-purpose major capability for the game as a whole, and will allow us to do some other things also not related to ships (for instance, planet explosions or planet status effects that are visibly there), which will also be coming tomorrow.
    • Also coming tomorrow, assuming that this all works correctly, are some upgraded base-game graphics to use these new capabilities, specifically around the various incarnations of warp gate.
  • Also created new visuals for the different phase states of matter for ships (including some base game and DLC1 content that uses this), but it isn't applied to those ships yet. Again, that will come tomorrow along with a large batch of other stuff.

Bugfixes

  • Fix a typo in a game lobby setting
    • Thanks to schoenberg for reporting
  • Fixed a couple of different errors that could happen in our new "reorganize player fleet lines" sort code.
  • Fix fleet memberships to sort by name if their strengths are equal in the end.
  • Fix a bug where journal entries that were "blocked" in XML were not correctly being blocked
    • Thanks to donblas for reporting.
  • In the event that one material can't be drawn, the game no longer freaks out any stops drawing all materials. It now gives you an error about that (once per run of the game per material name), and then just stops drawing that thing. It will be a drain on performance while this is happening, but won't cause things to look drastically wrong.
    • Previously these errors were only going to ErrorsReportedByEngine and were not very visible. We also almost never have these, but with making new art additions it can happen, usually on internal builds.
  • Correct an off-by-1K cost measurement for display purposes
    • I forget who reported this
  • Self Attritioning Ships (like tesla torpedoes) no longer give the Dark Spire energy
    • Reported by Tzarro
  • Add some defensive code to the Faction class for a weird exception I saw just after the game loaded
  • Fixed an error in the XML loading of the game where the required_expansion_list XML field did not get respected if the expansion required did not even exist in the player's game files.
    • This could cause massive issues if trying to load a mod that hat content locked behind DLCs but would fail to load if said DLCs was not bought.
    • In one case of Extended Ship Variants it was crashing the game in such a way that it would not even load to the main menu to disable the mod again.
      • Thanks to Zweihand and Charge for the report, and especially Charge for helping to debug this and testing out the solution. And thanks to NR SirLimbo for finding this in the code and fixing it!

Balance

  • Adjust the weapon ranges on a couple reflex weapon systems. They aren't actually used, but display on Z hotkey ranges. Should cut down on confusion a little.
    • Thanks to CRCGamer for adjusting.
  • Assigned command station techs as secondary tech branch to strikecraft hangar system defenses.
    • Military Command for the Bomber and Shrike Interceptor hangars.
    • Logistical Command for the V-Wing hangars.
    • Economic Command for the Metabolizing Gangsaw hangars.
    • Thanks to CRCGamer for adjusting.
  • Additional tweak to Attractive Matrix Fortress reflex weapon listed fire rate to be once per second. Cosmetic change since its actual fire rate is based on how quickly its being shot.
    • Thanks to CRCGamer for adjusting.

DLC 2

  • Fix a minor typo with the Reclamator
    • Thanks to Strategic Sage for reporting
  • If the scourge want to send a unit to a random metal generator on a planet that's been ravaged (thus, no metal generators) they will instead send units to a random location on the planet
  • Ambush Mines now have MUCH higher priority. These do nothing unless killed so these need to be preferred targets
  • Finally fixed the Drone reclamation drones (they weren't launching before). They now have a weak weapon jam in addition to their metabolism
  • Voidcaller Outguard now has true invulnerability (so it doesn't kill itself when attacking elecrtoxic units. It's event horizon AOE has been reworked so it's more likely to pull units all around it instead of in clumps
  • Voidpiercer's Void has AOE rework for same reasons
  • Ethereal Cruiser balance changes:
    • Ion Disintetegator paralysis now works on mass tx <13 (was 50). This is meant to affect most everything, but Tier 4 and 5 exogalactic units are immune
    • Base damage of Ion Disintetegator 50K -> 5K but now gets muliplier of x1 per 1tx, capping at x15 -- this means its still a solid ship to chip away at even the Flenser
    • Burst fire reversed so it starts with the burst and then has cooldown
  • Fixed minor typo with the Drone Stockade

Zenith Miners

  • When the Miner ravages a planet, it now correctly updates the planet graphics
  • Zenith Miners are now 50% ravage planet, 50% completely destroy planet, so we can show off the awesome Ravaged Planet graphics more
  • Improve some miner tooltips
  • Miners will also appear on player planets later into the game
  • Miners will not revisit a Ravaged planet
    • There's nothing left to eat!

Zenith Architrave

  • The ZA civil war is no longer the default. You must enable the civil war for >= 2 ZAs in the game lobby to see this behaviour.
    • I'm worried that newer players (or those who skim tooltips) will enable >= 2 ZAs and get crushed by the Civil War in an unfun fashion. The Civil War is much more for advanced players I think. It's very different to everything else in the game, so this makes me think it should be opt-in.
    • The other major problem is for a player in a constricted map type (Snake? X?) who gets a home planet between two ZAs that enter civil war. If there happen to be no other paths between the ZAs, you could easily die without any counterplay.
    • Or if you took an MDC on a planet in a a choke point and the ZA comes through and kills it (or your defenses protecting it), that just seems unfun
  • To compensate for losing the civil war, ZAs in non-civil-war mode will be much more aggressively expansionistic once they take a few planets; the more planets they take the more Pioneers they spawn (to a max of 6).
    • The hope is that players are motivated to go and kill non-Territory spawners to prevent the ZA from overrunning their territory. Or they can hope the AI's spawned Exogalactic War Units will keep the ZA suppressed.
    • This is not quite as impactful as a civil war, but it should keep the player interested in engaging with the ZA.
  • This also constitutes a buff to a lone ZA (though the player could enable civil war for a single ZA to use the old pioneer spawning rate)
  • Crupellarii retaliation changed to a flat riposte of 50 damage at mark 1 from a 20% damage mirror
    • ZA phased Cestus were inheriting an auto self-destruct from their parent. Reworked to give this back its intended vampirsm.
  • New Zenith Architrave Cruiser! The "Spartacus" cruiser integrates the mysterious phasing properties common to the Architrave periodically phases to and from Multi-phase. In realspace, it is equipped with three phaser weapons, which all phase targets with no shields and low energy usage. Its spiderweb phaser has planetary range and only hits mobile targets, stunning their engines and reeling targets towards itself. Its ionized phaser is short range and designed to quickly wear down shields to enable the phasing effect. The phasion bombs it launches completely bypass the shield prevention but can be destroyed in flight. While in Multi-Phase, the Spartacus Cruiser switches to its vorpal beams that wreak havoc on weakened ships and launches phased Cestus drones that are permanently in Multi-phase.
  • The ZA Castras can now be hacked for ZA units, as well as the portal
    • The goal is to give the players more carrots to interact with the ZA; you can now build a giant fleet of ZA ships if you're willing to spend the hacking poitns
      • Suggested by zeusalmighty
  • The ZA can now have their civil wars turned off
    • This setting is on a per-faction basis, so you need to apply it to all of them
    • This means that the Non-Civil-Warring ZA will just expand independently of any other ZAs.
    • I know I will want to play some games with multiple ZAs, but without their giant impact on the galaxy during a civil war

DZ / Svikari Changes

  • Jormugander base damage from 10K to 12K (per beam)
  • New Dark Zenith Cruiser! The "Gungnir" Cruiser has a weaker version of the Jormugander's annihilator beam, but still incredibly powerful. It is also equipped with a harpoon launcher and a seeker bomb launcher, the former that can immobilize even the most massive of ships and the latter that sends slow accelerating projectiles that do devastating damage if not shot down in flight. The hull is made of an electrotoxic substance favored by the Dark Zenith that will instantly return feedback to the Gungnir's attackers, causing attackers to take damage proportional to the damage taken by the Gungnir.
  • some major adjustments to the DZ that need further testing. But the general idea is that the DZ's invasion interval was set super low so they were getting free ships every few seconds. This interval has been increased dramatically
    • Made some additional adjustments to go with the interval tweaking. Basically, lower intensities generally gain a larger initial invasion because their interval for ships is longer. They need to still be able to invade after all
    • DZ gain more epistyles/terminii with intensity. Shifting their power away from their initial invasion towards their infrastrucutre
  • AI Zenith Dragon Changes:
    • Chain lightning fires every second (instead of every 4 seconds). Now deals full damage to secondary targets instead of 20%
    • AI Zenith Dragon has new overlay as a chain lightning eye)
  • The fimbulwinter enable/disable setting is now a boolean toggle instead of a dropdown. Much easier to work with.
  • If the fimbulwinter is disabled, the DZ planets that warp in are not Fimbulwintered

Mod Updates

  • Mod Updates:
    • AMU:
      • The base types for Cruisers and Destroyers do not load unless DLC 2 (for Cruisers) and DLC 3 (for Destroyers) are installed, will no longer confuse the game into thinking that there are cruisers and destroyers are in the game to populate the Cruiser/Destroyer Construction Facilities.
      • Along with the bug of required_expansion_list not always correctly working this was causing MASSIVE slowdown and an exception at the start of the game if players had the Exotic Ships mod installed, rendering the mod effectively unplayable.
        • Thanks to cml, LordNSR and Charge for reporting, especially Charge who helped to debug this as I was entirely unable to get the error myself.
    • Kaizers Marauders:
      • Adjusted the Raid Seeker, Raid Carrier and Raid Blaster no longer inherit from AMU's Cruiser prototype, instead they now inherit from the Heavy Prigate prototype so the mod can work without DLC 2.
    • ExS:
      • Void Weavers now try to go into melee range to attack so they actually use their zombification in Multi-Phase.

2.905 Alien Homes

(Released May 11th, 2021)

  • Fix a bug with a yet-unwritten journal for Raid Engines
    • Thanks to GreatYng for reporting.
  • The shape of the ODSS icon has been adjusted to be more distinctive from the TSS, and neither rely on an overlay anymore.
    • Thanks to Zweihander2021 for reporting.
  • Fixes the music debug menu so that tracks the user switches away from are no longer deleted from the list
    • Thanks to GreatYng for reporting and Dominus for fixing.
  • Fix a bug where command stations that grant their turrets bonus attack power weren't correctly factoring in that bonus power when doing strength calculations.
    • This lead to the game woefully underestimating the strength of units on high-mark military command stations.
    • From a discussion with a number of people on discord

DLC 2

  • Make the DZ a bit more efficient at consolidating their initial invasion gains
    • Thanks to zeus for reporting
  • The icon for the Vengeful Sniper Array has been updated to no longer look so similar to the frigate icon.
    • Thanks to Zweihander2021 for reporting.
  • Planet visual definitions no longer have a do_not_randomly_seed="true" option.
    • Instead they have a sub_seed_tag="SomeText", which accomplishes the same thing but ALSO puts them into a group of planet definitions to randomly seed for whatever the occasion is.
    • This can be used by mods or otherwise to trigger specific planets for specific purposes.
    • Please note that each planet definition only can have a single tag. You can make copies of the definitions if you need them in more than one tag (which seems unlikely in the first place).
  • The same sub_seed_tag="SomeText" has been set up for "space boxes" (aka nebula sky backgrounds).
  • You can now call SpaceboxDefinitionTable.SetSpaceboxDefinitionByTag(), or PlanetDefinitionTable.SetPlanetDefinitionByTag() to have the host set the visual stylings for some planet's faction by whatever logic you want, and it will properly sync any changes to clients.
    • This can be called serially, every frame, because it basically looks for if the tag of the current thing doesn't match, then set it to one of those things that has a tag that is matching (if possible).
    • Hint to modders: you can actually look at the various spaceboxes that we have, or planets, and just pick a subset to copy with a given tag and then assign it like you see us doing for the DZ, ZA, and Dyson Sphere. You can then have a unique feel for your particular faction's space, whether you actually are creating original art or not. Maybe you always want really dark or light or blue or red or whatever type nebulas for a given faction, etc.
  • There is an IsRavaged property on planets now, so that when one gets ravaged it won't compete back and forth with any factions for what graphic should show. It will show ravaged.
  • There are now special nebula backgrounds assigned to all of the DZ and ZA territory in DLC2.
    • There are special planet graphics assigned to DZ plnets, and the ZA home planet in DLC2.
  • Planets that are ravaged by a Miner in DLC2 will now show it in a dramatic fashion. This includes ones from savegames prior to this build.
  • Added a new AddonObjectOrParticleFieldPrefab table, which will be used for defining secondary effects, including particle effects, for specific ships (like the Zenith Miner). The code is about halfway complete.
  • Big thanks to Puffin for the new backgrounds used for the DZ and ZA!

New Mod: Exotic Ships by SirLimbo

  • Added a new mod to the game: Exotic Ships.
    • This mod adds ships with both potent and complex mechanics, synergies and playstyles.
    • Even without DLCs a total of 17 new ships and new 6 starter fleets are available.
      • Mechanics involve ships that revolve around Forcefield Piercing, Gravitic Cores, Tractor-induced bonus Damage, Acid, Repair Beams, Norris effect, Shield Implosion, Structure/Ship-specific Weapons and more...
    • If DLC 1 is enabled an additional 8 ships and 4 starter fleets are unlocked.
      • Mechanics involve ships that revolve around Forcefield-induced bonus Damage, Damage Harmonics, Range Harmonics, Von Neumann, Drone Guns, Attrition, etc...
    • If DLC 2 is enabled an additional 12 ships and 4 starter fleets are enabled.
      • Mechanics involve ships that revolve around Shot Attraction Fields, Chain Lightning Guns, Classical Hydra-Head Spawning, Revenge-Firing weapons, Electrotoxicity, Chain-Firing Weapons, various State-Of-Matter changes, etc...
      • All of these ships, with exception of the FRS ship lines have lower chance to seed than normal. In general only about 50% the rate in Transports compared to all other ship lines, and in ARSs only 5% compared to normal ships, which equals 50% of ship variants. Thus Exotic Ships are quite rare. The exact quantity is up to chance and potential other mods which add ships, such as Extended Ship Variants.
      • In return these ships can be very powerful and have sometimes evil mechanics to exploit. The presence of 2 or 3 Exotic Ships can make tech investments worth that were not considered before and allow for new strategies and ship counters against all factions.
      • The starter fleets usually consist out only 3 lines: 2 Strike Craft and 1 Frigate. One of them is just 2 Light Frigates. However, due to the power of Exotic Ships they are not underpowered in the slightest.
      • In all likelihood a good number of games will be required to acquire and play with every Exotic Ship at least once.

2.904 Dragon Hotifx

(Released May 11th, 2021)

  • Fix a bug where the 'Hack an ARS' achievement wasn't firing
    • Thanks to Atia on discord for reporting
  • Three new Guardians from CRCGamer uniquely for Warden fleet usage are added to the game. They are currently only available to the DLC2 AITypes that get new ships (Beast, Gladiator etc...) for balance testing.
    • The intent is to give the warden fleet some unique and distinctive units like AIWC's riot fleet; these are Warden Fleet only ships.
  • Fix some outdated text for the Exotic Text
    • Reported by Atia on discord.
  • Turrets now self-build in 90s no matter their metal cost. Small turrets were built in 60s, large ones in 150s and a number of odd costs turrets were either faster or slower to build. This is no longer the case.
    • This time is unaffected by being on a hostile planet, and doesn't count engineer support.
    • Raid turrets build 2x faster than others turrets, so 45s self build. This no longer change based on their cost, which led some turrets like scrap to self-build in 20s, or makeshift in 15s.
    • Thanks to ArnaudB for adjusting.
  • Command Stations self-build times reduced to 20 from 60. Mostly a QoL change, so if you don't have Engineers around when blowing up a station, you have much less time to wait before you can queue buildings.
    • Thanks to ArnaudB for adjusting.

DLC2

  • Improve some DZ targeting to prevent them from charging off after some minor factions early game
  • Fix a bug with the new DLC2 dragons with DLC1 and DLC2 enabled

2.903 Journals For Miles

(Released May 10th, 2021)

Bugfixes

  • Fix a typo in the Cursed Golem hacking screen and the Botnet decription, as well as one in the Exogalactic War Unit tips
    • Thanks to GreatYng for reporting these
  • Exos should never be able to actually spawn using relentless AI wave logic anymore. Even if that is requested, the data should be self-correcting now. So this should never cause an exception that shuts down the AI faction, unlike recent builds.
    • Thanks to Strategic Sage for reporting.
  • Fixed several issues in AnalyzeFriendlyToHostileBalance() that could happen as cross-threading errors even in single player, causing the AI sentinels faction to shut down. This was quite rare.
    • Thanks to Strategic Sage and GreatYng for reporting.
  • Experimental change: In order to avoid cross-threading errors in a proactive fashion, have added a new SpeedGroup.Dummy, which is basically the same as being null, but without actually being null. Rather than assigning to null when we are done with a speed group, we can assign to SpeedGroup.Dummy.
    • This does mean that in places where we are looking at speed groups to see if they are on, we now have to also make sure that IsDummy is false, but that is comparably rare and overall this frees us from the worry of having a null check on SpeedGroup be false in one line of code, and then in the next line of code it is suddenly giving a nullref exception because of the reassignment from another thread.
    • This is kind of the opposite of our usual approach to dealing with cross-threading exceptions, and it's an interesting initial case study on a fairly limited-use class. If things seem okay with this, then we could in theory make dummy planets, planet factions, factions, etc, so that we don't run into cross-threading NRE's from them and yet don't have to code so defensively all the time. We'll see.
  • Fixed an issue where if a flagship was crippled while in transport-load mode but did NOT have any ships inside it, then it would get stuck in that mode and the ships in its fleet would not respond to orders. If the flagship had ships inside it when it became crippled, then it would work properly, so this took some specific timing.
    • Thanks to aliyah for reporting, and Badger for figuring out what it was.
  • Fixed some cross-threading exceptions that could happen in AlterLODIfNeeded().
    • Thanks to zeus for reporting.

Multiplayer Fixes

  • Fix to the "InternalCreateActualShotForSalvo error at debugStage 4200" error on MP clients.
    • Thanks to Badger and his MP play group for reporting.
  • DumpFleetContentsIntoFactionLoose() is no longer allowed to be called on MP clients. It was possible for it to error sometimes, but even if it was not erroring, it was probably not doing the correct thing (because it was probably just missing some data in a transient fashion, and then mis-filing units).
    • When it comes to the fleets that were continuously losing all their information and then gaining it back, the client machines calling this method (even without errors) may have been a big part of the culprit.
    • Thanks to Badger and his MP play group for reporting.
  • DestroyFleetContentsAndWriteLog(), DestroyFleetContentsSilent(), RemoveAnyEmptySlotsPresent(), DespawnAllContentsFromSwap(), SetAllMembershipsUpFromDesignTemplate_FullCapOverwritingNotAdding_AssumeNoDuplicates(), InnerHelper_FillFromOneTemplate(), InnerHelper_FillFromDrawBagType(), InnerHelper_FillFromDrawBagType_FullCapOverwritingNotAdding_AssumeNoDuplicates(), and various things related to destroying extra units because of the count in place being higher than the ship cap are all no longer run on clients.
    • These are important things on the host, mainly for data correction and finding data that is stale for some reason (it matters in SP, too). But for clients, their data is often slightly stale, so acting on it will only make it worse. They'll find out real info from the host soon enough, if data is stale. They don't have the information needed to make corrections on their own.
  • Fix to the "BuildSidebar.OnUpdateDirectPlacement error at debugStage 8600" exception that could happen on MP clients.
    • Thanks to Badger and his MP play group for reporting.
  • Fixed the "BuildSidebar.OnUpdateDirectPlacement error at debugStage 2300" error that could happen on MP clients.
    • Thanks to Badger, Bummeri, KaleR, Jusa, and Exlium for reporting.
  • Fixed "DoShotHitLogic error at debugStage 2200" error that could happen on MP clients, although did so in a rather brute force way.
    • Thanks to Badger and his MP play group for reporting.
  • Fixed the "DoOnAnyDeathInCombatLogic_AfterFullDeathOrPartOfStackDeath debugCode 2100" error that could happen on MP clients, and which was mainly related to things that spawn on death of a parent unit, or stack handling, etc. Does not need to happen on the client.
    • Thanks to Badger and his MP play group for reporting.
  • The "During placement: fleetMembershipForType == null!" error is no longer a hard error, but rather just does a soft (invisible) log to the debug log. If we see this a lot, this is a problem, but this seems to be exclusive to some sort of client and host miscommunication right now, so we're just going to monitor it and not let it get in the way of other operations.
    • Thanks to Bummeri, KaleR, and Jusa for reporting.

Journal Enhancements

  • Journals can now be triggered when the player has forces on a planet with a specific unit type (using only XML). There are two classes of these entries, "normal" and "high priority".
  • High priority entries are always played immediately (AI Eyes, etc).
  • Normal Priorities are throttled to play once every 30 seconds, though this throttling can be undone (or modified) by changing a single C# value.
  • The High vs Normal priority is because I was concerned that a new player who starts adjacent to a planet with a TSS and ARS will be overwhelmed by immediately getting 3 journal popups ("How to deal with Guards", "How to deal with an ARS", "How to deal with a TSS"). If we wall-of-text someone immediately it's not great.
  • To make a unit emit a Journal entry, you take the unit type XML you want to have a journal entry for and apply the following fields:
    • journal_name_to_play_on_player_encounter # xml field with the name of the journal entry you want
    • journal_high_priority # xml field with 'true' or 'false'. This is for high Priority entries
  • New beginner journal about AI Eyes.
  • New beginner tips for how to spend science beyond just the tech tab!
  • Added is_blocked_from_triggering="true" as an option on journal entries, so that if we have ones that are defined by the programmers, but don't have text yet, we can put them in place without them firing with placeholder text.
    • Currently applied to:
      • Orbital Mass Driver
      • ARS
      • TSS
      • Guard Units (as a concept on an enemy planet)
      • Threat (high) (when there's a ton of enemy threat)
      • Threat (low) (when there's a some enemy threat, but not a ton yet)

Game Balance

  • Nerf to shot attraction range of Bulwark turrets from 6000 to 3500.
    • Unfortunately as a small turret type that is readily available the amount of coverage these were giving was too generous. And certain structures protected by entire nests of these were far more durable than the AI could reasonably deal with at lower AIP. Thus certain baits were a bit *too* effective.
  • Minor stat adjustments to the Dragon (now called "Spire Dragon" to distinguish from the "Zenith Dragon" that appears in response to the Dark Zenith invasion)
    • armor 140-> 350mm; energy 15K-> 150K; mass 7tx -> 11tx

DLC 2

  • Add some defensive code to the ZA Civil War
    • Reported by a number of testers
  • Fix a null reference exception when hovering DZ units in a wave
    • Thanks to donblas for reporting
  • The Geneticist AI type now has more of its scourge units vulnerable to zombification
    • This way zombifying player units are more useful against it. Playing Zombifying Starting Fleet into Geneticist was awful
  • The Spire Hammer AI type has had a unit rebalance
    • Thanks to crcgamer for the changes

DZ / Svikari Changes

  • Seeker bombs now increase in stats per mark, but base damage decreased significantly. Jormugandr's seeker bombs now start at mark 7.
  • Jormugandr now has regeneration -- repairs to full health in 30 minutes (from 1 health)
  • Exo strike directed at Jormugandr from 500 -> 350 strength at all intensities. Jormugandr shouldn't be killed by these but should take a considerable amount of damage (and then repair in time for the next one)
  • Merkismathr time before phasing increased from 20 -> 30 seconds. It was just able to avoid too much damage and getting too much value out of its ambush bonus
  • Nerfed electoxic effects of guardian tier units and up
  • Jarl will be more likely to spawn a Dreng before killed
  • DZ 10 exostrike every 20 min (up from 15)
  • increased time of Jormugandr rampage on diff 5 and up
  • Significant improvements to how efficiently the DZ distribute its resources
  • In the Dark Zenith Difficulty xml, the game can specify how many "Anti-DZ Dragons" will be spawned when the DZ invade. The lore is that the AI is strengthening itself against the new DZ incursion.
    • The Zenith Dragon has a powerful chain lightning attack instead of the coilbeam, as well as a weak (5%) elecotoxic retaliation
    • The player should need to take risks and reach a higher power level in DZ games. If they can just quickly snipe the AI to avoid dealing with the DZ (and thus not actually experience anything not in the vanilla game), that's as not interesting.
    • From a discussion started by Strategic Sage

ZA Balance changes

  • The ZA now has a new XML setting for its Difficulty; MaxSpawnerMarkLevel
    • Requested by zeus
  • adjusted the new "max mark level of spawner/portal" for each intensity.
    • Intensities 1-4 cap at mark 4.
    • Intensities 5-6 cap at mark 5.
    • Intensities 7-8 cap at mark 6.
    • Intensities 9-10 cap at mark 7 (so really, no cap)

Spire Hammer AI type changes

  • Significant balance changes to Spire ships utilized by Spire Hammer AI type overall these should make the smaller standard Spire ships utilized by this AI feel less like paper tigers.
    • AI Spire Frigate changes:
      • Strength multiplier removed
      • Base health raised to 90000 from 35000
      • Base shields raised to 45000 from 18000
      • Base damage reduced to 7500 from 15000 per shot
      • AI purchase price raised from 1000 to 2250
    • AI Spire Destroyer changes:
      • Strength multiplier adjusted from 1.4 to 1.2
      • Base health raised to 200000 from 70000
      • Base shields raised to 100000 from 35000
      • Base damage reduced to 25000 from 40000 per shot
      • Damage multiplier of 3x against large targets adjusted to kick in at 5tx instead of 7tx. This means the bonus is far more generally applicable against players since normally only command stations and centerpieces of the player meet the previous threshold.
      • AI purchase price raised from 1800 to 5500
    • AI Spire Fortress change:
      • Strength multiplier of 2 added. This thing does a disgusting amount of damage at high range with a coilbeam and was under-representing how dangerous it actually is.
  • Thanks CRCGamer for the above changes!

Mod Updates

  • AMU:
    • Now has a new Rollup for all DSAAs.
    • Fixed some bugs in AMU's Faction Allegiance management:
      • No matter whether or not the faction has a team, is allied to any Player or any AI the FactionAllegiance now also correctly saves all other data (such as allied to players, AIs, traders, etc). In theory simply always saving the RelatedFactionOrNull would be enough, but this way it forward-fixes any other potential exotic faction allegiance states causing trouble.
      • Tested out these changes and found out that this Marauders in a test case would STILL go hostile to the player if Kaizer was present, even when they have no reason to.
      • Fixed another bug in the SmartFactionImplementation where Allegiances would always be overwritten even if correctly serialized. This was a leftover from when the OnDeterministicThreadOnly_DoInitialLogic function would happen BEFORE deserialization.
        • Both of these combined now fix Kaizers Marauders in games with Kaizer present going hostile-all-except-other-kaizer-allied after loading a save, even when they shouldn't.
        • Unfortunately saves with broken allegiances cannot be repaired because the required data just wasn't stored. They won't fail to load, but allegiances are permanently wrong.
        • It's still not a good idea to trust your Marauder allies...
          • Thanks to LordNSR for stumbling upon and reporting this.
      • The variable TeamIsMinorFactionTeam is now correctly renamed to IsInAnyTeam. This was no bug, but simply false.
    • The DynamicAveragingRing now is serializable and inherits from SuperBasicSerializable.
      • It has saveAverageOnly (required in constructor). If enabled the DAR will only save the average value, which is much more efficient in data size. If disabled it will save every single variable contained and be as correct as possible.
      • Note that only the same save-style DAR can be loaded.
    • Executor Work:
      • Fixed a number of bugs for OnAnyDeathExecutors_HostAndClient and their tracing.
      • Added a new OnSpecialActionExecutors_HostAndClient using the new DeterministicSpecialActionExecutor.
      • Fixed the ExecuteOnlyOnce mechanic not actually applying anywhere, it was simply forgotten to implement it.
    • Fixed a few bugs in AMU's wrappers for Factions, Planets and Planet Factions where all of them could not serialize them being null. I'm honestly surprised that didn't crash everything sooner.
    • The Global Variable Overwriter now uses the above logic for better performance:
      • Instead of executing the code at game start and once per second it now executes at game start and whenever the settings are changed. This means it'll be much more efficient.
  • Kaizers Marauders:
    • Using the new DSAA Rollup from AMU Player-allied Marauders will now target any hostile DSAA that doesn't produce AIP on death. Non-Player-allied Marauders will target any DSAA.
      • Thanks to LordNSR for noticing that Marauder units were targeting the Raid Blaster, Kaizer had the same problem (his credit was missed in the last patchnotes, sorry). This is stage 2 of the adjustment.
    • Changed the wording in the Galaxy Settings from Kaizers Marauders (Multi-Planet Settling and Healing Allies) to be more clear, and correct English (hopefully).
      • Thanks to LordNSR for reporting. This must've been written in one tired night...
    • Fixed (Warping-In) Marauder Capitals mentioning GCAs.
      • Thanks to LordNSR for reporting.

2.902 Rather Refined Ghosts

(Released May 8th, 2021)

  • At the bottom of the quick start menu, and the campaign lobby, there is now a Campaign Type field.
    • This only lets you choose Humanity Ascendant, but it explains about the upcoming Expert and Deathwish modes. For now it does not mention Sandbox.
  • In the Planet sidebar, there's now an option to show your allies Fleets under Watched/Local fleets
    • This option is only available in multiplayer
    • Being able to track what all your allies are doing can be very useful, especially for more experienced players helping newer players
  • Add a 'select all engineers' hotkey. This is unset by default
    • Suggested by JordanK and aliyah
  • Add an 'Advanced' option to the Dark Spire preventing them from spawning Loci.

Help For New Players

  • Add a few tips of the day from Discord.
  • "Advisor" journal entries are now "TIPS" journal entries, and are shown with a bright light blue color regardless of what your faction color is, for maximum visibility.
    • We really want new players to notice when there's a new contextual tip for them, and not mistake it for being bossed around or for other info that might not be pertinent.
  • The hacking tab tooltip now says "Hack Target At Planet" rather than "Hack Enemies," since you might hack allies or even your own stuff (generally your stuff is from a different screen, but that's not always going to be true.)
    • It also says "Hacking is done with flagships at the same planet unless otherwise specified. Some very powerful hacks are done on your own fleets, in the fleet details window on the fleets tab."
    • Thanks to Vincent for inspiring this change.
  • In the tooltip for hacks, it already specified what kinds of ships could do the hack for every given hack (they're all flagships of some sort, but it really does vary a lot).
    • This information is now shown in a bright green color, and has been reworded to be more concise and clear.
    • Thanks to Vincent for inspiring this change.
  • Improve the spire campaign first journal entry to press upon the reader how dangerous it is.

Balance

  • Carrier Guardians, Shredder Guardians, and Teuthida Guardians are now disallowed from spawning in waves. These are all drone-producers that can wind up being far stronger than the wave warning would lead you to expect.
    • Thanks to Strategic Sage for suggesting, and aliyah for reporting the initial problem.
  • A number of balance adjustments to starting turret counts on some of the battlestations and command stations.
    • Thanks to ArnaudB and CRCGamer for sorting this out.

Bugfixes

  • Add some defensive code when deploying a wave composition
    • Thanks to slake-moth for reporting
  • Exos are no longer allowed to use Relentless Waves; if they use the Relentless Wave faction then they don't behave like Exos, but do behave like waves
    • If we want the ability to summon waves like we do Exos, that should be it's own thing, and I for one thing it would be useful.
    • This was causing a number of code paths to drop a mini-wave instead of any exo, like hacking. Buff the exo response to hacking as well, since it was very low.
  • Fixed a very weak memory leak that could happen when you were reloading all the data types (changing expansions or mods that are enabled, but not restarting the game) in entity order pools.
  • Recoded the way "ship to ship lines" are drawn from one to another, which improves performance and also fixes a rare memory leak (that was becoming less rare), and which was a huge amount of code to the point it makes me nervous. Once this seems not-glitchy in our internal version, then we'll probably do a day of beta just to be sure. Depending on how solid it seems.
    • Overall this is great for performance, and it has a major positive effect on how correct and impressive chain lightning looks, too.
  • Fixed a rare exception that could happen in CopyShortTermFramePlanningDataIntoSim and absolutely kill the simulation until it was restarted. Not sure how new this was.
    • Thanks to Tzarro for reporting.
  • Improved the efficiency of ship-to-ship lines that occur on distant planets in all cases in MP, and for non-weapons cases in single player and MP.
  • Fixed a cross threading bug that could occur in the Dark Zenith when they were trying to move to a harvester but the harvester died or was removed. It now tries once more and then just gives up until next cycle if that's going on.

Multiplayer Fixes

  • With the build sidebar open in multiplayer, it was apparently possible to get some errors as a MP client on an AMD machine. We unfortunately have not fixed it, but we have put in instrumentation to localize the error's impact, find out where it is further (with the next user report on BuildSidebar.OnUpdateDirectPlacement errors), and then move to a full fix once we have that added info.
    • Thanks to Aidalee, Vincent, Bummeri, KaleR, and Jusa for reporting.
  • Fixed the cross-threading "DoEntitySecondLogic for LogisticalCommandStation debug code 161" error that could happen on MP clients. We had gotten all of them in that method but missed this one.
    • Thanks to Aidalee and Vincent for reporting.
  • Likely fixed the "Error in PerFrame_CalculateEffectiveFleetData, debugStage 800" exception that could happen on MP clients, but if not it is at least much better instrumented and all the obvious possible causes are fixed.
    • Thanks to Bummeri, KaleR, and Jusa for reporting.
  • HandleTransportsSim for the DZ no longer gets run on MP clients, as that was able to cause exceptions and was also not needed in the first place.
    • Thanks to Bummeri, KaleR, and Jusa for reporting.
  • Fixed a few dozen potential (but rare) cases where tooltips could error on MP clients if the client hovered over a unit at just the wrong time.
    • Thanks to Bummeri, KaleR, and Jusa for reporting.
  • ConvertEpistylesToPirate for the DZ no longer gets run on MP clients, as that was able to cause exceptions and was also not needed in the first place.
    • Thanks to Bummeri, KaleR, and Jusa for reporting.
  • HandleUpgrades for the DZ no longer gets run on MP clients, as that was able to cause exceptions and was also not needed in the first place.
    • Thanks to Bummeri, KaleR, and Jusa for reporting.
  • Fixed "DoEntitySecondLogic debug code 161", which could happen on MP clients.
    • Thanks to Bummeri, KaleR, and Jusa for reporting.
  • Put extra instrumentation into InternalCreateActualShotForSalvo() to isolate MP cross-threading errors, and put in defensive code for the most common possible cases.
    • Thanks to Bummeri, KaleR, and Jusa for reporting.
  • Fixed a major longstanding client-side bug in multiplayer where two copies of a ship/structure/unit could be created by mistake, and this led to lots of client confusion and ghosts and explosions of not-ghosts and so on.
    • Essentially what was happening is that sometimes the general-purpose client sync data was getting there before the "fast blast" data, which was not something I expected would ever be possible... but is. By simply making the fast blast data check to make sure it doesn't already have this entity (and thus update that one versus creating a duplicate), this fixes the bulk of the problems.
    • A few other changes in general were noted, including having the clients now log how many ghost suspects they have asked sync information for, and how many ghosts they have busted. We actually tried a few different things to mitigate ghost suspects, but it still winds up accidentally busting too many ghosts. So as it is, we wind up with more ghost suspects than we would prefer, but it should be in a place where it's not actually busting any invalid ghosts (and hopefully it finds no ghosts at all).
    • If you see a bunch of ships on a client get destroyed and then reappear, please do let us know!
    • Thanks to Bummeri, KaleR, Jusa, borisgrebenshchikov, Lictuel, Pringels, Sergie, Zweihander2021, and Liorik for reporting.

DLC 2

  • Add more defensive code for the Wormhole borer notification
    • Thanks to Zweihander2021 for the bug report
  • The ZA can build a max of one Castra per planet
    • At zeus' request
  • The DZ can now use the RequiredIntensity XML setting on a DZUpgrade to restrict it based on faction intensity.
  • Adjusted Phantasmal Host Frigate icon and shorthand from heavy to medium. Its actually a light armor hull but it generates frigate sized decoys.
    • Thanks to Tzarro for pointing out disparity.

DZ / Svikari Changes

  • Coerl alebdo 0.4 -> 0.7 (it has cloaking)
  • Intensity 1 changes
    • BaseInvasionStrengthPerPlanet: 15000 ->5000
    • BaseExoStrength="500000" BaseExoInterval="3600" -- A big exostrike 500 str every hour. Too frequent, I fear the DZ would get crushed invariably except if the exo strike was super weak, which would just get insta killed by the Jormugandr.
  • Intensity 2 changes
    • BaseInvasionStrengthPerPlanet: 13000 ->6000
    • BaseExoStrength="500000" BaseExoInterval="3300" -- A big exostrike 500 str every 55 min.
  • Intensity 3 changes
    • BaseInvasionStrengthPerPlanet: 14000 ->7000
    • BaseExoStrength="500000" BaseExoInterval="3000" -- A big exostrike 500 str every 50 min.
  • Intensity 4 changes
    • BaseInvasionStrengthPerPlanet: 12500 ->8000
    • BaseExoStrength="500000" BaseExoInterval="2700" -- A big exostrike 500 str every 45 min.
  • Intensity 5 changes
    • BaseInvasionStrengthPerPlanet: 12500 ->9000
    • BaseExoStrength="500000" BaseExoInterval="2400" -- A big exostrike 500 str every 40 min.
  • Intensity 6 changes
    • BaseInvasionStrengthPerPlanet: 13000 ->10000
    • BaseExoStrength="500000" BaseExoInterval="2100" -- A big exostrike 500 str every 35 min.
  • Intensity 7 changes
    • BaseInvasionStrengthPerPlanet: 13500 ->11000
    • BaseExoStrength="500000" BaseExoInterval="1800" -- A big exostrike 500 str every 30 min.
  • Intensity 8 changes
    • BaseExoStrength="500000" BaseExoInterval="1500" -- A big exostrike 500 str every 25 min.
  • Intensity 9 changes
    • BaseExoStrength="500000" BaseExoInterval="1200" -- A big exostrike 500 str every 20 min.
  • Intensity 10 changes
    • BaseExoStrength="500000" BaseExoInterval="900" -- A big exostrike 500 str every 15 min.
  • Tier 1 (Guardians) requires 3 variant upgrades (eg., tier 0 sinister)
  • Tier 2 (Dire Guardians) unlocked at intensity >=5 and requires 6 variant upgrades
  • Tier 3 (Golems) unlocked at intensity >=6 and requires 10 variant upgrades
  • Mark 2 requires 1 variant upgrades
  • Mark 3 requires 3 variant upgrades
  • Mark 4 requires 5 variant upgrades
  • Mark 5 unlocked at intensity >=5 and requires 7 variant upgrades
  • Mark 6 unlocked at intensity >=6 and requires 9 variant upgrades
  • Mark 7 unlocked at intensity >=7 and requires 11 variant upgrades

ZA Balance changes

  • Replaced the ZA Cestus self-damaging attack with health_change_by_max_health_divided_by_this_per_attack="-1" so it always kill itself
    • thanks Puffin for pointing out the mix up!
  • Marking up of portal/spawner was 600 seconds at all intensities. Now, intensity 1 is 1200 and each intensity is 100 secconds fewer, maxing at 600 seconds at intensity 7+
  • "WarIntervalForStrengthIncrease="X"" tripled (20 ->60) at intensity 1, 10 seconds reduced per intensity until capping at 20 seconds (default) at intensity 5
  • "TimeBetweenTerritoryIncrease="X"" increased intensities 1 - 6. Intensity 1 20 -> 30 min, and 100 seconds fewer with each intensity until intensity 5 (900s ->1200s). Intensity 6 700s ->900s. The rest are 600 seconds (default)
  • Greatly increased the time before pioneers can spawn at intensity 1-3 (now 2 hours at 1, 10 min less per additional intensity), and a minor increase at 4 (now 1 hour)
  • "ExcessSpawnersToTriggerOtherArchitravesToAttackMe="X"" has basically been inverted. Intensity 1 went from 2->5 while Intensity 10 from 5->1. Basically, the lowest intensities will for all intents and purposes, never trigger a civil war (except in marathon games maybe). Intensity 10 should be triggering civil wars in most games

Mod Updates

  • AMU:
    • Now has a new Rollup for all DSAAs.
    • Fixed some bugs in AMU's Faction Allegiance management:
      • No matter whether or not the faction has a team, is allied to any Player or any AI the FactionAllegiance now also correctly saves all other data (such as allied to players, AIs, traders, etc). In theory simply always saving the RelatedFactionOrNull would be enough, but this way it forward-fixes any other potential exotic faction allegiance states causing trouble.
      • Tested out these changes and found out that this Marauders in a test case would STILL go hostile to the player if Kaizer was present, even when they have no reason to.
      • Fixed another bug in the SmartFactionImplementation where Allegiances would always be overwritten even if correctly serialized. This was a leftover from when the OnDeterministicThreadOnly_DoInitialLogic function would happen BEFORE deserialization.
        • Both of these combined now fix Kaizers Marauders in games with Kaizer present going hostile-all-except-other-kaizer-allied after loading a save, even when they shouldn't.
        • Unfortunately saves with broken allegiances cannot be repaired because the required data just wasn't stored. They won't fail to load, but allegiances are permanently wrong.
        • It's still not a good idea to trust your Marauder allies...
          • Thanks to LordNSR for stumbling upon and reporting this.
      • The variable TeamIsMinorFactionTeam is now correctly renamed to IsInAnyTeam. This was no bug, but simply false.
    • The DynamicAveragingRing now is serializable and inherits from SuperBasicSerializable.
      • It has saveAverageOnly (required in constructor). If enabled the DAR will only save the average value, which is much more efficient in data size. If disabled it will save every single variable contained and be as correct as possible.
      • Note that only the same save-style DAR can be loaded.
    • Executor Work:
      • Fixed a number of bugs for OnAnyDeathExecutors_HostAndClient and their tracing.
      • Added a new OnSpecialActionExecutors_HostAndClient using the new DeterministicSpecialActionExecutor.
      • Fixed the ExecuteOnlyOnce mechanic not actually applying anywhere, it was simply forgotten to implement it.
    • Fixed a few bugs in AMU's wrappers for Factions, Planets and Planet Factions where all of them could not serialize them being null. I'm honestly surprised that didn't crash everything sooner.
    • The Global Variable Overwriter now uses the above logic for better performance:
      • Instead of executing the code at game start and once per second it now executes at game start and whenever the settings are changed. This means it'll be much more efficient.
  • Kaizers Marauders:
    • Using the new DSAA Rollup from AMU Player-allied Marauders will now target any hostile DSAA that doesn't produce AIP on death. Non-Player-allied Marauders will target any DSAA.
      • Thanks to LordNSR for noticing that Marauder units were targeting the Raid Blaster, Kaizer had the same problem (his credit was missed in the last patchnotes, sorry). This is stage 2 of the adjustment.
    • Changed the wording in the Galaxy Settings from Kaizers Marauders (Multi-Planet Settling and Healing Allies) to be more clear, and correct English (hopefully).
      • Thanks to LordNSR for reporting. This must've been written in one tired night...
    • Fixed (Warping-In) Marauder Capitals mentioning GCAs.
      • Thanks to LordNSR for reporting.

Mods

  • Kaizers Marauders:
    • Reduced the Albedo of the Raid Blaster (and its derivatives) and Kaizer in all his variants and states from 0.9 to 0.85, meaning that the ships will no longer be targeted by the Mark 3 DSAA.

2.901 AIP Reduction Clarity

(Released May 6th, 2021)

  • Ship lines should now be sorted by strength in a number of places in the UI (hovering a flagship, the Fleet management window, etc)
    • Thanks to mahisev350 for the suggestion
  • The Swap Ship Lines UI only shows the player name if it's not you
    • Suggested by x4000.
  • In the event that an AIP reduction event does not actually reduce the AIP, it now explains "AIP Floor was hit! Reduction will apply more later as AIP rises. Current floor is: X"
    • Additionally, the AIP Never Reduces Below Amount is now shown on the same line of the AIP tooltip as the AIP Floor, so that it can't be missed. That was super easy to miss before.
    • And finally, the reported AIP floor now factors in the AIP Never Reduces Below Amount, versus looking like you SHOULD be able to reduce further and then mysteriously not being able to (unless you happen to read lower in the tooltip).
    • Thanks to The Main Man, MrButtermancer, Zeus, Strategic Sage, Badger, Lailah, and others for this discussion.

Bugfixes

  • Fixed a bug in the prior version where the new "Planet not to path through" underlay was throwing an error rather than showing.
    • Thanks to GreatYng for reporting.
  • Previously, you could get around the claim cost of a fleet leader by hacking to transform it. Now you can't hack to transform anything that is not yet fully claimed, or which is still partly under construction.
    • Thanks to Darkshade for reporting.
  • Fixed a general waste of performance where a lot of galaxy map display stuff was being calculated even when you were looking at the planet view. We discovered this quite by accident in fixing an MP bug, but this was a performance drain in solo play as well.

Multiplayer

  • There was a nonsensical failure to send a planet's data via multiplayer, but via code review all looks well. So this must be some sort of special case issue that we need to narrow down more. We've thus inserted 8 network canaries into the planet sync code, which will help us find the specific area in which the problem (which is apparently quite rare) occurs.
    • Thanks to Bummeri and their MP group for reporting.
  • In the multiplayer client, the "ghost check" code previously was deleting any units that it had not heard from the host about for 4 seconds' worth of sim cycles. This was working some of the time, but when there were too many ships it would cause periodic deletions and recreations of units, which was definitely bad.
    • One of the chief problems with ghosts is that they are not centrally registered on the client, so the host can't get in there and update them to say "you are okay" or "you are dead."
    • After 1 second of not hearing from the host, a unit on the client now ensures that it is centrally registered. This should keep it from being missed for updates and divergence checks. If it is dead on the host, we should find out in the next cycle.
    • After 8 seconds, now, if it still doesn't hear from the host then it gives up and suicides. This should be long enough for the very shortest sim cycle.
    • Thanks to Liorik, Bummeri, goodjoe696, and others for reporting. This was a tricky one!
  • Substantial update to how loading and unloading transports are handled in multiplayer. This gets rid of the bulk of the lag that clients were experiencing with this, as well as ship counts going crazy on the client in the fleet display as ships were shuffled in and out.
    • Essentially some of the fleet data just needed to be synced over at the same time, and the client needed to not do a few things that are host-side-only.
    • Thanks to Bummeri, goodjoe696, and others for reporting.
  • Fixed an exception that could happen on MP clients, where essentially if a fleet was updating at just the wrong time, it could cause an exception in trying to draw its info on the galaxy map.
  • Fixed an issue in MP where clients could get exceptions when ships transformed from one form to another.

DLC2

  • DZ Terminii now explicitly list the name of the resource they have for pickup (like 'We have 500 Izumite') instead of just '500'
    • Thanks to Strategic Sage for reporting
  • Add a new Community quickstart, 'The Devouring Badger'
  • DZ: add the ability for an upgrade to prereq a certain number of ship variant upgrades.
    • Requested by zeus for balance purposes

2.900 First Press Build

(Released May 6th, 2021)

  • Rejigger the timing of the Beginner Journals to try to prevent 4 from firing at once (which I saw). That's overwhelming.
    • If this isn't enough then we can put a beginner journal specific timer in instead to say "Only one beginner journal every X seconds"
  • Hovering ARS and TSS on the galaxy map now shows the tech lines for its available ships in Full Detail tooltips; this matches the behaviour for uncaptured flagships for a consistent experience
  • The Placement screen at the top right now reminds you of the metal costs.
    • It shows the base metal cost, then the 5x, 10x and 50x metal costs, for unobservant people like me who don't remember how much things cost, and would like a chance to easily see if I can afford to build 10 of something
  • Holding 'Alt' with units selected will now remind you what hotkeys exist to control just those units
    • Turns out there are hotkeys to control Melee units only, flagships only, units with tractors only, and a bunch of other things, but I can never remember them. Now it's easy to check!
  • Factories and Engineers always auto-build by default
    • Every player I know would turn them on immediately, so having them off at game start was just a n00b tax. The 'you should automate' beginner journal entry now appears for people who don't have auto-build defensive ships
  • The beginner Next Steps journal has real advice now
    • Thanks to Sage for this advice.
  • Hive Golem now has Greater Metabolism in the base game, as otherwise it got both standard and greater version with DLC2 update.

Tutorial Updates

  • It is now possible for planets to have "travel advisories" that block either player or NPC movement into those planets via wormholes, or block all of the above.
    • This can only be turned on via tutorials at the moment, and we have these set on most tutorial planets to prevent the AI from coming to help its smaller planet in late tutorials, and to prevent players from going too far into AI territory and dying in the tutorial in any of them.
    • Tutorial 1, nobody is allowed to leave any planet, you or the AI.
    • Tutorial 2, NPCs can't use any wormholes, and player is not allowed to go to Farland or Sidelander.
    • Tutorial 3, NPCs can't use any wormholes, and player is not allowed to go to Farland.
    • Tutorials 4 and 5 are blocked to NPCs on all wormholes, but let the players do whatever, including going to Farland and getting killed.
    • Thanks to LarryP for reporting it was possible get killed in the early tutorials.
  • Also for tutorials, we added a ne destroy_all_metal_harvesters="true" option.
    • This makes it so that in tutorial 3, on Sidelander, we can have all the harvesters (which take a long time to capture now) not get in the way of capturing the transport.
    • Essentially this was super slow now even on speed 5x.
  • Tutorial 3 now has some notes on how to speed up time, and about how to play in a fast-but-with-period-pausing playstyle.

Balance: Turret Simplification

  • An UI-focused update making turrets count far more intuitive.
    • The impact has been kept to a minimum, but this still has a number of implication. Particularly for starting turrets.
  • Turrets count in TSS reduced from 15 to 10 for small, 3 to 2 for large.
  • Defensive caps increased:
    • Battlestations: from 0.7 to 1.0
    • Citadels: from 1.4 to 2.0
    • Home Command: from 1.33 to 2.0
    • Economic: from 0.25 to 0.4
    • Logistic: from 0.48 to 0.8
    • Military: from 1.15 to 1.6
  • Starting Pike turrets now scales with Defensive capable.
    • Econ: 4, Logi: 8, Mil: 16, Home:20. This should balances "overpowered" Econ planets, now they no longer have a 4x cap on pike for free.
  • Starting Ambush and Beam turrets remain the same on mil. (32 and 3).
  • Starting Tachyton, Tractor and gravity generator counts have been adjusted. This changes little.
  • Minefields counts have been updated. This changes little.
    • Including DLC2 ones. (Zeus)
    • But not modded ones.
  • Station Keepers numbers have been adjusted to reflect Defensive Cap, they didn't before which increased confusion.
    • This concerns Watchman and Assault Station-keeping frigates.
  • Thanks to ArnaudB for making these changes!

Mod Updates

  • Update to MSD balance based on shifting base game balance
    • Turret counts available via TSS normalized to 10.
    • Escort Carrier count available by default to Economic reduced to 3.
    • Artillery Destroyer count available by default to Economic reduced to 1.

2.899 Almost Press Build

(Released May 5th, 2021)

  • Updated graphics for the Zenith Trader are now in place in the base game. We'll be doing a number of updates to base-game Zenith golems to make them fit with the new art style for the race as introduced in the upcoming expansion, but most of that art will be coming after the expansion itself releases.

Balance Updates

  • In galaxy advanced settings:
    • Number of maximum Data Centers increased from 6 to 9.
    • Number of maximum Major Data Centers increased from 2 to 3.
    • Number of maximum Distribution Nodes increased from 6 to 9.
    • These changes give back the ability to ease the game, which should particularly be welcome given DLC2 is likely to bring in new players.
      • This feature was appreciated by newcomers before, and it felt frustrating to have three sliders whose sole option was to make things harder for the player.
      • Bear in mind that in the future modes that are more for experienced players (Guerilla Warfare and Deathwish in particular), we'll maintain very strict limits for balance. But this main widest-appeal mode (to be called Humanity Ascendant in the future) we want to make sure as many people can comfortably enjoy as possible.
    • Thanks to ArnaudB for updating this.
  • On difficulty 9 and 10, the hunter fleet will be even nastier about going after MDCs

UI Updates

  • Add beginner journal entries teaching players about watching flagships, and queueing unload orders for their flagships. These are very important techniques for good play.
  • Add a journal entry when the AI Overlord transforms explaining the mechanic
    • Thanks to Miloch for pointing out some potential confusion.
  • The escape menu now shows the personal settings and galaxy options on a single line, to make them less easy to miss (in terms of them both being there, and similar but different).
    • The escape menu has moved View/Edit Factions much further up, to a place of high visual priority.
    • The escape menu now has a "Visit Us On Discord" button, because frankly that's the best place to get tips and community advice for the game these days if you don't know exactly where to head on youtube, etc.
      • The discord tooltip in this menu, and on the main menu, now have a tooltip explaining that it's the best place to go for tips and similar, and that the forums are basically dust-catching now.
  • In the More section on the main menu, the links to the forums (which are almost dead now, because of discord) have been removed.
    • We also removed the link to our mailing list, as we don't really actively manage that anymore (though it does still exist), because it's not typically a way people want to hear from us.
    • And lastly, we removed the link to the wiki (which you can still get to by just clicking the patch notes button anyhow), because other than for patch notes our wiki is basically in the game rather than on our site. The fewer options that people have to look past that don't matter, the better.
  • The in-game credits for DLC2 have been greatly expanded to properly reflect everyone's role. This team has grown in 2021 for this particular project!
  • When you have set a planet to be a no-path-through zone, it now shows a red and black octagon around it on the galaxy map to remind you of that.
    • Thanks to Badger for suggesting.
  • On full tooltips, hovering a neutral flagship will show the techs that upgrade each of its ship lines next to that ship line.
    • The goal is to make it easier to figure out what synergies that flagship has at a glance, without c-clicking.
    • This is also explained in a Tip of the Day
  • When hacking an ARS, holding Ctl will show the techs that upgrade those ship lines for easier synergy determinations

Utility Updates

  • Fixed a mapgen bug that was interfering with properly starting up the Test Chamber.
  • Fixed another bug in our camera code that would cause it to not work properly if there was only a single planet (aka the Test Chamber), so its dynamic zoom could not properly kick in.
  • The "reload select bits of xml" function (default F8) now works again for the first time since the XML Import overhaul. We haven't needed it until now.
    • It now works with lod_distance_overrides, size_scale, visuals_scale_multiplier, gimbal_name_extra_offset_y, and gimbal_icon_size_multiplier.
    • Also now with y_offset_of_icon, y_offset_of_ship_in_visual_space, y_offset_of_ship_emission_and_hit_point, rotation_x_of_ship, and rotation_z_of_ship fields.
    • These are all the things we tend to need when setting up a new DLC's art, or in the design of mods, but it serves little purpose beyond that.
    • We've actually never before had the capability of altering quite this many of them all at once, so this is a very nice improvement!
  • Added a new lod_distance_multiplier, which lets us adjust the LODs for our graphics in a multiplicative form (as they are scaled up or down) versus having to completely redefine them.
  • The test chamber no longer tries (and fails) to do autosaves.
  • The spawn requests from all expansions and mods are now all combined in a single test chamber, rather than it only taking the most recent one.
  • Test chamber data now also gets reloaded as part of the F8 function.
    • However, it does not restart the test chamber itself.
  • When you are in the test chamber, you can now hit the button to load the test chamber again, and it will reload it. It won't always actually show the ships, so you may have to click that a couple of times. But this is for modders and developers only, anyway.

Bugfixes

  • Fixed a puzzling issue where a hack could get into an invalid state and be unable to close itself down. It was in the process of trying to fail, but missing some of the metadata, so unable to finish wrapping up. These now properly fail, but don't log their hacking event since that was the part that was missing.
    • Thanks to goku454545 for reporting.
  • Fixed a couple of rare cross-threading issues that could happen with ships moving between planets and the AI thinking about it in the background and then having a nullref exception.
    • Thanks to Darkshade and Badger for reporting.

Mod Updates

  • Kaizers Marauders / Extended Ship Variants
    • Removed or replaced the icon overlay for any entity using Overlays1/Spacedock_Mobile. It seems this icon was removed entirely.

2.850 Icons, Targeting, And ODSS

(Released May 4th, 2021)

  • Increased numbers of sectors from 2 to 3 in the ODSS (how many times you can hack it)
    • Thanks to ArnaudB for adjusting.
  • Fixed an exception that could happen in Astro Trains when they wanted to spawn a wave but were not doing so for some reason.
    • Thanks to goodjoe696 for reporting.
  • Add a Tip of the Day telling players that they can queue unload operations
    • Thanks to a conversation with aliyah on discord
  • Waves against Marauders now use the smaller of current AIP and Marauder's AIP when calculating anti-marauder wave size.
    • Marauders often wind up with really high AIP, so this should be a nerf to the AI response to the marauders (especially player-allied)
  • Shot/damage logic fixes/improvements:
    • Fixed multiple cases of shots being fired twice onto the same target, or damaging the target twice if they shouldn't:
      • As it turns out the game would allow weapons with sufficient shots to attack the same target in the TargetPriorityList twice if it was not overkilled from the first shot.
        • Now the weapon shifts targets it attacks that weren't already overkilled to the front of its target priority list and, in the 2nd loop where it seeks for targets that are overkilled starts to look for targets at the end of this "already fired upon" sub-section.
        • This should actually speed up the sim a bit because the game no longer wrongfully creates multiple shots for the same target or even check them.
      • The same bug was possible for the main attack target and the FRD attack target, which have also been excluded for double-fire.
        • Also the weapon chooses a new main attack target or FRD attack target from its target list it'll now remove them from the list so it won't even get the chance to iterate over them again. This should, again, improve performance by a small bit.
      • Point Beam Weapons (such as the Hunter Seeker's Mass Destabilisation Beam) were actually hitting targets twice, once in the actual shot and once more in an AoE damage instance that should not exist with point beams.
        • The game now automatically sets shots_detonate_immediately to true for point beam weapons to limit the damage instances to 1 only.
    • Fixed a number of "abnormal" sources of damage (electrotoxicity, attrition, etc) being limited in the amount of stacks they kill per damage instance.
      • Especially the Nidorian Toroid was limited to killing off 1 unit per stack. So no matter the target's durability it could at best kill a stack of 100 enemies in 100 seconds.
    • Added new max_attrition_damage and added_max_attrition_damage_per_mark for ships dealing attrition damage. This limits the amount of attrition damage per tick they are allowed to do and scales with both fleet attack power and hacked attack power just like the attrition damage itself. If both is 0 there is no limit, which is the default.
      • For now the the Nodorian Tortoid is limited to dealing a base 100k + 25k/mark level attrition damage per second. Compared to before this is a hefty nerf, but in raw DPS it is still very significant, and counteracts the ship eating stacks due to the fix from above. This means that only upon targeting more than 1250 enemies at once the limit will be in effect at all.
      • Attrition damage will not spread equally among targets but focus as much as possible. This is to prevent it from having the same flaw old Siege Frigates had in splitting damage among so many targets it never actually kills anything.
    • Thanks to NR SirLimbo for all of these improvements!

Mod Updates

  • Yet another attempt to stop civilian industry raids from appearing. Though at this point they don't cause much performance issue.
    • Thanks to ArnaudB for adjusting.
  • AMU:
    • The AMU base entities for Light/Medium/Heavy Frigates, Destroyers and Cruisers now use their new icons. This will trickle down to multiple entities in Kaizers Marauders and Extended Ship Variants.
  • AMU
    • Fixed a small but nasty bug in the DynamicAveragerRing that would cause the sum of all averages to be wrong and ending up doing the opposite of what it's supposed to do.
    • This would lead to horrible hitches in Kaizers Marauders when planets had tons of defenses on them.
    • Planets with this type of build-up will likely lagg a few times after loading a save, but the hitches should grow less and less severe and eventually all but disappear.
      • Thanks to Sorrydough for reporting and testing the fix.

Icon Work

  • All of the icons for DLC2 are now in place! This increases the total number of icons in the game by about 50%, it's actually pretty crazy. But it's all contextual, don't worry.
  • The Astro Train Station icon has been updated to look like a lot less literal train station.
  • The Scourge (DLC1) now show a little icon overlay on units that are in the process of warping in.
    • This is now consistent with us doing that for a variety of units in DLC2.
  • The Scourge (DLC1) now have new fancier icons for denoting each of the races that are primary to the warrior that they have produced.
  • The TSS and ODSS now have much larger overlay icons that are also colored, in order to make them easier to tell apart. Previously they were just tiny little black smudges to differentiate them, at the scale you tended to see them.
  • Reworked the Frigate icons again. They were too complicated in their recent version. But at least not BOAT.

2.816 Frigate Icons And Tuning

(Released May 1st, 2021)

  • Several adjustments to D-SAA entities
    • Added an icon overlay to make them a little more obvious.
    • Made the v3 versions on Bastions and AI Homeworlds display on the galaxy map.
    • Nerfed the detection speed a little.
    • Removed FRD non-attention from base level of D-SAA since the most basic tier has no AIP attached.
    • Thanks to CRCGamer for adjusting.

Bugfixes

  • Fixed a typo of parasite hydra being hyrda.
    • Thanks to ArnaudB for fixing.
  • Grand Salvage displayed name was blank for some reason. This is now fixed.
    • Thank Abuchris on discord for the report, and ArnaudB for fixing.
  • Fixed a bug where if stacks were killed entirely, with enough damage remaining to potentially kill even more stacks the game overestimated the amount of damage, leading to wrong amounts of electrotoxic return damage among other things.
    • Thanks to NR SirLimbo for finding this, following it down the rabbit hole, and fixing it!
  • Did another change to stop AI raids from bothering Civilian Industry faction
    • Apparently some players still have raids on a single planet at a time. Please report saves when the raid is announced or about to launch. Assuming you still have them after this fix.
    • Thanks to ArnaudB for fixing.
  • AMU / Kaizers Marauders:
    • Fixed a couple of places where the wrong DoForPlanets was used, bugging things out.
      • Thanks to LordNSR for reporting.
  • Kaizers Marauders:
    • Fixed their capital ships not having short names set up and inheriting "CC AMU Base".
      • From a screenshot of LordNSR.
  • Fixed an issue where minefields were showing up in technology unlock strength comparision as ship, not defense. Among other places.
    • Thanks to donblas for reporting, Badger for the fix, and CRZgatecrusher for verifying the fix.
  • Fixed some cross-threading bugs that could happen in the GetSelectionContains() methods in some circumstances.
    • Thanks to Zweihand for reporting.

Icon Work

  • The frigate icon has been updated to look better, and have variants for light, medium, and heavy frigate classes.
    • It no longer looks like a boat, which is... really nice! ;)
  • New icon update conventions, this creates a TBD for modders in general, too:
    • The existing Frigate icon (Ships1/Starship) is now what we would consider a medium-class frigate. Right now we're only using that for the PFFL ones, and things like outguard flagships.
        • All existing frigates will default to this, which is fine for now, but differentiation is probably good to do.
    • There is also a new FFL icon (Ships1/Starship_Light), and a FFH icon (Ships1/Starship_Heavy).
    • We do actually have a first FFM (medium class frigate) in DLC2, the minelayer, and this also uses the default icon.
  • If you have been designing Elites (cruisers or destroyers) for your mods for DLC2, then you'll want to use the new icons for those.
    • Ships2/Cruiser and Ships2/Destroyer.
    • If you're making alien cruisers or destroyers (like we have for the Spire in DLC1, then carry on with whatever you were using before, probably).
    • All of the existing DLC2 cruisers have been updated to use the new icon, and we don't have any destroyers yet.

2.815 Polishing And Bugfixing

(Released April 30th, 2021)

  • Bastille Turret updated: it's now a long range turret firing burst of missiles for a good amount of damage. It cannot fire at close enemies. It still retains the 4x dmg multiplier.
    • The dps stated is wrong. It has about 2700 dps with the 4x bonus, instead of 1500 dps before the bonus as is shown.
  • Either way, this should make it more compelling and unique to take, rather than an uninteresting and generally useless turret.
    • Thanks to ArnaudB for updating.
  • The ability to have one or more arbitrary underlays under planets on the galaxy map has been added. This is for use with things like certain planet statuses in DLC2.
  • Added a new DoOnSpecialEvent_OnMainThread() that can be overridden on any faction, and which gets called on various UI-related events.
    • These mostly are related to settings windows being opened and closed or saved, etc. The purpose is for certain mods to be able to hook into those screens better.
    • Thanks to NR SirLimbo for requesting.
  • The way that planet icons are drawn on the galaxy map has been upgraded by a surprising amount. We're able to put more information in there now.
    • We're currently able to show status changes to planets, such as "Nomadic" and (the mysterious) "experiencing Fimbulwinter," and later can do more things with that. It's not very mod-friendly yet for being extended, but it's great for our immediate needs.
    • Additionally, the AI Homeworld and Bastion worlds now have different colored borders paired with interiors that are filled with a specific image. This is along the lines of how your own planets show the kind of command station you have chosen on them, and the intent is to aid in visibility for those worlds.
    • We also have new stylings for the Dark Zenith and the Zenith Architrave, which is important in the latter case in particular because the ZA might be occupying a planet but not consider that part of its innermost territory. The difference is now distinct at an immediate glance, as well as being in the tooltip. The ZA will murder you on certain planets that it considers to be its own, and is much more lenient on planets that it might have just snagged from someone else.
    • This whole process took far longer than expected, but it's a good launching point for us to be able to do increasing numbers of things in the future, and allow for modders to do the same at some point (not yet, but later).

Bugfixes

  • Update to The Reprocessors mod by CRZgatecrusher.
    • The wrong one was applied two versions back.
  • AMU / Kaizers Marauders:
    • Fixed a number of outdated methods to fit with the most recent version of the AIW2 codebase. Should have no functional impact.
  • Updated AI Shield Generators mod by cml to match current code requirements.
  • Previously, if the client in MP had incorrect wormhole data, then they would get tons of "Was looking for a wormhole on the far side of X" messages spamming their log HARD. This message now only shows up on hosts.
    • Ideally we obviously fix the wormhole issue on the client, but the first part of this is to make sure that it doesn't cause lag and log spam if it does break. After all, the host will handle the wormhole traversal fine, so it's possible for clients to not even notice that things are off.
    • Thanks to Bummeri, Kalervo, and Jusa for reporting.
  • MP clients no longer try to directly move nomad planets. The odds of them coming up with the same result was extremely low.
    • Thanks to Badger, Bummeri, Kalervo, and Jusa for reporting.
  • Fixed an MP issue that could happen with Zenith Miners on MP clients in ModifyMinersIfNecessary(). This is now just run on hosts.
    • Thanks to Bummeri, Kalervo, and Jusa for reporting.
  • Added a new Network_HostOnly_NeedToSyncPlanetPositionAndLinksAndWormholesToClients that should be set anytime the host moves a planet, destroys it, or changes around its links. This is set in a variety of places now relating to nomads and miners and even the dark zenith.
    • In those situations, it then does something it does not usually do, which is resend all of the wormhole connections to the client, which then should be up to date. This is untested at the moment.
    • The planet positions it turns out are already updated, as is the planet destroyed status, but the wormholes were the lagging element.
    • Thanks to Badger, Bummeri, Kalervo, and Jusa for reporting.
  • In savegames or lobby settings where for some reason the relentless wave subfaction is not tied properly to a specific AI faction, it now works to rebuild that in a sensible way if it can, or just chooses the first AI faction if it can't. This should solve the errors resulting from it either way, and the worst case should be that if you were having a civil war and it didn't get the optimization perfect, one side might have an edge over the other.
    • Thanks to Isiel for reporting.
  • FINALLY managed to fix a longstanding bug that has eluded me for years, where sometimes the tooltips were insanely thin for some reason. We never could figure out the proper conditions to make it happen, it sometimes seemed OS-specific, and often fiddling with settings made the problem go away for users.
    • It turns out that to reproduce the problem, your general tooltip scale had to be set to exactly 1.0, and you had to restart the game and then it would be messed up until you changed it to something else. If you changed it back to 1.0 without restarting, it would still be fine (until your next restart).
    • The general problem is that we have a "last scale" stored in a few variables, and it was set to 1. It doesn't do certain calculations over if the last scale is the same as the current scale, but it definitely needs to do these calculations at least once after starting the game! We have changed these "last scale" variables to start at a much more reasonable -1 (meaning nothing could ever match it), which means that it's not possible to trigger this problem anymore.
    • Big thanks to Maluraq for their help in finding this, including sharing a video of it in action so that we could walk through what turned out to be the steps to reproduce it.

Beta 2.814 Hotfix For Murder-By-Powerup

(Released April 30th, 2021)

  • Add group selection modifier to only select turrets, unbound by default.
    • Thanks to donblas for adding.
  • Fixed a couple of exceptions that could happen in the human faction, shutting it down, if there were no ARSes or neutral transports out and about to capture when the game wanted to give you a journal message about that.
    • Thanks to CRZgatecrusher and donblas for reporting.
  • Fixed a bug that was very old, but actually just started expressing itself yesterday because a DIFFERENT old bug was keeping it at bay until yesterday (when I fixed that bug). That is odd enough in and of itself, but the result was actually hilarious, so let's see if I can do it justice.
    • Essentially, all of those "not owned by anybody" units (transports, golems, etc) were being mistakenly given ownership to the AI of the planet they were on. These are supposed to be the capturable goodies that you go out and collect, recall.
    • Because of the unintentional ownership change during mapgen, these things turned on and went into destroy mode. A few minutes into any new game, and every capturable that was supposed to be out there for you to collect at some point... would come murder you instead.
    • Nintendo added poison mushrooms that chase Mario and kill him, but this is some next level revenge of the powerups, I have to say.
    • Thanks to donblas for being the original recipient of this, and CRZgatecrusher, Metrekec, Ovalcircle, CRCGamer, Strategic Sage, and others for reporting.

Beta 2.813 Golem Relations

(Released April 29th, 2021)

  • Fixed an issue where we were filling and then never using a list called EntityIDsWaitingAgainstThisPlanet<>, and in the new parallel loop code for it, that was causing exceptions in some savegames. This has simply been removed, as it was a pointless waste of CPU at the best of times, and now also an exception on top of that.
    • Thanks to slake-moth for reporting.
  • [Journal] Right clicking entries marks that as read.
    • Thanks to donblas for implementing!

Balance

  • Nerfed ticket value of Interplanetary Engineers to not be obnoxiously in almost every ODSS rotation.
  • The TSS now grants 4 turret lines to choose from, up from 3 last build but still down from 5 the build before that. Happy middle ground.
    • Thanks to Zeus and Strategic Sage for suggesting in response to the rumblings of others.

Spies

  • Nerfs to spies. They now are a Markless entity and have been rebalanced around what was a Mark III spy previously.
    • On top of that they are now only a single spy per military and two per logistic command without getting extra copies for being marked up happening.
    • Thanks to CRCGamer for updating.
  • Implemented D-SAA structures that will scan for and reveal player spies. These come in several different versions. The higher tier versions unmask spies considerably faster, and in the case of the v3 which only shows up on Bastions and Homeworlds also sports a gun to very quickly remove the offending spy.
    • Thanks to CRCGamer for coming up with this and implementing it!

Officers

  • Officers in general no longer come with fleet ships along for the ride. It's no longer limited to just the early officers.
  • AIP costs of capturing golems have been reduced, and their energy has been increased.
    • Armored Golem AIP 20 -> 16, energy 50k to 200k.
    • Artillery Golem AIP 15 -> 12, energy 50k to 200k.
    • Regenerator Golem AIP 15 -> 12, energy 50k to 200k.
    • Cursed Golem AIP 15 -> 12, energy 50k to 200k.
    • Botnet Golem AIP 40 -> 25, energy 50k to 400k.
    • Black Widow Golem AIP already 11 since early officer, energy 50k to 150k.
    • Hive Golem AIP 20 -> 15, energy 50k to 200k.
  • AIP costs of capturing arks have been reduced, and their energy has been increased.
    • Rorqual Hegira AIP 8 -> 7 even though early officer, energy 7k to 100k.
    • Thanatos AIP 10 -> 9, energy 7k to 100k.
    • Gyrn, the Voidhome AIP 10 -> 9, energy 7k to 100k.
    • Orchid AIP 8 -> 7 even though early officer, energy 7k to 100k.
    • Ark One AIP 8 -> 7 even though early officer, energy 7k to 100k.
    • Belle Prime (DLC1) AIP 10 -> 9, energy 7k to 100k.
    • Great A'Thomek (DLC1) AIP 10 -> 9, energy 7k to 100k.
    • Nodorian Tortoid (DLC1) AIP 10 -> 9, energy 7k to 100k.
    • Sol Ater (DLC1) AIP 10 -> 9, energy 7k to 100k.
    • Grand Salvage (DLC1) AIP 10 -> 9, energy 7k to 100k.
  • AIP costs of capturing lone wolves have been reduced, and their energy has been increased.
    • All three lost spire frigate variants AIP 15 -> 11, energy 15k to 250k.
  • Thanks to Strategic Sage for starting the discussion on the energy costs being way too low, and Zeus, Lord of Nothing, and others for suggesting refinements.

Base Game Updates

  • The game is now way more explicit about when it is in the middle of mapgen or not. You can call a variable right on the Mapgen class to find out if that's the case, now.
    • During mapgen, GetControllingFaction() on planets now uses much more complicated logic that is based around a lot of mapgen-specific logic, which means that things are correctly attributed and units that are intended to be seeded "belonging to the planet owner" now properly do that instead of belonging to no one.
    • Thanks to CRCGamer for reporting.
  • In the event that you load an older savegame into a new one that has different energy balance, if it dropped your net energy below zero, you're now given a free handicap of extra energy to not wreck that campaign.
    • This is logged into your debug log, and then you can also see it in the tooltip for energy at the top of the screen.
    • The idea here is that we do need a free hand to be able to rebalance energy at times, but we don't want to be wrecking existing games as we do so. And modders frequently have the same sort of needs.
    • With this, if we or modders need to make changes, the game will just automatically help you out and keep your existing saves from becoming unplayable due to brownout.
  • Add hotkeys to build 1/2 and 1/3 of total capacity of some structure when you hold the hotkey and click in a spot, default unbound.
    • Thanks to donblas for implementing this!

Mod Updates

  • Civilian Industry: now no longer creates AI raids. The performance drops from those were too much. This means the faction is essentially "free". The AI gets nothing to counter it.
    • For the future: instead use a variant of the wormhole invasion to create a similar AI response against civilian.
    • Thanks to ArnaudB for adding this in.
  • The Reprocessors mod by CRZgatecrusher has been updated to the latest code standards.

Multiplayer Improvements

  • Fixed an inversion of boolean logic with Network_FrameToStartAnyProcessing on ships, which may have been one cause of ghosts; it's hard to be sure.
  • Updated multiplayer clients to track how long it has been since they have heard from the host to be based on the number of sim cycles rather than using realtime OR game time.
    • Doing it via gametime would have adverse effects with regard to the fact that things take realtime. But using realtime like we had been doing had adverse effects if the simulation got paused for a bit waiting on something. For instance, we don't want a temporary network outage to cause the client to suicide all units and then have to rebuild them.
    • The method of using sim steps as the count (each one is approximately 100ms) lets us be far more granular with our checking, because we know that communications must be open for these to be progressing, and yet it is also game-speed-independent.
    • Based on this, all the things that say "it's been x amount of time since this unit was touched by the server" are based on this metric rather than actual realtime (which is what it was before).
    • Also based on that, we now have it set to murder ghosts after 4 seconds, rather than 60 seconds (curiously, it actually turned out to usually be 64 seconds.
    • Thanks to Bummeri and greyhoundgames for reports in this area.
  • Fixed a cross-threading exception that could happen in particular on multiplayer clients.
    • Thanks to KaleR for reporting.
  • Fixed an exception that could happen in DoBailOutChecksIfWasJustCrippled() after units were crippled on MP clients, even if you were not using bail out code.
    • Thanks to KaleR for reporting.
  • Fixed an exception that could happen when trying to unload transports on MP clients. This again is something that just needs to be run on the host in the first place.
    • Thanks to KaleR for reporting.
  • Fixed an exception that could happen during AOE damage calculations on MP clients.
    • Thanks to KaleR and Jusa for reporting.

Beta 2.811 Brief Beta For Balance

(Released April 28th, 2021)

  • Took a quick moment to add a new DoForEntitiesParallel() set of methods, which are centered mainly around wide-spanning "reset or prepare all the things for something that's coming."
    • This is something that should add quite a bit of performance to a few specific areas of the game, but it's really not something to use if you don't know exactly what you're doing in the code. This is the warning label.

Balance

  • Balance Changes
    • Fixed description of dire forcefieled guardian to say units protected by the shield do full damage (instead of only half)
    • Added a 2.2 strength multiplier to the Shredder Dire Guardian -- its strength value was wildly underestimating it because its drones weren't considered
    • Usurper metal cost 12,000 -> 100,000
    • Tier 1 exgalactic unit energy increase 15K -> 50K
    • Tier 2 exgalactic metal cost 2M ->5M; energy increase 15K -> 75K; armor thickness 180 mm -> 245mm
    • Tier 3 exgalactic metal cost 2M ->6M; energy increase 15K -> 100K; armor thickness 180 mm -> 350mm (except Jackalope); mass 8tx ->12tx
    • Tier 4 exgalactic metal cost 2M ->8M; energy increase 15K -> 250K; armor thickness 180 mm -> 350mm
    • Flenser metal cost 2M ->10M; energy increase 15K -> 1M
    • Thanks to Zeus for adjusting.
  • When they are spawned (they always spawn as "early officer fleets"), the following arks and golems no longer have any ship lines included with them:
    • Black Widow Golem (also had AIP capture cost reduced from 15 to 11).
    • Ark One (also had AIP capture cost reduced from 10 to 8).
    • Orchid (also had AIP capture cost reduced from 10 to 8).
    • Rorqual Hegira (also had AIP capture cost reduced from 10 to 8).
    • This lets you keep the option to get a golem or Ark early in the game, but without a giant mass of other ships coming along with it.
    • This doesn't stop this early officer from being stupidly overpowered in most real games, but it does keep there from being such an abundance of extra ship lines right away.
    • This really wasn't exactly what Strategic Sage had in mind when we discussed this, since the golem/ark itself was what was so overpowered, but that's something we'll deal with in a different fashion.
      • On difficulty 6 and down, we are continuing to seed these exactly as we have up until now (within 1-4 hops of a single player homeworld), since this is indeed quite a big boost and is a great early introduction to the game.
      • On difficulty 7+, we are now seeding these "early officer" fleets 6-16 hops away from any of the player homeworlds. This makes them still a presence in the game (and an interesting and inexpensive item you can pick up), but not an early-game power-maw.
    • Thanks to Strategic Sage for the discussion that led to this (among many other things that are coming soon).
  • The ARS now gives 3 strikecraft ship lines as options, rather than 4. Still 1 frigate ship line.
    • Similarly, the TSS now gives 3 turret options rather than 5.
    • And the ODSS now gives 3 other defensive options rather than 4.
    • The idea here is to prevent not quite so overwhelmingly many choices, especially when you consider how many ARSes and TSSes and so forth are actually out in the galaxy in general. This is a very small trim in the main, but it should make things less overwhelming as well as preventing these ship lines from being so devalued from being so common.
    • Thanks to Strategic Sage for the discussion that led to this.
  • The "Mark 2 will automatically be reached for the AI if you have at least 10 strength outside of transports on one of their Mark 7 worlds" now only applies to difficulty 10.
    • Similarly, the "Mark 3 will automatically be reached if you have at least 10 strength outside of transports on their homeworld" also only applies to difficulty 10.
    • Anyone who is playing difficulty 10 is looking for a rough time in general, and there are various ways to attempt to lobotomize the AI by keeping the AIP so incredibly low that the AI barely gets to act. That's not really a normal game at all.
    • Additionally, when this new mechanic was introduced, originally it was to spare players the angst of trying to keep their AIP below the threshold where the AI marks up. The reasoning was that if players did not have that stress point, then they would just freely use the AIP up to the threshold for mark 4 of the AI, and have a more interesting and dynamic time because of it.
    • However, what was actually happening in midlevel and low-level play is that this was essentially outlawing low-AIP gameplay styles, in favor of mid and high AIP styles. For difficulty 10, it makes sense to go ahead and keep this in place because difficulty 10 is its own beast, but for the whole "don't want people to stress about the mark-up thresholds" side of things, that argument just hasn't really held water over the long term, and it invalidated some play styles without meaning to.
    • Thanks to Strategic Sage for the discussion that led to this change.
  • Regular engineers can no longer seed in the ODSS. You'll only get the interplanetary variety, now (which are better). This should also solve the issue of having multiple groups of engineers clogging up the ODSS. However, please do let us know if you do still run into (freshly rolled) situations of too-many-engineers.
    • Thanks to donblas for reporting.

Bugfixes

  • In the event that something causes a ship to change states of matter, and that ship has a "forced to always be state of matter" that is not the default (realspace), then when that ship returns to "normal" it will now return to what it is "forced to be" instead of realspace. This should solve a variety of edge cases for unusual units.
    • Thanks to Zeus for reporting.
  • Adjusted things so that non-human factions can never have the crippled status on their units. So even if a human-style golem gets added to an AI (as was happening with some DLC2 golems and the Gladiator AI type), you'll never run into them being immortal crippled gods. This seemed like the most expedient way to fix the issue, especially when thinking about mods that might make the same sort of error. Just make it not an error.
    • Thanks to Zweihander2021 and Zeus for reporting.
  • Fixed a bug where certain types of golems being added to the AI could wind up having a little fleet of their own, whereas they should have been "just another AI unit."
  • If mapgen can't seed something really close to a specific faction despite wanting to, because of not finding a planet of that faction, it will now throw a visible error during mapgen. It also does a better job in general of trying to find such planets, though. This should hopefully solve the occasional mystery of why one player in multiplayer doesn't have an ARS near them.
  • Made a few of the lists and dictionaries from ArcenSimContext obsolete, and require developers/modders to use [ThreadStatic] local variables for those ones instead.
    • This actually helps to solve a few bugs where we could run into more threads than expected sharing one of these variables and thus running into a problem.
  • Related to the above, a variety of methods for counting planets or iterating over planets no longer require a context to be passed in, and the version that did is marked as obsolete.
    • Here again this lets us avoid some cross-threading problems that were rearing up lately.
  • Fixed a rather funky exception that could happen inside of DoForPlanetsWithinXHops() at random times, but most particularly within mapgen.
  • Put in a variety of defensive code to prevent any exceptions in GetIsPlacementPointSafe().
    • Thanks to CRCGamer for reporting.
  • Put in some defensive code to catch any exceptions in UpdateDataForPlanning().
    • Thanks to Zeus for reporting.
  • Fixed "When Crippled: Bail Out To Nearest Friendly Planet" to properly have text saying that it defaults to off.
    • Thanks to Smidlee for reporting.

DLC2 Mechanics

  • On ship systems, you can now define a inflicts_state_of_matter_on_target_for_seconds="60" or whatever to inflict a certain state of matter on any units that are shot by that system for a certain amount of time. You specify which kind of state of matter with state_of_matter_for_target_to_become="MultiPhase" or similar.
    • This allows for ships to throw other ships into solo or multi phase states, as desired. Either taking them out of the battle for a bit, or bringing them to a secondary battlefield where they can be throttled for a while.
    • Thanks to Zeus for requesting (for DLC2).
  • Added a new cannot_inflict_state_of_matter_if_target_has_any_shields_up="true" option for those same sort of ship systems, which makes it so that if the ship had any sliver of personal shields in place when the shot impacts, it will not cause the change in state of matter.
    • Thanks to Zeus for suggesting for DLC2 mechanics.
  • Added cannot_inflict_state_of_matter_if_target_has_energy_usage_of_at_least="3000" (or whatever number) for those same sort of systems.
    • For this, if the number was set to 3000, then any ships with 3000 energy usage or more would not be affected by this phasing change. Any with 2999 would. Any ships with 0 energy usage will always be affected no matter what.
    • If this field is omitted, then all targets are affected.
    • Thanks to Zeus for requesting for DLC2.
  • Added a new must_be_this_state_of_matter_to_be_enabled="MultiPhase" (or whatever), and a companion care_about_state_of_matter_to_be_enabled="true" for systems of any type (NOT just weapons! Can also be tachyon or tractor or whatever).
    • If the latter is true, then the desired state of matter must match that of the ship itself. So if the ship is currently in multi-phase, this gun turns on. If it's in normalspace, it turns off. Or vice-versa, as you prefer.
    • As noted, this can be used for all sorts of systems, so there's a lot of flexibility there.
    • The care_about_state_of_matter_to_be_enabled="true" might seem redundant, but it's way more efficient to check, and easier to override in copy_from children.
      • So that must_be_this_state_of_matter_to_be_enabled attribute is just completely ignored unless care_about_state_of_matter_to_be_enabled="true", which is nice.
    • There is also a new is_invisible_in_tooltips_if_not_a_match_by_state_of_matter="true" that you can turn on, which makes the systems invisible when the ship is the wrong state of matter to be using them. Otherwise you can see the system all the time, but just with the note "this only works if the state of matter of the ship is X" on there.
    • Thanks to Zeus for requesting for DLC2.

Base Game Mechanics

  • Added tachyon_hits_albedo_more_than. This can be used on its own, or in conjunction with tachyon_hits_albedo_less_than.
    • The tooltips adapt to show less than or greater than or a specific range, as needed.
    • Thanks to CRCGamer for suggesting.
  • There is now a new auto_seeding_on_planets sub-node that you can put on units, that specifies what planets they should be placed on, and what chance they have of being placed on planets of that sort.
    • Please note that this is something that is to be used sparingly, because for each unit, it is evaluated individually rather than as some sort of pool. So these are mainly for fixtures that should have a decent chance of being a part of any given planet matching the description.
    • There is a planet_type attribute on this, which must be one of the following:
      • None, Mark1, Mark2, Mark3, Mark4, Mark5, Mark6NonBastion, Mark7NonHomeworld, AIBastion, AIHomeworld, PlayerHomeworld.
    • There is then a chance_of_seeding attribute, which should be an integer number between 0 (no chance) and 100 (always seeds on every matching planet in every game).
    • Please note that, as with resource_production nodes, these are cleared and start fresh when you move to a copy_from, but they are retained with "parial record" modifications.
    • At the moment, the only possibility when seeding these is that they seed belonging to the same owner as the planet they are seeding on. If we need to get more complicated than that later, we can do so.
    • This is currently untested, as we don't have any units to seed using this yet, but the format would be like this:
      • <auto_seeding_on_planets planet_type="AIHomeworld" chance_of_seeding="90"/> if you wanted to have a 90% chance of seeding a given unit somewhere on each AI homeworld.
    • Thanks to CRCGamer for suggesting.

2.810 Hotfix for Death

(Released April 28th, 2021)

  • Fixed a bug in the prior version where ghostbusting was being so thorough that it was actually preventing things from dying to remains, or being crippled, on hosts and single player machines. The "deep scrub ghosts" logic now only applies on multiplayer clients, and if it gets a bit overzealous and scrubs something too much, the host will be along to fix that very soon after.
    • It's possible that if this leads to brief visual artifacts on the client in an ongoing fashion (that remains to be seen), that we could make this specifically exclude things that die to remains or things that are crippled rather than dying, etc. We'll need more MP testing feedback to know if that's required or not.
    • Thanks to Democracy, donblas, bahrman, and psychophilosopher for reporting.

2.809 Self Optimization

(Released April 27th, 2021)

Balance

  • Balance adjustment for Space Planes and Mirage strikecraft
    • Damage reduction value against distant foes reduced from 99% to 90%
    • Base health doubled from 1200 to 2400
    • The Mirage had its strength multiplier value raised to 2 from 1.6 to account for its shield ignoring damage which quickly disposes of most system defenses when deployed in large numbers.
    • The Mirage had its AI purchase price raised from 15 to 18 to match the price of the Space Plane the base variant. The more dangerous version being cheaper was leading to some gargantuan sized stacks in games with particularly bad RNG for the player.
    • Both ships should now be much closer in estimated strength value to their actual impact since a 99% damage reduction effect against fixed defenses that cannot close distance basically made even a simple mark one stack of ~60 ships have over seven million effective health. Now that same mark one stack would only have about a million and a half effective health. These ships are still quite dangerous if you don't have a nearby fleet or specific counters handy, but shouldn't chain wipe multiple systems on their own.
    • Thanks to CRCGamer for adjusting.
  • Adjusted Expatriate Tech cost scaling
    • Previously was 2000, 2750, 5000, 7500, 10000 science cost.
    • New adjusted costs of 1000, 2500, 4000, 5500, 7000.
    • Makes grabbing a few ranks to improve HRF unlocks or Outguard easier to swallow while the final two ranks are still an expensive splurge.
    • Thanks to CRCGamer for adjusting.

Performance

  • Updated the central DoForPlanets() type methods to now have a SingleThreaded and Parallel variant for each one.
    • The parallel versions are able to run on a ton of threads at once, and are way more efficient. However, there are very strict rules about how they are allowed to touch data. If you're a modder (or developer) for the game, and you don't fully understand what you're doing with this aspect of threading, then always just choose singlethreaded. It's slower but safer.
    • So far, we've used the parallel variants in a few places that should dramatically speed up a few areas of code that were previously bottlenecks in really large galaxies, or with lots of battles going on.
    • There are more places where we could use this, but those would take some refactoring to port over for various structural reasons, so we'll just handle those as they become pain points.

Bugfixes

  • Fixed a couple of cross-threading exceptions that could happen in Base_StrengthData_PlanetFaction_Stance even in single-player on suitably multi-core machines.
    • Thanks to abuchris for reporting.
  • Silenced a pointless "Null ArcenShot InstancedRenderer" error that could happen in ReactToShotHittingSquad() in certain cross-threading instances. Originally we had that code in place to make sure there were no problems, but now it's definitely pointless.
    • Thanks to abuchris for reporting.
  • Fixed a few more cross-threading issues that could happen in GetEnergyUsage() and similar on units.
    • Thanks to abuchris and Bummeri for reporting.
  • Fixed a pretty huge mistake in GetEnergyUsage() where if it could not find the fleet membership, it was using the shield amount of the unit rather than the energy cost of the unit.
    • It's likely that this was never really being hit, because the fleet membership should always be there except when something is in the middle of teardown anyhow, but still oof.
  • Fixed some more cross-threading issues that could happen in DoEntitySecondLogic_FromSimBGThread().
    • Thanks to abuchris for reporting.
  • Fixed a cross-threading exception that could happen in CalculateSpeed(), more likely in MP than SP, but possible in both. Also sped up this method for stationary units in general.
    • Thanks to abuchris and Bummeri for reporting.
  • When the count to spawn on death is set to zero, it no longer throws an exception warning you of this when that type of unit dies. This makes it possible to override that field on copy_from children in the main game or in DLC or mods.
  • If count_to_spawn_on_death is zero, then the "on death, will spawn" part of the tooltip won't show. This is very useful for when we are using copy_from and then forking a unit to not spawn something on death.
    • Thanks to Zeus for reporting.
  • Fixed a number of rare cross-threading bugs that were possible inside of the shot visualizer.
    • Thanks to slake-moth for reporting.
  • Fixed an exception that could happen in GetNumberOfTimesHacked() after a number of hacks were performed on various units.
    • Thanks to Therival for reporting.
  • DoOnFail_CalledFromMainSimOnly() now has very granular exception handling, and will report problems that it has in a sub-area, as well as not actually breaking the entire flow if just part of it goes wrong.
    • Thanks to greyhoundgames for reporting.
  • Fixed some cross-threading issues that could happen with hacks that were in the middle of being failed throwing exceptions. (It's possible that these were things that also had a success but then were triggering a fail at the same time for some reason, but both should be fixed now).
    • Thanks to greyhoundgames for reporting.
  • When a TSS or similar has too-few items to grant, that should now auto-repair itself just like the too-high case does. This is untested so far, so please let us know if that's not the case.
    • Thanks to Metrekec, ArnaudB, GreatYng, and others for reporting.

Multiplayer Improvements

  • In the event that a given unit on a multiplayer client has not gotten any updates from the host for a full 60 seconds, have it just suicide itself.
    • This is a very long timeout, but we want to make sure that this does not kick in by accident if at all possible. Brief interruptions in network connectivity, or a particularly difficult load of ship syncs to cycle through shouldn't be able to accidentally trigger this, is the goal.
    • That said, in the context of 4-5 hour gaming session, or even a 20 minute gaming session, this should hopefully act as the ultimate end-stage "goalie" to catch any client ghosts that sneak through in any other fashion.
    • Thanks to abuchris and Bummeri and their playgroups for reporting.
  • In general, added a two-fold new thing for deleting units that we want to have die.
    • On MP clients, it keeps a record of all the things that the host asked it to delete but that it could not find. If those units later do a ghost check, those units now also check that central list. If they find their name there, they kill themselves rather than going through infinite more ghost checks.
      • The amount of added processing caused by this on clients should be pretty low, and it should make some ship deaths more responsive.
    • In general, when ships die on one of many background sim threads, we now have them write their death into a central concurrent dictionary. The death cleanup process looks through this along with the usual stuff it looks through, and this thus prevents things that are not in the central registry properly from being immortal ghosts.
      • In theory this could have some singleplayer or host applications, but mostly this helps MP clients, at least at the moment. Here again, this should lead to rapid responsible ghost death, and hopefully avoiding hitting the 60-second goalie.
    • Thanks to abuchris and Bummeri and their playgroups for reporting.
  • Added two new commands to the game:
    • cmd:stop sim: Stop the simulation. This halts the simulation on your machine until you enter the command a second time. This can be useful for artificially inflicting "very behind" status on an MP client and then seeing if it can catch up.
    • cmd:resync: Send a fresh copy of everything from the host to all clients. Previously, the only way to really do this was to disconnect and reconnect. This should prove to be a much quicker way of accomplishing the same thing.
    • Details: https://wiki.arcengames.com/index.php?title=AI_War_2:Cheats
  • A variety of the long-term continuous threads are now explicitly barred on multiplayer clients. Something funky is going on where clients are getting some extra orders from somewhere (which is leading to a rubber band effect during battles), and this doesn't seem to be the answer, but it is at least ruling out some possibilities.
    • At the moment we have a test case multiplayer game that rubberbands constantly, and we seem to have reduced the severity of it a bit, but it's still pretty bad. We're still looking into the source of that.
  • The scope of where random seeds are reinitialized for combat rounds has been narrowed down to specific planet factions at each planet. This makes it so that if there is a simulation divergence in one faction on a planet, it won't bleed over into ships of other factions on the same planet. This does help to keep the host and client more in sync in MP, but it isn't the root source of rubber-banding, it turns out.
  • Added a new ArcenGameDebugLogger that allows us to log arbitrary data from the game simulation at various points in a thread-safe fashion (so it does work inside Parallel loops) so that we can do things like compare the output from a host and a client.
    • The rubber-banding issue during combat is something that we can reliably reproduce within seconds with one save in particular, and it really marrs the multiplayer experience, so we'd like to figure out where the heck the simulations are diverging and why.
  • Added a huge amount of debug output options to MovementPlanning, since we were seeing divergences on the client and the host. We're now able to see what actually happens, and more or less why (when we turn the option on in code).
  • Adjusted things so that the auto-kite settings are now properly set in an MP-friendly fashion for the warden and hunter kite-master variants.
    • There's now a centralized method for MP-safe setting kiting settings.
  • The UnitsAutoKite variable on factions has been renamed to UnitsAutoKite_NeverSetDirectlyOrItBreaksEverything, since it seemed to be being set by some outside process.
  • The way that partial-sync status is transferred has been condensed into one style, whereas before it had been split in two, because this makes things vastly more straightforward to make sure are correct.
Death Of Rubber-Banding
  • Fixed an incredibly annoying bug where ships were seeming to rubber-band away to one direction and then back on MP clients. Not always, but if it was happening to you then it was constant.
    • This was the result of actually a much more serious bug that was introduced in the last week or so -- back when the bandwidth for the game was majorly improved, whatever release that was.
    • Normally we were inferring the position of factions in the central index, and taking their data in that way. If there are 18 factions and we send them all in order, then the first one is 0, and the last one is 17. Pretty easy. It doesn't save much data, but why not.
    • Well, I'll tell you why not. When I later had the clever idea to only send player faction data on the highest frequency, it started putting those at position 0 and 1 (0 typically being "natural objects"/nobody, and 1 typically being the first AI but not always) in a two-empire game. This meant that in a two-empire game, it was likely that if the second empire had ship kiting on (it is on by default), then it would turn kiting on for just the client on that first AI faction. This would cause the ships to behave wildly differently on the client compared to the host, leading to constant corrections from the host, aka the rubber-banding.
    • Mitigating this problem was the fact that every second or so, the data for all the factions would get fully copied back over, so player data was no looking entirely insane, and mostly this was being applied to just one AI faction or similar, anyway. But then a few hundred milliseconds after that, it would come back in and write the wrong data into the AI faction again.
    • Overall it's hard to guess how many strange bugs in the last week or so were caused by this, but apparently all of them were subtle enough that just the kiting was abundantly clear since it caused rubber-banding.
    • Thanks to abuchris and Bummeri for reporting the rubber-banding, and giving an idea of how to reproduce it.
Client/Host Collaborative Bandwidth Optimization
  • The host and client now have more robust communications with one another about where exactly they are in the sim-processing pipeline. In the event that the client finds out it is more than 400ms behind, it will start showing a little notice in the upper right corner. In the event that the host becomes aware that a client is at least 1 second behind, then it will show a notice about that.
    • Using our new "cmd:stop sim" command to artificially stall out the client (as if the network connection were interrupted) and then restart it, we see the client doing a proper catchup without any incident at the moment.
    • There are some folks reporting some command lag, and if that is happening then we should start seeing these notices, at least. It may be that the command lag was an artifact of the wrong-faction data being passed in the prior build, or the rubber-band desync data. But in case it's not, now we'll have more information to work with.
    • It's possible that potentially the host is filling the client channel with too much sync data in some cases, causing it to fall behind in a way that this wouldn't replicate, so next we'll deal with that by essentially requiring acks for sync data on the client.
    • Thanks to abuchris and Bummeri for reporting.
  • It's possible that the host was sending sync data at a rate that clients could not handle, in some cases, leading to a general backup of data until the connection is broken and reformed.
    • This isn't something that we can easily check for, but it logically stands to reason, because -- unlike the central game stuff -- we don't ask for any kind of acknowledgement of receipt on that data.
    • Now we do. On the host, underneath the Sync Cycles info in the escape menu, you can now see it counting up a bit more slowly, as it is waiting to hear back from all clients before proceeding.
      • Sometimes a client won't answer, though. Maybe the client just connected and it missed the message, or maybe the client disconnected but hasn't been pruned yet.
      • When this happens, then the host machine will start counting to 60 over sim frames, which might take around 6 seconds overall.
      • If that's happening, you'll see the "waiting for acks" count go above 0. When it hits 60, then it just says "okay, nevermind waiting on the clients, just move to the next."
      • The "Acks Skipped" count will then go up by one, and the most likely result is that all the clients start responding with acks properly after that. After initial connection, you're should be very unlikely to see any Acks skipped, but one or two acks skipped at the very start of a connection to the host is just fine.
        • Huh! Actually, after running for a while, we randomly saw an ack skip happen again, in our own testing. This might actually be some evidence of the network client being overwhelmed, and it gives all of the clients a chance to breathe a bit and catch up.
    • Overall this winds up reducing the bandwidth usage a bit, depending on how quickly the clients respond, anyhow. This does NOT pose any risk of actually slowing down the game simulation (actually, kind of the opposite).
    • This also does not slow down the sync data for the ships themselves, as that's on a separate process that we're not throttling via these acks.
      • There's a very outside chance that the ship data could stack up enough to where this is a problem, in which case we'd need to add acks for that as well. Right now in our testing, we're seeing 75% of the data sent from the host as ship sync checks and divergent ship fixes, so it's possible that now that has shuffled into the top spot as something that actually can become a runaway process.
  • Okay, one last communication vector between the client and host now has acks involved. (The clients all having to say "I heard you and got the data" before the host says the next big chunk of data).
    • This overall is not a giant bandwidth reduction, and it is not too much of a slowdown in how quickly ship sync cycles are completed, but depending on the nature of your network connection between the host and the slowest client, this will cause the syncs to inherently adapt to their environment.
      • Put another way, in a semi-ideal case, the bandwidth is not really lowered. But if things get congested or there's a lot of packet loss, then this will inherently slow down the process rather than just flooding the client with sync info.
    • Overall even in a semi-ideal state, this does seem to be closer to 50% of the network traffic now rather than 75%, so we must have reduced the overall volume if that's the case. It's hard to be too precise between runs, but it does look like maybe a further 20% to 30% reduction in bandwidth usage.
    • Most importantly, these changes are adaptive to nonoptimal network environments of all sorts while not actually slowing down the gameplay, so it should yield better results in basically all situations.
    • The only data beyond this that we could really gate behind acks is all too central to the game running smoothly, and it's also a tiny minority of the data being sent (15% or so), so those will remain un-gated.

Mod Updates

  • AMU:
    • Removed some leftovers from AJEA (Auto-Juggle Energy) debugging.
      • Thanks to Chris McElligott Park for noticing.
  • Kaizers Marauders:
    • Nerfed the Raid Super Battleship's health, shield and damage by 40%, and it loses its boarding strike weapon. It was a ball of super-powered steamrolling nonsense.
      • Thanks to ArnaudB for the balancing feedback.
  • Extended Ship Variants:
    • The Engineering Transport Flagship no longer shows that it's "claiming neutral units" but instead "assists claiming units", similar to engineers.
      • Thanks to Sorrydough for reporting most recently, but I think others reported it a while ago as well.
  • AMU / Kaizers Marauders:
    • Updated to fit the most recent changes in the Vanilla codebase.
  • AMU / Kaizers Marauders:
    • Made some fine-tuning for the DoForPlanets code to avoid cross-threading issues.
    • While doing so found a bug in the Fireteam Maintenance code where it was not moving units to planets of their fireteam if they had no orders at all but still were on a wrong planet. This may already have been caught by the Vanilla fireteam code, but it's good to have fixed.

2.808 MP Ghostbusting

(Released April 23rd, 2021)

  • Add an additional beginner journal for after you've taken the nearby ARS and flagship.
    • This is very placeholder-y and needs to be rewritten by someone more skilled at the game
  • The Hacking menu now shows an estimate strength response for many hacks.
    • This estimates are more what you call guidelines than actual rules. The goal is more to let you see "Oh, this will be something like 10-20 Str response; easy" vs "This is a 200 str response. I need to bring lots of forces"
    • Not every hack has an estimate
  • Some improvements to the ARS section of the beginner journal pointing out that hacking an ARS three times is often risky
  • Added a new "Hacker OS" planet name set by ZeroTheHero.
  • "The Reprocessers" mod by CRZgatecrusher has been updated to have proper shortnames and work with the new sidebar styles better.

Balance Adjustments

  • Make the AI less susceptible to being trapped by forcefields
    • If you have blocked some AI ships retreat path with forcefields over a wormhole, they are now allowed to find another wormhole to retreat to
    • This behaviour is only for AI difficulty >= 7
  • Increased metal production of Zenith Metal Generator from 3000 to 5000 m/s.
    • With energy metal production and costs having been increased in the paradigm, it felt underwhelming for a structure you need to defend, and gave to little of a boost.
  • Increased energy production of Zenith Energy Generator from 600k to 900k.
    • Same logic except it felt lacking compared to economical stations. This makes it great wihout being OP.
  • Increased hull and shield of both Zenith Generators by 10x. This makes them roughly as resilient as a Forcefield mark III. So they don't instantly die the moment forcefields go down. They are very pricy to repair though.
    • Thanks to ArnaudB for adjusting.
  • AI Risk analysers are now less significantly punishing than having Fallen Spire active.
    • Base ExoStrike budget reduced from 20k to 10k. This means the strikes have less strength but are launched faster. (for comparison, One spire city in Fallen Spire intensity 5 is 8k.)
    • Exo strike starts charging after 55min of 40min of gametime.
    • Income for Exostrikes from Risk Analysers changed: 15->50 budget for AI-held analysers, 50->30 for neutral analysers, 150->75 for player-held analysers. With 7+ Analysers, the income from each analyser in all three cases is lower.
    • This change makes using the faction compelling to players instead of an overwhelmingly bad deal. It was worse to hold the analysers than to kill them in every situation. Now, you want to actively hunt down the analysers an deal with them one way or another, because they provide much more income in the AI's hands. Exostrikes are also more common and less deadly, thus better able to take advantage of well-timed CPAs and Waves, instead of a doom tsunami when those happened to sync up.
    • Thanks to ArnaudB for adjusting.
  • Hacking cost on ARSes has been reduced back from 16 to 12. There was a lot of discussion on this, and the boost a build or so back from 8 to 16 was more than had been intended by those originally proposing it. Apologies for misunderstanding, and thank you to everyone for the discussion!

Bugfixes

  • Fix a bug with tutorials introduced in the last patch
    • Thanks to greyhoundgames for reporting
  • Added wrappers to catch exceptions happening in UpdatePowerLevel, CheckIfPlayerHasSeenFaction, and UpdatePlanetInfluence in factions, and make it clear which factions had the error while also not blocking proper execution of other factions.
    • If a mod in particular has an exception in one of these methods, it will now have less of an impact on the rest of the game.
    • Thanks to various folks for reporting the errors in some mod factions here.
  • Fixed a cross-threading issue that could occur in CalculateCurrentShieldRadius(), most commonly on MP clients.
    • Thanks to Bummeri for reporting.
  • Recompiled Civilian Industries because of nonspecific report of them having some sort of exception. Everything seems okay at the moment, and we don't play the mod directly, so until we get a report with more details there's not a lot we can do.
    • There is currently a bug in the Kaizer's Marauders mod that is pending a fix from that mod author, so it may have been having downstream effects on other factions. The changes in this build overall should keep mod faction bugs from impacting other factions.
  • Preemptively fixed a lot of potential rare cross-threading issues in the core unit logic. Preferable to picking these up randomly as they trickle in, largely through MP play.
  • Adjusted a piece of onstart code that allows Kaizer's Marauders to work again.
    • Thanks to various folks for reporting, and NR SirLimbo for helping coordinate what his mods needed versus what the game was now doing, and why.

MP Ghost Busting

  • Fixed another way in which multiplayer clients could have "ghosts" left behind after battles.
    • This is actually a two-pronged thing, with some ghosts that you could even hover over not being zapped before, and with others that disappeared when you hovered, but did not disappear until then because of something like the unit being set to be new to the planet continuously.
    • Both cases are now caught, but it's still possible to have some ghosts in some cases that last for up to 3 realtime seconds or until someone hovers over them. We can pretty much reliably reproduce that, but thankfully that's fairly fast self-correct even if it's not as fast as under a second like the bulk of cases.
    • Thanks to Bummeri for reporting.
  • On MP clients, you can now see how long it has been since a ship has been updated by the server by hovering over it. If it has been more than 5 seconds (realtime, not game time), it will show up in red in general.
  • Made some adjustments on MP servers to do more thorough sync checks in general, which leads to fewer ghosts!
    • This was a case of saving some data to be clever, but in the end causing far more data to be sent in the first place, sigh.
    • This new change has now dramatically cut down the amount of sync data that we send, while at the same time making the client correct faster, aka feel more responsive.
    • Ghosts still happen and get caught, but it's far fewer of them, and they do all seem to be caught by the above process now.

Steamworks Update

  • Updated Facepunch.Steamworks to the newest version from their git repository, moving up from the prior version that was from July 6, 2020.
    • It's notable that under the hood they are now calling a newer version of some of Valve's networking APIs, which I didn't even notice was a thing that Valve did (they do it for backwards compatibility with old games). So hopefully that makes some positive differences.
  • Updated our usage of the Steamworks API to version 1.51, which for OSX also includes shifting the usage from their .bundle file (older) to their new .dylib file.

2.807 Beginner Journals and MP Sync

(Released April 22nd, 2021)

  • Blitzkrieg turret now fires 36 drones every 17s instead of 12 every 6s. This gives the AI more windows to close in before being assaulted by the next wave.
    • Thanks to ArnaudB for adjusting.
  • Blitzkrieg: Reduced hull for Automated Drones from 2240 to 1200 hull and Mini Automated Drones 750 to 400 hull.
    • Death of an Automated Drone creates 4 drones instead of 3 on death.
    • Speed of both drones increased to 2200.
  • Makeshift: Drone speed increased from 800 to 1600.
    • All of those changes make the drones rush in closer to the AI so they can be swatted by splash damage instead of arriving in an ever-stalling wave. The drones are gunbot-like health so they'll die like the chaff they're supposed to be. This makes both raid turrets more powerful on offense and hopefully weaker on defence.
    • Thanks to ArnaudB for adjusting.
  • Base hacking point cost for FRS hacks has been increased from 10 to 22.
    • Cruisers are now 18 instead of 10, and destroyers now 16 instead of 12.
    • Regular ARS is now 16 instead of 8.
    • The hope is to overall have better balance by not giving players SO much power at such a low cost.
    • Thanks to Strategic Sage for the suggestions.

Beginner Journal Improvements

  • Add some new beginner journals to give the player some early game direction. This kinda duplicates the same detail that is in the Intel Menu, but duplicating critical information is good design. I want a new player to feel like the game is actively poking them to make good choices.
    • After a minute of gameplay, the player gets a beginner journal journal entry chat saying "We think we've found a good target for you. See the Journal for more details".
      • The game has detected whether the closest ARS or flagship is the best target (the weaker of those two planets). The journal explains how an ARS or flagship works.
      • When the player has accomplished this first objective, they get a journal prompt about the second objective.
  • Both of these journal entries suggest looking at the Intel menu for more ideas

Bugfixes

  • When exceptions happen in trying to deserialize a table row by index, it now includes the field name properly. This will help fixing exceptions in those serialization areas.
    • Thanks to NR SirLimbo for the report that made it clear we had a gap here.
  • Fixed a funky exception that could show up on at least a few linux machines in the prior version of the game, typically when entering the lobby.
    • Thanks to Badger for reporting.
  • Added three more canaries that are network-only, these ones into hacking events, so that we can identify if there is a problem with them.
    • Thanks to NR SirLimbo for reporting an issue there.
  • Added another canary around the active hacking event on entities, again only for multiplayer. Code review seemed fine, so narrowing it down even further seems needed.
    • Thanks to NR SirLimbo for reporting.
  • Put in some extra paranoid canaries, for the network only, surrounding each kind of external data. That way if a specific mod or subfaction or whatever has a serialization issue, it will become apparent which one it was.
    • Thanks to NR SirLimbo for the report that inspired this change.
  • Fixed a super longstanding MP issue that has become more prominent recently, but has been hiding in plain sight basically since the start, breaking ship sync intermittently and also causing some other issues.
    • Essentially, on MP clients it would not properly say "I finished my current hack" on ships that were hacking. This led to situations where it tried to deserialize nonexistent hacking event data on the hacker every time the host would send it new data, which would then lead to serialization failures and in general a long and continual divergence in the simulations.
    • However, this was something that would fix itself on disconnect or reconnect, or save and reload, so that made this super extra hard to find. Until recently, it was also not clear that this was related to hacking events, because without the new density of canaries we didn't find out things were wrong until long enough after a hack finished that they didn't seem correlated to anyone.
    • This was surely a cause for various other UI and behavior problems on clients, such as likely inability to do more hacks with that hacker, and other things of that sort.
    • We have verified the fix, and knock on wood let's hope this is the last of the mystery sync issues!
    • HUGE thanks to NR SirLimbo and ArnaudB for the multiplayer session and report that led to this finally being discovered and nailed.
  • Fix a bug where ships in Exos weren't properly clearing their exo status if they were against something like a Spire City.
    • Thanks to kasnavada for reporting.

2.806 Correctness By Attrition

(Released April 21st, 2021)

  • Put a flair on AI defensive structures built by the Zenith Trader to make it easy to tell if they cause AIP on death
    • Further work from a bug report by mahisev350
  • Removed the dmg bonus for Nodorian as its main weapon damage did crazy damage.
    • Its attrition is also bugged, doing much less dmg than it should.
    • Thanks to ArnaudB for updating.
  • Reduced RorqualHegira shield from 1.5m shield to 1.0m shield. Reduced shield hack cost from 40 to 20, can be done twice.
    • This basically put it where it was.
    • Thanks to ArnaudB for updating.
  • Improve the hovertext for units that are warping in.
  • Some minor buffs to instigators. The 'Strengthen Wormhole Invasion' instigator should no longer spawn if the AI can't actually send wormhole invasions.
  • When a stacked unit takes attrition damage, it takes numStacks * baseDamage damage instead. This means that stacks are no longer a really effective counter to attrition damage.
    • Also a preemptive nerf to the nodorian totoroid.
  • Fix a bug where battle Notifications could report incorrect enemy strength.
  • Fixed an exception that could still happen in SetAllMembershipsUpFromDesignTemplates(), in MP or SP, largely during map generation.
    • Thanks to Bummeri for reporting.

Quite A Lot Of Multiplayer Improvements!

  • Canaries in MP in the prior version greatly narrowed down the ship serialization issue. Thankfully it does not seem to be in external code. However, we still can't find it. We've introduced one possible fix that is cross-threading related, but for now inserted more MP-specific canaries to get a more detailed snapshot of where the issue might be.
    • Thanks to Bummeri for reporting.
  • Our LiteNetLib implementation has been updated so that if a client disconnects but the host still has a few lingering messages for them, it won't throw any errors. If the client is supposed to be there or is in some other state, it also gives more information.
    • Thanks to Bummeri for reporting.
  • Revised the network sync a bit so that it once again checks the faction and the type of the unit when it comes to correctness.
    • This normally should not be needed, but it is a thing that can happen where ships transform but keep their ID, or in particular when they are gifted between factions (especially subfactions of the AI).
  • Also fixed a bug where when a ship sync happened and there was a faction mismatch, it was not properly changing the faction.
    • This was leading to things like "rubber band ships" on the clients where the AI "sentinels" ships would move in one direction on the client and then jolt back when sync caught them. This is because they were actually hunter ships, which would make different decision (aka sitting there) in this specific case.
    • Ironically, in the quest to save a bit of check data, this absolutely flooded the game with correction data since it couldn't correct things properly.
  • Fixed several exceptions that could happen because of cross-threading on MP clients in particular.
  • Fixed some more rare exceptions that could happen on MP clients when certain state was invalid and a ship tried to transform or similar.
  • Another source of strange behavior on clients (rubber-banding units, or unkillable units) was "ghost" units that were somehow still thought to be alive on the client, but the host knows are dead. When a client mouses over these sorts of units, they destroy themselves, but until then they mess with the client simulation quite a lot. Why exactly these exist is hard to say, but the clients now do a sanity check for potential ghost units, and request full syncs from the server on any of them that are ghosts.
    • The ones that are updated in this way are stale for SOME reason, even if they're not a ghost unit, so this should solve sync issues that can be missed via the main process.
    • In the escape menu if you have detailed info turned on, the client now sees a "Ghost Suspect Syncs" stat. Hopefully it doesn't go too crazy, but it's measuring this.
  • Whenever the game would normally do that "Memory Profile Debug Data On Game Exit" dump to your local log, if you were a multiplayer host or client it also now dumps how many messages and how many bytes were sent and received. For sends, it also has it broken down by channel.
    • This is one of those "hey, that's some useful trivia for us or end users and doesn't take much time or space" things.
  • MASSIVE savings in terms of amount of network traffic. We're talking roughly 75% savings for network hosts and clients. It's based on these two advanced features that have been added under the networking tab:
    • Host: Number Of Skips In Rolling Sync
      • The larger the number, the more of a break the network host takes between giving bulk data about updated planets, factions, fleets, etc to clients. This can dramatically lower the bandwidth requirements of the game, but can also make it take longer for errors to self-correct.
      • This doesn't really have an effect on units themselves, which are synced in a parallel process, so the bulk of things will be fine. Default is 2, but you can push it a bit higher without many issues if your bandwidth is that high.
    • Host: Number Of Skips In Ultra-Frequent Sync
      • The larger the number, the more of a break the network host takes between giving every-sim-frame sync data about things like faction data. This can moderately lower the bandwidth requirements of the game, but can also make the client see a slightly delayed view of certain central numbers.
      • This doesn't really have an effect on units themselves, which are synced in a parallel process, so the bulk of things will be fine. Default is 2, and it's probably okay to go a bit higher if you must. When it 'skips' one of these cycles, it still sends the human-player faction info, so that critical part happens no matter what.
    • This should also make the Steam Tubes style of networking way more playable in general, as the congestion on the main channel will be much lower. This was kind of an "oh, hey, we can do that" sort of moment that came as a surprise.

2.805 Relentless On Several Levels

(Released April 20th, 2021)

  • Fixed not being able to hack for a third Dark Spire design at the Vengeance Generator
    • Note: check if third hack blow up the VG.
    • Thanks to ArnaudB for fixing.
  • Two new kinds of mark level scaling have been added.
    • MobileLoneWolfFleetFlagship now gets whatever is assigned to is_default_for_lonewolf="true" (if there is anything).
    • MobileOfficerCombatFleetFlagship now gets whatever is assigned to is_default_for_officers="true" (if there is anything).
    • Thanks to ArnaudB for requesting.
  • It's not entirely clear what "Threat Waves" were in the current paradigm of the game, or if they were even working. At any rate, they were highly undesirable mechanically if they did work, and they were just an option in the lobby. They have now been removed.
    • Thanks to Democracy and Badger for suggesting.
  • Fix a bug where structures that had died back to neutral could incorrectly be reclaimable during battles, which was a needless resource drain as the AI killed the things you were rebuilding.
    • We were always looking at the "time we were created (ie game start time)" instead of actually tracking the "time we last were killed and reset to neutral", so we would always think that it had been a really long time since the unit was reset to neutral.
    • This was not really a problem until Metal Generators were more expensive to reclaim and the game was trying to reclaim them during a battle
  • Added a new GetDifficultyOrdinal_OrNegativeOneIfNotRelevant() that can be used on factions to get a difficulty or intensity for that faction if one is relevant. For most it just returns -1 right now, but for AI Sentinels it returns the AI difficulty.

Relentless Wave Intelligence Increase

  • When the game swapped to the Relentless Wave faction, waves also got dumber; they would only go after your command station every time.
    • Relentless waves are now smarter; the goal is more interesting and varied (and hopefully smarter and more dangerous) waves. Note that these advanced behaviours are more likely on higher difficulties (and usually won't happen at all on low difficulties).
    • Here are the rules
      • If there's a wave on a planet adjacent to your homeworld, the wave is allowed to just go for the the throat. Note the wave will only do this if it thinks it can make a real run at your king
      • If the wave is outnumbered on the current planet but there's a weak adjacent planet, the wave is allowed to go after the weaker planet
      • The default wave behaviour on a planet is "just fight generically, don't go after anything in particular"
      • The wave is allowed to go straight for your command station on higher difficulties if it thinks that is a good idea
      • The wave is allowed to go after structures that would generate AIP on death
      • The wave is allowed to dispatch really fast ships or cloaked ships to bring down your metal generators
  • Badger was thinking about Bellatrix's steam comment and that the waves could be much smarter. Then he remembered he had already written all that wave intelligence code, it just hadn't been ported over to the Relentless Wave faction yet.

Balance

  • Balance adjustments following yet another difficulty 10 win with a heavy emphasis on Exotic tech.
    • Vampire Turret and Harmonic Turret swap techs.
    • Harmonic Turret reload reduced from 2s to 3s.
      • This is to make it harder to have a good mono-tech turret nest with only Exotic since Harmonic turrets are quite strong on their own with sufficient numbers to cap their gimmick.
    • Acid Turret debuff scaling nerfed from 65 +20/mark to 50 +5/mark
      • This is because the damage is treated as base damage and is multiplied out by things like special damage bonuses, military command percentage damage bonus, and FRS buff fleet damage bonus. And is incredibly powerful for things with high amounts of multi-shot or very high fire rates.
    • Vanguard acid debuff scaling dropped from 30 +10/mark to 20 +5/mark for same reasoning.
    • Parasitic starting fleet adjusted. Parasitic Pike line replaced with V-Wings to make the fleet have a way to catch targets more reliably and to make it not able to upgrade three out of four ships off a single tech.
    • Thanks to CRCGamer for adjusting.
  • Changed military Command damage multiplier to +25% per mark as they were supposed to. The bonus is +0% at Mark I.
    • This was supposed to have gone through over a month ago, I don't know why this went back to 10%+15% mark
    • Thanks to ArnaudB for adjusting.
  • Increased metal cost for Phase 1 and Phase 2 Overlord to 5million. Just so metabolism give a reward to the players, rather than 0 for killing each phase.
    • Thanks to ArnaudB for adjusting.
  • To make the shifted Harmonic Turret fit subterfuge better it now does 2x damage versus targets requiring 2500 or more power.
    • Thanks to CRCGamer for adjusting.
  • Minor balance tweak to the Vanguard drones used by both AI and player versions of Escort Carriers within More System Defenders so they aren't better than regular non-drone version that was just nerfed. Base damage amplification value 30 -> 15
    • Thanks to CRCGamer for adjusting.
  • Changed Crusher so its magnetic Pull now hit 50 targets instead of being an AOE. It kept hitting the closest unit instead of trying to bring in more. That should solve it and make it much better.
    • Thanks to ArnaudB for adjusting.
  • Metal Generators are much tankier but also more expensive to claim.
    • The goal is to make defending Metal Generators something you might actually think about. Previously Metal Generators were extremely cheap to claim but also very flimsy, so they basically were rebuilt as soon as your command station was built (and there were no enemies).
  • AI Allied Scourge at intensity >= 6 now get a faster start
  • Nerfs to the Dyson Sphere to make sure they don't spawn units every second
  • Improve the game's ability to detect when Hunter ships are supposed to be warping out due to defeated enemies
    • Thanks to samnainocard for a save game where an immense number of hunter ships were spawn-camping the dyson

Overlords By Difficulty

  • There is now a separate version of the AI Overlord (both phases 1 and 2) at each difficulty level. The prior version from the beta was really designed for difficulty 8, and so was game-endingly hard on difficulty 6 and similar, while being too easy on difficulty 10.
    • The general changes as compared to the base stats are:
      • Diff 1: 5% of health and attack power compared to normal. Phase 2 speed 150 (was 300 in prior builds). Known as the v0.001proto.
      • Diff 2: 10% of health and attack power compared to normal. Phase 2 speed 150. Known as the v0.002proto.
      • Diff 3: 15% of health and attack power compared to normal. Phase 2 speed 150. Known as the v0.003proto.
      • Diff 4: 20% of health and attack power compared to normal. Phase 2 speed 200. Known as the v0.44rc.
      • Diff 5: 25% of health and attack power compared to normal. Phase 2 speed 200. Known as the v5xrc.
      • Diff 6: 50% of health and attack power compared to normal. Phase 2 speed 200. Known as the x6kx.
      • Diff 7: 75% of health and attack power compared to normal. Phase 2 speed 250. Known as the t7000.
      • Diff 8: 100% of health and attack power compared to normal. Phase 2 speed 300. Known as the t80.
      • Diff 9: 120% of health and attack power compared to normal. Phase 2 speed 400. Known as the z90. That phase 2 speed is no joke.
      • Diff 10: This actually shows off our ability to have multiple overlord variants! Because why not.
        • Diff 10 A: 180% of health and 200% of attack power compared to normal. Phase 2 speed 500. Known as the x4000 Super. This whole thing is a death machine.
        • Diff 10 B: 180% of health and 150% of attack power compared to normal, plus 150% of normal attack range (ow). Phase 2 speed 500. Known as the PFFN. This is also a death machine.
        • Fun fact: I (Chris) have been using the nickname x-4000 online since the late-ish 90s, because it was the name of the villain in a novel I was writing at the time. Different clones from the same facility, or something like that (I was a high school writer, leaving a lot to be desired there). The hero was y-3003, but since I was originally using this online handle as a romhacker, I chose to use the villainous name and it stuck. Now it's actually finally in a work in an appropriate place.
    • Thanks to donblas for reporting what a crazy difficulty spike the Phase 2 overlord was in difficulty 6 games. Thanks to Badger for suggesting the PFFN variant, in honor of Puffin's contributions and long-time battle against diff 10 victors.
  • When savegames are loaded, any older-style AI Overlords will be converted into their newer counterparts depending on the difficulty of each respective AI. So if you had a multi-AI game, you'll have multiple variants of AI Overlord if their difficulties varied.
    • This makes it so that lower-difficulty games-in-progress can avoid the shock super-hard ending difficulty spike.

Bugfixes

  • Put in some new cross-threading protections for when entity order collections are altered in any way.
    • Rather than using a concurrent queue or something of that nature, we are using an old fashioned style of thread lock on the lists in question.
    • There is the very rare risk that this could cause a deadlock, but most likely this would be detected and it will kill the background thread. In the event that happens, we can adjust further. It's also possible that this was the cause of the freezing up that Strategic Sage saw over the weekend, although we're probably not that lucky.
    • Thanks to ptarth and Waladil for reporting.
  • Fixed a regression that was a long-standing issue where if you tried to load a save that failed, and then clicked out of the load savegame window, you would wind up in a purgatory that was half crazed-main-game-ui and half main menu ui.
  • Adjusted our entity order serialization code a bit so that EntityOrderType.Length can actually be serialized if need be.
  • Improved the debug messages when entity systems fail to deserialize.
  • The game now supports putting "canaries" into serialized savegames as well as on the network.
    • This is useful for quickly detecting when there is savegame corruption of some sort, which could be caused by a mistake on our part, or a bug in a mod that contains savegame-style data.
      • Because of the utility with mods, which are ever-changing, this is something we're putting in in a minimally-invasive fashion so that we can leave this in indefinitely rather than just having it when we know we have some sort of problem in our own code.
  • There is some sort of ultra-rare serialization problem with entities that breaks certain savegames. This must be something that has a very strong temporal component, or is using a feature that very few ships use, or something of that nature.
    • Right now we are unable to identify where it is, although we know it is not mod-related. The new canaries are an attempt to locate this, given the rarity of the item in question.
    • We wish that we were able to to solve this directly in one go, but essentially we need a version of this where it is broken after saving with the canaries present in order for us to find it. We've tried reverse engineering it from existing broken saves, but did not find anything conclusive despite a few promising leads.
    • Thanks to ptarth for the one set of saves that had this problem.
  • Put in some better clarity when Astro Trains run into trouble doing a depot event.]
  • Fix a bug where player-allied Nanocaust might snipe player-allied scourge units when they spawn in
    • Thanks to Geeber51 for reporting
  • Fixed a couple of bugs that could happen in DoMilitiaThreatReaction() in Civilian Industries, but in general just instrumented that code so that if it happens again we will know where and why it is happening.
    • Thanks to gigastar for the report.
  • Improve the text of some settings related to player-allied factions
    • Thanks to mahisev350 for reporting.
  • In a number of places in the game, we're updating counts from across multiple threads. It's generally for informational purposes, and originally was not too much under contention. But it has been lately, and we were getting wrong numbers.
    • We are now using System.Threading.Interlocked.Add() instead of just using variable++ as an operator. This performs better, and gives correct results.
  • Rather than using finalizers and other not-so-efficient methods to track objects of which we are suspicious, we are now using a new ReferencerTracker class of our own design, which uses WeakReferences in a ConcurrentDictionary that is fed by the constructors of suspect objects, and which are parsed and pruned on background worker threads every 3 seconds or so.

Multiplayer Fixes

  • Fixed some exceptions that could happen in DeployDroneContents_ONLYCallFromSimBGThread() on MP clients. This should not have been running on clients in general.
    • Thanks to Badger and Zegma for reporting.
  • Put in some more canary code in Client_AcceptDivergenceDataFromHost, which seems to have been having some errors in MP at times.
    • Errors in this could cause various strange afflictions like units disappearing, so finding the root of this is important and this should be a good step on that path.
    • Thanks to Badger and Zegma for reporting.
  • Fixed an exception that could happen during hacks on MP clients. In general this code is again now not run on MP clients. Ships involved are being immediately synced from the host to the clients anyhow.
    • In general, just to be on the safe side, but in extra instrumentation for this even on the host, and split it into its own method, however.
    • Thanks to Badger for reporting.
  • Fixed a number of potential cross-threading issues in ActuallyFireSalvoAtTargetPriorityList(), most of which were mainly able to happen on MP clients, but technically which could likely happen under rare circumstances in SP as well.
    • Thanks to Badger and Zegma for reporting.
  • Fixed some cross threading exceptions that could happen in WriteCityTooltipDetails, mainly in MP.
    • Thanks to Badger for reporting.
  • Canary was hit for some faction's external data in MP, but not sure which one. We have improved the canary code to give us more information about what faction name and type is present.
    • Thanks to Badger for reporting.
  • Whenever you quit the game to the main menu or the OS from an active game (or get booted in multiplayer from a lost connection) it now logs a little "Memory Profile Debug Data On Game Exit" table.\
    • This currently covers how many fleets, fleet memberships, orders, planetfactions, faction, other gameentities, shots, ships, speed groups, fireteams, pathfinders, gamecommands, and planets have been created, garbage collected, and are still active since last reloading the game.
    • There seems to be a memory leak in multiplayer on the clients, and comparing these numbers between client and host should give us some ideas on where that is. It's possible that these are in "external data" somewhere, in which case we will have to greatly expand our footprint reporting.
    • If you're curious, essentially if the number of active ones is super duper high on the client, that's the point of concern for a memory leak. That said, if the number of total ones created is very much higher on the client compared to the host, then that could be indicative of a performance problem (rather than a memory leak).
    • These numbers mean almost nothing in isolation (unless numbers are in the hundreds of thousands or up), so if you report your version of these, please pair the client(s) and the host versions of the report together.
    • If your game is getting laggy near the end of a long session, or clients are seeing strange behaviors, or whatever else, then please do send us these plus whatever other information you feel like is relevant!
    • Fleets or fleet memberships in particular are suspicious right now, as Badger had noted that sometimes on clients not all of the ships would be selected if you press the hotkey associated with that fleet. That could be a different form of code bug, but malformed/duplicate fleets or memberships is the highest likelihood. Paired with general command delays and slowdowns on clients in long sessions that reset when disconnecting and reconnecting, we know there is SOME sort of client memory leak in general.
    • In the absolute worst case, we can brute force fixing some of this (that may be needed in the event that mods are what contain a memory leak, for example, since we can't fix those sorts of things) by doing a complete rebuild on the client periodically, but this would lose some UI state and might be annoying. If we did do it, for the most part it would likely just feel like a "save interruption" in a game like Factorio. And if we did it, it would be an optional thing. For now we'd rather go hunting for the leak.
  • Fixed a number of DoEntitySecondLogic_FromSimBGThread() errors that could happen on ships on MP clients.
    • Thanks to Zegma for reporting.
  • Fixed a whole nest of more things that could go wrong in cross-threading on MP clients in wormhole traversal logic, AI orders reevaluation, etc.
    • Thanks to Zegma for reporting.
  • The way that we were sometimes pre-generating PKIDs on the host and giving them to clients, and the way we were calling CreateNew_CallWithSpecificPKIDID_ClientOrHost(), has all been removed.
    • This almost never worked entirely properly, and tended to cause players to see the things they created exploding and then reforming exactly where they were. It also used more network data than is needed.
    • This was a clever idea before we came up with the concept of our "fast blast" network sync from the host, but now it's entirely unnecessary.
    • This also solves a cross-threading bug that could happen in that code, but that was honestly the lesser of the problems there.
    • Thanks to Zegma for reporting.
  • Introduced more network canaries into the fast blast data, as some of it was not coming through properly for clients in some cases. In all cases, this seems to be ship data, so it's probably the same problem that we're seeing in some rare savegame cases for single player.
    • Thanks to Zegma for reporting.
  • Stacks that are split are now done only on the host, and the data is sent quickly to clients. This avoids some errors that could otherwise happen on MP clients.
    • Thanks to Zegma for reporting.
  • Fixed an exception that could happen in SwitchToFaction() on MP clients. This is now only done on MP hosts and then quickly synced to clients.
    • Thanks to Zegma for reporting.
  • Fixed a couple of cross threading errors that could happen on MP clients in GetIsSelfConstructionBlocked().
    • Thanks to Zegma for reporting.
  • Fixed an exception that could happen in DeployAIReinforcementContents() on MP clients. This is now only run on hosts, and clients hear about it quickly after.
    • Thanks to Zegma for reporting.
  • Fixed up the way that we deserialize squad orders so that it is vastly more efficient for multiplayer clients.
    • This was at least a mild memory leak on MP clients, and possible quite a severe one.
  • Also fixed a memory leak (probably a mild one) in the single-player game related to orders, in cases where the firing orders were invalid for some reason.
    • This was likely very very mild, if it even came up at all. But nice to have things fixed.
  • Fixed an exception in SetAllMembershipsUpFromDesignTemplates() that could happen on MP clients when they were connecting in. That only needs to run on the host anyhow.
  • Multiplayer clients are now a bit slower about deleting ships that were not in the prior sync cycle. They now wait two sync cycles to be sure, as well as not deleting something that is so new it has not been sync-processed at all yet.
    • This should reduce some network traffic, and some flickering of new units, and some issues with units that just moved between planets. This might have the side effect of a few dead entities sticking around for a few extra seconds on the client, but probably not (a different process should catch that).
  • Multiplayer clients now split "catastrophic" ship mismatches (which should be just from a faction switch), and count missing ship mismatches as a separate category.

2.803 Multiplayer Option Overload

(Released April 16th, 2021)

  • Updated the Fallen Spire journals
    • Thanks to Vinco for some excellent feedback
  • Watched Fleets are now above Local fleets if both watched and local are above the ships in the planet tab
    • Thanks to Daw11 for the feedback
  • Improve the text when you are hovering a fleet in the sidebar and ask for more detailed in formation
    • This was annoying Badger
  • Added a new skip_all_waves="true" option for tutorials, which prevents any waves from spawning in them. This is set on for all of our tutorials, as we don't wish for any waves in these specific ones.
    • Thanks to Mr W and Strategic Sage for reporting.
  • Fixed an issue where the GOG linux installer did not have the UnityPlayer.so file. This was missed because we upgraded to a new version of unity, and they moved that file there without us noticing it. Apologies!

Way Too Many Networking Options, But Here We Are

  • Holy explosion of Steam networking frameworks, Batman!
    • So... the networking options that we provided in the prior release did not work for everyone, and we're not sure why. To err on the side of caution, right now we're providing a stupidly high number of options. We'd love nothing more than to pare this back down, so feedback on what works and what does not would be very welcome.
    • There are now SIX variations of Steam networking, and soon that number may be eight, but we'll see.
      • These come in pairs, with Relay being ones that are sent through Valve's servers, and Direct being ones that just go across the general Internet (and sometimes require the host to share their public IP with the clients).
    • The first pair is called Steam Multi-Sockets.
      • These connect via four socket connections on four different ports (as with last release), and thus are way more efficient because of how they are able to avoid data traffic jams. These may not connect for all players, though, or if connectivity is rough, they be more prone to dropping client connections since there are four that must be maintained per client.
    • The second pair is called Steam Tubes:
      • This is the sort of networking we started out with in 2.800. It uses just a single socket connection, no channels or anything, and shoves all the data along it. It is VERY prone to traffic jams, because of this. This should only be used if Multi-Sockets is not working for you.
    • The third pair is called Steam P2P:
      • This uses a different (and slightly older) form of Steam networking called P2P. The underlying technology is completely different from the two forms of networking above. This works phenomenally well for some people, and is very fast for them. For others, it won't even connect. For a few others, for some reason the underlying network actually corrupts data from time to time.
    • In the game, we have ranked all of the various connection types from S tier down to C tier, with color-coding. This was the only real way we could think of to make this at least slightly less overwhelming, but it's still now awesome. Apologies for that.
    • Huge thanks to Fluffiest and bluastelo for helping us live-bugtest this.
      • They eventually got it to work with Steam P2P, but neither Multi-Sockets nor Tubes were working until they made the P2P connection. After the P2P connection was made, Tubes started working... so maybe that means that Multi-Sockets would then work? If so, they could move all the way back to Multi-Sockets, and have the most performant connection possible.
  • Our integration with Steamworks no longer uses asynchronous callbacks. This was causing callbacks to be checked every 16ms, which in some cases is a bit too slow. We are now running callbacks every frame, directly on the main thread, because with those -- particularly the networking ones -- we want to be able to directly get the results asap and we need them on the main thread anyhow.
    • It's possible that the use of async callbacks was what was causing flaky networking via Steam for some folks, but it's hard to be sure just yet.
  • Actually updated our callbacks-running to be even more explicitly checked right before network messages are checked. This should ensure absolutely the most timely possible reception of network messages via Steam.
  • Fixed a random crash that could sometimes happen on clients of Steam Multi-Socket networking.
    • Thanks to Fluffiest and bluastelo for reporting.

2.802 Multiplayer Steams Onward

(Released April 16th, 2021)

  • Adjusted several parts of the game to use EnumerateFiles() rather than GetFiles(), and the same for directories, because these things cause less of a delay when you have a huge number of savegames or campaigns.
  • Updated several aspects of the quick start window and load savegame window to make them load much faster when you have hundreds of savegames on your machine.
  • added_shots_per_salvo_per_mark can now take in non-integer numbers. The result at any given mark level will be rounded down to the nearest integer.
    • The math is [mark level above 1] * [added_amount], rounded down. So if you have a value of 0.6, then at mark 2 it would be just 0.6, round down to 0. At mark 3 it would be 1.2, round down to 1. At mark 4, 1.8, round down to 1. At mark 5, 2.4, round down to 2. Mark 6, exactly 3, and at 7 it will round down to 3 also.
    • If you want an added shot at marks 3 and 5 and 7, then a good number is 0.5. That would give you +1 at mark 3, and +1 at mark 5, and then +1 at mark 7 rather than mark 6.
    • Thanks to CRCGamer for requesting.
  • Balance adjustment to Tritium Sniper Frigate: Now gains an extra shot per salvo at marks 4 and 6.
    • This should make it more competitive with its variant the Ramifier Frigate.
    • Thanks to CRCGamer for updating this.
  • Add a setting to not place the Strike, Lone or Officer prefix before fleet names.
    • Thanks to Badger for adding.

Bugfixes

  • Fixed a bug where electrotoxic effects were not working because we had intentionally disabled them when looking for a certain crash, and it accidentally got left off.
    • Thanks to CRCGamer for reporting.
  • Fixed icon not working in Powerful Command Stations Mod by ArnaudB.
  • Updated the game to allow parsing "false" as 0 when doing xml processing.
    • This solves the problem of potential exceptions when someone has AutoBuildAssaultFrigates in the old format rather than the newer style.
    • Thanks to KingSyphilis for reporting.
  • Fixed a random cross-threading exception that could happen in FindProtectingForcefieldToHitInsteadOfTarget() if the stars aligned just wrong. This could affect multiplayer or singleplayer, and is not a new bug, but is just THAT rare.
  • Fixed a fairly rare bug that was causing units to not serialize properly sometimes. It seemed to be related to the incomingshots list on units, which is something that really should only be sent in fully network syncs but should not be sent to disk or as part of smaller network syncs.
    • Essentially, because of the many improvements made to multiplayer efficiency, this unfortunately had created a miniature version of Russian Roulette (some sort of fantasy chain gun with 2000 slots but only one with a bullet in it), where if you got tagged with it, it would corrupt your save.
    • Thankfully, autosaves are a thing, and in the example save that had this issue, there was an autosave from literally 20 seconds earlier that did not have the problem. And with extensive testing on the same save, we couldn't get it to replicate.
    • That said, some of the persistent intermittent errors that folks were seeing in multiplayer were a lot less rare (because multiplayer takes a lot more tries at Russian Roulette, not because the actual odds changed), and this is probably an accidental discovery of what those were.
    • Thanks to deR Zaubererer and their MP partner for discovering this.
  • Fixed an oversight where the "Intra Galactic Coordinators Permadeath" option was still in the advanced settings, even though IGCs themselves have been removed.
    • Thanks to Democracy for reporting.
  • Fixed an exception that could happen when completing a spire relic hack if the spire relic was not on a nearby planet.
    • Thanks to vinco for reporting.
  • Ships that regenerate in a certain amount of time based on seconds_to_fully_regenerate_hull now will still do it in that same amount of time even if their maximum hull health is increased by outside factors like a hack.
    • Thanks to CRCGamer and Democracy for reporting.
  • Fixed an issue on the ODSS tooltips where it was still saying you could hack four times instead of twice.
    • Thanks to Zer0h1nder for reporting.
  • Removed some old code that would complain about multiple PG factions if they were in the "wrong" order. It was annoying on startup of many savegames.
    • Thanks to Badger for the save demonstrating it.
  • Dyson sphere: add some defensive code for a random crash Badger saw.
    • Thanks to Badger for adding.
  • Fix a typo in the fleets swap line messages.
    • Thanks to Badger for fixing.
  • Fix a very fun bug with ships aggrod by the dyson joining the hunter fleet.
    • This also was a memory leak, and has been around since October 2019. It happened more the more factions you had in general, and the more times you reloaded saves before closing the game.
    • Huge thanks to Badger for hunting this one down and fixing it!

Multiplayer Updates

  • Put in some code with Steam P2P networking that should make it more likely to connect in general for more people.
  • Steam networking has been split into four separate frameworks that you can choose from, rather than (recently) two or (previous to a few weeks ago) one.
    • This lets you choose between Steam P2P direct or relayed, or Steam Sockets (formerly Steam Connection-Oriented or C-O) Direct or Relayed.
    • The Steam P2P Direct method is new and doesn't require any special configuration. You just select a steam friend and hit connect like always. It may or may not work well, though.
    • The Steam Sockets Direct method is also new, and requires you to connect via IP address, which the host must provide to you. This works with both local and public IP addresses, and should be able to avoid NAT punchthrough -- but if that fails, you will still need to use Steam Sockets Relay to work around it.
      • This method is noticeably faster than any of the other Steam methods, but slightly less convenient because of the whole IP-sharing thing.
  • On the networking tab, there is now enough room in the textboxes for you to read IPV6 addresses.
  • The call to find your public IP address is now run asynchronously, so when you first click into the networking tab it no longer has a moment of lag while it contacts a server to find out what your IP is for you.
  • When you are in the lobby as a multiplayer host, or in the escape menu as a multiplayer host once a game has started, it now specifies what your public and local IPs are if you are on the sort of networking framework that needs that.
    • In those places, it also specifies what networking framework you are using, in general.
  • In the escape menu, if you are in single-player mode, it now will also show that. It looks like there were some ways for people to wind up no longer being a host without realizing it, and this will let people actually check. This is possibly what was leading to some (but definitely not all) connection issues for some folks.
  • Fixed a bug where if you tried to load a savegame to host in multiplayer, but encountered an error, then it would switch you to single-player mode. That was going to be a problem if you were then expecting clients to be able to connect!
  • Major networking improvement for the Steam Sockets networking style!
    • Steam sockets does not support multi-channel data, which is very limiting when it comes to sending main data quickly, but also having other large pieces of data that get there in a relatively-timely-but-not-so-urgent fashion.
    • To work around this, we basically followed Valve's suggestion and built in a multi-port solution, which uses the port you have chosen (for direct connection), or the virtual port 0 (for relayed connections), plus the next 3 numbered ports after that.
    • You can now see in your log as the client and host make and accept connections on each of those four channels/ports, and once all four are connected, then it starts sending data across them as needed.
    • If any of the four drop, then it will kill them all, but there's not really any reason to think that disconnects should be more frequent because of that. That was my original fear, but if that does happen I can potentially work around it a couple of ways. I have yet to see a disconnect, though, which is good.
    • Overall this takes the data sent from the host to clients, and makes something like 97% of it go on the secondary ports, which is a gigantic boost to the ability of the main port to send and receive timely information to keep the game going.
  • The two Steam P2P network options have been commented-out for now, making them unavailable for use. The only advantage that they had over Steam Sockets was that they could send multi-channel data (and that was a huge advantage). But P2P has been very unreliable, and other game developers are recommending to avoid it. It's still there in the xml if someone needs to uncomment it and try it for some reason, but we're hoping to have fewer options to confuse people.
    • The need to have Steam Sockets Relay and Steam Sockets Direct as two separate options will pretty much always remain (because they work fundamentally differently and have very different pros and cons), but we'd definitely like to avoid having a silly amount of choices.
  • Fixed up an issue where MP client machines could mess with the hack options of TSSes, ARSes, and similar. Now that is strictly handled by the host, and any changes that are made are sent to the clients post-haste. This was mostly already being caught and fixed on the client, but there was no good reason for the client to be doing this, and it just added inconsistencies to fix.
  • Fixed a very funky exception that could happen in DoFactionStepLogic_Stage2 on random factions on MP clients in particular, but in MP in general.
  • Fixed a variety of exceptions that could happen in HandleAutobuild() mainly in multiplayer, on the host or clients, due to cross-thread racing. Technically it could also happen in solo play, but we haven't seen any evidence of it actually doing so.
    • Thanks to Badger for reporting.
  • The "BLARRRGH! Only authorized to execute through frame" error is now silenced. That... really wasn't actually a problem that was worth even complaining about. This was something that was showing up lately in at least a few multiplayer sessions, though something else seemed to be going on with them in general.
    • Thanks to Badger for reporting.
  • Fixed a possible issue in multiplayer where out of order messages from the server might have potentially messed with the Network_AuthorizedToExecuteThroughFrameNumber.
    • There should not be out of order messages in the first place, but just in case.
  • Fixed an issue in CheckForInternalShipDeployment_ReinforcementLocations() that could happen on MP clients, which really did not need to be running that logic anyhow.
    • Thanks to Badger for reporting.
  • Fixed an exception that could happen in SpawnRaiders() on Marauders in multiplayer clients. Again not something they needed to ever do, it's left to just the host now.
    • Thanks to Badger for reporting.
  • Fixed a number of possible cross-threading issues in CalculateShipsThatYouCanCapture(), which were vastly more likely to happen on MP clients.
    • Thanks to Badger for reporting.
  • Fixed several more cross-threading bugs that could happen in WriteFleetTooltip(), again way more commonly on MP clients than anywhere else.
    • Thanks to Badger for reporting.
  • Fixed another cross-threading bug that could happen in Hacking_GrantShipLine_DontDestroyTarget.GetCanBeHacked(), again mainly on MP clients. The obvious potential errors have been fixed, but then also it will now show in the ui an "error at debug stage x" message if it still runs into one. It will also silently log the error for us to look at more later, and to be able to further fix if need be.
    • Thanks to Badger for reporting.
  • Fixed an exception in SetNextTargetForTradeStation() that could happen on multiplayer clients using the Civilian Industries mod.
    • Thanks to Zegma for reporting.

Prior Release Notes

AI War 2:The Paradigm Shift