Initial commit

This commit is contained in:
Signal 2025-09-12 15:40:57 -04:00
commit d52c39e873
21 changed files with 581 additions and 0 deletions

View file

View file

@ -0,0 +1,73 @@
rgt_towns = {
plots = {},
spawners = {}
}
local ns = rgt_towns
include "visuals.lua"
include "items.lua"
include "schems.lua"
include "plots.lua"
--[[
{
label = "", -- Display name
texture = "inventory_image",
plot = "main:base"
}
--]]
function ns.register_spawner(def)
ns.spawners[def.plot] = def
end
function ns.create_spawner(for_plot)
local s = ItemStack("rgt_towns:spawner")
local m = s:get_meta()
m:set_string("plot", for_plot)
m:set_string("description", ns.spawners[for_plot].label)
return s
end
--[[
{
name = "", -- Technical name used in API calls.
label = "", -- Non-technical name.
description = "", -- The short description shown in constructors.
long_description = "", -- The essay shown in the guide.
thumbnail = "", -- Optional; defines the thumbnail shown in the guide.
size = <vector>, -- The amount of space taken up by this plot, in grid squares.
schematic = <schem> or {},
recipe = { -- 3x3 crafting recipe for this structure, as a flat list of ItemStack strings.
"stone 60", "wood 10", "stone 60",
"cobble 25", "diamond 3", "cobble 25",
"stone 60", "iron 15", "stone 60"
},
can_build = { -- List of the names of plots that can be built from this plot.
"main:windmill",
...
},
slots = { -- List of hooks for auxiliary construction slots contained in the schematic, indexed by the `name` node meta field.
upgrade = {
recipes = { -- A list of recipes
upgrade = { -- Contains name, description, and recipe.
name = "Upgrade",
description = "Upgrade to Windmill+ Pro.",
recipe = { -- A craft recipe, per above.
...
}
}
},
on_apply = function(plot) -- Called when the player confirms the constructor's action. Return true to not automatically consume input items.
rgt_towns.swap_plot(plot, "main:windmill_plus")
end
}
}
}
--]]
function ns.register_plot(def)
if not def.name then
warn "A plot was registered without a name!"
return
end
ns.plots[def.name] = def
end

View file

@ -0,0 +1,31 @@
local ns = rgt_towns
minetest.register_craftitem(":rgt_towns:spawner", {
description = "Blank Plot Spawner (you shouldn't have this)",
stack_max = 1,
on_wield = function(m)
end,
while_wielded = function(m)
end,
on_unwield = function(m)
end,
on_place = function(s, p, pt)
local m = s:get_meta()
local owner = m:get("owner")
if owner and owner ~= p:get_player_name() then
warn("<"..p:get_player_name().."> tried to use <"..owner..">'s '"..(m:get("description") or "Blank Plot Spawner").."' (and failed).")
return
end
local plot = m:get("plot")
if plot then
ns.place_plot(plot, p:get_pos())
else
warn("<"..p:get_player_name().."> tried to use an uninitialized plot spawner.")
end
end
})

View file

@ -0,0 +1,2 @@
name = rgt_towns_core
depends = rgt_base, rgt_world

View file

@ -0,0 +1,14 @@
local ns = rgt_towns
function ns.get_grid()
end
local repl = {
-- ["default:dirt"] = "adrift:dirt",
-- ["default:wood"] = "adrift:water"
}
function ns.place_plot(plot, pos)
minetest.place_schematic(pos, ns.plots[plot].schematic, nil, repl, true, {place_center_x = true, place_center_z = true})
end

View file

@ -0,0 +1,22 @@
local ns = rgt_towns
function ns.load_schematic(file)
local out = {}
local f = io.open(file) or error("Failed to open schematic.")
local chr = f:read(1)
while chr do
chr = f:read(1)
end
f:close()
end
function ns.export_region_as_schematic(pos1, pos2)
end
--[[
4d 54 53 4d 00 04 00 0f 00 0f 00 0f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 00 10 00 0c 64 65 66 61 75 6c 74 3a 64 69 72 74 00 1b 64 65 66 61 75 6c 74 3a 64 69 72 74 5f 77 69 74 68 5f 64 72 79 5f 67 72 61 73 73 00 03 61 69 72 00 17 64 65 66 61 75 6c 74 3a 64 69 72 74 5f 77 69 74 68 5f 67 72 61 73 73 00 0f 64 65 66 61 75 6c 74 3a 67 72 61 73 73 5f 33 00 0f 64 65 66 61 75 6c 74 3a 67 72 61 73 73 5f 32 00 0f 64 65 66 61 75 6c 74 3a 67 72 61 73 73 5f 35 00 0f 64 65 66 61 75 6c 74 3a 67 72 61 73 73 5f 31 00 11 73 74 61 69 72 73 3a 73 74 61 69 72 5f 77 6f 6f 64 00 12 64 65 66 61 75 6c 74 3a 66 65 6e 63 65 5f 77 6f 6f 64 00 0c 64 65 66 61 75 6c 74 3a 77 6f 6f 64 00 0a 77 6f 6f 6c 3a 77 68 69 74 65 00 10 73 74 61 69 72 73 3a 73 6c 61 62 5f 77 6f 6f 64 00 0d 64 65 66 61 75 6c 74 3a 63 68 65 73 74 00 0f 64 65 66 61 75 6c 74 3a 66 75 72 6e 61 63 65 00 0f 64 65 66 61 75 6c 74 3a 67 72 61 73 73 5f 34 78 9c ed 99 db 12 82 20 14 45 31 2a b5 eb 93 d3 e7 f6 eb 05 84 97 01 41 c5 03 03 ed b5 8d 17 9a ea b8 e6 a0 18 63 64 54 ce 1c 90 9d 42 6d 90 1b 99 37 78 4c 7e 36 72 0c ad 41 d3 9f 76 a8 be fd 94 bc fe fc 43 69 d0 ee 4f 39 1c ff 86 a1 f7 ce c9 cf 47 7e 89 63 70 7c 05 1c 0c d6 72 6c be d1 a3 19 f7 ac 48 eb ac 2f 64 36 8f c4 31 38 d7 83 d3 55 b4 1e 8d 2a 0d bb fc 62 33 d8 b2 6b 1f 5b 6d ae 39 fd 09 ae 73 93 87 df 74 06 97 ac 98 8d cc 4d be cc d9 7b 40 dd 6e f7 2a 30 b8 f4 3a a8 63 f6 99 db e0 23 a0 6e 18 dc c7 a0 6f ff 80 1e f4 27 ad 41 33 d3 b5 15 d7 41 7f e2 18 9c bf 17 ad 71 2f 1a 98 38 06 97 f5 e0 53 8e d8 e5 af 0b a5 41 ff 33 19 95 33 c3 5e 7e 7b 68 0d fa 9e 8b 4e fb 0d dd b7 25 d4 06 f1 df 04 71 de 00 00 00 00 00 00 00 00 6c 10 6e 78 01 00 31 78 75 e2 e8 a9 b8 38 ca 45 d6 d6 f9 de 95 31 9c 57 9c 0f 06 8b 71 d9 17 52 6a 81 3d e5 17 28 86 b2 7a f0 cf 56 51 00 c0 4a 3e 4f 8f a4 76
]]

View file

@ -0,0 +1,73 @@
local ns = rgt_towns
function ns.add_line(from, to)
local dist = vector.distance(from, to)
local vel = dist
return minetest.add_particlespawner {
pos = from,
vel = vector.direction(from, to) *vel,
amount = dist *vel,
time = 0,
exptime = dist /vel,
texture = "[fill:1x1:0,0:#35f",
glow = 14,
}
end
--[[
1 2 X
4 6
Z
=============
3 5
7 8
]]
function ns.add_cube(from, to)
local p1 = from
local p2 = vector.new(to.x, from.y, from.z)
local p3 = vector.new(from.x, to.y, from.z)
local p4 = vector.new(from.x, from.y, to.z)
local p5 = vector.new(to.x, to.y, from.z)
local p6 = vector.new(to.x, from.y, to.z)
local p7 = vector.new(from.x, to.y, to.z)
local p8 = to
return {
ns.add_line(p1, p2),
ns.add_line(p1, p3),
ns.add_line(p1, p4),
ns.add_line(p4, p6),
ns.add_line(p4, p7),
ns.add_line(p2, p6),
ns.add_line(p8, p5),
ns.add_line(p8, p6),
ns.add_line(p8, p7),
ns.add_line(p5, p2),
ns.add_line(p5, p3),
ns.add_line(p7, p3),
}
end
function ns.visualize_mesh(pos, mesh)
for l in io.lines(mesh) do
local x, y, z = l:match "^v%s+(%d+)%s+(%d+)%s+(%d+)"
if x ~= nil and y ~= nil and z ~= nil then
end
end
end

View file

@ -0,0 +1,184 @@
rgt_towns.editor = {
workspaces = {}
}
local ns = rgt_towns.editor
local db = minetest.get_mod_storage()
minetest.register_entity(":display", {
initial_properties = {
visual = "sprite",
textures = {"blank.png"},
pointable = false,
static_save = false
},
on_activate = function(e, data)
if data then
data = minetest.deserialize(data)
e.object:set_properties(data)
end
e.object:set_armor_groups{immortal = 1}
end
})
function ns.reconstitute_workspace(name, ws)
if not ws then ws = db:get("workspace:"..name) end
end
function ns.unload_workspace(ws)
end
minetest.register_entity(":rgt_towns_editor:workspace", {
initial_properties = {
visual = "sprite",
textures = {"blank.png"},
pointable = false
},
on_activate = function(e, data, dtime)
local ws = db:get("workspace:"..data)
if not ws then
e.object:remove()
return
end
ws = minetest.deserialize(ws)
e.object:set_armor_groups{immortal = 1}
e.workspace = data
if not ns.workspaces[data] then
ns.workspaces[data] = {}
end
ns.workspaces[data].marker = e.object
ns.reconstitute_workspace(data, ws)
end,
on_deactivate = function(e)
ns.workspaces[e.workspace].marker = nil
ns.unload_workspace(ns.workspaces[e.workspace])
end,
get_staticdata = function(e)
return e.workspace
end
})
function ns.get_workspace_center(pos, size)
return pos +vector.multiply(size, 7)
end
function ns.close_workspace(name)
local ws = ns.workspaces[name]
if ws then
for k, x in pairs(ws) do
if k ~= "marker" then
if x.remove then
x:remove()
elseif type(x) == "table" then
for _, y in pairs(x) do
minetest.delete_particlespawner(y)
end
else
minetest.delete_particlespawner(y)
end
end
end
end
ns.workspaces[name] = nil
db:set_string("workspace:"..name, "")
end
function ns.get_workspace(name)
local ws = db:get("workspace:"..name)
if ws then return mietest.deserialize(ws) end
end
function ns.place_workspace(name, pos)
local ws = db:get("workspace:"..name)
if ws then
ns.close_workspace(name)
end
pos = pos:round()
ws = {
pos = pos,
size = vector.new(1,4,1)
}
db:set_string("workspace:"..name, minetest.serialize(ws))
minetest.add_entity(ns.get_workspace_center(pos, ws.size), "rgt_towns_editor:workspace", name)
ns.workspaces[name].outline = rgt_towns.add_cube(vector.offset(ws.pos, -0.5,-0.5,-0.5), vector.add(ws.pos, vector.multiply(ws.size, 15)):offset(-0.5,-0.5,-0.5))
return ws
end
function ns.clear_workspace(ws)
local a = ws.pos
local b = vector.add(ws.pos, vector.multiply(ws.size, 14))
local vm = minetest.get_voxel_manip(a, b)
local va = VoxelArea(vm:get_emerged_area())
local data = vm:get_data()
local c_air = minetest.get_content_id("air")
for i in va:iterp(a, b) do
data[i] = c_air
end
vm:set_data(data)
vm:write_to_map()
end
function ns.load_plot(ws, plot)
minetest.place_schematic(ws.pos, rgt_towns.plots[plot].schematic, nil, nil, true, {})
end
function ns.set_workspace_size(ws, x, y, z)
end
function ns.export_workspace(ws, label)
local world_path = minetest.get_worldpath().."/"
minetest.mkdir(world_path.."rgt_towns/plots")
minetest.create_schematic(ws.pos, vector.add(ws.pos, vector.multiply(ws.size, 14)), nil, world_path.."rgt_towns/plots/"..label:gsub("[^a-zA-Z0-9._-]", "_")..".mts")
end
minetest.register_chatcommand("new_plot", {
func = function(name, args)
local ws = ns.place_workspace(name, minetest.get_player_by_name(name):get_pos())
if args == "clear" then
ns.clear_workspace(ws)
end
end
})
minetest.register_chatcommand("load_plot", {
func = function(name, args)
if args and args ~= "" then
ns.load_plot(name, args)
end
end
})
minetest.register_chatcommand("set_plot_size", {
func = function(name, args)
if args and args ~= "" then
local x, y, z = args:match "(%d+)%s+(%d+)%s+(%d+)"
if not y then y = x end
if not z then z = x end
ns.set_workspace_size(ns.get_workspace(name), x, y, z)
tell(name, "Size set to "..x.."x"..y.."x"..z..".")
end
end
})
minetest.register_chatcommand("export_plot", {
func = function(name, args)
local ws = db:get("workspace:"..name)
if ws then
ws = minetest.deserialize(ws)
else
return
end
if args == "" then args = nil end
ns.export_workspace(ws, args or "unnamed")
end
})

View file

@ -0,0 +1,2 @@
name = rgt_towns_editor
depends = rgt_towns_core

View file

@ -0,0 +1,49 @@
# Made in Blockbench 4.12.5
mtllib cube.mtl
o cube
v 0.5 0.5 0.5
v 0.5 0.5 -0.5
v 0.5 -0.5 0.5
v 0.5 -0.5 -0.5
v -0.5 0.5 -0.5
v -0.5 0.5 0.5
v -0.5 -0.5 -0.5
v -0.5 -0.5 0.5
vt 0 1
vt 1 1
vt 1 0
vt 0 0
vt 0 1
vt 1 1
vt 1 0
vt 0 0
vt 0 1
vt 1 1
vt 1 0
vt 0 0
vt 0 1
vt 1 1
vt 1 0
vt 0 0
vt 0 1
vt 1 1
vt 1 0
vt 0 0
vt 0 1
vt 1 1
vt 1 0
vt 0 0
vn 0 0 -1
vn 1 0 0
vn 0 0 1
vn -1 0 0
vn 0 1 0
vn 0 -1 0
usemtl m_8c088280-b6ec-0daf-ec32-02e4d3fa1b3e
f 4/4/1 7/3/1 5/2/1 2/1/1
f 3/8/2 4/7/2 2/6/2 1/5/2
f 8/12/3 3/11/3 1/10/3 6/9/3
f 7/16/4 8/15/4 6/14/4 5/13/4
f 6/20/5 1/19/5 2/18/5 5/17/5
f 7/24/6 4/23/6 3/22/6 8/21/6

View file

@ -0,0 +1,25 @@
rgt_towns.main = {}
ns = rgt_towns.main
ns.plots = {
}
rgt_towns.register_spawner{
plot = "covered_wagon",
label = "Town Charter"
}
minetest.register_chatcommand("charter", {
func = function(name, args)
minetest.get_player_by_name(name):get_inventory():add_item("main", rgt_towns.create_spawner("covered_wagon"))
end
})
rgt_towns.register_plot{
name = "covered_wagon",
label = "Covered Wagon",
description = "Hello world",
schematic = minetest.get_modpath(minetest.get_current_modname()).."/schems/covered_wagon.mts",
can_build = ns.plots
}

View file

@ -0,0 +1,2 @@
name = rgt_towns_main
depends = rgt_towns_core

Binary file not shown.