The Asset-Library - Basics

Imagine your game like this (very simplified):
Assets + Graphics → Binary (Anno1800.exe) → What you can do and see on screen
You cannot modify the Binary. What you can do, is feeding it new or changed assets and graphics that the game can interpret. That means, you have to stick to the rules, only if you write Code that can be parsed by the game, it will do what you want it to do.

What skills are needed to get started?

First, no, you do not need to be a programmer, although this is always a plus.
If you aren‘t a programmer, it is strongly recommended you familiarize yourself with the concepts of data types, variables, arrays, inheritance as well as (generic) dictionaries and vectors/lists. You don‘t need to write actual code with it, but understanding those is quite valuable.
Most of the game files are using the XML scripting language. I won‘t explain any XML syntax and going to assume basic XML knowledge, if you don‘t know any of this, you should read into that topic first. You should also be or get familiar with Xpath, since this is needed for the modloader later on.

Understand the Asset Library

So, this should be the first in some kind of tutorial series about asset modding. First, I want to apologize (no, not canadian) – the start is gonna be more dry and theoretical stuff, but you‘ll need it in order to get to the interesting parts, especially if you like to inject new functionality.
For Assets, Anno uses a few basic concepts all over again:

  • Assets are actual ingame objects (like a building, a ship, or a construction menu) that are built from a template.
  • Templates are Blueprints for Assets that configure defaults for values in each asset using this template, and say which properties it has.
  • Properties are Containers that are directly contained by an Asset. Properties can contain Containers, but Containers cannot contain a property.
  • Containers are collections of Values, vectors or other containers.
  • Vectors are lists of variables or containers
  • Dictionaries are like vectors, but each element gets a unique name that needs to match a hardcode the game is looking for. Because of this, the size is limited to the amount of available hardcodes.
  • Values are simple variables or arrays
Note: To differentiate between the name of a value and the value itself, I will call the name „variable“ from now on.

Properties

This is the hardest to understand, but once you get it, you will have no problems understanding any templates and assets the game offers.
Properties.xml essentially consists of two parts: DefaultContainerValues and DefaultValues. Those are grouped for better overview in the dev tools, but in general you could narrow it down to those two.
DefaultContainerValues defines which Containers a property uses, define Variables inside those containers, in case the container contains a vector or dictionary, the content type of this data structure is given.
DefaultValues defines the variables that are contained directly inside the property and inherit the Containers from DefaultContainerValues.
As the names might suggest, setting the a value for a variable inside the properties.xml sets this value as default for this variable in every asset using this property.

You can change the values for variables, but you cannot tell the game to load other containers or variables, since this is a direct export of what the game expects!
Note that on rare occasions, some of the export is incomplete, in that case every variable is given inside assets.xml.

If you need any information on what you can do with each property, this is where you should look. The following is a shortened version of the „IrrigationConfig“ property, along with some comments.

Example: Property IrrigationConfig[ Copy codeblock ]
<Properties> <DefaultContainerValues> <Building> <IrrigationConfig> <IrrigationSpreading> <!-- Variable inside Container inside Property: Variable is defined in the same spot --> <IrrigationSpreadRule>MaxAbsDist</IrrigationSpreadRule> </IrrigationSpreading> <!-- IrrigationIslandSeeds is a container containing a vector --> <IrrigationIslandSeeds> <!-- Island is the content type of that vector--> <Island>0</Island> </IrrigationIslandSeeds> </IrrigationConfig> </Building> </DefaultContainerValues> <DefaultValues> <IrrigationConfig> <!-- Containers are inherited --> <IrrigationSpreading /> <IrrigationIslandSeeds /> <!-- Variable directly inside Property: Variable is defined elsewhere, in the Property inside DefaultValues --> <StaticIrrigationRandomizerFrequency>2</StaticIrrigationRandomizerFrequency> </IrrigationConfig> </DefaultValues> </Properties>
Enlarge codebox

In case a container A contains another container B, B is defined in ContainerValues and then inherited by A. If B contains Variables, those are defined in the same spot.
The following example shows the DefaultContainerValues for the IrrigationConfig property:

Example: Container in Container[ Copy codeblock ]
<Properties> <DefaultContainerValues> <IrrigationConfig> <VisualsAndEffects> <!-- Defining the Vegetation Container --> <ContainerValues> <Vegetation> <!-- Variables inside Container inside Container inside Property: Variables are defined in the same spot --> <FadingSpeed>0.05</FadingSpeed> <BlurRadius>1</BlurRadius> </Vegetation> </ContainerValues> <!-- The defined Vegetation Container is now inherited into VisualsAndEffects --> <!-- Note: In this case, Vegetation is just a simple Container --> <!-- but it could also refer to the content type of a vector if VisualsAndEffects was one! --> <Vegetation /> </VisualsAndEffects> </IrrigationConfig> </DefaultContainerValues> <DefaultValues> <IrrigationConfig /> </DefaultValues> </Properties>
Enlarge codebox

The full definition of our IrrigationConfig should look something like this:

Example: Full IrrigationConfig[ Copy codeblock ]
<Properties> <DefaultContainerValues> <Building> <IrrigationConfig> <IrrigationSpreading> <IrrigationSpreadRule>MaxAbsDist</IrrigationSpreadRule> </IrrigationSpreading> <IrrigationIslandSeeds> <Island>0</Island> </IrrigationIslandSeeds> <VisualsAndEffects> <ContainerValues> <Vegetation> <FadingSpeed>0.05</FadingSpeed> <BlurRadius>1</BlurRadius> </Vegetation> </ContainerValues> <Vegetation /> </VisualsAndEffects> </IrrigationConfig> </Building> </DefaultContainerValues> <DefaultValues> <IrrigationConfig> <IrrigationSpreading /> <IrrigationIslandSeeds /> <VisualsAndEffects /> <StaticIrrigationRandomizerFrequency>2</StaticIrrigationRandomizerFrequency> </IrrigationConfig> </DefaultValues> </Properties>
Enlarge codebox

Data Types

The following Data Types are used for variables:

  • int → mostly signed 16 or 32 bit integers
  • float → american style 0.1305
  • boolean → noted as 0 or 1
  • String → without quotation marks
  • Hardcode → used like a String, however only predefined names are accepted.
You need to figure out the data type of a Variable by yourself by taking a look at how it‘s used inside all three files. Also, there is no full list of hard codes that can be used. Previous games like 2205 had a datasets.xml which contained this information, however this is not the case with 1800, and it would be a great thing if something like this could be published in the future by Ubisoft.

Templates

A template consists of a unique name as well as a collection of properties that objects using this template have.
The same as properties, Groups are only there for overview in Dev Tools and essentially are irrelevant

i.e. take a look at the Template „UnlockableAsset“

This one only has the Standard and the Locked Property.
Templates can define default values for any variable inside a property, which is then applied for all assets using this template, and that‘s essentially it.

Inheritance

At this point we should take a quick look at inheritance in general.

This is our custom template „CustomIrrigationConfig“.

As you might recall from earlier, the Property has a default Value of 2 for StaticIrrigationRandomizerFrequency. We now want to change that to 5, but keep the rest.
For this, we do not have to copy+paste everything, we just have to change that variable and leave the rest out.
In templates and assets, containers are automatically inherited, however properties are not (keep this in mind!). We could also manually inherit containers, but we do not have to.

Now, we also want to change the FadingSpeed inside VisualsAndEffects. For that, we have to first manually inherit VisualsAndEffects, inside that manually inherit Vegetation, and inside that override the FadingSpeed.

For dictionaries, the unique names are treated like containers, for vectors, inheritance has to be made manually. For this, see here (Only german).

Now let‘s get to creating actual ingame objects. Each Asset has the Standard property, which defines the GUID of an object.

An Asset consists of a Template and Values. To create our asset, we start of by specifing the template. In our case we will create a simple building from the template FactoryBuilding7. For Values, we will note down the exact properties that this Template has, without any Variables or Containers.

Then we‘ll do the Values.
I have decided to allocate the GUID 1337733142 for my building. This is now added in the Standard property as a Variable. For better overview, we can set a Name inside Standard too, though this is only for us. More about GUIDs you can find here.

Theoretically, we now have a fully functional factory. Except it produces nothing from nothing, does not cost any workforce or credits and does not have construction cost.
So let‘s assign those things to our factory.
We will make a factory that produces canned food from zinc and potatoes, and just because we can, we will do it in the new world with Obreros.

Assign Values[ Copy codeblock ]
<Asset> <Template>FactoryBuilding</Template> <Values> <Standard> <GUID>1337733142</GUID> <Name>Canned Food Factory 02 - Variant uses Potatoes and Zinc</Name> </Standard> <Building> <!-- Building for Colony01 (which is south america) --> <AssociatedRegions>Colony01</AssociatedRegions> <!-- Random rotation in the building preview --> <BuildModeRandomRotation>90</BuildModeRandomRotation> </Building> <Blocking> <!-- The radius in which grass and trees will be hidden in preview/deleted when built--> <HidePropsRadius>0</HidePropsRadius> <DeletePropsRadius>0</DeletePropsRadius> </Blocking> <Cost> <Costs> <Item> <!-- Referencing Money --> <Ingredient>1010017</Ingredient> <Amount>10000</Amount> </Item> <Item> <!-- Referencing Wood --> <Ingredient>1010196</Ingredient> <Amount>50</Amount> </Item> <Item> <!-- Referencing Bricks --> <Ingredient>1010205</Ingredient> <Amount>30</Amount> </Item> <Item> <Ingredient>1010218</Ingredient> </Item> <Item> <Ingredient>1010207</Ingredient> </Item> <Item> <Ingredient>1010202</Ingredient> </Item> </Costs> </Cost> <Object /> <Mesh /> <Selection> <!-- Hardcode, referencing the Participant (Character) that is visible in the menu. --> <!-- in our case it is the Obrero --> <ParticipantMessageArcheType>SA_Resident_tier02_atWork</ParticipantMessageArcheType> </Selection> <Text /> <Constructable /> <Locked /> <SoundEmitter /> <FeedbackController /> <Infolayer /> <UpgradeList /> <Factory7 /> <FactoryBase> <FactoryInputs> <Item> <!-- Product references the GUID of Potatoes --> <Product>1010195</Product> <Amount>1</Amount> <!-- internal Storage for Potatoes --> <StorageAmount>6</StorageAmount> </Item> <Item> <!-- Product references the GUID of Zinc--> <Product>1010229</Product> <Amount>1</Amount> <!-- internal Storage for Zinc --> <StorageAmount>3</StorageAmount> </Item> </FactoryInputs> <FactoryOutputs> <Item> <!-- Product references the GUID of Canned Food --> <Product>1010217</Product> <Amount>1</Amount> <!-- internal storage for Canned Food --> <StorageAmount>4</StorageAmount> </Item> </FactoryOutputs> <!-- Time in seconds needed to produce 1t --> <CycleTime>45</CycleTime> </FactoryBase> <LogisticNode /> <AmbientMoodProvider /> <Maintenance> <!-- Maintenance Cost --> <Maintenances> <Item> <!-- Money --> <Product>1010017</Product> <Amount>40</Amount> <InactiveAmount>20</InactiveAmount> </Item> <Item> <!-- Obrero Workforce --> <Product>1010367</Product> <Amount>25</Amount> </Item> </Maintenances> </Maintenance> <Attackable /> <Pausable /> <IncidentInfectable /> <Industrializable> <!-- Turn off industrialization, since we don't have electricity in the new world --> <BoostedByIndustrialization>0</BoostedByIndustrialization> </Industrializable> <Culture /> <QuestObject /> <Electrifiable /> </Values> </Asset>
Enlarge codebox

One thing is missing now – the visuals. Anno more or less seperates graphics from logic. Everything graphics-related is stored in other files, we simply reference their path, starting from the game‘s „data“ folder.

Assign graphics[ Copy codeblock ]
<Asset> <Template>FactoryBuilding7</Template> <Values> <Standard> <GUID>1337733142</GUID> <Name>Canned Food Factory 02 - Variant uses Potatoes and Zinc</Name> <IconFilename>data/ui/2kimages/main/3dicons/icon_canned_goulash.png</IconFilename> </Standard> <Building> <AssociatedRegions>Colony01</AssociatedRegions> <BuildModeRandomRotation>90</BuildModeRandomRotation> </Building> <Blocking> <HidePropsRadius>0</HidePropsRadius> <DeletePropsRadius>0</DeletePropsRadius> </Blocking> <Cost> <Costs> <Item> <Ingredient>1010017</Ingredient> <Amount>10000</Amount> </Item> <Item> <Ingredient>1010196</Ingredient> <Amount>50</Amount> </Item> <Item> <Ingredient>1010205</Ingredient> <Amount>30</Amount> </Item> <Item> <Ingredient>1010218</Ingredient> </Item> <Item> <Ingredient>1010207</Ingredient> </Item> <Item> <Ingredient>1010202</Ingredient> </Item> </Costs> </Cost> <Object> <Variations> <!-- Multiple cfg files enable scrolling through variations with Shift+V --> <Item> <Filename>data/graphics/buildings/production/workshop_colony01_01/workshop_colony01_01.cfg</Filename> </Item> </Variations> </Object> <Mesh /> <Selection> <ParticipantMessageArcheType>SA_Resident_tier02_atWork</ParticipantMessageArcheType> </Selection> <Text /> <Constructable /> <Locked /> <SoundEmitter /> <FeedbackController /> <Infolayer /> <UpgradeList /> <Factory7 /> <FactoryBase> <FactoryInputs> <Item> <Product>1010195</Product> <Amount>1</Amount> <StorageAmount>6</StorageAmount> </Item> <Item> <Product>1010229</Product> <Amount>1</Amount> <StorageAmount>3</StorageAmount> </Item> </FactoryInputs> <FactoryOutputs> <Item> <Product>1010217</Product> <Amount>1</Amount> <StorageAmount>4</StorageAmount> </Item> </FactoryOutputs> <CycleTime>45</CycleTime> </FactoryBase> <LogisticNode /> <AmbientMoodProvider /> <Maintenance> <Maintenances> <Item> <Product>1010017</Product> <Amount>40</Amount> <InactiveAmount>20</InactiveAmount> </Item> <Item> <Product>1010367</Product> <Amount>25</Amount> </Item> </Maintenances> </Maintenance> <Attackable /> <Pausable /> <IncidentInfectable /> <Industrializable> <BoostedByIndustrialization>0</BoostedByIndustrialization> </Industrializable> <Culture /> <QuestObject /> <Electrifiable /> </Values> </Asset>
Enlarge codebox

Take a look at the example again. You should pay close attention to Building, Maintenance, Object and FactoryBase Containers, you will most likely encounter them many times.
We now have a fully functional asset that we could add ingame, that Anno will interpret correctly.