Initial commit
This commit is contained in:
commit
11754c0b75
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
## Generic ignorable patterns and files
|
||||
*~
|
||||
.*.swp
|
||||
*bak*
|
||||
tags
|
||||
*.vim
|
||||
|
5
LICENSE.txt
Normal file
5
LICENSE.txt
Normal file
@ -0,0 +1,5 @@
|
||||
Meshnodes for Minetest [meshnode]
|
||||
=================================
|
||||
|
||||
Copyright (C) 2013 Stuart Jones - LGPL
|
||||
|
50
README.txt
Normal file
50
README.txt
Normal file
@ -0,0 +1,50 @@
|
||||
Meshnodes for Minetest [meshnode]
|
||||
=================================
|
||||
|
||||
Meshnodes is a mod that transforms ordinary cubic nodes into a connected
|
||||
array of replica entities to which players can attach to and manoeuvre.
|
||||
|
||||
To use, simply build or place a model using only fully cubic nodes
|
||||
(i.e. no stairs, slabs or nodeboxes for now). Next place a meshnode controller
|
||||
in the appropriate position, the operator will be attached directly on top
|
||||
of the controller node. Now right click the controller and enter the
|
||||
minimum and maximum extents of the model (relative to the controller x,y,z)
|
||||
e.g. for a 3x3 square of nodes with the controller placed above the center
|
||||
node, the relative positions would be minp = -1,-1,-1 maxp = 1,0,1
|
||||
|
||||
Alternatively, if you are using worldedit, you can use the position
|
||||
markers to define the extents of the model. However, this must be done
|
||||
before the controller is placed.
|
||||
|
||||
Controls
|
||||
========
|
||||
|
||||
[Up] Forward
|
||||
[Down] Reverse
|
||||
[Left] Rotate Left
|
||||
[Right] Rotate Right
|
||||
[Jump] Up
|
||||
[Sneak] Down
|
||||
[RMB] Attach/Detach
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
Only works for nodes with drawtype normal, allfaces_optional or glasslike.
|
||||
Models will disappear or become detached from the controller if they become
|
||||
unloaded. This can cause the server to warn against excessive objects and
|
||||
destroy them accordingly.
|
||||
|
||||
I have tried a number of ways the get the models to persist after a server
|
||||
restart but so far all of my efforts have been thwarted by minetest's buggy
|
||||
object management system. I also wanted to be able to attach 'passengers'
|
||||
to the entities, however, this has not been possible for the same reason.
|
||||
|
||||
Know Issues
|
||||
===========
|
||||
|
||||
The player controlling the entity may appear to be connected to the wrong
|
||||
part of the model when viewed by a player that was not present during the
|
||||
initial attachment. Currently the only solution is for the operator to
|
||||
detach then re-attach to the model in the presence of said player.
|
||||
|
0
depends.txt
Normal file
0
depends.txt
Normal file
226
init.lua
Normal file
226
init.lua
Normal file
@ -0,0 +1,226 @@
|
||||
MESHNODE_MAX_SPEED = 2
|
||||
MESHNODE_MAX_LIFT = 1
|
||||
MESHNODE_YAW_AMOUNT = 0.02
|
||||
MESHNODE_MAX_RADIUS = 10
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
local input = io.open(modpath.."/meshnode.conf", "r")
|
||||
if input then
|
||||
dofile(modpath.."/meshnode.conf")
|
||||
input:close()
|
||||
input = nil
|
||||
end
|
||||
|
||||
local allowed_drawtypes = {
|
||||
"normal",
|
||||
"allfaces_optional",
|
||||
"glasslike",
|
||||
}
|
||||
|
||||
local function is_allowed_drawtype(drawtype)
|
||||
for _, v in pairs(allowed_drawtypes) do
|
||||
if v == drawtype then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function is_valid_pos(pos)
|
||||
if pos then
|
||||
if pos.x and pos.y and pos.z then
|
||||
return math.abs(pos.x) <= MESHNODE_MAX_RADIUS and
|
||||
math.abs(pos.y) <= MESHNODE_MAX_RADIUS and
|
||||
math.abs(pos.z) <= MESHNODE_MAX_RADIUS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_step(a, b)
|
||||
if a > b then
|
||||
return -1
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
local function create_meshnode(pos, parent)
|
||||
local node = minetest.get_node(pos)
|
||||
local item = minetest.registered_items[node.name]
|
||||
if item then
|
||||
if item.tiles and is_allowed_drawtype(item.drawtype) then
|
||||
local t = item.tiles
|
||||
local textures = {t[1], t[1], t[1], t[1], t[1], t[1]}
|
||||
if #t == 3 then
|
||||
textures = {t[1], t[2], t[3], t[3], t[3], t[3]}
|
||||
elseif #t == 6 then
|
||||
textures = t
|
||||
end
|
||||
local object = minetest.add_entity(pos, "meshnode:mesh")
|
||||
if object then
|
||||
object:set_properties({textures=textures})
|
||||
local y = 0
|
||||
if node.param2 then
|
||||
y = 90 * node.param2
|
||||
end
|
||||
local offset = vector.subtract(pos, parent:getpos())
|
||||
offset = vector.multiply(offset, {x=10,y=10,z=10})
|
||||
object:set_attach(parent, "", offset, {x=0,y=y,z=0})
|
||||
end
|
||||
end
|
||||
minetest.remove_node(pos)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_entity("meshnode:ctrl", {
|
||||
physical = true,
|
||||
visual = "cube",
|
||||
visual_size = {x=1, y=1},
|
||||
textures = {
|
||||
"meshnode_top.png",
|
||||
"meshnode_side.png",
|
||||
"meshnode_side.png",
|
||||
"meshnode_side.png",
|
||||
"meshnode_side.png",
|
||||
"meshnode_side.png",
|
||||
},
|
||||
player = nil,
|
||||
speed = 0,
|
||||
lift = 0,
|
||||
on_activate = function(self, staticdata, dtime_s)
|
||||
if staticdata == "expired" then
|
||||
self.object:remove()
|
||||
end
|
||||
self.object:set_armor_groups({cracky=50})
|
||||
end,
|
||||
on_rightclick = function(self, clicker)
|
||||
if self.player == nil then
|
||||
clicker:set_attach(self.object, "", {x=0,y=15,z=0}, {x=0,y=90,z=0})
|
||||
self.player = clicker
|
||||
else
|
||||
self.player:set_detach()
|
||||
self.player = nil
|
||||
end
|
||||
end,
|
||||
on_step = function(self, dtime)
|
||||
if self.player then
|
||||
local velocity = self.object:getvelocity()
|
||||
local yaw = self.object:getyaw()
|
||||
local speed = self.speed
|
||||
local lift = self.lift
|
||||
local ctrl = self.player:get_player_control()
|
||||
if ctrl.up then
|
||||
speed = speed + 0.1
|
||||
elseif ctrl.down then
|
||||
speed = speed - 0.1
|
||||
else
|
||||
speed = speed * 0.99
|
||||
end
|
||||
if speed > MESHNODE_MAX_SPEED then
|
||||
speed = MESHNODE_MAX_SPEED
|
||||
elseif speed < 0 then
|
||||
speed = 0
|
||||
end
|
||||
if ctrl.jump then
|
||||
lift = lift + 0.1
|
||||
elseif ctrl.sneak then
|
||||
lift = lift - 0.1
|
||||
else
|
||||
lift = lift * 0.9
|
||||
end
|
||||
if lift > MESHNODE_MAX_LIFT then
|
||||
lift = MESHNODE_MAX_LIFT
|
||||
elseif lift < 0 - MESHNODE_MAX_LIFT then
|
||||
lift = 0 - MESHNODE_MAX_LIFT
|
||||
end
|
||||
if ctrl.left then
|
||||
yaw = yaw + MESHNODE_YAW_AMOUNT
|
||||
elseif ctrl.right then
|
||||
yaw = yaw - MESHNODE_YAW_AMOUNT
|
||||
end
|
||||
velocity.x = math.cos(yaw) * speed
|
||||
velocity.y = lift
|
||||
velocity.z = math.sin(yaw) * speed
|
||||
self.object:setyaw(yaw)
|
||||
self.object:setvelocity(velocity)
|
||||
self.speed = speed
|
||||
self.lift = lift
|
||||
else
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
self.speed = 0
|
||||
self.lift = 0
|
||||
end
|
||||
end,
|
||||
get_staticdata = function(self)
|
||||
return "expired"
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_entity("meshnode:mesh", {
|
||||
physical = true,
|
||||
visual = "cube",
|
||||
visual_size = {x=1, y=1},
|
||||
on_activate = function(self, staticdata, dtime_s)
|
||||
if staticdata == "expired" then
|
||||
self.object:remove()
|
||||
end
|
||||
end,
|
||||
get_staticdata = function(self)
|
||||
return "expired"
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("meshnode:controller", {
|
||||
description = "Meshnode Controller",
|
||||
paramtype2 = "facedir",
|
||||
tiles = {"meshnode_top.png", "meshnode_side.png", "meshnode_side.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=3, oddly_breakable_by_hand=3},
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", "size[5,3]"
|
||||
.."field[0.5,1;2,0.5;minp;Minp;${minp}]"
|
||||
.."field[3.0,1;2,0.5;maxp;Maxp;${maxp}]"
|
||||
.."button_exit[1.0,2;3,0.5;connect;Generate Entity]"
|
||||
)
|
||||
meta:set_string("infotext", "Meshnode Controller")
|
||||
end,
|
||||
after_place_node = function(pos, placer)
|
||||
if worldedit then
|
||||
local name = placer:get_player_name()
|
||||
local meta = minetest.get_meta(pos)
|
||||
if worldedit.pos1[name] then
|
||||
local p = vector.subtract(worldedit.pos1[name], pos)
|
||||
meta:set_string("minp", p.x..","..p.y..","..p.z)
|
||||
end
|
||||
if worldedit.pos2[name] then
|
||||
local p = vector.subtract(worldedit.pos2[name], pos)
|
||||
meta:set_string("maxp", p.x..","..p.y..","..p.z)
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
if fields.connect and not fields.quit then
|
||||
local minp = minetest.string_to_pos(fields.minp)
|
||||
local maxp = minetest.string_to_pos(fields.maxp)
|
||||
if is_valid_pos(minp) and is_valid_pos(maxp) then
|
||||
local nodes = {}
|
||||
local node = minetest.get_node(pos)
|
||||
minetest.remove_node(pos)
|
||||
local object = minetest.add_entity(pos, "meshnode:ctrl")
|
||||
if object then
|
||||
for x = minp.x, maxp.x, get_step(minp.x, maxp.x) do
|
||||
for y = minp.y, maxp.y, get_step(minp.y, maxp.y) do
|
||||
for z = minp.z, maxp.z, get_step(minp.z, maxp.z) do
|
||||
local node_pos = vector.add(pos, {x=x, y=y, z=z})
|
||||
create_meshnode(node_pos, object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local name = sender:get_player_name()
|
||||
minetest.chat_send_player(name, "Invalid Position!")
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
14
meshnode.conf.example
Normal file
14
meshnode.conf.example
Normal file
@ -0,0 +1,14 @@
|
||||
-- Meshnode configuration (defaults)
|
||||
|
||||
-- Maximum Entity Speed
|
||||
MESHNODE_MAX_SPEED = 2
|
||||
|
||||
-- Maximum Up/Down Velocity
|
||||
MESHNODE_MAX_LIFT = 1
|
||||
|
||||
-- Rotational Step (Radians)
|
||||
MESHNODE_YAW_AMOUNT = 0.02
|
||||
|
||||
-- Maximum Entity Area
|
||||
MESHNODE_MAX_RADIUS = 10
|
||||
|
BIN
textures/meshnode_side.png
Normal file
BIN
textures/meshnode_side.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 699 B |
BIN
textures/meshnode_top.png
Normal file
BIN
textures/meshnode_top.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 878 B |
Loading…
x
Reference in New Issue
Block a user