Converters explained

You have used converters without thinking about them. Every patch has one. This page explains what a converter actually is, so the PM:Patch(converter, ...) form and the typed modules make sense.

What a converter does

An asset is stored as JSON. Your callback works with a Lua value. Something has to translate between the two, in both directions: JSON into the value you edit, then your edited value back into JSON for the game. That something is the converter. It has two jobs:

  • Lift the asset's JSON into the value your Do callback receives.

  • Serialize that value back into JSON after your callback runs (or signal that the asset should be deleted).

The generic JSON converter does the minimal version: it hands you the raw JSON as a table-like value and writes it straight back. A typed converter does more. The parts converter, for example, lifts the JSON into a PartUserData with :AddModule and the other helpers, then serializes that back to the part's JSON form when you are done. The typed helpers you use throughout the typed modules are what a typed converter adds on top of the raw JSON.

Why PM:Patch takes a converter

The fully general patch call is PM:Patch(converter, label, name). The first argument names the converter to use. Everything else is built on this:

  • PM.JSON:Patch(label, name) is PM:Patch("JSON", label, name). It picks the generic converter for you.

  • PM.Parts:Patch(name) is, in effect, PM:Patch("Part", "parts_data", name). It picks the parts converter and the parts label for you.

That is the whole relationship between the typed modules and the generic API: each typed module is a thin method that fills in a converter and a label so you do not type them. The value you get in the callback is whatever that converter produces.

When you would name a converter yourself

Almost never. If a typed module exists for your content, use it. If no typed module exists but you just want raw JSON, use PM.JSON. The only time you use PM:Patch(converter, ...) directly is when a converter exists that no typed module wraps, for example a converter another mod registered and exposed by name but without a Lua submodule of its own. In that case you name it explicitly:

PM:Patch("SomeOtherConverter", "some_label", "MyPatch")
   :Do(function(value) ... end)

Where converters come from

The generic JSON converter and the typed converters (Part, and the rest) ship with PatchManager. A mod can add more from C#, and once it does, the new converter is usable from Lua by its name.

As a Lua patch author you do not have to think about any of that. You use the converter names you are handed: the typed modules and PM.JSON fill theirs in for you, and if another mod wants you to patch its custom content, it tells you the converter name to pass to PM:Patch. So for you, a converter is just the name that decides what kind of value your callback gets, and you will always be given the name when you need it. The Extending in C# page is only for the other side of this: writing a converter yourself, which is a C# mod task, not a Lua one.