Author Topic: Modding collections (lists, maps).  (Read 3289 times)

Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Modding collections (lists, maps).
« on: March 26, 2023, 11:18:57 pm »
I would like to create two mods that add ammunition to a weapon in a vanilla game, along with some other items specific to each mod.

A question is, how could this be accomplished with current configuration interpretation semantics.

Currently, there exists a definition

  - type: STR_SMALL_LAUNCHER
    compatibleAmmo:
      - STR_STUN_BOMB
      - STR_ELERIUM_BOMB
      - STR_EMP_BOMB

which corresponds to configuration

{ { type : "STR_SMALL_LAUNCHER" ,
      compatibleAmmo: [ "STR_STUN_BOMB" , "STR_ELERIUM_BOMB" , "STR_EMP_BOMB" ]
   },
   # ...
}


I would like to provide additional definitions, along the lines of

  - type: STR_SMALL_LAUNCHER
    compatibleAmmo:
      - insert: STR_MEGA_BOMB
      - insert: STR_GIGA_BOMB

in one mod and also

  - type: STR_SMALL_LAUNCHER
    compatibleAmmo:
      - insert: STR_GIANT_BOMB
      - insert: STR_ULTRA_BOMB

in another mod in order to yield the following configuration:

{ { type : "STR_SMALL_LAUNCHER" ,
      compatibleAmmo: [ "STR_STUN_BOMB" , "STR_ELERIUM_BOMB" , "STR_EMP_BOMB",
      "STR_MEGA_BOMB", "STR_GIGA_BOMB", "STR_GIANT_BOMB", "STR_ULTRA_BOMB" ] },
   # ...
}


What is the best way to accomplish that?


Online Yankes

  • Commander
  • *****
  • Posts: 3209
    • View Profile
Re: Modding collections (lists, maps).
« Reply #1 on: March 27, 2023, 01:28:18 am »
I assume you target OXCE, then you can:


For some properties yes, add `!info` after node name to get feedback in logs for game what options are avaiable. If none is show its mean this is "dumb" node and do not support special operations.

quoting: https://www.ufopaedia.org/index.php/Ruleset_Reference_Nightly_(OpenXcom)
Code: [Select]
#base mod:
 items:
   - type: STR_WEAPON
     compatibleAmmo: !info     #this tag does not change anything, but when used it will show (in the log file) if the list supports this functionality or not
       - STR_AMMO_1
       - STR_AMMO_2
 
 #sub-mod
 items:
   - type: STR_WEAPON
     compatibleAmmo: !add      #now `STR_WEAPON` will have ammo list equal to `[STR_AMMO_1, STR_AMMO_2, STR_AMMO_3]`
       - STR_AMMO_3
 
 #another sub-mod
 items:
   - type: STR_WEAPON
     compatibleAmmo: !remove   #now `STR_WEAPON` will have ammo list equal to `[STR_AMMO_1, STR_AMMO_3]`
       - STR_AMMO_2

another thing is do not use `type:` when you override some other mod items, use `override:` that check if item exist and do not interpret your typo as new item.
you can use too `update:` that allow missing item with given name, and then it skip given additions.

This `override:` and `update:` recent addition to OXCE, best if you add in mod metadata what version of OXCE you created mod with.

Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Re: Modding collections (lists, maps).
« Reply #2 on: March 27, 2023, 02:20:39 am »
@Yankes, Thank you.  I'll experiment in the next few days with these tags.

So far, this seems like a good approach with the config design: the tags are a nice side channel to the main data stream.  I have been trying to figure out the approaches based on patching, and some YAML-specific patching libraries, but the inherent issue seems to be a problem of versioning.

More discussion is available at the https://openxcom.org/forum/index.php/topic,11192.msg154202.html#msg154202.

Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Re: Modding collections (lists, maps).
« Reply #3 on: March 27, 2023, 02:46:31 am »

another thing is do not use `type:` when you override some other mod items, use `override:` that check if item exist and do not interpret your typo as new item.
you can use too `update:` that allow missing item with given name, and then it skip given additions.

This `override:` and `update:` recent addition to OXCE, best if you add in mod metadata what version of OXCE you created mod with.

Concerning the versioning, what metadata item should be used?  Would the following be appropriate?
requiredExtendedVersion: "7.8"

I wonder, how should I approach the following scenario.  Two sub-mods add weapons that need to share sub-munitions that are common to all three mods.
Code: [Select]
#base mod:
 items:
   - type: STR_MINI_CANNON
     compatibleAmmo:
       - STR_MINI_BOMB
 
 #sub-mod-1
 items:
   - override: STR_MINI_CANNON
     compatibleAmmo: !add
       - STR_MAXI_BOMB
   - type: STR_MINI_ASSAULT_CANNON
     compatibleAmmo:
       - STR_MINI_BOMB
       - STR_MAXI_BOMB
 
 # sub-mod-2
 items:
   - type: STR_MAXI_CANNON
# how to approach these definitions?
# I would like to use STR_MINI_BOMB and STR_MAXI_BOMB here if sub-mod-1 is loaded
# If sub-mod-1 is *not* loaded, I would like to use STR_MINI_BOMB here
# Would it be more preferable to simply require sub-mod-1 to be always loade
# by including it as a dependency?


Online Yankes

  • Commander
  • *****
  • Posts: 3209
    • View Profile
Re: Modding collections (lists, maps).
« Reply #4 on: March 27, 2023, 04:08:15 am »
It need `7.8.14` as it was added after `7.8.0`was published.

If I understand correctly, you want support 3 cases:
Code: [Select]
#only one mod A
items:
   - type: STR_A
     compatibleAmmo:
       - STR_A_AMMO

Code: [Select]
#only one mod B
items:
   - type: STR_B
     compatibleAmmo:
       - STR_B_AMMO
and
Code: [Select]
#both A and B
items:
   - type: STR_A
     compatibleAmmo:
       - STR_A_AMMO
       - STR_B_AMMO
   - type: STR_B
     compatibleAmmo:
       - STR_A_AMMO
       - STR_B_AMMO

Then no, this is not possible, any options avaialbe can only check if given item exist before game try update it.
If both mods need be independent of each other then you need third mod that link both and it set up all cross references.


Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Re: Modding collections (lists, maps).
« Reply #5 on: March 27, 2023, 05:43:48 am »
It need `7.8.14` as it was added after `7.8.0`was published.

If I understand correctly, you want support 3 cases:
Code: [Select]
#only one mod A
items:
   - type: STR_A
     compatibleAmmo:
       - STR_A_AMMO

Code: [Select]
#only one mod B
items:
   - type: STR_B
     compatibleAmmo:
       - STR_B_AMMO
and
Code: [Select]
#both A and B
items:
   - type: STR_A
     compatibleAmmo:
       - STR_A_AMMO
       - STR_B_AMMO
   - type: STR_B
     compatibleAmmo:
       - STR_A_AMMO
       - STR_B_AMMO

Then no, this is not possible, any options avaialbe can only check if given item exist before game try update it.
If both mods need be independent of each other then you need third mod that link both and it set up all cross references.

Thank you for sharing this.

From the modder perspective, the addition of an extra mod is not an unacceptable solution.  I wonder, if there exists a way to specify a dependency on other non-master mods, and in particular the dependency on versions.  Ideally, there should be a dependency clause along the lines of ">=0.2".  Pretty much like rpm / deb packages.

Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Re: Modding collections (lists, maps).
« Reply #6 on: March 27, 2023, 05:45:30 am »
I assume you target OXCE, then you can:


For some properties yes, add `!info` after node name to get feedback in logs for game what options are avaiable. If none is show its mean this is "dumb" node and do not support special operations.

quoting: https://www.ufopaedia.org/index.php/Ruleset_Reference_Nightly_(OpenXcom)
Code: [Select]
#base mod:
 items:
   - type: STR_WEAPON
     compatibleAmmo: !info     #this tag does not change anything, but when used it will show (in the log file) if the list supports this functionality or not
       - STR_AMMO_1
       - STR_AMMO_2
 
 #sub-mod
 items:
   - type: STR_WEAPON
     compatibleAmmo: !add      #now `STR_WEAPON` will have ammo list equal to `[STR_AMMO_1, STR_AMMO_2, STR_AMMO_3]`
       - STR_AMMO_3
 
 #another sub-mod
 items:
   - type: STR_WEAPON
     compatibleAmmo: !remove   #now `STR_WEAPON` will have ammo list equal to `[STR_AMMO_1, STR_AMMO_3]`
       - STR_AMMO_2

another thing is do not use `type:` when you override some other mod items, use `override:` that check if item exist and do not interpret your typo as new item.
you can use too `update:` that allow missing item with given name, and then it skip given additions.

This `override:` and `update:` recent addition to OXCE, best if you add in mod metadata what version of OXCE you created mod with.

I noticed that the wiki mentions an ability to inherit definitions.  I wonder, how does listOrder get generated when inheritance occurs?  Also, is it possible to somehow automate the generation of this value in mods?  It's not a huge issue, but could be a nuisance maintenance-wise.

Online Yankes

  • Commander
  • *****
  • Posts: 3209
    • View Profile
Re: Modding collections (lists, maps).
« Reply #7 on: March 27, 2023, 04:26:19 pm »
Thank you for sharing this.

From the modder perspective, the addition of an extra mod is not an unacceptable solution.  I wonder, if there exists a way to specify a dependency on other non-master mods, and in particular the dependency on versions.  Ideally, there should be a dependency clause along the lines of ">=0.2".  Pretty much like rpm / deb packages.

`overrdie:` in some way could work in that aspect, as you could "probe" if other mod was already loaded.
In theory we could add mechanism like this, it will be complex as will need handle lot of corner cases. Only problem is that only couple of small mods (that I aware of) could benefit from it, for now grain/cost ratio is too small to consider adding feature like this.

Beside `requiredMasterModVersion` is not yet used much at this time, adding more features like this would be waste of time if nobody will use it.

I noticed that the wiki mentions an ability to inherit definitions.  I wonder, how does listOrder get generated when inheritance occurs?  Also, is it possible to somehow automate the generation of this value in mods?  It's not a huge issue, but could be a nuisance maintenance-wise.

This is not "inherit" its more like "sharing" because it work only in one file and work more like copy-paste on yaml level that object in memory.
And `listOrder` in OXCE is only updated when new rule is created, aka `new:` or old `type:` if given name did not exists before, in OXC or older OXCE it was incremented each time you use `type:` even if do not use it.

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 8628
    • View Profile
Re: Modding collections (lists, maps).
« Reply #8 on: March 28, 2023, 09:50:28 am »
I noticed that the wiki mentions an ability to inherit definitions.

It's not inheritance, it's an automated copy-paste.

I will update the ruleset reference this weekend to be more precise.

Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Re: Modding collections (lists, maps).
« Reply #9 on: March 28, 2023, 12:24:13 pm »
It's not inheritance, it's an automated copy-paste.

I will update the ruleset reference this weekend to be more precise.

I would appreciate that.  Thank you.

I would like to inquire, if it is possible to remove nodes in the definitions.  Say,

Code: [Select]
- type: STR_MEGA_BOMB
  refNode: *STR_STUN_BOMB
  # now, I need to remove recoveryPoints from the STR_STUN_BOMB definition,
  # so that it doesn't appear anywhere in STR_MEGA_BOMB
  # the following seems hackish
  recoveryPoints: 0
  # could I instead use something along the lines of
  # recoveryPoints !remove
  # that is not a to-spec YAML, though ...


Online Yankes

  • Commander
  • *****
  • Posts: 3209
    • View Profile
Re: Modding collections (lists, maps).
« Reply #10 on: March 28, 2023, 12:34:27 pm »
You need set new value, there no other way and probably will not be as it would require rewrite all rule loading to handle every property.

Best way to avoid it is simply have in `STR_STUN_BOMB` only things that do not change, and you do not need overwrite after.

Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Re: Modding collections (lists, maps).
« Reply #11 on: March 28, 2023, 09:35:36 pm »
You need set new value, there no other way and probably will not be as it would require rewrite all rule loading to handle every property.

Best way to avoid it is simply have in `STR_STUN_BOMB` only things that do not change, and you do not need overwrite after.

Well, what I would like to accomplish is to inherit from an existing definition, which has an extraneous property.  For example, if I inherit from a STR_LARGE_ROCKET, there's a parameter costBuy.  This parameter does not make sense in an item that is produced and is never being bought.  For instance, in a mod I may desire to make a gas rocket.  The rocket would largely share the traits of a large rocket, but woudld have a different damage mode, different graphics, and could only be manufactured at a workshop.  When a master mod maker encounters this issue, he has an option of simply exhaustively specifying all parameters for a new type.  As a sub-mod maker, I would like to avoid doing so, since I conceptually want to only alter an existing definition.

Now, I understand that items come with a pre-defined set of parameters.  How does costBuy get semantically handled?  I asssume, it has a default value which is interpreted appropriately.  An issue is what is a canonical default value for each type of argument node.  From a general scripting standpoint, a good approach is to assign a form of null value to a field to indicate that it needs to contain either a default or other empty placeholder.

Please note that assigning a null value is conceptually different than removing a node, but for all practical purposes it yields the same semantic effect from the perspective of modding.

What would happen if I assign a null value to costBuy?  to recoveryPoints?
« Last Edit: March 28, 2023, 09:43:25 pm by zee_ra »

Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Re: Modding collections (lists, maps).
« Reply #12 on: March 28, 2023, 09:48:27 pm »
It's not inheritance, it's an automated copy-paste.

I will update the ruleset reference this weekend to be more precise.

What do you think about making a page on wiki to go over the common mod making problems and their solutions?  I am currently making a small mod to XCF that adjusts some weapons and armors, and vehicles.  Ideally, it should make these adjustments tunable as game options.  No scripting would is being involved.  I think, it covers almost all of the basic extension questions : altering graphics, altering config, and not making the project into an unmaintainable mess.  That is, it is a case of a small mod that alters some parameters, and does not need subsequent maintenance as the master evolves.

I could contribute my perspective as a mod maker.  Someone should be able to provide narrative responses to sections I'll put forth.

Online Yankes

  • Commander
  • *****
  • Posts: 3209
    • View Profile
Re: Modding collections (lists, maps).
« Reply #13 on: March 28, 2023, 10:28:44 pm »
Well, what I would like to accomplish is to inherit from an existing definition, which has an extraneous property.  For example, if I inherit from a STR_LARGE_ROCKET, there's a parameter costBuy.  This parameter does not make sense in an item that is produced and is never being bought.  For instance, in a mod I may desire to make a gas rocket.  The rocket would largely share the traits of a large rocket, but woudld have a different damage mode, different graphics, and could only be manufactured at a workshop.  When a master mod maker encounters this issue, he has an option of simply exhaustively specifying all parameters for a new type.  As a sub-mod maker, I would like to avoid doing so, since I conceptually want to only alter an existing definition.

Copy-paste all properties of base mod file to your mod and alter it in your heart content. This is only solution that will last long time. If you did any "inherit" of object do you not control in any way, it will break if base mod change it in incompatible way.

Now, I understand that items come with a pre-defined set of parameters.  How does costBuy get semantically handled?  I asssume, it has a default value which is interpreted appropriately.  An issue is what is a canonical default value for each type of argument node.  From a general scripting standpoint, a good approach is to assign a form of null value to a field to indicate that it needs to contain either a default or other empty placeholder.

You could suggest it 10 years ago when SupSuper start writing OXC, now most how its is handled is set in stone and I or any other developer do not plan to alter it in any major way as it would break any most of mods in wild.

Sematic is simple, you keep current value (by not mentioning property in any way) or setting it by new value. For default values, look in ufopedia page.


Please note that assigning a null value is conceptually different than removing a node, but for all practical purposes it yields the same semantic effect from the perspective of modding.

What would happen if I assign a null value to costBuy?  to recoveryPoints?
probably it will get ignored by yaml-cpp as it can't convert text `null` to number.

Offline zee_ra

  • Colonel
  • ****
  • Posts: 200
    • View Profile
Re: Modding collections (lists, maps).
« Reply #14 on: March 28, 2023, 11:01:25 pm »
Copy-paste all properties of base mod file to your mod and alter it in your heart content. This is only solution that will last long time. If you did any "inherit" of object do you not control in any way, it will break if base mod change it in incompatible way.

The problem is that the inheritance of properties would be lost in this case.

You could suggest it 10 years ago when SupSuper start writing OXC, now most how its is handled is set in stone and I or any other developer do not plan to alter it in any major way as it would break any most of mods in wild.

Sematic is simple, you keep current value (by not mentioning property in any way) or setting it by new value. For default values, look in ufopedia page.

probably it will get ignored by yaml-cpp as it can't convert text `null` to number.

Are there sets of canonical defaults that would yield the desired outcome (in my case, being effectively a no-op).

Also, how had the null values been used in the existing mods that contradicts their semantics as no-op values?

I could e.g. set recoveryPoints to 0 to achieve this end consistently.

Now, regarding the costBuy the issue is more along the lines of what value could yield me a desired interpretation.  If the value must be numerical, then perhaps a negative number could have a desired significance.  Or a zero?  Ideally of course, the value should be a more complex variant type, but numerical conventions are workable.

probably it will get ignored by yaml-cpp as it can't convert text `null` to number.

Do any of the conversion stages populate the entire set of all arguments available for an object?  If so, there must be defaults defined for all arguments, and most of them should include a no-op value case (i.e. a value whose effect is to have no effect).

A conversion stage should be able to convert null to a no-op default, unless there's some established semantical conversion regarding nulls that would contradict such interpretation.