Add spawn function and improve chatcommand feedback
This commit is contained in:
parent
f4428b9d1f
commit
f4dfba13b4
@ -84,12 +84,20 @@ Permanently unload and delete named NPC. (requires server priv)
|
||||
|
||||
Loads the NPC at the specified postion. (requires ownership or server priv)
|
||||
|
||||
/npcf load npc_name 0, 5, 0
|
||||
/npcf load npc_name 0, 1.5, 0
|
||||
|
||||
Use 'here' to load the NPC at the player's current position.
|
||||
|
||||
/npcf load npc_name here
|
||||
|
||||
### setpos npc_name pos | here
|
||||
|
||||
Set named NPC location. (x, y, z)
|
||||
|
||||
/npcf setpos npc_name 0, 1.5, 0
|
||||
|
||||
Use 'here' to load the NPC at the player's current position.
|
||||
|
||||
### setskin npc_name skin_filename | random
|
||||
|
||||
Set the skin texture of the named NPC. (requires server priv)
|
||||
@ -100,12 +108,6 @@ If you have Zeg9's skins mod installed you can select a random texture from said
|
||||
|
||||
/npcf setskin npc_name random
|
||||
|
||||
### setpos npc_name pos
|
||||
|
||||
Set named NPC location. (x, y, z)
|
||||
|
||||
/npcf setpos npc_name 0, 5, 0
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
@ -142,7 +144,7 @@ Additional properties included by the framework. (defaults)
|
||||
armor_groups = {immortal=1},
|
||||
inventory_image = "npcf_info_inv.png",
|
||||
show_nametag = true,
|
||||
nametag_color = "white",
|
||||
nametag_color = "white", --textcolors mod adds red, blue, green, cyan, yellow and magenta
|
||||
metadata = {},
|
||||
var = {},
|
||||
timer = 0,
|
||||
@ -165,10 +167,7 @@ where it may be desireable update the statically saved position.
|
||||
|
||||
Callbacks
|
||||
---------
|
||||
Additional callbacks included by the framework.
|
||||
|
||||
### on_registration = function(self, pos, sender)
|
||||
Only ever called once by the framework upon successful NPC registration.
|
||||
Additional callbacks provided by the framework.
|
||||
|
||||
### on_construct = function(self)
|
||||
This is called before the slightly delayed inbuilt on_activate callback.
|
||||
@ -176,12 +175,19 @@ Please note that the self.npc_name, self.owner and self.origin properties
|
||||
may not be available or nil at the time of registration.
|
||||
|
||||
### on_receive_fields = function(self, fields, sender)
|
||||
Called when a button is pressed in the NPC's formspec.
|
||||
Called when a button is pressed in the NPC's formspec. text fields, dropdown,
|
||||
list and checkbox selections are automatically stored in the self.metadata table.
|
||||
|
||||
### on_registration = function(self, pos, sender)
|
||||
Only ever called once upon successful NPC registration using a spawner.
|
||||
Currently not used anywhere and may be removed from future version.
|
||||
|
||||
|
||||
npcf
|
||||
----
|
||||
The global NPC framework namespace.
|
||||
|
||||
The global NPC framework namespace. Other global variables include.
|
||||
### Global Constants
|
||||
|
||||
NPCF_ANIM_STAND = 1
|
||||
NPCF_ANIM_SIT = 2
|
||||
@ -210,21 +216,42 @@ The metadata table is persistent following a reload and automatically stores sub
|
||||
The var table should be used for non-persistent data storage only. Note that self.timer is
|
||||
automatically incremented by the framework but should be reset externally.
|
||||
|
||||
### npcf:clear_npc(npc_name)
|
||||
### npcf:spawn(pos, name, def)
|
||||
|
||||
Spawns and registers a NPC entity at the specified position. Returns a minetest ObjectRef on success.
|
||||
|
||||
local pos = player:getpos()
|
||||
local yaw = player:get_look_yaw()
|
||||
local player_name = player:get_player_name()
|
||||
local luaentity = npcf:spawn(pos, "npcf:guard_npc", {
|
||||
owner = player_name,
|
||||
npc_name = "Sam",
|
||||
origin = {pos=pos, yaw=yaw}, --optional
|
||||
})
|
||||
|
||||
Note that the on_registration callback will not be issued when spawning NPC's this way.
|
||||
|
||||
### npcf:clear(npc_name)
|
||||
|
||||
Clear (unload) named NPC.
|
||||
|
||||
### npcf:load_npc(npc_name, pos)
|
||||
### npcf:load(npc_name, pos)
|
||||
|
||||
Loads the NPC at the specified postion. If pos is nil then the NPC is loaded at the last saved origin.
|
||||
|
||||
### npcf:save_npc(luaentity)
|
||||
### npcf:save(luaentity)
|
||||
|
||||
Save current NPC state to file.
|
||||
|
||||
on_receive_fields = function(self, fields, sender)
|
||||
if fields.save then
|
||||
npcf:save(self)
|
||||
end
|
||||
end,
|
||||
|
||||
### npcf:set_animation(luaentity, state)
|
||||
|
||||
Sets the entity animation state.
|
||||
Sets the NPC's animation state.
|
||||
|
||||
on_activate = function(self, staticdata, dtime_s)
|
||||
npcf:set_animation(self, NPCF_ANIM_STAND)
|
||||
@ -238,7 +265,7 @@ Returns a table of all registered NPCs. (loaded or unloaded)
|
||||
|
||||
### npcf:get_luaentity(npc_name)
|
||||
|
||||
Returns a minetest ObjectRef of the npc entity.
|
||||
Returns a minetest ObjectRef of the NPC entity.
|
||||
|
||||
### npcf:get_face_direction(v1, v2)
|
||||
|
||||
@ -254,6 +281,6 @@ Returns a velocity vector for the given speed, y velocity and yaw.
|
||||
Shows a formspec, similar to minetest.show_formspec() but with the npc_name included.
|
||||
Submitted data can then be captured in the NPC's own 'on_receive_fields' callback.
|
||||
|
||||
Note that Form text fields, dropdown, list and checkbox selections are automatically
|
||||
Note that form text fields, dropdown, list and checkbox selections are automatically
|
||||
stored in the NPC's metadata table. Image/Button clicks, however, are not.
|
||||
|
||||
|
@ -9,6 +9,12 @@ minetest.register_chatcommand("npcf", {
|
||||
if cmd == "setpos" then
|
||||
if admin or name == index[npc_name] then
|
||||
local pos = minetest.string_to_pos(args)
|
||||
if args == "here" then
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player then
|
||||
pos = player:getpos()
|
||||
end
|
||||
end
|
||||
if pos then
|
||||
pos.y = pos.y + 1
|
||||
local luaentity = npcf:get_luaentity(npc_name)
|
||||
@ -16,9 +22,13 @@ minetest.register_chatcommand("npcf", {
|
||||
if admin or luaentity.owner == name then
|
||||
luaentity.object:setpos(pos)
|
||||
luaentity.origin.pos = pos
|
||||
npcf:save_npc(luaentity)
|
||||
npcf:save(luaentity)
|
||||
pos = minetest.pos_to_string(pos)
|
||||
minetest.log("action", name.." moves NPC "..npc_name.." to "..pos)
|
||||
end
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(name, "Invalid position "..args)
|
||||
end
|
||||
end
|
||||
elseif cmd == "load" then
|
||||
@ -32,11 +42,13 @@ minetest.register_chatcommand("npcf", {
|
||||
end
|
||||
if pos then
|
||||
pos.y = pos.y + 1
|
||||
if npcf:load_npc(npc_name, pos) then
|
||||
if npcf:load(npc_name, pos) then
|
||||
minetest.after(1, function()
|
||||
local luaentity = npcf:get_luaentity(npc_name)
|
||||
if luaentity then
|
||||
npcf:save_npc(luaentity)
|
||||
npcf:save(luaentity)
|
||||
pos = minetest.pos_to_string(pos)
|
||||
minetest.log("action", name.." loads NPC "..npc_name.." at "..pos)
|
||||
else
|
||||
minetest.chat_send_player(name, "Unable to load "..npc_name)
|
||||
end
|
||||
@ -74,7 +86,8 @@ minetest.register_chatcommand("npcf", {
|
||||
cmd, npc_name = string.match(param, "([^ ]+) (.+)")
|
||||
if cmd and npc_name then
|
||||
if cmd == "delete" and admin then
|
||||
npcf:clear_npc(npc_name)
|
||||
npcf:clear(npc_name)
|
||||
minetest.log("action", name.." deletes NPC "..npc_name)
|
||||
local input = io.open(NPCF_DATADIR.."/"..npc_name..".npc", "r")
|
||||
if input then
|
||||
io.close(input)
|
||||
@ -90,11 +103,14 @@ minetest.register_chatcommand("npcf", {
|
||||
end
|
||||
elseif cmd == "clear" then
|
||||
if admin or name == index[npc_name] then
|
||||
npcf:clear_npc(npc_name)
|
||||
npcf:clear(npc_name)
|
||||
minetest.log("action", name.." clears NPC "..npc_name)
|
||||
end
|
||||
elseif cmd == "reload" then
|
||||
if admin or name == index[npc_name] then
|
||||
if not npcf:load_npc(npc_name, nil) then
|
||||
if npcf:load(npc_name, nil) then
|
||||
minetest.log("action", name.." reloads NPC "..npc_name)
|
||||
else
|
||||
minetest.chat_send_player(name, "Unable to reload "..npc_name)
|
||||
end
|
||||
end
|
||||
@ -103,8 +119,10 @@ minetest.register_chatcommand("npcf", {
|
||||
local saved = false
|
||||
local luaentity = npcf:get_luaentity(npc_name)
|
||||
if luaentity then
|
||||
if npcf:save_npc(luaentity) then
|
||||
if npcf:save(luaentity) then
|
||||
saved = true
|
||||
minetest.chat_send_player(name, npc_name.." has been saved")
|
||||
minetest.log("action", name.." saves NPC "..npc_name)
|
||||
end
|
||||
end
|
||||
if saved == false then
|
||||
@ -147,14 +165,16 @@ minetest.register_chatcommand("npcf", {
|
||||
end
|
||||
minetest.chat_send_player(name, "NPC List: "..msg)
|
||||
elseif cmd == "clearobjects" and admin then
|
||||
minetest.log("action", name.." clears all NPC objects")
|
||||
for _,ref in pairs(minetest.luaentities) do
|
||||
if ref.object and ref.npcf_id then
|
||||
ref.object:remove()
|
||||
end
|
||||
end
|
||||
elseif cmd == "loadobjects" and admin then
|
||||
minetest.log("action", name.." reloads all NPC objects")
|
||||
for npc_name,_ in pairs(index) do
|
||||
npcf:load_npc(npc_name, nil)
|
||||
npcf:load(npc_name, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
179
npcf/npcf.lua
179
npcf/npcf.lua
@ -104,6 +104,10 @@ local function get_valid_player_name(player)
|
||||
end
|
||||
end
|
||||
|
||||
local function get_valid_npc_name(npc_name)
|
||||
return npc_name:len() <= 12 and npc_name:match("^[A-Za-z0-9%_%-]+$")
|
||||
end
|
||||
|
||||
local function get_valid_entity(luaentity)
|
||||
if luaentity then
|
||||
if luaentity.name and luaentity.owner and luaentity.origin then
|
||||
@ -326,10 +330,8 @@ function npcf:register_npc(name, def)
|
||||
local owner = meta:get_string("owner")
|
||||
local player_name = sender:get_player_name()
|
||||
if player_name == owner then
|
||||
if fields.name:len() <= 12 and fields.name:match("^[A-Za-z0-9%_%-]+$") then
|
||||
local input = io.open(NPCF_DATADIR.."/"..fields.name..".npc", "r")
|
||||
if input then
|
||||
io.close(input)
|
||||
if get_valid_npc_name(fields.name) then
|
||||
if index[fields.name] then
|
||||
minetest.chat_send_player(player_name, "Error: Name Already Taken!")
|
||||
return
|
||||
end
|
||||
@ -339,70 +341,89 @@ function npcf:register_npc(name, def)
|
||||
end
|
||||
minetest.dig_node(pos)
|
||||
local npc_pos = {x=pos.x, y=pos.y + 0.5, z=pos.z}
|
||||
local npc = minetest.add_entity(npc_pos, name)
|
||||
if npc then
|
||||
local luaentity = npc:get_luaentity()
|
||||
if luaentity then
|
||||
luaentity.owner = player_name
|
||||
luaentity.npc_name = fields.name
|
||||
luaentity.origin = {pos=npc_pos, yaw=luaentity.object:getyaw()}
|
||||
save_npc(luaentity)
|
||||
index[fields.name] = owner
|
||||
local output = io.open(NPCF_DATADIR.."/index.txt", 'w')
|
||||
if output then
|
||||
output:write(minetest.serialize(index))
|
||||
io.close(output)
|
||||
else
|
||||
minetest.log("error", "Failed to add "..fields.name.." to npc index")
|
||||
end
|
||||
if luaentity.show_nametag then
|
||||
add_nametag(luaentity)
|
||||
end
|
||||
if type(def.on_registration) == "function" then
|
||||
def.on_registration(luaentity, pos, sender)
|
||||
end
|
||||
end
|
||||
local luaentity = npcf:spawn(npc_pos, name, {
|
||||
owner = player_name,
|
||||
npc_name = fields.name,
|
||||
})
|
||||
if luaentity and type(def.on_registration) == "function" then
|
||||
def.on_registration(luaentity, pos, sender)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function npcf:clear_npc(npc_name)
|
||||
for _,ref in pairs(minetest.luaentities) do
|
||||
if ref.object and ref.npc_name == npc_name then
|
||||
ref.object:remove()
|
||||
function npcf:spawn(pos, name, def)
|
||||
if pos and name and def.npc_name and def.owner then
|
||||
if get_valid_npc_name(def.npc_name) and index[def.npc_name] == nil then
|
||||
local entity = minetest.add_entity(pos, name)
|
||||
if entity then
|
||||
local luaentity = entity:get_luaentity()
|
||||
if luaentity then
|
||||
luaentity.owner = def.owner
|
||||
luaentity.npc_name = def.npc_name
|
||||
luaentity.origin = def.origin or {pos=pos, yaw=0}
|
||||
index[def.npc_name] = def.owner
|
||||
if npcf:save(luaentity) then
|
||||
local output = io.open(NPCF_DATADIR.."/index.txt", 'w')
|
||||
if output then
|
||||
output:write(minetest.serialize(index))
|
||||
io.close(output)
|
||||
if NPCF_SHOW_NAMETAGS == true and luaentity.show_nametag == true then
|
||||
add_nametag(luaentity)
|
||||
end
|
||||
return luaentity
|
||||
else
|
||||
minetest.log("error", "Failed to add "..def.npc_name.." to NPC index")
|
||||
end
|
||||
else
|
||||
minetest.log("error", "Failed to save NPC "..def.npc_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function npcf:load_npc(npc_name, pos)
|
||||
npcf:clear_npc(npc_name)
|
||||
local input = io.open(NPCF_DATADIR.."/"..npc_name..".npc", "r")
|
||||
if input then
|
||||
local data = minetest.deserialize(input:read('*all'))
|
||||
io.close(input)
|
||||
if data then
|
||||
if pos and data.origin then
|
||||
data.origin.pos = pos
|
||||
function npcf:clear(npc_name)
|
||||
if get_valid_npc_name(npc_name) then
|
||||
for _,ref in pairs(minetest.luaentities) do
|
||||
if ref.object and ref.npc_name == npc_name then
|
||||
ref.object:remove()
|
||||
end
|
||||
if data.origin.pos then
|
||||
local npc = minetest.add_entity(data.origin.pos, data.name)
|
||||
if npc then
|
||||
local luaentity = npc:get_luaentity()
|
||||
if luaentity then
|
||||
luaentity.owner = data.owner
|
||||
luaentity.npc_name = npc_name
|
||||
luaentity.origin = data.origin
|
||||
luaentity.animation = data.animation
|
||||
luaentity.metadata = data.metadata
|
||||
luaentity.object:setyaw(data.origin.yaw)
|
||||
luaentity.properties = data.properties
|
||||
luaentity.object:set_properties(data.properties)
|
||||
if NPCF_SHOW_NAMETAGS == true and luaentity.show_nametag == true then
|
||||
add_nametag(luaentity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function npcf:load(npc_name, pos)
|
||||
if get_valid_npc_name(npc_name) then
|
||||
npcf:clear(npc_name)
|
||||
local input = io.open(NPCF_DATADIR.."/"..npc_name..".npc", "r")
|
||||
if input then
|
||||
local data = minetest.deserialize(input:read('*all'))
|
||||
io.close(input)
|
||||
if data then
|
||||
if pos and data.origin then
|
||||
data.origin.pos = pos
|
||||
end
|
||||
if data.origin.pos then
|
||||
local npc = minetest.add_entity(data.origin.pos, data.name)
|
||||
if npc then
|
||||
local luaentity = npc:get_luaentity()
|
||||
if luaentity then
|
||||
luaentity.owner = data.owner
|
||||
luaentity.npc_name = npc_name
|
||||
luaentity.origin = data.origin
|
||||
luaentity.animation = data.animation
|
||||
luaentity.metadata = data.metadata
|
||||
luaentity.object:setyaw(data.origin.yaw)
|
||||
luaentity.properties = data.properties
|
||||
luaentity.object:set_properties(data.properties)
|
||||
if NPCF_SHOW_NAMETAGS == true and luaentity.show_nametag == true then
|
||||
add_nametag(luaentity)
|
||||
end
|
||||
return 1
|
||||
end
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -411,27 +432,29 @@ function npcf:load_npc(npc_name, pos)
|
||||
minetest.log("error", "Failed to load "..npc_name)
|
||||
end
|
||||
|
||||
function npcf:save_npc(luaentity)
|
||||
local npc = {
|
||||
name = luaentity.name,
|
||||
owner = luaentity.owner,
|
||||
origin = luaentity.origin,
|
||||
animation = luaentity.animation,
|
||||
metadata = luaentity.metadata,
|
||||
properties = luaentity.properties,
|
||||
}
|
||||
local npc_name = luaentity.npc_name
|
||||
local output = io.open(NPCF_DATADIR.."/"..npc_name..".npc", 'w')
|
||||
if output then
|
||||
output:write(minetest.serialize(npc))
|
||||
io.close(output)
|
||||
return 1
|
||||
function npcf:save(luaentity)
|
||||
if get_valid_entity(luaentity) then
|
||||
local npc = {
|
||||
name = luaentity.name,
|
||||
owner = luaentity.owner,
|
||||
origin = luaentity.origin,
|
||||
animation = luaentity.animation,
|
||||
metadata = luaentity.metadata,
|
||||
properties = luaentity.properties,
|
||||
}
|
||||
local npc_name = luaentity.npc_name
|
||||
local output = io.open(NPCF_DATADIR.."/"..npc_name..".npc", 'w')
|
||||
if output then
|
||||
output:write(minetest.serialize(npc))
|
||||
io.close(output)
|
||||
return 1
|
||||
end
|
||||
end
|
||||
minetest.log("error", "Failed to save "..npc_name)
|
||||
end
|
||||
|
||||
function npcf:set_animation(luaentity, state)
|
||||
if luaentity and state then
|
||||
if get_valid_entity(luaentity) and state then
|
||||
if state ~= luaentity.state then
|
||||
local speed = luaentity.animation_speed
|
||||
local anim = luaentity.animation
|
||||
@ -460,7 +483,7 @@ function npcf:get_index()
|
||||
end
|
||||
|
||||
function npcf:get_luaentity(npc_name)
|
||||
if npc_name then
|
||||
if get_valid_npc_name(npc_name) then
|
||||
for _,ref in pairs(minetest.luaentities) do
|
||||
if ref.object then
|
||||
if ref.npcf_id == "npc" and ref.npc_name == npc_name then
|
||||
@ -472,10 +495,12 @@ function npcf:get_luaentity(npc_name)
|
||||
end
|
||||
|
||||
function npcf:get_face_direction(v1, v2)
|
||||
if v1.x and v2.x and v1.z and v2.z then
|
||||
dx = v1.x - v2.x
|
||||
dz = v2.z - v1.z
|
||||
return math.atan2(dx, dz)
|
||||
if v1 and v2 then
|
||||
if v1.x and v2.x and v1.z and v2.z then
|
||||
dx = v1.x - v2.x
|
||||
dz = v2.z - v1.z
|
||||
return math.atan2(dx, dz)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user