# CustomClothingBase on Aelrynth

**Third-party mod.** CustomClothingBase is by **OptimShi** - https://github.com/OptimShi/CustomClothingBase,
brought in at upstream `122145d` (v1.11, 2025-08-20) on 2026-09-30 at a player's request. `README.md`
here is upstream's and says how it works: JSON files in the mod's `json` folder add to or replace
ClothingTable (0x10xxxxxx) entries on the server, so items can have new colour schemes and part swaps
built from art the retail client already has. Nothing is sent to the client but the usual appearance
data - no download, no dat change (direction 2 holds).

**Licence.** Upstream has no LICENSE file. A Harmony mod that patches ACE is a derivative of ACE, which
is AGPL-3.0, so it is published with the server's source (`publish-source.sh`) like every running mod,
credited here. If upstream adds a licence, copy it in beside this file.

**What we changed** (keep this list short and exact):
- `CustomClothingBase.csproj`: rewritten for `Mods/Directory.Build.props` - net10.0, ACE from our
  build, Harmony from the host (upstream pinned Lib.Harmony 2.3.6 and System.Text.Json 8, both left
  out). Packages kept: ACEmulator.ACE.Shared 1.0.9, Krafs.Publicizer, JsonNet.ContractResolvers,
  Newtonsoft.Json.
- `PatchClass.cs`: the JSON options are built when the class loads instead of in `OnWorldOpen`.
  On its first load `OnWorldOpen` did not run (ACE.Shared writes a missing Settings.json and stops
  there), the options stayed null, and every custom file failed ("could not be converted to
  System.UInt32" on the first hex value). `Stop` tolerates null Settings for the same reason.
- `Mod.cs`: a `Stop` that cannot recurse. ACE.Shared's `BasicMod.Stop` calls `DisableModByPath`
  from its catch, which calls `Stop` again: when this mod's Stop threw on null Settings (staging,
  2026-09-30 14:02:41, `mod disable`), the server died of a stack overflow. Each patch is stopped on
  its own now, failures logged, nothing calls back into disable. Same fix in CustomSpells, whose
  `AELRYNTH.md` lists the ACE.Shared hazards for both.

**Deploy:** put Settings.json in the folder before the first `mod-load` (ACE.Shared's first load
only writes it). Editing Settings.json restarts the mod by itself.

**The name stays `CustomClothingBase`** (not `Aeshnidae.*`): the mod finds its own folder with
`ModManager.GetModContainerByName("CustomClothingBase")`.

**Using it.** A look is content: the JSON file goes in the repo (`Mods/Content/clothing/`, not only
on the server), and the weenie that wears it (ClothingBase DID, PaletteTemplate) changes through the
ledger with a patch note, like any other world change. Console: `clothingbase-export <0x10...>` writes
an entry to `json/` (note: into the same folder the mod reads - an export IS an override, identical
to the dat until edited); `clear-clothing-cache` re-reads them (the folder is also watched).

**Tested** 2026-09-30 on staging: upstream's `Examples/10000322.json` (a green Virindi Mask,
PaletteTemplate 8) merged into the retail table - retail has palette templates 3, 14, 39; with the
file, 3, 8, 14, 39. Not yet seen in a client.
