-- Copyright (c) 2025 Cainiao1053. All Rights Reserved.
-- This code is protected under copyright law. Unauthorized reproduction, distribution, modification, or any derivative works are strictly prohibited without explicit written permission from the copyright holder.
-- Use of this code is restricted solely to its intended purpose within The Adventure of Valkyrienskies. Any other use, including commercial use, redistribution, or reverse engineering, is forbidden without prior authorization.
function mat_mul(A, B)
local m, n, p = #A, #A[1], #B[1]
local C = {}
for i = 1, m do
C[i] = {}
for j = 1, p do
C[i][j] = 0
for k = 1, n do
C[i][j] = C[i][j] + A[i][k] * B[k][j]
end
end
end
return C
end
local function dot(a, b)
local s = 0
for i = 1, #a do s = s + a[i] * b[i] end
return s
end
local function mat_mult(A, B)
local M = { {}, {}, {} }
for i = 1, 3 do for j = 1, 3 do M[i][j] = A[i][1] * B[1][j] + A[i][2] * B[2][j] + A[i][3] * B[3][j] end end
return M
end
function get_euler(direction)
local R
if direction == "east" then
R = { { 0, 0, 1 }, { 0, 1, 0 }, { -1, 0, 0 } }
elseif direction == "west" then
R = { { 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 } }
elseif direction == "south" then
R = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }
elseif direction == "north" then
R = { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, -1 } }
else
error("No direction selected")
end
local M = ship.getTransformationMatrix()
M = mat_mult(M, R)
local yaw, pitch, roll, yawMatrix = math.atan2(-M[1][3], M[3][3]), -math.asin(M[2][3]), math.atan2(M[2][1], M[2][2]),
{ { M[1][1], M[1][3] }, { M[3][1], M[3][3] } }
return yaw, pitch, roll, yawMatrix
end
local function sizeLimit(val, lim) -- lim is positive definite
if val > lim then
val = lim
elseif val < -lim then
val = -lim
end
return val
end
local function sizeLimitPositive(val, lim) -- lim is positive definite
if val > lim then
val = lim
elseif val < 0 then
val = 0
end
return val
end
local function inPhase(val) -- lim is positive definite
if val > math.pi then
val = val - 2 * math.pi
elseif val < -math.pi then
val = val + 2 * math.pi
end
return val
end
function mat_inv_2x2(A)
local a, b = A[1][1], A[1][2]
local c, d = A[2][1], A[2][2]
local det = a * d - b * c
if math.abs(det) < 1e-8 then error("Cannot Inverse") end
return {
{ d / det, -b / det },
{ -c / det, a / det }
}
end
function getTgtRotMatrix(x0, z0, xt, zt)
local dx = xt - x0
local dz = zt - z0
local dist = math.sqrt(dx ^ 2 + dz ^ 2)
local Rt = { { dz / dist, -dx / dist },
{ dx / dist, dz / dist } }
return Rt
end
function getTgtRotVector(x0, z0, xt, zt)
local dx = xt - x0
local dz = zt - z0
local dist = math.sqrt(dx ^ 2 + dz ^ 2)
local Rt = { { -dx },
{ dz } }
return Rt, dist
end
local function serializeTable(t, indent) --serialize table to save in a file
indent = indent or ""
local result = "{\n"
local nextIndent = indent .. " "
for k, v in pairs(t) do
local keyStr
if type(k) == "string" then
keyStr = string.format("[%q]", k)
else
keyStr = string.format("[%d]", k)
end
local valueStr
if type(v) == "table" then
valueStr = serializeTable(v, nextIndent)
elseif type(v) == "string" then
valueStr = string.format("%q", v)
else
valueStr = tostring(v)
end
result = result .. nextIndent .. keyStr .. " = " .. valueStr .. ",\n"
end
result = result .. indent .. "}"
return result
end
function saveToFile(fileName, tableName)
local file = io.open(fileName, "w")
file:write("return " .. serializeTable(tableName))
file:close()
end
-- This Project is done by Cainiao1053 and follows the Liscence @All Rights Reserved
-- Commercial use, copy or edit without permission form the owner are NOT allowed
function writeText(text, w, line) -- write text to the central of a line
term.setCursorPos(w / 2 - string.len(text) / 2, line);
term.write(text);
end
function writeTextOnRight(text, w, line)
term.setCursorPos(w - string.len(text), line);
term.write(text);
end
function clearWriteText(text, w, line) -- write text to the central of a line
term.setCursorPos(w / 2 - string.len(text) / 2, line);
term.clearLine()
term.write(text);
end
function DrawBackground(w, h, bgcolor, titlecolor, titletextcolor, textcolor, title)
term.clear()
paintutils.drawFilledBox(1, 1, w, h, bgcolor);
paintutils.drawFilledBox(1, 1, w, 1, titlecolor);
term.setBackgroundColor(titlecolor);
term.setTextColor(titletextcolor);
writeText(title, w, 1)
writeTextOnRight("ID: " .. selfID, w, 1)
term.setBackgroundColor(bgcolor);
term.setTextColor(textcolor);
end
function writeLines(context, textcolor, bgcolor, startline, maxlength, startContext) -- take table as input
local startContext = startContext or 1
local lines = #context
if lines > maxlength + startContext - 1 then
lines = maxlength + startContext - 1
end
term.setBackgroundColor(bgcolor);
term.setTextColor(textcolor);
for i = startContext, lines do
writeText(context[i], w, i + startline - startContext)
end
end
function writeCoordLines(context, textcolor, bgcolor, startline, maxlength, startContext) -- take table as input
local startContext = startContext or 1
local lines = #context
if lines > maxlength + startContext - 1 then
lines = maxlength + startContext - 1
end
term.setBackgroundColor(bgcolor);
term.setTextColor(textcolor);
for i = startContext, lines do
writeText("X: " .. context[i][1] .. " Y: " .. context[i][2] .. " Z: " .. context[i][3], w,
i + startline - startContext)
end
end
function clearWriteLines(context, textcolor, bgcolor, startline, maxlength, startContext) -- take table as input
local startContext = startContext or 1
local lines = #context
if lines > maxlength + startContext - 1 then
lines = maxlength + startContext - 1
end
term.setBackgroundColor(bgcolor);
term.setTextColor(textcolor);
for i = startContext, lines do
clearWriteText(context[i], w, i + startline - startContext)
end
end
function drawButton(text, line, backgroundcolor, buttoncolor)
term.setBackgroundColor(buttoncolor);
writeText(text, w, line)
term.setBackgroundColor(backgroundcolor);
end
function writePageFlip(w, h, buttoncolor, backgroundcolor, leftIcon, rightIcon)
local leftIcon = leftIcon or "<<"
local rightIcon = rightIcon or ">>"
term.setBackgroundColor(buttoncolor)
term.setCursorPos(w / 4, h);
term.write(leftIcon);
term.setCursorPos(3 * w / 4, h);
term.write(rightIcon);
term.setBackgroundColor(backgroundcolor)
end
function getPageAndRem(context, numPerPage)
local total = #context
local page = math.floor(total / numPerPage) + 1
local rem = total % numPerPage
return page, rem
end
function getChatBoxContent(chatMessage)
if string.find(chatMessage, "xaero%-waypoint") ~= nil then
local chatLocation = {};
local locationPointer = 0
for word in string.gmatch(chatMessage, "[%~%-%d]+") do
locationPointer = locationPointer + 1;
chatLocation[locationPointer] = word;
end
local chatX = tonumber(chatLocation[2]);
local chatZ = tonumber(chatLocation[4]);
if type(chatX) == "number" and type(chatZ) == "number" then
chatbox.sendMessageToPlayer("Point Added", currentOwner, systemTitle);
return { chatX, "undefined", chatZ }
else
chatbox.sendMessageToPlayer("Can't add point na you FAILURE", currentOwner, systemTitle);
end
else
chatbox.sendMessageToPlayer("Can't add point na you FAILURE", currentOwner, systemTitle);
end
end
function getPlayerPos(player)
local PL = coord.getPlayersAll(ownerScanRange)
local hasPlayer = false
local dir = 0
local playerX = 0
local playerZ = 0
local playerY = 0
for key, val in pairs(PL) do
if val.name == player then
dir = val.viewVector
playerX = val.x
playerZ = val.z
playerY = val.y
hasPlayer = true
end
end
return hasPlayer, dir, playerX, playerZ, playerY
end
function scanPlayersAround()
local PL = coord.getPlayersAll(ownerScanRange)
local players = {}
for key, val in pairs(PL) do
table.insert(players, val.name)
end
return players
end
function changeMODE()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
writeText("Select Mode", w, 2)
writeLines(validModes, textcolor, backgroundcolor, 3, 8)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
if validModes[cursy - 2] and cursy - 2 ~= modeSwitch then
modeSwitch = cursy - 2
takeRedstone = false
if modeSwitch == 1 or modeSwitch == 2 then
controlMode = 1
currentRoute = {}
elseif modeSwitch == 3 then
end
clearWriteText("Change to: " .. validModes[modeSwitch], w, 2)
mainText[2] = "Current Mode: " .. validModes[modeSwitch]
end
end
function switchModeOperations()
if validModes[modeSwitch] then
modeOperations[modeSwitch]()
end
end
function switchModeSettings()
end
function viewStatus()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
local statusText = { "Ship Name: " .. ship.getName(), "Ship ID: " .. ship.getId(), "Ship Mass: " ..
tostring(ship.getMass() / 1000) .. " t", "Constraint Num: " .. tostring(#ship.getConstraints() / 3) }
writeLines(statusText, textcolor, backgroundcolor, 2, 10)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
end
-- point mode
function pointModeOperation()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
pointModeText = { "Add New Point", "View Point List", "Delete Points" }
pointModeFunctions = { AddNewPoint, viewPointList, deletePoints }
writeLines(pointModeText, textcolor, backgroundcolor, 2, 10)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
if pointModeFunctions[cursy - 1] then
pointModeFunctions[cursy - 1]()
end
end
function AddNewPoint()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
addPointContext = { "Type Coord", "Select From Minimap", "Select On Screen" }
addPointFunctions = { typeCoordToPoint, selectFromMinimap, screenMapSelect }
writeLines(addPointContext, textcolor, backgroundcolor, 2, 10)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
if addPointFunctions[cursy - 1] then
addPointFunctions[cursy - 1]()
end
end
function typeCoordToPoint()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
local newCoordX
local newCoordZ
writeText("Type in X coord", w, 2)
term.setCursorPos(w / 2 - 2, 3)
newCoordX = tonumber(read())
writeText("Type in Z coord", w, 4)
term.setCursorPos(w / 2 - 2, 5)
newCoordZ = tonumber(read())
if type(newCoordX) == "number" and type(newCoordZ) == "number" then
local newCoord = { newCoordX, "undefined", newCoordZ }
table.insert(currentRoute, newCoord)
writeText("Successful Added", w, 8)
else
writeText("Fail to Add Points", w, 8)
end
sleep(0.3)
end
function selectFromMinimap()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
if chatbox then
writeText("Share A Point From Minimap To Add", w, 2)
local event = ""
local chatUser = ""
local chatMessage = ""
while chatUser ~= currentOwner do
event, chatUser, chatMessage = os.pullEvent("chat")
local newPoint = getChatBoxContent(chatMessage)
if newPoint then
table.insert(currentRoute, newPoint)
end
sleep(0.1)
end
else
writeText("Chat Box not Installed", w, 2)
end
end
function screenMapSelect()
end
function viewPointList()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
writeText("Current Points on Route", w, 2)
local pointNum = #currentRoute
if pointNum > 0 then
writeCoordLines(currentRoute, textcolor, backgroundcolor, 3, h - 5)
else
writeText("List is Empty", w, 3)
end
sleep(0.2)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
end
function deletePoints()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
writeText("Select Point to Delete", w, 2)
writeCoordLines(currentRoute, textcolor, backgroundcolor, 3, h - 5)
drawButton("Delete All", h - 3, backgroundcolor, buttoncolor)
drawButton("Back", h - 2, backgroundcolor, buttoncolor)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
if cursy < h - 3 then
if currentRoute[cursy - 2] then
table.remove(currentRoute, cursy - 2)
clearWriteText("Point Deleted", w, 2)
sleep(0.3)
end
elseif cursy == h - 3 then
currentRoute = {}
clearWriteText("Route Cleared", w, 2)
sleep(0.5)
elseif cursy == h - 2 then
end
end
function pointModeSettings()
end
-- pin mode
function pinModeOperation()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
pinModeText = { "Current Distance: " .. pathDistance, "Enable", "disable", "Change Distance", "STOP",
"Backward Mode: " .. tostring(backwardMove) }
writeLines(pinModeText, textcolor, backgroundcolor, 2, 10)
writePageFlip(w, 5, buttoncolor, backgroundcolor, "-25", "+25")
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
if cursy == 3 then
takeRedstone = true
clearWriteText("Enabled Pin Action", w, 2)
elseif cursy == 4 then
takeRedstone = false
clearWriteText("Disabled Pin Action", w, 2)
elseif cursy == 5 then
while cursy == 5 do
evn, but, cursx, cursy = os.pullEvent("mouse_click");
if cursx <= w / 2 and cursy == 5 then
pathDistance = pathDistance - 25
elseif cursx > w / 2 and cursy == 5 then
pathDistance = pathDistance + 25
end
if pathDistance < 50 then
pathDistance = 50
elseif pathDistance > 350 then
pathDistance = 350
end
clearWriteText("Current Distance: " .. pathDistance, w, 2)
sleep(0.25)
end
elseif cursy == 6 then
currentRoute = {}
writeText("Ship Stopped", w, 2)
elseif cursy == 7 then
if backwardMove == true then
backwardMove = false
else
backwardMove = true
end
end
end
function pinModeSettings()
end
-- player navigation
function playerNavigationOperation()
end
function playerNavigationSettings()
end
function setOwner()
local players = scanPlayersAround()
local quitSelect = false
local pages, rem = getPageAndRem(players, h - 6)
local currentPage = 1
while quitSelect == false do
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
writeText("Select Player As Owner", w, 2)
writePageFlip(w, h - 2, buttoncolor, backgroundcolor)
drawButton("BACK", h - 1, backgroundcolor, buttoncolor)
writeLines(players, textcolor, backgroundcolor, 3, h - 6, (currentPage - 1) * (h - 6) + 1)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
local selected = cursy + (currentPage - 1) * (h - 6) - 2
if players[selected] and cursy < h - 3 then
currentOwner = players[selected]
mainText[5] = "Current Owner: " .. players[selected]
clearWriteText("Set Owner to: " .. players[selected], w, 2)
quitSelect = true
elseif cursy == h - 2 then
if cursx <= w / 2 then
if currentPage > 1 then
currentPage = currentPage - 1
end
elseif cursx > w / 2 then
if currentPage < pages then
currentPage = currentPage + 1
end
end
elseif cursy == h - 1 then
quitSelect = true
else
clearWriteText("No Such Player", w, 2)
quitSelect = true
end
sleep(0.5)
end
end
function generalPD(eP, eD, Gp, Gd)
local u = -eP * Gp - eD * Gd
return u
end
function openConfig()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
configContext = { "Remote Computer ID: " .. systemConfig.remoteControlId , "Shipyard Direction: "..systemConfig.initialDirection}
writeLines(configContext, textcolor, backgroundcolor, 2, 12)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
if cursy == 2 then
changeControlID()
elseif cursy == 3 then
changeShipyardDirect()
end
end
function changeControlID()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
writeText("Type The ID Of Control Pad", w, 2)
term.setCursorPos(w / 2 - 2, 3)
local newID = tonumber(read())
if type(newID) == "number" then
systemConfig.remoteControlId = newID
clearWriteText("Configuration Success", w, 2)
saveToFile("config.lua", systemConfig)
else
clearWriteText("Configuration Failed", w, 2)
end
sleep(0.5)
end
function changeShipyardDirect()
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
writeText("Select New Direction",w,2)
local shipyardDirectCand = {"south","west","north","east"}
writeLines(shipyardDirectCand,textcolor,backgroundcolor,3,10)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
if shipyardDirectCand[cursy-2] then
systemConfig.initialDirection = shipyardDirectCand[cursy-2]
clearWriteText("Configuration Success", w, 2)
saveToFile("config.lua", systemConfig)
else
clearWriteText("Disregard", w, 2)
end
sleep(0.5)
end
function Panel()
while true do
DrawBackground(w, h, backgroundcolor, titlecolor, titletextcolor, textcolor, systemTitle)
writeLines(mainText, textcolor, backgroundcolor, 2, 16)
local evn, but, cursx, cursy = os.pullEvent("mouse_click");
if panelOptions[cursy - 1] then
panelOptions[cursy - 1]()
end
sleep(0.5)
end
end
function playerHeading()
while true do
os.pullEvent("redstone")
if takeRedstone == true then
local hasPlayer, playerView, playerX, playerZ, playerY = getPlayerPos(currentOwner)
if hasPlayer == true then
local viewNormalizer = math.sqrt(playerView.x ^ 2 + playerView.z ^ 2)
currentRoute = { { playerX + pathDistance * playerView.x / viewNormalizer, playerY, playerZ + pathDistance * playerView.z / viewNormalizer } }
end
end
sleep(2)
end
end
function commandReceive()
sleep(1)
if modem then
modem.open(systemConfig.modemChannel)
while true do
local event, sender, message, protocol = os.pullEvent("rednet_message")
if sender == systemConfig.remoteControlId then
end
end
end
end
function mainControl()
while true do
if controlMode == 1 and currentRoute[1] then
shipYaw, shipPitch, shipRoll, yawMatrix = get_euler(systemConfig.initialDirection)
shipPos = ship.getWorldspacePosition()
targetMatrix, targetDist = getTgtRotVector(shipPos.x, shipPos.z, currentRoute[1][1], currentRoute[1][3])
velRaw = ship.getVelocity()
shipVel = dot({ yawMatrix[1][2], yawMatrix[2][2] }, { velRaw.x, velRaw.z })
errPrj = mat_mul(yawMatrix, targetMatrix)
omegaYaw = ship.getOmega().y
errPrj[2][1] = sizeLimit(errPrj[2][1], 120)
uForward = generalPD(-errPrj[2][1], shipVel, 0.07, 0.07)
if backwardMove == true then
if errPrj[2][1] < 0 then
errPrj[1][1] = -errPrj[1][1]
end
uYaw = generalPD(errPrj[1][1] / (targetDist + 1), omegaYaw, 7, 11)
uYaw = sizeLimit(uYaw, 1)
uForward = sizeLimit(uForward, 1 - math.abs(uYaw) / 1.5)
else
uYaw = generalPD(errPrj[1][1] / (targetDist + 1), omegaYaw, 7, 11)
uYaw = sizeLimit(uYaw, 1)
uForward = sizeLimitPositive(uForward, 1 - math.abs(uYaw) / 1.5)
end
helm.move(uYaw, 0, uForward)
if math.abs(shipPos.x - currentRoute[1][1]) < 12 and math.abs(shipPos.z - currentRoute[1][3]) < 12 then
table.remove(currentRoute, 1)
end
sleep(dt)
else
helm.move(0, 0, 0)
sleep(1)
end
end
end
function configInit()
local configFile = io.open("config.lua","r")
if configFile then
systemConfig = dofile("config.lua")
else
systemConfig = {}
systemConfig.shipName = "Ship"
systemConfig.defaultOwner = ""
systemConfig.remoteControlId = -1
systemConfig.modemChannel = 483
systemConfig.initialDirection = "south"
systemConfig.yawGp = 7
systemConfig.yawGd = 11
systemConfig.fwGp = 0.07
systemConfig.fwGd = 0.05
saveToFile("config.lua",systemConfig)
end
end
function initialize()
--system initialization
w, h = term.getSize()
currentOwner = systemConfig.defaultOwner
term.setPaletteColour(colors.blue, 0xA1050)
term.setPaletteColour(colors.orange, 0xE37D10)
chatbox = peripheral.find("chatBox")
currentRoute = {}
selfID = os.computerID()
--core initialization
mainText = { "STATUS", "CHANGE MODE", "OPERATION", "MODE SETTINGS", "SET OWNER", "CONFIG" }
validModes = { "POINT MODE", "PIN MODE", "VISION NAVIGATION" }
modeOperations = { pointModeOperation, pinModeOperation, playerNavigationOperation }
modeSettings = { pointModeSettings, pinModeSettings, playerNavigationSettings }
panelOptions = { viewStatus, changeMODE, switchModeOperations, switchModeSettings, setOwner, openConfig }
modeSwitch = -1
controlMode = 0
helm = peripheral.find("eureka_ship_helm")
modem = peripheral.find("modem")
takeRedstone = false
dt = 0.1
backwardMove = false
-- hardcoded configs
ownerScanRange = 200 -- the maximum range for scanning owner
backgroundcolor = colors.white
textcolor = colors.black
titlecolor = colors.blue
titletextcolor = colors.orange
buttoncolor = colors.red
systemTitle = "CAINIAOTECH"
pathDistance = 125
end
configInit()
initialize()
parallel.waitForAll(Panel, mainControl, playerHeading)
他是如何接受游戏内的聊天消息的?
最新发布