This document defines the Lua descriptor format for LunyEngine API code generation.
CodeGen~ folder - Excluded from Unity (automatic via ~) and Godot (via .gdignore)
Luny/
├── [runtime code]
└── CodeGen~/
├── .gdignore # Empty file for Godot exclusion
├── README.md # How to run generator
├── Descriptors/
│ └── Services/
│ ├── vehicle_service.lua
│ └── Unity/
│ └── vehicle_service_unity.lua
└── Generators/ # Custom generator implementations
├── ServiceInterfaceGenerator.cs
├── UnityServiceGenerator.cs
└── BlockGenerator.cs
LunyScript/
├── [runtime code]
└── CodeGen~/
├── .gdignore
├── README.md
├── Descriptors/
│ └── Blocks/
│ └── vehicle_blocks.lua
└── Generators/ # Optional: custom generators
Benefits:
~ suffix).gdignore)┌─────────────────────────────────────┐
│ Block Descriptors (LunyScript) │
│ - User-facing block API │
│ - References service interfaces │
│ - Engine-agnostic │
└─────────────┬───────────────────────┘
│ depends on
↓
┌─────────────────────────────────────┐
│ Service Descriptors (Luny) │
│ - Engine service interfaces │
│ - Engine-specific implementations │
│ - Native engine calls │
└─────────────────────────────────────┘
Dependency Flow:
Location: CodeGen~/Descriptors/Services/{domain}_service.lua
Purpose: Define engine service interface contract and implementations
-- vehicle_service.lua
return {
-- Metadata
service_name = "Vehicle", -- Generates IVehicleEngineService
version = "1.0",
description = "Vehicle control operations",
-- Output paths (relative to descriptor file location)
output = {
interface = "../../Generated/IVehicleEngineService.cs",
unity = "../../Unity/Generated/UnityVehicleEngineService.cs",
godot = "../../Godot/Generated/GodotVehicleEngineService.cs"
},
-- Service interface contract (engine-agnostic)
methods = {
SetSpeed = {
description = "Set forward velocity magnitude",
params = {
{name="speed", type="number", min=0, max=100, required=true}
},
returns = "void"
},
Steer = {
description = "Set steering direction",
params = {
{name="direction", type="number", min=-1, max=1, required=true}
},
returns = "void"
},
Honk = {
description = "Play horn sound",
params = {},
returns = "void"
}
},
-- Engine-specific implementations
engines = {
Unity = dofile("Services/Unity/vehicle_service_unity.lua"),
Godot = dofile("Services/Godot/vehicle_service_godot.lua")
}
}
Location: Descriptors/Services/{Engine}/{domain}_service_{engine}.lua
Purpose: Define engine-specific implementation details
-- Services/Unity/vehicle_service_unity.lua
return {
SetSpeed = {
namespace = "UnityEngine",
target = "Rigidbody.velocity",
transformation = "ToVector3Forward",
version_overrides = {
default = "Rigidbody.velocity",
["6000.3.4"] = "Rigidbody.linearVelocity" -- Unity 6.3.4+
}
},
Steer = {
namespace = "UnityEngine",
target = "CarController.steerAngle",
transformation = {name="Scale", factor=45.0}
},
Honk = {
namespace = "UnityEngine",
target = "AudioSource.PlayOneShot",
signature = {"AudioClip", "float"}, -- For overload resolution
params = {
{name="clip", type="object", transformation="LookupAsset", default="HornSound"}
}
}
}
params = {
{
name = "speed", -- Parameter name
type = "number", -- Lua type: "number", "bool", "string", "object"
min = 0, -- Optional: numeric range validation
max = 100,
required = true, -- Optional: is parameter required?
default = nil, -- Optional: default value if not provided
description = "Speed value in units/sec"
}
}
Location: CodeGen~/Descriptors/Blocks/{domain}_blocks.lua
Purpose: Define user-facing block API that uses services
-- vehicle_blocks.lua
return {
-- Metadata
block_group = "Vehicle", -- Generates static class Vehicle
service_dependency = "IVehicleEngineService", -- Which service interface to use
version = "1.0",
description = "User-facing vehicle control blocks",
-- Output path (relative to descriptor file location)
output = {
blocks = "../../../Generated/VehicleAPI.cs"
},
-- User-facing blocks
blocks = {
SetSpeed = {
description = "Set vehicle forward speed",
user_params = {
{name="speed", type="number"} -- What user provides to block
},
service_method = "SetSpeed", -- Which service method to call
service_args = {
"speed" -- Map user param → service param (can transform here)
}
},
Steer = {
description = "Steer vehicle left/right",
user_params = {
{name="direction", type="number"}
},
service_method = "Steer",
service_args = {"direction"}
},
Honk = {
description = "Play horn sound",
user_params = {}, -- No user parameters
service_method = "Honk",
service_args = {}
}
}
}
user_params = {
{
name = "speed", -- Parameter name
type = "number", -- C# type at user API level
validation = { -- Optional: validation at block construction
min = 0,
max = 100
},
description = "Forward speed"
}
}
service_args = {
"speed", -- Simple: pass through user param directly
-- OR complex mapping (future):
{param="speed", transformation="Scale", factor=0.5}
}
Used in service method parameters:
"number" - double precision (maps to C# double)"bool" - boolean (maps to C# bool)"string" - string (maps to C# string)"object" - generic object reference (maps to C# object or specific type)Used in block user parameters - same as Lua types for MVP.
Future: May add strongly-typed variants ("int", "float", etc.)
Transformations convert semantic parameters to engine-native types.
transformation = "ToVector3Forward"
References a registered C# transformation by name.
transformation = {
name = "Scale",
factor = 45.0
}
Table format allows passing configuration to transformation.
Numeric:
Scale - multiply by factor: {name="Scale", factor=N}Normalize - clamp to range: {name="Normalize", min=0, max=1}Clamp - clamp to range: {name="Clamp", min=N, max=M}Vector:
ToVector3Forward - double → Vector3(0, 0, value)ToVector3Up - double → Vector3(0, value, 0)ToVector3 - (x,y,z) → Vector3(x, y, z)Lookup:
LookupAsset - string → engine asset referenceLookupObject - string → scene object referenceversion_overrides = {
default = "Rigidbody.velocity",
["6000.3.4"] = "Rigidbody.linearVelocity", -- Unity 6.3.4+
["6000.7.0"] = "Rigidbody.linearVelocityNew" -- Unity 6.7.0+
}
Resolution rules:
major.minor.patch"6000.3.4" targetversion = "1.0" -- Descriptor format version
Allows tracking breaking changes to descriptor format itself.
For cleaner target specifications:
namespace = "UnityEngine"
target = "Rigidbody.velocity"
-- Generates: UnityEngine.Rigidbody
Benefits:
For engine methods with multiple overloads:
signature = {"AudioClip", "float"}
Specifies parameter types to select correct overload at generation time.
When needed:
AudioSource.PlayOneShot(AudioClip) vs PlayOneShot(AudioClip, float)Instantiate(GameObject) vs Instantiate(GameObject, Transform) vs Instantiate(GameObject, Vector3, Quaternion)Default: If omitted, assumes single implementation or no ambiguity.
Create new service descriptor:
-- Descriptors/Services/ThirdParty/custom_service.lua
return {
service_name = "CustomFeature",
methods = { ... },
engines = {
Unity = dofile("Services/ThirdParty/Unity/custom_service_unity.lua")
}
}
Generator produces ICustomFeatureEngineService in custom namespace.
Create new block group using existing or custom service:
-- CodeGen~/Descriptors/Blocks/ThirdParty/custom_blocks.lua
return {
block_group = "CustomAPI",
service_dependency = "ICustomFeatureEngineService",
output = {
blocks = "../../../../MyFramework/Generated/CustomAPI.cs"
},
blocks = { ... }
}
Generator produces CustomAPI static class with blocks.
Output paths are specified in descriptors (relative to descriptor file):
output = {
interface = "../../../Generated/ICustomService.cs",
unity = "../../../Unity/Generated/UnityCustomService.cs",
blocks = "../../../Generated/CustomAPI.cs"
}
No CLI output path arguments needed - descriptors are self-contained.
Currently all methods return void. Future:
methods = {
GetSpeed = {
params = {},
returns = "number" -- How to handle return values in blocks?
}
}
Options:
Decision: Deferred for MVP (all blocks are setters)
Current: Transformations operate on single parameters.
Future: Some operations need multiple inputs:
transformation = {
name = "ToVector3",
params = {"x", "y", "z"} -- Combine three user params
}
Decision: Deferred for MVP (use service-level transformation)
How to handle failures?
error_behavior = "throw" -- Options: "throw", "log", "silent"
Options:
Decision: TBD, likely throw for MVP (fail loudly)
Two-descriptor system:
Clear separation:
Self-contained:
Folder convention:
CodeGen~/ - Excluded from Unity/GodotNext: Define generator tool architecture and code emission strategy.