1. We have added the ability to collapse/expand forum categories and widgets on forum home.
    Dismiss Notice
  2. All Civ avatars are brought back and available for selection in the Avatar Gallery! There are 945 avatars total.
    Dismiss Notice
  3. To make the site more secure, we have installed SSL certificates and enabled HTTPS for both the main site and forums.
    Dismiss Notice
  4. Civ6 is released! Order now! (Amazon US | Amazon UK | Amazon CA | Amazon DE | Amazon FR)
    Dismiss Notice
  5. Dismiss Notice
  6. Forum account upgrades are available for ad-free browsing.
    Dismiss Notice

CIv6 ModInfo Schema

Discussion in 'Civ6 - Modding Tutorials & Reference' started by PlotinusRedux, Dec 5, 2016.

  1. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    After looking at the example mods and DLC, examining Mods.sqlite, testing, and reviewing the main .exe disassembly, I think I've identified all the valid elements, etc., currently allowed in the .modinfo files.

    Much of this information is already at least partially known, though some of it has been incomplete or incorrect. Many .modinfo files currently contain incorrect usage that doesn't harm anything but also does nothing, such as using a <Component> element under Settings\Custom\Items, which ignores anything but <File> elements.

    Here is an XSD that can be used to validate .modinfo files with any XML schema validator--there's a free online one at http://www.utilities-online.info/xsdvalidation/ that's slow but works if you don't have another tool. There's a faster one at http://www.xmlforasp.net/SchemaValidator.aspx but it seemed to report incorrect line numbers for errors.

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    
      <xs:annotation>
        <xs:documentation>
          Unofficial schema for Civ 6 .modinfo files.  Created by PlotinusRedux.  Version 0.2  1/5/2016
        </xs:documentation>
      </xs:annotation>
    
      <xs:complexType name="ModRelations">
        <xs:sequence>
          <xs:element name="Mod">
            <xs:complexType>
              <xs:attribute name="id" type="xs:string" use="required"/>
              <xs:attribute name="title" type="xs:string"/>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
    
      <xs:complexType name="ItemList">
        <xs:sequence>
          <xs:element name="File" minOccurs="1" maxOccurs="unbounded">
            <xs:complexType>
              <xs:simpleContent>
                <xs:extension base="xs:string">
                  <xs:attribute name="Priority" type="xs:integer" default="0">
                    <xs:annotation>
                      <xs:documentation>Signed integer determining the load order of files within the component.  Higher numbers load earlier.</xs:documentation>
                    </xs:annotation>
                  </xs:attribute>
                </xs:extension>
              </xs:simpleContent>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
    
      <xs:complexType name="BaseComponent">
        <xs:all>
          <xs:element name="Properties" minOccurs="0">
            <xs:complexType>
              <xs:all>
                <xs:element name="RuleSet" type="xs:string" minOccurs="0"/>
                <xs:element name="LoadOrder" type="xs:integer" minOccurs="0">
                  <xs:annotation>
                    <xs:documentation>Signed integer determining component load order globally across mods.  Lower numbers load earlier.</xs:documentation>
                  </xs:annotation>
                </xs:element>             
              </xs:all>
            </xs:complexType>
          </xs:element>
          <xs:element name="Items" type="ItemList" minOccurs="1"/>
        </xs:all>
        <xs:attribute name="id" type="xs:string" default=""/>
      </xs:complexType>
    
      <xs:complexType name="ContextComponent">
        <xs:all>
          <xs:element name="Properties" minOccurs="0">
            <xs:complexType>
              <xs:all>
                <xs:element name="RuleSet" type="xs:string" minOccurs="0"/>
                <xs:element name="LoadOrder" type="xs:integer" minOccurs="0">
                  <xs:annotation>
                    <xs:documentation>Signed integer determining component load order globally across mods.  Lower numbers load earlier.</xs:documentation>
                  </xs:annotation>
                </xs:element>           
                <xs:element name="Context" type="xs:string" minOccurs="1">
                  <xs:annotation>
                    <xs:documentation>UI Context, like "InGame"</xs:documentation>
                  </xs:annotation>
                </xs:element>         
              </xs:all>
            </xs:complexType>
          </xs:element>
          <xs:element name="Items" type="ItemList" minOccurs="1"/>
        </xs:all>
        <xs:attribute name="id" type="xs:string" default=""/>
      </xs:complexType>
    
      <xs:complexType name="BaseSetting">
        <xs:all>   
          <xs:element name="Properties" minOccurs="0">
            <xs:complexType>
              <xs:all> 
                <xs:element name="LoadOrder" type="xs:integer" minOccurs="0">
                  <xs:annotation>
                    <xs:documentation>Signed integer determining component load order globally across mods.  Lower numbers load earlier.</xs:documentation>
                  </xs:annotation>
                </xs:element>             
              </xs:all>
            </xs:complexType>
          </xs:element>   
          <xs:element name="Items" type="ItemList" minOccurs="1"/>
        </xs:all>
        <xs:attribute name="id" type="xs:string" default=""/>
      </xs:complexType>
    
      <xs:complexType name="MapSetting">
        <xs:all>
          <xs:element name="Properties" minOccurs="0">
            <xs:complexType>
              <xs:all>
                <xs:element name="Group" type="xs:string" minOccurs="1"/>
                <xs:element name="Name" type="xs:string" minOccurs="1"/>
                <xs:element name="Description" type="xs:string" minOccurs="0"/>
              </xs:all>
            </xs:complexType>
          </xs:element>
          <xs:element name="Items" type="ItemList" minOccurs="1"/>
        </xs:all>
        <xs:attribute name="id" type="xs:string" default=""/>
      </xs:complexType>
    
      <xs:group name="Translations">
        <xs:all>
          <xs:element name="en_US" type="xs:string" minOccurs="0"/>
          <xs:element name="fr_FR" type="xs:string" minOccurs="0"/>
          <xs:element name="de_DE" type="xs:string" minOccurs="0"/>
          <xs:element name="it_IT" type="xs:string" minOccurs="0"/>
          <xs:element name="es_ES" type="xs:string" minOccurs="0"/>
          <xs:element name="ja_JP" type="xs:string" minOccurs="0"/>
          <xs:element name="ru_RU" type="xs:string" minOccurs="0"/>
          <xs:element name="pl_PL" type="xs:string" minOccurs="0"/>
          <xs:element name="ko_KR" type="xs:string" minOccurs="0"/>
          <xs:element name="zh_Hant_HK" type="xs:string" minOccurs="0"/>
          <xs:element name="zh_Hans_CN" type="xs:string" minOccurs="0"/>
          <xs:element name="pt_BR" type="xs:string" minOccurs="0"/>
        </xs:all>
      </xs:group>
    
      <xs:element name="Mod">
        <xs:complexType>
          <xs:all>
            <xs:element name="Properties" minOccurs="1">
              <xs:complexType>
                <xs:sequence>
                  <xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
                </xs:sequence>
                <!--
                <xs:all>
                  <xs:element name="Name" type="xs:string" minOccurs="1"/>
                  <xs:element name="Teaser" type="xs:string" minOccurs="1"/>
                  <xs:element name="Trusted" type="xs:string" minOccurs="0"/>
                  <xs:element name="ShowInBrowser" type="xs:string" minOccurs="0"/>
                  <xs:element name="DisabledAtStartup" type="xs:int" minOccurs="0"/>
                  <xs:element name="EnabledByDefault" type="xs:int" minOccurs="0"/>
                  <xs:element name="Stability" type="xs:string" minOccurs="0"/>
                  <xs:element name="Description" type="xs:string" minOccurs="0"/>
                  <xs:element name="Authors" type="xs:string" minOccurs="0"/>
                  <xs:element name="SpecialThanks" type="xs:string" minOccurs="0"/>
                </xs:all>
                 -->
              </xs:complexType>
            </xs:element>
            <xs:element name="References" type="ModRelations" minOccurs="0"/>
            <xs:element name="Dependencies" type="ModRelations" minOccurs="0"/>
            <xs:element name="Blocks" type="ModRelations" minOccurs="0"/>
            <xs:element name="Files" minOccurs="1">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="File" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
                </xs:sequence>
              </xs:complexType>
            </xs:element>
            <xs:element name="Components" minOccurs="0">
              <xs:annotation>
                <xs:documentation>Items loaded when game first starts</xs:documentation>
              </xs:annotation>
              <xs:complexType>
                <xs:choice minOccurs="1" maxOccurs="unbounded">
                  <xs:element name="UpdateDatabase" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Updates to the main game database (DebugGameplay.sqlite).  FileTypes: xml, sql</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="UpdateAudio" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Adds audio files.  FileTypes: ini, bnk, txt, xml</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="UpdateARX" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Logitech ARX for displaying game info on a mobile device.  FileTypes: html, etc.?</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="ModArt" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>.dep file that tells which new .artdef files to load.  The .artdef files must have the same name as base artdefs, and aren't included in the .modinfo file at all, just the mod's directory.  FileTypes: dep</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="UserInterface" type="ContextComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>New UI files.  For each XXX.xml, an XXX.lua is implied FileTypes: xml</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="LocalizedText" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>In-game localized text.  FileTypes: xml</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="GameplayScripts" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Scripts that run in the main Lua context at the start of the game and on reloads.  FileTypes: lua</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="ImportFiles" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Overrides of files under the main Assets folder.  FileTypes: xml, lua, *?</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="Icons" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>XML files to add icons to the game.  FileTypes: xml</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                </xs:choice>
              </xs:complexType>
            </xs:element>
            <xs:element name="Settings" minOccurs="0">
              <xs:annotation>
                <xs:documentation>Objects loaded on game set up</xs:documentation>
              </xs:annotation>
              <xs:complexType>
                <xs:choice minOccurs="1" maxOccurs="unbounded">
                  <xs:element name="Custom" type="BaseSetting" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Updates to Configuration database (DebugConfiguration.sqlite).  Some people are putting Component elements under Items here--they don't get read into the database.  FileTypes: xml, sql</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="Map" type="MapSetting" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Custom map.  FileTypes: Civ6Map</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="LocalizedText" type="BaseSetting" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Localized text for game setup screens.  FileTypes: xml</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="WorldBuilder" type="BaseSetting" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>Not sure, but presumably updates to the world builder tables.  FileTypes: xml, sql?</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="Icons" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>XML files to add icons to the game that are needed for the game setup screens.  FileTypes: xml</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                  <xs:element name="ModArt" type="BaseComponent" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                      <xs:documentation>.dep file that tells which new .artdef files to load that are needed for the game setup screens.  The .artdef files must have the same name as base artdefs, and aren't included in the .modinfo file at all, just the mod's directory.  FileTypes: dep</xs:documentation>
                    </xs:annotation>
                  </xs:element>
                </xs:choice>
              </xs:complexType>
            </xs:element>
            <xs:element name="LocalizedText" minOccurs="0">
              <xs:annotation>
                <xs:documentation>Optional translations for text in .modinfo itself (mod/Properties and mod/Settings/Map/Properties)</xs:documentation>
              </xs:annotation>
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="Text" maxOccurs="unbounded">
                    <xs:complexType>
                      <xs:group ref="Translations"/>
                      <xs:attribute name="id" type="xs:string"/>
                    </xs:complexType>
                  </xs:element>
                </xs:sequence>
              </xs:complexType>
            </xs:element>
          </xs:all>
          <xs:attribute name="id" type="xs:string" use="required"/>
          <xs:attribute name="version" type="xs:int" default="0"/>
        </xs:complexType>
      </xs:element>
    </xs:schema>
    
    All example of a well formed .modinfo file correctly using all available elements:

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <Mod id="79a96bee-c555-45b4-ae34-5221c115ef92" version = "1">
    
      <!--Localizable mod property text.  Only Name and Description seem to be shown in game-->
      <Properties>
        <!--Required and displayed in game-->
        <Name>LOC_NAME</Name>
        <Teaser>LOC_TEASER</Teaser>
    
        <!--Optional, really for Fixaris Use Only
        <Trusted>1784197304</Trusted>
        <ShowInBrowser>AlwaysHidden</ShowInBrowser>
        <DisabledAtStartup>0</DisabledAtStartup>
        <EnabledByDefault>0</EnabledByDefault>
         -->
    
        <!--Common but not used by game-->
        <Stability>LOC_STABILITY</Stability>
        <Description>LOC_DESCRIPTION</Description>
        <Authors>LOC_AUTHORS</Authors>
        <SpecialThanks>LOC_SPECIAL_THANKS</SpecialThanks>
      </Properties>
    
      <!--Referenced mods.  This mod will load after referenced mods if both are enabled-->
      <References>
        <Mod id="79a96bee-c555-45b4-ae34-5221c115efa0" title="somemod0" />
      </References>
    
      <!--Required mods-->
      <Dependencies>
        <Mod id="79a96bee-c555-45b4-ae34-5221c115efa2" title="somemod2" />
      </Dependencies>
    
      <!--Incompatible mods.-->
      <Blocks>
        <Mod id="79a96bee-c555-45b4-ae34-5221c115efa4" title="somemod4" />
      </Blocks>
    
      <!--List of all files used in the mod-->
      <Files>
        <File>SomeDatabaseUpdate1.xml</File>
        <File>SomeDatabaseUpdate2.sql</File>
        <File>SomeSound.wem</File>
        <File>SomeIcon.pgn</File>
        <File>SomeArtdef.artdef</File>
        <File>SomeUI.xml</File>
        <File>SomeUI.lua</File>
        <File>SomeText.xml</File>
        <File>SomeScript.lua</File>
        <File>SomeFileOverride1.xml</File>
        <File>SomeFileOverride2.lua</File>
        <File>SomeConfigDatabaseUpdate1.xml</File>
        <File>SomeConfigDatabaseUpdate2.sql</File>
        <File>SomeMap.Civ6Map</File>
        <File>SomeWorldbuilderFile.xml</File>
      </Files>
    
      <!--Objects loaded after the game starts-->
      <Components>
        <!--Updates to the main game database (DebugGameplay.sqlite)-->
        <UpdateDatabase id="Arbitrary_UpdateDatabase">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
            <!--No idea what LoadOrder does, it's optional-->
            <LoadOrder>100</LoadOrder>
          </Properties>
          <Items>
            <File>SomeDatabaseUpdate1.xml</File>
            <File Priority="2">SomeDatabaseUpdate2.sql</File>
          </Items>
        </UpdateDatabase>
    
        <!--Some Audio thing, Wem files under Base/Platforms/Windows/Audio maybe?-->
        <!--No idea how this would work with different platforms-->
        <UpdateAudio id="Arbitrary_UpdateAudio">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
          </Properties>
          <Items>
            <File>SomeSound.wem</File>
          </Items>
        </UpdateAudio>
    
        <!--Files related to Logitech ARX for view game info on mobile devices-->
        <UpdateARX id="Arbitrary_UpdateARX">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
          </Properties>
          <Items>
            <File>SomeIcon.pgn</File>
          </Items>
        </UpdateARX>
    
        <!--.dep file for .artdef files.  The .artdef files themselves aren't included
            in .modinfo at all, only in the mod's directory -->
        <ModArt id="Arbitrary_UpdateModArt">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
          </Properties>
          <Items>
            <File>SomeArtdef.artdef</File>
          </Items>
        </ModArt>
    
        <!--New UI files-->
        <UserInterface id="Arbitrary_UserInterface">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
            <Context>InGame</Context>
          </Properties>
          <Items>
            <File>SomeUI.xml</File>
            <!--SomeUI.lua is implied-->
          </Items>
        </UserInterface>
    
        <!--Localized Text-->
        <LocalizedText id="Arbitrary_LocalizedText">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
          </Properties>
          <Items>
            <File>SomeText.xml</File>
          </Items>
        </LocalizedText>
    
        <!--Scripts to run when the mod starts or reloads-->
        <GameplayScripts id="Arbitrary_GameplayScripts">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
          </Properties>
          <Items>
            <File>SomeScript.lua</File>
          </Items>
        </GameplayScripts>
    
        <!--Overrides of files under the main Assets folder-->
        <ImportFiles id="Arbitrary_ImportFiles">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
          </Properties>
          <Items>
            <File>SomeFileOverride1.xml</File>
            <File>SomeFileOverride2.lua</File>
          </Items>
        </ImportFiles>
    
        <!--Adds icons-->
        <Icons id="Arbitrary_Icons">
          <Properties>
            <RuleSet>RULESET_SOME_RULESET</RuleSet>
          </Properties>
          <Items>
            <File>SomeIcons.xml</File>
          </Items>
        </Icons>
     
      </Components>
    
      <!--Objects loaded on game set up-->
      <Settings>
        <!--Updates to Configuration database (DebugConfiguration.sqlite)-->
        <Custom id="Arbitrary_Custom">
          <Items>
            <!--Some peopler are putting <Component> tags here,-->
            <!--But they're not even read into the Mods.sqlite database.-->
            <File>SomeConfigDatabaseUpdate1.xml</File>
            <File>SomeConfigDatabaseUpdate2.sql</File>
          </Items>
        </Custom>
    
        <!--Custom map-->
        <Map id="Arbitrary_Custom_Map">
          <Properties>
            <Group>Some_Map_Group</Group>
            <Name>LOC_MAP_NAME1</Name>
            <Description>LOC_MAP_DESCRIPTION1</Description>
          </Properties>
          <Items>
            <File>SomeMap.Civ6Map</File>
          </Items>
        </Map>
    
        <!-- Localized Text for configuration screens -->
        <LocalizedText id="Arbitrary_LocalizedText2">
          <Items>
            <File>ConfigTextFile.xml</File>
          </Items>
        </LocalizedText>
    
        <!--No real idea-->
        <WorldBuilder id="Arbitrary_WorldBuilder">
          <Items>
            <File>SomeWorldbuilderFile.xml</File>
          </Items>
        </WorldBuilder>
    
        <!--Adds icons needed during game set up-->
        <Icons id="Arbitrary_Icons2">
          <Items>
            <File>SomeIcons.xml</File>
          </Items>
        </Icons>
    
        <!--.dep file for .artdef files needed during game setup.
            The .artdef files themselves aren't included
            in .modinfo at all, only in the mod's directory -->
        <ModArt id="Arbitrary_UpdateModArt2">
          <Items>
            <File>SomeArtdef.artdef</File>
          </Items>
        </ModArt>
      </Settings>
    
      <!--Localized text for values used in .modinfo itself-->
      <!--Seems limited to Mod/Properties and Mod/Settings/Map/Properties-->
      <LocalizedText>
        <Text id="LOC_NAME">
          <en_US>Mod Name</en_US>
        </Text>
        <Text id="LOC_STABILITY">
          <en_US>Beta, etc.</en_US>
        </Text>
        <Text id="LOC_TEASER">
          <en_US>Description Shown In Game</en_US>
        </Text>
        <Text id="LOC_DESCRIPTION">
          <en_US>Full Description (Not Shown Anywhere)</en_US>
        </Text>
        <Text id="LOC_AUTHORS">
          <en_US>Authors</en_US>
        </Text>
        <Text id="LOC_SPECIAL_THANKS">
          <en_US>All the little people</en_US>
        </Text>
        <Text id="LOC_MAP_NAME1">
          <en_US>Custom Map Name</en_US>
        </Text>
        <Text id="LOC_MAP_DESCRIPTION1">
          <en_US>Custom Map Description</en_US>
        </Text>
      </LocalizedText>
    </Mod>
    And finally some useful SQL statements to run against the Mods.sqlite database to verify your mod's values really are getting into the system the way you want:

    Code:
    SELECT * FROM Mods WHERE ModId = "79a96bee-c555-45b4-ae34-5221c115ef92";
    
    SELECT Name, Value, Locale, Text
    FROM ModProperties mp
        INNER JOIN Mods m on mp.ModRowId = m.ModRowId
        LEFT OUTER JOIN LocalizedText l ON l.Tag = mp.Value
    WHERE m.ModId = "79a96bee-c555-45b4-ae34-5221c115ef92"
    ORDER BY Name;
    
    SELECT ComponentType, ComponentId, Path, Priority
    FROM ModFiles f
        INNER JOIN ComponentFiles cf ON f.FileRowId = cf.FileRowId
        INNER JOIN Components c ON cf.ComponentRowId = c.ComponentRowId
        INNER JOIN Mods m on c.ModRowId = m.ModRowId
    WHERE m.ModId = "79a96bee-c555-45b4-ae34-5221c115ef92"
    ORDER BY ComponentType, ComponentId, Path;
    
    SELECT ComponentType, ComponentId, Name, Value
    FROM ComponentProperties cp
        INNER JOIN Components c ON cp.ComponentRowId = c.ComponentRowId
        INNER JOIN Mods m on c.ModRowId = m.ModRowId
    WHERE m.ModId = "79a96bee-c555-45b4-ae34-5221c115ef92"
    ORDER BY ComponentType, ComponentId, Name;
    
    SELECT SettingType, SettingId, Path, Priority
    FROM ModFiles f
        INNER JOIN SettingFiles sf ON f.FileRowId = sf.FileRowId
        INNER JOIN Settings s ON sf.SettingRowId = s.SettingRowId
        INNER JOIN Mods m on s.ModRowId = m.ModRowId
    WHERE m.ModId = "79a96bee-c555-45b4-ae34-5221c115ef92"
    ORDER BY SettingType, SettingId, Path;
    
    SELECT SettingType, SettingId, Name, Value, Locale, Text
    FROM SettingProperties sp
        INNER JOIN Settings s ON sp.SettingRowId = s.SettingRowId
        INNER JOIN Mods m on s.ModRowId = m.ModRowId
        LEFT OUTER JOIN LocalizedText l ON l.Tag = sp.Value
    WHERE m.ModId = "79a96bee-c555-45b4-ae34-5221c115ef92"
    ORDER BY SettingType, SettingId, Name;
    
    SELECT OtherModId, OtherModTitle, Relationship
    FROM ModRelationships r
        INNER JOIN Mods m on r.ModRowId = m.ModRowId
    WHERE m.ModId = "79a96bee-c555-45b4-ae34-5221c115ef92"
    ORDER BY OtherModId, OtherModTitle;
    File versions can be downloaded from:

    http://qskoz.com/Civ6/Civ6ModInfoSchema.xsd
    http://qskoz.com/Civ6/Test.modinfo
    http://qskoz.com/Civ6/ModInfo.sql

    [Edit: Changed <ModArt> filetype to .dep]
    [Edit: Update ARX comments to indicate it relates to the Logitech Arx app for showing game information on a phone]
    [Edit: Updated for Winter patch:
    *Added new <Icons> element;
    *Updated description of <ModArt>
    *Added <LoadOrder> property to <UpdateDatabase>
    *Added <Icons> and <ModArt> to Settings, as they can appear under <Components> or <Settings>]
    [Edit 1/5/17: Added <LoadOrder> to all components and updated its annotation.]
    [Edit 1/24/17: If the optional "id" attribute is used for a component, it must start with a letter and contain no spaces, as it is sent directly to sqlite to create a save point.]
     
    Last edited: Jan 24, 2017
    Sesostris, astog, Gedemon and 3 others like this.
  2. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    Common .modinfo mistakes I'm seeing:

    • The id attribute of the root Mod element can technically be any unique string, but following the example of the Firaxis mods should be a GUID without the enclosing brackets. https://www.guidgenerator.com/online-guid-generator.aspx is a quick way to get a GUID in the correct format.
    • The version attribute of the root Mod element is an integer. The game reads <Mod ... version="1.5"> as version 1. My suggestion would be to treat it as MajorVersion * 100 + MinorVersion. Of course, the game doesn't currently do anything with it other than store it in Mods.sqlite, it doesn't even display it anywhere, so it doesn't really matter at this point--mods are either completely reloaded every time the game starts, or it's using the file timestamps in the database to decide when to reload them, I'm not sure which.
    • Only <File> elements under <Items> do anything for any component or setting element. Some people have been doing something like this, which does nothing as far as the game is concerned, and there is no reason to have a <Settings> element at all if this is all it's being used for:
      Code:
          <Settings>
              <Custom id="SomeID">
                  <Items>
                      <!--This does nothing-->
                      <Component>SomeComponentID</Component>
                  </Items>
              </Custom>
          </Settings>
    • <File> elements under <Items> can have a Priority attribute. No other attributes do anything. <File> elements under <Files> don't read any attributes. <File import="1">, for instance, doesn't add anything to <File> in either case.
    • <Mod> elements under <References>, <Dependencies>, and <Blocks> only have an "id" and "title" attribute. Any other attribute (like "minVersion") is ignored.
    • <Properties> under Components only use a <RuleSet> element, except for <UserInterface>, which also has a <Context> element. Settings elements use no <Properties> element, except for <Map>, which uses <Group>, <Name>, and <Description>. Everything else is ignored by the game.
    • Under the root <Mod> element, the only elements under <Properties> used by the game are <Name>, <Teaser>, and the DLC properties <Trusted>, <ShowInBrowser>, <DisabledAtStartup>, and <EnabledByDefault>. Other properties get read into Mods.sqlite but aren't ever displayed in the game, so are really just informative for human viewers of the .modinfo file. So if you're putting in the same text for <Description> and <Teaser>, you can just leave <Description> out. Also, there's no reason to localize anything but <Name> and <Teaser>.
     
    Last edited: Dec 6, 2016
  3. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,640
    Location:
    France
    Thank you :)

    <Description> and <Authors> are defined in the Firaxis scenarios, they may be used in the future.

    From my test <File>SomeUI.lua</File> is not required under <UserInterface>, the XML is enough (but the XML must define a context for the Lua file IIRC)
     
  4. Deliverator

    Deliverator Graphical Hackificator

    Joined:
    Feb 12, 2008
    Messages:
    3,990
    Location:
    London, UK
    I think this should be moved to the Modding Tutorials and Reference subforum.
     
  5. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    @Gedemon, yeah, I just noticed Base\Assets\UI\Text\en_US\UI_Mods_Text.xml, which does have localized text for things like "Author(s):" and "Special Thanks:", as well as "BROWSE WORKSHOP", though nothing references them yet, so maybe they will use them once they get the Workshop stuff set up.

    @Deliverator, anyone feel free to move it, or edit and add the information to the existing .modinfo post, etc.
     
  6. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,640
    Location:
    France
    Moderator Action: Moved to Tutorial & Reference, I've closed the outdated thread
     
  7. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,640
    Location:
    France
    Ok, now we have two DLC that add arts, time to examine their structure (and yes, seems some code was missing to allow it)
     
  8. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
  9. TimurB

    TimurB Chieftain

    Joined:
    Apr 13, 2016
    Messages:
    76
    Gender:
    Male
    Location:
    Atlantis
    How to make a different version of a mod?
    I was just changing the number in the version field
    Before:
    Code:
    <Mod id="79a96bee-c555-45b4-ae34-5221c115ef92" version = "6">
    After:
    Code:
    <Mod id="79a96bee-c555-45b4-ae34-5221c115ef92" version = "16">
    But apparently i cant reload the saved game. It said, not every mod installed (i forget the exact words).
    It ll work if i change the version to 7.
     
    Last edited: Dec 26, 2016
  10. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    @TimurB that's odd, my guess would be it won't load older versions of the mod with the saved game, and even though the field is saved as an int in the DB, it's doing a string comparison to check if the version is higher, since in a string comparison, "16" < "6". If I'm right, 59 shouldn't load and 60 should and you're stuck using versions that start with the digit "6" or higher now...

    A good reason to go with Major Version * 100 + Minor version, I guess, at least until you get to major version 10.... Left padding with 0's wouldn't help, because they'd get thrown out when it's converted to an int for the DB.
     
  11. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    So does anyone know of a reason for the <Files> element off the root to exist? Would it ever contain a file that hadn't already been listed in the <Items> section of some element under <Components> or <Settings>?

    I'm working on my auto-merge and I was working on linking up the <Files> element with the various <Items> elements when I realized I can't think of a single reason to even parse <Files> since I've already built the list of files from the various <Items> and even included the "implied" files that wouldn't be under the <Files> element--like *.artdef, the *.lua files that go with UI *.xml files, etc.

    I know in Civ 5 the <Files> element included tags like the MD5 hash and whether to import the file, but you can see from the ModFiles table all it's reading is the filename and path. I could see it having a use if it included the files like *.artdef that don't show up under any <Items> elements, but in Firaxis's own DLC they didn't included those. It definitely has to be there or the game doesn't load them into ModFiles, but isn't it completely redundant at this point, or am I missing something?
     
  12. anansethespider

    anansethespider Chieftain

    Joined:
    Oct 27, 2016
    Messages:
    289
    Gender:
    Male
    You seem very knowledgable about matters, so maybe you can help me with a vexing problem in my mod.

    I've got a large mod package including overhauls to many game systems, including the Tech and Civics trees. The Tech and Civics tree xml files are formulated in the exact same way, and both are well-formed (passes all checks with XML editor, and has worked over hundreds of games), but only the Civics tree consistently has a UI display error where some of the civics overlap each other some of the time.

    On some loads everything is hunky dory and all the civics display perfectly. On other loads, the tech prereqs function normally, but the UI "erases" some of them by overlapping two different into columns together.

    Does this have something to do with the different natures of the Tech and Civics tree? You mentioned that it's not handled as a traditional XML file, but a UI one? I'm at my wit's end trying to figure this out and would really appreciate any assistance :)
     
  13. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    @anansethespider , if you were talking to me, I wouldn't say I'm "very knowledgeable", I only started Civ modding with Civ 6 and I've never used Lua before now. Really my previous experience is with hacking games that weren't meant to be modded rather than modding games that were. Mainly I read what the more experienced people around here post avidly and do a lot of banging my head into walls until something breaks.

    Short Answer: From looking at the lua code, within each era, only include civics on the same UITreeRow if they are related to each other in a prerequisite chain. I.e., if C1, C2, and C3 are civics of the same era on the same UITreeRow, it has to be the case that you can't get C2 without having C1, and you can't get C3 without having C2. They don't have to be immediate prerequisites of each other, just somewhere in the same chain.

    Long Answer: I haven't actually messed with the civics or tech trees yet myself, but the relevant code for formatting the civics tree is in base/assets/ui/screens/CivicsTree.lua[252] in the AllocateUI() routine, and it's got a clear bug in it. Starting at line 307 of CivicsTree.lua instead of:

    Code:
                -- No prereqs? Just put at start, otherwise push forward past them all.
                if item.Prereqs ~= nil then
                    for _,prereq in ipairs(item.Prereqs) do                            -- For every prereq                
                        local isPrereqMatched :boolean = false;                
                        for x=pos,maxColumns,1 do                                    -- For every column (from last highest found start position)
                            for y=ROW_MIN, ROW_MAX,1 do                                -- For every row in the column
                                if grid.rows[y].columns[x] ~= nil then                -- Is a prereq in that position of the grid?
                                    if prereq == grid.rows[y].columns[x] then        -- And is it a prereq for this item?
                                        pos = x + 1;                                -- If so, this item can only exist at least 1 column further over from the prereq
                                        isPrereqMatched = true;
                                        break;
                                    end
                                end
                            end
                            if isPrereqMatched then                         
                                -- Ensuring this node wasn't just placed on top of another:
                                while( grid.rows[item.UITreeRow].columns[pos] ~= nil ) do
                                    pos = pos + 1;
                                end
                                break;
                            end
                        end
                    end
                end
    it should be:

    Code:
                -- No prereqs? Just put at start, otherwise push forward past them all.
                if item.Prereqs ~= nil then
                    for _,prereq in ipairs(item.Prereqs) do                            -- For every prereq                
                        local isPrereqMatched :boolean = false;                
                        for x=pos,maxColumns,1 do                                    -- For every column (from last highest found start position)
                            for y=ROW_MIN, ROW_MAX,1 do                                -- For every row in the column
                                if grid.rows[y].columns[x] ~= nil then                -- Is a prereq in that position of the grid?
                                    if prereq == grid.rows[y].columns[x] then        -- And is it a prereq for this item?
                                        pos = x + 1;                                -- If so, this item can only exist at least 1 column further over from the prereq
                                        isPrereqMatched = true;
                                        break;
                                    end
                                end
                            end
                            if isPrereqMatched then                         
                                break;
                            end
                        end
                    end
                end
                -- Ensuring this node wasn't just placed on top of another:
                while( grid.rows[item.UITreeRow].columns[pos] ~= nil ) do
                    pos = pos + 1;
                end
    
    You can try changing that in CivicsTree.lua under base and if it works, either adjust your UITreeRow values to work around the bug or include the fixed version of CivicsTree.lua in your mod in the <ImportFiles> section of your .modinfo.

    The bug would occur if you had 2 civics C1 and C2 of the same era with the same UITreeRow value where either (1) neither C1 nor C2 had a prerequisite from within their era, or (2) C1 didn't have a prerequisite from within it's era and C1 wasn't in a prerequisite chain leading up to C2.

    (2) is likely the case here, as (1) would always cause the issue, while (2) would appear randomly based on the undeterministic order of for...in on non-sequence tables in Lua.

    So the work-around would be to insure that within each era you only include civics on the same UITreeRow that belong to the same prerequisite chain. Of course that limits you to a total of 7 independent chains since there are only 7 rows.

    On the other hand, using the code fix rather than the work-around will have an undesirable side effect--civics will never overlap, but in both cases above C1 and C2 will appear before or after each other randomly.

    A more involved code fix could get around that by running the while loop twice, first adding only items for which isPrereqMatched was false after the for loops (meaning it had no same-era prereq), then adding only the remaining items. That would insure C1 always appeared before C2 in case (2). However, if there was then a C3 on the same row in the same era which wasn't related to C2 by a prerequisite chain but did have a prerequisite from within the same, C2 and C3 would still appear in random order.

    All in all, just using the work-around is probably the best way to go--within each era, only include civics on the same row if they are part of the same prerequisite chain. I haven't looked at the tech tree code but I'm sure the same rule applies to it.
     
    Last edited: Dec 31, 2016
  14. anansethespider

    anansethespider Chieftain

    Joined:
    Oct 27, 2016
    Messages:
    289
    Gender:
    Male
    I believe I've followed all of those constraints, but no luck. I'd love for you to take a look at the file and let me know what you think!

    https://forums.civfanatics.com/resources/ananses-bfg-modpack.25825/


    Here's the file. All of the Civics changes are contained in LinearCivics.xml - at the very bottom of the file, there are a few era changes. And those should be the only things that effect the Civics Tree.

    The error seems to be randomly placed throughout the Civics tree, but most often in the Classical Era. Sometimes it does not occur at all. And even when it does occur, the actual Civics progression still works.



    EDIT, upon re-reading what you wrote, I think that my error is the first one - having C1 and C2 both in the same UITreeRow, neither of which have a pre-req within the era. However, the error is very inconsistent, so I don't know...

    Do you believe that your .lua fix would address this?
     
    Last edited: Dec 31, 2016
  15. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    @anansethespider no wonder, their sort routine that is supposed to make sure civics come after their prerequisites in eraGrids[].sortRow.columns[] is fubar'ed, you can't use swap there. I don't really know how it isn't broken in the base game--probably because they don't have more than 3 columns per era, so that crazy swap thing somehow works--but just doing a print shows it sorts your civics in the wrong order.

    Here's a fix for the bug I verified fixes the problem using your mod. In Base/Assets/UI/Screens/CivicsTree.lua beginning at line 278 replace:
    Code:
        -- Manually sort based on prereqs, 2(N log N)
        for eraType,grid in pairs(eraGrids) do      
            local numEraItems:number = table.count(grid.sortRow.columns);
            if numEraItems > 1 then          
                for pass=1,2,1 do                    -- Make 2 passes so the first swapped item is checked.
                    for a=1,numEraItems do
                        for b=a,numEraItems do
                            if a ~= b then
                                for _,prereq in ipairs(m_kItemDefaults[grid.sortRow.columns[a] ].Prereqs) do
                                    if prereq == grid.sortRow.columns[b] then
                                        grid.sortRow.columns[a], grid.sortRow.columns[b] = grid.sortRow.columns[b], grid.sortRow.columns[a];    -- swap LUA style
                                    end
                                end                  
                            end
                        end
                    end
                end
            end
        end
    with:
    Code:
        -- Manually sort based on prereqs
        for eraType,grid in pairs(eraGrids) do      
            local numEraItems:number = table.count(grid.sortRow.columns);
            if numEraItems > 1 then
                local a : number = 1;
                while ( a < numEraItems ) do
                    local found = false;
                    for b = numEraItems, a + 1, -1 do
                        for _,prereq in ipairs(m_kItemDefaults[grid.sortRow.columns[a]].Prereqs) do
                            if prereq == grid.sortRow.columns[b] then
                                found = true;
                                table.insert(grid.sortRow.columns, b, table.remove(grid.sortRow.columns, a));
                                break;
                            end
                        end
                        if found then
                            break;
                        end;
                    end;
    
                    if ( not found ) then
                        a = a + 1;
                    end
                end
            end
        end
    In the tech tree view they didn't even try to sort by prereqs, they just set the column directly based on the tech's cost, so just make sure you don't have any techs with the same cost and UITreeRow. I didn't see any problems viewing your tech tree, though.

    Someone should probably get the above to Firaxis somehow so they can fix it in the next patch, that's going to bite every mod with 4+ civics columns in a single era even if it somehow works for 3-.
     
    Horem likes this.
  16. anansethespider

    anansethespider Chieftain

    Joined:
    Oct 27, 2016
    Messages:
    289
    Gender:
    Male
    you sir are a gentleman and a scholar. Best thing to happen to me so far this year! TYVM


    Edit, I'm thinking I should add this fix to my mod, but I'm not sure how to update lua from a modinfo. Would this be a simple addition?
     
    Last edited: Jan 1, 2017
  17. Aidence

    Aidence The Archduke

    Joined:
    Nov 23, 2013
    Messages:
    224
    Gender:
    Male
    I am working on adding a civilization and am following the guidelines set by Firaxis with Poland yet I have a question: When I am providing the directory for my files, do I put that it is in the mods file or not? If not, then where do I put it? Can someone help me with this? Thanks.
     
  18. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    In .modinfo, you put in the path relative to your mod's root. So if you have:

    Code:
    /Documents
        /My Games
            /Sid Meier's Civilization VI
                /Mods
                    /YourMod
                        YourMod.modinfo
                        YourModFile1.xml
                        /Data
                            YourModFile2.xml
    In YourMod.modinfo, you would refer to YourModFile1.xml as just "YourModFile1.xml", and to YourModFile2.xml as "Data/YourModFile2.xml".

    Is that what you were asking?
     
  19. Aidence

    Aidence The Archduke

    Joined:
    Nov 23, 2013
    Messages:
    224
    Gender:
    Male
    I am a bit confused. I am referring to this:
    Code:
    <File>Data/Poland_Jadwiga_GameplayData.xml</File>
    The directory you provided is correct so would I put
    Code:
    <File>Mods/Data/Poland_Jadwiga_GameplayData.xml</File>
    or would it just be the same as Firaxis put?
     
  20. PlotinusRedux

    PlotinusRedux Chieftain

    Joined:
    Jul 11, 2013
    Messages:
    196
    Whatever directory your .modinfo file is in is the mod's base directory, so you just provide whatever path is needed to get from that directory to the file you're referencing. If the file is in the same directory as the .modinfo file, you just use the filename itself. If the file is in a subdirectory below that file, you include that subdirectory with the filename.
     

Share This Page

Ebates: Get Paid to Shop