mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
update: packages,lua,retro (4 files)
This commit is contained in:
95
packages/media_center/seed/scripts/lua/retro_combos.lua
Normal file
95
packages/media_center/seed/scripts/lua/retro_combos.lua
Normal file
@@ -0,0 +1,95 @@
|
||||
--[[
|
||||
Libretro combo and motion inputs
|
||||
Complex input sequences and fighting game motions
|
||||
]]
|
||||
|
||||
local input = require("lua.retro_input")
|
||||
|
||||
---@class RetroCombosModule
|
||||
local M = {}
|
||||
|
||||
-- ============================================================================
|
||||
-- Combo/Macro System
|
||||
-- ============================================================================
|
||||
|
||||
---Execute a sequence of inputs
|
||||
---@param session_id string Session identifier
|
||||
---@param inputs ComboInput[] Array of input specifications
|
||||
---@param player? number Player number (default 0)
|
||||
function M.combo(session_id, inputs, player)
|
||||
for _, input_spec in ipairs(inputs) do
|
||||
if input_spec.button then
|
||||
input.tap(session_id, input_spec.button, player, input_spec.duration_ms)
|
||||
elseif input_spec.analog then
|
||||
input.flick_analog(session_id, input_spec.analog.stick,
|
||||
input_spec.analog.x, input_spec.analog.y, input_spec.duration_ms, player)
|
||||
end
|
||||
if input_spec.wait_after_ms then
|
||||
sleep(input_spec.wait_after_ms)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- Fighting Game Motions
|
||||
-- ============================================================================
|
||||
|
||||
--- Common fighting game motions
|
||||
M.MOTION = {
|
||||
-- Quarter circle forward (↓↘→)
|
||||
QCF = function(session_id, player)
|
||||
input.tap(session_id, "down", player, 30)
|
||||
input.diagonal(session_id, "right", "down", 30, player)
|
||||
input.tap(session_id, "right", player, 30)
|
||||
end,
|
||||
|
||||
-- Quarter circle back (↓↙←)
|
||||
QCB = function(session_id, player)
|
||||
input.tap(session_id, "down", player, 30)
|
||||
input.diagonal(session_id, "left", "down", 30, player)
|
||||
input.tap(session_id, "left", player, 30)
|
||||
end,
|
||||
|
||||
-- Dragon punch / Shoryuken (→↓↘)
|
||||
DP = function(session_id, player)
|
||||
input.tap(session_id, "right", player, 30)
|
||||
input.tap(session_id, "down", player, 30)
|
||||
input.diagonal(session_id, "right", "down", 30, player)
|
||||
end,
|
||||
|
||||
-- Half circle forward (←↙↓↘→)
|
||||
HCF = function(session_id, player)
|
||||
input.tap(session_id, "left", player, 30)
|
||||
input.diagonal(session_id, "left", "down", 30, player)
|
||||
input.tap(session_id, "down", player, 30)
|
||||
input.diagonal(session_id, "right", "down", 30, player)
|
||||
input.tap(session_id, "right", player, 30)
|
||||
end,
|
||||
|
||||
-- Charge back then forward
|
||||
CHARGE_BF = function(session_id, charge_ms, player)
|
||||
charge_ms = charge_ms or 800
|
||||
input.hold_direction(session_id, "left", charge_ms, player)
|
||||
input.tap(session_id, "right", player, 30)
|
||||
end,
|
||||
|
||||
-- 360 motion (for grapplers)
|
||||
CIRCLE = function(session_id, player)
|
||||
local dirs = {"right", "down", "left", "up"}
|
||||
for _, dir in ipairs(dirs) do
|
||||
input.tap(session_id, dir, player, 20)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---Execute a motion then press a button
|
||||
---@param session_id string Session identifier
|
||||
---@param motion function Motion from MOTION table
|
||||
---@param button string Button to press after motion
|
||||
---@param player? number Player number (default 0)
|
||||
function M.special_move(session_id, motion, button, player)
|
||||
motion(session_id, player)
|
||||
input.tap(session_id, button, player)
|
||||
end
|
||||
|
||||
return M
|
||||
169
packages/media_center/seed/scripts/lua/retro_input.lua
Normal file
169
packages/media_center/seed/scripts/lua/retro_input.lua
Normal file
@@ -0,0 +1,169 @@
|
||||
--[[
|
||||
Libretro input handling
|
||||
Button presses, analog sticks, combos, and fighting game motions
|
||||
]]
|
||||
|
||||
local constants = require("lua.retro_constants")
|
||||
|
||||
---@class RetroInputModule
|
||||
local M = {}
|
||||
|
||||
-- Re-export constants for convenience
|
||||
M.BUTTON = constants.BUTTON
|
||||
M.AXIS = constants.AXIS
|
||||
|
||||
-- ============================================================================
|
||||
-- Basic Input Functions
|
||||
-- ============================================================================
|
||||
|
||||
---Press and release a button (tap)
|
||||
---@param session_id string Session identifier
|
||||
---@param button string Button from BUTTON table
|
||||
---@param player? number Player number (default 0)
|
||||
---@param duration_ms? number Hold duration in ms (default 50)
|
||||
function M.tap(session_id, button, player, duration_ms)
|
||||
player = player or 0
|
||||
duration_ms = duration_ms or 50
|
||||
|
||||
M.press(session_id, button, player)
|
||||
sleep(duration_ms)
|
||||
M.release(session_id, button, player)
|
||||
end
|
||||
|
||||
---Press a button (hold down)
|
||||
---@param session_id string Session identifier
|
||||
---@param button string Button from BUTTON table
|
||||
---@param player? number Player number (default 0)
|
||||
function M.press(session_id, button, player)
|
||||
player = player or 0
|
||||
http.post("/api/v1/retro/sessions/" .. session_id .. "/input", {
|
||||
player = player,
|
||||
button = button,
|
||||
pressed = true
|
||||
})
|
||||
end
|
||||
|
||||
---Release a button
|
||||
---@param session_id string Session identifier
|
||||
---@param button string Button from BUTTON table
|
||||
---@param player? number Player number (default 0)
|
||||
function M.release(session_id, button, player)
|
||||
player = player or 0
|
||||
http.post("/api/v1/retro/sessions/" .. session_id .. "/input", {
|
||||
player = player,
|
||||
button = button,
|
||||
pressed = false
|
||||
})
|
||||
end
|
||||
|
||||
---Release all buttons for a player
|
||||
---@param session_id string Session identifier
|
||||
---@param player? number Player number (default 0)
|
||||
function M.release_all(session_id, player)
|
||||
player = player or 0
|
||||
for _, btn in pairs(M.BUTTON) do
|
||||
M.release(session_id, btn, player)
|
||||
end
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- Direction Shortcuts
|
||||
-- ============================================================================
|
||||
|
||||
---Tap UP button
|
||||
---@param session_id string Session identifier
|
||||
---@param player? number Player number (default 0)
|
||||
function M.up(session_id, player)
|
||||
M.tap(session_id, M.BUTTON.UP, player)
|
||||
end
|
||||
|
||||
---Tap DOWN button
|
||||
---@param session_id string Session identifier
|
||||
---@param player? number Player number (default 0)
|
||||
function M.down(session_id, player)
|
||||
M.tap(session_id, M.BUTTON.DOWN, player)
|
||||
end
|
||||
|
||||
---Tap LEFT button
|
||||
---@param session_id string Session identifier
|
||||
---@param player? number Player number (default 0)
|
||||
function M.left(session_id, player)
|
||||
M.tap(session_id, M.BUTTON.LEFT, player)
|
||||
end
|
||||
|
||||
---Tap RIGHT button
|
||||
---@param session_id string Session identifier
|
||||
---@param player? number Player number (default 0)
|
||||
function M.right(session_id, player)
|
||||
M.tap(session_id, M.BUTTON.RIGHT, player)
|
||||
end
|
||||
|
||||
---Hold a direction
|
||||
---@param session_id string Session identifier
|
||||
---@param direction string "up", "down", "left", "right"
|
||||
---@param duration_ms number How long to hold in milliseconds
|
||||
---@param player? number Player number (default 0)
|
||||
function M.hold_direction(session_id, direction, duration_ms, player)
|
||||
M.press(session_id, direction, player)
|
||||
sleep(duration_ms)
|
||||
M.release(session_id, direction, player)
|
||||
end
|
||||
|
||||
---Move in a diagonal direction
|
||||
---@param session_id string Session identifier
|
||||
---@param horizontal string "left" or "right"
|
||||
---@param vertical string "up" or "down"
|
||||
---@param duration_ms? number Hold duration (default 50)
|
||||
---@param player? number Player number (default 0)
|
||||
function M.diagonal(session_id, horizontal, vertical, duration_ms, player)
|
||||
duration_ms = duration_ms or 50
|
||||
M.press(session_id, horizontal, player)
|
||||
M.press(session_id, vertical, player)
|
||||
sleep(duration_ms)
|
||||
M.release(session_id, horizontal, player)
|
||||
M.release(session_id, vertical, player)
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- Analog Stick Input
|
||||
-- ============================================================================
|
||||
|
||||
---Set analog stick position
|
||||
---@param session_id string Session identifier
|
||||
---@param stick string "left" or "right"
|
||||
---@param x number -1.0 to 1.0 (left to right)
|
||||
---@param y number -1.0 to 1.0 (up to down)
|
||||
---@param player? number Player number (default 0)
|
||||
function M.set_analog(session_id, stick, x, y, player)
|
||||
player = player or 0
|
||||
http.post("/api/v1/retro/sessions/" .. session_id .. "/input/analog", {
|
||||
player = player,
|
||||
stick = stick,
|
||||
x = math.max(-1.0, math.min(1.0, x)),
|
||||
y = math.max(-1.0, math.min(1.0, y))
|
||||
})
|
||||
end
|
||||
|
||||
---Center (release) analog stick
|
||||
---@param session_id string Session identifier
|
||||
---@param stick string "left" or "right"
|
||||
---@param player? number Player number (default 0)
|
||||
function M.center_analog(session_id, stick, player)
|
||||
M.set_analog(session_id, stick, 0, 0, player)
|
||||
end
|
||||
|
||||
---Move analog stick in a direction and return to center
|
||||
---@param session_id string Session identifier
|
||||
---@param stick string "left" or "right"
|
||||
---@param x number -1.0 to 1.0 horizontal axis
|
||||
---@param y number -1.0 to 1.0 vertical axis
|
||||
---@param duration_ms? number How long to hold (default 100)
|
||||
---@param player? number Player number (default 0)
|
||||
function M.flick_analog(session_id, stick, x, y, duration_ms, player)
|
||||
duration_ms = duration_ms or 100
|
||||
M.set_analog(session_id, stick, x, y, player)
|
||||
sleep(duration_ms)
|
||||
M.center_analog(session_id, stick, player)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,125 @@
|
||||
-- Tests for permission access checking
|
||||
-- Tests check_access function with various scenarios
|
||||
|
||||
local checkAccess = require("permissions.check_access")
|
||||
|
||||
describe("Permission Access Checking", function()
|
||||
|
||||
describe("Basic access checks", function()
|
||||
it("should allow access when user level meets requirement", function()
|
||||
local result = checkAccess.check_access(3, {
|
||||
enabled = true,
|
||||
minLevel = 2
|
||||
})
|
||||
assert.is_true(result.allowed)
|
||||
assert.is_nil(result.reason)
|
||||
end)
|
||||
|
||||
it("should deny access when user level is too low", function()
|
||||
local result = checkAccess.check_access(1, {
|
||||
enabled = true,
|
||||
minLevel = 3
|
||||
})
|
||||
assert.is_false(result.allowed)
|
||||
assert.equals("Insufficient permission level", result.reason)
|
||||
assert.equals(3, result.requiredLevel)
|
||||
end)
|
||||
|
||||
it("should deny access when resource is disabled", function()
|
||||
local result = checkAccess.check_access(5, {
|
||||
enabled = false,
|
||||
minLevel = 1
|
||||
})
|
||||
assert.is_false(result.allowed)
|
||||
assert.equals("Resource is currently disabled", result.reason)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("Database requirements", function()
|
||||
it("should allow access when database is enabled and required", function()
|
||||
local result = checkAccess.check_access(3, {
|
||||
enabled = true,
|
||||
minLevel = 2,
|
||||
databaseRequired = true
|
||||
}, {}, true)
|
||||
assert.is_true(result.allowed)
|
||||
end)
|
||||
|
||||
it("should deny access when database is disabled but required", function()
|
||||
local result = checkAccess.check_access(3, {
|
||||
enabled = true,
|
||||
minLevel = 2,
|
||||
databaseRequired = true
|
||||
}, {}, false)
|
||||
assert.is_false(result.allowed)
|
||||
assert.equals("Database is required but not enabled", result.reason)
|
||||
end)
|
||||
|
||||
it("should allow access when database is disabled and not required", function()
|
||||
local result = checkAccess.check_access(3, {
|
||||
enabled = true,
|
||||
minLevel = 2
|
||||
}, {}, false)
|
||||
assert.is_true(result.allowed)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("Feature flags", function()
|
||||
it("should allow access when all required flags are enabled", function()
|
||||
local result = checkAccess.check_access(3, {
|
||||
enabled = true,
|
||||
minLevel = 2,
|
||||
featureFlags = {"flag1", "flag2"}
|
||||
}, {
|
||||
flag1 = true,
|
||||
flag2 = true
|
||||
})
|
||||
assert.is_true(result.allowed)
|
||||
end)
|
||||
|
||||
it("should deny access when required flag is missing", function()
|
||||
local result = checkAccess.check_access(3, {
|
||||
enabled = true,
|
||||
minLevel = 2,
|
||||
featureFlags = {"flag1", "flag2"}
|
||||
}, {
|
||||
flag1 = true,
|
||||
flag2 = false
|
||||
})
|
||||
assert.is_false(result.allowed)
|
||||
assert.equals("Required feature flag 'flag2' is not enabled", result.reason)
|
||||
end)
|
||||
|
||||
it("should allow access when no flags are required", function()
|
||||
local result = checkAccess.check_access(3, {
|
||||
enabled = true,
|
||||
minLevel = 2
|
||||
}, {})
|
||||
assert.is_true(result.allowed)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("Combined checks", function()
|
||||
it("should pass all checks when all requirements are met", function()
|
||||
local result = checkAccess.check_access(5, {
|
||||
enabled = true,
|
||||
minLevel = 4,
|
||||
databaseRequired = true,
|
||||
featureFlags = {"advanced_mode"}
|
||||
}, {
|
||||
advanced_mode = true
|
||||
}, true)
|
||||
assert.is_true(result.allowed)
|
||||
end)
|
||||
|
||||
it("should fail on first check that doesn't pass", function()
|
||||
local result = checkAccess.check_access(3, {
|
||||
enabled = false,
|
||||
minLevel = 4,
|
||||
databaseRequired = true
|
||||
}, {}, true)
|
||||
assert.is_false(result.allowed)
|
||||
assert.equals("Resource is currently disabled", result.reason)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
@@ -1,4 +1,6 @@
|
||||
-- This file has been split into smaller modules in editor/
|
||||
-- Use require("editor") or the individual submodules instead
|
||||
--- This file has been split into smaller modules in editor/
|
||||
--- Use require("editor") or the individual submodules instead
|
||||
---@module editor
|
||||
---@deprecated Use editor.init instead
|
||||
|
||||
return require("editor.init")
|
||||
|
||||
Reference in New Issue
Block a user