123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- --[[
- stacked_realms, a API that allows modders to easily create stacked realms!
- Copyright (C) 2020 Genshin (emperor_genshin@hotmail.com)
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- --]]
- local update_interval = minetest.settings:get("realm_update_interval") or 1
- --Realm Registration Table
- realms = {
- locations = {},
- --[Method] Set String for Realm Context
- set_string = function(self, string, value)
- assert(string, "context string is missing."..dump(string))
- assert(type(string) == "string", "context string must be a string."..dump(string))
- assert(value or value == "", "context string\'s value is missing."..dump(value))
- if value == "" then --If the value is empty, nil it!
- value = nil
- end
- self[string] = value
- end,
-
- --[Method] Set String for Realm Context
- get_string = function(self, string)
- assert(string, "context string is missing."..dump(string))
- assert(type(string) == "string", "context string must be a string."..dump(string))
- return self[string]
- end
- }
- --[Global Function]: Register a new realm
- function realms.register_realm(realm, def)
- assert(realm, "realm requires a name.".. dump(realm))
- assert(def, "realm \""..realm.."\" does not have a definition table.".. dump(def))
- assert(type(def) == "table", "def is not a table.".. dump(def))
- assert(def.min_height and type(def.min_height) == "number", "min_height is not returning number or it\'s returning nil".. dump(def.min_height))
- assert(def.max_height and type(def.max_height) == "number", "max_height is not returning number or it\'s returning nil".. dump(def.max_height))
- assert(def.skybox_type and type(def.skybox_type) == "string"
- and (def.skybox_type == "default" or def.skybox_type == "colored" or def.skybox_type == "textured"),
- "skybox_type is not defined or it's not a string, must have a value of default, colored, or textured")
- assert(def.on_realm_entry and type(def.on_realm_entry) == "function", "def requires method \"on_realm_entry\" for realm \""..realm.."\".")
- assert(def.on_realm_entry and type(def.on_realm_leave) == "function", "def requires method \"on_realm_leave\" for realm \""..realm.."\".")
- assert(not realms.locations[realm], "attempt to register a realm that already exist." .. dump(realm))
- realms.locations[realm] = def
- def.in_realm = {} --Table array containing player names of players that are currently in the realm
- def.name = realm
- minetest.log("action", "Realm "..tostring(realm).." is now registered.")
- end
- --[Global Function]: Get the location name that the player is currently in (returns a string or nil)
- function get_player_realm_location(player)
- local name = player:get_player_name()
- local location = nil
- local list = realms.locations
- for k,v in pairs(list)do
- local realm = k
- if list[realm]["in_realm"][name] then
- location = realm
- break
- end
- end
- return location
- end
- --[Local Function]: Verify registered realms if they don't have matching minimum and max heights. If they do, purge them from their registration table
- local function verify_realms()
- local list = realms.locations
- local to_verify = {}
- local count = 0
- local verified_count = 0
- --First, store their names to a separate table and count them for verification
- for k,v in pairs(list)do
- local realm = k
- local def = v
- count = count + 1
- verified_count = count
- table.insert(to_verify, realm)
- end
- --then do another loop to go through all registered realms and verify conflicting height values
- for k,v in pairs(to_verify) do
- local realm = v
- local data = list[realm]
- local to_count = count
- minetest.log("action", "Verifing Realm "..tostring(realm).." for potential conflicting values before it becomes active.")
- while to_count > 0 do
- local to_compare = to_verify[to_count]
- local comparison = nil
- if list[realm] then
- comparison = list[realm]["name"]
- end
- if comparison and comparison ~= to_compare then --do not compare with yourself
- to_compare = list[to_compare]
- if to_compare == nil then else
- if data.min_height == to_compare.min_height then
- realms.locations[realm] = nil
- verified_count = verified_count - 1
- minetest.log("warning", "Realm with conflicting height values found, removing realm "..tostring(realm).." from the realms registration table to prevent potential errors.")
- elseif data.max_height == to_compare.max_height then
- realms.locations[realm] = nil
- verified_count = verified_count - 1
- minetest.log("warning", "Realm with conflicting height values found, removing realm "..tostring(realm).." from the realms registration table to prevent potential errors.")
- elseif data.min_height == to_compare.max_height or to_compare.max_height == data.min_height then
- realms.locations[realm] = nil
- verified_count = verified_count - 1
- minetest.log("warning", "Realm with conflicting height values found, removing realm "..tostring(realm).." from the realms registration table to prevent potential errors.")
- end
- end
- end
- to_count = to_count - 1
- end
- end
- minetest.log("action", tostring(verified_count).." out of "..tostring(count).." Realms have been verified and ready to activate.")
- end
- --[Local Function]: MArk the accurate current location by doing a checksum for each realm table
- local function in_realm_checksum(player, current_location)
- local name = player:get_player_name()
- local list = realms.locations
- for k,v in pairs(list) do
- local realm_to_check = k
- local to_compare = v["in_realm"]
- if realm_to_check ~= current_location then --Skip checking the current location to compare it's data with the other locations
- for a,b in pairs(to_compare) do
- local found_name = a
- if found_name == name then --If found, remove the player from the old location
- realms.locations[realm_to_check].in_realm[name] = nil
- list[realm_to_check]:on_realm_leave(player)
- break --Stop this loop after the job is completed
- end
- end
- end
- end
- list[current_location]:on_realm_entry(player)
- return
- end
- --[Local Function]: Realms Handler
- local function handle_realms()
- for _, player in ipairs(minetest.get_connected_players()) do
- local name = player:get_player_name()
- local list = realms.locations
- local pos = player:get_pos()
- local update_skybox = false
- local location_data = nil
- local old_location = ""
- local left_realm = false
- for k,v in pairs(list) do
- local realm = k
- local def = v
- local info = def["in_realm"]
- location_data = def
- if (pos.y < def.max_height and pos.y > def.min_height) or (pos.y == def.max_height or pos.y == def.min_height) then --Add player to the realm if the player is currently inside of it's bounds
- if info[name] == nil then
- update_skybox = true
- realms.locations[realm]["in_realm"][name] = true
- in_realm_checksum(player, realm)
- minetest.log("action", tostring(name).." is now in "..tostring(realm)..".")
- break
- end
- end
- end
- if update_skybox == true and location_data.skybox_type == "default" then
- player:set_sky(nil, "regular", {})
- player:set_clouds({
- density = 0.4,
- color = "#fff0f0e5",
- ambient = "#000000",
- height = 120,
- thickness = 16,
- speed = {x = 0, y = -2},
- })
- --If player exists, set his physics_override to 0 and notify him and the sender.
- player:set_physics_override({
- speed = minetest.settings:get("movement_speed_walk") or 1,
- jump = 1,
- gravity = 1.0,
- sneak = true,
- sneak_glitch = false,
- new_move = false,
- })
- elseif update_skybox == true and location_data.skybox_type == "colored" then
- player:set_sky(location_data.skybox_color, "plain", {})
- if location_data.enable_clouds == true then
- player:set_clouds({
- density = location_data.cloud_density or 0.4,
- color = location_data.cloud_color or "#fff0f0e5",
- ambient = location_data.cloud_ambient_color or "#000000",
- height = location_data.cloud_height or 120,
- thickness = location_data.cloud_thickness or 16,
- speed = location_data.cloud_speed or {x = 0, y = -2},
- })
- end
- if location_data.realm_physics == true then
- --If player exists, set his physics_override to 0 and notify him and the sender.
- player:set_physics_override({
- speed = minetest.settings:get("movement_speed_walk") or 1,
- jump = 1,
- gravity = location_data.realm_gravity or 1.0,
- sneak = true,
- sneak_glitch = false,
- new_move = false,
- })
- end
- elseif update_skybox == true and location_data.skybox_type == "textured" then
- player:set_sky({}, "skybox", location_data.skybox_textures)
- if location_data.enable_clouds == true then
- player:set_clouds({
- density = location_data.cloud_density or 0.4,
- color = location_data.cloud_color or "#fff0f0e5",
- ambient = location_data.cloud_ambient_color or "#000000",
- height = location_data.cloud_height or 120,
- thickness = location_data.cloud_thickness or 16,
- speed = location_data.cloud_speed or {x = 0, y = -2},
- })
- end
- if location_data.realm_physics == true then
- --If player exists, set his physics_override to 0 and notify him and the sender.
- player:set_physics_override({
- speed = minetest.settings:get("movement_speed_walk") or 1,
- jump = 1,
- gravity = location_data.realm_gravity or 1.0,
- sneak = true,
- sneak_glitch = false,
- new_move = false,
- })
- end
- end
- end
- minetest.after(update_interval, function()
- handle_realms()
- end)
- end
-
- --Activate cooldown handler
- minetest.register_on_mods_loaded(function()
- minetest.after(update_interval, function()
- verify_realms()
- handle_realms()
- end)
- end)
- minetest.register_on_leaveplayer(function(player)
- local name = player:get_player_name()
- if name then
- player:set_sky({}, "regular", {})
- for k,v in pairs(realms.locations)do
- local realm = k
- if realms.locations[realm]["in_realm"][name] == true then
- realms.locations[realm]["in_realm"][name] = nil
- end
- end
- end
- end)
|