Skip to content

[Suggestion] Revisit support for LUA #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Monniasza opened this issue Feb 2, 2025 · 5 comments
Open

[Suggestion] Revisit support for LUA #33

Monniasza opened this issue Feb 2, 2025 · 5 comments
Assignees
Labels
BLOCKED Blocked by a task, issue or external event enhancement New feature or request

Comments

@Monniasza
Copy link

Monniasza commented Feb 2, 2025

Preamble

Hi. After 4.5 years with a lot of breaks, I'm finally wanting a solid API for patches. Today I've been trying to implement ISRU patching and I've got plans to expand Ultimate Part Converter with more features. But I've hit several issues, like https://forum.kerbalspaceprogram.com/topic/50533-18x-112x-module-manager-423-july-03th-2023-fireworks-season/page/309/#comment-4440498, which makes both of my attempts at finding nodes with non-standard ID keys difficult, if not impossible. The need for arbitrarily programmable patching system is dictated by lack of constructs that allow cross-products of several lists of nodes, which is needed to implement B9 Fuel Switch compatibility for LPG converter.

The Overview

I'm suggesting addition of Lua API, like #5 that was given to me, but I've not wanted it yet, because the Ultimate Part Converter, which was a part of SSTO Project in the past was simpler and had just half of the code that I want to have now. But it was still remarkable, that it converted any LF jet, LF+Ox rocket, LF tank and LF+Ox tank to its LPG version, while supporting 2 fuel switching mods and SMURFF at the same time. And it still does that today perfectly.

Overview of the API and scripting environment

This solution combines approaches of both #5 and sarbian#157. In particular, it combines Lua API from #5 and functions from the advanced constructs issue. Here are all functions:

  • regexp(pattern,string) - run regexp expression on a string
  • sin, cos, tan, log10, ln, log2, expE, exp10, mod, exp, sec, csc, sqrt, curt, root, log - math functions
  • getKeys(node): finds all keys of a given node
  • getKeysName(node, name): finds all keys with given name of a given node
  • getKey(node, name): finds the first key with given name of a given node, or nil if not found
  • setKey(key, value): sets a key to a value
  • addKey(node, name, value): adds a key to a value and returns the new key
  • resetKey(node, name, value): creates or sets a key and returns the new/existing key
  • setNameKey(node, name, value): sets a key to a value only if present and returns the key or nil if not found
  • renameKey(key, name) - renames a key
  • delKey(key): deletes the key

  • getAllNodes(node): gets all sub-nodes of a node
  • getTypeNodes(node, type): gets all sub-nodes of a node with given type
  • getNode(node, type): gets the first sub-node of a node with given type, or nil if not found
  • addNode(node, name, value): adds a node to a value and returns the new node
  • resetNode(node, name, value): creates or sets a node and returns the new/existing node
  • setNameNode(node, name, value): sets a node to a value only if present and returns the node or nil if not found
  • delNode(node) - deletes a given node
  • retypeNode(node, newtype) - changes type of the node
  • cloneNode(existingNode, targetParent) - copies a node and returns the new node
  • copyNode(existingNode, targetNode) - copies all node data to a different node
  • clearNode(node) - removes all data from a node

  • rootNode(type): find a primary root-node with given type
  • rootNodeName(type, name): find a root-node with given type and name

  • FIRST(callback), BEFORE(mod, callback), FOR(mod, callback), AFTER(mod, callback), LAST(mod, callback), FINAL(callback): runs the callback without arguments on given stage of loading. BEFORE, FOR, AFTER and LAST also take a modname.

Final Considerations

It's a long Feature Request, but it has to because the API will be finally extensive and very powerful. If it's implemented, I'll be grateful and Ultimate Part Converter will be bigger and better than ever.

@Lisias Lisias self-assigned this Feb 3, 2025
@Lisias Lisias added the duplicate This issue or pull request already exists label Feb 3, 2025
@Lisias
Copy link

Lisias commented Feb 3, 2025

Close as duplicate for #5

@Lisias Lisias added enhancement New feature or request and removed duplicate This issue or pull request already exists labels Feb 3, 2025
@Lisias
Copy link

Lisias commented Feb 3, 2025

I was closing this as duplicate for #5, but then I realized this is, indeed, a follow up.

So I'm adding "blocked", as #5 needs to be implemented first

@Lisias Lisias added the BLOCKED Blocked by a task, issue or external event label Feb 4, 2025
@Monniasza
Copy link
Author

EDIT: Removed unnecessary "programming" before "API" in the OP

@Lisias
Copy link

Lisias commented Feb 4, 2025

I'm not sure if I get the need of most of that functions, Module Manager already provides most of the features itself.

What I think we need is a way to delegated to a Lua script the resolution of values, or the filtering of nodes.

The cos, sin, et all are nice additions, but I think that we should implement that on MM "default functions" saving the need to switch the context for something trivial.

The temporal directives should really be on the patch? Why not implement it as hooks on the .lua file itself?

Instead of:

@PART[yada]:FOR[MOD,##lua_call(yada, yada, yada)] { }

Or

@PART[yada]:FOR(MOD,lua_callback) { }

where this last option would create a whole new syntax creep on MM, why not just

file: GameData/ModA/Compatiblity/ModB.cfg
@PART[something]:FOR[ModA]:NEEDS[ModB]
{
}
@PART[*]:BEFORE[MobA]
{
}
@PART[something.else]:AFTER[MobB]
{
}
@PART[yet.something.else]:AFTER[MobB]
{
}

--------------------------

file:  GameData/ModA/Compatiblity/ModB.lua
ModA.FOR = function(node)
{
    yada yada yada
}
ModA.AFTER = function(node)
{
    yada yada yada
}
ModA.BEFORE = function(node)
{
    yada yada yada
}

Where node would be the node where the Directive is used. So:

  • ModA.FOR would be called once with @PART[something] as node on the :FOR phase of ModA as long Mob exists.
  • ModA.BEFORE would be called for each possible @PART[*] as node (one call for node) on the :BEFORE phase of MobA.
  • ModA.AFTER would be called twice, one with @PART[something.else] and another with @PART[yet.something.else] as node, on the :AFTER phase of ModB.

I'm not exactly sure about the usefulness of these callbacks, since I don't think it would be a good idea to allow Lua to generate or manipulate Nodes itself (Module Manager should be the only guy in town allowed to do that). But other than that, I think this mechanism would work better.

We need to keep in mind: we will need to keep the ConfigCache consistent, and the only way to guarantee that is not allowing anyone else manipulating Nodes.

@Lisias
Copy link

Lisias commented Feb 4, 2025

Humm... Would not you be thinking on a "GameDatabaseGenerator" where a Lua Script would create the ConfigNodes itself instead of KSP reading Config.cfg files from the file system?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BLOCKED Blocked by a task, issue or external event enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants