Modding:General Best Practices: Difference between revisions

m Small cleanup (fix missing noun after "IScribed*"; link to the serialization article)
 
(3 intermediate revisions by one other user not shown)
Line 29: Line 29:
</objects>
</objects>
</syntaxhighlight>
</syntaxhighlight>
==ObjectBlueprint Definitions==
In general, unless you're defining a unique object, make sure you add the xml attribute <code>Load="Merge"</code> (and avoid including the <code>Inherits</code> attribute) to prevent breaking behavior.


=Random Functions=
=Random Functions=
{{Main|Modding:Random Functions}}
{{Main|Modding:Random Functions}}
To avoid conflicts and to keep consistency between seeds, Stat.Random() and Stat.Rnd() should not be called. The ideal is to use [[Modding:Random_Functions#GetSeededRandomGenerator.28string_Seed.29|GetSeededRandomGenerator()]] for your mod's randomness. The next best is calling RandomCosmetic() or Rnd2().
To avoid conflicts and to keep consistency between seeds, Stat.Random() and Stat.Rnd() should not be called. The ideal is to use [[Modding:Random_Functions#GetSeededRandomGenerator.28string_Seed.29|GetSeededRandomGenerator()]] for your mod's randomness. The next best is calling RandomCosmetic() or Rnd2().
=ObjectBlueprint Definitions=
In general, unless you're defining a unique object, make sure you add the xml property <code>Load="Merge"</code> to prevent breaking behavior.


=Stats=
=Stats=
Prefer using <code>value</code> over <code>sValue</code>, unless you're creating a unique creature. When loading ObjectBlueprints, the code loads both <code>sValue</code> and <code>value</code> into a stat, then if <code>sValue</code> is set, prefers using that to set a stat over <code>value</code>.
Prefer using <code>value</code> over <code>sValue</code>, unless you're creating a unique creature. When loading ObjectBlueprints, the code loads both <code>sValue</code> and <code>value</code> into a stat, then if <code>sValue</code> is set, prefers using that to set a stat over <code>value</code>.
=Named arguments=
When interacting with Qud's C# API, prefer using [https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments named arguments] to fill out optional parameters.
For example, consider <code>XRL.UI.Popup.AskString()</code>:
<syntaxhighlight lang="csharp">
// namespace XRL.UI
// public class Popup
public static string AskString(
  string Message,
  string Default = "",
  string Sound = PROMPT_SOUND,
  string RestrictChars = null,
  string WantsSpecificPrompt = null,
  int MaxLength = 80,
  int MinLength = 0,
  bool ReturnNullForEscape = false,
  bool EscapeNonMarkupFormatting = true,
  bool? AllowColorize = null
)
</syntaxhighlight>
Without named arguments, calling the function may look like
<syntaxhighlight lang="csharp">
using XRL.UI;
var response = Popup.AskString(
  "How are you doing?",
  "Okay",
  Popup.PROMPT_SOUND,
  null,
  null,
  80,
  0,
  true,
  true,
  true
);
</syntaxhighlight>
With named arguments for intentionally-set optional parameters, calling the function may look like
<syntaxhighlight lang="csharp">
using XRL.UI;
var response = Popup.AskString(
  "How are you doing?",
  Default: "Okay",
  MaxLength: 80, // note: same as current default
  ReturnNullForEscape: true,
  AllowColorize: true
);
</syntaxhighlight>
This provides a couple of related benefits:
# '''Flexibility and resilience.''' By specifying only the arguments you want to set, your code will adapt to changes in default values and many common parameter list changes (e.g. the addition of a new optional parameter or the reorganization of optional parameters).
# '''More sensible errors.''' If the parameter list changes in a way that cannot be automatically resolved (e.g. the removal of a parameter you set), the error message will generally include the name of your argument instead of the index (or worse, continuing to compile with the argument going to the wrong parameter).
# '''Documentation.''' By naming arguments, you provide clarity to future readers of your code (including yourself) as to its intended purpose.
'''Avoid including positional arguments after named ones!''' Calling <code>void Foo(int A, string B, bool C)</code> like <code>Foo(A: 0, "blah", C: false)</code> will cause cryptic errors if the parameter list gets reorganized.


= Save migration =
= Save migration =
Line 58: Line 115:
</syntaxhighlight>
</syntaxhighlight>


The <code>IScribed*</code> have some performance implications you should be aware of that are relevant to certain mods; see the serialization article for more details.
The <code>IScribed*</code> classes have some performance implications you should be aware of that are relevant to certain mods; see the [[Modding:Serialization (Saving/Loading)|serialization article]] for more details.


= Harmony Patches =
= Harmony Patches =