Lua Script Migration

From PMDOWiki
Revision as of 02:39, 15 July 2024 by IDK (talk | contribs) (behavior on some improper ports)

Between 0.8.1 and 0.8.2, the lua scripting system has changed. When you reserialize mods between these versions, the lua scripts will go through an automatic conversion.


Diff Modding

Main Case

In the new system, lua scripts are diff modded. This means that instead of having to replace the entire file in the base game, you can chose to just add or redefine functions that you want.

For example, the script event_misc.lua contains the following methods:

function STATUS_SCRIPT.Test(owner, ownerChar, context, args)
function MAP_STATUS_SCRIPT.Test(owner, ownerChar, character, status, msg, args)
function MAP_STATUS_SCRIPT.ShopGreeting(owner, ownerChar, character, status, msg, args)
function MAP_STATUS_SCRIPT.SetShopkeeperHostile(owner, ownerChar, character, status, msg, args)
function ITEM_SCRIPT.Test(owner, ownerChar, context, args)
function ITEM_SCRIPT.CastawayCaveShift(owner, ownerChar, context, args)
function ITEM_SCRIPT.SleepingCalderaShift(owner, ownerChar, context, args)
function REFRESH_SCRIPT.Test(owner, ownerChar, character, args)
function SKILL_CHANGE_SCRIPT.Test(owner, character, skillIndices, args)

In the old system, if you wanted to mod just the MAP_STATUS_SCRIPT.ShopGreeting event, you would need to copy the entire event_misc.lua from the base game, modify MAP_STATUS_SCRIPT.ShopGreeting, and save it to your mod.

In the new system, all you need to do is create an event.lua with your custom MAP_STATUS_SCRIPT.ShopGreeting in it, and nothing else.

This makes it easy to maintain scripts, as the base game scripts can change. In the old system, if MAP_STATUS_SCRIPT.SetShopkeeperHostile in the base game changed after you copied over event_misc.lua, you would have had to copy the changed version of that method to your own mod to stay updated. Now in the new system, if you don't redefine the method in your mod, you won't have to worry about it.

This works on all scripts found in the Data/Script folder, and all subfolders except Data/Script/services.


Services

Services behave slightly differently. Originally, creating a new service in the mod would add its events on top of the base game's events. However, it now replaces the original service and removes the base game's event triggers in favor of your new ones.


Breaking Changes

Namespace Folders

With the diff modding changes, a caveat is that all lua scripts are namespaced. This way, you can reference methods from the base game specifically. However, it means that all scripts need to be moved to a subfolder in the name of your mod's namespace.

For example, your mod has the namespace my_mod, and your scripts are currently in the Data/Script folder of your mod (You can find/specify your mod's namespace in the Mod.xml). In this situation, you should move all your code to a new folder, Data/Script/my_mod

★ This is done as a part of auto-conversion.

Namespace References

Additionally, your require calls must be updated to specify whether you're importing code from the origin namespace or your own namespace. And meanwhile, if you made custom scripts on your own mod, you need to instead change the require to reflect your namespace, because the code is in your namespace of mod. For example, the header of a ground map script you created may look like this:

require 'common'
require 'GeneralFunctions'
require 'PartnerEssentials'
require 'ground.my_town.my_town_ch_1'
require 'ground.my_town.my_town_ch_2'

Let's assume in this example, your mod has namespace my_mod. You created this ground script in Data/Script/ground/my_town/init.lua. You referred to common from the base code, but are referring to your own script for the rest of the includes. You will need to change it to this:

require 'origin.common'
require 'my_mod.GeneralFunctions'
require 'my_mod.PartnerEssentials'
require 'my_mod.ground.my_town.my_town_ch_1'
require 'my_mod.ground.my_town.my_town_ch_2'

If this isn't done, the mod will complain about being unable to load modules that aren't there.


References to these packages also need to be updated in places where they're used without require. Most notably, AI initialization. Ex: AI:SetCharacterAI(partner, "ai.ground_partner", CH('PLAYER'), partner.Position) should be changed to AI:SetCharacterAI(partner, "origin.ai.ground_partner", CH('PLAYER'), partner.Position) or AI:SetCharacterAI(partner, "my_mod.ai.ground_partner", CH('PLAYER'), partner.Position), if your mod is overriding the original ai.

If this isn't done, you will get AI errors on maps where ground character AI is supposed to work.

★ This section is done as a part of auto-conversion.

Starting Scripts

In the base game, PMDO calls the following scripts directly from the game on startup, which in turn make a require call to additional scripts:

  • main.lua
  • common.lua
    • common_talk.lua
    • common_shop.lua
    • common_vars.lua
    • common_tutor.lua
  • event.lua
    • event_single.lua
    • event_battle.lua
    • event_misc.lua
    • event_mapgen.lua
  • include.lua

common.lua and event.lua both make require calls to load their child scripts. If you have modded versions of the the child scripts, you will need to add the parent script with a single require call to the child. For example, if you modded event_mapgen, you will need to make sure you have an event.lua that has require 'my_mod.event_mapgen in it.

★ This section is done as a part of auto-conversion.

Automatic Tables

The tables for common scripts and event scripts, such as SINGLE_CHAR_SCRIPT, BATTLE_SCRIPT, and so on, are now declared by the game's code, so you don't need to declare them as empty tables anymore. You shouldn't, because the modding system stacks the base game's methods with your mod's on top, and redefining the variable would result in your mod removing the base game's functions.

You will need to remove these lines from the event scripts:

  • common.lua:
    • COMMON = {}
  • event_single.lua:
    • SINGLE_CHAR_SCRIPT = {}
  • event_battle.lua:
    • BATTLE_SCRIPT= {}
  • event_misc.lua:
    • STATUS_SCRIPT = {}
    • MAP_STATUS_SCRIPT = {}
    • ITEM_SCRIPT = {}
    • REFRESH_SCRIPT = {}
    • SKILL_CHANGE_SCRIPT = {}
    • GROUND_ITEM_EVENT_SCRIPT = {}
  • event_mapgen.lua:
    • ZONE_GEN_SCRIPT = {}
    • FLOOR_GEN_SCRIPT = {}

★ This section is done as a part of auto-conversion.

Services

Due to the change in services, several things must be accounted for:

  • If you have services with the same name as those of the base game (debug_tools, menu_tools, upgrade_tools), your service now overwrites the original instead of adding onto it. If you want to add new functionality without overwriting the old, make a new service with a new name.
  • The base game's debug_tools service used to have an event for OnMenuButtonPressed. That event has been moved out of the service and into its own service, menu_tools. If you are overriding OnMenuPressed in any services and do not replace menu_tools, you will have the main menu opened twice when menu button is pressed!


Non-Breaking Changes

These changes are not mandatory to get your mod working, but are good to have.

Deprecated MapStrings

The use of the MapStrings variable to obtain the text strings for ground maps is no longer needed. You no longer need to declare them, you no longer need to initialize them, and you no longer need to reference them. Instead, strings for a ground map are automatically loaded and stored in the game for you to call on. You should remove these statements from your ground map scripts:

local MapStrings = {}

MapStrings = COMMON.AutoLoadLocalizedStrings()

Then, you should change all references to MapStrings to STRINGS.MapStrings

★ This section is done as a part of auto-conversion.

Redundant Functions

As mentioned in the Diff Modding section, if you don't redefine the method in your mod, you won't have to worry about it. If you have any files where you copied over the base game's scripts and edited just a single method, you can delete the other methods from that modded lua file. This will make your code more resilient to base game lua changes.

Un-Needed Files

The following files are no longer needed in your mod and will have no effect:

  • The file Data/Script/debugger.lua
  • The folder Data/Script/bin
  • The folder Data/Script/lib

You can safely delete them. Their require statements in common.lua are also no longer needed:

Class    = require 'lib.middleclass'
Mediator = require 'lib.mediator' 
Serpent = require 'lib.serpent'

★ This section is done as a part of auto-conversion.

Migration Checklist

When you reserialize mods between these versions, the lua scripts will go through an automatic conversion. Some breaking changes detailed in the above section are automatically fixed. Some will not.

Items marked with ★ are automatically converted on reserialization from versions <=0.8.1 to >=0.8.2

  • ★ Lua scripts are moved to a subfolder based on the mod's namespace.
  • ★ References to require "common" become require "origin.common"
  • ★ References to your own scripts require "yourscript" changed to include your namespace require "yournamespace.yourscript"
  • ★ common and event scripts need their empty table declarations removed.
  • ★ Scripts modded from children of common.lua or event.lua must have a modded version of their parent with an include to the child.
  • Services that have the same name as the base game's service need to be renamed, IF you don't want to overwrite the base logic.

These are optional changes that you don't have to make, but is good to clean up files or code no longer needed:

  • ★ MapStrings is deprecated.
    • ★ Remove variable declaration and initialization statements.
    • ★ Replace references to MapStrings with STRINGS.MapStrings
  • ★ Deleted Data/Script/bin and Data/Script/lib subfolders
  • ★ Deleted Data/Script/services/baseservice.lua file
  • Functions identical to the base game are removed in the mod, for the files of common.lua and event.lua
  • Functions identical to the base game are removed in the mod, for the files in ground and zone