BaYoNeTTe's mods

Hello space settlers,

I plan to do a bunch of smaller and maybe also slightly bigger mods around various features of the game. Since some of them may be useful, I’ll publish them on Steam. Here you can find additional information (especially about compatibility issues with other mods, if known), report bugs or even request new mods that I may assist in doing. Although my spare time is very limited, so don’t expect too much :disappointed_relieved:

logo StartGamePaused

Once after loading this mod hits the pause button for you (and also after dismissing the welcome dialog on a new game). If you are one of those people like me who may wander off doing other things during the sometimes lengthy loading process, then this mod may be for you.

logo NoLevelUpMessage

Suppresses the city level up messages. Since they have no real meaning in the game anymore and can be quite annoying if your habs downgrade frequently below a level-up threshold, this mod helps you get rid of them.

logo Clean Terraforming Panel

First of all this gives you a steeper color gradient when looking at total progress so you can discern spots not quite at 100% more easily.

Secondly this fixes some calculations regarding Terraforming. It didn’t take into consideration the whole map but only a quarter of it, which should be fixed. More importantly, the map coverage of the individual terraformers now consider only the playable map area rather than the whole world, which should be much more useful.

Keep the game running for at least a minute after loading to get accurate numbers. Terraforming progress is only very loosely saved, so the game first needs to warm itself up after loading.

I am sorry if there are some issues and remaining inaccuracies in this mode. Fixing this was a lot harder than anticipated.

logo Consumption At Start

Resources are removed from the incoming storage at the start of each production cycle, rather than at the end. This will fix several issues you may have with deliveries not being made in time. This also enables Drone Fertilization to work correctly.
Another small change is that buildings with almost full output will stay at 100% progress until at least one of their producibles falls so low that finishing the production won’t waste any of that producible (vanilla IS: as soon as 1 output is missing 1 unit, it will finish production, potentially wasting a bunch of its outputs).
At the same time this update smoothes out production times by reducing a mini-lag of several frames that occurs in each cycle. This makes your production numbers more accurate (the numbers stay the same, but the actual production changes).

Finally, unless your infrastructure is sub-par you will now be able to supply all buildings with their resources before they stop production. So I made all buildings issue resource shortage warnings immediately instead of having a 10s grace period. Same for power. Also applies to habitats.

Car Speed Visualization

When turning on car visualization your cars won’t all be red. Hopefully at least. Cars get color grades: red, orange, yellow or green, based on their speed. They will be green at a speed of 60 or faster, which is a concrete road. I chose this as the limit for green because that is the minimum road level you want to have in late game. If you forget to upgrade some roads, cars will only be yellow on gravel road. Side roads only allow for orange speed but that is ok. If you see red anywhere, then you have a problem in that place. This mod will help you find the places that prevent you from reaching 100% traffic flow.

If you have really many cars, using this mod may impact performance quite a bit. Getting this to work at all required some tricks, so please let me know if there are any issues.

More Raods On Big Stations

The Large Station and the Main Station have a total of 8 input and 8 output roads, so twice as many as previously. The duplicates are next to the original ones, so now inputs and outputs come in pairs. This mod is a quick placeholder for a proper revamp of the (bigger) stations that I want to do at some point.

logo Convenient Laser Targeting

Improves your experience with the laser targeting station in the following ways:

  • Mineral deposits can only be selected when you hold CTRL while clicking. No accidentally lasering your good stuff away. (To de-select, also hold CTRL!)
  • Misclicking doesn’t deselect the targeting station.
  • Holding SHIFT you can select a whole area to be lasered clean (except minerals).
  • Improve the highlighting of selected targets.
  • Add a button to the menu bar that will select a laser targeting station. Doubleclick will zoom to it as well.
  • All targeting stations share a target list. This helps avoid some bugs that exist in vanilla InfraSpace.

Warning: With this mod it is very easy to select many objects at once. The GUI doesn’t like that though and there is no way to unselect an area. If you accidentally select too much, you will have to demolish all targeting stations to quickly deselect. Also, it will still take hours to laser everything into oblivion, because lasering speed is not adressed with this mod.

Retain Intersection Settings

Makes a much harder effort to retain your intersection settings.

Many operations in vanilla IS are destructive to your intersection settings (lane connection rules, traffic signs and traffic lights). This mod tries to protect your settings in many such cases.
For example the replace-road tool will keep your settings if the amount of lanes doesn’t change.
Reversing two-way roads is no longer possible, because that also had the effect of erasing some of your intersection settings without any actual benefit.

Car Path Visualization

Clicking on a car shows the path where it came from in addition to the one it intends to take.

Note: When a car needs to re-route on its way to the destination then it will forget the entire past path and the mod can’t show it to you anymore.
Unfortunately this happens very frequently. Addressing this issue is very difficult or maybe even impossible, I’ll look into it in the future.

There are a lot of other improvements I can do to this mod. Hopefully I will find time for that at some point.

diamond Mines and Diamonds

Reworks balance of mines and adds new related content.
(This mod will not work well with existing saves due to changed building sizes and some other balancing changes.)

First, here is a summary of all changes:

  • All mines have a longer production cycles, releasing minerals in batches.
  • Most mines have a bigger footprint.
  • Large mines need much more power and a few more people.
  • Large mines produce even more resources compared to small mines.
  • Large mines consume motors during operation (1 per batch).
  • Motors are slightly cheaper to produce.
  • New resource Diamond.
  • Diamonds can upgrade mines to increase yield.
  • High tech tools and the drill need Diamonds instead of methane.
  • New building: Diamond Synthesizer. Requires a new tech Diamond Coated Tools to unlock. Turns carbon into diamonds.
  • New visualization overlay for resource deposits on the map.
  • New building: Seismic Prospector. Requires a new tech Seismology. Increases minable area around mineral deposits in its range.
  • New car models for trucks carrying ore (sand, iron, copper, aluminum, iridium, uranium, adamantine).
  • New models for sand and sulfur mines to match their footprint.

Release All Trucks

A tiny mod that fixes an issue with cars being deleted before they leave the factory, causing goods to be lost and production numbers to be wrong. Happened to me very much with return trips on.

2 Likes

@Daniel While fixing the Terraforming Panel (see above) I hopefully resolved some bugs (or intended behavior?).

First of all, the individual terraforming types’ map coverage should only relate to the playable map area. The players have no interest in the total world coverage, I think.

To fix this, two places need to change. The first is TerraformingManager.GetTerraformedTypeCoverageArea(). It needs to look something like this:

        public float GetTerraformedTypeCoverageArea(string type)
        {
            int tilesOnPlayableMapPerDim = (int)(progressDim.x * playableAreaSize / worldSize.x + 0.5f);
            return (float)(terraformBuildingsManager.GetTerraformedPointsCountPerType(type)) / (tilesOnPlayableMapPerDim * tilesOnPlayableMapPerDim);
        }

If you look at the original you will see that the playableAreaSize cancel’s itself out in the calculation, thus you end up with dividing by the terraforming tile count of the entire world.

The second part that needs to change is in TerraformBuildingsManager.TerraformerJob.Execute(). I had a really hard time working with this one because I can’t patch the method directly. I guess that’s because of the attribute [BurstCompile] :sob:

My decompiled version probably looks a lot different than your original. It has a ton of local variables that are just decompiled to Num1, Num2 etc. for which I devised new names based on what I thought their meaning was. I will use screenshots for this explanation.

First of all, this code section which is used for the individual terraform type coverage needs to move down into an IF so they are only counting the playable map area:


This will basically be the required changes for the playable map coverage. But the Execute() method also has another severe issues, which is happening here:

The variable I dubbed progressOnMapStart is calculated correctly, but the variable progressOnMapEnd is not. It is using the size of the map, whereas it should really use corner+size, e.g. like this:

int progressOnMapEnd = Helper.ProjectClampInt((int)mapCorner + mapSize, 0, (int)(worldSize - 1f), 0, terraformedProgressDim.x - 1);

The mapCorner is 512 or something, the mapSize is 1024. So you want the range from 512 + 1536 covered. At the moment you are only covering 512 to 1024, which (since we are talking surface area) is only a quarter of the playable map.

Changing this may incur some rounding issue. In my version, I also needed to change the following condition, turning less-than-or-equal to less-than only:

Hope this helps make InfraSpace even better!

1 Like

Thanks a lot Bayonette!

From a quick glance it seems like you are right. I’ll look into it later this week.

1 Like

@Daniel I released another mod, Consumption At Start. I consider this an overall improvement to the game, so suggest to considering to take this over into the main game.
But the reason I’m mentioning you is not because of that, but because I found several things while creating this mod. Two tiny bugs I highlighted in separate threads. But there is another issue I learned about that you should pay attention to:

There is an inaccuracy in FactoryProductionLogic.UpdateSimulationThread(). This causes production times to longer by about 10 frames than they are supposed to. For factories with slow cycles this is hardly relevant, but for fast ones (5s, or even faster with efficiency boosts) this amounts to about 4% slower output than you are advertising.

I made a setup with just a sand mine (5s cycle) on a basically empty map, so frame rate was constant. I measured about 10 cycles as accurately as my reflexes allowed, and the real time was always longer than 5s, usually it was around 5.2s. The 200ms is equal to the 10 simulation frames I mentioned. I tried to fix the deficiency with my mod, too, and measured again. The times were spot on 5s, or very slightly around that (measurement inaccuracy).

The problem is here:

			if (productionTimeStep < productionDefinition.timeSteps)
			{
				productionTimeStep = Mathf.Clamp(productionTimeStep + possibleProgressPer10Frames, 0, productionDefinition.timeSteps * 2);
				lastProductionSteps = possibleProgressPer10Frames;
			}
			else if (!OutgoingStorageFull())
			{
				Produce();
				productionTimeStep = 0;
			}

When a production cycle is finished, you simply set the productionTimeStep to 0. This doesn’t account for the fact that production in those 10 frames may have exceeded 100% progress. E.g. if it was at 99.95% in the last update and afterwards it is at 100.45%, then you basically wasted 0.45% of progress. This would be no problem for a sand mine operating at 100% efficiency though, because it makes 1000 progress every 10 frames and needs exactly 25000, so it always hits the number spot on. A second effect is that you need to check for the progress immediately after you added the progress. The current code waits until the next update to check for progress. These 10 frames are wasted, waiting at 100% progress. I think you can even see that on the progress bar if you have very quick eyes. There is a tiny stutter at 100%.

For reference, my implementation:

Code

I also needed to change Produce() and Building.UpdateFrameThread(), but FactoryProductionLogic.UpdateSimulationThread() is the meat of the action.

byte district = WorldScripts.Inst.districtsManager.GetDistrict(__instance.consumerProducer.building.GetPosition());
            __instance.consumerProducer.lastStepPowerProduced = 0f;
            int possibleProgressPer10Frames = Mathf.RoundToInt(100f * __instance.GetEfficiency()) * 10;
            ___lastProductionSteps = 0;
            if ( ( ( __instance.logicOverride != "spaceship"               ) ||
                   ( __instance.productionDefinition.consumables.Count > 0 ) ) &&
                 ( ( !__instance.HasTerraformingLogicOverride()      ) ||
                   ( __instance.consumerProducer.building.HasPower() )       ) &&
                 ( !__instance.OutgoingStorageFull()                         ) &&
                 ( ( ___productionTimeStep > 0             ) ||
                   ( __instance.IncomingStorageFulfilled() )                 ) )
            {
                __instance.couldWork = true;
                if (___productionTimeStep == 0 && possibleProgressPer10Frames > 0)
                {
                    ModifyIncomingStorage(__instance, -1);
                }
                ___productionTimeStep += Mathf.Min(possibleProgressPer10Frames, __instance.productionDefinition.timeSteps);
                ___lastProductionSteps = possibleProgressPer10Frames;
                if (___productionTimeStep >= __instance.productionDefinition.timeSteps)
                {
                    __instance.Produce();
                    if (__instance.IncomingStorageFulfilled())
                    {
                        // immediately produce again
                        ModifyIncomingStorage(__instance, -1);
                        ___productionTimeStep = Mathf.Max(___productionTimeStep - __instance.productionDefinition.timeSteps, 1); // 1 minimum to mark that resources were already spent
                    }
                    else
                    {
                        // no resources, reset progress to 0
                        ___productionTimeStep = 0;
                    }
                }
                __instance.consumerProducer.lastStepPowerProduced = __instance.productionDefinition.powerOutput;
                if (__instance.consumerProducer.lastStepPowerProduced > 0f)
                {
                    __instance.consumerProducer.lastStepPowerProduced *= __instance.GetEfficiencyExceptPower();
                }
            }
            else
            {
                __instance.couldWork = false;
                if (__instance.HasTerraformingLogicOverride())
                {
                    Old.buildingModule.terraformerUpdater.UpdateEfficiency(__instance.consumerProducer.building.GetID(), 0f);
                }
            }
            double productionFactor = 5 * 60 * possibleProgressPer10Frames / (double)__instance.productionDefinition.timeSteps;
            foreach (ResourceCost consumable in __instance.productionDefinition.consumables)
            {
                Old.GetSimulator().market.AddConsumptionPerSecond(consumable.resource, consumable.amount * productionFactor, district);
            }
            foreach (ResourceCost producable in __instance.productionDefinition.producables)
            {
                Old.GetSimulator().market.AddProductionPerSecond(producable.resource, (double)producable.amount * productionFactor, district);
            }
            __instance.consumerProducer.lastStepPowerNeeded = (float)GetPowerNeeded.Invoke(__instance, null);
2 Likes

It seems you can’t edit posts anymore after 1 month? @Daniel It would be nice if you can change this setting, even if just for me. I really need to edit posts in the modding category for longer than that. There’s also the reference topic, and I plan to have a bigger mod in the future that will also need updates over a longer period of time.


I think there is an open point about laser targets not being highlighted in all cases. Some environment objects don’t highlight properly or only very little. I tried many different settings and in the end what worked best across almost all objects is to set the _EmissionMap to a plain white texture while the object is targeted. You are using the emission map to create some nice glow effect for some stuff, but it’s making setting the emission color useless. I also deleted the special shader cases, because they don’t seem to be relevant for environment objects? Here’s my current version:

[HarmonyPatch(typeof(EnvironmentObject))]
public class EnvironmentObjectPatch
{
    private static int emissionMapID = Shader.PropertyToID("_EmissionMap");

    [HarmonyPatch("SetTint")]
    [HarmonyPrefix]
    public static bool SetTint(Color color, EnvironmentObject __instance, ref bool ___tintUpdatedDuringOverrideMaterial, bool ___overrideMaterialActive,
                               ref Color ___tintColorCached, Color ___noTint, int ___emissionColorPropertyID, int ___colorPropertyID)
    {
        bool updateAfterOverrideMaterial = ___tintUpdatedDuringOverrideMaterial && !___overrideMaterialActive;
        if (color == ___tintColorCached && !updateAfterOverrideMaterial)
        {
            return false;
        }
        ___tintColorCached = color;
        ___tintUpdatedDuringOverrideMaterial = ___tintUpdatedDuringOverrideMaterial || ___overrideMaterialActive;
        if (updateAfterOverrideMaterial)
        {
            ___tintUpdatedDuringOverrideMaterial = false;
        }
        bool useNoTint = color == ___noTint;
        MaterialPropertyBlock emissionColorMpb = new MaterialPropertyBlock();
        emissionColorMpb.SetColor(___emissionColorPropertyID, color);
        emissionColorMpb.SetTexture(emissionMapID, Texture2D.whiteTexture);
        for (int i = 0; i < __instance.meshRendererInfos.Count; i++)
        {
            MeshRendererInfo meshRendererInfo = __instance.meshRendererInfos[i];
            MeshRenderer meshRenderer = meshRendererInfo.mr;
            if (useNoTint)
            {
                meshRenderer.SetPropertyBlock(null);
            }
            else
            {
                meshRendererInfo.sharedMaterial.EnableKeyword("_EMISSION");
                meshRenderer.SetPropertyBlock(emissionColorMpb);
            }
        }
        return false;
    }
}
1 Like

ok, I changed the setting. Can you edit your old posts now?

2 Likes

Yes, the button is back. Much appreciated!

1 Like

I really like the car speed visualization mod! It helps tremendously for trying to check for those random “everyone change lanes” issues when you have modified a road, especially on superhighways. I already found a couple errors that simply needed a rebuild of the affected road sections. One other odd bug/issue I noticed was on some long stretches of Superhighway that I had extended manually instead of letting the game make its normal segmented sections of road: when I scrolled the camera past a couple of these long sections, the deliveries were completely disappearing while/when I scrolled the screen! After rebuilding them the bug/issue went away. I was losing a TON of resource deliveries that I didn’t know about. Which was definitely causing more “Habitat Downgraded” issues, even when using Distribution Centers. Thank you!

Glad you like it so much! I’ll be making more user interface and quality of life mods like this in the future. But for now I’m a bit stuck on technical difficulties with my current work. That’s why there hasn’t been any new content lately.

1 Like

Finally got to Terraforming, and your mod still helps/shows more info! Not sure if it’s “needed” to get to 100% terraforming progress, but here are some screenshots showing that your increased gradient range still has an effect with the current release version! (ver 1.35.426)

(I would ignore the differences in displayed %'s in the left panel as I did not give the game any time to recalculate, eg you can see in the lower panel’s display it shows 0% magnetic field which is not true as I definitely have the magnetic field generator in operation. UPDATE: just checked again after letting the game run for a bit and the %'s now all match the %'s shown without the mod enabled, so all good! :+1:)

Without Clean Terraforming Panel:

With Clean Terraforming Panel:

Thanks again BaYoNeTTe :beers:

1 Like

I released a new mod Car Path Visualization. It helps by showing the past path in addition to the future path.

This was a really quick implementation though and it has a lot of shortcomings. The worst part is probably that cars forget their past path when they reroute. In vanilla IS this behavior makes sense because the past path is irrelevant. But that also means that fixing this should be possible: just save the old past path and prepend it after rerouting. If it doesn’t connect seamlessly for whatever reason it should still look good.

Then there are some artifacts in the visuals that I can’t quite explain yet. And trains also look a little weird. Not sure if this is easily fixable. I also want to change the color of the past path but that isn’t as easy as I thought. This needs research.

When all that works then I also want to add a feature to factories (and potentially other buildings as well) to visualize where all their currently incoming cars are coming from. I think that’s going to look both cool and be useful for analysis of traffic issues. Same for outgoing traffic but it may be a lot harder.

After several months of works I released my first mod that actually adds new content: Mines and Diamonds.
If you look at the result you wouldn’t think it takes that long to create this mod and you’re right, but I first had to learn several new skills and also solve many problems (including motivational ones!) along the way. Glad it’s finally done. New similar mods should be easier for me to do now.

Thank you for doing this work. Is there any way a GOG user can download your mods outside of the Steam Workshop?

1 Like

Yes, please have a look at Mods for non-Steam players - #2 by BaYoNeTTe

If you see a mod on Steam that you like but that is missing on Nexusmods, then you can also ask in Discord if a Steam user can download it for you. Not sure if this is legally ok but I suspect nobody cares…

If you have a specific feature request you can also tell me. If I think it would make IS better than I may create a mod for it.

1 Like

Wow, thank you! I was just on Nexus, and it only showed about two mods. Not sure what was up with that.

What got me going down this route was little things that bugged me in the game, and these mods you’ve assembled do that and much more. Really appreciate your posts here.

Hope you don’t mind if I post this here: I’ve been running all of your mods, and really enjoying the extra bits they add to the game. However, I’m running into a crash right now. It’s happened a couple of times so far, around when I’m deleting or modifying roads. The crucial stacktrace seems to be this:

0x000001887EE9C7BC (Mono JIT Code) (wrapper managed-to-native) UnityEngine.GameObject:SetActive (UnityEngine.GameObject,bool)
0x00000188CD6C6FBB (Mono JIT Code) NotificationManager:ShowNotification (NotificationConfig)
0x00000188CD6C6A33 (Mono JIT Code) NotificationConfig:Show ()
0x00000188D5759FEB (Mono JIT Code) BaYoNeTTe.EnvironmentObjectPatch:Deselect (bool)
0x000001887F8CD703 (Mono JIT Code) (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition:EnvironmentObject.Deselect_Patch1 (EnvironmentObject,bool)
0x00000188D5759C54 (Mono JIT Code) MultiSelector:HandleLeftClickDeselect (MultiSelectable,bool)
0x00000188D5759983 (Mono JIT Code) MultiSelector:DeselectTarget (MultiSelectable)
0x00000188C7E48123 (Mono JIT Code) LaserProductionLogic:UpdateSimulationThread ()
0x00000188C7A17FC6 (Mono JIT Code) ConsumerProducer:UpdateSimulationThread (bool)
0x00000188C7A11D63 (Mono JIT Code) Building:UpdateSimulationThread ()
0x00000188C7A11BA6 (Mono JIT Code) NodeUpdateSimulationTask:Execute ()
0x000001887F52DE3A (Mono JIT Code) Job:Execute ()
0x000001887F52DBAB (Mono JIT Code) Unity.Jobs.IJobExtensions/JobStruct`1<Job>:Execute (Job&,intptr,intptr,Unity.Jobs.LowLevel.Unsafe.JobRanges&,int)
0x000001887F52DCAA (Mono JIT Code) (wrapper delegate-invoke) Unity.Jobs.IJobExtensions/JobStruct`1/ExecuteJobFunction<Job>:invoke_void_T&_intptr_intptr_JobRanges&_int (Job&,intptr,intptr,Unity.Jobs.LowLevel.Unsafe.JobRanges&,int)
0x000001887F52DAA6 (Mono JIT Code) (wrapper runtime-invoke) <Module>:runtime_invoke_void__this___intptr&_intptr_intptr_intptr&_int (object,intptr,intptr,intptr)

Are you able to tell by this what’s going on?

The game crashes when the laser destroyed the last target in its list and tries to raise a notification about this. Try disabling the notification: go to your save file and edit it (make a backup copy before you do!). Look for notifyWhenEmpty and set it to false. Save the file, load the game and please report if you have any more crashes with the same stack trace.


When I released the mod this problem never happened but now it does very regularly. It’s not even a usual exception but it’s something inside the Unity game engine that breaks down. But the devs didn’t update the engine as far as I know so I can’t figure out why it happens now all of a sudden. I also didn’t get very far with debugging yet. It’s on the top of my list once I can work on the game again, which still takes a while because I’m not at home these days.

1 Like

Your suggestion appears to have done the trick, thanks! I noticed how the stack trace wanders off into the depths of the Unity engine so I figured you might have your work cut out for you on this one. Thanks again for everything you’ve done though.