That is great I was worried you might get stuck on this one (as anyone easily can)
andrew-raphael-lukasik
Creator of
Recent community posts
Please don't go overly complicated with game saving. Start small, release, expand/fix later. Don't try to save complex stuff from the start (let game lose some data); saving/loading just structures, resources and where/how many units there are - will be more than enough for now! Even just structures will be ok for first release.
I say that because serialization can easily become very complicated, especially when you want to save graphs (ai planning states) or object references (guaranteed duplicates when deserialized naively) - headache^2, don't even go there right now!
(0.12.11) Dillema: No amount of containers is enough
There is no way right now to cap, for example, how much of minerals or ice mining lasers prospect. This always results in more container being needed all the time.
I think that a list of max global resources would be better than manual "Ignore Resource" drag&drop panel. In this scenario given resources would be just be placed in ignored state every time when specific quantity is met
(0.12.9) Bug Feature: Priorities
How to kill all your crew in 3 easy steps:
- Expand your station, make sure everyone is busy with important tasks.
- <meanwhile> Toilet becomes fully filled with... content. </meanwhile>
- Thats it, game over. Everyone dies of diarrhea because f****** nobody wants to clean it up anymore and prefers just to wait in line until their a** explodes :O
(0.12.7) Bug: WorkManager.RevalidateJobs throws 900ms-long tantrums for reasons
Repro steps:
- Create a floor tile completely enclosed with walls somewhere
- Create a build order for container on this tile
- Connect that isolated tile (with build order waiting) to the rest of the base
- Watch as one worker comes to construct it and fails at it doing it forever
- Cancel that build order to fix it
- <CPU fan cooler accelarates to mach 1>
That's great!
PS: Please don't over-rely on events (outside UI ofc). Those are 10x times slower and complicate future debugging considerably. If something can be just a method call - let it be just that, you will thank yourself for that later on (less time spent debugging==more productivity==happier you).
Unit tests are of some value Only when you find yourself actually testing something manually a lot and would love to automate that - in other situations it's mostly another costly vanity coding.
Exception #1: Big enterprise software, where codebase maintenance and stability is more important than change (creative work does that a lot)
Exception #2: Well staffed MATURE game projects going for stable release
I have no idea what service locator pattern is and I'm glad for it! :T
In my personal experience implementing patterns is very luring but only to become a very costly vanity work (and sometimes even deadly one to given project). Because in later stages of development everything becomes so horrendously complicated that everyone is praying for simplicity, productivity stalls.
Keep it simple - this is most undervalued yet most productive pattern out there (!).
Easy (but lazy) solution to most of those allocations would be to use LazyCacheStrings and change your code into something like this:
public static LazyCacheStrings<ItemType> ItemTypeStrings = new LazyCacheStrings<ItemType>( (t)=>t.ToString() ); static LazyCacheStrings<System.ValueTuple<float,float>> TitleStrings = new LazyCacheStrings<System.ValueTuple<float,float>>( (kv)=>string.Format("Items {0:0} / {1:0}",kv.Item1,kv.Item2) ); static LazyCacheStrings<System.ValueTuple<ItemType,float>> SectionStrings = new LazyCacheStrings<System.ValueTuple<ItemType,float>>( (kv)=>string.Format("{0} {1:##}",ItemTypeStrings[kv.Item1],kv.Item2) ); void Update () { ItemContainer container = SingletonMB<StationContent>.Instance.GetContainer(); title.text = TitleStrings[ ( container.CapacityUsed , container.Capacity ) ]; sectionLines.RemoveAllLines(); int numContainerItems = container.Items.Count; for( int i=0 ; i<numContainerItems ; i++ ) { ItemStack itemStack = container.Items[i]; sectionLines.Set( ItemTypeStrings[ itemStack.Type ] , SectionStrings[ ( itemStack.Type , itemStack.Amount ) ] ); } }
This should limit worst of this runaway allocations just some seconds after game start (once caches fill up). It's not the best solution but certainly the simplest one to implement.
To give you an example of how to get rid of string allocations think about creating lookup tables for your values (enum is easy and natural candidate for that). This is how you create an lookup table for enums:
public static readonly Dictionary<ItemType,string> ItemTypeStrings = new Dictionary<ItemType,string>{ { ItemType.Metal, "Metal" } , { ItemType.Food, "Food" } , { ItemType.Water, "Water" } , { ItemType.Mineral, "Mineral" } , { ItemType.Dirt, "Dirt" } , { ItemType.WasteWater, "Waste Water" } , { ItemType.LOX, "LOX" } , { ItemType.LH2, "LH2" } , { ItemType.AsteroidaldWater, "Asteroidald Water" } , { ItemType.MetalOre, "Metal Ore" } , { ItemType.Component , "Component" } , { ItemType.None , "None" } , };
And that will give you an ability to replace every:
string myTypeString = itemStack.Type.ToString();//allocation
with:
string myTypeString = ItemTypeStrings[ itemStack.Type ];
which will allocate no memory at all (==what we want)
After cleaning code up just a bit it can be like this (cleaner to read/understand imho):
void Update () { ItemContainer container = SingletonMB<StationContent>.Instance.GetContainer(); title.text = string.Format( "Items {0:0} / {1:0}" , container.CapacityUsed , container.Capacity ); sectionLines.RemoveAllLines(); int numContainerItems = container.Items.Count; for( int i=0 ; i<numContainerItems ; i++ ) { ItemStack itemStack = container.Items[i]; string identifier = itemStack.Type.ToString(); string text = string.Format( "{0} {1:##}" , identifier , itemStack.Amount ); sectionLines.Set( identifier , text ); } }
Note that 'string.Format()' is slightly better than '"strA"+"strB"'
Also System.Text.StringBuilder would be better (string.Format uses it internally).
Few words of friendly comments:
void Update () { // *** - ToString allocates at least 2 bytes for every character // **** - adding strings together with '+' operator is more or less equivalet to *** ItemContainer container = SingletonMB<StationContent>.Instance.GetContainer(); TextMeshProUGUI title = this.title;// this does nothing - remove line float num = container.CapacityUsed; string str1 = num.ToString("0");// *** num = container.Capacity;// reusing local variables is not needed for anything string str2 = num.ToString("0");// *** string str3 = "Items " + str1 + " / " + str2;// **** title.text = str3; this.sectionLines.RemoveAllLines(); foreach( ItemStack itemStack in container.Items )// unfortunately, starting 'foreach' allocates memory - in Update methods try to use simpler old 'for' iterator instead of 'foreach' { PanelSectionLines sectionLines = this.sectionLines;// this does nothing - remove line ItemType type = itemStack.Type; string _identifier = type.ToString();// *** type = itemStack.Type;// this does nothing - remove line string _text = type.ToString() + " " + itemStack.Amount.ToString("##");// **** sectionLines.Set(_identifier, _text); } }
Downsides of ToString() calls are not that simple to get rid of in context of UI. But it's better that you're aware of it and step-by-step will be trying to avoid them in the future (strings in general).
(0.12.6) Bug: GeneralItemPanel.Update method is allocating >10MB of garbage memory PER SECOND.
This leads to GC.Collect() calls causing this pattern of CPU spikes:
This 180KB seems like nothing... until you actually multiply it by your framerate.
One probably won't even notice this bump on high-end machine but it can seriously throttle any weaker laptop or older pc. And for no valid reason really.
PS: I have no idea from where this Instantiate call is coming from but it looks like that is the biggest offender here allocation-wise (consider object pooling).
(itch.io/app) Bug: Launching game via app launches an installer instead of actual game executable.
Friendly tip: try not to rely on singletons. Those seems fancy at first but are more trouble than they're worth in the end. Just pre-instancing them manually in the editor and accessing them through fields isn't that hard and will make your program more resilient. Meaning just:
[SerializeField] BuildManager _buildManager;
then:
_buildManager.ExitBuildMode();
instead of:
SingletonMB<BuildManager>.Instance.ExitBuildMode();
(0.12.6) Another NullReferenceException in main menu
(that burst of asteroids I guess)
NullReferenceException: Object reference not set to an instance of an object
at Game.Objects.Asteroid.AsteroidFactory.Awake () [0x00008] in C:\Users\Taz\Space Architect\Assets\Scripts\Objects\Asteroid\AsteroidFactory.cs:13
UnityEngine.GameObject:Internal_AddComponentWithType(Type)
UnityEngine.GameObject:AddComponent(Type) (at C:\buildslave\unity\build\Runtime\Export\Scripting\GameObject.bindings.cs:222)
UnityEngine.GameObject:AddComponent() (at C:\buildslave\unity\build\Runtime\Export\Scripting\GameObject.bindings.cs:227)
SingletonMB`1:get_Instance() (at C:\Users\Taz\Space Architect\Assets\Scripts\Utils\SingletonMB.cs:34)
AsteroidManager:GenerateBurstLine(Int32) (at C:\Users\Taz\Space Architect\Assets\Scripts\Managers\AsteroidManager.cs:77)
Game.InputManager:Update() (at C:\Users\Taz\Space Architect\Assets\Scripts\Managers\InputManager.cs:40)
(Filename: C:/Users/Taz/Space Architect/Assets/Scripts/Objects/Asteroid/AsteroidFactory.cs Line: 13)
Where do I send bug reports?
0.12.5 callstack:
(Filename: C:/Users/Taz/Space Architect/Assets/Scripts/UI/Panels/VisitorPanel.cs Line: 60)
NotImplementedException: The method or operation is not implemented.
at Game.UI.Panel.VisitorPanel.HandleLeft (Game.Visitors.Visitor _visitor, System.EventArgs e) [0x00001] in C:\Users\Taz\Space Architect\Assets\Scripts\UI\Panels\VisitorPanel.cs:60
at (wrapper delegate-invoke) <Module>.invoke_void_Visitor_EventArgs(Game.Visitors.Visitor,System.EventArgs)
at Game.Visitors.Visitor.CallLeft () [0x00001] in C:\Users\Taz\Space Architect\Assets\Scripts\Visitors\Visitor.cs:136
at Game.Visitors.Visitor.Remove () [0x00001] in C:\Users\Taz\Space Architect\Assets\Scripts\Visitors\Visitor.cs:115
at Game.Visitors.Visitor.Update () [0x00114] in C:\Users\Taz\Space Architect\Assets\Scripts\Visitors\Visitor.cs:81
Thank you for your feedback! Much appreciated and I'm looking forward to hearing more from you.
So I just added an arrow in radar view to help player find what he needs.
I will try to repair policeman ai too so he would behave accordingly again (this feature broke just about hour before #cyberpunkjam's deadline ;_;).