<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://softwareinc.coredumping.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Khornel</id>
	<title>Software Inc. - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://softwareinc.coredumping.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Khornel"/>
	<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php/Special:Contributions/Khornel"/>
	<updated>2026-07-29T14:37:00Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.35.0</generator>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1375</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1375"/>
		<updated>2026-04-14T17:19:50Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Button in the main HUD */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). You can use one of the built-in icons by calling '''ObjectDatabase.Instance.GetIcon'''(name) and use the console command '''SHOW_ICONS''' to see all the built-in icons, or if you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, ModBehaviour callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;Window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/Label&amp;gt;&lt;br /&gt;
				&amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/Button&amp;gt;&lt;br /&gt;
				&amp;lt;Combo OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/Combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/ScrollView&amp;gt;&lt;br /&gt;
&amp;lt;/Window&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; and OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; part. Note that using &amp;quot;this&amp;quot; will refer to the actual component the tag represents. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
public void ShowMessageCombo(GUICombobox x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x.SelectedItemString, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding tags to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements, children tags are added directly to the element.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Modding&amp;diff=1374</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Modding&amp;diff=1374"/>
		<updated>2026-04-06T16:01:06Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Localizations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mods in Software Inc. can be defined in simple text-based files or using C# and compiling code for the game to load. You can add new software types, furniture, translations and room textures using only the [[TyD|TyD]] file format. &lt;br /&gt;
&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
You'll need the in-game console to properly test your mods and check if everything is working as it should. The debugging console is enabled by binding the console key at the bottom of the key binding menu in the options window. More information about how to use console can be found on [[Console]].&lt;br /&gt;
&lt;br /&gt;
== Folder structure ==&lt;br /&gt;
Unless downloaded from the Steam Workshop, mods are placed in the root of the game folder, depending on which type of mod you are making. Each mod should be placed in its own folder within the following folders (Note that these folders might not exist in the first place, so you should create them yourself):&lt;br /&gt;
* Software types and personalities should be placed in the '''Mods''' folder.&lt;br /&gt;
* Furniture should be placed in the '''Furniture''' folder.&lt;br /&gt;
* Room, path and roof textures should be placed in the '''Materials''' folder.&lt;br /&gt;
* C# code and dll files should be placed in the '''DLLMods''' folder.&lt;br /&gt;
* Translations should be placed in the '''Localization''' folder.&lt;br /&gt;
&lt;br /&gt;
== Meta file ==&lt;br /&gt;
Each mod will take its name from the folder it is in. However, you can customize the '''Name''', '''Description''' and '''Author''' of your mod by adding a meta.tyd file to the root of your mod's folder, containing the specified records. This file will be created automatically when you edit your mod in-game (Not implemented yet as of Alpha 11.4.7).&lt;br /&gt;
&lt;br /&gt;
== Localizations ==&lt;br /&gt;
Please go to [https://translate.coredumping.com translate.coredumping.com] to help translate the game.&lt;br /&gt;
&lt;br /&gt;
== Mod types ==&lt;br /&gt;
=== Data mod ===&lt;br /&gt;
[[Data Modding|Read the documentation here.]]&lt;br /&gt;
&lt;br /&gt;
Data mods can add, change or remove software types, AI company types, name generators and employee personalities. This is all done with [[TyD|TyD]] files, however software can have scripts attached using [[SIPL|SIPL]].&lt;br /&gt;
&lt;br /&gt;
=== Furniture ===&lt;br /&gt;
[[Furniture Modding|Read the documentation here.]]&lt;br /&gt;
&lt;br /&gt;
You can add furniture using .obj 3D object files. The furniture modding system, while only using [[TyD|TyD]] files, allows you to change pretty much anything about your furniture that would be possible to change from within the game's engine.&lt;br /&gt;
&lt;br /&gt;
=== Materials ===&lt;br /&gt;
[[Material Modding|Read the documentation here.]]&lt;br /&gt;
&lt;br /&gt;
Material mods allow you to load textures into the game for interior walls, exterior walls, floors, roofs and paths.&lt;br /&gt;
&lt;br /&gt;
=== Code mod ===&lt;br /&gt;
[[Code Modding|Read the documentation here.]]&lt;br /&gt;
&lt;br /&gt;
If you want to dive even further, you can put .cs files directly with the game, and it will compile and load your scripts on startup. For more control, you can compile your own DLL files for the game to load.&lt;br /&gt;
&lt;br /&gt;
=== Localizations ===&lt;br /&gt;
To create a localization you can copy the English folder from the Localization folder and fill in your own text in the appropriate fields. Localization files are written entirely in [[TyD|TyD]], to be easily human-readable.&lt;br /&gt;
&lt;br /&gt;
Localizations can also contain '''femalefirstnames.txt''', '''malefirstnames.txt''' and '''lastnames.txt''' files to overwrite the default employee names in the game. These should contain a list of names separated by new lines, ordered by how common the name is.&lt;br /&gt;
&lt;br /&gt;
====Helpful console commands====&lt;br /&gt;
* '''COMPARE_LOCALIZATION''' X Y - Compares what has changed between between localization X and Y, Y should almost always be &amp;quot;English&amp;quot;&lt;br /&gt;
* '''CONVERT_LOCALIZATION_TYD''' X - Converts localization named X from XML to TyD&lt;br /&gt;
* '''RELOAD_LOCALIZATION''' - Reloads all localizations, but does not update UI instantly when in-game&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Modding&amp;diff=1373</id>
		<title>Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Modding&amp;diff=1373"/>
		<updated>2026-04-06T16:00:47Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Localizations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mods in Software Inc. can be defined in simple text-based files or using C# and compiling code for the game to load. You can add new software types, furniture, translations and room textures using only the [[TyD|TyD]] file format. &lt;br /&gt;
&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
You'll need the in-game console to properly test your mods and check if everything is working as it should. The debugging console is enabled by binding the console key at the bottom of the key binding menu in the options window. More information about how to use console can be found on [[Console]].&lt;br /&gt;
&lt;br /&gt;
== Folder structure ==&lt;br /&gt;
Unless downloaded from the Steam Workshop, mods are placed in the root of the game folder, depending on which type of mod you are making. Each mod should be placed in its own folder within the following folders (Note that these folders might not exist in the first place, so you should create them yourself):&lt;br /&gt;
* Software types and personalities should be placed in the '''Mods''' folder.&lt;br /&gt;
* Furniture should be placed in the '''Furniture''' folder.&lt;br /&gt;
* Room, path and roof textures should be placed in the '''Materials''' folder.&lt;br /&gt;
* C# code and dll files should be placed in the '''DLLMods''' folder.&lt;br /&gt;
* Translations should be placed in the '''Localization''' folder.&lt;br /&gt;
&lt;br /&gt;
== Meta file ==&lt;br /&gt;
Each mod will take its name from the folder it is in. However, you can customize the '''Name''', '''Description''' and '''Author''' of your mod by adding a meta.tyd file to the root of your mod's folder, containing the specified records. This file will be created automatically when you edit your mod in-game (Not implemented yet as of Alpha 11.4.7).&lt;br /&gt;
&lt;br /&gt;
== Localizations ==&lt;br /&gt;
Please go to [https://translate.coredumping.com] to help translate the game.&lt;br /&gt;
&lt;br /&gt;
== Mod types ==&lt;br /&gt;
=== Data mod ===&lt;br /&gt;
[[Data Modding|Read the documentation here.]]&lt;br /&gt;
&lt;br /&gt;
Data mods can add, change or remove software types, AI company types, name generators and employee personalities. This is all done with [[TyD|TyD]] files, however software can have scripts attached using [[SIPL|SIPL]].&lt;br /&gt;
&lt;br /&gt;
=== Furniture ===&lt;br /&gt;
[[Furniture Modding|Read the documentation here.]]&lt;br /&gt;
&lt;br /&gt;
You can add furniture using .obj 3D object files. The furniture modding system, while only using [[TyD|TyD]] files, allows you to change pretty much anything about your furniture that would be possible to change from within the game's engine.&lt;br /&gt;
&lt;br /&gt;
=== Materials ===&lt;br /&gt;
[[Material Modding|Read the documentation here.]]&lt;br /&gt;
&lt;br /&gt;
Material mods allow you to load textures into the game for interior walls, exterior walls, floors, roofs and paths.&lt;br /&gt;
&lt;br /&gt;
=== Code mod ===&lt;br /&gt;
[[Code Modding|Read the documentation here.]]&lt;br /&gt;
&lt;br /&gt;
If you want to dive even further, you can put .cs files directly with the game, and it will compile and load your scripts on startup. For more control, you can compile your own DLL files for the game to load.&lt;br /&gt;
&lt;br /&gt;
=== Localizations ===&lt;br /&gt;
To create a localization you can copy the English folder from the Localization folder and fill in your own text in the appropriate fields. Localization files are written entirely in [[TyD|TyD]], to be easily human-readable.&lt;br /&gt;
&lt;br /&gt;
Localizations can also contain '''femalefirstnames.txt''', '''malefirstnames.txt''' and '''lastnames.txt''' files to overwrite the default employee names in the game. These should contain a list of names separated by new lines, ordered by how common the name is.&lt;br /&gt;
&lt;br /&gt;
====Helpful console commands====&lt;br /&gt;
* '''COMPARE_LOCALIZATION''' X Y - Compares what has changed between between localization X and Y, Y should almost always be &amp;quot;English&amp;quot;&lt;br /&gt;
* '''CONVERT_LOCALIZATION_TYD''' X - Converts localization named X from XML to TyD&lt;br /&gt;
* '''RELOAD_LOCALIZATION''' - Reloads all localizations, but does not update UI instantly when in-game&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1372</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1372"/>
		<updated>2026-03-27T07:47:06Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, ModBehaviour callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;Window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/Label&amp;gt;&lt;br /&gt;
				&amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/Button&amp;gt;&lt;br /&gt;
				&amp;lt;Combo OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/Combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/ScrollView&amp;gt;&lt;br /&gt;
&amp;lt;/Window&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; and OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; part. Note that using &amp;quot;this&amp;quot; will refer to the actual component the tag represents. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
public void ShowMessageCombo(GUICombobox x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x.SelectedItemString, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding tags to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements, children tags are added directly to the element.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1371</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1371"/>
		<updated>2026-03-27T07:46:12Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, ModBehaviour callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;scrollview anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/label&amp;gt;&lt;br /&gt;
				&amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/button&amp;gt;&lt;br /&gt;
				&amp;lt;combo OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/scrollview&amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; and OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; part. Note that using &amp;quot;this&amp;quot; will refer to the actual component the tag represents. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
public void ShowMessageCombo(GUICombobox x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x.SelectedItemString, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding tags to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements, children tags are added directly to the element.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1370</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1370"/>
		<updated>2026-03-26T13:23:59Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;scrollview anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/label&amp;gt;&lt;br /&gt;
				&amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/button&amp;gt;&lt;br /&gt;
				&amp;lt;combo OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/scrollview&amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; and OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; part. Note that using &amp;quot;this&amp;quot; will refer to the actual component the tag represents. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
public void ShowMessageCombo(GUICombobox x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x.SelectedItemString, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding tags to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements, children tags are added directly to the element.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1369</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1369"/>
		<updated>2026-03-26T13:23:50Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;scrollview anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/label&amp;gt;&lt;br /&gt;
				&amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/button&amp;gt;&lt;br /&gt;
				&amp;lt;combo OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/scrollview&amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; and OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; part. Note that using &amp;quot;this&amp;quot; will refer to the actual component the tag represents. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
public void ShowMessageCombo(GUICombobox x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x.SelectedItemString, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding tags to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements, children tags are added directly to the element.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1368</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1368"/>
		<updated>2026-03-26T13:22:36Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;scrollview anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/label&amp;gt;&lt;br /&gt;
				&amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/button&amp;gt;&lt;br /&gt;
				&amp;lt;combo OnSelectedChanged=&amp;quot;ShowMessageCombo(this)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/scrollview&amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding tags to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements, children tags are added directly to the element.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1367</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1367"/>
		<updated>2026-03-26T07:56:00Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;Window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding tags to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements, children tags are added directly to the element.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1366</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1366"/>
		<updated>2026-03-26T07:55:32Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;Window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding elements or layouts to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements, children tags are added directly to the element.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1365</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1365"/>
		<updated>2026-03-26T07:55:05Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;Window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
Note that when adding elements or layouts to a window or scrollview, you are not adding it directly to the window or scrollview, but their content panels. For the rest of the elements children elements are added directly to the object.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1364</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1364"/>
		<updated>2026-03-25T21:25:17Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Networking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;Window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call '''MemoryStream.SetLength'''(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call '''MemoryStream.ToArray'''() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1363</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1363"/>
		<updated>2026-03-25T21:24:16Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Networking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;Window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone except player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1362</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1362"/>
		<updated>2026-03-25T21:22:23Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;Window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1361</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1361"/>
		<updated>2026-03-25T21:20:54Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input (input field for text)&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1360</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1360"/>
		<updated>2026-03-25T21:20:27Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality in your mod to reload UI from an XML while the mod is still running for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1359</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1359"/>
		<updated>2026-03-25T21:18:06Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the '''button''', '''input''' and '''combo''' have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1358</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1358"/>
		<updated>2026-03-25T21:17:41Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the button, input and combo have event variables, i.e. '''onClick''', '''onValueChanged''' and '''OnSelectedChanged''' (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1357</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1357"/>
		<updated>2026-03-25T21:15:24Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/Label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/Button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;Combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/Combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1356</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1356"/>
		<updated>2026-03-25T21:14:33Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test Window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/Window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1355</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1355"/>
		<updated>2026-03-25T21:12:44Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* HTML-like UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Remember case sensitivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1354</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1354"/>
		<updated>2026-03-25T21:11:54Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
=== Button in the main HUD ===&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
=== HTML-like UI ===&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1353</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1353"/>
		<updated>2026-03-25T21:09:39Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.VerticalLayoutGroup.html)&lt;br /&gt;
* gridlayout (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.GridLayoutGroup.html)&lt;br /&gt;
* contentfitter (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.ContentSizeFitter.html)&lt;br /&gt;
* layoutelement (see https://docs.unity3d.com/2018.2/Documentation/ScriptReference/UI.LayoutElement.html)&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1352</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1352"/>
		<updated>2026-03-25T21:06:05Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout (see https://docs.unity3d.com/Packages/com.unity.ugui@1.0/manual/script-HorizontalLayoutGroup.html)&lt;br /&gt;
* verticallayout (uses padding and spacing, childForceExpandHeight, childForceExpandWidth, childControlHeight, childControlWidth)&lt;br /&gt;
* gridlayout (uses padding and spacing, cellSize, constraint)&lt;br /&gt;
* contentfitter&lt;br /&gt;
* layoutelement&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1351</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1351"/>
		<updated>2026-03-25T21:01:57Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this);&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout&lt;br /&gt;
* verticallayout&lt;br /&gt;
* gridlayout&lt;br /&gt;
* contentfitter&lt;br /&gt;
* layoutelement&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1350</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1350"/>
		<updated>2026-03-25T21:01:32Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. You can use '''WindowManager.Spawn*''' to spawn UI elements to put your UI into. I'm using '''this''' for the '''callback''' parameter, so when you click the button, the method '''ShowMessage''' from the current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout&lt;br /&gt;
* verticallayout&lt;br /&gt;
* gridlayout&lt;br /&gt;
* contentfitter&lt;br /&gt;
* layoutelement&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1349</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1349"/>
		<updated>2026-03-25T21:00:35Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
These are the current layout tags that will allow you to add a component to the UI element it is defined under. Any position and anchor changes will be applied to the parent:&lt;br /&gt;
* horizontallayout&lt;br /&gt;
* verticallayout&lt;br /&gt;
* gridlayout&lt;br /&gt;
* contentfitter&lt;br /&gt;
* layoutelement&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1348</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1348"/>
		<updated>2026-03-25T20:59:16Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
These are the current object tags that will allow you to create a new UI element:&lt;br /&gt;
* empty&lt;br /&gt;
* panel&lt;br /&gt;
* button&lt;br /&gt;
* label&lt;br /&gt;
* list&lt;br /&gt;
* input&lt;br /&gt;
* checkbox&lt;br /&gt;
* progressbar&lt;br /&gt;
* slider&lt;br /&gt;
* combo&lt;br /&gt;
* scrollbar&lt;br /&gt;
* scrollview&lt;br /&gt;
* window&lt;br /&gt;
* image&lt;br /&gt;
* rawimage&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1347</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1347"/>
		<updated>2026-03-25T20:55:59Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Compatibility */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    //(this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    //(Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    //(Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    //(This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1346</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1346"/>
		<updated>2026-03-25T20:55:42Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Project setup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    (this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    (This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1345</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1345"/>
		<updated>2026-03-25T20:55:32Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Dependencies */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
    {&lt;br /&gt;
    AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
    base.Initialize(parentMod);&lt;br /&gt;
    }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    (this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    (This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1344</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1344"/>
		<updated>2026-03-25T20:55:09Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Compatibility */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
&amp;lt;pre class='language-cs'&amp;gt;#if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
    (this is beta pre 1.7)&lt;br /&gt;
#elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
    (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
#elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
    (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
#else&lt;br /&gt;
    (This is for all future versions beta 1.11+)&lt;br /&gt;
#endif&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1343</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1343"/>
		<updated>2026-03-25T20:54:25Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-cs&amp;quot;&amp;gt;var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
Debug.log(label.text);&lt;br /&gt;
public void ShowMessage(string x)&lt;br /&gt;
	{&lt;br /&gt;
	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
	}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=MediaWiki:Common.js&amp;diff=1342</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=MediaWiki:Common.js&amp;diff=1342"/>
		<updated>2026-03-25T20:53:48Z</updated>

		<summary type="html">&lt;p&gt;Khornel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&lt;br /&gt;
  &amp;quot;https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js&amp;quot;&lt;br /&gt;
);&lt;br /&gt;
mw.loader.load(&lt;br /&gt;
  &amp;quot;https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css&amp;quot;,&lt;br /&gt;
  &amp;quot;text/css&amp;quot;&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
mw.loader.using([], function () {&lt;br /&gt;
  // Wait until highlight.js is actually available&lt;br /&gt;
  function initHighlight() {&lt;br /&gt;
    if (typeof hljs !== &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
      hljs.configure({&lt;br /&gt;
        cssSelector: 'pre[class*=&amp;quot;language-&amp;quot;]'&lt;br /&gt;
      });&lt;br /&gt;
      hljs.highlightAll();&lt;br /&gt;
    } else {&lt;br /&gt;
      // try again shortly&lt;br /&gt;
      setTimeout(initHighlight, 50);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  initHighlight();&lt;br /&gt;
});&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=MediaWiki:Common.js&amp;diff=1341</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=MediaWiki:Common.js&amp;diff=1341"/>
		<updated>2026-03-25T20:52:57Z</updated>

		<summary type="html">&lt;p&gt;Khornel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js&amp;quot;);&lt;br /&gt;
mw.loader.load(&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css&amp;quot;, &amp;quot;text/css&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$(function () {&lt;br /&gt;
  hljs.configure({&lt;br /&gt;
    cssSelector: 'pre[class*=&amp;quot;language-&amp;quot;]'&lt;br /&gt;
  });&lt;br /&gt;
  hljs.highlightAll();&lt;br /&gt;
});&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1340</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1340"/>
		<updated>2026-03-25T20:52:45Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1339</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1339"/>
		<updated>2026-03-25T20:52:33Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1338</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1338"/>
		<updated>2026-03-25T20:52:19Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1337</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1337"/>
		<updated>2026-03-25T20:52:03Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1336</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1336"/>
		<updated>2026-03-25T20:51:39Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;amp;gt;&amp;amp;lt;pre&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/pre&amp;amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1335</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1335"/>
		<updated>2026-03-25T20:50:28Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;amp;gt;&amp;amp;lt;pre&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/pre&amp;amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1334</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1334"/>
		<updated>2026-03-25T20:48:59Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;html&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;amp;gt;&amp;amp;lt;pre&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/pre&amp;amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/html&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1333</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1333"/>
		<updated>2026-03-25T20:48:38Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&amp;amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;amp;gt;&amp;amp;lt;pre&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/pre&amp;amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1332</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1332"/>
		<updated>2026-03-25T20:48:26Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;amp;gt;&amp;amp;lt;pre&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/pre&amp;amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1331</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1331"/>
		<updated>2026-03-25T20:48:15Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;amp;gt;&amp;amp;lt;pre&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Hello&amp;amp;lt;/label&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;amp;gt;Click me&amp;amp;lt;/button&amp;amp;gt;&lt;br /&gt;
				&amp;amp;lt;combo height=&amp;quot;24&amp;quot;&amp;amp;gt;a,b,c&amp;amp;lt;/combo&amp;amp;gt;&lt;br /&gt;
			&amp;amp;lt;/ContentFitter&amp;amp;gt;&lt;br /&gt;
		&amp;amp;lt;/VerticalLayout&amp;amp;gt;&lt;br /&gt;
	&amp;amp;lt;/ScrollView&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/window&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/pre&amp;amp;gt;&amp;amp;lt;/code&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1330</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1330"/>
		<updated>2026-03-25T20:47:39Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/label&amp;gt;&lt;br /&gt;
				&amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/button&amp;gt;&lt;br /&gt;
				&amp;lt;combo height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/ScrollView&amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1329</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1329"/>
		<updated>2026-03-25T20:47:21Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;html&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/label&amp;gt;&lt;br /&gt;
				&amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/button&amp;gt;&lt;br /&gt;
				&amp;lt;combo height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/ScrollView&amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/html&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1328</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1328"/>
		<updated>2026-03-25T20:44:40Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/label&amp;gt;&lt;br /&gt;
				&amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/button&amp;gt;&lt;br /&gt;
				&amp;lt;combo height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/ScrollView&amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1327</id>
		<title>Code Modding</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=Code_Modding&amp;diff=1327"/>
		<updated>2026-03-25T20:43:14Z</updated>

		<summary type="html">&lt;p&gt;Khornel: /* Creating UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can compile C# files or load dll libraries directly in Software Inc.&lt;br /&gt;
&lt;br /&gt;
A good grasp of C# programming and the Unity3D API is required to make a code based mod.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
== Project setup ==&lt;br /&gt;
To create your own mod start a .NET Class Library project in Visual Studio, targeted at the .NET 4 profile. You should download and install the '''.NET 4 Framework''' if you don't have it, '''.NET Core is not the same.'''&lt;br /&gt;
&lt;br /&gt;
You should add a reference to the following libraries: Note that you might need to add references to more, depending on what you want to do.&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.UI.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\UnityEngine.CoreModule.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp.dll&lt;br /&gt;
&lt;br /&gt;
* Software Inc_Data\Managed\Assembly-CSharp-firstpass.dll&lt;br /&gt;
&lt;br /&gt;
Start by creating a class that implements the ModMeta abstract class, then implement as many classes that inherit from ModBehaviour as you want.&lt;br /&gt;
&lt;br /&gt;
The ModMeta class will contain information about your mod and act as a manager for your mod.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace myMod &lt;br /&gt;
{&lt;br /&gt;
  internal class MyModMeta : ModMeta&lt;br /&gt;
    {&lt;br /&gt;
        public override void ConstructOptionsScreen(RectTransform parent, bool inGame)&lt;br /&gt;
        {&lt;br /&gt;
            Text text = WindowManager.SpawnLabel();&lt;br /&gt;
            text.text = &amp;quot;This is the description of my mod\nIt shows in dropdown 'My Mod!' in the 'Mods' section of the options area.&amp;quot;;&lt;br /&gt;
            WindowManager.AddElementToElement(text.gameObject, parent.gameObject, new Rect(0f, 0f, 400f, 128f),&lt;br /&gt;
                new Rect(0f, 0f, 0f, 0f));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public override string Name =&amp;gt; &amp;quot;My Mod!&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ModBehaviours are just a subclass of Unity's [https://docs.unity3d.com/2017.4/Documentation/ScriptReference/MonoBehaviour.html MonoBehavior] and work the same way, i.e. they use the same life cycle of Awake, Start, Update, OnDestroy, ModBehaviours only differ in that they have the abstract OnActive and OnDeactivate methods, to signal when the mod is toggled. Each ModBehaviour implementation will be instantiated once the mod is loaded.&lt;br /&gt;
&lt;br /&gt;
== Compile ==&lt;br /&gt;
When you're done, create a subfolder for your mod in a folder called &amp;quot;DLLMods&amp;quot; in the game's root directory and put your compiled .dll file in it, or .cs files if you want the game to compile them for you. Note that if you let the game compile the C# files for you, you are limited to C# version 3, but '''using the game's compiler is required if you want to upload your mod to the Steam Workshop'''.&lt;br /&gt;
&lt;br /&gt;
If you use the game's compiler, note that it will inject error handling code into each function body, you can disable this behaviour while you are developing your mod using the launch paramater '''-DisableModErrors'''.&lt;br /&gt;
&lt;br /&gt;
'''Please note that due to a bug in the compiler the game uses, you cannot use enums if you are using straight .cs files or the game will crash'''&lt;br /&gt;
&lt;br /&gt;
== Example mod ==&lt;br /&gt;
Here's a working mod  example that lets you change how many floors you can build on, complete with comments:&lt;br /&gt;
[https://softwareinc.coredumping.com/FloorMod.zip Floor Mod] (Updated to work with Alpha 10.7+)&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
If you want to reference external dll files, you can put them in the '''Software Inc_Data\Managed''' folder.&lt;br /&gt;
&lt;br /&gt;
You can also add this code snippet to your ModMeta class, to load dll files from a subfolder: (Note that this requires GiveMeFreedom and it might not find the correct dll filename, so you might need to adjust it to your situation)&lt;br /&gt;
 public override void Initialize(ModController.DLLMod parentMod)&lt;br /&gt;
     {&lt;br /&gt;
     AppDomain.CurrentDomain.AssemblyResolve += (x, y) =&amp;gt; Assembly.LoadFrom(Path.Combine(parentMod.FolderPath(), &amp;quot;'''SubFolder'''/&amp;quot; + y.Name.Substring(0, y.Name.IndexOf(&amp;quot;,&amp;quot;)) + &amp;quot;.dll&amp;quot;));&lt;br /&gt;
     base.Initialize(parentMod);&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
From Beta 1.7+ you can use define symbols for non-dll-based mods that are compiled by the game, e.g.&lt;br /&gt;
 #if !SWINCBETA &amp;amp;&amp;amp; !SWINCRELEASE&lt;br /&gt;
     (this is beta pre 1.7)&lt;br /&gt;
 #elif SWINCBETA1_7 || SWINCBETA1_8&lt;br /&gt;
     (Something broke in beta 1.9, so this is sectioned off)&lt;br /&gt;
 #elif SWINCBETA1_9 || SWINCBETA1_10&lt;br /&gt;
     (Something broke in beta 1.11, so this is sectioned off)&lt;br /&gt;
 #else&lt;br /&gt;
     (This is for all future versions beta 1.11+)&lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
The game will define 3 symbols SWINC'''TYPE''' (SWINCBETA or SWINCRELEASE), SWINCTYPE'''MAJOR''' (SWINCBETA1, SWINCBETA2, etc.) and SWINCTYPEMAJOR'''_MINOR''' (SWINCBETA1_7, SWINCBETA1_8, etc.)&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
== Debugging console ==&lt;br /&gt;
Before you do anything, you should enable the in-game debugging console by binding the console key at the bottom of the key binding menu in the options window. This will help you debug your mod by giving you error messages and enabling the '''RECOMPILE_DLL_MOD''', '''RELOAD_DLL_MOD''' and '''UNLOAD_DLL_MOD''' commands.&lt;br /&gt;
&lt;br /&gt;
== Helpful commands ==&lt;br /&gt;
The '''EXECUTE''' command will allow you to execute arbitrary [[SIPL]] code (which closely resembles C#) while the game is running. E.g. if you wanted to find the highest paid employee you could write &amp;lt;code&amp;gt;EXECUTE GameSettings.sActorManager.Actors.OrderByDescending(x.employee.Salary).First()&amp;lt;/code&amp;gt; or if you wanted to color all selected rooms' exterior green you could write &amp;lt;code&amp;gt;EXECUTE Selected.Where(x is Room).ForEach(x.OutsideColor = Color(0,1,0))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Here are some handy variables and functions you can use with '''EXECUTE''':&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings&lt;br /&gt;
|References the currently active instance of GameSettings&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController&lt;br /&gt;
|References the currently active instance of SelectorController&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation&lt;br /&gt;
|References the currently active instance of MarketSimulation&lt;br /&gt;
|-&lt;br /&gt;
|Selected&lt;br /&gt;
|List of objects currently selected in-game&lt;br /&gt;
|-&lt;br /&gt;
|LastProduct&lt;br /&gt;
|Reference to last product opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|LastCompany&lt;br /&gt;
|Reference to last company opened in a detail window&lt;br /&gt;
|-&lt;br /&gt;
|WorkItems&lt;br /&gt;
|List of the active player company's tasks (GameSettings.MyCompany)&lt;br /&gt;
|-&lt;br /&gt;
|Now&lt;br /&gt;
|Current in-game date&lt;br /&gt;
|-&lt;br /&gt;
|CopyToClipboard(o)&lt;br /&gt;
|Copies '''o''' to the clipboard, wrap your entire statement in this to put the result in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
|DoSelect(o)&lt;br /&gt;
|Selects '''o''' in-game, can be an object or a list, e.g. DoSelect(GameSettings.sActorManager.Actors)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The '''SHOW_INSPECTOR''' command opens a window that allows you to inspect all objects in the active scene.&lt;br /&gt;
&lt;br /&gt;
== Note on threading ==&lt;br /&gt;
You should stick to the '''ModBehaviour''''s Update method, rather than trying to write your own update loop with threads or timers, as you cannot interact with Unity's system from other threads and you will most likely end up causing race conditions when interacting with the game's systems. You can use Unity's '''Time''' class to keep track of elapsed time between frames.&lt;br /&gt;
&lt;br /&gt;
== Saving and loading data ==&lt;br /&gt;
=== Global data ===&lt;br /&gt;
All '''ModBehaviours''' have '''SaveSetting''' and '''LoadSetting''' methods to save data globally.&lt;br /&gt;
&lt;br /&gt;
Note that '''SaveSetting''' and '''LoadSetting''' are generic and will call '''ToString()''' and try to convert the saved string back to the data type you specify when loading, so this will only work for simple types, like integers, floats, doubles, bools, strings, etc.&lt;br /&gt;
&lt;br /&gt;
To load something back, use &amp;lt;code&amp;gt;LoadSetting&amp;lt;type&amp;gt;(&amp;quot;Key&amp;quot;, defaultvalue)&amp;lt;/code&amp;gt;, e.g. &amp;lt;code&amp;gt;LoadSetting&amp;lt;bool&amp;gt;(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LoadSetting(&amp;quot;Notifications&amp;quot;, false)&amp;lt;/code&amp;gt;, since the type '''bool''' is implicit from using '''false'''.&lt;br /&gt;
&lt;br /&gt;
There's also '''TryLoadSetting''', if you want to handle when the setting doesn't exist and '''DeleteSetting''' to remove existing settings.&lt;br /&gt;
&lt;br /&gt;
=== Per save data ===&lt;br /&gt;
You can also save data to the player's save file, to keep settings per save, by overriding your '''ModBehaviours'''' '''Serialize''' and '''Deserialize''' methods. These use a '''WriteDictionary''', which is just a dictionary of whatever you want, and the game will handle turning it into bits.&lt;br /&gt;
&lt;br /&gt;
The WriteDictionary is powerful, in that it has no limitations on the data you can save, but '''please note that any custom classes saved using this method ''has'' to have an empty constructor'''. If you want some fields not to be serialized, use the '''[System.NonSerialized]''' attribute. Properties are not serialized, so you need to create backing fields. Saving custom classes from your mod will also break saves if the mod is no longer installed, so it's best to avoid when you can.&lt;br /&gt;
&lt;br /&gt;
When you want to save data, override and populate the WriteDictionary with values in the '''Serialize(WriteDictionary data, GameReader.LoadMode mode)''' method, this will then be returned when a save is loaded in the '''Deserialize(WriteDictionary data, GameReader.LoadMode mode)''' method. If you wanted to save a setting you can write &amp;lt;code&amp;gt;data[&amp;quot;Notifications&amp;quot;] = true&amp;lt;/code&amp;gt; and load it back with &amp;lt;code&amp;gt;Notifications = data.Get(&amp;quot;Notifications&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is also a '''LoadMode''' parameter, which tells you whether it was a full save, a build mode save or a company save (Usually used when the player is moving to another map or during multiplayer synchronization), which will allow you to only save data needed for each type. In most cases it's best to avoid saving anything for a build mode save.&lt;br /&gt;
&lt;br /&gt;
You can also override the serialization methods in the ModMeta class to take complete control of saving data. Returning null will make the mod not save any data. To help you with serializing data from your ModBehaviours, the ModMeta class has a '''ModBehaviours''' list of all active ModBehaviours that were created when the mod was first loaded. However, the default behaviour is to call Serialize and Deserialize on your ModBehaviours in turn and check if they saved any data, so just leaving it as is will work in most cases.&lt;br /&gt;
&lt;br /&gt;
Note that your the save data is identified by the '''Name''' you've set in the '''ModMeta''' class. If you change this name, it will no longer be able to find the correct data from older saves and name clashes will result in data loss.&lt;br /&gt;
&lt;br /&gt;
== Reading external files ==&lt;br /&gt;
All modbehaviours have access to their '''ParentMod''', this is the class that manages your mod, and through this you can load files using the methods '''LoadTexture'''(png, jpg, jpeg), '''LoadXMLFile'''(xml, only first tag), '''LoadFullXMLFile'''(xml, all tags in a list), '''LoadTydFile'''(tyd), '''LoadAudio'''(mp3, wav, ogg), '''LoadGLTF'''(gltf, glb, only loads the first mesh and its morph targets) and '''LoadOBJ'''(obj). Note that these methods all use relative paths from where your mod is installed and using '''../''' won't work.&lt;br /&gt;
&lt;br /&gt;
== Creating UI ==&lt;br /&gt;
You can add buttons to the bottom main HUD by calling '''HUD.Instance.AddBottomButton'''(string panel, string name, string desc, Sprite icon). If you want your own Icon you need to instantiate a Sprite with a texture that you load using '''ParentMod.LoadTexture''' or in the '''ModMeta''''s '''Initialize'''(ModController.DLLMod parentMod) method. The game uses 32x32 icons that are completely white with a transparent background, if you want to stay consistent.&lt;br /&gt;
&lt;br /&gt;
You can load in UIs using xml files with an html like structure using '''WindowManager.GenerateUI'''(List&amp;lt;XMLParser.XMLNode&amp;gt; nodes, GameObject parent, object callback). Example: &lt;br /&gt;
&amp;lt;code class=&amp;quot;language-html&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;window MinSize=&amp;quot;0,0&amp;quot; NonLocTitle=&amp;quot;Test window&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;ScrollView anchor=&amp;quot;fill&amp;quot; position=&amp;quot;4,4&amp;quot; size=&amp;quot;-8,-8&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;VerticalLayout anchor=&amp;quot;top&amp;quot; padding=&amp;quot;4,4,4,4&amp;quot; spacing=&amp;quot;2&amp;quot; childForceExpandHeight=&amp;quot;False&amp;quot; childControlHeight=&amp;quot;False&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;ContentFitter verticalFit=&amp;quot;PreferredSize&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;label id=&amp;quot;lab&amp;quot; color=&amp;quot;FF0000&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Hello&amp;lt;/label&amp;gt;&lt;br /&gt;
				&amp;lt;button onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; height=&amp;quot;24&amp;quot;&amp;gt;Click me&amp;lt;/button&amp;gt;&lt;br /&gt;
				&amp;lt;combo height=&amp;quot;24&amp;quot;&amp;gt;a,b,c&amp;lt;/combo&amp;gt;&lt;br /&gt;
			&amp;lt;/ContentFitter&amp;gt;&lt;br /&gt;
		&amp;lt;/VerticalLayout&amp;gt;&lt;br /&gt;
	&amp;lt;/ScrollView&amp;gt;&lt;br /&gt;
&amp;lt;/window&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
This will create a window with a scroll view containing a label, a button and a combobox automatically laid out vertically. Please note that attributes, e.g. '''position'''=&amp;quot;4,4&amp;quot; are case sensitive!&lt;br /&gt;
&lt;br /&gt;
To position an element you can use the '''anchor''' attribute to decide where the element should be anchored to in the element it is sitting in. The anchor is basically a box that contains the element formatted as x,y,width,height, where all values should be between 0-1, representing 0-100% in the parent element. An anchor of (0,0,0,0) is just the top left corner of the element and (0,0,1,1) is an anchor that fills the entire element, since width and height is 1=100%. '''position''' is the x, y pixel offset from the top left of the anchor. '''size''' or '''width''' and '''height''' is the pixel offset from the bottom right corner of the anchor. '''anchor''' can be formatted as either &amp;quot;'''#,#,#,#'''&amp;quot;, &amp;quot;'''middle,center'''&amp;quot;, &amp;quot;'''bottom,right'''&amp;quot;, &amp;quot;'''top'''&amp;quot;(to fill the entire top), &amp;quot;'''left'''&amp;quot;(to the fill the left side) or &amp;quot;'''fill'''&amp;quot; to fill the entire element, etc. Note that in the scroll view I'm using '''anchor'''=&amp;quot;fill&amp;quot; '''position'''=&amp;quot;4,4&amp;quot; '''size'''=&amp;quot;-8,-8&amp;quot;, because I want it to fill the parent window with a 4 pixel margin, so I have to decrease the size by 4 x 4 = 8, which is why size is -8,-8.&lt;br /&gt;
&lt;br /&gt;
You can also use the '''id''' attribute to reference the element in your code after the UI has been loaded.&lt;br /&gt;
&lt;br /&gt;
The game will try to find a corrosponding variable to set for the element for any other attributes you use (Rememeber case sensivity). Some elements, like the button and combo have event variable, i.e. onClick and OnSelectedChanged (use visual studio's code lookup feature to see what is possible), these can be set to function calls that will be called directly on an object you set when creating the UI, i.e. the  onClick=&amp;quot;ShowMessage(Hehe)&amp;quot; part. Here's an example of how you would create and use this UI:&lt;br /&gt;
 var elements = WindowManager.GenerateUI(ParentMod.LoadFullXMLFile(&amp;quot;UI.xml&amp;quot;), null, this)[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 var label = (Text)elements[&amp;quot;lab&amp;quot;];&lt;br /&gt;
 Debug.log(label.text);&lt;br /&gt;
 public void ShowMessage(string x)&lt;br /&gt;
 	{&lt;br /&gt;
 	WindowManager.Instance.ShowMessageBox(x, true, DialogWindow.DialogType.Information);&lt;br /&gt;
 	}&lt;br /&gt;
&lt;br /&gt;
Note that the '''parent''' parameter of '''GenerateUI''' call is null, because all the UI will be added as a child to the parent object, but since we are spawning a window, this is not necessary to define. and I'm using '''this''' for the callback parameter, so when you click the button, the method '''ShowMessage''' from this current class will be called.&lt;br /&gt;
&lt;br /&gt;
Note that creating UI like this is done on the fly, so you could add functionality to reload the XML when you want for rapid testing.&lt;br /&gt;
&lt;br /&gt;
== Networking ==&lt;br /&gt;
To send data to players in multiplayer you first need to call '''ParentMod.RegisterNetworkID'''(id) in a ModBehaviour. The id should be a value between 1-255, it will be used to identify messages to and from your mod, so you should pick a unique number that is unlikely to clash with other mods. When your mod is deactivated, the id will automatically be de-registered and will have to be re-registered to work. Please note that if players don't enable code mods when they host a game, all code mods will be deactivated immediately.&lt;br /&gt;
&lt;br /&gt;
To send messages you have to call '''ParentMod.SendNetworkMessage'''(byte[] data, ModBehaviour.MessageTarget target, byte targetID) in your ModBehaviour, where target can be '''everyone'''(default), '''everyone but me'''(so avoid sending message to self), '''everyone except'''(everyone player with targetID), '''specifically''' (only player with targetID) and '''host'''. For performance reasons, I recommend instantiating a '''MemoryStream''' when your mod first loads and when you want to send data call MemoryStream.SetLength(0) to reset its data and then use the extension methods that Software Inc. comes with to write arbitrary data to the stream. Finally call MemoryStream.ToArray() to send the data. Please be careful about how much data you send, you should keep the packages as small as possible.&lt;br /&gt;
&lt;br /&gt;
When you want to receive data, override '''ModMeta.ReceiveNetworkMessage'''(SINetworking.NetworkPlayer player, MemoryStream stream), and just use the Stream extension methods to turn the bytes in the MemoryStream back into data you use, in the same order you sent it.&lt;br /&gt;
&lt;br /&gt;
You should start by deciding how you want to layout your data. A good idea is to use the first byte to identify what type of message you are sending. You should also send a ping message to everyone in the start of a game, to check if other players also have the mod installed. You can use '''ParentMod.GetCurrentPlayers()''' to see who is currently connected (this includes the local player).&lt;br /&gt;
&lt;br /&gt;
The extension methods Software Inc. has for Stream objects include the ability to write any type you want, with simple types like ints, bools and strings having the best performance. They will be called ReadX or WriteX. It also has generic methods to write lists and dictionaries. If you implement the interface '''IByteData''' and add a static '''Type ReadData(Stream st)''' method for a class, you can also quickly write that class using the '''Stream.Read/WriteByteObject''' extension methods. You can also use '''Stream.WriteObject''' to write arbitrary data, however this will quickly balloon in size and is very slow, so use it carefully,&lt;br /&gt;
&lt;br /&gt;
== Full access ==&lt;br /&gt;
By default, certain namespaces and types are off-limits to mods for security reasons. If you want to make a mod that writes to files or accesses the internet, you need to put a public static bool called GiveMeFreedom in your ModMeta implementation. Note that this only works for dll-based mods, which can't be uploaded to the Steam Workshop, and the user will be warned.&lt;br /&gt;
&lt;br /&gt;
= Events =&lt;br /&gt;
As of Alpha 11.6.5.&lt;br /&gt;
&lt;br /&gt;
Note that no MarketSimulation events are raised during the initial market simulation to avoid race conditions.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.IsDoneLoadingGame&lt;br /&gt;
|Raised when a new game has finished loading. Beware that this can be raised before the initial market simulation is done.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.GameReady&lt;br /&gt;
|Raised when the game is guaranteed to be finished loading and the player has full control.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.OnQuit&lt;br /&gt;
|When the player quits an active game.&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.OnServersChanged&lt;br /&gt;
|When servers have been added or removed. Usually used to keep server dropdowns updated&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductReleased + OnAddOnReleased&lt;br /&gt;
|When a product is released, but does not count Mock products, which are products that are only available to support during beta for the player.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnProductRemoved + OnAddOnRemoved&lt;br /&gt;
|When a product is removed. Products are usually removed from the game after 20 years of inactivity to keep the save file from bloating.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyFounded&lt;br /&gt;
|When a new company is founded, not including the player's company.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnCompanyClosed&lt;br /&gt;
|When a new company is closed down.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnTechResearched&lt;br /&gt;
|When new a new tech level is researched, not including the initial tech levels.&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.OnFrameworkReleased&lt;br /&gt;
|When a framework is released.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnHourPassed&lt;br /&gt;
|When an hour has passed, after everything has updated (server refresh, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnDayPassed&lt;br /&gt;
|When a day has passed, after everything has updated (market simulation, etc.). This is called right before OnMonthPassed when a month passes, so it is basically the same as OnMonthPassed with 1 days per month, except it happens before bills are processed.&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.OnMonthPassed&lt;br /&gt;
|When a month has passed, after everything has updated (bills, etc.).&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Entry points =&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|GameSettings.Instance&lt;br /&gt;
|This class contains most of the objects that manage the game&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.MyCompany&lt;br /&gt;
|The player's company&lt;br /&gt;
|-&lt;br /&gt;
|MarketSimulation.Active&lt;br /&gt;
|Manages all companies and products&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sRoomManager&lt;br /&gt;
|Manages rooms, furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|GameSettings.Instance.sActorManager&lt;br /&gt;
|Manages employees and teams&lt;br /&gt;
|-&lt;br /&gt;
|SelectorController.Instance&lt;br /&gt;
|Manages selection&lt;br /&gt;
|-&lt;br /&gt;
|TimeOfDay.Instance&lt;br /&gt;
|Manages time&lt;br /&gt;
|-&lt;br /&gt;
|HUD.Instance&lt;br /&gt;
|Manages the main HUD and windows&lt;br /&gt;
|-&lt;br /&gt;
|ObjectDatabase.Instance&lt;br /&gt;
|Contains all furniture and room segments&lt;br /&gt;
|-&lt;br /&gt;
|WindowManager&lt;br /&gt;
|Controls windows and has functions to create windows and GUI elements&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
	<entry>
		<id>https://softwareinc.coredumping.com/wiki/index.php?title=MediaWiki:Common.js&amp;diff=1326</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://softwareinc.coredumping.com/wiki/index.php?title=MediaWiki:Common.js&amp;diff=1326"/>
		<updated>2026-03-25T20:42:37Z</updated>

		<summary type="html">&lt;p&gt;Khornel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mw.loader.load(&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js&amp;quot;);&lt;br /&gt;
mw.loader.load(&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css&amp;quot;, &amp;quot;text/css&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$(document).ready(function () {&lt;br /&gt;
  var blocks = document.querySelectorAll('pre code');&lt;br /&gt;
  for (var i = 0; i &amp;lt; blocks.length; i++) {&lt;br /&gt;
    hljs.highlightElement(blocks[i]);&lt;br /&gt;
  }&lt;br /&gt;
});&lt;/div&gt;</summary>
		<author><name>Khornel</name></author>
	</entry>
</feed>