add void_chest particle switch, tweaks to void_chest: add misteres original animation, net-performance tweaks, staging meseportals, update git notes.

master
MeseCraft 2022-07-18 23:27:27 -05:00
parent c04faca957
commit d4e504fd1a
48 changed files with 6495 additions and 36 deletions

View File

@ -1,19 +1,19 @@
## Just some notes on how to properly use git.
add changes
# add changes
git add .
commit changes to branch
# commit changes to branch
git commit
push changes to repo
# push changes to repo
git push
Switch working branch in git:
# Switch working branch in git:
git checkout <branch-name>
merges changes from master into current working branch.
git merge master
# merge changes from "testing" branch into current working branch.
git merge testing
updates local files from git
# updates local files from git
git pull

View File

@ -1,3 +1,7 @@
void_chest = {
show_particles = (minetest.settings:get("void_chest.show_particles") ~= "false")
}
-- Register the void chest.
minetest.register_node("void_chest:void_chest", {
description = "" ..core.colorize("#660099","Void Chest\n") ..core.colorize("#FFFFFF", "Use the power of the void to store your items."),
@ -8,8 +12,10 @@ minetest.register_node("void_chest:void_chest", {
legacy_facedir_simple = true,
sounds = default.node_sound_wood_defaults(),
on_construct = function(pos)
local timer = minetest.get_node_timer(pos)
timer:start(.1) -- in seconds
if void_chest.show_particles then
local timer = minetest.get_node_timer(pos)
timer:start(.1) -- in seconds
end
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
"size[8,9]"..
@ -38,32 +44,39 @@ minetest.register_node("void_chest:void_chest", {
" takes stuff from void chest at "..minetest.pos_to_string(pos))
end,
on_timer = function(pos)
-- Particles for the void effect, implemented by MisterE, thanks!
for i=1,10 do -- number of particles spawned every on_timer
local vel_scalar = math.random(0,5)/10 -- multiplied by the particle's velocity vector of 1
local accel_scalar = math.random(1,5)/10 -- multiplied by the particle's accel vector of 1
local expir = math.random(1,10) -- number of sec particle will last, if it doesn't hit a node
local particle_pos = {x=pos.x + ((math.random(-10,10)/10)*(math.random(6,15)/10)), y=pos.y + ((math.random(-10,10)/10)*(math.random(6,15)/10)), z=pos.z+ ((math.random(-10,10)/10)*(math.random(6,15)/10))}
local part_vel = vector.direction(particle_pos, pos)
part_vel = {x= vel_scalar*part_vel.x, y= vel_scalar*part_vel.y, z= vel_scalar*part_vel.z}
local part_accel = vector.direction(particle_pos, pos)
part_accel = {x= accel_scalar*part_accel.x, y= accel_scalar*part_accel.y, z= accel_scalar*part_accel.z}
minetest.add_particle({
pos = particle_pos,
velocity = part_vel,
acceleration = part_accel,
expirationtime = expir,
size = math.random(7,10)/10,
collisiondetection = true,
collision_removal = true,
vertical = false,
texture = "void_chest_void_particle.png",
glow = 5,
})
if void_chest.show_particles then
-- Particles for the void effect, implemented by MisterE, thanks!
for i=1,2 do -- number of particles spawned every on_timer
local spin_speed = math.random(80,175)/1000 --controls how fast a particular particle spins
local vel_scalar = math.random(0,5)/10 -- multiplied by the particle's velocity vector of 1
local accel_scalar = math.random(1,5)/10 -- multiplied by the particle's accel vector of 1
local expir = math.random(1,5) -- number of sec particle will last, if it doesn't hit a node
local particle_pos = {x=pos.x + ((math.random(-15,15)/10)*(math.random(6,15)/10)), y=pos.y + ((math.random(-15,15)/10)*(math.random(6,15)/10)), z=pos.z+ ((math.random(-15,15)/10)*(math.random(6,15)/10))}
local part_vel = vector.direction(particle_pos, pos)
part_vel = {x= vel_scalar*part_vel.x, y= vel_scalar*part_vel.y, z= vel_scalar*part_vel.z}
local part_accel = vector.direction(particle_pos, pos)
part_accel = {x= accel_scalar*part_accel.x, y= accel_scalar*part_accel.y, z= accel_scalar*part_accel.z}
minetest.add_particle({
pos = particle_pos,
velocity = part_vel,
acceleration = part_accel,
expirationtime = expir,
size = math.random(5,15)/10,
collisiondetection = true,
collision_removal = true,
vertical = false,
texture = "void_chest_void_particle.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = spin_speed,
},
glow = 5,
})
end
end
return true
return true
end,
})
@ -80,7 +93,7 @@ if minetest.get_modpath("magic_materials") then
}
})
else -- Else we use a recipe using "default" to avoid a hard dependency.
minetest.register_craft({
minetest.register_craft({
output = 'void_chest:void_chest',
recipe = {
{'default:steelblock','default:obsidian_block','default:steelblock'},
@ -94,3 +107,4 @@ minetest.register_on_joinplayer(function(player)
local inv = player:get_inventory()
inv:set_size("void_chest:void_chest", 8*4)
end)

View File

@ -0,0 +1,8 @@
# VOID CHEST SETTINGS
# VOID CHEST:
# on low performance servers the particles can cause a drop in performance.
# Default: true
void_chest.show_particles (Show Particles) bool true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,20 @@
Changes by Piezo_:
Improved portal response time by changing the teleport routine from a node update to a global step
Changed how portals update their world-node
Changed model scale and hitbox dimensions
Vertically offset model to be partially buried.
Non-player objects can now travel through portals
Reduced active portal brightness somewhat
Restructured portal network to prevent players causing trouble by naming themself "players" or "registered_players"
Visual style and sounds completely re-done to add originality
Public portals can now be used by anyone, but only the portal's owner can set the description and public/private state.
Server operators can disable "ownership" of portals by setting meseportals.allowPrivatePortals (in init.lua) to false
Added search bar, and formspec security measures.
A maximum number of allowed portals per player can be set via meseportals.maxPlayerPortals
Added permissions "msp_admin", which allows full control and access to all portals, and "msp_unlimited", which bypasses the portal cap.
Portals and all associated nodes are now fully protection-aware.
Reorganized/Split up files
Position and rotation relative to the portal are now maintained, making travel feel smoother.
Changes by SpaghettiToastBook:
Added meseportals.can_connect

View File

@ -0,0 +1,39 @@
Media:
Portal, item, and controller textures: CC BY-SA (4.0) by Piezo_
textures/meseportal_adminlock.png: CC BY-SA (4.0) by Piezo_
Other GUI Elements: See <https://github.com/minetest-mods/unified_inventory/blob/master/README.md>
Models: CC BY-SA (4.0) by Piezo_
Sounds:
Portal noises (meseportal_open, meseportal_close): CC BY-SA (4.0) by Piezo_
Portal noise (meseportal_warp) is a distorted versin of default_water_footstep.2.ogg from minetest_game
GUI sounds: (click and paperflip2.ogg) See <https://github.com/minetest-mods/unified_inventory/blob/master/README.md>
Source code:
Copyright (C) 2018 "Piezo_"
Copyright (C) 2015-2016 - Maciej "RealBadAngel" Kasatkin
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 X CONSORTIUM 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.
Except as contained in this notice, the name of the authors shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from the authors.

View File

@ -0,0 +1,2 @@
default
bucket

View File

@ -0,0 +1 @@
A futuristic multiplayer transportation system built on RealBadAngel's mod for Minetest.

View File

@ -0,0 +1,30 @@
--data tables definitions
meseportals={}
meseportals_network = {}
meseportals_gui = {}
meseportals.allowPrivatePortals = true
meseportals.maxPlayerPortals = 14 -- Set to 0 or lower to restrict portal placement to only players with msp_unlimited privilege
meseportals.close_after = 240 -- Automatically close portals after a while (default: 4 min)
meseportals.default_page = "main"
meseportals_gui["players"]={}
meseportals["registered_players"] = {}
meseportals.current_page={}
minetest.register_privilege("msp_admin", {
description = "Allows full control of all mese portals.",
give_to_singleplayer = false,
})
minetest.register_privilege("msp_unlimited", {
description = "Allows player to place an unlimited number of mese portals.",
give_to_singleplayer = true,
})
modpath=minetest.get_modpath("meseportals")
dofile(modpath.."/meseportal_network.lua")
dofile(modpath.."/meseportal_gui.lua")
dofile(modpath.."/portal_defs.lua")
dofile(modpath.."/recipes.lua")
dofile(modpath.."/node_behaviors.lua")

View File

@ -0,0 +1,474 @@
local reportFormspecViolation = function(submitter_name, violation)
local path = minetest.get_worldpath().."/meseportals_incidents.log"
local file = io.open( path, "r" )
local data = ""
if( file ) then
data = file:read("*all")
file:close()
end
data = data.."<"..os.date().."> "..submitter_name.." "..violation.."\n"
file = io.open( path, "w" )
if( file ) then
file:write( data )
file:close()
end
end
local getCleanText = function(submitter_name, scan_text)
if scan_text ~= nil then
if string.find(scan_text, ";") or
string.find(scan_text, "%[") or
string.find(scan_text, "%]") or
string.find(scan_text, "\\") then
reportFormspecViolation(submitter_name, "sent dirty string of length "..string.len(scan_text)..": "..scan_text)
--Call me paranoid. The length bit is so that someone can't get away with causing their report to line-break, and fabricating a fake report on the next line, essentially framing another player as well as themself.
return ""
else
return scan_text
end
else
return nil
end
end
meseportals.searchportals = function(pos, player_name, isAdmin)
meseportals_gui["players"][player_name]["own_portals"]={}
meseportals_gui["players"][player_name]["public_portals"]={}
local own_portals_count=0
local public_portals_count=0
for __,portal in ipairs(meseportals_network[player_name]) do
if portal["pos"].x==pos.x and portal["pos"].y==pos.y and portal["pos"].z==pos.z then
--current_portal=portals
else
own_portals_count=own_portals_count+1
if string.find(portal["description"], meseportals_gui["players"][player_name]["query"]) then
table.insert(meseportals_gui["players"][player_name]["own_portals"],portal)
end
end
end
-- get all public portals
for __,tab in ipairs(meseportals["registered_players"]) do
local temp=tab["player_name"]
for __,portal in ipairs(meseportals_network[temp]) do
if string.find(portal["description"], meseportals_gui["players"][player_name]["query"]) then
if portal["type"]=="public" or portal["owner"] == player_name or isAdmin or not meseportals.allowPrivatePortals then
if portal["pos"].x==pos.x and portal["pos"].y==pos.y and portal["pos"].z==pos.z then
--current_portal=portals
else
public_portals_count=public_portals_count+1
table.insert(meseportals_gui["players"][player_name]["public_portals"],portal)
end
end
end
end
end
meseportals_gui["players"][player_name]["own_portals_count"]=own_portals_count
meseportals_gui["players"][player_name]["public_portals_count"]=public_portals_count
end
-- Mods can override this to restict portal connections.
-- Admins ignore this.
meseportals.can_connect = function(src_portal, dest_portal)
return dest_portal["destination"] == nil, "Destination portal is busy."
end
--show formspec to player
meseportals.portalFormspecHandler = function(pos, _, clicker, _)
if (meseportals.findPortal(pos) ~= nil) then
local player_name = clicker:get_player_name()
local isAdmin = minetest.check_player_privs(clicker, {msp_admin=true})
local owner=meseportals.findPortal(pos)["owner"]
if meseportals.findPortal(pos)["type"] == "private" and player_name ~= owner and meseportals.allowPrivatePortals and not isAdmin then
minetest.chat_send_player(clicker:get_player_name(), meseportals.findPortal(pos)["owner"] .." has set this portal to private.")
return
else
local current_portal=meseportals.findPortal(pos)
meseportals_gui["players"][player_name]["query"]=""
meseportals.searchportals(pos, player_name, isAdmin)
-- print(dump(meseportals_gui["players"][player_name]["public_portals"]))
if current_portal == nil then
print ("Portal not registered in network! Please remove it and place once again.")
return nil
end
meseportals_gui["players"][player_name]["current_index"]=0
meseportals_gui["players"][player_name]["temp_portal"]["owner"]=current_portal.owner
meseportals_gui["players"][player_name]["temp_portal"]["type"]=current_portal["type"]
meseportals_gui["players"][player_name]["temp_portal"]["description"]=current_portal["description"]
meseportals_gui["players"][player_name]["temp_portal"]["pos"]={}
meseportals_gui["players"][player_name]["temp_portal"]["pos"] = vector.new(pos)
if current_portal["destination"] then
meseportals_gui["players"][player_name]["temp_portal"]["destination_description"]=current_portal["destination_description"]
meseportals_gui["players"][player_name]["temp_portal"]["destination_dir"]=current_portal["destination_dir"]
meseportals_gui["players"][player_name]["temp_portal"]["destination"]={}
meseportals_gui["players"][player_name]["temp_portal"]["destination"].x=current_portal["destination"].x
meseportals_gui["players"][player_name]["temp_portal"]["destination"].y=current_portal["destination"].y
meseportals_gui["players"][player_name]["temp_portal"]["destination"].z=current_portal["destination"].z
else
meseportals_gui["players"][player_name]["temp_portal"]["destination"]=nil
end
meseportals_gui["players"][player_name]["dest_type"]="all"
local formspec=meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"]=formspec
if formspec ~=nil then minetest.show_formspec(player_name, "meseportals_main", formspec) end
end
else
minetest.chat_send_player(clicker:get_player_name(), "This portal is broken.")
end
end
-- get_formspec
meseportals.get_formspec = function(player_name,page)
if player_name==nil then return nil end
meseportals_gui["players"][player_name]["current_page"]=page
local temp_portal=meseportals_gui["players"][player_name]["temp_portal"]
local isAdmin = minetest.check_player_privs(player_name, {msp_admin=true})
local formspec = "size[14,9.8]"
--background
formspec = formspec .."background[-0.19,-0.25;14.38,10.6;meseportal_ui_form_bg.png]"
formspec = formspec.."label[0,0.0;Mese Portal ("
if meseportals.allowPrivatePortals then
formspec=formspec..temp_portal["owner"]
end
formspec = formspec..")]"
formspec = formspec.."label[0,.5;Position: ("..temp_portal["pos"].x..","..temp_portal["pos"].y..","..temp_portal["pos"].z..")]"
if player_name == temp_portal["owner"] or isAdmin or not meseportals.allowPrivatePortals then
if meseportals.allowPrivatePortals then
formspec = formspec.."image_button[3.5,.6;.6,.6;meseportal_toggle_icon.png;toggle_type;]"
formspec = formspec.."label[4,.5;Type: "..temp_portal["type"].."]"
end
formspec = formspec.."image_button[6.5,.6;.6,.6;meseportal_pencil_icon.png;edit_desc;]"
end
formspec = formspec.."label[0,1.1;Destination: ]"
if temp_portal["destination"] then
if meseportals.findPortal(temp_portal["destination"]) then
if isAdmin or meseportals.findPortal(temp_portal["destination"])["type"] ~= "private" or player_name == meseportals.findPortal(temp_portal["destination"])["owner"] or not meseportals.allowPrivatePortals then
formspec = formspec.."label[2.5,1.1;"..temp_portal["destination_description"].." ("..temp_portal["destination"].x..","..temp_portal["destination"].y..","..temp_portal["destination"].z..") "
if isAdmin then
formspec = formspec.."("..meseportals.findPortal(temp_portal["destination"])["type"]..")"
end
formspec = formspec.."]"
else
formspec = formspec.."label[2.5,1.1;Private Portal]"
end
else
formspec = formspec.."label[2.5,1.1;Invalid Destination]"
end
formspec = formspec.."image_button[2,1.2;.6,.6;meseportal_cancel_icon.png;remove_dest;]"
else
formspec = formspec.."label[2,1.1;Not connected]"
end
formspec = formspec.."label[0,1.7;Aviable destinations:]"
formspec = formspec.."image_button[3.5,1.8;.6,.6;meseportal_toggle_icon.png;toggle_dest_type;]"
formspec = formspec.."label[4,1.7;Filter: "..meseportals_gui["players"][player_name]["dest_type"].."]"
formspec = formspec.."image_button[12.6,1.375;.8,.8;meseportal_ui_search_icon.png;update_search_query;]"
formspec = formspec.."field[9.5,1.6;3.5,1;search_box;Search...;"..meseportals_gui["players"][player_name]["query"].."]"
if page=="main" then
if player_name == temp_portal["owner"]or isAdmin or not meseportals.allowPrivatePortals then
formspec = formspec.."image_button[6.5,.6;.6,.6;meseportal_pencil_icon.png;edit_desc;]"
end
formspec = formspec.."label[7,.5;Description: "..temp_portal["description"].."]"
end
if page=="edit_desc" then
if player_name == temp_portal["owner"]or isAdmin or not meseportals.allowPrivatePortals then
formspec = formspec.."image_button[6.5,.6;.6,.6;meseportal_ok_icon.png;save_desc;]"
end
formspec = formspec.."field[7.3,.7;5,1;desc_box;Edit portal description:;"..temp_portal["description"].."]"
end
local list_index=meseportals_gui["players"][player_name]["current_index"]
local page=math.ceil(list_index / 24)
local pagemax
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
pagemax = math.ceil((meseportals_gui["players"][player_name]["own_portals_count"] / 24))
local x,y
for y=0,7,1 do
for x=0,2,1 do
local portal_temp=meseportals_gui["players"][player_name]["own_portals"][list_index+1]
if portal_temp then
formspec = formspec.."image_button["..(x*4.5)..","..(2.5+y*.87)..";.6,.6;meseportal.png;list_button"..list_index..";]"
formspec = formspec.."label["..(x*4.5+.5)..","..(2.3+y*.87)..";"
if portal_temp["destination"] ~= nil then
formspec = formspec.."<A> "
end
formspec = formspec.."("..portal_temp["pos"].x..","..portal_temp["pos"].y..","..portal_temp["pos"].z..") "..portal_temp["type"].."]"
formspec = formspec.."label["..(x*4.5+.5)..","..(2.7+y*.87)..";"..portal_temp["description"].."]"
end
list_index=list_index+1
end
end
else
pagemax = math.ceil(meseportals_gui["players"][player_name]["public_portals_count"] / 24)
local x,y
for y=0,7,1 do
for x=0,2,1 do
local portal_temp=meseportals_gui["players"][player_name]["public_portals"][list_index+1]
if portal_temp then
formspec = formspec.."image_button["..(x*4.5)..","..(2.5+y*.87)..";.6,.6;meseportal.png;list_button"..list_index..";]"
formspec = formspec.."label["..(x*4.5+.5)..","..(2.3+y*.87)..";"
if portal_temp["destination"] ~= nil then
formspec = formspec.."<A> "
end
formspec=formspec.."("..portal_temp["pos"].x..","..portal_temp["pos"].y..","..portal_temp["pos"].z..") "..portal_temp["owner"].."]"
formspec = formspec.."label["..(x*4.5+.5)..","..(2.7+y*.87)..";"..portal_temp["description"]
if isAdmin then
formspec = formspec.." ("..portal_temp["type"]..")"
end
formspec = formspec.."]"
end
list_index=list_index+1
end
end
end
formspec=formspec.."label[7.5,1.7;Page: "..((pagemax > 0) and (page + 1) or 0).." of "..pagemax.."]"
formspec = formspec.."image_button[6.5,1.8;.6,.6;meseportal_left_icon.png;page_left;]"
formspec = formspec.."image_button[6.9,1.8;.6,.6;meseportal_right_icon.png;page_right;]"
if isAdmin then formspec = formspec.."image_button_exit[5.1,9.3;.8,.8;meseportal_adminlock.png;lock_and_save;]" end
formspec = formspec.."image_button_exit[6.1,9.3;.8,.8;meseportal_ok_icon.png;save_changes;]"
formspec = formspec.."image_button_exit[7.1,9.3;.8,.8;meseportal_cancel_icon.png;discard_changes;]"
return formspec
end
-- register_on_player_receive_fields
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "meseportals_main" then return end
local player_name = player:get_player_name()
local isAdmin = minetest.check_player_privs(player, {msp_admin=true})
local temp_portal=meseportals_gui["players"][player_name]["temp_portal"]
if not temp_portal then return end
local current_portal=meseportals.findPortal(meseportals_gui["players"][player_name]["temp_portal"]["pos"])
local formspec
if current_portal then
if (player_name ~= current_portal["owner"] and temp_portal["type"] == "private" and not isAdmin) and meseportals.allowPrivatePortals then
reportFormspecViolation(player_name, "accessed someone else's private portal!")
return
end
if player_name == current_portal["owner"] or isAdmin or not meseportals.allowPrivatePortals then
if fields.toggle_type then
if temp_portal["type"] == "private" then
temp_portal["type"] = "public"
else
temp_portal["type"] = "private"
end
meseportals_gui["players"][player_name]["current_index"]=0
formspec= meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
return
end
if fields.edit_desc then
formspec= meseportals.get_formspec(player_name,"edit_desc")
meseportals_gui["players"][player_name]["formspec"]=formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
return
end
if fields.save_desc then
temp_portal["description"]=getCleanText(player_name, fields.desc_box)
formspec= meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"]=formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
return
end
else
if fields.toggle_type then
reportFormspecViolation(player_name, "attempted to change type of someone else's portal!")
end
if fields.edit_desc then
reportFormspecViolation(player_name, "attempted to edit description of someone else's portal!")
end
if fields.save_desc then
reportFormspecViolation(player_name, "attempted to change description of someone else's portal!")
end
end
if fields.toggle_dest_type then
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
meseportals_gui["players"][player_name]["dest_type"] = "all"
else meseportals_gui["players"][player_name]["dest_type"] = "own" end
meseportals_gui["players"][player_name]["current_index"] = 0
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
return
end
if fields.update_search_query then
meseportals_gui["players"][player_name]["query"] = getCleanText(player_name, fields.search_box)
meseportals.searchportals(current_portal["pos"], player_name, isAdmin)
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
end
-- page controls
local start=math.floor(meseportals_gui["players"][player_name]["current_index"]/24 +1 )
local start_i=start
local pagemax
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
pagemax = math.ceil((meseportals_gui["players"][player_name]["own_portals_count"]) / 24)
else
pagemax = math.ceil((meseportals_gui["players"][player_name]["public_portals_count"]) / 24)
end
if pagemax == 0 then pagemax = 1 end
if fields.page_left then
minetest.sound_play("paperflip2", {to_player=player_name, gain = 1.0})
start_i = start_i - 1
if start_i < 1 then start_i = 1 end
if not (start_i == start) then
meseportals_gui["players"][player_name]["current_index"] = (start_i-1)*24
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
end
end
if fields.page_right then
minetest.sound_play("paperflip2", {to_player=player_name, gain = 1.0})
start_i = start_i + 1
if start_i > pagemax then start_i = pagemax end
if not (start_i == start) then
meseportals_gui["players"][player_name]["current_index"] = (start_i-1)*24
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
end
end
if fields.discard_changes then
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
end
if current_portal.admin_lock and not isAdmin then
minetest.chat_send_player(player_name, "This portal has been locked by an admin.")
return
end
if fields.remove_dest then
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
temp_portal["destination"]=nil
temp_portal["destination_description"]=nil
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
end
if fields.save_changes or fields.lock_and_save then
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
if player_name == current_portal["owner"] or isAdmin or not meseportals.allowPrivatePortals then
if fields.desc_box ~= nil then
temp_portal["description"]=getCleanText(player_name, fields.desc_box)
end
current_portal["type"]=temp_portal["type"]
current_portal["description"]=temp_portal["description"]
end
if temp_portal["destination"] then
local dest_portal = meseportals.findPortal(temp_portal["destination"])
if dest_portal then
if isAdmin then
current_portal.admin_lock = fields.lock_and_save
dest_portal.admin_lock = fields.lock_and_save
elseif fields.lock_and_save then
reportFormspecViolation(player_name, "attempted to admin-lock a portal while missing msp_admin privilege!")
end
if dest_portal["type"] ~= "private" or dest_portal["owner"] == player_name or isAdmin then
if current_portal["destination"] ~= nil then
current_portal["destination_deactivate"] = vector.new(current_portal["destination"])
end
current_portal["destination"]={}
current_portal["destination"]=vector.new(temp_portal["destination"])
current_portal["destination_description"]=temp_portal["destination_description"]
current_portal["destination_dir"]=temp_portal["destination_dir"]
else
reportFormspecViolation(player_name, "attempted to connect to private portal at "..minetest.pos_to_string(dest_portal.pos).." from "..minetest.pos_to_string(current_portal.pos))
end
else
minetest.chat_send_player(player_name, "The destination portal seems to have vanished while you were in the menu...")
end
else
if current_portal["destination"] ~= nil then
current_portal["destination_deactivate"] = vector.new(current_portal["destination"])
meseportals.deactivatePortal(current_portal.pos)
end
end
if current_portal["destination_deactivate"] ~= nil then
if not temp_portal["destination"] then
current_portal.admin_lock = nil
end
if meseportals.findPortal(current_portal["destination_deactivate"]) then
meseportals.findPortal(current_portal["destination_deactivate"]).admin_lock = nil
meseportals.deactivatePortal (current_portal["destination_deactivate"])
current_portal["destination_deactivate"] = nil
end
end
if meseportals.findPortal(current_portal["destination"]) then
local dest_portal = meseportals.findPortal(current_portal["destination"])
local can_connect, fail_reason = meseportals.can_connect(table.copy(current_portal), table.copy(dest_portal))
if can_connect or isAdmin then
dest_portal.admin_lock = current_portal.admin_lock
-- Connecting to a portal, its locked state becomes the same as this portal.
if dest_portal["destination"] then --Admin can interrupt any existing connection
meseportals.deactivatePortal(dest_portal["destination"])
end
meseportals.activatePortal (current_portal.pos)
dest_portal["destination"] = current_portal["pos"]
dest_portal["destination_description"] = current_portal["description"]
dest_portal["destination_dir"] = current_portal["dir"]
meseportals.activatePortal (dest_portal.pos)
current_portal["time"] = meseportals.close_after
else
if fail_reason then
minetest.chat_send_player(player_name, "Connection failed: " .. fail_reason)
else
minetest.chat_send_player(player_name, "Connection failed.")
end
meseportals.deactivatePortal (current_portal["pos"])
end
else
meseportals.deactivatePortal (current_portal["pos"])
end
if meseportals.save_data(current_portal["owner"])==nil then
print ("[meseportals] Couldnt update network file!")
end
end
local list_index=meseportals_gui["players"][player_name]["current_index"]
local i
for i=0,23,1 do
local button="list_button"..i+list_index
if fields[button] then
minetest.sound_play("click", {to_player=player_name, gain = 1.0})
local portal=meseportals_gui["players"][player_name]["temp_portal"]
local dest_portal
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
dest_portal=meseportals_gui["players"][player_name]["own_portals"][list_index+i+1]
else
dest_portal=meseportals_gui["players"][player_name]["public_portals"][list_index+i+1]
end
portal["destination"]=vector.new(dest_portal["pos"])
portal["destination_description"]=dest_portal["description"]
portal["destination_dir"]=dest_portal["dir"]
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
end
end
end
end)

View File

@ -0,0 +1,148 @@
local function table_empty(tab)
for key in pairs(tab) do return false end
return true
end
meseportals.save_data = function(table_pointer)
local data = minetest.serialize( meseportals_network[table_pointer] )
local path = minetest.get_worldpath().."/meseportals_"..table_pointer..".data"
local file = io.open( path, "w" )
if( file ) then
file:write( data )
file:close()
return true
else return nil
end
end
meseportals.restore_data = function(table_pointer)
local path = minetest.get_worldpath().."/meseportals_"..table_pointer..".data"
local file = io.open( path, "r" )
if( file ) then
local data = file:read("*all")
meseportals_network[table_pointer] = minetest.deserialize( data )
file:close()
if table_empty(meseportals_network[table_pointer]) then os.remove(path) end
return true
else return nil
end
end
meseportals.load_players = function()
local path = minetest.get_worldpath().."/meseportals.players"
local file = io.open( path, "r" )
if( file ) then
local data = file:read("*all")
meseportals["registered_players"] = minetest.deserialize( data )
file:close()
if table_empty(meseportals["registered_players"]) then os.remove(path) end
return true
else return nil
end
end
meseportals.save_players = function()
if table_empty(meseportals["registered_players"]) then return end
local data = minetest.serialize( meseportals["registered_players"] )
local path = minetest.get_worldpath().."/meseportals.players"
local file = io.open( path, "w" )
if( file ) then
file:write( data )
file:close()
return true
else return nil
end
end
-- load meseportalss network data
if meseportals.load_players() ~= nil then
for __,tab in ipairs(meseportals["registered_players"]) do
if meseportals.restore_data(tab["player_name"]) == nil then
--print ("[meseportals] Error loading data!")
meseportals_network[tab["player_name"]] = {}
end
end
else
print ("[meseportals] Error loading data! Creating new file.")
meseportals["registered_players"]={}
meseportals.save_players()
end
-- register_on_joinplayer
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
local registered=nil
for __,tab in ipairs(meseportals["registered_players"]) do
if tab["player_name"] == player_name then registered = true break end
end
if registered == nil then
local new={}
new["player_name"]=player_name
table.insert(meseportals["registered_players"],new)
meseportals_network[player_name]={}
meseportals.save_players()
meseportals.save_data(player_name)
end
meseportals_gui["players"][player_name]={
formspec = "",
current_page = meseportals.default_page,
own_portals ={},
own_portals_count =0,
public_portals ={},
public_portals_count =0,
current_index =0,
temp_portal ={},
}
end)
meseportals.unregisterPortal = function(pos)
for _,tab in pairs(meseportals.registered_players) do
local player_name=tab.player_name
for __,portal in ipairs(meseportals_network[player_name]) do
if portal["pos"].x==pos.x and portal["pos"].y==pos.y and portal["pos"].z==pos.z then
table.remove(meseportals_network[player_name], __)
if meseportals.save_data(player_name)==nil then
print ("[meseportals] Couldnt update network file!")
end
end
end
end
end
meseportals.registerPortal = function(player_name,pos,dir)
if meseportals.findPortal(pos) then
--An annoying glitch
meseportals.unregisterPortal(pos)
end
if meseportals_network[player_name]==nil then
meseportals_network[player_name]={}
end
local new_portal ={}
new_portal["pos"]=pos
new_portal["type"]="public"
new_portal["description"]="Portal at (" ..new_portal["pos"].x .."," ..new_portal["pos"].y .."," ..new_portal["pos"].z ..")"
new_portal["dir"]=dir
new_portal["owner"]=player_name
table.insert(meseportals_network[player_name],new_portal)
if meseportals.save_data(player_name)==nil then
print ("[meseportals] Couldnt update network file!")
end
end
meseportals.findPortal = function(pos)
if pos ~= nil then
for _,tab in pairs(meseportals.registered_players) do
local player_name=tab.player_name
for _,portals in pairs(meseportals_network[player_name]) do
if portals
and vector.equals(portals.pos, pos) then
return portals
end
end
end
end
return nil
end

View File

@ -0,0 +1 @@
name = meseportals

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,164 @@
# Blender v2.79 (sub 0) OBJ File: 'controller.blend'
# www.blender.org
o control_panel_Plane.002
v -0.351000 0.270000 0.476056
v -0.351000 -0.270000 0.476056
v -0.388572 0.298902 0.496045
v 0.388572 0.298902 0.496045
v -0.388572 -0.298902 0.496045
v 0.388572 -0.298902 0.496045
v -0.419801 0.322924 0.486703
v 0.419801 0.322924 0.486703
v -0.419801 -0.322924 0.486703
v 0.419801 -0.322924 0.486703
v -0.427885 0.329142 0.478620
v 0.427885 0.329142 0.478620
v -0.427885 -0.329143 0.478620
v 0.427885 -0.329143 0.478620
v -0.351000 0.270000 0.466722
v 0.351000 0.270000 0.466722
v -0.351000 -0.270000 0.466722
v 0.351000 -0.270000 0.466722
v -0.360401 0.277231 0.459573
v 0.360401 0.277231 0.459573
v -0.360401 -0.277231 0.459573
v 0.360401 -0.277232 0.459573
v -0.388572 0.298902 0.450244
v 0.388572 0.298902 0.450244
v -0.388572 -0.298902 0.450244
v 0.388572 -0.298902 0.450244
v -0.419801 0.322924 0.456074
v 0.419801 0.322924 0.456074
v -0.419801 -0.322924 0.456074
v 0.419801 -0.322924 0.456074
v -0.427885 0.329142 0.464158
v 0.427885 0.329142 0.464158
v -0.427885 -0.329143 0.464157
v 0.427885 -0.329143 0.464157
vt 0.892354 0.497145
vt 0.892324 0.102503
vt 0.379290 0.102541
vt 0.379319 0.497183
vt 0.357770 0.086684
vt 0.357802 0.513043
vt 0.913874 0.513002
vt 0.913842 0.086643
vt 0.358706 0.514199
vt 0.912971 0.514158
vt 0.912938 0.085487
vt 0.358673 0.085527
vt 0.353414 0.523967
vt 0.920746 0.523967
vt 0.918229 0.075719
vt 0.350898 0.075719
vt 0.350220 0.082578
vt 0.350255 0.517149
vt 0.921424 0.517108
vt 0.921389 0.082537
vt 0.504874 0.999888
vt 0.504874 0.611610
vt 0.000112 0.611610
vt 0.000112 0.999888
vt 0.871302 0.024079
vt 0.395517 0.024114
vt 0.376922 0.039689
vt 0.889899 0.039651
vt 0.407894 0.583827
vt 0.869900 0.583768
vt 0.876127 0.575572
vt 0.400342 0.575607
vt 0.863750 0.015859
vt 0.401744 0.015917
vt 0.284769 0.121626
vt 0.284796 0.478109
vt 0.292593 0.482882
vt 0.292565 0.116852
vt 0.986876 0.478060
vt 0.986849 0.121577
vt 0.979052 0.116803
vt 0.979080 0.482834
vt 0.312184 0.497187
vt 0.312155 0.102545
vt 0.959460 0.102499
vt 0.959490 0.497141
vt 0.894722 0.559997
vt 0.381745 0.560035
vt 0.333158 0.513043
vt 0.333125 0.086685
vt 0.938486 0.086642
vt 0.938519 0.513001
vt 0.915334 0.543678
vt 0.361131 0.543720
vt 0.356310 0.056008
vt 0.910513 0.055966
vt 0.920740 0.533870
vt 0.353409 0.533869
vt 0.350903 0.065816
vt 0.918235 0.065816
vt 0.340708 0.517150
vt 0.340672 0.082579
vt 0.930936 0.082536
vt 0.930972 0.517107
vn 0.0000 0.0000 -1.0000
vn -0.2866 0.0000 -0.9581
vn 0.2866 0.0000 -0.9581
vn 0.0000 0.3624 -0.9320
vn -0.0000 -0.3624 -0.9320
vn 0.0000 0.7926 -0.6097
vn -0.0000 -0.7926 -0.6097
vn -0.7071 0.0000 -0.7071
vn 0.7071 0.0000 -0.7071
vn 0.0000 0.0000 1.0000
vn 0.0000 0.3954 0.9185
vn -0.0000 -0.7030 0.7112
vn 0.0000 0.7030 0.7112
vn 0.6053 -0.0000 0.7960
vn -0.6053 0.0000 0.7960
vn 0.3144 -0.0000 0.9493
vn -0.3144 -0.0000 0.9493
vn -0.0000 -0.3954 0.9185
vn -0.1835 -0.0000 0.9830
vn 0.1835 -0.0000 0.9830
vn 0.0000 0.2358 0.9718
vn -0.0000 -0.2358 0.9718
vn 0.0000 0.7926 0.6097
vn -0.0000 -0.7926 0.6097
vn -0.7071 -0.0000 0.7071
vn 0.7071 -0.0000 0.7071
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 1.0000 0.0000 0.0000
vn -0.0000 -1.0000 0.0000
g control_panel_Plane.002_0001
s off
f 5/1/1 3/2/1 4/3/1 6/4/1
f 4/3/2 8/5/2 10/6/2 6/4/2
f 5/1/3 9/7/3 7/8/3 3/2/3
f 6/4/4 10/9/4 9/10/4 5/1/4
f 3/2/5 7/11/5 8/12/5 4/3/5
f 10/9/6 14/13/6 13/14/6 9/10/6
f 7/11/7 11/15/7 12/16/7 8/12/7
f 8/5/8 12/17/8 14/18/8 10/6/8
f 9/7/9 13/19/9 11/20/9 7/8/9
f 15/21/10 17/22/10 18/23/10 16/24/10
f 19/25/11 20/26/11 24/27/11 23/28/11
f 18/29/12 17/30/12 21/31/12 22/32/12
f 15/33/13 16/34/13 20/26/13 19/25/13
f 16/35/14 18/36/14 22/37/14 20/38/14
f 17/39/15 15/40/15 19/41/15 21/42/15
f 20/38/16 22/37/16 26/43/16 24/44/16
f 21/42/17 19/41/17 23/45/17 25/46/17
f 22/32/18 21/31/18 25/47/18 26/48/18
f 24/44/19 26/43/19 30/49/19 28/50/19
f 25/46/20 23/45/20 27/51/20 29/52/20
f 26/48/21 25/47/21 29/53/21 30/54/21
f 23/28/22 24/27/22 28/55/22 27/56/22
f 30/54/23 29/53/23 33/57/23 34/58/23
f 27/56/24 28/55/24 32/59/24 31/60/24
f 28/50/25 30/49/25 34/61/25 32/62/25
f 29/52/26 27/51/26 31/63/26 33/64/26
f 13/14/27 14/13/27 34/58/27 33/57/27
f 14/18/28 12/17/28 32/62/28 34/61/28
f 11/20/29 13/19/29 33/64/29 31/63/29
f 12/16/30 11/15/30 31/60/30 32/59/30
l 2 1

View File

@ -0,0 +1,182 @@
minetest.register_abm({
nodenames = {"meseportals:portal_collider"},
interval = 1,
chance = 1,
action = function(pos)
local portalpos = minetest.string_to_pos(minetest.get_meta(pos):get_string("portal"))
if portalpos then
local nodeName = minetest.get_node(portalpos).name
if nodeName ~= "ignore" then --If the portal is on the edge of the loaded world, wait to update
if nodeName ~= "meseportals:portalnode_on" and nodeName ~= "meseportals:portalnode_off" then
minetest.remove_node(pos)
end
end
end
end
})
minetest.register_abm({
nodenames = {"meseportals:portalnode_on", "meseportals:portalnode_off"},
interval = 1,
chance = 1,
action = function(pos)
local current_portal = meseportals.findPortal(pos)
if not current_portal then
minetest.remove_node(pos)
return
end
end
})
minetest.register_globalstep(function(dtime)
local meta, infotext, pos1, pos, dir, dir1, hdiff, dest_portal
for _, skip in pairs(meseportals_network) do
for __, portal in pairs(skip) do
if portal then
pos = portal["pos"]
if portal["time"] and not portal["admin_lock"] then -- Close portals automatically after a while
if portal["time"] > 0 then
portal["time"] = portal["time"] - dtime
else
portal["time"] = nil
if portal["destination"] then
meseportals.deactivatePortal(portal["destination"])
end
meseportals.deactivatePortal(pos)
end
end
if minetest.get_node_or_nil(pos) then -- Do the complicated stuff only if the portal is loaded
if minetest.get_node(pos).name ~= "meseportals:portalnode_off"
and minetest.get_node(pos).name ~= "meseportals:portalnode_on"
then --Portal broke
if portal["destination"] then
meseportals.deactivatePortal(portal["destination"])
end
meseportals.unregisterPortal(pos)
elseif portal["updateme"] then -- Node needs to update
if portal["destination"] == nil then
if minetest.get_node(pos).name ~= "meseportals:portalnode_off" then
minetest.sound_play("meseportal_close", {pos = pos, gain=0.6, max_hear_distance = 40})
end
meseportals.swap_portal_node(pos,"meseportals:portalnode_off",portal["dir"])
else
meseportals.swap_portal_node(pos,"meseportals:portalnode_on",portal["dir"])
minetest.sound_play("meseportal_open", {pos = pos, gain=0.6, max_hear_distance = 40})
end
portal["updateme"] = false
meseportals.save_data(portal["owner"])
meta = minetest.get_meta(pos)
if portal["type"]=="private" and meseportals.allowPrivatePortals then
infotext="Private Portal"
else
infotext=(portal["description"])
if meseportals.allowPrivatePortals then
infotext=infotext.." ("..portal["owner"].."'s Public Portal)"
end
dest_portal = meseportals.findPortal(portal["destination"])
if dest_portal then
if dest_portal["type"] == "public" or not meseportals.allowPrivatePortals then
infotext=infotext.."\nDestination: " ..portal["destination_description"] .." ("..portal["destination"].x..","..portal["destination"].y..","..portal["destination"].z..") "
else
infotext=infotext.."\nDestination: Private Portal"
end
end
end
if portal.admin_lock then
infotext=infotext.."\nAdmin connection (Can not be closed)"
end
meta:set_string("infotext",infotext)
end
--Teleport players
dest_portal=meseportals.findPortal(portal["destination"])
if dest_portal then
pos1 = vector.new(dest_portal["pos"])
dir = portal.dir
dir1 = portal.destination_dir
for _,object in pairs(core.get_objects_inside_radius({x = pos.x, y = pos.y, z = pos.z}, 2)) do
hdiff = nil
if dir == 1
or dir == 3 then
if math.floor(object:get_pos().x + 0.5) == pos.x then
hdiff = (object:get_pos().z - pos.z)
end
else
if math.floor(object:get_pos().z + 0.5) == pos.z then
hdiff = (object:get_pos().x - pos.x)
end
end
if hdiff then
pos1.y = pos1.y + (object:get_pos().y - pos.y) + 0.2
local dest_angle = ((dir1 - 2) * -90)
dest_angle = ((object:get_look_horizontal() or object:get_yaw()) + math.pi) + ((dir1 - dir) * -(math.pi/2))
if dir == 1 or dir == 2 then
hdiff = -hdiff
end
--hdiff = -1
if dir1 == 0 then --ALL CORRECT
pos1.z = pos1.z-1.25
pos1.x = pos1.x - hdiff
elseif dir1 == 1 then
pos1.x = pos1.x-1.25
pos1.z = pos1.z + hdiff
elseif dir1 == 2 then
pos1.z=pos1.z+1.25
pos1.x = pos1.x + hdiff
elseif dir1 == 3 then
pos1.x = pos1.x+1.25
pos1.z = pos1.z - hdiff
end
local vel = object:get_velocity() or object:get_player_velocity()
vel.x = -vel.x
local magnitude = math.sqrt((vel.x*vel.x) + (vel.z*vel.z))
if math.abs(vel.z) < 0.01 then
vel.z = 0.01
end
local direction = math.atan(vel.x/vel.z)
-- Direction of velocity plus the change in look direction
if vel.z < 0 then
direction = direction + math.pi
end
direction = direction + math.pi + ((dir1 - dir) * -(math.pi/2))
vel.x = magnitude * -math.sin(direction)
vel.z = magnitude * math.cos(direction)
local moved = false
if object:is_player() then
object:set_pos(pos1)
if vector.equals(vector.round(object:get_pos()), vector.round(pos1)) then moved = true end
elseif object:get_properties().physical == true then
object:set_pos(pos1)
moved = true
end
if moved then
if object:is_player() then
--player:set_player_velocity(vel) -- TODO: Bother the devs more about this
object:set_look_horizontal(dest_angle)
minetest.sound_play("meseportal_warp", {to_player=object:get_player_name(), gain=0.6, max_hear_distance=15})
else
object:set_velocity(vel)
object:set_yaw(dest_angle)
end
minetest.sound_play("meseportal_warp", {pos = pos, gain=0.6, max_hear_distance=15})
minetest.sound_play("meseportal_warp", {pos = pos1, gain=0.6, max_hear_distance=15})
end
end
end
else
if portal["destination"] then --Destination portal broke/vanished
meseportals.deactivatePortal(pos)
end
end
end
end
end
end
end)

View File

@ -0,0 +1,469 @@
function meseportals.swap_portal_node(pos,name,dir)
local node = core.get_node(pos)
local meta = core.get_meta(pos)
meta:set_string("dont_destroy","true")
local meta0 = meta:to_table()
node.name = name
node.param2=dir
core.set_node(pos,{name=name, param2=dir})
meta:from_table(meta0)
meta:set_string("dont_destroy","false")
end
minetest.register_node("meseportals:portal_collider",{
drawtype = "airlike",
on_blast = function() end,
drop = "",
groups = {not_in_creative_inventory=1,immovable=2},
sunlight_propagates = true,
can_dig = false,
paramtype = "light",
selection_box = {
type = "fixed",
fixed={0.0,0.0,0.0,0.0,0.0,0.0}},
})
function placeportalCollider(pos, pos1, player)
local placed = false
if minetest.check_player_privs(player, {protection_bypass=true}) or not minetest.is_protected(pos, player:get_player_name()) then
if minetest.registered_nodes[minetest.get_node(pos).name] then
if minetest.get_node(pos).name == "air" or minetest.registered_nodes[minetest.get_node(pos).name].buildable_to then
core.set_node(pos,{name="meseportals:portal_collider"})
local meta = minetest.get_meta(pos)
meta:set_string("portal", minetest.pos_to_string(pos1))
placed = true
end
end
end
return placed
end
local function placeportal(player,pos)
if minetest.check_player_privs(player, {msp_unlimited=true}) or meseportals.maxPlayerPortals > #meseportals_network[player:get_player_name()] then
local dir = minetest.dir_to_facedir(player:get_look_dir())
local pos1 = vector.new(pos)
local hadRoom = true
if dir == 1
or dir == 3 then
pos1.z=pos1.z+2
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.z=pos1.z-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.z=pos1.z-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.z=pos1.z-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.z=pos1.z-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y-1
placeportalCollider(pos1, pos, player)
pos1.z=pos1.z+1
placeportalCollider(pos1, pos, player)
pos1.z=pos1.z+1
placeportalCollider(pos1, pos, player)
pos1.z=pos1.z+1
placeportalCollider(pos1, pos, player)
pos1.z=pos1.z+1
placeportalCollider(pos1, pos, player)
else
pos1.x=pos1.x+2
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.x=pos1.x-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.x=pos1.x-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.x=pos1.x-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.x=pos1.x-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
pos1.y=pos1.y-1
placeportalCollider(pos1, pos, player)
pos1.x=pos1.x+1
placeportalCollider(pos1, pos, player)
pos1.x=pos1.x+1
placeportalCollider(pos1, pos, player)
pos1.x=pos1.x+1
placeportalCollider(pos1, pos, player)
pos1.x=pos1.x+1
placeportalCollider(pos1, pos, player)
end
if hadRoom then
meseportals.swap_portal_node(pos,"meseportals:portalnode_off",dir)
local player_name = player:get_player_name()
meseportals.registerPortal(player_name, pos, dir)
return true
else
minetest.remove_node(pos)
minetest.chat_send_player(player:get_player_name(), "Not enough room!")
end
else
minetest.chat_send_player(player:get_player_name(), "You have reached the maximum allowed number of portals!")
core.remove_node(pos)
end
end
function meseportals.activatePortal(pos)
local portal = meseportals.findPortal(pos)
if meseportals.findPortal(pos) then
portal["updateme"] = true
meseportals.save_data(portal["owner"])
end
end
function meseportals.deactivatePortal(pos)
local portal = meseportals.findPortal(pos)
if portal then
portal["destination"] = nil
portal["destination_description"] = nil
portal["destination_dir"] = nil
portal["updateme"] = true
meseportals.save_data(portal["owner"])
end
end
local function removeportal(pos)
if (meseportals.findPortal(pos) ~= nil) then
local meta = core.get_meta(pos)
if meta:get_string("dont_destroy") == "true" then
-- when swapping it
return
end
if meseportals.findPortal(pos)["destination"] then
meseportals.deactivatePortal(meseportals.findPortal(pos)["destination"])
end
meseportals.unregisterPortal(pos)
end
end
local msp_selection_box = {
type = "fixed",
fixed={{-2.5,-1.5,-0.2,2.5,3.5,0.2},},
}
local msp_groups = {cracky=2,not_in_creative_inventory=1,immovable=2}
local msp_groups1 = {cracky=2,immovabl=2}
local old_pttfp = minetest.pointed_thing_to_face_pos
minetest.pointed_thing_to_face_pos = function(placer, pointed_thing)
if pointed_thing and placer and pointed_thing.above and pointed_thing.under then
if pointed_thing.under.x == pointed_thing.above.x and pointed_thing.under.y == pointed_thing.above.y and pointed_thing.under.z == pointed_thing.above.z then
return placer:get_pos()
else
return old_pttfp(placer, pointed_thing)
end
else
return vector.new(0,0,0)
end
end
minetest.register_node("meseportals:portalnode_on",{
tiles = {
--{name = "gray.png"},
--{
--name = "puddle_animated.png",
--animation = {
-- type = "vertical_frames",
-- aspect_w = 16,
-- aspect_h = 16,
-- length = 2.0,
-- },
--},
{name = "meseportal_vortex.png",--Portal
animation = {
type = "vertical_frames",
},
},
{name = "meseportal_mese_on.png", --Buttons
animation = {
type = "vertical_frames",
},
},
{name = "meseportal_mese_on.png", --Cables
animation = {
type = "vertical_frames",
},
},
{name = "meseportal_mese_on.png", --Coil
animation = {
type = "vertical_frames",
},
},
{name = "meseportal_frame.png"}, --Frame
},
drawtype = "mesh",
mesh = "meseportal.obj",
visual_scale = 5.0,
groups = msp_groups,
drop = "meseportals:portalnode_off",
paramtype2 = "facedir",
paramtype = "light",
light_source = 5,
selection_box = msp_selection_box,
walkable = false,
on_destruct = removeportal,
on_rightclick=meseportals.portalFormspecHandler,
})
minetest.register_node("meseportals:portalnode_off",{
description = "Mese Portal (Sneak+Place = Buried)",
inventory_image = "meseportal.png",
wield_image = "meseportal.png",
tiles = {
{name = "meseportal_null.png"},
{name = "meseportal_mese_off.png"},
{name = "meseportal_mese_off.png"},
{name = "meseportal_mese_off.png"},
{name = "meseportal_frame.png"},
},
groups = msp_groups1,
paramtype2 = "facedir",
paramtype = "light",
drawtype = "mesh",
drop = "meseportals:portalnode_off",
mesh = "meseportal.obj",
visual_scale = 5.0,
selection_box = msp_selection_box,
walkable = false,
on_destruct = removeportal,
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above
if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name] then
if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].on_rightclick and not placer:get_player_control().sneak then
return minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
end
if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].buildable_to then
pos = pointed_thing.under
end
end
if minetest.check_player_privs(placer, {protection_bypass=true}) or not minetest.is_protected(pos, placer:get_player_name()) then
minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
if placer:get_player_control().sneak then
minetest.set_node(pos, node)
else
minetest.remove_node(pos)
pos.y = pos.y + 1
minetest.set_node(pos, node)
end
if placeportal(placer,pos) then
return itemstack
else
return nil
end
end
end,
on_rightclick=meseportals.portalFormspecHandler,
})
local old_protected = minetest.is_protected
local basecheck = { --f = face (x or z axis)
{x=0, z=0, f=0},
{x=1, z=0, f=1},
{x=2, z=0, f=1},
{x=-1, z=0, f=1},
{x=-2, z=0, f=1},
{x=0, z=1, f=2},
{x=0, z=2, f=2},
{x=0, z=-1, f=2},
{x=0, z=-2, f=2},
}
minetest.is_protected = function(pos, player, ...) --Protect the bottom of the portal
if not pos then return end
local pos1 = vector.new(pos.x, pos.y + 1, pos.z) --Allocate
local portal
for _,pos2 in pairs(basecheck) do
pos1.x = pos.x + pos2.x
pos1.z = pos.z + pos2.z
portal = meseportals.findPortal(pos1)
if portal then
if pos2.f == 0 then return true end --Right under
if (pos2.f == 1) == (portal.dir == 0 or portal.dir == 2) then --Adjacent, XNOR with facedir
return true
end
end
end
portal = meseportals.findPortal(pos)
if portal and not minetest.check_player_privs(player, {msp_admin=true}) then
if portal.owner ~= player then
minetest.chat_send_player(player, "This portal belongs to " ..portal["owner"] .."!")
return true
end
if portal.admin_lock then
minetest.chat_send_player(player, "This portal has been locked by an admin.")
return true
end
end
return old_protected(pos, player, ...)
end
local usePortalController = function(pos, clicker)
if meseportals.findPortal(pos) then
meseportals.portalFormspecHandler(pos, nil, clicker, nil)
else
minetest.chat_send_player(clicker:get_player_name(), "The linked portal was moved or destroyed. Link this controller to a new portal.")
end
end
minetest.register_node("meseportals:linked_portal_controller", {
description = "Linked Portal Controller",
inventory_image = "meseportal_controller_inventory.png",
wield_image = "meseportal_controller_inventory.png",
tiles = {{name = "meseportal_controller.png"}},
drawtype = "mesh",
paramtype = "light",
paramtype2 = "facedir",
mesh = "meseportal_controller.obj",
drop = "meseportals:unlinked_portal_controller",
groups = {cracky=3,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
stack_max = 1,
walkable = true,
light_source = 5,
selection_box = {
type = "fixed",
fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
},
collision_box = {
type = "fixed",
fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
},
on_place = function(itemstack, placer, pointed_thing)
if minetest.check_player_privs(placer, {protection_bypass=true}) or not minetest.is_protected(pointed_thing.above, placer:get_player_name()) then
local rightClicked = minetest.get_node(pointed_thing.under).name
if not placer:get_player_control().sneak then
if rightClicked == "meseportals:portalnode_on" or rightClicked == "meseportals:portalnode_off" then
local portal = meseportals.findPortal(pointed_thing.under)
if portal then
if portal["type"] == "public" or placer:get_player_name() == portal["owner"] or minetest.check_player_privs(placer, {msp_admin=true}) or not meseportals.allowPrivatePortals then
minetest.chat_send_player(placer:get_player_name(), "Controller linked to "..portal["description"])
itemstack:get_meta():set_string("portal", minetest.pos_to_string(pointed_thing.under))
itemstack:get_meta():set_string("description", "Linked Portal Controller ["..portal["description"].."]")
return itemstack
else
minetest.chat_send_player(placer:get_player_name(), portal["owner"] .." has set this portal to private.")
end
else
minetest.chat_send_player(placer:get_player_name(), "This portal is broken.")
end
elseif minetest.registered_nodes[rightClicked] and minetest.registered_nodes[rightClicked].on_rightclick then
return minetest.registered_nodes[rightClicked].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
end
end
local p
if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name] and minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].buildable_to then
p = pointed_thing.under
else
p = pointed_thing.above
end
local portalID = itemstack:get_meta():get_string("portal")
minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
local meta = minetest.get_meta(p)
meta:set_string("portal", portalID)
return itemstack
end
end,
on_use = function(itemstack, user)
local pos1 = minetest.string_to_pos(itemstack:get_meta():get_string("portal"))
usePortalController(pos1, user)
end,
on_rightclick = function(pos, node, clicker)
local pos1 = minetest.string_to_pos(minetest.get_meta(pos):get_string("portal"))
usePortalController(pos1, clicker)
end
})
minetest.register_node("meseportals:unlinked_portal_controller", {
description = "Unlinked Portal Controller",
inventory_image = "meseportal_controller_inventory_unlinked.png",
wield_image = "meseportal_controller_inventory_unlinked.png",
tiles = {{name = "meseportal_controller_unlinked.png"}},
drawtype = "mesh",
paramtype = "light",
paramtype2 = "facedir",
mesh = "meseportal_controller.obj",
drop = "meseportals:unlinked_portal_controller",
groups = {cracky=3,oddly_breakable_by_hand=2},
walkable = true,
selection_box = {
type = "fixed",
fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
},
collision_box = {
type = "fixed",
fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
},
on_place = function(itemstack, placer, pointed_thing)
local rightClicked = minetest.get_node(pointed_thing.under).name
if not placer:get_player_control().sneak then
if rightClicked == "meseportals:portalnode_on" or rightClicked == "meseportals:portalnode_off" then
local portal = meseportals.findPortal(pointed_thing.under)
if portal then
if portal["type"] == "public" or placer:get_player_name() == portal["owner"] or minetest.check_player_privs(placer, {msp_admin=true}) then
minetest.chat_send_player(placer:get_player_name(), "Controller linked to "..portal["description"])
itemstack:set_name("meseportals:linked_portal_controller")
itemstack:get_meta():set_string("portal", minetest.pos_to_string(pointed_thing.under))
itemstack:get_meta():set_string("description", "Linked Portal Controller ["..portal["description"].."]")
return itemstack
else
minetest.chat_send_player(placer:get_player_name(), portal["owner"] .." has set this portal to private.")
return
end
else
minetest.chat_send_player(placer:get_player_name(), "This portal is broken.")
end
elseif minetest.registered_nodes[rightClicked] and minetest.registered_nodes[rightClicked].on_rightclick then
return minetest.registered_nodes[rightClicked].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
end
end
return minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
end,
on_use = function(_, user)
minetest.chat_send_player(user:get_player_name(), "This controller is not linked. Link this controller to a portal by right-clicking the portal.")
end,
on_rightclick = function(_, __, user)
minetest.chat_send_player(user:get_player_name(), "This controller is not linked. Link this controller to a portal by right-clicking the portal.")
end,
})
minetest.register_craftitem("meseportals:portal_segment", {
description = "Encased Mesenetic Field Coil",
inventory_image = "meseportal_portal_part.png",
wield_image = "meseportal_portal_part.png",
})
minetest.register_craftitem("meseportals:tesseract_crystal", {
description = "Tesseract Crystal",
inventory_image = "meseportal_tesseract.png",
wield_image = "meseportal_tesseract.png",
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,46 @@
local OB = "default:obsidian"
local MC = "default:mese_crystal"
local MB = "default:mese_block"
local DI = "default:diamond"
local MC = "default:mese_crystal"
local GL = "default:obsidian_glass"
local LV = "bucket:bucket_lava"
local TC = "meseportals:tesseract_crystal"
local PS = "meseportals:portal_segment"
minetest.register_craft({
output = "meseportals:tesseract_crystal",
recipe = {
{DI, MC, DI},
{MC, OB, MC},
{DI, MC, DI},
}
})
minetest.register_craft({
output = "meseportals:portal_segment",
recipe = {
{OB, OB, OB},
{MB, LV, MB},
{OB, OB, OB},
},
replacements = {{"bucket:bucket_lava", "bucket:bucket_empty"}}
})
minetest.register_craft({
output = "meseportals:portalnode_off",
recipe = {
{PS, TC, PS},
{TC, "", TC},
{PS, TC, PS},
}
})
minetest.register_craft({
output = "meseportals:unlinked_portal_controller",
recipe = {
{GL, GL, GL},
{GL, TC, GL},
{GL, GL, GL},
}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB