• We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.

PDXKatten

Community Programs Specialist
Administrator
Paradox Staff
Moderator
QA
Oct 14, 2022
452
3.985
Mods [WIP]

The current modding functionality is a work-in-progress. Check out the example mods and the additional information below to get started with creating mods in Millennia!
Examples:

Installing Mods

Mods can be added to the game by subscribing to them in the Steam Workshop https://steamcommunity.com/app/1268590/workshop/ . After subscribing to an item in the workshop, it will be downloaded and available to use in game. You must re-launch the game to pick up any new mods that you subscribe to.

You can view, enable, and disable mods within the game by clicking the “Mods” button on the main menu
1.png


Creating Mods

To create and test your mods before uploading them to the Steam Workshop, you must create a “Mods” folder where the game’s data is:
C:\Users\<username>\AppData\LocalLow\CPromptGames\Millennia\Mods

Sub-folders in this “Mods” directory should contain the individual mods you are working on.

Folder Structure

A mod can contain the following sub-folders depending on the nature of the mod, and these sub-folders are case-sensitive.
2.png


Creating a Custom Nation

A Custom Nation mod should contain the following:
  1. A custom nation xml file in the CustomNations sub-folder
  2. A flag image (png or jpg) in the Flags sub-folder
  3. A names xml file if you want to create custom town/city names for the custom nation placed in the Names sub-folder
  4. A string xml file

The Flags sub-folder needs to have an xml file that lists the flags that are a part of the mod and the flag images:
3.png


4.png


One custom nation needs a regular flag and a splinter flag, and the splinter flag should be named as <FlagName>_SPLINTER. The flag images should be 256x128 to show up in the game correctly.

Names sub-folder can contain one or more xml file that contains the city and town names for your custom nation. It should follow the following format:
5.png


The IDs for the name tables should be unique and the table types should be set correctly based on whether the names are for cities or towns. NTT_City is for city names and NTT_Town is for town names. The names themselves should begin and end with $$. You will need to add various strings for your nation for each city name, town name, the nation name, and the splinter nation name:
6.png


The CustomNations sub-folder can contain one or more custom nation xml. An example custom nation xml can be seen below:
7.png


NationName is the name that will show up in game for your nation. The CityNameCollection and TownNameCollection should have the IDs of the name tables you created. Flag should be the name of the flag you placed in the Flags sub-folder.

Sprites

Any other images (png or jpg) you want to use in your mod should be placed in the Sprites sub-folder as well as a SpriteInfo.xml file that contains basic information about the sprites.
8.png


Image size guide:
  • Unit Portraits – 256 x 256
  • Improvement Icon – 256 x 256
  • Tech image – 256 x 256
  • National Spirit Icon small – 64 x 64
  • National Spirit Icon – 180 x 60
  • National Spirit Portrait – 640 x 1080 (should also have transparent background)
  • Event images (innovation, chaos) – 16:9 aspect ratio

Creating and Modifying Decks

To change existing decks, you must specify what deck it is you want to change. You do this by the xml tag:
9.png


By default, cards inside a deck that have the <AppendToDeck> xml tag will be added to that existing deck. To modify existing cards within that deck you are changing, you can use the following tags:
10.png


If you want to add a deck, and not just modify an existing one, then simply omit the <AppendToDeck> tag from whatever deck xml you have in your Decks sub-folder.

Strings

Once you get your mod working in-game, you will need to create a strings xml in the Strings sub-folder to fill in the text that you want to go along with your mod.
11.png

12.png


Creating Assets in Unity - [DOWNLOAD MOD PACKAGE HERE]

Assets for mods are loaded through Unity’s Addressables system. To create assets for your mods you must install Unity 2019.4.40f1. Create a new project after installing Unity and import the mod tools package and install the Addressables package
13.png


After the project has been created, you must change some settings with Addressables. Window->Asset Management->Addressables->Settings
14.png


Build Remote Catalog should be checked. Load path must be set to <custom> and with {MOD_PATH} as the value. Build path is the path where the built catalog and asset bundles will be placed. This path can be set to any folder you choose, but you’ll want to remember that location

The mod tools package includes examples for a unit, a landmark, and an improvement and scripts that you’ll need to attach to prefabs so that they’ll work correctly in game.
Any asset you want to include in your mod from Unity needs to be marked as “Addressable”
15.png


Once the assets have been marked, you can build the addressables by navigating to Window->Asset Management->Addressables->Groups and then from that window Build->New Build->Default Build Script. The folder that you set as the Build Path will contain the asset bundles and catalog files you need to copy and paste into the Assets folder of your mod.

16.png


Creating a Unit

To create a unit, you must attach the AUnitMemberModel.cs script as a component on the unit prefab that you create. The script is used to configure how the unit is presented in the game and for mapping animations to in-game actions.
17.png


Animations that are used for your unit need to be marked as Legacy to work in game
18.png


You must also define the unit’s stats and other data in xml.
19.png


The UnitMemberPrefab should be set to the addressable key from Unity:
20.png


And the Portrait should be set to the sprite image that you place in the Sprites folder.

Creating a Landmark

A landmark does not require any scripts to be attached to it. Create a prefab with the model you want to use for your landmark and follow the instructions to export it as an addressable. You’ll need a landmark xml file in the Landmarks sub-folder and an entity xml file in the Entities sub-folder.

Make sure that the landmark EntityInfo definition has the EntityPrefab data set to the value of the Addressable path from Unity
21.png

22.png


The landmark entry in the landmark xml should have its MapTile value be the name of the ID of the landmark entity.
23.png


Creating an Improvement

An improvement prefab must have the AEntityBuilding and AGameData scripts attached to it to work in-game. You must define the improvement’s data in xml
24.png


The IconName should be set to the sprite that you want to show for this improvement and the EntityPrefab should be set to the key of the addressable from Unity.

Uploading Mods to the Steam Workshop

Local mods will be listed in the Mods UI and have an Upload button that is used for uploading to the workshop.
25.png


Clicking this button will bring up the upload dialog. Items are required to have a title, but it is a good idea to give your item a preview image and description.
26.png


After the item is uploaded, its default visibility will be hidden. You should go to the item’s detail page to make any further edits and to change the visibility to public when ready.

If you are wanting to update an existing mod that you’ve already uploaded, you should fill in the “Existing Steam ID” field with the existing item’s ID. This can be found on the item’s detail page:
27.png






Hello Modders!

We have decided to let you see the XML files for Millennia, as they normally aren't available to be seen due to the way the game is normally released. Have a fun time browsing through the files and seeing what you can come up with. This is similar to how on Paradox Grand Strategy games we have a lot of script files available to modders to look through and alter for their mods!You can see the attached file for said XML files!

Happy browsing modders! See the attached ZIP file for the files!
 

Attachments

  • Millenia_XML_Examples.zip
    629,6 KB · Views: 0
Last edited by a moderator:
  • 1
  • 1Like
Reactions:
May I ask why did you choose XML? It's well known as inconvenient and verbose. Other Paradox games use JSON-like format, and YAML is pretty well known too - why not one of those?

And similarly, all this system feels very verbose and inconvenient. Like the format is auto-generated from your internal data structures, with no regard for real humans writing mods. I understand that your internal code went through many optimizations and clarifications, and it needs all those IDs, parts and very long names containing namespaces and data structures, but from content creation point of view, all this is more annoying than helpful. Perhaps you could create some translation layer between mod definitions (easy on humans) and actual data structures in code (easy on computer)?
 
Last edited:
  • 2Like
Reactions:
Could you write a guide on how to look the base game resources definitions? For example to get the list of decks, improvements, etc... That may be useful to patch some of them (since you describe how to remove a card from a deck) and to get more examples.
 
Could you write a guide on how to look the base game resources definitions? For example to get the list of decks, improvements, etc... That may be useful to patch some of them (since you describe how to remove a card from a deck) and to get more examples.
You can use tools to extract the unity assests. For example AssetRipper or AssetStudio(the original is not developed anymore, but there are various forks which are updated, but I don't know which of these is good). AssetRipper will put all the TextAssests in one folder and does not preserve the structure of the Addressables. But it is not so important for the XML, because the modding system has a different structure anyway.
 
  • 1Like
  • 1
Reactions:
Is there any documentation on the list of <Personality> options for the custom nations? It would be helpful if we knew what personality options there are, as well as what they mean for the way the AI attempts to interact with others.
 
  • 1
Reactions:
You can use tools to extract the unity assests. For example AssetRipper or AssetStudio(the original is not developed anymore, but there are various forks which are updated, but I don't know which of these is good). AssetRipper will put all the TextAssests in one folder and does not preserve the structure of the Addressables. But it is not so important for the XML, because the modding system has a different structure anyway.
Is there a way to know which files, exactly, we're supposed to extract? The structure is very different compared to games like Ck2 or Eu4 and I'm having trouble navigating the folders, even with AssetRipper.
 
Is there a way to know which files, exactly, we're supposed to extract? The structure is very different compared to games like Ck2 or Eu4 and I'm having trouble navigating the folders, even with AssetRipper.
When I use AssetRipper I extract everything. Then the xml files are in the folder ExportedProject/Assets/TextAsset. The icons should be in the Texture2D folder. Unfortunately I haven't found a way to put all extracted files into a folder structure which mirrors the Addressables which are used by the game. But you can usually deduce the type of file by its name. E.g. the ages decks all start with DECK-TECHAGE, english and haxor localisation files end in -Strings.txt, governments start with GOV, national spirits start with DECK- followed by their name
 
  • 1Like
Reactions:
So, there are separate tags for RemoveCard and ReplaceEffectsForCard. Is there an actual difference in use, if you need to redefine the whole card in the second case anyway?
 
Yes, but what do the personalities even mean? Like what is AIP_Max? AIP_Default? AIP_Aggressive compared to AIP_Bully? These words mean nothing without a description or list of personality game logic changes. I assume an Opportunist would declare war if you have a significantly smaller power score, or are already engaged in a war? An Appeaser would likely accept demands? Like how would I even know what these mean?
 
Yes, but what do the personalities even mean? Like what is AIP_Max? AIP_Default? AIP_Aggressive compared to AIP_Bully? These words mean nothing without a description or list of personality game logic changes. I assume an Opportunist would declare war if you have a significantly smaller power score, or are already engaged in a war? An Appeaser would likely accept demands? Like how would I even know what these mean?
Some of the impacts can be seen in the AIGoals.xml and their different messages are in the DiplomacyStrings localisation asset. You would have to up the rest of the coding in the code.
 
Each "Personality" is controlled by two "Attributes"
Attributes affect how likely they are to send/accept Diplomatic Messages (Send Gift, Open Borders, Open Embassy, etc.)

Aggressive - More likely to declare war/resistant to ending wars & is hostile towards more powerful Nations

Reserved - Fearful of more powerful Nations & less likely to take "mean" diplomatic actions (Threaten, Demand, etc.)

Opportunist - More likely to take "mean" diplomatic actions & Fearful of more powerful Nations

Militant - More likely to take "mean" diplomatic actions & more likely to declare war/resistant to ending wars

Isolationist - Less likely to accept Bilateral agreements & less likely to declare war/willing to end wars

Cooperative - More likely to send "nice" diplomatic actions (Gifts) & extra friendly towards Nations with positive Diplomatic Opinion

Careful - Extra friendly towards Nations with positive Diplomatic Opinion & fearful of more powerful Nations

Diplomat - Less hostile towards Nations with negative Diplomatic Opinion & is more likely to accept Bilateral agreements

All AI Personalities are affected by many factors, it's just that each Personality emphasize two factors more
 
CPG Jackson on Discord:
Here's an xml example for editing an existing entity, I can work with Hudson on getting an example up on the workshop for y'all to take a look at sometime soon.
Some notes about modifying existing entities:If you specify an existing entity in the <ExportTo> tag, that will allow you to change the data of the entity that you specify. Any data that you specify here will then override the data fields or add new data to the existing entity. If you want to remove the data field from the existing entity, then give the data a value of REMOVE in xml as shown above. You can also add or remove tags on the existing entity. To remove a tag you give the tag the prefix “Remove:” followed by the name of the existing tag that’s in the entity that you specified.This should work for existing buildings, units, and improvements.
Image


1726666114860.png




You can also change/override the Icon and Portrait of the existing entity by filling in those in the xml
 
Last edited:
  • 1Like
Reactions:
Not sure if this is right place to post this, but I have noticed a bug with the modding system. I used your examples to modify the that choses requirements for advancing to the 2nd age. Now when I am advancing I have 2 age of bronze advances. My mod and the original.

Code here:
XML:
<ADeck>
   <ReshuffleWhenEmpty>false</ReshuffleWhenEmpty>
   <MaintainOrderWhenShuffled>true</MaintainOrderWhenShuffled>
   <DeckName>VERYSLOWGAMETECHAGE1</DeckName>
   <AppendToDeck>TECHAGE1</AppendToDeck>


    <Tags>
    <Tag>ReplaceEffectsForCard:TECHAGE1-ADVANCE</Tag>
    </Tags>
    <Definition>


      <ACard>
         <ID>TECHAGE1-ADVANCE</ID>
         <ExecutionType>CX_All</ExecutionType>
         <Subtype>CST_Tech</Subtype>
         <Choices>
            <ACardChoice>
               <Effects>
                  <ACardEffect>
                     <EffectType>CE_ResearchTech</EffectType>
                     <Payload>TECHAGE2-BASE</Payload>
                     <!--<Hidden>true</Hidden>-->
                  </ACardEffect>
                  <ACardEffect>
                     <EffectType>CE_RebuildVisuals</EffectType>
                     <Payload>ROADS,ALL</Payload>
                     <Hidden>true</Hidden>
                  </ACardEffect>
               </Effects>
            </ACardChoice>
         </Choices>
         <CardTags>
            <Tags>
               <Tag>TechRequirement:SpecialRequirement-CountTechsWithReq,TECHAGE1-BASE,4</Tag>
               <Tag>TechCostAdjustPerTechWithReq:0.1,TECHAGE1-BASE</Tag>
               <!--<Tag>TechCostBase:40</Tag>-->
               <Tag>TechCostBase:22</Tag>
               <Tag>AIValue:4</Tag>
               <Tag>HelpAlertOnResearchBegin:FIRSTAGE</Tag>
               <Tag>TelemetryNameOverride:TECHAGE1-TECHAGE2_BASE_ADVANCE</Tag>
               <Tag>AgeAdvance</Tag>
            </Tags>
         </CardTags>
      </ACard>
      
</Definition>
</ADeck>
1728074449209.png
 
Not sure if this is right place to post this, but I have noticed a bug with the modding system. I used your examples to modify the that choses requirements for advancing to the 2nd age. Now when I am advancing I have 2 age of bronze advances. My mod and the original.

Code here:
XML:
<ADeck>
   <ReshuffleWhenEmpty>false</ReshuffleWhenEmpty>
   <MaintainOrderWhenShuffled>true</MaintainOrderWhenShuffled>
   <DeckName>VERYSLOWGAMETECHAGE1</DeckName>
   <AppendToDeck>TECHAGE1</AppendToDeck>


    <Tags>
    <Tag>ReplaceEffectsForCard:TECHAGE1-ADVANCE</Tag>
    </Tags>
    <Definition>


      <ACard>
         <ID>TECHAGE1-ADVANCE</ID>
         <ExecutionType>CX_All</ExecutionType>
         <Subtype>CST_Tech</Subtype>
         <Choices>
            <ACardChoice>
               <Effects>
                  <ACardEffect>
                     <EffectType>CE_ResearchTech</EffectType>
                     <Payload>TECHAGE2-BASE</Payload>
                     <!--<Hidden>true</Hidden>-->
                  </ACardEffect>
                  <ACardEffect>
                     <EffectType>CE_RebuildVisuals</EffectType>
                     <Payload>ROADS,ALL</Payload>
                     <Hidden>true</Hidden>
                  </ACardEffect>
               </Effects>
            </ACardChoice>
         </Choices>
         <CardTags>
            <Tags>
               <Tag>TechRequirement:SpecialRequirement-CountTechsWithReq,TECHAGE1-BASE,4</Tag>
               <Tag>TechCostAdjustPerTechWithReq:0.1,TECHAGE1-BASE</Tag>
               <!--<Tag>TechCostBase:40</Tag>-->
               <Tag>TechCostBase:22</Tag>
               <Tag>AIValue:4</Tag>
               <Tag>HelpAlertOnResearchBegin:FIRSTAGE</Tag>
               <Tag>TelemetryNameOverride:TECHAGE1-TECHAGE2_BASE_ADVANCE</Tag>
               <Tag>AgeAdvance</Tag>
            </Tags>
         </CardTags>
      </ACard>
     
</Definition>
</ADeck>
That's a bug in your mod and not a bug in your modding system. You can't just put a <Tags> section in a random place and expect it to do something. You need to put the tags in a card. And I think your card must have a different ID than the card which you want to replace. And your card seems to have the same effects as the normal TECHAGE1-ADVANCE who's effects you are replacing. So it would have no effect. You can't replace tags with ReplaceEffectsForCard. Instead you must remove the normal card(with a card which does only that) and add another card which contains the tags and effects which you want
 
That's a bug in your mod and not a bug in your modding system. You can't just put a <Tags> section in a random place and expect it to do something. You need to put the tags in a card. And I think your card must have a different ID than the card which you want to replace. And your card seems to have the same effects as the normal TECHAGE1-ADVANCE who's effects you are replacing. So it would have no effect. You can't replace tags with ReplaceEffectsForCard. Instead you must remove the normal card(with a card which does only that) and add another card which contains the tags and effects which you want
I don't think so. It actually does work in that it increases the Techs required to advance to 4 instead of default 3. The tags required are where they are supposed be according to the examples. It is saying to replace the effects of that card with the one in my code. The bug is the duplication in the ui, not to mention 1 of them takes less research time.
 
I don't think so. It actually does work in that it increases the Techs required to advance to 4 instead of default 3.
That's your new card. But because you are using neither RemoveCard, AddEffectsToCard nor ReplaceEffectsForCard, you still have the old card with the old requirements. If you would have used ReplaceEffectsForCard correctly, it would have replaced the effects, but your tags would not have been used.
 
  • 1Like
Reactions: