甜瓜游乐场 Lua 芯片执行器模拟 - Melon Playground Lua chip sandbox
Project description
Melon Lua Sandbox
甜瓜游乐场 Lua 芯片执行器模拟器。
基于 APK 逆向分析提取的真实 LuaPreamble.lua + 完整 Example_ApiReference_en.lua,使用 Python + lupa(LuaJIT)重现已有的 Lua 芯片执行环境。所有 API 名称、参数、返回值均与现实一致。
特性
- ✅ 真实前置脚本
LuaPreamble.lua(Entity OOP、shared/signal/require系统) - ✅ 甜瓜允许的标准库(
stdlib_melon+verify_melon_stdlib.py) - ✅ 11 个 ApiModule:
entity、spawn、env、camera、input、inputFilter、chip、mechanic、world、variables、uicontrol、print - ✅ SDK 目录:
object_physics_by_id.json(495 条尺寸;spawn.create("202")/spawn_entity(object_id=…)) - ✅ 类型化输入输出:
inputs.num.x、outputs.string.status、outputs.vec.dir、outputs.color.tint等 - ✅ 完整生命周期:
OnInit、OnTick、OnActivated、OnDeactivated、OnSpawned、OnDestroy - ✅ Box2D 真实 2D 物理:重力、碰撞、
addForce、setVelocity、freeze、gravityScale - ✅ 无真实时间等待,适合快速批量 tick 模拟
安装
pip install -e .
依赖:lupa(LuaJIT 绑定)、Box2D(pybox2d)。
已发布到 PyPI:
pip install melon-lua
CLI 使用
# 基础运行(5 秒 × 20 TPS = 100 tick)
melon-lua samples/hello_chip.lua
# 精确跑 N tick(推荐)
melon-lua samples/bignum.lua --ticks 1000
# 静态输入
melon-lua samples/adder.lua --inputs inputs.json
# 时间线输入(按 tick 切换)
melon-lua samples/adder.lua --inputs-timeline timeline.json
# 快速 TPS
melon-lua samples/bignum.lua --ticks 100 --tps 60
# 种子实体(物理测试)
melon-lua samples/physics_demo.lua --ticks 80 \
--seed-entity "crate,0,10" \
--seed-static "floor,0,0"
# 列出 API
melon-lua --api-list
输入文件格式
静态 inputs.json:
{
"num": {"a": 5, "b": 3},
"string": {"mode": "attack"}
}
时间线 timeline.json(tick 从 1 开始,设置后持续到下个变化点):
{
"1": {"num": {"a": 1}},
"30": {"num": {"a": 10}},
"60": {"num": {"a": 0}}
}
文档
docs/API.md— Python SDK 完整参考(WorldContext、MelonScriptRunner、catalog、preview 等)docs/LUA_GUIDE.md— 甜瓜 Lua 芯片开发完整指南(生命周期、API 速查 + 标准库)docs/stdlib.md— 甜瓜芯片允许的标准库完整清单(含禁用项与验证方法)docs/guide.md— 原始简版教程(已整合进 LUA_GUIDE.md)
建议先读 docs/LUA_GUIDE.md 写芯片,再用 docs/API.md 做 Python 侧集成/模拟。
from melon_lua import (
MelonScriptRunner, WorldContext,
get_profile_by_object_id, object_id_for_name, list_spawnables,
)
# 495 物体:objectId + 碰撞尺寸(贴图可选)
print(object_id_for_name("ResizablePlastic")) # 202
prof = get_profile_by_object_id(202)
world = WorldContext()
# 按 objectId 或 gameObjectName 生成(自动套 APK 尺寸)
world.spawn_entity("202", 0, 5, dynamic=True) # Plastic plate
world.spawn_entity("Box", 2, 5, dynamic=True)
world.spawn_entity("ground", 0, 0, dynamic=False, scale_x=10.0)
runner = MelonScriptRunner(tps=20, world=world)
source = '''
function OnInit()
print("chip started")
end
function OnTick()
local e = Entity(1)
local x, y = e:getPosition()
outputs.num.x = x
outputs.num.y = y
end
'''
runner.compile(source)
runner.run_loop(ticks=100)
print(runner.logs)
手动单步:
runner.call_on_init()
result = runner.run_tick(inputs={"num": {"a": 5}})
print(result["outputs"])
真实 API 示例
function OnInit()
print("init!")
end
function OnTick()
-- 读取类型化输入
local speed = inputs.num.speed or 0
-- Entity OOP
local e = Entity(1)
e:setVelocity(speed, 0)
-- 物理
local x, y = e:getPosition()
outputs.num.x = x
outputs.num.y = y
-- 生成请求(异步回调)
spawn.create("human", x + 2, y)
end
function OnSpawned(requestId, entities)
print("spawned request", requestId, "got", #entities, "entities")
end
生命周期
function OnInit() end -- 芯片初始化,调用一次
function OnActivated() end -- 激活时调用一次
function OnTick() end -- 每 tick 调用(按 TPS)
function OnDeactivated() end -- 停用时调用一次
function OnDestroy() end -- 销毁时调用一次
function OnSpawned(requestId, entities) end -- spawn.create 完成后回调
Box2D 物理
默认重力 (0, -9.8),y 轴向上为正。创建 entity 时通过 dynamic=True/False 决定是否为刚体。
物理方法:
entity:addForce(fx, fy)/addForceAtPosition(fx, fy, px, py)/addTorque(t)entity:setVelocity(vx, vy)/setAngularVelocity(w)entity:setPosition(x, y)/setAngle(deg)entity:freeze(bool)/freezeRotation(bool)/setGravityScale(s)
注意:物理 Tick 与世界 Tick 同步,不按真实时间阻塞,因此可以快速模拟长时间演化。
项目结构
melon_lua/
├── preamble.lua -- 真实 LuaPreamble.lua(APK 原版)
├── runner.py -- 芯片执行引擎
├── world.py -- Box2D 物理世界 + 全局状态
├── entity.py -- Entity 数据模型
└── backend/ -- 11 个真实 ApiModule 的 Python 后端
├── entity_backend.py
├── env_backend.py
├── spawn_backend.py
├── chip_backend.py
├── mechanic_backend.py
├── world_backend.py
├── camera_backend.py
├── input_backend.py
├── inputFilter_backend.py
├── variables_backend.py
└── uicontrol_backend.py
限制
- 物理使用 Box2D,但物体形状目前均为矩形 box(与 sprite 无关),碰撞材质使用默认值。
- 渲染、音效、网络、真实输入设备无法模拟。
- 某些 ApiModule(如
mechanic、uicontrol、inputFilter)在沙盒中返回 mock 值,适合验证逻辑而非真实 UI/输入行为。
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file melon_lua-4.0.0.tar.gz.
File metadata
- Download URL: melon_lua-4.0.0.tar.gz
- Upload date:
- Size: 2.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a113237d4a367d80c086cf588192ed7855a0e4330094301a2c195ab8e5e05cf
|
|
| MD5 |
37597a925ceda3030515d150f1a324e9
|
|
| BLAKE2b-256 |
9d782d26adb9f5f72e8d2e85470cef177533ad0c6770d177cd58c1eb092359ac
|
Provenance
The following attestation bundles were made for melon_lua-4.0.0.tar.gz:
Publisher:
publish.yml on xunxiing/MelonLuaSandbox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
melon_lua-4.0.0.tar.gz -
Subject digest:
0a113237d4a367d80c086cf588192ed7855a0e4330094301a2c195ab8e5e05cf - Sigstore transparency entry: 1992540045
- Sigstore integration time:
-
Permalink:
xunxiing/MelonLuaSandbox@4f7ed9feba6141c4cd8ad2363a56b100c980b650 -
Branch / Tag:
refs/tags/v4.0.0 - Owner: https://github.com/xunxiing
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4f7ed9feba6141c4cd8ad2363a56b100c980b650 -
Trigger Event:
push
-
Statement type:
File details
Details for the file melon_lua-4.0.0-py3-none-any.whl.
File metadata
- Download URL: melon_lua-4.0.0-py3-none-any.whl
- Upload date:
- Size: 2.5 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5bb330c3ba54abf752741a1671ef466d439a976a28480014b42bd78d2279ba04
|
|
| MD5 |
6e6e44d476f3d4278d161737eef010f5
|
|
| BLAKE2b-256 |
8883b09829e07c6450e249aa0cdb4d827780a4dafdbd30f9f2c1eb8764a7eccc
|
Provenance
The following attestation bundles were made for melon_lua-4.0.0-py3-none-any.whl:
Publisher:
publish.yml on xunxiing/MelonLuaSandbox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
melon_lua-4.0.0-py3-none-any.whl -
Subject digest:
5bb330c3ba54abf752741a1671ef466d439a976a28480014b42bd78d2279ba04 - Sigstore transparency entry: 1992540168
- Sigstore integration time:
-
Permalink:
xunxiing/MelonLuaSandbox@4f7ed9feba6141c4cd8ad2363a56b100c980b650 -
Branch / Tag:
refs/tags/v4.0.0 - Owner: https://github.com/xunxiing
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4f7ed9feba6141c4cd8ad2363a56b100c980b650 -
Trigger Event:
push
-
Statement type: