How to create a mod (WIP)

Modding Prerequisites

There a great article about it in the game forum written by main developer ai_enabled:

http://forums.atomictorch.com/index.php?topic=1027.0

Here will be same steps that mentioned in article above, but with screenshots and more walkthrough.

Install CryoFall Editor. (optional but highly recommended)You can develop mods by using Client or Server, but it's highly recommended to use CryoFall Editor as it including both Client and Server in a single executable (and some other awesome developer features as well).

You can find it in your Library -> Tools.

Prepare working directoryIt's highly recommended to use other game directory than main game folder.

Locate installed game folder: Right click on CryoFall Editor (or CryoFall game client if you don't want to use Editor) in you Steam Library and select "Properties". There go to tab "Local files" and press button "Browse local files".

.

Copy it content to prepared folder excluding "steam" file.

For example I use `D:\Projects\CryoFall\ModDevelopment`

.

You can see at screenshot above few bat scripts that I use to automatically update my working directory whenever new game version is released.

Extract core modsWhy we need it would be told in next section.

You can use "Extract Core and Mods.cmd" to do it for you or do it manually.

.

Install Visual Studio 2019.This and other few steps are not mandatory and you can use any text editor for your needs, but if you want to create something big or complicated, then I am recommending you to use Visual Studio or other IDE for do it.

In this and other sections I will use free community edition of Visual Studio as reference.

Visual studio download page.[visualstudio.microsoft.com]

Before installation, please ensure that you've checked ".NET Framework 4.7.2 targeting pack".

If you already have VS2019 installed, please ensure launch Visual Studio Installer -> Modify -> Individual components -- and ensure that ".NET Framework 4.7.2 targeting pack" is checked.

.

.

Download and install CryoFall Modding SDK extension for VS2019.You can download it from site[marketplace.visualstudio.com] or find it in Visual studio online extension list:

.

Note, that after extension installation you need to restart Visual Studio.

Configure Visual Studio (optional but highly recommended)A few important notes:

XAML Designer is not supported

Though it can work fine in most cases, but it's recommended to disable it (Visual Studio Options, XAML designer, uncheck "Enable XAML Designer").

If you want to debug your code with breakpoints:

Go to Visual Studio Options, Debugging, uncheck "Require source files to exactly match the original version" (because the game includes C# compiler which performs some code-generation and so resulting C# files do not match the original C# files - but it's not a problem for step-by-step debugging as the C# code lines kept intact).

How Mods Works In This Game

Here I gather some info from forum[forums.atomictorch.com] , wiki and my own experience as mod creator.

The game IS a mod for the engineEssentially the game IS a mod for the engine. It uses available API to create the entire game.

The entire Core.cpk package is a VisualStudio Project with EVERYTHING. It is completely open to the players. Every single game system is 100% open-source :)

Mods extension*.cpk for Core Package and *.mpk for Mod Package

Basically, these files are just a regular .zip archive (with no compression) and they should contain files directly, not in an extra subfolder.

The game could work fine with both archive Core.cpk file or unpacked Core.cpk folder — it will either create a virtual file system to access the files in the archive or use the real file system

Live re-compilingThe CryoFall custom game engine (called Renkei) supports live reloading of C# & XAML code (as well as all the visual and audio assets) so it's not necessary to restart the game to observe the changes!

Mods interactionWhen a mod file (or several mod files) is loaded it will merge with the already loaded core files into a so-called "virtual file system". Even though the contents of the core and mod packages are stored separately, the game will treat them as one file system with shared paths. Now, what does that mean?

As an example, let's say we have a CPK with a file located at "/content/some_file.txt" and an MPK with a file "/content/some_file.txt" that has the same path and name. What happens when we start the game? Since both files in the CPK and the MPK share the same path, the file stored in the MPK will override the one in the CPK since it was loaded after the CPK. This mechanism makes it possible to override the core functionality and content easily without recompiling the whole CPK or modifying its content. The same principle works not just with content files, but with assets, scripts, and any other type of files.

Virtual file system concepts The core and all mods are loaded into one virtual file system, with an overwrite rule (See "File precedents and overloading" section above for explanation).

Mods can use each other's files, so don't hesitate to use original game resources in your mods.

MPK files are loaded in the order listed in ModsConfig.xml. If two MPK files have the same file (path+name), the file in the later MPK will be loaded.

File names are NOT case-sensitive. QWER.xml and qwer.xml are considered the same file!

Mod Structure

Header.xml

Most important file: It contains all essential information about mod:

<?xml version="1.0" encoding="utf-8"?> <root> <id>unique_mod_id</id> <title>Name of the mod</title> <author>Author name</author> <description>Brief description for the mod.</description> <version>1.0.0</version> <!-- current mod version --> <updated>01.01.2015</updated> <!-- last updated date --> <!-- Mod type: 1 - server, 2 - client-server, 3 - client --> <!-- Please note: mods of type 1 and 2 are ignored when you're connecting to the server which is missing them --> <modtype>2</modtype> </root>All the elements are mandatory for a mod and must be properly specified.

ModtypeIt is a special parameter which defines whether a mod should be loaded by a server, client, or both.

client

For example, if we want to create a mod which just replaces some icons, that would be a typical client mod. Client-side mods will be ignored by servers if listed in ModsConfig.xml.

server

On the other hand, mods that contains only server-side alterations, like spawn scripts are typical server mods. If they are listed in ModsConfig.xml, a server will load them but clients won't, and the server won't demand that the player have them in order to play.

Again, clients do not need any server-side mods to connect.

client-server

Lastly there is a client-server mod, which is needed on both client and server. If a server was created with a specific client-server mod and the client doesn't have the same one, the server won't let the client connect.

LocationThe header file must be placed in the root of the MPK like so:

root --> --> Content/ --> Scripts/ --> UI/ The content and data folders are also on the same level.

Version HandlingThe way the game treats mod files is actually a bit trickier. This is because you may have different versions of the same mod in your mods folder and since they share the same ID how would the game know which one to load?

When a mod is loaded, the version of the mod must be specified along with its ID. The full internal ID for a mod is [id]_[version]. For instance, the unique ID of this mod from the above example would be unique_mod_id_1.0.0.

To determine which mods the game should load, there's a file ModsConfig.xml (usually located in the user documents folder). All mods that should be loaded should be listed in this file.

Creating Your First Mod

So, you know everything you should know about mods for CryoFall?

Than let's try to make new mod.

Open Visual Studio 2019

Create new CryoFall Mod Project If you setup CryoFall Mod SDK right, than you should find new project template for CryoFall Mod

Enter name of your new mod

Project name is your mod name.

I named it "TestModPleaseIgnore" for educational purpose.

Select working directory 'Data/Mods' folder

My working directory is 'C:\Projects\CryoFall\ModDevelopment'

So, mod would go to 'C:\Projects\CryoFall\ModDevelopment\Data\Mods\'

Check "Place solution and project in the same directory" checkbox.

(In VS2017 it was inverted checkbox. In VS2019 this checkbox name is more clear of what we need to achieve.)If all was set up correctly then you should see something like this:

(There is some warnings in "Dependencies" section, it's fine, let's clear them now.)

Switch project platform from "Debug_LibsAsProjects" to simple "Debug".

After that - save project, close it and open again. (This will clear dependencies problems)

Link Core mod to your project (optional but highly recommended) File -> Add -> Existing Project

Select `AtomicTorch.CBND.CoreMod.csproj` located in Core/Core.cpk of your working directory.

After doing so - you can notice that CoreMod project was added in Solution Explorer:

.

Add reference to CoreMod projectOpen Reference Manager window (there is few ways of doing so)

(This screenshot from VS2017, in VS2019 it's "Add Project Reference...")

.

And check checkbox for CoreMod project.

.

Adding CoreMod to your project is QoL addition:

Visual Studio IntelliSense will help you with auto-complete of core game api.

You can easily look to core game code while working on your mod.

Using breakpoints on core game code for debugging purposes.

Save changes

Add your mod to gameGo to your working directory's 'Data' folder and edit ModConfig.xml file with any text editor.

For unpacked mods there a bit different entry in ModConfig.xml:

<?xml version="1.0" encoding="utf-8" standalone="yes"?> <mods> <unpacked_mod> <mod_id>core_1.0.0</mod_id> <is_core_mod>1</is_core_mod> <path>Core/Core.cpk</path> </unpacked_mod> <unpacked_mod> <mod_id>editor_1.0.0</mod_id> <is_core_mod>0</is_core_mod> <path>Core/Editor.mpk</path> </unpacked_mod> <unpacked_mod> <mod_id>TestModPleaseIgnore_0.0.1</mod_id> <is_core_mod>0</is_core_mod> <path>Data/Mods/TestModPleaseIgnore</path> </unpacked_mod> </mods> Run gameRun it directly from your working directory.

`CryoFall Editor.exe` (or `CryoFall Client.exe` If you want to test it in proper environment)

Is my mod are loaded at all?Our new fresh mod is absolutely useless and do absolutely nothing, so how to check if it loaded at all?

The answer is simple: check logs!

Go to 'Data\Logs' of your working directory and open latest 'Client_CryoFall_.....log'

In the beginning there should be few lines:

[IMP] Mods catalog initialized. Available files: core_1.0.0, editor_1.0.0, TestModPleaseIgnore_0.0.1 [IMP] Mods config location: "D:\Projects\CryoFall\ModDevelopment\Data\ModsConfig.xml" Active core/mods list: * core - ClientServer v1.0.0 (from folder "D:/Projects/CryoFall/ModDevelopment/Core/Core.cpk") * editor - ClientServer v1.0.0 (from folder "D:/Projects/CryoFall/ModDevelopment/Core/Editor.mpk") * TestModPleaseIgnore - ClientServer v0.0.1 (from folder "D:/Projects/CryoFall/ModDevelopment/Data/Mods/TestModPleaseIgnore") [IMP] Real file system initialized successfully: Core mod: Core Mods list: * Editor * TestModPleaseIgnore First line: Show all available mods.

Second line: Show result of 'ModsConfig.xml' parsing.

Third line: Show which mods loaded successfully.

Prepare mod for distributionAfter all the necessary work on your mod is done, it's time to prepare it to distribution to the world.

We need to pack it to *.mpk as all other mods do.

As was said previously - mpk is just an zip-archive without compression.

You can use any suitable tool to do so, just don't forget to add all necessary things inside.

(header.xml, license.txt and all your work)

For WinRaR:

For 7-Zip:

Change format to "ZIP", compression method to "Store" and resulting file extension to ".mpk"

Making Something Useful

There a few different ways of modding:

Altering existing code

Expanding content

Making something completely new

More about it is in sections below.

- Altering Existing Code

If you want just to adjust some numbers or make some small changes for original code: you need to copy existed CoreMod file, put it in your mod in corresponding folder (following folder hierarchy in CoreMod) and make some changes there.

After your mod loads to the game, it replaces this file in game virtual file system and game will use it as original.

Examples:

To adjust the game LP rate (gained via skills activity) you need to make a copy of '/Scripts/Technologies/Base/TechConstants.cs' and altered constant SkillExperienceMultiplier. (Please note that it is server-side changes)

If you want to extend the lifespan of the buildings built by players (for example, if you want to play on your server rarely and don't want to see your base destroyed after the login a few days later) than you are looking for this file 'Scripts/StaticObjects/Structures/Base/StructureConstants.cs' constant StructureDecayDelaySeconds defining the duration in seconds after which the structure decay will kick-in if the player is not visiting the base longer than the defined duration. (Please note that it is server-side changes)

If you want to alter some icons - all you need to do is find existing item icon in Content folder of CoreMod, and create a new one with same name and path in your mod's folder. (it's a pure client mod) Also, please note, that for some icons to determine theirs attach point are used a magenta pixel.

- Expanding Content

Adding new items, buildings, mobs or other game object are related to this.

(Please note, that it is client-server mod type)

For example we want to add new Ammo for sniper rifle with uranium core:

Find existing object of that type in CoreMod files.

Let's take as example an incendiary ammo for sniper rifle 'Scripts\Items\Ammo\ItemAmmo300Incendiary.cs'

Copy it to your mod with new name

Let's name it 'ItemAmmo300Uranium' and save it to our mod:

'Scripts\Items\Ammo\ItemAmmo300Uranium.cs'

Alter some parameters

For example add radiation poisoning, slightly increase range and armor piercing:

namespace AtomicTorch.CBND.CoreMod.Items.Ammo { using AtomicTorch.CBND.CoreMod.CharacterStatusEffects; using AtomicTorch.CBND.CoreMod.CharacterStatusEffects.Debuffs; using AtomicTorch.CBND.GameApi.Data.Characters; using AtomicTorch.CBND.GameApi.Data.Weapons; using AtomicTorch.GameEngine.Common.Helpers; public class ItemAmmo300Uranium : ProtoItemAmmo, IAmmoCaliber300 { public override string Description => "Heavy anti-material .300 round with uranium core."; public override string Name => ".300 uranium ammo"; public override void ServerOnCharacterHit(ICharacter damagedCharacter, double damage) { // 40% chance to add bleeding if (RandomHelper.RollWithProbability(0.40)) { damagedCharacter.ServerAddStatusEffect<StatusEffectBleeding>(intensity: 0.05); // 30 seconds } // Add radiation poisoning instead of heat damagedCharacter.ServerAddStatusEffect<StatusEffectRadiationPoisoning>(intensity: 0.25); } protected override void PrepareDamageDescription( out double damageValue, out double armorPiercingCoef, out double finalDamageMultiplier, out double rangeMax, DamageDistribution damageDistribution) { damageValue = 35; // very high armor piercing armorPiercingCoef = 0.8; finalDamageMultiplier = 1.5; // more range for rounds with uranium core rangeMax = 15; // only kinetic damage on impact damageDistribution.Set(DamageType.Kinetic, 1.0); } } } Now we have new ammo type in code, what we a missing? Right, icon.

Add icon

Add images to Content folder of your mod with corresponding folder and exact same name as new object

For our ammo it would be 'Content\Textures\Items\Ammo\ItemAmmo300Uranium.png'

We are successfully added new ammo to the game, but wait where it is?

We forgot to add recipe for it.

Btw, I suggest for your to use CNEI mod, that can show all entity in a game.

Add recipe for items

For our new ammo it should be something like this:

'Scripts\CraftRecipes\StationCrafting\WeaponWorkbench\RecipeAmmo300Uranium.cs'

namespace AtomicTorch.CBND.CoreMod.CraftRecipes { using System; using AtomicTorch.CBND.CoreMod.Items.Ammo; using AtomicTorch.CBND.CoreMod.Items.Generic; using AtomicTorch.CBND.CoreMod.StaticObjects.Structures.CraftingStations; using AtomicTorch.CBND.CoreMod.Systems; using AtomicTorch.CBND.CoreMod.Systems.Crafting; public class RecipeAmmo300Uranium : Recipe.RecipeForStationCrafting { protected override void SetupRecipe( StationsList stations, out TimeSpan duration, InputItems inputItems, OutputItems outputItems) { stations.Add<ObjectWeaponWorkbench>(); duration = CraftingDuration.Medium; inputItems.Add<ItemIngotSteel>(count: 5); inputItems.Add<ItemIngotCopper>(count: 5); inputItems.Add<ItemFormulatedGunpowder>(count: 30); inputItems.Add<ItemComponentsIndustrialChemicals>(count: 5); outputItems.Add<ItemAmmo300Uranium>(count: 10); } } } I use old recipe for incendiary ammo, as we don't add uranium yet :D (You can do it on your own, because it's just an example)

Add new technology node (or alter existed one)

Now recipe is set, but it's not shown in workbench yet, because we need to unlock it with corresponding technology.

Let's add new technology node for our new ammo right after incendiary ammo

'Scripts\Technologies\Tier4\Offense4\TechNodeAmmo300Uranium.cs'

namespace AtomicTorch.CBND.CoreMod.Technologies.Tier4.Offense4 { using AtomicTorch.CBND.CoreMod.CraftRecipes; public class TechNodeAmmo300Uranium : TechNode<TechGroupOffense4> { protected override void PrepareTechNode(Config config) { config.Effects .AddRecipe<RecipeAmmo300Uranium>(); config.SetRequiredNode<TechNodeAmmo300Incendiary>(); } } }

Congratulation to us, we made something useful (or not).

This is resulting project tree of our work:

- Making Something Completely New (WIP)

This is the hardest part of modding (adding new gui, new systems or other various things).

You can look into existed mods and learn the ways of how they work or investigate CoreMod game code to figure it by yourself.

Some explanation of different script types and their usage.

ClientComponents, Systems and Triggers.

This kind of scripts executes every frame (or on some small time interval).

ClientComponents - executes only on client.

(Things related to gui, various helpers and other client related stuff)

Systems - executes on client and server, main way of client-server interaction.

(Client tell server to run server variant of function on it's side)

Triggers - executes only on server.

(Various spawn scripts and other things) Bootstrappers.

This kind of scripts are executes on game start.

You can specify order of it using:

[PrepareOrder(afterType: typeof(BootstrapperClientCore))]Also in BootstrapperClientGame there is few event callbacks that you can use on game init and reset. (it's actual game load after you choose server to connect)

Adding hotkeys

There is few things you need to do to make it work:

Add new button enum

Something like that:

[NotPersistent] // Prevent this enum to be a part of network serialization. public enum MyNewButtons { [Description("Do almost nothing")] [ButtonInfo(InputKey.J, Category = "My new amazing mod")] DoNothing, } Register new button enum on game startup.

Add new bootstrapper for your mod and add lines

public override void ClientInitialize() { ClientInputManager.RegisterButtonsEnum<MyNewButtons>(); }there MyNewButtons is a name of your button enum.

Assign actions to your new hotkeys

Start new input context in ClientInputContext to handle button actions.

(You can add it on game startup, game load or on some specific action)

gameplayInputContext = ClientInputContext .Start("My amazing mod input context") .HandleButtonDown(MyNewButtons.DoNothing, MyFunctionThatDoNothing()); If you want to disable buttons from using - just stop related input context.

gameplayInputContext?.Stop(); gameplayInputContext = null; Adding options

Main game settings menu are made by procedural generation.

It's assemble all categories and options based on existed scripts of ProtoOptionCategory and ProtoOption types.

Local settings storage

Local settings are stored in 'Data/ClientStorage' folder.

To load or save storage you need to use followed Api:

settingsStorage = Api.Client.Storage.GetStorage("Mods/YourMod.Settings");(You can use any name you want, but to avoid conflicts I suggest using 'Mods/UnicModID' as base)

You need to register all custom types you want to storage there

settingsStorage.RegisterType(typeof(MyCustomType));After that you can try to load settings from local storage

settingsStorage.TryLoad(out settingsInstance)Do not forget to create new settings if none already existed and version mismatch cases.

To save settings use this:

settingsStorage.Save(settingsInstance); ...

Troubleshooting (WIP)

I'm starting Editor\Client from my dev directory, but it instantly closed and run one from steam instead.

It happens because of steam file with no extension in your dev folder that you copy from steam game folder. Just delete this file (in your dev folder) and all should be fine.

Source: https://steamcommunity.com/sharedfiles/filedetails/?id=1707742469					

More CryoFall guilds