435 lines
12 KiB
Lua
435 lines
12 KiB
Lua
-- ME空间原件控制器
|
||
-- 功能: 管理ME空间原件的存储和切换
|
||
--printUtf8 = load(http.get("https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8ptrint.lua").readAll())()
|
||
|
||
--function print(a)
|
||
-- printUtf8(a,colors.white,colors.lightGray)
|
||
--end
|
||
|
||
-- 全局变量
|
||
CONFIG_FILE = "config.cfg"
|
||
CHECK_INTERVAL = 2 -- 检测间隔(秒)
|
||
REDSTONE_PULSE_INTERVAL = 0.1 -- 红石脉冲间隔(秒)
|
||
MAX_WAIT_CYCLES = 30 -- 最大等待循环次数
|
||
|
||
peripherals = nil
|
||
config = nil
|
||
|
||
-- 初始化外围设备
|
||
local function initPeripherals()
|
||
-- 左侧: 红网网卡
|
||
local left = peripheral.getType("left")
|
||
if left ~= "modem" then
|
||
error("左侧没有找到红网网卡!")
|
||
end
|
||
|
||
-- 从配置读取监听端口
|
||
local listenPort = config.rednet_ports and config.rednet_ports.listen or 101
|
||
peripheral.wrap("left").open(listenPort) -- 打开监听端口
|
||
|
||
-- 右侧: 扬声器
|
||
local right = peripheral.getType("right")
|
||
if right ~= "speaker" then
|
||
print("警告: 右侧没有找到扬声器")
|
||
end
|
||
|
||
-- 前方: 空间IO端口
|
||
local front = peripheral.getType("front")
|
||
if front ~= "ae2:spatial_io_port" then
|
||
error("前方没有找到空间IO端口!")
|
||
end
|
||
|
||
return {
|
||
modem = peripheral.wrap("left"),
|
||
speaker = peripheral.wrap("right"),
|
||
spatial_io = peripheral.wrap("front")
|
||
}
|
||
end
|
||
|
||
-- 读取配置文件
|
||
local function readConfig()
|
||
if not fs.exists(CONFIG_FILE) then
|
||
-- 创建默认配置文件
|
||
local defaultConfig = {
|
||
current_disk = nil,
|
||
current_slot = nil,
|
||
disks = {}, -- 格式: {["显示名称"] = 槽位编号}
|
||
rednet_ports = {
|
||
listen = 101, -- 监听端口
|
||
status = 100, -- 状态发送端口
|
||
response = 102 -- 响应发送端口
|
||
}
|
||
}
|
||
|
||
local file = fs.open(CONFIG_FILE, "w")
|
||
file.write(textutils.serialize(defaultConfig))
|
||
file.close()
|
||
|
||
print("已创建默认配置文件,请手动编辑 " .. CONFIG_FILE .. " 配置原件映射")
|
||
return defaultConfig
|
||
end
|
||
|
||
local file = fs.open(CONFIG_FILE, "r")
|
||
local content = file.readAll()
|
||
file.close()
|
||
|
||
local loadedConfig = textutils.unserialize(content) or {
|
||
current_disk = nil,
|
||
current_slot = nil,
|
||
disks = {}
|
||
}
|
||
|
||
-- 确保端口配置存在
|
||
if not loadedConfig.rednet_ports then
|
||
loadedConfig.rednet_ports = {
|
||
listen = 101,
|
||
status = 100,
|
||
response = 102
|
||
}
|
||
else
|
||
-- 设置默认值
|
||
loadedConfig.rednet_ports.listen = loadedConfig.rednet_ports.listen or 101
|
||
loadedConfig.rednet_ports.status = loadedConfig.rednet_ports.status or 100
|
||
loadedConfig.rednet_ports.response = loadedConfig.rednet_ports.response or 102
|
||
end
|
||
|
||
return loadedConfig
|
||
end
|
||
|
||
-- 写入配置文件
|
||
-- 写入配置文件
|
||
local function writeConfig()
|
||
-- 创建按槽位排序的disks表
|
||
local sortedDisks = {}
|
||
|
||
-- 先将disks转换为数组形式进行排序
|
||
local tempArray = {}
|
||
for name, slot in pairs(config.disks) do
|
||
table.insert(tempArray, {name = name, slot = slot})
|
||
end
|
||
|
||
-- 按槽位排序
|
||
table.sort(tempArray, function(a, b)
|
||
return a.slot < b.slot
|
||
end)
|
||
|
||
-- 重新构建有序的disks表
|
||
for _, item in ipairs(tempArray) do
|
||
sortedDisks[item.name] = item.slot
|
||
end
|
||
|
||
-- 创建临时配置,使用排序后的disks
|
||
local configToSave = {
|
||
rednet_ports = config.rednet_ports,
|
||
current_disk = config.current_disk,
|
||
current_slot = config.current_slot,
|
||
disks = sortedDisks
|
||
}
|
||
|
||
local file = fs.open(CONFIG_FILE, "w")
|
||
file.write(textutils.serialize(configToSave))
|
||
file.close()
|
||
end
|
||
|
||
-- 播放声音提示
|
||
local function playSound(soundType)
|
||
if peripherals.speaker then
|
||
pcall(function()
|
||
if soundType == "success" then
|
||
peripherals.speaker.playSound("block.note_block.pling", 1.0, 2.0)
|
||
elseif soundType == "working" then
|
||
for i=1,3 do
|
||
peripherals.speaker.playSound("block.note_block.bass", 3, 1)
|
||
sleep(1)
|
||
end
|
||
elseif soundType == "error" then
|
||
peripherals.speaker.playSound("block.note_block.bass", 1.0, 0.5)
|
||
end
|
||
end)
|
||
end
|
||
end
|
||
|
||
-- 发送红石脉冲
|
||
local function sendRedstonePulse()
|
||
redstone.setOutput("front", true)
|
||
sleep(0.1)
|
||
redstone.setOutput("front", false)
|
||
end
|
||
|
||
-- 发送状态信息到红网
|
||
local function sendStatusUpdate()
|
||
-- 从配置读取端口
|
||
local statusPort = config.rednet_ports.status
|
||
local listenPort = config.rednet_ports.listen
|
||
|
||
-- 通过红网发送状态
|
||
peripherals.modem.transmit(statusPort, listenPort, {
|
||
type = "status_update",
|
||
current_disk = config.current_disk,
|
||
disks = config.disks,
|
||
timestamp = os.time()
|
||
})
|
||
|
||
print("状态已发送到端口 " .. statusPort .. ": 当前原件=" .. (config.current_disk or "无"))
|
||
end
|
||
|
||
-- 检查空间IO端口状态
|
||
local function checkSpatialIOState()
|
||
local slots = peripherals.spatial_io.list()
|
||
local state = {
|
||
slot1 = slots[1], -- 第一格: 未放出/已收回
|
||
slot2 = slots[2] -- 第二格: 已放出
|
||
}
|
||
return state
|
||
end
|
||
|
||
-- 验证槽位是否有物品
|
||
local function validateSlotHasItem(slot)
|
||
local item = turtle.getItemDetail(slot)
|
||
return item ~= nil
|
||
end
|
||
|
||
-- 收回当前原件
|
||
local function retractCurrentDisk()
|
||
if not config.current_disk or not config.current_slot then
|
||
return true -- 没有当前原件,直接返回成功
|
||
end
|
||
|
||
print("开始收回原件: " .. config.current_disk)
|
||
|
||
-- 切换到当前原件槽位
|
||
turtle.select(config.current_slot)
|
||
|
||
-- 尝试从空间IO端口拿取
|
||
if turtle.suck() then
|
||
print("235 原件已取回")
|
||
end
|
||
|
||
-- 将原件放入空间IO端口
|
||
if not turtle.drop() then
|
||
error("无法放入空间IO端口")
|
||
end
|
||
|
||
print("通过红石信号收回原件...")
|
||
|
||
local waitCycles = 0
|
||
while waitCycles < MAX_WAIT_CYCLES do
|
||
-- 发送红石脉冲
|
||
sendRedstonePulse()
|
||
|
||
-- 检查空间IO端口状态
|
||
local state = checkSpatialIOState()
|
||
|
||
if state.slot2 and not state.slot1 then
|
||
-- 原件已回到第2格,尝试拿取
|
||
if turtle.suck() then
|
||
print("原件收回成功")
|
||
return true
|
||
end
|
||
end
|
||
|
||
sleep(REDSTONE_PULSE_INTERVAL)
|
||
waitCycles = waitCycles + 1
|
||
end
|
||
|
||
print("收回原件超时!")
|
||
return false
|
||
end
|
||
|
||
-- 放出目标原件
|
||
local function deployTargetDisk(targetDisk)
|
||
local targetSlot = config.disks[targetDisk]
|
||
if not targetSlot then
|
||
error("未找到原件: " .. targetDisk)
|
||
end
|
||
|
||
-- 验证槽位
|
||
if not validateSlotHasItem(targetSlot) then
|
||
error("槽位 " .. targetSlot .. " 没有物品,无法放出")
|
||
end
|
||
|
||
print("开始放出原件: " .. targetDisk)
|
||
|
||
-- 切换到目标槽位
|
||
turtle.select(targetSlot)
|
||
|
||
-- 将原件放入空间IO端口
|
||
if not turtle.drop() then
|
||
error("无法放入空间IO端口")
|
||
end
|
||
|
||
-- 通过红石信号激活放出
|
||
print("通过红石信号放出原件...")
|
||
|
||
local waitCycles = 0
|
||
while waitCycles < MAX_WAIT_CYCLES do
|
||
-- 发送红石脉冲
|
||
sendRedstonePulse()
|
||
|
||
-- 检查空间IO端口状态
|
||
local state = checkSpatialIOState()
|
||
|
||
if state.slot2 and not state.slot1 then
|
||
-- 原件已移动到第二格,放出成功
|
||
print("原件放出成功")
|
||
return true
|
||
end
|
||
|
||
sleep(REDSTONE_PULSE_INTERVAL)
|
||
waitCycles = waitCycles + 1
|
||
end
|
||
|
||
print("放出原件超时!")
|
||
return false
|
||
end
|
||
|
||
-- 切换到指定原件
|
||
local function switchToDisk(targetDisk)
|
||
print("收到切换命令: " .. targetDisk)
|
||
|
||
-- 检查是否已经是目标原件
|
||
if config.current_disk == targetDisk then
|
||
print("已经是目标原件,无需切换")
|
||
playSound("success")
|
||
return true
|
||
end
|
||
|
||
-- 检查目标原件是否存在
|
||
if not config.disks[targetDisk] then
|
||
print("错误: 未配置原件 '" .. targetDisk .. "'")
|
||
playSound("error")
|
||
return false
|
||
end
|
||
|
||
playSound("working")
|
||
|
||
-- 收回当前原件
|
||
if not retractCurrentDisk() then
|
||
playSound("error")
|
||
return false
|
||
end
|
||
|
||
-- 放出目标原件
|
||
if not deployTargetDisk(targetDisk) then
|
||
playSound("error")
|
||
return false
|
||
end
|
||
|
||
-- 更新配置文件
|
||
config.current_disk = targetDisk
|
||
config.current_slot = config.disks[targetDisk]
|
||
writeConfig()
|
||
|
||
playSound("success")
|
||
print("切换完成: " .. targetDisk)
|
||
sendStatusUpdate() -- 发送状态更新
|
||
return true
|
||
end
|
||
|
||
-- 处理红网消息
|
||
local function handleRednetMessage(message)
|
||
local responsePort = config.rednet_ports.response
|
||
local listenPort = config.rednet_ports.listen
|
||
|
||
if message.type == "switch_disk" and message.disk_name then
|
||
local success = switchToDisk(message.disk_name)
|
||
|
||
-- 发送响应
|
||
peripherals.modem.transmit(responsePort, listenPort, {
|
||
type = "switch_response",
|
||
disk_name = message.disk_name,
|
||
success = success,
|
||
timestamp = os.time()
|
||
})
|
||
|
||
elseif message.type == "status_request" then
|
||
-- 发送状态信息
|
||
peripherals.modem.transmit(responsePort, listenPort, {
|
||
type = "status_response",
|
||
current_disk = config.current_disk,
|
||
disks = config.disks,
|
||
timestamp = os.time()
|
||
})
|
||
elseif message.type == "reload_config" then
|
||
-- 重新加载配置
|
||
config = readConfig()
|
||
peripherals.modem.transmit(responsePort, listenPort, {
|
||
type = "reload_response",
|
||
success = true,
|
||
timestamp = os.time()
|
||
})
|
||
print("配置已重新加载")
|
||
end
|
||
end
|
||
|
||
-- 主循环 - 状态发送
|
||
local function main()
|
||
print("ME空间原件控制器启动中...")
|
||
|
||
|
||
print("1 外围设备初始化完成")
|
||
print("2 当前原件: " .. (config.current_disk or "无"))
|
||
print("3 配置的原件: ")
|
||
for name, slot in pairs(config.disks) do
|
||
print(" " .. name .. " -> 槽位 " .. slot)
|
||
end
|
||
print("4 红网端口配置: ")
|
||
print(" 监听端口: " .. config.rednet_ports.listen)
|
||
print(" 状态端口: " .. config.rednet_ports.status)
|
||
print(" 响应端口: " .. config.rednet_ports.response)
|
||
|
||
-- 初始状态发送
|
||
sendStatusUpdate()
|
||
|
||
while true do
|
||
sleep(CHECK_INTERVAL)
|
||
sendStatusUpdate()
|
||
end
|
||
end
|
||
|
||
-- 主循环 - 消息监听
|
||
local function main1()
|
||
local listenPort = config.rednet_ports.listen
|
||
|
||
while true do
|
||
-- 检查红网消息
|
||
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||
if channel == listenPort and type(message) == "table" then
|
||
handleRednetMessage(message)
|
||
end
|
||
end
|
||
end
|
||
|
||
-- 初始化检查
|
||
if not turtle then
|
||
error("这个脚本需要在海龟上运行!")
|
||
end
|
||
|
||
-- 检查配置文件是否存在,如果不存在则创建并提示
|
||
if not fs.exists(CONFIG_FILE) then
|
||
config = readConfig() -- 这会创建默认配置文件
|
||
print("请编辑 " .. CONFIG_FILE .. " 文件配置原件映射,格式如下:")
|
||
print("{")
|
||
print(' current_disk = "原件A",')
|
||
print(' current_slot = 1,')
|
||
print(' disks = {')
|
||
print(' ["原件A"] = 1,')
|
||
print(' ["原件B"] = 2,')
|
||
print(' ["原件C"] = 3')
|
||
print(" },")
|
||
print(' rednet_ports = {')
|
||
print(' listen = 101, -- 监听端口')
|
||
print(' status = 100, -- 状态发送端口')
|
||
print(' response = 102 -- 响应发送端口')
|
||
print(" }")
|
||
print("}")
|
||
print("配置完成后重新启动脚本")
|
||
return
|
||
end
|
||
|
||
|
||
config = readConfig()
|
||
peripherals = initPeripherals()
|
||
|
||
-- 启动程序
|
||
parallel.waitForAny(main, main1) |