Skip to content

Instantly share code, notes, and snippets.

@object-Object
Last active August 2, 2022 22:05
Show Gist options
  • Save object-Object/8780a0929e76e5e948599d1cf468d7a0 to your computer and use it in GitHub Desktop.
Save object-Object/8780a0929e76e5e948599d1cf468d7a0 to your computer and use it in GitHub Desktop.
A Hex Casting spell circle and ComputerCraft programs to implement a /tp command.

Global Teleport

This spell and program work together to implement a /tp command with absolute coordinates in Hex Casting. Teleports you using an alt account so you don't drop your items. Designed on Fabric 1.18.2 with Hex Casting 0.9.2, CC: Restitched, and Allium Peripherals.

Commands

  • $help
  • $tp <x> <y> <z>
  • $tp <waypoint name>
  • $waypoint list
  • $waypoint add <waypoint name> <x> <y> <z>
  • $waypoint set <waypoint name> <x> <y> <z>
  • $waypoint (delete | remove) <waypoint name>

Setup

  • Build the circle with a Cleric Impetus according to GlobalTeleport.c. I'd advise making sure it's entirely within a single chunk to make chunkloading easier. The circle fits easily in one chunk. Bind the impetus to your alt account.
  • Put an Akashic Library somewhere in the world, containing your true name under the key EAST (a single line to the right). Put your alt account's Greater Sentinel inside the library.
  • Place the computer such that its left side is facing the impetus. Put a chat modem on the right side and an ender modem on the bottom. Right click the chat modem to bind it to yourself. Add a comparator pointing from one of the last slates in the circle to the computer (side doesn't matter, but use weak power to make sure it doesn't trigger the impetus again).
  • Craft 21 turtles. Give each one a diamond pickaxe on the left and a wireless modem on the right. Place each one above one of the slates marked with x_ / y_ / z_ comments, and set the turtle's name to the corresponding comment. For example, for the first turtle, do label set x_sign.
  • Create 18 slates for each number literal from 1 to 15, and 3 slates for -1. Put one -1 slate in the second slot of each sign turtle. Put one of each remaining slate in each non-sign turtle in order, leaving the first slot empty (0 goes there, but it's already in the circle). For example, the first row of the x_-1 turtle should look like [blank, 1, 2, 3].
  • On the computer, run wget https://is.gd/esolaf startup and reboot (this is a shortened link leading to https://gist.githubusercontent.com/object-Object/8780a0929e76e5e948599d1cf468d7a0/raw/computer.lua; if you don't trust it, feel free to write that link out by hand or copy the script to Pastebin).
  • On each turtle, run wget https://is.gd/orapan startup and reboot (as above, for https://gist.githubusercontent.com/object-Object/8780a0929e76e5e948599d1cf468d7a0/raw/turtle.lua).
  • On a pocket computer, run wget https://is.gd/igeyaw startup and shutdown (as above, for https://gist.githubusercontent.com/object-Object/8780a0929e76e5e948599d1cf468d7a0/raw/pocket.lua).

Usage

  • Teleport using the above commands.
  • Keep your pocket computer in a backpack. The chat modem unbinds when the server restarts. To get back to your computer and rebind it, put the pocket computer in your inventory, and it will start up and ask the computer to teleport you home.
--[[
Copyright (c) 2022 object-Object
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
local prettyPrefix = "$"
local prefix = "^%$" -- prettyPrefix with ^ at the start and all characters escaped with %
local maxNum = 1048575.9375 -- fffff.f
local turtleProtocol = "teleport"
local backupRequestProtocol = "request_teleport_home"
local backupResponseProtocol = "request_teleport_response"
local hostname = "object_Object"
local waypoints = {}
if fs.exists("waypoints.txt") then
local f = fs.open("waypoints.txt", "r")
waypoints = textutils.unserialize(f.readAll())
f.close()
end
local chat = peripheral.wrap("right")
chat.uncapture()
chat.capture(prefix)
rednet.host(backupRequestProtocol, hostname)
rednet.open("bottom")
local function say(id, message, isError, isDone)
if id == -1 then
if isError then
chat.say("§c"..message.."§r")
else
chat.say(message)
end
else
rednet.send(id, {
content = message,
color = isError and colors.red or colors.white,
final = isDone,
}, backupResponseProtocol)
end
end
local function sendToTurtle(label, value)
rednet.send(rednet.lookup(turtleProtocol, label), value, turtleProtocol)
end
local function sendHex(name, decimalNum)
if decimalNum > maxNum or decimalNum < -maxNum then
error("Number out of range: "..decimalNum)
end
local sign = decimalNum >= 0 and 1 or -1
decimalNum = math.floor(math.abs(decimalNum) * 16 + 0.5)
local digits = {0, 0, 0, 0, 0, 0}
do
local index = 1
while decimalNum ~= 0 do
local digit = decimalNum % 16
digits[index] = digit
decimalNum = math.floor(decimalNum / 16)
index = index + 1
end
end
if #digits > 6 then
error("Failed to parse number: "..decimalNum)
end
sendToTurtle(name.."_sign", sign)
for index, digit in ipairs(digits) do
sendToTurtle(name.."_"..index-2, digit)
end
end
local function teleportTo(x, y, z, id)
say(id, "Preparing...", false, false)
redstone.setOutput("left", true)
sendHex("x", x)
sendHex("y", y)
sendHex("z", z)
sleep(2/10)
redstone.setOutput("left", false)
sleep(2/10)
local result = parallel.waitForAny(
function() os.pullEvent("redstone") end,
function() sleep(30) end
)
if result == 1 then
say(id, "Teleporting.", false, true)
else
say(id, "Timed out. The circle probably didn't run.", true, true)
end
sleep(1)
sendHex("x", 0)
sendHex("y", 0)
sendHex("z", 0)
end
local function saveWaypoints()
local f = fs.open("waypoints.txt", "w")
f.write(textutils.serialize(waypoints))
f.close()
end
local function strPos(pos)
return "("..pos.x..", "..pos.y..", "..pos.z..")"
end
local function strXYZ(x, y, z)
return strPos{x=x, y=y, z=z}
end
local coordPattern = "([%-%d%.]+)%s+([%-%d%.]+)%s+([%-%d%.]+)"
local commands = {
tp = function(args, id)
if args == "" then
error("Missing coordinates")
end
local pos = waypoints[args]
if pos then
teleportTo(pos.x, pos.y, pos.z, id)
return
end
local x, y, z = args:match("^"..coordPattern)
x, y, z = tonumber(x), tonumber(y), tonumber(z)
if not (x and y and z) then
error("Invalid coordinates: "..args)
end
teleportTo(x, y, z, id)
end,
waypoint = function(args, id)
local action, rest = args:match("^(%S+)%s*(.*)")
rest = rest or ""
if action == "list" then
if not next(waypoints) then
error("No waypoints have been created.")
end
say(id, "Waypoints:", false, false)
local toSend = {}
for waypoint, pos in pairs(waypoints) do
table.insert(toSend, " "..waypoint..": "..strPos(pos))
end
for i, message in ipairs(toSend) do
say(id, message, false, i == #toSend)
end
elseif action == "add" or action == "set" then
local waypoint, x, y, z = rest:match("^(.+)%s+"..coordPattern)
x, y, z = tonumber(x), tonumber(y), tonumber(z)
if not waypoint then
error("Invalid args for "..action..": "..rest)
elseif not (x and y and z) then
error("Invalid coordinates in args for "..action..": "..rest)
end
local pos = waypoints[waypoint]
if pos and action == "add" then
error("Waypoint "..waypoint.." already exists at "..strPos(pos)..".")
elseif not pos and action == "set" then
error("Invalid waypoint: "..waypoint)
end
waypoints[waypoint] = {x=x, y=y, z=z}
saveWaypoints()
if action == "add" then
say(id, "Added waypoint "..waypoint.." at "..strXYZ(x, y, z)..".", false, true)
elseif action == "set" then
say(id, "Set waypoint "..waypoint.." to "..strXYZ(x, y, z)..", was "..strPos(pos)..".", false, true)
end
elseif action == "remove" or action == "delete" then
local pos = waypoints[rest]
if not pos then
error("Invalid waypoint: "..rest)
end
waypoints[rest] = nil
saveWaypoints()
say(id, "Removed waypoint "..rest..", was "..strPos(pos)..".", false, true)
else
error("Invalid args: "..args)
end
end,
help = function(args, id)
say(id, "Commands:", false, false)
say(id, " $help", false, false)
say(id, " $tp <x> <y> <z>", false, false)
say(id, " $tp waypoint <waypoint name>", false, false)
say(id, " $waypoint list", false, false)
say(id, " $waypoint add <waypoint name> <x> <y> <z>", false, false)
say(id, " $waypoint set <waypoint name> <x> <y> <z>", false, false)
say(id, " $waypoint (delete | remove) <waypoint name>", false, true)
end,
}
print("Waiting for commands with prefix "..prettyPrefix)
while true do
local _, id, message
local result = parallel.waitForAny(
function()
id = -1
_, message = os.pullEvent("chat_capture")
end,
function()
id = rednet.receive(backupRequestProtocol)
end
)
local command, args
if result == 1 then
command, args = message:match(prefix.."(%S+)%s+(.+)")
command = command or message:match(prefix.."(.+)")
args = args or ""
else
command, args = "tp", "home"
end
local func = commands[command]
if func then
local success, err = pcall(func, args, id)
if not success then
say(id, err, true, true)
end
else
say(id, "Unknown command: "..command, true, true)
end
end
// thoth spell to convert hex to dec
{
flock_dis
// 16^4 place
16
4
power
multiplicative
// 16^3 place
jester
16
3
power
multiplicative
additive
// 16^2 place
jester
16
2
power
multiplicative
additive
// 16^1 place
jester
16
multiplicative
additive
// 16^0 place
jester
additive
// 16^-1 place
jester
16
-1
power
multiplicative
additive
// sign
multiplicative
}
1 // x_sign
0 // x_-1
0 // x_0
0 // x_1
0 // x_2
0 // x_3
0 // x_4
7
flock_gam
1 // y_sign
0 // y_-1
0 // y_0
0 // y_1
0 // y_2
0 // y_3
0 // y_4
7
flock_gam
1 // z_sign
0 // z_-1
0 // z_0
0 // z_1
0 // z_2
0 // z_3
0 // z_4
7
flock_gam
// convert the coordinates into an absolute vector
3
flock_gam
thoth
flock_dis
vector_exalt
// get my true name from the library
locate_sentinel
consideration
EAST
akasha_dist
// convert the coordinates to relative
gemini
compass
3
fisherman
jester
subtractive
teleport
--[[
Copyright (c) 2022 object-Object
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
local pretty = require("cc.pretty")
local targetProtocol = "request_teleport_home"
local targetHostname = "object_Object"
local responseProtocol = "request_teleport_response"
rednet.open("back")
rednet.send(rednet.lookup(targetProtocol, targetHostname), "", targetProtocol)
print("Requesting teleport home.")
print()
while true do
local _, message, protocol = rednet.receive(responseProtocol)
pretty.print(pretty.text(message.content, message.color))
if message.final then
print()
print("Press enter to shutdown.")
read()
os.shutdown()
end
end
--[[
Copyright (c) 2022 object-Object
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
local label = os.getComputerLabel()
if not label then error("Label must be set!") end
local isSign = not not label:match("sign$")
rednet.host("teleport", label)
rednet.open("right")
print("Listening for commands as "..label..".")
while true do
local _, num = rednet.receive("teleport")
local slot
if not isSign then
slot = num + 1
elseif num == 1 then
slot = 1
else -- num is -1
slot = 2
end
print("Placing "..num.." from slot "..slot..".")
turtle.digDown()
turtle.select(slot)
turtle.placeDown()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment