[Mod] Node ownership [node_ownership]
-
- Member
- Posts: 214
- Joined: Thu Nov 17, 2011 06:31
- Location: California, USA
[Mod] Node ownership [node_ownership]
Node ownership
Description:
Here is a mod that can set some level of area ownership.
/set_owner PlayerName -100,-100,-100 100,100,100
And it will assign the cube area inside those 2 points to the player. This mod will prevent another player from placing or removing a node inside that area unless this player is added by the area's owner with the next function. The areas created with this function can not overlap. (Required to have "privs" privilege to use this function)
/add_owner PlayerName -100,-100,-100 100,100,100
Once a player is assigned an area he can call this function with the same pattern as /set_owner and allow other players to work in a part of his area. The areas created with this function can overlap.
/list_areas
Will show you all the entries in the owner table that you can delete. They will be the areas you own or areas you added for someone else in your area. (if you have "privs" then you will see all entries)
/remove_areas areaID
Will remove entry from owner table with this ID number. Use /list_owner_entries to see entries you can remove and what their IDs are.
/change_area_owner areaID new_owner
Allows you to transfer an area to a different player.
Requires some code changes to work right. The diff for the changes is at the top of the code here. Also, make sure the mod name is correct in the first line which sets 'owners_db_filename'
There is also a commented out change in 'minetest.register_on_placenode' that will be affected by the InvRef patch that is coming soon.
License(for my code/changes):
GPL
Download
Here is a download for the patched files if you can't get them to patch right. Mar 22, 2012, 10:15am PST(Date it was made)
Description:
Here is a mod that can set some level of area ownership.
/set_owner PlayerName -100,-100,-100 100,100,100
And it will assign the cube area inside those 2 points to the player. This mod will prevent another player from placing or removing a node inside that area unless this player is added by the area's owner with the next function. The areas created with this function can not overlap. (Required to have "privs" privilege to use this function)
/add_owner PlayerName -100,-100,-100 100,100,100
Once a player is assigned an area he can call this function with the same pattern as /set_owner and allow other players to work in a part of his area. The areas created with this function can overlap.
/list_areas
Will show you all the entries in the owner table that you can delete. They will be the areas you own or areas you added for someone else in your area. (if you have "privs" then you will see all entries)
/remove_areas areaID
Will remove entry from owner table with this ID number. Use /list_owner_entries to see entries you can remove and what their IDs are.
/change_area_owner areaID new_owner
Allows you to transfer an area to a different player.
Requires some code changes to work right. The diff for the changes is at the top of the code here. Also, make sure the mod name is correct in the first line which sets 'owners_db_filename'
There is also a commented out change in 'minetest.register_on_placenode' that will be affected by the InvRef patch that is coming soon.
License(for my code/changes):
GPL
Download
Here is a download for the patched files if you can't get them to patch right. Mar 22, 2012, 10:15am PST(Date it was made)
Last edited by randomproof on Sun Mar 25, 2012 01:07, edited 1 time in total.
- MrThebuilder3
- Member
- Posts: 104
- Joined: Sat Nov 19, 2011 18:26
-
- Member
- Posts: 214
- Joined: Thu Nov 17, 2011 06:31
- Location: California, USA
-
- Member
- Posts: 214
- Joined: Thu Nov 17, 2011 06:31
- Location: California, USA
I don't like the idea of an actual cornerstone-block. You need to points to define a 3d area so you would need two blocks and one would be floating in the air. I wanted a 3d area because you would want to protect area just above and below an area without having to protect any caves deep underneath. Also, it is just easier to code.robin wrote:Great idea, but i personally would like to see that with a cornerstone-block and a sign instead of the commands.
I also had the idea of making a mod that would use this mod and automatically assign a new player a plot when they first joined a server.
The area around the cornerstone should be protected. Every player gets one cornerstone upon first login. The cornerstone protect a fixed area (i.e. "cube-radius"=20). Cornerstone can be crafted from anrandomproof wrote: I don't like the idea of an actual cornerstone-block. You need to points to define a 3d area so you would need two blocks and one would be floating in the air. I wanted a 3d area because you would want to protect area just above and below an area without having to protect any caves deep underneath. Also, it is just easier to code.
expensive recipe. Signs next to cornerstones define who is able to dig.
This should not block interaction area with chests or similar items for other players.
I think you should be able to name the plot you want /name_plot (coors),(coors) so its easier to add_owner and such /add_owner (name) but also keep the coordinates ones so you can only give a part of the plot
Zen S.D.
The next generation of tranquility!malheureusement mon français n'est pas bon :<
Owner of the Zelo's
In game name: MuadTralk, spdtainted, sdzen, sd zen, sdzeno
- MirceaKitsune
- Member
- Posts: 941
- Joined: Sat May 21, 2011 22:31
- GitHub: MirceaKitsune
- IRC: Taoki
- In-game: MirceaKitsune
- Location: Romania, Bucharest
The idea of an ownership mod is good, but I'm not a fan of the approach used here (defining it via chat commands). The way I'd like this is by making it part of the fence. So when a player surrounds a whole area with fences, the blocks inside are his and others can't edit it. This would have its own issues of course... such as defining the height of the owned area, and people creating fences around objects they don't own in order to claim them. Still a nice idea I believe.
Well I just tried this mod and it seemed to work somewhat. I couldn't use /remove_areas as it didn't work. Also got the coords wrong apparently when adding an area so could you explain some more on this?
Also noticed that someone without permission can dig in an area and it looks to them like they dug despite it appearing to others they didn't. Thats with 0.4 20120122 version on Ubuntu.
Also noticed that someone without permission can dig in an area and it looks to them like they dug despite it appearing to others they didn't. Thats with 0.4 20120122 version on Ubuntu.
"Before you speak, ask yourself: Is it kind, is it true, is it necessary, does it improve upon the silence?"
My mods: http://goo.gl/n4kpn
(Currently Various, Industrial, Fakeblocks, Jail, MoarCraft, Christmas, Replicator, minetest dev installer for linux, bash mod installer, windows mod installer)
My mods: http://goo.gl/n4kpn
(Currently Various, Industrial, Fakeblocks, Jail, MoarCraft, Christmas, Replicator, minetest dev installer for linux, bash mod installer, windows mod installer)
Alright well I got it to working but is there some way to make it have all land available to anyone except for the land specifically marked as owned?
Right now it seems all land is off limits except what is specifically owned.
Right now it seems all land is off limits except what is specifically owned.
"Before you speak, ask yourself: Is it kind, is it true, is it necessary, does it improve upon the silence?"
My mods: http://goo.gl/n4kpn
(Currently Various, Industrial, Fakeblocks, Jail, MoarCraft, Christmas, Replicator, minetest dev installer for linux, bash mod installer, windows mod installer)
My mods: http://goo.gl/n4kpn
(Currently Various, Industrial, Fakeblocks, Jail, MoarCraft, Christmas, Replicator, minetest dev installer for linux, bash mod installer, windows mod installer)
Alright, so Raphael just put this on his server. One thing I noticed is that the whole world is not unplayable, technically speaking. No one can mine, dig, or build anything.
This should work in the reverse a bit. Instead of requiring ownership of an area. It should be, build house here, set ownership.
(better explanation) The whole world, should start out open and free to dig and build. Then you can add the "ownership" to the area.
Edit: Also, with adding a co-owner, it should be possible to remove them.
Edit2: Forget about the first edit. I found out what you did. Tricky! You should inform people about that. How when you add someone else to your area, that they are given an areaID.
This should work in the reverse a bit. Instead of requiring ownership of an area. It should be, build house here, set ownership.
(better explanation) The whole world, should start out open and free to dig and build. Then you can add the "ownership" to the area.
Edit: Also, with adding a co-owner, it should be possible to remove them.
Edit2: Forget about the first edit. I found out what you did. Tricky! You should inform people about that. How when you add someone else to your area, that they are given an areaID.
Last edited by Gatharoth on Mon Feb 27, 2012 07:42, edited 1 time in total.
- jordan4ibanez
- Member
- Posts: 1923
- Joined: Tue Sep 27, 2011 18:44
- GitHub: jordan4ibanez
- IRC: jordan4ibanez
- In-game: jordan4ibanez
-
- Member
- Posts: 214
- Joined: Thu Nov 17, 2011 06:31
- Location: California, USA
It took me a while to decide on how this would work and it hasn't had a lot of testing so there might bugs. And yes there is a problem with nodes being dug in that they disappear in the local client and not on the server. To fix that would require a code change.
I will take a look at putting together a README when I have some time tomorrow.
I will take a look at putting together a README when I have some time tomorrow.
Actually I've notice that when the player that dug the node, leaves that area, so that dug node is no longer visible. Then comes back. The node will be there again. Same with reconnecting to the server.randomproof wrote:It took me a while to decide on how this would work and it hasn't had a lot of testing so there might bugs. And yes there is a problem with nodes being dug in that they disappear in the local client and not on the server. To fix that would require a code change.
I will take a look at putting together a README when I have some time tomorrow.
So its not much of a problem.
-
- Member
- Posts: 214
- Joined: Thu Nov 17, 2011 06:31
- Location: California, USA
Yes, the client software assumes that the dig happens when it sends the request to the server and there is no way for my mod to tell the server to tell the client that this action didn't complete. The functionality is in the server (it is used when you try to dig something too far from the player) but the server is not checking to see if a mod aborted the function.Gatharoth wrote:Actually I've notice that when the player that dug the node, leaves that area, so that dug node is no longer visible. Then comes back. The node will be there again. Same with reconnecting to the server.randomproof wrote:It took me a while to decide on how this would work and it hasn't had a lot of testing so there might bugs. And yes there is a problem with nodes being dug in that they disappear in the local client and not on the server. To fix that would require a code change.
I will take a look at putting together a README when I have some time tomorrow.
So its not much of a problem.
Alright! I've done it. I've "reversed" how this works. So players can now dig and build on areas that have NO owners. And then later request ownership from someone who can set it. Now don't worry about griefers! Because the actual protection is still there! But only to areas that have an owner.
Here's the code for it.
Here is what is new.
So all I've done is added "if HasOwner(pos)" to both the dig, and place node functions. And closed it of course.
Here's the code for it.
Code: Select all
local owners_db_filename = minetest.get_modpath("node_ownership") .. "/owners.tbl"
do
-- declare local variables
--// exportstring( string )
--// returns a "Lua" portable version of the string
local function exportstring( s )
s = string.format( "%q",s )
-- to replace
s = string.gsub( s,"\\\n","\\n" )
s = string.gsub( s,"\r","\\r" )
s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" )
return s
end
--// The Save Function
function table.save( tbl,filename )
local charS,charE = " ","\n"
local file,err
-- create a pseudo file that writes to a string and return the string
if not filename then
file = { write = function( self,newstr ) self.str = self.str..newstr end, str = "" }
charS,charE = "",""
-- write table to tmpfile
elseif filename == true or filename == 1 then
charS,charE,file = "","",io.tmpfile()
-- write table to file
-- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error
else
file,err = io.open( filename, "w" )
if err then return _,err end
end
-- initiate variables for save procedure
local tables,lookup = { tbl },{ [tbl] = 1 }
file:write( "return {"..charE )
for idx,t in ipairs( tables ) do
if filename and filename ~= true and filename ~= 1 then
file:write( "-- Table: {"..idx.."}"..charE )
end
file:write( "{"..charE )
local thandled = {}
for i,v in ipairs( t ) do
thandled[i] = true
-- escape functions and userdata
if type( v ) ~= "userdata" then
-- only handle value
if type( v ) == "table" then
if not lookup[v] then
table.insert( tables, v )
lookup[v] = #tables
end
file:write( charS.."{"..lookup[v].."},"..charE )
elseif type( v ) == "function" then
file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE )
else
local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
file:write( charS..value..","..charE )
end
end
end
for i,v in pairs( t ) do
-- escape functions and userdata
if (not thandled[i]) and type( v ) ~= "userdata" then
-- handle index
if type( i ) == "table" then
if not lookup[i] then
table.insert( tables,i )
lookup[i] = #tables
end
file:write( charS.."[{"..lookup[i].."}]=" )
else
local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i )
file:write( charS..index.."=" )
end
-- handle value
if type( v ) == "table" then
if not lookup[v] then
table.insert( tables,v )
lookup[v] = #tables
end
file:write( "{"..lookup[v].."},"..charE )
elseif type( v ) == "function" then
file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE )
else
local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
file:write( value..","..charE )
end
end
end
file:write( "},"..charE )
end
file:write( "}" )
-- Return Values
-- return stringtable from string
if not filename then
-- set marker for stringtable
return file.str.."--|"
-- return stringttable from file
elseif filename == true or filename == 1 then
file:seek ( "set" )
-- no need to close file, it gets closed and removed automatically
-- set marker for stringtable
return file:read( "*a" ).."--|"
-- close file and return 1
else
file:close()
return 1
end
end
--// The Load Function
function table.load( sfile )
-- catch marker for stringtable
if string.sub( sfile,-3,-1 ) == "--|" then
tables,err = loadstring( sfile )
else
tables,err = loadfile( sfile )
end
if err then return _,err
end
tables = tables()
for idx = 1,#tables do
local tolinkv,tolinki = {},{}
for i,v in pairs( tables[idx] ) do
if type( v ) == "table" and tables[v[1]] then
table.insert( tolinkv,{ i,tables[v[1]] } )
end
if type( i ) == "table" and tables[i[1]] then
table.insert( tolinki,{ i,tables[i[1]] } )
end
end
-- link values, first due to possible changes of indices
for _,v in ipairs( tolinkv ) do
tables[idx][v[1]] = v[2]
end
-- link indices
for _,v in ipairs( tolinki ) do
tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil
end
end
return tables[1]
end
-- close do
end
owner_defs = table.load(owners_db_filename)
if type(owner_defs) ~= "table" then
owner_defs = {}
end
function IsPlayerNodeOwner(pos, name)
for _,def in pairs(owner_defs) do
if pos.x >= def.x1 and pos.x <= def.x2 or
pos.x <= def.x1 and pos.x >= def.x2 then
if pos.y >= def.y1 and pos.y <= def.y2 or
pos.y <= def.y1 and pos.y >= def.y2 then
if pos.z >= def.z1 and pos.z <= def.z2 or
pos.z <= def.z1 and pos.z >= def.z2 then
if name == def.owner then
return true
end
end
end
end
end
return false
end
function HasOwner(pos)
for _,def in pairs(owner_defs) do
if pos.x >= def.x1 and pos.x <= def.x2 or
pos.x <= def.x1 and pos.x >= def.x2 then
if pos.y >= def.y1 and pos.y <= def.y2 or
pos.y <= def.y1 and pos.y >= def.y2 then
if pos.z >= def.z1 and pos.z <= def.z2 or
pos.z <= def.z1 and pos.z >= def.z2 then
return true
end
end
end
end
return false
end
local old_node_place = minetest.item_place
function minetest.item_place(itemstack, placer, pointed_thing)
if itemstack:get_definition().type == "node" then
local pos = pointed_thing.above
if HasOwner(pos) then
if not IsPlayerNodeOwner(pos, placer:get_player_name()) then
minetest.chat_send_player(placer:get_player_name(), "You can not place nodes here.")
return itemstack
end
end
return old_node_place(itemstack, placer, pointed_thing)
end
return old_node_place(itemstack, placer, pointed_thing)
end
local old_node_dig = minetest.node_dig
function minetest.node_dig(pos, node, digger)
if HasOwner(pos) then
if not IsPlayerNodeOwner(pos, digger:get_player_name()) then
minetest.chat_send_player(digger:get_player_name(), "You can not dig nodes here.")
return
end
end
old_node_dig(pos, node, digger)
end
function CheckCollisions(pos1, pos2)
-- Find all 8 cube corners and make sure all 8 are not already in someone elses zone
pos3 = {x=pos2.x,y=pos1.y,z=pos1.z}
pos4 = {x=pos1.x,y=pos2.y,z=pos1.z}
pos5 = {x=pos1.x,y=pos2.y,z=pos2.z}
pos6 = {x=pos1.x,y=pos1.y,z=pos2.z}
pos7 = {x=pos2.x,y=pos2.y,z=pos1.z}
pos8 = {x=pos2.x,y=pos1.y,z=pos2.z}
if HasOwner(pos1) == false and
HasOwner(pos2) == false and
HasOwner(pos3) == false and
HasOwner(pos4) == false and
HasOwner(pos5) == false and
HasOwner(pos6) == false and
HasOwner(pos7) == false and
HasOwner(pos8) == false then
return false
end
return true
end
function RemoveTableEntryRe(r_id)
--Find child entries and remove them
for n,def in pairs(owner_defs) do
if def.parent == r_id then
RemoveTableEntryRe(def.id)
end
end
-- now remove main entry
for n,def in pairs(owner_defs) do
if def.id == r_id then
table.remove(owner_defs, n)
break
end
end
end
function RemoveTableEntry(r_id)
RemoveTableEntryRe(r_id)
--Re-number ids to match place in table
for n,ndef in pairs(owner_defs) do
if ndef.id ~= n then
for p,pdef in pairs(owner_defs) do
if pdef.parent == ndef.id then
pdef.parent = n
end
end
ndef.id = n
end
end
table.save( owner_defs, owners_db_filename )
end
minetest.register_on_chat_message(function(name, message)
local cmd = "/set_owner"
if message:sub(0, #cmd) == cmd then
if not minetest.get_player_privs(name)["privs"] then
minetest.chat_send_player(name, "you don't have permission to do this")
return true -- Handled chat message
end
local ownername, sx, sy, sz, ex, ey, ez = string.match(message, cmd.." (.-) ([0-9%-]-)%,([0-9%-]-)%,([0-9%-]-) ([0-9%-]-)%,([0-9%-]-)%,([0-9%-]*)")
if ownername == nil or string.len(ownername) == 0
or sx == nil or string.len(sx) == 0
or sy == nil or string.len(sy) == 0
or sz == nil or string.len(sz) == 0
or ex == nil or string.len(ex) == 0
or ey == nil or string.len(ey) == 0
or ez == nil or string.len(ez) == 0
then
minetest.chat_send_player(name, 'usage: '..cmd..' playername startpos endpos')
return true -- Handled chat message
end
local player = minetest.env:get_player_by_name(ownername)
if player == nil then
print("player is nil")
return true -- Handled chat message
end
print(cmd.." invoked, owner=" .. ownername .. " startpos=" .. sx .. "," .. sy .. "," .. sz .. " endpos=" .. ex .. "," .. ey .. "," .. ez)
sx = tonumber(sx)
sy = tonumber(sy)
sz = tonumber(sz)
ex = tonumber(ex)
ey = tonumber(ey)
ez = tonumber(ez)
if (CheckCollisions({x=sx,y=sy,z=sz}, {x=ex,y=ey,z=ez})) == true then
minetest.chat_send_player(name, "Owner Collision")
return true -- Handled chat message
end
table.insert(owner_defs, {x1=sx, y1=sy, z1=sz, x2=ex, y2=ey, z2=ez, owner=ownername})
owner_defs[table.maxn(owner_defs)].id = table.maxn(owner_defs)
table.save( owner_defs, owners_db_filename )
return true -- Handled chat message
end
local cmd = "/add_owner"
if message:sub(0, #cmd) == cmd then
local new_ownername, sx, sy, sz, ex, ey, ez = string.match(message, cmd.." (.-) ([0-9%-]-)%,([0-9%-]-)%,([0-9%-]-) ([0-9%-]-)%,([0-9%-]-)%,([0-9%-]*)")
if new_ownername == nil or string.len(new_ownername) == 0
or sx == nil or string.len(sx) == 0
or sy == nil or string.len(sy) == 0
or sz == nil or string.len(sz) == 0
or ex == nil or string.len(ex) == 0
or ey == nil or string.len(ey) == 0
or ez == nil or string.len(ez) == 0
then
minetest.chat_send_player(name, 'usage: '..cmd..' playername startpos endpos')
return true -- Handled chat message
end
local player = minetest.env:get_player_by_name(new_ownername)
if player == nil then
print("player is nil")
return true -- Handled chat message
end
print(cmd.." invoked, new_ownername=" .. new_ownername .. " startpos=" .. sx .. "," .. sy .. "," .. sz .. " endpos=" .. ex .. "," .. ey .. "," .. ez)
sx = tonumber(sx)
sy = tonumber(sy)
sz = tonumber(sz)
ex = tonumber(ex)
ey = tonumber(ey)
ez = tonumber(ez)
area_pos1 = {x=sx, y=sy, z=sz}
area_pos2 = {x=ex, y=ey, z=ez}
p=nil
--Look to see if this new area is inside an area owned by the player using this function
for n,def in pairs(owner_defs) do
if (area_pos1.x >= def.x1 and area_pos1.x <= def.x2 or
area_pos1.x <= def.x1 and area_pos1.x >= def.x2) and
(area_pos2.x >= def.x1 and area_pos2.x <= def.x2 or
area_pos2.x <= def.x1 and area_pos2.x >= def.x2) then
if (area_pos1.y >= def.y1 and area_pos1.y <= def.y2 or
area_pos1.y <= def.y1 and area_pos1.y >= def.y2) and
(area_pos2.y >= def.y1 and area_pos2.y <= def.y2 or
area_pos2.y <= def.y1 and area_pos2.y >= def.y2) then
if (area_pos1.z >= def.z1 and area_pos1.z <= def.z2 or
area_pos1.z <= def.z1 and area_pos1.z >= def.z2) and
(area_pos2.z >= def.z1 and area_pos2.z <= def.z2 or
area_pos2.z <= def.z1 and area_pos2.z >= def.z2) then
--OK, found entry that has both area_poss
if def.owner == name then
p=def.id
break
end
end
end
end
end
if p == nil then
minetest.chat_send_player(name, "You don't have permission to do this")
return true -- Handled chat message
end
table.insert(owner_defs, {x1=sx, y1=sy, z1=sz, x2=ex, y2=ey, z2=ez, owner=new_ownername})
if p ~= nil then
owner_defs[table.maxn(owner_defs)].parent = p
end
owner_defs[table.maxn(owner_defs)].id = table.maxn(owner_defs)
table.save( owner_defs, owners_db_filename )
return true -- Handled chat message
end
local cmd = "/list_areas"
if message:sub(0, #cmd) == cmd then
show_all = false
if minetest.get_player_privs(name)["privs"] then
show_all = true
minetest.chat_send_player(name, "Showing all owner entries")
for n,def in pairs(owner_defs) do
entry = def.id .. ": " .. def.owner .. " (" .. def.x1 .. "," .. def.y1 .. "," .. def.z1 .. ") (" .. def.x2 .. "," .. def.y2 .. "," .. def.z2 .. ")"
if def.parent ~= nil then
entry = entry .. " parent: " .. def.parent
end
minetest.chat_send_player(name, entry)
end
else
minetest.chat_send_player(name, "Showing your owner entries (You can delete only these)")
for n,def in pairs(owner_defs) do
if def.owner == name then
entry = def.id .. ": " .. def.owner .. " (" .. def.x1 .. "," .. def.y1 .. "," .. def.z1 .. ") (" .. def.x2 .. "," .. def.y2 .. "," .. def.z2 .. ")"
if def.parent ~= nil then
entry = entry .. " parent: " .. def.parent
end
minetest.chat_send_player(name, entry)
for n,defc in pairs(owner_defs) do
if defc.parent == def.id then
entry = "->" .. defc.id .. ": " .. defc.owner .. " (" .. defc.x1 .. "," .. defc.y1 .. "," .. defc.z1 .. ") (" .. defc.x2 .. "," .. defc.y2 .. "," .. defc.z2 .. ")"
if defc.parent ~= nil then
entry = entry .. " parent: " .. defc.parent
end
minetest.chat_send_player(name, entry)
end
end
end
end
end
end
local cmd = "/remove_areas"
if message:sub(0, #cmd) == cmd then
your_ids = {}
for n,def in pairs(owner_defs) do
if def.owner == name then
table.insert(your_ids, def.id)
for n,defc in pairs(owner_defs) do
if defc.parent == def.id then
table.insert(your_ids, defc.id)
end
end
end
end
local e = string.match(message, cmd.." (.*)")
if e == nil or string.len(e) == 0 then
minetest.chat_send_player(name, 'usage: '..cmd..' entry_number')
minetest.chat_send_player(name, 'use /list_owner_entries to see entries')
return true -- Handled chat message
end
e = tonumber(e)
found = false
for _,k in pairs(your_ids) do
if k == e then
RemoveTableEntry(e)
table.save( owner_defs, owners_db_filename )
return true -- Handled chat message
end
end
return true -- Handled chat message
end
local cmd = "/change_area_owner"
if message:sub(0, #cmd) == cmd then
your_ids = {}
for n,def in pairs(owner_defs) do
if def.owner == name then
table.insert(your_ids, def.id)
for n,defc in pairs(owner_defs) do
if defc.parent == def.id then
table.insert(your_ids, defc.id)
end
end
end
end
local e, new_owner = string.match(message, cmd.." (.-) (.*)")
if e == nil or new_owner == nil or
string.len(e) == 0 or string.len(new_owner) == 0 then
minetest.chat_send_player(name, 'usage: '..cmd..' entry_number new_owner')
minetest.chat_send_player(name, 'use /list_owner_entries to see entries')
return true -- Handled chat message
end
local player = minetest.env:get_player_by_name(new_owner)
if player == nil then
print("new_owner is nil")
return true -- Handled chat message
end
e = tonumber(e)
found = false
for _,k in pairs(your_ids) do
if k == e then
for n,def in pairs(owner_defs) do
if def.id == e then
owner_defs[n].owner = new_owner
table.save( owner_defs, owners_db_filename )
return true -- Handled chat message
end
end
end
end
return true -- Handled chat message
end
end)
Code: Select all
function minetest.item_place(itemstack, placer, pointed_thing)
if itemstack:get_definition().type == "node" then
local pos = pointed_thing.above
if HasOwner(pos) then
if not IsPlayerNodeOwner(pos, placer:get_player_name()) then
minetest.chat_send_player(placer:get_player_name(), "You can not place nodes here.")
return itemstack
end
end
return old_node_place(itemstack, placer, pointed_thing)
end
return old_node_place(itemstack, placer, pointed_thing)
end
local old_node_dig = minetest.node_dig
function minetest.node_dig(pos, node, digger)
if HasOwner(pos) then
if not IsPlayerNodeOwner(pos, digger:get_player_name()) then
minetest.chat_send_player(digger:get_player_name(), "You can not dig nodes here.")
return
end
end
old_node_dig(pos, node, digger)
end
+1 solves my problemGatharoth wrote:Alright! I've done it. I've "reversed" how this works. So players can now dig and build on areas that have NO owners. And then later request ownership from someone who can set it. Now don't worry about griefers! Because the actual protection is still there! But only to areas that have an owner.
Here's the code for it.
Here is what is new.Code: Select all
local owners_db_filename = minetest.get_modpath("node_ownership") .. "/owners.tbl" do -- declare local variables --// exportstring( string ) --// returns a "Lua" portable version of the string local function exportstring( s ) s = string.format( "%q",s ) -- to replace s = string.gsub( s,"\\\n","\\n" ) s = string.gsub( s,"\r","\\r" ) s = string.gsub( s,string.char(26),""..string.char(26).."" ) return s end --// The Save Function function table.save( tbl,filename ) local charS,charE = " ","\n" local file,err -- create a pseudo file that writes to a string and return the string if not filename then file = { write = function( self,newstr ) self.str = self.str..newstr end, str = "" } charS,charE = "","" -- write table to tmpfile elseif filename == true or filename == 1 then charS,charE,file = "","",io.tmpfile() -- write table to file -- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error else file,err = io.open( filename, "w" ) if err then return _,err end end -- initiate variables for save procedure local tables,lookup = { tbl },{ [tbl] = 1 } file:write( "return {"..charE ) for idx,t in ipairs( tables ) do if filename and filename ~= true and filename ~= 1 then file:write( "-- Table: {"..idx.."}"..charE ) end file:write( "{"..charE ) local thandled = {} for i,v in ipairs( t ) do thandled[i] = true -- escape functions and userdata if type( v ) ~= "userdata" then -- only handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables, v ) lookup[v] = #tables end file:write( charS.."{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( charS..value..","..charE ) end end end for i,v in pairs( t ) do -- escape functions and userdata if (not thandled[i]) and type( v ) ~= "userdata" then -- handle index if type( i ) == "table" then if not lookup[i] then table.insert( tables,i ) lookup[i] = #tables end file:write( charS.."[{"..lookup[i].."}]=" ) else local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i ) file:write( charS..index.."=" ) end -- handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables,v ) lookup[v] = #tables end file:write( "{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( value..","..charE ) end end end file:write( "},"..charE ) end file:write( "}" ) -- Return Values -- return stringtable from string if not filename then -- set marker for stringtable return file.str.."--|" -- return stringttable from file elseif filename == true or filename == 1 then file:seek ( "set" ) -- no need to close file, it gets closed and removed automatically -- set marker for stringtable return file:read( "*a" ).."--|" -- close file and return 1 else file:close() return 1 end end --// The Load Function function table.load( sfile ) -- catch marker for stringtable if string.sub( sfile,-3,-1 ) == "--|" then tables,err = loadstring( sfile ) else tables,err = loadfile( sfile ) end if err then return _,err end tables = tables() for idx = 1,#tables do local tolinkv,tolinki = {},{} for i,v in pairs( tables[idx] ) do if type( v ) == "table" and tables[v[1]] then table.insert( tolinkv,{ i,tables[v[1]] } ) end if type( i ) == "table" and tables[i[1]] then table.insert( tolinki,{ i,tables[i[1]] } ) end end -- link values, first due to possible changes of indices for _,v in ipairs( tolinkv ) do tables[idx][v[1]] = v[2] end -- link indices for _,v in ipairs( tolinki ) do tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil end end return tables[1] end -- close do end owner_defs = table.load(owners_db_filename) if type(owner_defs) ~= "table" then owner_defs = {} end function IsPlayerNodeOwner(pos, name) for _,def in pairs(owner_defs) do if pos.x >= def.x1 and pos.x <= def.x2 or pos.x <= def.x1 and pos.x >= def.x2 then if pos.y >= def.y1 and pos.y <= def.y2 or pos.y <= def.y1 and pos.y >= def.y2 then if pos.z >= def.z1 and pos.z <= def.z2 or pos.z <= def.z1 and pos.z >= def.z2 then if name == def.owner then return true end end end end end return false end function HasOwner(pos) for _,def in pairs(owner_defs) do if pos.x >= def.x1 and pos.x <= def.x2 or pos.x <= def.x1 and pos.x >= def.x2 then if pos.y >= def.y1 and pos.y <= def.y2 or pos.y <= def.y1 and pos.y >= def.y2 then if pos.z >= def.z1 and pos.z <= def.z2 or pos.z <= def.z1 and pos.z >= def.z2 then return true end end end end return false end local old_node_place = minetest.item_place function minetest.item_place(itemstack, placer, pointed_thing) if itemstack:get_definition().type == "node" then local pos = pointed_thing.above if HasOwner(pos) then if not IsPlayerNodeOwner(pos, placer:get_player_name()) then minetest.chat_send_player(placer:get_player_name(), "You can not place nodes here.") return itemstack end end return old_node_place(itemstack, placer, pointed_thing) end return old_node_place(itemstack, placer, pointed_thing) end local old_node_dig = minetest.node_dig function minetest.node_dig(pos, node, digger) if HasOwner(pos) then if not IsPlayerNodeOwner(pos, digger:get_player_name()) then minetest.chat_send_player(digger:get_player_name(), "You can not dig nodes here.") return end end old_node_dig(pos, node, digger) end function CheckCollisions(pos1, pos2) -- Find all 8 cube corners and make sure all 8 are not already in someone elses zone pos3 = {x=pos2.x,y=pos1.y,z=pos1.z} pos4 = {x=pos1.x,y=pos2.y,z=pos1.z} pos5 = {x=pos1.x,y=pos2.y,z=pos2.z} pos6 = {x=pos1.x,y=pos1.y,z=pos2.z} pos7 = {x=pos2.x,y=pos2.y,z=pos1.z} pos8 = {x=pos2.x,y=pos1.y,z=pos2.z} if HasOwner(pos1) == false and HasOwner(pos2) == false and HasOwner(pos3) == false and HasOwner(pos4) == false and HasOwner(pos5) == false and HasOwner(pos6) == false and HasOwner(pos7) == false and HasOwner(pos8) == false then return false end return true end function RemoveTableEntryRe(r_id) --Find child entries and remove them for n,def in pairs(owner_defs) do if def.parent == r_id then RemoveTableEntryRe(def.id) end end -- now remove main entry for n,def in pairs(owner_defs) do if def.id == r_id then table.remove(owner_defs, n) break end end end function RemoveTableEntry(r_id) RemoveTableEntryRe(r_id) --Re-number ids to match place in table for n,ndef in pairs(owner_defs) do if ndef.id ~= n then for p,pdef in pairs(owner_defs) do if pdef.parent == ndef.id then pdef.parent = n end end ndef.id = n end end table.save( owner_defs, owners_db_filename ) end minetest.register_on_chat_message(function(name, message) local cmd = "/set_owner" if message:sub(0, #cmd) == cmd then if not minetest.get_player_privs(name)["privs"] then minetest.chat_send_player(name, "you don't have permission to do this") return true -- Handled chat message end local ownername, sx, sy, sz, ex, ey, ez = string.match(message, cmd.." (.-) ([0-9%-]-)%,([0-9%-]-)%,([0-9%-]-) ([0-9%-]-)%,([0-9%-]-)%,([0-9%-]*)") if ownername == nil or string.len(ownername) == 0 or sx == nil or string.len(sx) == 0 or sy == nil or string.len(sy) == 0 or sz == nil or string.len(sz) == 0 or ex == nil or string.len(ex) == 0 or ey == nil or string.len(ey) == 0 or ez == nil or string.len(ez) == 0 then minetest.chat_send_player(name, 'usage: '..cmd..' playername startpos endpos') return true -- Handled chat message end local player = minetest.env:get_player_by_name(ownername) if player == nil then print("player is nil") return true -- Handled chat message end print(cmd.." invoked, owner=" .. ownername .. " startpos=" .. sx .. "," .. sy .. "," .. sz .. " endpos=" .. ex .. "," .. ey .. "," .. ez) sx = tonumber(sx) sy = tonumber(sy) sz = tonumber(sz) ex = tonumber(ex) ey = tonumber(ey) ez = tonumber(ez) if (CheckCollisions({x=sx,y=sy,z=sz}, {x=ex,y=ey,z=ez})) == true then minetest.chat_send_player(name, "Owner Collision") return true -- Handled chat message end table.insert(owner_defs, {x1=sx, y1=sy, z1=sz, x2=ex, y2=ey, z2=ez, owner=ownername}) owner_defs[table.maxn(owner_defs)].id = table.maxn(owner_defs) table.save( owner_defs, owners_db_filename ) return true -- Handled chat message end local cmd = "/add_owner" if message:sub(0, #cmd) == cmd then local new_ownername, sx, sy, sz, ex, ey, ez = string.match(message, cmd.." (.-) ([0-9%-]-)%,([0-9%-]-)%,([0-9%-]-) ([0-9%-]-)%,([0-9%-]-)%,([0-9%-]*)") if new_ownername == nil or string.len(new_ownername) == 0 or sx == nil or string.len(sx) == 0 or sy == nil or string.len(sy) == 0 or sz == nil or string.len(sz) == 0 or ex == nil or string.len(ex) == 0 or ey == nil or string.len(ey) == 0 or ez == nil or string.len(ez) == 0 then minetest.chat_send_player(name, 'usage: '..cmd..' playername startpos endpos') return true -- Handled chat message end local player = minetest.env:get_player_by_name(new_ownername) if player == nil then print("player is nil") return true -- Handled chat message end print(cmd.." invoked, new_ownername=" .. new_ownername .. " startpos=" .. sx .. "," .. sy .. "," .. sz .. " endpos=" .. ex .. "," .. ey .. "," .. ez) sx = tonumber(sx) sy = tonumber(sy) sz = tonumber(sz) ex = tonumber(ex) ey = tonumber(ey) ez = tonumber(ez) area_pos1 = {x=sx, y=sy, z=sz} area_pos2 = {x=ex, y=ey, z=ez} p=nil --Look to see if this new area is inside an area owned by the player using this function for n,def in pairs(owner_defs) do if (area_pos1.x >= def.x1 and area_pos1.x <= def.x2 or area_pos1.x <= def.x1 and area_pos1.x >= def.x2) and (area_pos2.x >= def.x1 and area_pos2.x <= def.x2 or area_pos2.x <= def.x1 and area_pos2.x >= def.x2) then if (area_pos1.y >= def.y1 and area_pos1.y <= def.y2 or area_pos1.y <= def.y1 and area_pos1.y >= def.y2) and (area_pos2.y >= def.y1 and area_pos2.y <= def.y2 or area_pos2.y <= def.y1 and area_pos2.y >= def.y2) then if (area_pos1.z >= def.z1 and area_pos1.z <= def.z2 or area_pos1.z <= def.z1 and area_pos1.z >= def.z2) and (area_pos2.z >= def.z1 and area_pos2.z <= def.z2 or area_pos2.z <= def.z1 and area_pos2.z >= def.z2) then --OK, found entry that has both area_poss if def.owner == name then p=def.id break end end end end end if p == nil then minetest.chat_send_player(name, "You don't have permission to do this") return true -- Handled chat message end table.insert(owner_defs, {x1=sx, y1=sy, z1=sz, x2=ex, y2=ey, z2=ez, owner=new_ownername}) if p ~= nil then owner_defs[table.maxn(owner_defs)].parent = p end owner_defs[table.maxn(owner_defs)].id = table.maxn(owner_defs) table.save( owner_defs, owners_db_filename ) return true -- Handled chat message end local cmd = "/list_areas" if message:sub(0, #cmd) == cmd then show_all = false if minetest.get_player_privs(name)["privs"] then show_all = true minetest.chat_send_player(name, "Showing all owner entries") for n,def in pairs(owner_defs) do entry = def.id .. ": " .. def.owner .. " (" .. def.x1 .. "," .. def.y1 .. "," .. def.z1 .. ") (" .. def.x2 .. "," .. def.y2 .. "," .. def.z2 .. ")" if def.parent ~= nil then entry = entry .. " parent: " .. def.parent end minetest.chat_send_player(name, entry) end else minetest.chat_send_player(name, "Showing your owner entries (You can delete only these)") for n,def in pairs(owner_defs) do if def.owner == name then entry = def.id .. ": " .. def.owner .. " (" .. def.x1 .. "," .. def.y1 .. "," .. def.z1 .. ") (" .. def.x2 .. "," .. def.y2 .. "," .. def.z2 .. ")" if def.parent ~= nil then entry = entry .. " parent: " .. def.parent end minetest.chat_send_player(name, entry) for n,defc in pairs(owner_defs) do if defc.parent == def.id then entry = "->" .. defc.id .. ": " .. defc.owner .. " (" .. defc.x1 .. "," .. defc.y1 .. "," .. defc.z1 .. ") (" .. defc.x2 .. "," .. defc.y2 .. "," .. defc.z2 .. ")" if defc.parent ~= nil then entry = entry .. " parent: " .. defc.parent end minetest.chat_send_player(name, entry) end end end end end end local cmd = "/remove_areas" if message:sub(0, #cmd) == cmd then your_ids = {} for n,def in pairs(owner_defs) do if def.owner == name then table.insert(your_ids, def.id) for n,defc in pairs(owner_defs) do if defc.parent == def.id then table.insert(your_ids, defc.id) end end end end local e = string.match(message, cmd.." (.*)") if e == nil or string.len(e) == 0 then minetest.chat_send_player(name, 'usage: '..cmd..' entry_number') minetest.chat_send_player(name, 'use /list_owner_entries to see entries') return true -- Handled chat message end e = tonumber(e) found = false for _,k in pairs(your_ids) do if k == e then RemoveTableEntry(e) table.save( owner_defs, owners_db_filename ) return true -- Handled chat message end end return true -- Handled chat message end local cmd = "/change_area_owner" if message:sub(0, #cmd) == cmd then your_ids = {} for n,def in pairs(owner_defs) do if def.owner == name then table.insert(your_ids, def.id) for n,defc in pairs(owner_defs) do if defc.parent == def.id then table.insert(your_ids, defc.id) end end end end local e, new_owner = string.match(message, cmd.." (.-) (.*)") if e == nil or new_owner == nil or string.len(e) == 0 or string.len(new_owner) == 0 then minetest.chat_send_player(name, 'usage: '..cmd..' entry_number new_owner') minetest.chat_send_player(name, 'use /list_owner_entries to see entries') return true -- Handled chat message end local player = minetest.env:get_player_by_name(new_owner) if player == nil then print("new_owner is nil") return true -- Handled chat message end e = tonumber(e) found = false for _,k in pairs(your_ids) do if k == e then for n,def in pairs(owner_defs) do if def.id == e then owner_defs[n].owner = new_owner table.save( owner_defs, owners_db_filename ) return true -- Handled chat message end end end end return true -- Handled chat message end end)
So all I've done is added "if HasOwner(pos)" to both the dig, and place node functions. And closed it of course.Code: Select all
function minetest.item_place(itemstack, placer, pointed_thing) if itemstack:get_definition().type == "node" then local pos = pointed_thing.above if HasOwner(pos) then if not IsPlayerNodeOwner(pos, placer:get_player_name()) then minetest.chat_send_player(placer:get_player_name(), "You can not place nodes here.") return itemstack end end return old_node_place(itemstack, placer, pointed_thing) end return old_node_place(itemstack, placer, pointed_thing) end local old_node_dig = minetest.node_dig function minetest.node_dig(pos, node, digger) if HasOwner(pos) then if not IsPlayerNodeOwner(pos, digger:get_player_name()) then minetest.chat_send_player(digger:get_player_name(), "You can not dig nodes here.") return end end old_node_dig(pos, node, digger) end
"Before you speak, ask yourself: Is it kind, is it true, is it necessary, does it improve upon the silence?"
My mods: http://goo.gl/n4kpn
(Currently Various, Industrial, Fakeblocks, Jail, MoarCraft, Christmas, Replicator, minetest dev installer for linux, bash mod installer, windows mod installer)
My mods: http://goo.gl/n4kpn
(Currently Various, Industrial, Fakeblocks, Jail, MoarCraft, Christmas, Replicator, minetest dev installer for linux, bash mod installer, windows mod installer)
-
- Member
- Posts: 214
- Joined: Thu Nov 17, 2011 06:31
- Location: California, USA
Thank you, I've added this to the first post. I think someone is working on a method of interacting with players with some kind of a GUI so when/if that happens it might be possible to get rid of the confusing chat commands.Gatharoth wrote:Alright! I've done it. I've "reversed" how this works. So players can now dig and build on areas that have NO owners. And then later request ownership from someone who can set it. Now don't worry about griefers! Because the actual protection is still there! But only to areas that have an owner.
Here's the code for it.
So all I've done is added "if HasOwner(pos)" to both the dig, and place node functions. And closed it of course.Code: Select all
...
Last edited by randomproof on Tue Feb 28, 2012 16:39, edited 1 time in total.
I'm still working on upgrading my "clans" fork to 0.4. It has new block borderstone, by which you can own a 16x16x16 terrain block. IMO much better than any gui or chat commands.
Check this thread in a few weeks.
Check this thread in a few weeks.
Last edited by jachoo on Tue Feb 28, 2012 16:59, edited 1 time in total.
Well I actually like the idea of players getting say 8 blocks that they place at the corners of the land they want (with limits of size). That way one could protect areas without blocks littering it.jachoo wrote:I'm still working on upgrading my "clans" fork to 0.4. It has new block borderstone, by which you can own a 16x16x16 terrain block. IMO much better than any gui or chat commands.
Check this thread in a few weeks.
"Before you speak, ask yourself: Is it kind, is it true, is it necessary, does it improve upon the silence?"
My mods: http://goo.gl/n4kpn
(Currently Various, Industrial, Fakeblocks, Jail, MoarCraft, Christmas, Replicator, minetest dev installer for linux, bash mod installer, windows mod installer)
My mods: http://goo.gl/n4kpn
(Currently Various, Industrial, Fakeblocks, Jail, MoarCraft, Christmas, Replicator, minetest dev installer for linux, bash mod installer, windows mod installer)
randomproof wrote:Yes, the client software assumes that the dig happens when it sends the request to the server and there is no way for my mod to tell the server to tell the client that this action didn't complete. The functionality is in the server (it is used when you try to dig something too far from the player) but the server is not checking to see if a mod aborted the function.
Question, do you think forcing a node_update would "fix" this problem?
Edit: Never mind. Tried it, and it didn't work.
Last edited by Gatharoth on Wed Feb 29, 2012 04:10, edited 1 time in total.
Who is online
Users browsing this forum: No registered users and 6 guests