Merge remote-tracking branch 'minetest/master'
Conflicts: src/CMakeLists.txt src/game.cpp src/script/lua_api/l_util.hmaster
commit
3c64860b41
|
@ -102,7 +102,7 @@ core.register_chatcommand("help", {
|
|||
description = "Get help for commands or list privileges",
|
||||
func = function(name, param)
|
||||
local function format_help_line(cmd, def)
|
||||
local msg = "/"..cmd
|
||||
local msg = core.colorize("#00ffff", "/"..cmd)
|
||||
if def.params and def.params ~= "" then
|
||||
msg = msg .. " " .. def.params
|
||||
end
|
||||
|
|
|
@ -197,3 +197,35 @@ function core.http_add_fetch(httpenv)
|
|||
|
||||
return httpenv
|
||||
end
|
||||
|
||||
if minetest.setting_getbool("disable_escape_sequences") then
|
||||
|
||||
function core.get_color_escape_sequence(color)
|
||||
return ""
|
||||
end
|
||||
|
||||
function core.get_background_escape_sequence(color)
|
||||
return ""
|
||||
end
|
||||
|
||||
function core.colorize(color, message)
|
||||
return message
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
local ESCAPE_CHAR = string.char(0x1b)
|
||||
function core.get_color_escape_sequence(color)
|
||||
return ESCAPE_CHAR .. "(c@" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.get_background_escape_sequence(color)
|
||||
return ESCAPE_CHAR .. "(b@" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.colorize(color, message)
|
||||
return core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("#ffffff")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -32,7 +32,10 @@ core.register_privilege("settime", "Can use /time")
|
|||
core.register_privilege("privs", "Can modify privileges")
|
||||
core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
|
||||
core.register_privilege("server", "Can do server maintenance stuff")
|
||||
core.register_privilege("protection_bypass", "Can bypass node protection in the world")
|
||||
core.register_privilege("protection_bypass", {
|
||||
description = "Can bypass node protection in the world",
|
||||
give_to_singleplayer = false,
|
||||
})
|
||||
core.register_privilege("shout", "Can speak in chat")
|
||||
core.register_privilege("ban", "Can ban and unban players")
|
||||
core.register_privilege("kick", "Can kick players")
|
||||
|
|
|
@ -615,6 +615,11 @@ server_announce (Announce server) bool false
|
|||
# If you want to announce your ipv6 address, use serverlist_url = v6.servers.minetest.net.
|
||||
serverlist_url (Serverlist URL) string servers.minetest.net
|
||||
|
||||
# Disable escape sequences, e.g. chat coloring.
|
||||
# Use this if you want to run a server with pre-0.4.14 clients and you want to disable
|
||||
# the escape sequences generated by mods.
|
||||
disable_escape_sequences (Disable escape sequences) bool false
|
||||
|
||||
[*Network]
|
||||
|
||||
# Network port to listen (UDP).
|
||||
|
|
|
@ -1701,6 +1701,24 @@ numerical form, the raw integer value of an ARGB8 quad:
|
|||
or string form, a ColorString (defined above):
|
||||
`colorspec = "green"`
|
||||
|
||||
Escape sequences
|
||||
----------------
|
||||
Most text can contain escape sequences, that can for example color the text.
|
||||
There are a few exceptions: tab headers, dropdowns and vertical labels can't.
|
||||
The following functions provide escape sequences:
|
||||
* `core.get_color_escape_sequence(color)`:
|
||||
* `color` is a ColorString
|
||||
* The escape sequence sets the text color to `color`
|
||||
* `core.colorize(color, message)`:
|
||||
* Equivalent to:
|
||||
`core.get_color_escape_sequence(color) ..
|
||||
message ..
|
||||
core.get_color_escape_sequence("#ffffff")`
|
||||
* `color.get_background_escape_sequence(color)`
|
||||
* `color` is a ColorString
|
||||
* The escape sequence sets the background of the whole text element to
|
||||
`color`. Only defined for item descriptions and tooltips.
|
||||
|
||||
Spatial Vectors
|
||||
---------------
|
||||
* `vector.new(a[, b, c])`: returns a vector:
|
||||
|
@ -1951,12 +1969,21 @@ Call these functions only at load time!
|
|||
* `minetest.notify_authentication_modified(name)`
|
||||
* Should be called by the authentication handler if privileges changes.
|
||||
* To report everybody, set `name=nil`.
|
||||
* `minetest.check_password_entry(name, entry, password)`
|
||||
* Returns true if the "db entry" for a player with name matches given
|
||||
* password, false otherwise.
|
||||
* The "db entry" is the usually player-individual value that is derived
|
||||
* from the player's chosen password and stored on the server in order to allow
|
||||
* authentication whenever the player desires to log in.
|
||||
* Only use this function for making it possible to log in via the password from
|
||||
* via protocols like IRC, other uses for inside the game are frowned upon.
|
||||
* `minetest.get_password_hash(name, raw_password)`
|
||||
* Convert a name-password pair to a password hash that Minetest can use.
|
||||
* The returned value alone is not a good basis for password checks based
|
||||
* on comparing the password hash in the database with the password hash
|
||||
* from the function, with an externally provided password, as the hash
|
||||
* in the db might use the new SRP verifier format.
|
||||
* For this purpose, use minetest.check_password_entry instead.
|
||||
* `minetest.string_to_privs(str)`: returns `{priv1=true,...}`
|
||||
* `minetest.privs_to_string(privs)`: returns `"priv1,priv2,..."`
|
||||
* Convert between two privilege representations
|
||||
|
@ -2438,6 +2465,10 @@ These functions return the leftover itemstack.
|
|||
* See documentation on `minetest.compress()` for supported compression methods.
|
||||
* currently supported.
|
||||
* `...` indicates method-specific arguments. Currently, no methods use this.
|
||||
* `minetest.encode_base64(string)`: returns string encoded in base64
|
||||
* Encodes a string in base64.
|
||||
* `minetest.decode_base64(string)`: returns string
|
||||
* Decodes a string encoded in base64.
|
||||
* `minetest.is_protected(pos, name)`: returns boolean
|
||||
* Returns true, if player `name` shouldn't be abled to dig at `pos` or do other
|
||||
actions, defineable by mods, due to some mod-defined ownership-like concept.
|
||||
|
@ -3881,6 +3912,9 @@ Definition tables
|
|||
size = 1,
|
||||
collisiondetection = false,
|
||||
-- ^ collisiondetection: if true collides with physical objects
|
||||
collision_removal = false,
|
||||
-- ^ collision_removal: if true then particle is removed when it collides,
|
||||
-- ^ requires collisiondetection = true to have any effect
|
||||
vertical = false,
|
||||
-- ^ vertical: if true faces player using y axis only
|
||||
texture = "image.png",
|
||||
|
@ -3910,6 +3944,9 @@ Definition tables
|
|||
-- ^ minsize/maxsize, minexptime/maxexptime (expirationtime)
|
||||
collisiondetection = false,
|
||||
-- ^ collisiondetection: if true uses collision detection
|
||||
collision_removal = false,
|
||||
-- ^ collision_removal: if true then particle is removed when it collides,
|
||||
-- ^ requires collisiondetection = true to have any effect
|
||||
vertical = false,
|
||||
-- ^ vertical: if true faces player using y axis only
|
||||
texture = "image.png",
|
||||
|
|
|
@ -210,6 +210,10 @@ string:trim()
|
|||
^ eg. string.trim("\n \t\tfoo bar\t ") == "foo bar"
|
||||
core.is_yes(arg) (possible in async calls)
|
||||
^ returns whether arg can be interpreted as yes
|
||||
minetest.encode_base64(string) (possible in async calls)
|
||||
^ Encodes a string in base64.
|
||||
minetest.decode_base64(string) (possible in async calls)
|
||||
^ Decodes a string encoded in base64.
|
||||
|
||||
Version compat:
|
||||
core.get_min_supp_proto()
|
||||
|
|
|
@ -8,7 +8,7 @@ msgstr ""
|
|||
"Project-Id-Version: 0.0.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-05 16:13+0200\n"
|
||||
"PO-Revision-Date: 2016-05-06 02:25+0000\n"
|
||||
"PO-Revision-Date: 2016-05-11 04:34+0000\n"
|
||||
"Last-Translator: Wuzzy <almikes@aol.com>\n"
|
||||
"Language-Team: German "
|
||||
"<https://hosted.weblate.org/projects/minetest/minetest/de/>\n"
|
||||
|
@ -2944,7 +2944,7 @@ msgstr ""
|
|||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Liquid fluidity"
|
||||
msgstr "Flüssigkeitswiederstand"
|
||||
msgstr "Flüssigkeitswiderstand"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Liquid fluidity smoothing"
|
||||
|
|
|
@ -8,20 +8,20 @@ msgstr ""
|
|||
"Project-Id-Version: minetest\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-05 16:13+0200\n"
|
||||
"PO-Revision-Date: 2015-10-26 16:22+0200\n"
|
||||
"Last-Translator: ChaosWormz <chaoswormz@openmailbox.org>\n"
|
||||
"Language-Team: Hebrew <https://hosted.weblate.org/projects/minetest/minetest/"
|
||||
"he/>\n"
|
||||
"PO-Revision-Date: 2016-05-26 21:01+0000\n"
|
||||
"Last-Translator: yuval hreman <huckvrni@gmail.com>\n"
|
||||
"Language-Team: Hebrew "
|
||||
"<https://hosted.weblate.org/projects/minetest/minetest/he/>\n"
|
||||
"Language: he\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 2.5-dev\n"
|
||||
"X-Generator: Weblate 2.7-dev\n"
|
||||
|
||||
#: builtin/fstk/ui.lua
|
||||
msgid "An error occured in a Lua script, such as a mod:"
|
||||
msgstr ""
|
||||
msgstr "אירעה שגיאה בקוד לואה (Lua), כנראה באחד המודים:"
|
||||
|
||||
#: builtin/fstk/ui.lua
|
||||
msgid "An error occured:"
|
||||
|
@ -41,7 +41,7 @@ msgstr "התחבר מחדש"
|
|||
|
||||
#: builtin/fstk/ui.lua
|
||||
msgid "The server has requested a reconnect:"
|
||||
msgstr ""
|
||||
msgstr "השרת מבקש שתתחבר מחדש:"
|
||||
|
||||
#: builtin/mainmenu/common.lua src/game.cpp
|
||||
msgid "Loading..."
|
||||
|
@ -49,27 +49,27 @@ msgstr "טוען..."
|
|||
|
||||
#: builtin/mainmenu/common.lua
|
||||
msgid "Protocol version mismatch. "
|
||||
msgstr ""
|
||||
msgstr "שגיאה בגרסאות הפרוטוקול. "
|
||||
|
||||
#: builtin/mainmenu/common.lua
|
||||
msgid "Server enforces protocol version $1. "
|
||||
msgstr ""
|
||||
msgstr "השרת יפעיל את פרוטוקול גרסה $1. בכוח "
|
||||
|
||||
#: builtin/mainmenu/common.lua
|
||||
msgid "Server supports protocol versions between $1 and $2. "
|
||||
msgstr ""
|
||||
msgstr "השרת תומך בפרוטוקולים בין גרסה $1 וגרסה $2. "
|
||||
|
||||
#: builtin/mainmenu/common.lua
|
||||
msgid "Try reenabling public serverlist and check your internet connection."
|
||||
msgstr ""
|
||||
msgstr "נסה לצאת והכנס מחדש לרשימת השרתים ובדוק את חיבור האינטרנט שלך."
|
||||
|
||||
#: builtin/mainmenu/common.lua
|
||||
msgid "We only support protocol version $1."
|
||||
msgstr ""
|
||||
msgstr "אנו תומכים רק בגירסה 1$ של הפרוטוקול."
|
||||
|
||||
#: builtin/mainmenu/common.lua
|
||||
msgid "We support protocol versions between version $1 and $2."
|
||||
msgstr ""
|
||||
msgstr "אנו תומכים בגרסאות בין 1$ ל-2$ של הפרוטוקול."
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua builtin/mainmenu/dlg_create_world.lua
|
||||
#: builtin/mainmenu/dlg_delete_mod.lua builtin/mainmenu/dlg_delete_world.lua
|
||||
|
@ -93,13 +93,15 @@ msgstr ""
|
|||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
msgid "Enable all"
|
||||
msgstr "אפשר בכל"
|
||||
msgstr "אפשר הכל"
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
msgid ""
|
||||
"Failed to enable mod \"$1\" as it contains disallowed characters. Only "
|
||||
"chararacters [a-z0-9_] are allowed."
|
||||
msgstr ""
|
||||
"טעינת המוד \"1$\" נכשלה מכיוון שהוא מכיל תווים לא חוקיים. רק התווים [a-z0-9_]"
|
||||
" מותרים."
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
msgid "Hide Game"
|
||||
|
@ -128,7 +130,7 @@ msgstr "מופעל"
|
|||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "A world named \"$1\" already exists"
|
||||
msgstr ""
|
||||
msgstr "עולם בשם \"1$\" כבר קיים"
|
||||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "Create"
|
||||
|
@ -136,11 +138,11 @@ msgstr "ליצור"
|
|||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "Download a subgame, such as minetest_game, from minetest.net"
|
||||
msgstr ""
|
||||
msgstr "הורד מפעיל משחק, למשל \"minetest_game\", מהאתר: minetest.net"
|
||||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "Download one from minetest.net"
|
||||
msgstr ""
|
||||
msgstr "הורד אחד מ-\"minetest.net\""
|
||||
|
||||
#: builtin/mainmenu/dlg_create_world.lua src/settings_translation_file.cpp
|
||||
msgid "Game"
|
||||
|
@ -148,11 +150,11 @@ msgstr "משחק"
|
|||
|
||||
#: builtin/mainmenu/dlg_create_world.lua src/settings_translation_file.cpp
|
||||
msgid "Mapgen"
|
||||
msgstr ""
|
||||
msgstr "מנוע מפות"
|
||||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "No worldname given or no game selected"
|
||||
msgstr ""
|
||||
msgstr "לא נבחר שם לעולם או שאף מפעיל משחק לא נבחר"
|
||||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "Seed"
|
||||
|
@ -160,7 +162,7 @@ msgstr ""
|
|||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "Warning: The minimal development test is meant for developers."
|
||||
msgstr ""
|
||||
msgstr "אזהרה: מצב המפתחים נועד למפתחים!."
|
||||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "World name"
|
||||
|
@ -168,7 +170,7 @@ msgstr "שם העולם"
|
|||
|
||||
#: builtin/mainmenu/dlg_create_world.lua
|
||||
msgid "You have no subgames installed."
|
||||
msgstr ""
|
||||
msgstr "אין לך אף מפעיל משחק מותקן."
|
||||
|
||||
#: builtin/mainmenu/dlg_delete_mod.lua
|
||||
msgid "Are you sure you want to delete \"$1\"?"
|
||||
|
@ -397,9 +399,8 @@ msgid "Uninstall selected modpack"
|
|||
msgstr ""
|
||||
|
||||
#: builtin/mainmenu/tab_multiplayer.lua
|
||||
#, fuzzy
|
||||
msgid "Address / Port"
|
||||
msgstr "כתובת / פורט :"
|
||||
msgstr "כתובת / פורט"
|
||||
|
||||
#: builtin/mainmenu/tab_multiplayer.lua src/settings_translation_file.cpp
|
||||
msgid "Client"
|
||||
|
@ -426,9 +427,8 @@ msgid "Favorite"
|
|||
msgstr ""
|
||||
|
||||
#: builtin/mainmenu/tab_multiplayer.lua builtin/mainmenu/tab_simple_main.lua
|
||||
#, fuzzy
|
||||
msgid "Name / Password"
|
||||
msgstr "שם/סיסמה :"
|
||||
msgstr "שם/סיסמה"
|
||||
|
||||
#: builtin/mainmenu/tab_multiplayer.lua builtin/mainmenu/tab_simple_main.lua
|
||||
msgid "PvP enabled"
|
||||
|
@ -505,9 +505,8 @@ msgid "8x"
|
|||
msgstr ""
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
#, fuzzy
|
||||
msgid "Advanced Settings"
|
||||
msgstr "הגדרות"
|
||||
msgstr "הגדרות מתקדמות"
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
msgid "Antialiasing:"
|
||||
|
@ -587,9 +586,8 @@ msgid "Parallax Occlusion"
|
|||
msgstr ""
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
#, fuzzy
|
||||
msgid "Particles"
|
||||
msgstr "אפשר בכל"
|
||||
msgstr "חלקיקים"
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
msgid "Settings"
|
||||
|
|
|
@ -7,7 +7,7 @@ msgstr ""
|
|||
"Project-Id-Version: Minetest 0.4.9\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-05 16:13+0200\n"
|
||||
"PO-Revision-Date: 2016-05-08 17:01+0000\n"
|
||||
"PO-Revision-Date: 2016-05-14 13:34+0000\n"
|
||||
"Last-Translator: Emon Omen <emon@openmailbox.org>\n"
|
||||
"Language-Team: Italian "
|
||||
"<https://hosted.weblate.org/projects/minetest/minetest/it/>\n"
|
||||
|
@ -2831,7 +2831,7 @@ msgstr "Tasto \"Usare\" per arrampicarsi/scendere"
|
|||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Language"
|
||||
msgstr "Linua"
|
||||
msgstr "Lingua"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Large cave depth"
|
||||
|
|
|
@ -8,17 +8,17 @@ msgstr ""
|
|||
"Project-Id-Version: minetest\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-05 16:13+0200\n"
|
||||
"PO-Revision-Date: 2016-04-18 23:08+0000\n"
|
||||
"Last-Translator: Stas Kies <stask85@gmail.com>\n"
|
||||
"Language-Team: Russian <https://hosted.weblate.org/projects/minetest/"
|
||||
"minetest/ru/>\n"
|
||||
"PO-Revision-Date: 2016-05-20 15:18+0000\n"
|
||||
"Last-Translator: Andrey K. <contact@libnaru.so>\n"
|
||||
"Language-Team: Russian "
|
||||
"<https://hosted.weblate.org/projects/minetest/minetest/ru/>\n"
|
||||
"Language: ru\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 2.6-dev\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<="
|
||||
"4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 2.7-dev\n"
|
||||
|
||||
#: builtin/fstk/ui.lua
|
||||
msgid "An error occured in a Lua script, such as a mod:"
|
||||
|
@ -98,12 +98,14 @@ msgid "Enable all"
|
|||
msgstr "Включить всё"
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Failed to enable mod \"$1\" as it contains disallowed characters. Only "
|
||||
"chararacters [a-z0-9_] are allowed."
|
||||
msgstr ""
|
||||
"Ошибка при попытке включения мода \"$1\" поскольку он содержит недопустимые "
|
||||
"символы. Допускается использование символов от Aa-Zz и от 0-9."
|
||||
"символы. Допускается использование строчных букв латинского алфавита, цифр, "
|
||||
"и знака подчёркивания."
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
msgid "Hide Game"
|
||||
|
@ -425,6 +427,7 @@ msgid "Creative mode"
|
|||
msgstr "Режим творчества"
|
||||
|
||||
#: builtin/mainmenu/tab_multiplayer.lua builtin/mainmenu/tab_simple_main.lua
|
||||
#, fuzzy
|
||||
msgid "Damage enabled"
|
||||
msgstr "Разрешить увечья"
|
||||
|
||||
|
@ -1620,16 +1623,23 @@ msgid "Colored fog"
|
|||
msgstr "Цветной туман"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Comma-separated list of trusted mods that are allowed to access insecure\n"
|
||||
"functions even when mod security is on (via request_insecure_environment())."
|
||||
msgstr ""
|
||||
"Список доверенных модов, через запятую, которым разрешён доступ к "
|
||||
"небезопасным функциям, даже в безопасном режиме (с помощью "
|
||||
"request_insecure_environment())."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Comma-seperated list of mods that are allowed to access HTTP APIs, which\n"
|
||||
"allow them to upload and download data to/from the internet."
|
||||
msgstr ""
|
||||
"Список доверенных модов, через запятую, которым разрешён доступ к HTTP API, "
|
||||
"что позволяет им отправлять и принимать данные в/из сети Интернет."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Command key"
|
||||
|
@ -1800,7 +1810,7 @@ msgstr ""
|
|||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Delay showing tooltips, stated in milliseconds."
|
||||
msgstr ""
|
||||
msgstr "Задержка показа подсказок, указанная в миллисекундах."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
|
@ -1923,8 +1933,9 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Enables animation of inventory items."
|
||||
msgstr ""
|
||||
msgstr "Включить анимацию предметов в инвентаре."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid ""
|
||||
|
@ -1979,18 +1990,22 @@ msgid "Fall bobbing"
|
|||
msgstr ""
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Fallback font"
|
||||
msgstr "Fallback шрифт"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Fallback font shadow"
|
||||
msgstr ""
|
||||
msgstr "Fallback тень шрифта"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Fallback font shadow alpha"
|
||||
msgstr ""
|
||||
msgstr "Fallback прозрачность тени шрифта"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Fallback font size"
|
||||
msgstr "Fallback размер шрифта"
|
||||
|
||||
|
@ -2016,7 +2031,7 @@ msgid ""
|
|||
"Fast movement (via use key).\n"
|
||||
"This requires the \"fast\" privilege on the server."
|
||||
msgstr ""
|
||||
"Быстрое перемещение (с использование клавиши).\n"
|
||||
"Быстрое перемещение (с использованием клавиши).\n"
|
||||
"Это требует привилегию \"fast\" на сервере."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
|
@ -2056,8 +2071,9 @@ msgid "Filtering"
|
|||
msgstr "Фильтрация"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Fixed map seed"
|
||||
msgstr "Конкретное семя мира"
|
||||
msgstr "Фиксированное зерно мира"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Fly key"
|
||||
|
@ -2101,13 +2117,12 @@ msgid "Font size"
|
|||
msgstr "Размер шрифта"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Format of screenshots."
|
||||
msgstr "Путь для сохранения скриншотов."
|
||||
msgstr "Формат скриншотов."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Forward key"
|
||||
msgstr "Вперед"
|
||||
msgstr "Клавиша вперёд"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Freetype fonts"
|
||||
|
@ -2166,6 +2181,7 @@ msgid "Generate normalmaps"
|
|||
msgstr "Генерировать карты нормалей"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Global map generation attributes.\n"
|
||||
"In Mapgen v6 the 'decorations' flag controls all decorations except trees\n"
|
||||
|
@ -2176,6 +2192,16 @@ msgid ""
|
|||
"default.\n"
|
||||
"Flags starting with 'no' are used to explicitly disable them."
|
||||
msgstr ""
|
||||
"Параметры глобального генератора карты.\n"
|
||||
"В генераторе карт v6 флаг 'decorations' управляет всем оформлением за "
|
||||
"исключением деревьев\n"
|
||||
" и junglegras(травы джунглей?), в остальных генераторах этот флаг управляет "
|
||||
"всем оформлением.\n"
|
||||
"Стандартные флаги, установленные в engine(инструменте?) следующие: caves, "
|
||||
"light, decorations\n"
|
||||
"Строка флагов изменяет стандартные настройки engine(инструмента?).\n"
|
||||
"Флаги, не указанные в строке флагов, по умолчанию не изменяются.\n"
|
||||
"Флаги, начинающиеся с 'no' используются для их явного отключения."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Graphics"
|
||||
|
@ -2201,18 +2227,26 @@ msgid ""
|
|||
"- log: mimic and log backtrace of deprecated call (default for debug).\n"
|
||||
"- error: abort on usage of deprecated call (suggested for mod developers)."
|
||||
msgstr ""
|
||||
"Обработка для устаревших вызовов lua api:\n"
|
||||
"- legacy: (иногда успешно) имитирует прежнее поведение (по умолчанию для "
|
||||
"релиза).\n"
|
||||
"- log: имитирует и журналирует backtrace(трассировку?след?) устаревших "
|
||||
"вызовов (по умолчанию для отладки).\n"
|
||||
"- error: прерывание при использовании устаревших вызовов (рекомендовано "
|
||||
"для разработчиков модов)."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Height component of the initial window size."
|
||||
msgstr ""
|
||||
msgstr "Высота содержимого (относительно?) исходного размера окна"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Height on which clouds are appearing."
|
||||
msgstr ""
|
||||
msgstr "Высота, на которой появляются облака."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "High-precision FPU"
|
||||
msgstr ""
|
||||
msgstr "Высокоточный FPU"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Homepage of server, to be displayed in the serverlist."
|
||||
|
@ -2220,33 +2254,43 @@ msgstr "Домашняя страница сервера, отображаема
|
|||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "How deep to make rivers"
|
||||
msgstr ""
|
||||
msgstr "Глубина рек"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"How large area of blocks are subject to the active block stuff, stated in "
|
||||
"mapblocks (16 nodes).\n"
|
||||
"In active blocks objects are loaded and ABMs run."
|
||||
msgstr ""
|
||||
"Размер площади из блоков, составляющей активный блок, расположенный в "
|
||||
"mapblocks (16 nodes).↵\n"
|
||||
"В активных блоках объекты загружаются и ABMs запускается."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"How many blocks are flying in the wire simultaneously for the whole server."
|
||||
msgstr ""
|
||||
msgstr "Количество блоков, передаваемых одновременно для всего сервера."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "How many blocks are flying in the wire simultaneously per client."
|
||||
msgstr ""
|
||||
msgstr "Количество блоков, передаваемых одновременно для каждого клиента."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"How much the server will wait before unloading unused mapblocks.\n"
|
||||
"Higher value is smoother, but will use more RAM."
|
||||
msgstr ""
|
||||
"Время ожидания сервера до выгрузки неиспользуемых mapblocks.\n"
|
||||
"Высокие значения более плавные, но используют больше RAM."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "How wide to make rivers"
|
||||
msgstr ""
|
||||
msgstr "Установка ширины рек"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
|
@ -2262,39 +2306,57 @@ msgid "IPv6 support."
|
|||
msgstr "IPv6 поддержка."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"If FPS would go higher than this, limit it by sleeping\n"
|
||||
"to not waste CPU power for no benefit."
|
||||
msgstr ""
|
||||
"Если FPS превысит это значение, ограничить его простоем,\n"
|
||||
"чтобы не тратить мощность процессора впустую."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"If disabled \"use\" key is used to fly fast if both fly and fast mode are "
|
||||
"enabled."
|
||||
msgstr ""
|
||||
"Если выключено, кнопка \"use\"(\"использовать\"?) используется для быстрого "
|
||||
"полёта, если одновременно включены быстрый режим и режим полёта."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"If enabled together with fly mode, player is able to fly through solid "
|
||||
"nodes.\n"
|
||||
"This requires the \"noclip\" privilege on the server."
|
||||
msgstr ""
|
||||
"Если включено одновременно с режимом полёта, игрок может летать через "
|
||||
"твердые nodes(узлы?вершины?). Это требует привилегий \"noclip\" на сервере."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"If enabled, \"use\" key instead of \"sneak\" key is used for climbing down "
|
||||
"and descending."
|
||||
msgstr ""
|
||||
"Если включено, клавиша \"use\"(\"использовать\"?) вместо \"sneak\"(\""
|
||||
"подкрасться\"?) будет использоваться для climbing down and descending."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"If enabled, actions are recorded for rollback.\n"
|
||||
"This option is only read when server starts."
|
||||
msgstr ""
|
||||
"Если включено, действия записываются для отката.\n"
|
||||
"Этот параметр считывается только при запуске сервера."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "If enabled, disable cheat prevention in multiplayer."
|
||||
msgstr ""
|
||||
"Если включено, отключается prevention(предупреждение?предотвращение?) "
|
||||
"читерства в мультиплеере."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid ""
|
||||
|
@ -3700,19 +3762,23 @@ msgstr "Каталог со скриншотами"
|
|||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Screenshot format"
|
||||
msgstr "Каталог со скриншотами"
|
||||
msgstr "Формат скриншота"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Screenshot quality"
|
||||
msgstr "Cкриншот"
|
||||
msgstr "Качество скриншота"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Screenshot quality. Only used for JPEG format.\n"
|
||||
"1 means worst quality; 100 means best quality.\n"
|
||||
"Use 0 for default quality."
|
||||
msgstr ""
|
||||
"Качество скриншота. Используется только для изображений в формате JPEG.\n"
|
||||
"1 означает плохое качество; 100 означает хорошее качество.\n"
|
||||
"Используйте 0 для настроек по умолчанию."
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
|
@ -3767,9 +3833,8 @@ msgid "Serverlist URL"
|
|||
msgstr "Список публичных серверов"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
msgid "Serverlist file"
|
||||
msgstr "Список публичных серверов"
|
||||
msgstr "Файл списка серверов"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
#, fuzzy
|
||||
|
|
|
@ -8,7 +8,7 @@ msgstr ""
|
|||
"Project-Id-Version: minetest\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-05 16:13+0200\n"
|
||||
"PO-Revision-Date: 2016-05-10 00:06+0000\n"
|
||||
"PO-Revision-Date: 2016-05-12 01:10+0000\n"
|
||||
"Last-Translator: Fixer <artem.brz@gmail.com>\n"
|
||||
"Language-Team: Ukrainian "
|
||||
"<https://hosted.weblate.org/projects/minetest/minetest/uk/>\n"
|
||||
|
@ -87,14 +87,12 @@ msgid "Depends:"
|
|||
msgstr "Залежить від:"
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
#, fuzzy
|
||||
msgid "Disable MP"
|
||||
msgstr "Вимкнути МП"
|
||||
msgstr "Вимкнути модпак"
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
#, fuzzy
|
||||
msgid "Enable MP"
|
||||
msgstr "Увімкнути МП"
|
||||
msgstr "Увімкнути модпак"
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
msgid "Enable all"
|
||||
|
@ -113,13 +111,12 @@ msgid "Hide Game"
|
|||
msgstr "Приховати гру"
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
#, fuzzy
|
||||
msgid "Hide mp content"
|
||||
msgstr "Приховати мп контент"
|
||||
msgstr "Сховати вміст модпаку"
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
msgid "Mod:"
|
||||
msgstr "Модифікація:"
|
||||
msgstr "Мод:"
|
||||
|
||||
#: builtin/mainmenu/dlg_config_world.lua
|
||||
#: builtin/mainmenu/dlg_settings_advanced.lua src/guiKeyChangeMenu.cpp
|
||||
|
@ -466,7 +463,7 @@ msgstr "Творчість"
|
|||
#: builtin/mainmenu/tab_server.lua builtin/mainmenu/tab_simple_main.lua
|
||||
#: builtin/mainmenu/tab_singleplayer.lua
|
||||
msgid "Enable Damage"
|
||||
msgstr "Увімкнути поранення"
|
||||
msgstr "Поранення"
|
||||
|
||||
#: builtin/mainmenu/tab_server.lua
|
||||
msgid "Name/Password"
|
||||
|
@ -538,9 +535,8 @@ msgid "Bilinear Filter"
|
|||
msgstr "Білінійна фільтрація"
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
#, fuzzy
|
||||
msgid "Bump Mapping"
|
||||
msgstr "Бамп-маппінг"
|
||||
msgstr "Бамп маппінг"
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
msgid "Change keys"
|
||||
|
@ -548,11 +544,11 @@ msgstr "Змінити клавіші"
|
|||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
msgid "Connected Glass"
|
||||
msgstr "З'єднане скло"
|
||||
msgstr "З'єднувати скло"
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
msgid "Fancy Leaves"
|
||||
msgstr "Гарні листя"
|
||||
msgstr "Гарне листя"
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
msgid "Mipmap"
|
||||
|
@ -568,7 +564,7 @@ msgstr "Ні"
|
|||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
msgid "No Filter"
|
||||
msgstr "Без фільтрування"
|
||||
msgstr "Без фільтрації"
|
||||
|
||||
#: builtin/mainmenu/tab_settings.lua
|
||||
msgid "No Mipmap"
|
||||
|
@ -896,7 +892,7 @@ msgstr "Далі"
|
|||
|
||||
#: src/guiKeyChangeMenu.cpp
|
||||
msgid "\"Use\" = climb down"
|
||||
msgstr "\"Використовувати\" = підніматися в гору"
|
||||
msgstr "\"Використовувати\" = підніматися вгору"
|
||||
|
||||
#: src/guiKeyChangeMenu.cpp
|
||||
msgid "Backward"
|
||||
|
@ -1564,7 +1560,7 @@ msgstr ""
|
|||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Client and Server"
|
||||
msgstr ""
|
||||
msgstr "Клієнт і сервер"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Climbing speed"
|
||||
|
@ -3261,7 +3257,7 @@ msgstr ""
|
|||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Network"
|
||||
msgstr ""
|
||||
msgstr "Мережа"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid ""
|
||||
|
@ -3534,7 +3530,7 @@ msgstr ""
|
|||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Security"
|
||||
msgstr ""
|
||||
msgstr "Безпека"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "See http://www.sqlite.org/pragma.html#pragma_synchronous"
|
||||
|
@ -3665,7 +3661,7 @@ msgstr "Крастися"
|
|||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid "Sound"
|
||||
msgstr ""
|
||||
msgstr "Звук"
|
||||
|
||||
#: src/settings_translation_file.cpp
|
||||
msgid ""
|
||||
|
|
|
@ -376,6 +376,7 @@ add_subdirectory(network)
|
|||
add_subdirectory(script)
|
||||
add_subdirectory(unittest)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(irrlicht_changes)
|
||||
|
||||
set(common_SRCS
|
||||
ban.cpp
|
||||
|
@ -493,6 +494,7 @@ set(client_SRCS
|
|||
${common_SRCS}
|
||||
${sound_SRCS}
|
||||
${client_network_SRCS}
|
||||
${client_irrlicht_changes_SRCS}
|
||||
ambiance.cpp
|
||||
camera.cpp
|
||||
client.cpp
|
||||
|
|
1128
src/cavegen.cpp
1128
src/cavegen.cpp
File diff suppressed because it is too large
Load Diff
185
src/cavegen.h
185
src/cavegen.h
|
@ -21,69 +21,79 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#define CAVEGEN_HEADER
|
||||
|
||||
#define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
|
||||
#define MGV5_LAVA_DEPTH -256
|
||||
#define MGV7_LAVA_DEPTH -256
|
||||
#define DEFAULT_LAVA_DEPTH (-256)
|
||||
|
||||
class MapgenV5;
|
||||
class MapgenV6;
|
||||
class MapgenV7;
|
||||
class GenerateNotifier;
|
||||
|
||||
class CaveV5 {
|
||||
/*
|
||||
CavesNoiseIntersection is a cave digging algorithm that carves smooth,
|
||||
web-like, continuous tunnels at points where the density of the intersection
|
||||
between two separate 3d noises is above a certain value. This value,
|
||||
cave_width, can be modified to set the effective width of these tunnels.
|
||||
|
||||
This algorithm is relatively heavyweight, taking ~80ms to generate an
|
||||
80x80x80 chunk of map on a modern processor. Use sparingly!
|
||||
|
||||
TODO(hmmmm): Remove dependency on biomes
|
||||
TODO(hmmmm): Find alternative to overgeneration as solution for sunlight issue
|
||||
*/
|
||||
class CavesNoiseIntersection {
|
||||
public:
|
||||
Mapgen *mg;
|
||||
MMVManip *vm;
|
||||
INodeDefManager *ndef;
|
||||
CavesNoiseIntersection(INodeDefManager *nodedef, BiomeManager *biomemgr,
|
||||
v3s16 chunksize, NoiseParams *np_cave1, NoiseParams *np_cave2,
|
||||
int seed, float cave_width);
|
||||
~CavesNoiseIntersection();
|
||||
|
||||
NoiseParams *np_caveliquids;
|
||||
void generateCaves(MMVManip *vm, v3s16 nmin, v3s16 nmax, u8 *biomemap);
|
||||
|
||||
s16 min_tunnel_diameter;
|
||||
s16 max_tunnel_diameter;
|
||||
u16 tunnel_routepoints;
|
||||
int dswitchint;
|
||||
int part_max_length_rs;
|
||||
private:
|
||||
INodeDefManager *m_ndef;
|
||||
BiomeManager *m_bmgr;
|
||||
|
||||
bool large_cave_is_flat;
|
||||
bool flooded;
|
||||
// configurable parameters
|
||||
v3s16 m_csize;
|
||||
float m_cave_width;
|
||||
|
||||
s16 max_stone_y;
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
// intermediate state variables
|
||||
u16 m_ystride;
|
||||
u16 m_zstride_1d;
|
||||
|
||||
v3f orp; // starting point, relative to caved space
|
||||
v3s16 of; // absolute coordinates of caved space
|
||||
v3s16 ar; // allowed route area
|
||||
s16 rs; // tunnel radius size
|
||||
v3f main_direction;
|
||||
|
||||
s16 route_y_min;
|
||||
s16 route_y_max;
|
||||
|
||||
PseudoRandom *ps;
|
||||
|
||||
content_t c_water_source;
|
||||
content_t c_lava_source;
|
||||
content_t c_ice;
|
||||
|
||||
int water_level;
|
||||
int ystride;
|
||||
|
||||
CaveV5() {}
|
||||
CaveV5(Mapgen *mg, PseudoRandom *ps);
|
||||
void makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height);
|
||||
void makeTunnel(bool dirswitch);
|
||||
void carveRoute(v3f vec, float f, bool randomize_xz);
|
||||
Noise *noise_cave1;
|
||||
Noise *noise_cave2;
|
||||
};
|
||||
|
||||
class CaveV6 {
|
||||
/*
|
||||
CavesRandomWalk is an implementation of a cave-digging algorithm that
|
||||
operates on the principle of a "random walk" to approximate the stochiastic
|
||||
activity of cavern development.
|
||||
|
||||
In summary, this algorithm works by carving a randomly sized tunnel in a
|
||||
random direction a random amount of times, randomly varying in width.
|
||||
All randomness here is uniformly distributed; alternative distributions have
|
||||
not yet been implemented.
|
||||
|
||||
This algorithm is very fast, executing in less than 1ms on average for an
|
||||
80x80x80 chunk of map on a modern processor.
|
||||
*/
|
||||
class CavesRandomWalk {
|
||||
public:
|
||||
MapgenV6 *mg;
|
||||
MMVManip *vm;
|
||||
INodeDefManager *ndef;
|
||||
GenerateNotifier *gennotify;
|
||||
s16 *heightmap;
|
||||
|
||||
// configurable parameters
|
||||
int seed;
|
||||
int water_level;
|
||||
int lava_depth;
|
||||
NoiseParams *np_caveliquids;
|
||||
|
||||
// intermediate state variables
|
||||
u16 ystride;
|
||||
|
||||
s16 min_tunnel_diameter;
|
||||
s16 max_tunnel_diameter;
|
||||
u16 tunnel_routepoints;
|
||||
int dswitchint;
|
||||
int part_max_length_rs;
|
||||
|
||||
bool large_cave;
|
||||
|
@ -104,38 +114,70 @@ public:
|
|||
s16 route_y_max;
|
||||
|
||||
PseudoRandom *ps;
|
||||
PseudoRandom *ps2;
|
||||
|
||||
content_t c_water_source;
|
||||
content_t c_lava_source;
|
||||
|
||||
int water_level;
|
||||
// ndef is a mandatory parameter.
|
||||
// If gennotify is NULL, generation events are not logged.
|
||||
CavesRandomWalk(INodeDefManager *ndef,
|
||||
GenerateNotifier *gennotify = NULL,
|
||||
int seed = 0,
|
||||
int water_level = 1,
|
||||
content_t water_source = CONTENT_IGNORE,
|
||||
content_t lava_source = CONTENT_IGNORE);
|
||||
|
||||
CaveV6() {}
|
||||
CaveV6(MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool large_cave);
|
||||
void makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height);
|
||||
// vm and ps are mandatory parameters.
|
||||
// If heightmap is NULL, the surface level at all points is assumed to
|
||||
// be water_level.
|
||||
void makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax, PseudoRandom *ps,
|
||||
bool is_large_cave, int max_stone_height, s16 *heightmap);
|
||||
|
||||
private:
|
||||
void makeTunnel(bool dirswitch);
|
||||
void carveRoute(v3f vec, float f, bool randomize_xz, bool tunnel_above_ground);
|
||||
void carveRoute(v3f vec, float f, bool randomize_xz);
|
||||
|
||||
inline bool isPosAboveSurface(v3s16 p);
|
||||
};
|
||||
|
||||
class CaveV7 {
|
||||
/*
|
||||
CavesV6 is the original version of caves used with Mapgen V6.
|
||||
|
||||
Though it uses the same fundamental algorithm as CavesRandomWalk, it is made
|
||||
separate to preserve the exact sequence of PseudoRandom calls - any change
|
||||
to this ordering results in the output being radically different.
|
||||
Because caves in Mapgen V6 are responsible for a large portion of the basic
|
||||
terrain shape, modifying this will break our contract of reverse
|
||||
compatibility for a 'stable' mapgen such as V6.
|
||||
|
||||
tl;dr,
|
||||
*** DO NOT TOUCH THIS CLASS UNLESS YOU KNOW WHAT YOU ARE DOING ***
|
||||
*/
|
||||
class CavesV6 {
|
||||
public:
|
||||
MapgenV7 *mg;
|
||||
MMVManip *vm;
|
||||
INodeDefManager *ndef;
|
||||
GenerateNotifier *gennotify;
|
||||
PseudoRandom *ps;
|
||||
PseudoRandom *ps2;
|
||||
|
||||
NoiseParams *np_caveliquids;
|
||||
// configurable parameters
|
||||
s16 *heightmap;
|
||||
content_t c_water_source;
|
||||
content_t c_lava_source;
|
||||
int water_level;
|
||||
|
||||
// intermediate state variables
|
||||
u16 ystride;
|
||||
|
||||
s16 min_tunnel_diameter;
|
||||
s16 max_tunnel_diameter;
|
||||
u16 tunnel_routepoints;
|
||||
int dswitchint;
|
||||
int part_max_length_rs;
|
||||
|
||||
bool large_cave;
|
||||
bool large_cave_is_flat;
|
||||
bool flooded;
|
||||
|
||||
s16 max_stone_y;
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
|
||||
|
@ -148,19 +190,26 @@ public:
|
|||
s16 route_y_min;
|
||||
s16 route_y_max;
|
||||
|
||||
PseudoRandom *ps;
|
||||
// ndef is a mandatory parameter.
|
||||
// If gennotify is NULL, generation events are not logged.
|
||||
CavesV6(INodeDefManager *ndef,
|
||||
GenerateNotifier *gennotify = NULL,
|
||||
int water_level = 1,
|
||||
content_t water_source = CONTENT_IGNORE,
|
||||
content_t lava_source = CONTENT_IGNORE);
|
||||
|
||||
content_t c_water_source;
|
||||
content_t c_lava_source;
|
||||
content_t c_ice;
|
||||
// vm, ps, and ps2 are mandatory parameters.
|
||||
// If heightmap is NULL, the surface level at all points is assumed to
|
||||
// be water_level.
|
||||
void makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax,
|
||||
PseudoRandom *ps, PseudoRandom *ps2,
|
||||
bool is_large_cave, int max_stone_height, s16 *heightmap = NULL);
|
||||
|
||||
int water_level;
|
||||
|
||||
CaveV7() {}
|
||||
CaveV7(MapgenV7 *mg, PseudoRandom *ps);
|
||||
void makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height);
|
||||
private:
|
||||
void makeTunnel(bool dirswitch);
|
||||
void carveRoute(v3f vec, float f, bool randomize_xz);
|
||||
void carveRoute(v3f vec, float f, bool randomize_xz, bool tunnel_above_ground);
|
||||
|
||||
inline s16 getSurfaceFromHeightmap(v3s16 p);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
CGUITTFont FreeType class for Irrlicht
|
||||
Copyright (c) 2009-2010 John Norman
|
||||
Copyright (c) 2016 Nathanaël Courant
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
|
@ -545,6 +546,13 @@ void CGUITTFont::setFontHinting(const bool enable, const bool enable_auto_hintin
|
|||
|
||||
void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
|
||||
{
|
||||
draw(EnrichedString(std::wstring(text.c_str()), color), position, color, hcenter, vcenter, clip);
|
||||
}
|
||||
|
||||
void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
|
||||
{
|
||||
std::vector<video::SColor> colors = text.getColors();
|
||||
|
||||
if (!Driver)
|
||||
return;
|
||||
|
||||
|
@ -572,7 +580,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
|||
}
|
||||
|
||||
// Convert to a unicode string.
|
||||
core::ustring utext(text);
|
||||
core::ustring utext = text.getString();
|
||||
|
||||
// Set up our render map.
|
||||
core::map<u32, CGUITTGlyphPage*> Render_Map;
|
||||
|
@ -581,6 +589,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
|||
u32 n;
|
||||
uchar32_t previousChar = 0;
|
||||
core::ustring::const_iterator iter(utext);
|
||||
std::vector<video::SColor> applied_colors;
|
||||
while (!iter.atEnd())
|
||||
{
|
||||
uchar32_t currentChar = *iter;
|
||||
|
@ -590,7 +599,7 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
|||
if (currentChar == L'\r') // Mac or Windows breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks.
|
||||
if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks.
|
||||
currentChar = *(++iter);
|
||||
}
|
||||
else if (currentChar == (uchar32_t)'\n') // Unix breaks
|
||||
|
@ -627,6 +636,9 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
|||
page->render_positions.push_back(core::position2di(offset.X + offx, offset.Y + offy));
|
||||
page->render_source_rects.push_back(glyph.source_rect);
|
||||
Render_Map.set(glyph.glyph_page, page);
|
||||
u32 current_color = iter.getPos();
|
||||
if (current_color < colors.size())
|
||||
applied_colors.push_back(colors[current_color]);
|
||||
}
|
||||
offset.X += getWidthFromCharacter(currentChar);
|
||||
|
||||
|
@ -645,8 +657,6 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
|||
|
||||
CGUITTGlyphPage* page = n->getValue();
|
||||
|
||||
if (!use_transparency) color.color |= 0xff000000;
|
||||
|
||||
if (shadow_offset) {
|
||||
for (size_t i = 0; i < page->render_positions.size(); ++i)
|
||||
page->render_positions[i] += core::vector2di(shadow_offset, shadow_offset);
|
||||
|
@ -654,7 +664,17 @@ void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position
|
|||
for (size_t i = 0; i < page->render_positions.size(); ++i)
|
||||
page->render_positions[i] -= core::vector2di(shadow_offset, shadow_offset);
|
||||
}
|
||||
Driver->draw2DImageBatch(page->texture, page->render_positions, page->render_source_rects, clip, color, true);
|
||||
for (size_t i = 0; i < page->render_positions.size(); ++i) {
|
||||
irr::video::SColor col;
|
||||
if (!applied_colors.empty()) {
|
||||
col = applied_colors[i < applied_colors.size() ? i : 0];
|
||||
} else {
|
||||
col = irr::video::SColor(255, 255, 255, 255);
|
||||
}
|
||||
if (!use_transparency)
|
||||
col.color |= 0xff000000;
|
||||
Driver->draw2DImage(page->texture, page->render_positions[i], page->render_source_rects[i], clip, col, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
CGUITTFont FreeType class for Irrlicht
|
||||
Copyright (c) 2009-2010 John Norman
|
||||
Copyright (c) 2016 Nathanaël Courant
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
|
@ -33,6 +34,8 @@
|
|||
|
||||
#include <irrlicht.h>
|
||||
#include <ft2build.h>
|
||||
#include <vector>
|
||||
#include "util/enriched_string.h"
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
namespace irr
|
||||
|
@ -258,6 +261,10 @@ namespace gui
|
|||
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
|
||||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||
const core::rect<s32>* clip=0);
|
||||
|
||||
virtual void draw(const EnrichedString& text, const core::rect<s32>& position,
|
||||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||
const core::rect<s32>* clip=0);
|
||||
|
||||
//! Returns the dimension of a character produced by this font.
|
||||
virtual core::dimension2d<u32> getCharDimension(const wchar_t ch) const;
|
||||
|
|
40
src/chat.cpp
40
src/chat.cpp
|
@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#include "chat.h"
|
||||
#include "debug.h"
|
||||
#include "config.h"
|
||||
#include "util/strfnd.h"
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
|
@ -251,8 +252,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
|||
u32 hanging_indentation = 0;
|
||||
|
||||
// Format the sender name and produce fragments
|
||||
if (!line.name.empty())
|
||||
{
|
||||
if (!line.name.empty()) {
|
||||
temp_frag.text = L"<";
|
||||
temp_frag.column = 0;
|
||||
//temp_frag.bold = 0;
|
||||
|
@ -267,22 +267,20 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
|||
next_frags.push_back(temp_frag);
|
||||
}
|
||||
|
||||
std::wstring name_sanitized = line.name.c_str();
|
||||
|
||||
// Choose an indentation level
|
||||
if (line.name.empty())
|
||||
{
|
||||
if (line.name.empty()) {
|
||||
// Server messages
|
||||
hanging_indentation = 0;
|
||||
}
|
||||
else if (line.name.size() + 3 <= cols/2)
|
||||
{
|
||||
} else if (name_sanitized.size() + 3 <= cols/2) {
|
||||
// Names shorter than about half the console width
|
||||
hanging_indentation = line.name.size() + 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Very long names
|
||||
hanging_indentation = 2;
|
||||
}
|
||||
//EnrichedString line_text(line.text);
|
||||
|
||||
next_line.first = true;
|
||||
bool text_processing = false;
|
||||
|
@ -338,7 +336,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
|||
while (frag_length < remaining_in_input &&
|
||||
frag_length < remaining_in_output)
|
||||
{
|
||||
if (isspace(line.text[in_pos + frag_length]))
|
||||
if (isspace(line.text.getString()[in_pos + frag_length]))
|
||||
space_pos = frag_length;
|
||||
++frag_length;
|
||||
}
|
||||
|
@ -686,9 +684,6 @@ ChatBackend::~ChatBackend()
|
|||
|
||||
void ChatBackend::addMessage(std::wstring name, std::wstring text)
|
||||
{
|
||||
name = unescape_enriched(name);
|
||||
text = unescape_enriched(text);
|
||||
|
||||
// Note: A message may consist of multiple lines, for example the MOTD.
|
||||
WStrfnd fnd(text);
|
||||
while (!fnd.at_end())
|
||||
|
@ -732,19 +727,22 @@ ChatBuffer& ChatBackend::getRecentBuffer()
|
|||
return m_recent_buffer;
|
||||
}
|
||||
|
||||
std::wstring ChatBackend::getRecentChat()
|
||||
EnrichedString ChatBackend::getRecentChat()
|
||||
{
|
||||
std::wostringstream stream;
|
||||
EnrichedString result;
|
||||
for (u32 i = 0; i < m_recent_buffer.getLineCount(); ++i)
|
||||
{
|
||||
const ChatLine& line = m_recent_buffer.getLine(i);
|
||||
if (i != 0)
|
||||
stream << L"\n";
|
||||
if (!line.name.empty())
|
||||
stream << L"<" << line.name << L"> ";
|
||||
stream << line.text;
|
||||
result += L"\n";
|
||||
if (!line.name.empty()) {
|
||||
result += L"<";
|
||||
result += line.name;
|
||||
result += L"> ";
|
||||
}
|
||||
result += line.text;
|
||||
}
|
||||
return stream.str();
|
||||
return result;
|
||||
}
|
||||
|
||||
ChatPrompt& ChatBackend::getPrompt()
|
||||
|
|
19
src/chat.h
19
src/chat.h
|
@ -20,11 +20,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#ifndef CHAT_HEADER
|
||||
#define CHAT_HEADER
|
||||
|
||||
#include "irrlichttypes.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include "irrlichttypes.h"
|
||||
#include "util/enriched_string.h"
|
||||
|
||||
// Chat console related classes
|
||||
|
||||
struct ChatLine
|
||||
|
@ -32,9 +34,9 @@ struct ChatLine
|
|||
// age in seconds
|
||||
f32 age;
|
||||
// name of sending player, or empty if sent by server
|
||||
std::wstring name;
|
||||
EnrichedString name;
|
||||
// message text
|
||||
std::wstring text;
|
||||
EnrichedString text;
|
||||
|
||||
ChatLine(std::wstring a_name, std::wstring a_text):
|
||||
age(0.0),
|
||||
|
@ -42,12 +44,19 @@ struct ChatLine
|
|||
text(a_text)
|
||||
{
|
||||
}
|
||||
|
||||
ChatLine(EnrichedString a_name, EnrichedString a_text):
|
||||
age(0.0),
|
||||
name(a_name),
|
||||
text(a_text)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ChatFormattedFragment
|
||||
{
|
||||
// text string
|
||||
std::wstring text;
|
||||
EnrichedString text;
|
||||
// starting column
|
||||
u32 column;
|
||||
// formatting
|
||||
|
@ -260,7 +269,7 @@ public:
|
|||
// Get the recent messages buffer
|
||||
ChatBuffer& getRecentBuffer();
|
||||
// Concatenate all recent messages
|
||||
std::wstring getRecentChat();
|
||||
EnrichedString getRecentChat();
|
||||
// Get the console prompt
|
||||
ChatPrompt& getPrompt();
|
||||
|
||||
|
|
|
@ -184,6 +184,7 @@ struct ClientEvent
|
|||
f32 expirationtime;
|
||||
f32 size;
|
||||
bool collisiondetection;
|
||||
bool collision_removal;
|
||||
bool vertical;
|
||||
std::string *texture;
|
||||
} spawn_particle;
|
||||
|
@ -201,6 +202,7 @@ struct ClientEvent
|
|||
f32 minsize;
|
||||
f32 maxsize;
|
||||
bool collisiondetection;
|
||||
bool collision_removal;
|
||||
bool vertical;
|
||||
std::string *texture;
|
||||
u32 id;
|
||||
|
|
|
@ -204,6 +204,8 @@ void set_default_settings(Settings *settings)
|
|||
settings->setDefault("server_description", "");
|
||||
settings->setDefault("public_serverlist","true");
|
||||
|
||||
settings->setDefault("disable_escape_sequences", "false");
|
||||
|
||||
#if USE_FREETYPE
|
||||
settings->setDefault("freetype", "true");
|
||||
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "liberationsans.ttf"));
|
||||
|
|
|
@ -38,22 +38,27 @@ NoiseParams nparams_dungeon_density(0.0, 1.0, v3f(2.5, 2.5, 2.5), 0, 2, 1.4, 2.0
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
DungeonGen::DungeonGen(Mapgen *mapgen, DungeonParams *dparams)
|
||||
DungeonGen::DungeonGen(INodeDefManager *ndef,
|
||||
GenerateNotifier *gennotify, DungeonParams *dparams)
|
||||
{
|
||||
this->mg = mapgen;
|
||||
this->vm = mapgen->vm;
|
||||
assert(ndef);
|
||||
|
||||
this->ndef = ndef;
|
||||
this->gennotify = gennotify;
|
||||
|
||||
#ifdef DGEN_USE_TORCHES
|
||||
c_torch = mg->ndef->getId("default:torch");
|
||||
c_torch = ndef->getId("default:torch");
|
||||
#endif
|
||||
|
||||
if (dparams) {
|
||||
memcpy(&dp, dparams, sizeof(dp));
|
||||
} else {
|
||||
dp.c_water = mg->ndef->getId("mapgen_water_source");
|
||||
dp.c_cobble = mg->ndef->getId("mapgen_cobble");
|
||||
dp.c_moss = mg->ndef->getId("mapgen_mossycobble");
|
||||
dp.c_stair = mg->ndef->getId("mapgen_stair_cobble");
|
||||
dp.seed = 0;
|
||||
|
||||
dp.c_water = ndef->getId("mapgen_water_source");
|
||||
dp.c_cobble = ndef->getId("mapgen_cobble");
|
||||
dp.c_moss = ndef->getId("mapgen_mossycobble");
|
||||
dp.c_stair = ndef->getId("mapgen_stair_cobble");
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 3.0;
|
||||
|
@ -67,18 +72,21 @@ DungeonGen::DungeonGen(Mapgen *mapgen, DungeonParams *dparams)
|
|||
}
|
||||
|
||||
// For mapgens using river water
|
||||
dp.c_river_water = mg->ndef->getId("mapgen_river_water_source");
|
||||
dp.c_river_water = ndef->getId("mapgen_river_water_source");
|
||||
if (dp.c_river_water == CONTENT_IGNORE)
|
||||
dp.c_river_water = mg->ndef->getId("mapgen_water_source");
|
||||
dp.c_river_water = ndef->getId("mapgen_water_source");
|
||||
}
|
||||
|
||||
|
||||
void DungeonGen::generate(u32 bseed, v3s16 nmin, v3s16 nmax)
|
||||
void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
|
||||
{
|
||||
assert(vm);
|
||||
|
||||
//TimeTaker t("gen dungeons");
|
||||
if (NoisePerlin3D(&dp.np_rarity, nmin.X, nmin.Y, nmin.Z, mg->seed) < 0.2)
|
||||
if (NoisePerlin3D(&dp.np_rarity, nmin.X, nmin.Y, nmin.Z, dp.seed) < 0.2)
|
||||
return;
|
||||
|
||||
this->vm = vm;
|
||||
this->blockseed = bseed;
|
||||
random.seed(bseed + 2);
|
||||
|
||||
|
@ -109,7 +117,7 @@ void DungeonGen::generate(u32 bseed, v3s16 nmin, v3s16 nmax)
|
|||
u32 i = vm->m_area.index(nmin.X, y, z);
|
||||
for (s16 x = nmin.X; x <= nmax.X; x++) {
|
||||
if (vm->m_data[i].getContent() == dp.c_cobble) {
|
||||
float wetness = NoisePerlin3D(&dp.np_wetness, x, y, z, mg->seed);
|
||||
float wetness = NoisePerlin3D(&dp.np_wetness, x, y, z, dp.seed);
|
||||
float density = NoisePerlin3D(&dp.np_density, x, y, z, blockseed);
|
||||
if (density < wetness / dp.mossratio)
|
||||
vm->m_data[i].setContent(dp.c_moss);
|
||||
|
@ -135,17 +143,23 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
|
|||
bool fits = false;
|
||||
for (u32 i = 0; i < 100 && !fits; i++) {
|
||||
bool is_large_room = ((random.next() & 3) == 1);
|
||||
roomsize = is_large_room ?
|
||||
v3s16(random.range(8, 16), random.range(8, 16), random.range(8, 16)) :
|
||||
v3s16(random.range(4, 8), random.range(4, 6), random.range(4, 8));
|
||||
if (is_large_room) {
|
||||
roomsize.Z = random.range(8, 16);
|
||||
roomsize.Y = random.range(8, 16);
|
||||
roomsize.X = random.range(8, 16);
|
||||
} else {
|
||||
roomsize.Z = random.range(4, 8);
|
||||
roomsize.Y = random.range(4, 6);
|
||||
roomsize.X = random.range(4, 8);
|
||||
}
|
||||
roomsize += dp.roomsize;
|
||||
|
||||
// start_padding is used to disallow starting the generation of
|
||||
// a dungeon in a neighboring generation chunk
|
||||
roomplace = vm->m_area.MinEdge + start_padding + v3s16(
|
||||
random.range(0, areasize.X - roomsize.X - start_padding.X),
|
||||
random.range(0, areasize.Y - roomsize.Y - start_padding.Y),
|
||||
random.range(0, areasize.Z - roomsize.Z - start_padding.Z));
|
||||
roomplace = vm->m_area.MinEdge + start_padding;
|
||||
roomplace.Z += random.range(0, areasize.Z - roomsize.Z - start_padding.Z);
|
||||
roomplace.Y += random.range(0, areasize.Y - roomsize.Y - start_padding.Y);
|
||||
roomplace.X += random.range(0, areasize.X - roomsize.X - start_padding.X);
|
||||
|
||||
/*
|
||||
Check that we're not putting the room to an unknown place,
|
||||
|
@ -181,7 +195,8 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
|
|||
makeRoom(roomsize, roomplace);
|
||||
|
||||
v3s16 room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2);
|
||||
mg->gennotify.addEvent(dp.notifytype, room_center);
|
||||
if (gennotify)
|
||||
gennotify->addEvent(dp.notifytype, room_center);
|
||||
|
||||
#ifdef DGEN_USE_TORCHES
|
||||
// Place torch at room center (for testing)
|
||||
|
@ -227,7 +242,9 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
|
|||
makeCorridor(doorplace, doordir, corridor_end, corridor_end_dir);
|
||||
|
||||
// Find a place for a random sized room
|
||||
roomsize = v3s16(random.range(4, 8), random.range(4, 6), random.range(4, 8));
|
||||
roomsize.Z = random.range(4, 8);
|
||||
roomsize.Y = random.range(4, 6);
|
||||
roomsize.X = random.range(4, 8);
|
||||
roomsize += dp.roomsize;
|
||||
|
||||
m_pos = corridor_end;
|
||||
|
@ -587,7 +604,10 @@ v3s16 rand_ortho_dir(PseudoRandom &random, bool diagonal_dirs)
|
|||
|
||||
do {
|
||||
trycount++;
|
||||
dir = v3s16(random.next() % 3 - 1, 0, random.next() % 3 - 1);
|
||||
|
||||
dir.Z = random.next() % 3 - 1;
|
||||
dir.Y = 0;
|
||||
dir.X = random.next() % 3 - 1;
|
||||
} while ((dir.X == 0 && dir.Z == 0) && trycount < 10);
|
||||
|
||||
return dir;
|
||||
|
|
|
@ -39,6 +39,8 @@ int dir_to_facedir(v3s16 d);
|
|||
|
||||
|
||||
struct DungeonParams {
|
||||
int seed;
|
||||
|
||||
content_t c_water;
|
||||
content_t c_river_water;
|
||||
content_t c_cobble;
|
||||
|
@ -59,7 +61,9 @@ struct DungeonParams {
|
|||
class DungeonGen {
|
||||
public:
|
||||
MMVManip *vm;
|
||||
Mapgen *mg;
|
||||
INodeDefManager *ndef;
|
||||
GenerateNotifier *gennotify;
|
||||
|
||||
u32 blockseed;
|
||||
PseudoRandom random;
|
||||
v3s16 csize;
|
||||
|
@ -67,17 +71,20 @@ public:
|
|||
content_t c_torch;
|
||||
DungeonParams dp;
|
||||
|
||||
//RoomWalker
|
||||
// RoomWalker
|
||||
v3s16 m_pos;
|
||||
v3s16 m_dir;
|
||||
|
||||
DungeonGen(Mapgen *mg, DungeonParams *dparams);
|
||||
void generate(u32 bseed, v3s16 full_node_min, v3s16 full_node_max);
|
||||
DungeonGen(INodeDefManager *ndef,
|
||||
GenerateNotifier *gennotify, DungeonParams *dparams);
|
||||
|
||||
void generate(MMVManip *vm, u32 bseed,
|
||||
v3s16 full_node_min, v3s16 full_node_max);
|
||||
|
||||
void makeDungeon(v3s16 start_padding);
|
||||
void makeRoom(v3s16 roomsize, v3s16 roomplace);
|
||||
void makeCorridor(v3s16 doorplace, v3s16 doordir,
|
||||
v3s16 &result_place, v3s16 &result_dir);
|
||||
v3s16 &result_place, v3s16 &result_dir);
|
||||
void makeDoor(v3s16 doorplace, v3s16 doordir);
|
||||
void makeFill(v3s16 place, v3s16 size, u8 avoid_flags, MapNode n, u8 or_flags);
|
||||
void makeHole(v3s16 place);
|
||||
|
@ -86,7 +93,7 @@ public:
|
|||
bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
|
||||
v3s16 &result_doordir, v3s16 &result_roomplace);
|
||||
|
||||
void randomizeDir()
|
||||
inline void randomizeDir()
|
||||
{
|
||||
m_dir = rand_ortho_dir(random, dp.diagonal_dirs);
|
||||
}
|
||||
|
|
|
@ -181,8 +181,6 @@ EmergeManager::~EmergeManager()
|
|||
delete oremgr;
|
||||
delete decomgr;
|
||||
delete schemmgr;
|
||||
|
||||
delete params.sparams;
|
||||
}
|
||||
|
||||
|
||||
|
|
40
src/game.cpp
40
src/game.cpp
|
@ -55,6 +55,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "tool.h"
|
||||
#include "util/directiontables.h"
|
||||
#include "util/pointedthing.h"
|
||||
#include "irrlicht_changes/static_text.h"
|
||||
#include "version.h"
|
||||
#include "minimap.h"
|
||||
#include "mapblock_mesh.h"
|
||||
|
@ -537,7 +538,7 @@ void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe,
|
|||
std::ostringstream os(std::ios_base::binary);
|
||||
g_profiler->printPage(os, show_profiler, show_profiler_max);
|
||||
std::wstring text = utf8_to_wide(os.str());
|
||||
guitext_profiler->setText(text.c_str());
|
||||
setStaticText(guitext_profiler, text.c_str());
|
||||
guitext_profiler->setVisible(true);
|
||||
|
||||
s32 w = fe->getTextWidth(text.c_str());
|
||||
|
@ -1240,7 +1241,11 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
|
|||
|
||||
// Get new messages from error log buffer
|
||||
while (!chat_log_error_buf.empty()) {
|
||||
chat_backend.addMessage(L"", utf8_to_wide(chat_log_error_buf.get()));
|
||||
std::wstring error_message = utf8_to_wide(chat_log_error_buf.get());
|
||||
if (!g_settings->getBool("disable_escape_sequences")) {
|
||||
error_message = L"\x1b(c@red)" + error_message + L"\x1b(c@white)";
|
||||
}
|
||||
chat_backend.addMessage(L"", error_message);
|
||||
}
|
||||
|
||||
// Get new messages from client
|
||||
|
@ -1255,10 +1260,10 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
|
|||
|
||||
// Display all messages in a static text element
|
||||
unsigned int recent_chat_count = chat_backend.getRecentBuffer().getLineCount();
|
||||
std::wstring recent_chat = chat_backend.getRecentChat();
|
||||
EnrichedString recent_chat = chat_backend.getRecentChat();
|
||||
unsigned int line_height = g_fontengine->getLineHeight();
|
||||
|
||||
guitext_chat->setText(recent_chat.c_str());
|
||||
setStaticText(guitext_chat, recent_chat);
|
||||
|
||||
// Update gui element size and position
|
||||
s32 chat_y = 5 + line_height;
|
||||
|
@ -1267,7 +1272,7 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
|
|||
chat_y += line_height;
|
||||
|
||||
// first pass to calculate height of text to be set
|
||||
s32 width = std::min(g_fontengine->getTextWidth(recent_chat) + 10,
|
||||
s32 width = std::min(g_fontengine->getTextWidth(recent_chat.c_str()) + 10,
|
||||
porting::getWindowSize().X - 20);
|
||||
core::rect<s32> rect(10, chat_y, width, chat_y + porting::getWindowSize().Y);
|
||||
guitext_chat->setRelativePosition(rect);
|
||||
|
@ -2214,37 +2219,39 @@ bool Game::createClient(const std::string &playername,
|
|||
bool Game::initGui()
|
||||
{
|
||||
// First line of debug text
|
||||
guitext = guienv->addStaticText(
|
||||
guitext = addStaticText(guienv,
|
||||
utf8_to_wide(PROJECT_NAME_C).c_str(),
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
false, false, guiroot);
|
||||
|
||||
// Second line of debug text
|
||||
guitext2 = guienv->addStaticText(
|
||||
guitext2 = addStaticText(guienv,
|
||||
L"",
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
false, false, guiroot);
|
||||
|
||||
// At the middle of the screen
|
||||
// Object infos are shown in this
|
||||
guitext_info = guienv->addStaticText(
|
||||
guitext_info = addStaticText(guienv,
|
||||
L"",
|
||||
core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5) + v2s32(100, 200),
|
||||
false, true, guiroot);
|
||||
|
||||
// Status text (displays info when showing and hiding GUI stuff, etc.)
|
||||
guitext_status = guienv->addStaticText(
|
||||
guitext_status = addStaticText(guienv,
|
||||
L"<Status>",
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
false, false, guiroot);
|
||||
guitext_status->setVisible(false);
|
||||
|
||||
// Chat text
|
||||
guitext_chat = guienv->addStaticText(
|
||||
guitext_chat = addStaticText(
|
||||
guienv,
|
||||
L"",
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
//false, false); // Disable word wrap as of now
|
||||
false, true, guiroot);
|
||||
|
||||
// Remove stale "recent" chat messages from previous connections
|
||||
chat_backend->clearRecentChat();
|
||||
|
||||
|
@ -2258,7 +2265,7 @@ bool Game::initGui()
|
|||
}
|
||||
|
||||
// Profiler text (size is updated when text is updated)
|
||||
guitext_profiler = guienv->addStaticText(
|
||||
guitext_profiler = addStaticText(guienv,
|
||||
L"<Profiler>",
|
||||
core::rect<s32>(0, 0, 0, 0),
|
||||
false, false, guiroot);
|
||||
|
@ -4355,16 +4362,17 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
|
|||
<< ", v_range = " << draw_control->wanted_range
|
||||
<< std::setprecision(3)
|
||||
<< ", RTT = " << client->getRTT();
|
||||
guitext->setText(utf8_to_wide(os.str()).c_str());
|
||||
setStaticText(guitext, utf8_to_wide(os.str()).c_str());
|
||||
guitext->setVisible(true);
|
||||
} else if (flags.show_hud || flags.show_chat) {
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
|
||||
os << PROJECT_NAME_C " " << g_version_hash
|
||||
<< " (" << (player_standing.X)
|
||||
<< ", " << (player_standing.Y)
|
||||
<< ", " << (player_standing.Z)
|
||||
<< ") " << yawToDirectionString(cam.camera_yaw);
|
||||
guitext->setText(utf8_to_wide(os.str()).c_str());
|
||||
setStaticText(guitext, utf8_to_wide(os.str()).c_str());
|
||||
guitext->setVisible(true);
|
||||
} else {
|
||||
guitext->setVisible(false);
|
||||
|
@ -4401,7 +4409,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
|
|||
}
|
||||
}
|
||||
|
||||
guitext2->setText(utf8_to_wide(os.str()).c_str());
|
||||
setStaticText(guitext2, utf8_to_wide(os.str()).c_str());
|
||||
guitext2->setVisible(true);
|
||||
|
||||
core::rect<s32> rect(
|
||||
|
@ -4413,7 +4421,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
|
|||
guitext2->setVisible(false);
|
||||
}
|
||||
|
||||
guitext_info->setText(infotext.c_str());
|
||||
setStaticText(guitext_info, infotext.c_str());
|
||||
guitext_info->setVisible(flags.show_hud && g_menumgr.menuCount() == 0);
|
||||
|
||||
float statustext_time_max = 1.5;
|
||||
|
@ -4427,7 +4435,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
|
|||
}
|
||||
}
|
||||
|
||||
guitext_status->setText(statustext.c_str());
|
||||
setStaticText(guitext_status, statustext.c_str());
|
||||
guitext_status->setVisible(!statustext.empty());
|
||||
|
||||
if (!statustext.empty()) {
|
||||
|
|
|
@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include <string>
|
||||
|
||||
#if USE_FREETYPE
|
||||
#include "xCGUITTFont.h"
|
||||
#include "xCGUITTFont.h"
|
||||
#endif
|
||||
|
||||
inline u32 clamp_u8(s32 value)
|
||||
|
@ -340,13 +340,28 @@ void GUIChatConsole::drawText()
|
|||
s32 x = (fragment.column + 1) * m_fontsize.X;
|
||||
core::rect<s32> destrect(
|
||||
x, y, x + m_fontsize.X * fragment.text.size(), y + m_fontsize.Y);
|
||||
m_font->draw(
|
||||
fragment.text.c_str(),
|
||||
destrect,
|
||||
video::SColor(255, 255, 255, 255),
|
||||
false,
|
||||
false,
|
||||
&AbsoluteClippingRect);
|
||||
|
||||
|
||||
#if USE_FREETYPE
|
||||
// Draw colored text if FreeType is enabled
|
||||
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(m_font);
|
||||
tmp->draw(
|
||||
fragment.text,
|
||||
destrect,
|
||||
video::SColor(255, 255, 255, 255),
|
||||
false,
|
||||
false,
|
||||
&AbsoluteClippingRect);
|
||||
#else
|
||||
// Otherwise use standard text
|
||||
m_font->draw(
|
||||
fragment.text.c_str(),
|
||||
destrect,
|
||||
video::SColor(255, 255, 255, 255),
|
||||
false,
|
||||
false,
|
||||
&AbsoluteClippingRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "log.h"
|
||||
#include "fontengine.h"
|
||||
#include "guiscalingfilter.h"
|
||||
#include "irrlicht_changes/static_text.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "client/tile.h"
|
||||
|
@ -172,15 +173,16 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
|
|||
m_sound_manager = &dummySoundManager;
|
||||
|
||||
//create topleft header
|
||||
std::wstring t = utf8_to_wide(std::string(PROJECT_NAME_C " ") +
|
||||
m_toplefttext = utf8_to_wide(std::string(PROJECT_NAME_C " ") +
|
||||
g_version_hash);
|
||||
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(t), g_fontengine->getTextHeight());
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
|
||||
g_fontengine->getTextHeight());
|
||||
rect += v2s32(4, 0);
|
||||
|
||||
m_irr_toplefttext =
|
||||
m_device->getGUIEnvironment()->addStaticText(t.c_str(),
|
||||
rect,false,true,0,-1);
|
||||
addStaticText(m_device->getGUIEnvironment(), m_toplefttext,
|
||||
rect, false, true, 0, -1);
|
||||
|
||||
//create formspecsource
|
||||
m_formspecgui = new FormspecFormSource("");
|
||||
|
@ -578,7 +580,7 @@ void GUIEngine::setTopleftText(std::string append)
|
|||
toset += utf8_to_wide(append);
|
||||
}
|
||||
|
||||
m_irr_toplefttext->setText(toset.c_str());
|
||||
m_toplefttext = toset;
|
||||
|
||||
updateTopLeftTextSize();
|
||||
}
|
||||
|
@ -586,15 +588,14 @@ void GUIEngine::setTopleftText(std::string append)
|
|||
/******************************************************************************/
|
||||
void GUIEngine::updateTopLeftTextSize()
|
||||
{
|
||||
std::wstring text = m_irr_toplefttext->getText();
|
||||
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(text), g_fontengine->getTextHeight());
|
||||
rect += v2s32(4, 0);
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
|
||||
g_fontengine->getTextHeight());
|
||||
rect += v2s32(4, 0);
|
||||
|
||||
m_irr_toplefttext->remove();
|
||||
m_irr_toplefttext =
|
||||
m_device->getGUIEnvironment()->addStaticText(text.c_str(),
|
||||
rect,false,true,0,-1);
|
||||
addStaticText(m_device->getGUIEnvironment(), m_toplefttext,
|
||||
rect, false, true, 0, -1);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "guiFormSpecMenu.h"
|
||||
#include "sound.h"
|
||||
#include "client/tile.h"
|
||||
#include "util/enriched_string.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/* Typedefs and macros */
|
||||
|
@ -275,6 +276,8 @@ private:
|
|||
|
||||
/** pointer to gui element shown at topleft corner */
|
||||
irr::gui::IGUIStaticText* m_irr_toplefttext;
|
||||
/** and text that is in it */
|
||||
EnrichedString m_toplefttext;
|
||||
|
||||
/** initialize cloud subsystem */
|
||||
void cloudInit();
|
||||
|
|
|
@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "util/hex.h"
|
||||
#include "util/numeric.h"
|
||||
#include "util/string.h" // for parseColorString()
|
||||
#include "irrlicht_changes/static_text.h"
|
||||
#include "guiscalingfilter.h"
|
||||
|
||||
#if USE_FREETYPE && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
|
||||
|
@ -249,37 +250,6 @@ std::vector<std::string>* GUIFormSpecMenu::getDropDownValues(const std::string &
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static std::vector<std::string> split(const std::string &s, char delim)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
std::string current = "";
|
||||
bool last_was_escape = false;
|
||||
for (unsigned int i = 0; i < s.size(); i++) {
|
||||
char si = s.c_str()[i];
|
||||
if (last_was_escape) {
|
||||
current += '\\';
|
||||
current += si;
|
||||
last_was_escape = false;
|
||||
} else {
|
||||
if (si == delim) {
|
||||
tokens.push_back(current);
|
||||
current = "";
|
||||
last_was_escape = false;
|
||||
} else if (si == '\\') {
|
||||
last_was_escape = true;
|
||||
} else {
|
||||
current += si;
|
||||
last_was_escape = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//push last element
|
||||
tokens.push_back(current);
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::parseSize(parserData* data,std::string element)
|
||||
{
|
||||
std::vector<std::string> parts = split(element,',');
|
||||
|
@ -966,7 +936,7 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element)
|
|||
int font_height = g_fontengine->getTextHeight();
|
||||
rect.UpperLeftCorner.Y -= font_height;
|
||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
}
|
||||
|
||||
e->setPasswordBox(true,L'*');
|
||||
|
@ -1021,7 +991,7 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
|
|||
if (name == "")
|
||||
{
|
||||
// spec field id to 0, this stops submit searching for a value that isn't there
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1056,7 +1026,7 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
|
|||
int font_height = g_fontengine->getTextHeight();
|
||||
rect.UpperLeftCorner.Y -= font_height;
|
||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1117,7 +1087,7 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,
|
|||
if (name == "")
|
||||
{
|
||||
// spec field id to 0, this stops submit searching for a value that isn't there
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1161,7 +1131,7 @@ void GUIFormSpecMenu::parseTextArea(parserData* data,
|
|||
int font_height = g_fontengine->getTextHeight();
|
||||
rect.UpperLeftCorner.Y -= font_height;
|
||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
||||
}
|
||||
}
|
||||
m_fields.push_back(spec);
|
||||
|
@ -1230,7 +1200,7 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element)
|
|||
258+m_fields.size()
|
||||
);
|
||||
gui::IGUIStaticText *e =
|
||||
Environment->addStaticText(spec.flabel.c_str(),
|
||||
addStaticText(Environment, spec.flabel.c_str(),
|
||||
rect, false, false, this, spec.fid);
|
||||
e->setTextAlignment(gui::EGUIA_UPPERLEFT,
|
||||
gui::EGUIA_CENTER);
|
||||
|
@ -1284,7 +1254,7 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element)
|
|||
258+m_fields.size()
|
||||
);
|
||||
gui::IGUIStaticText *t =
|
||||
Environment->addStaticText(spec.flabel.c_str(), rect, false, false, this, spec.fid);
|
||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, false, this, spec.fid);
|
||||
t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
|
||||
m_fields.push_back(spec);
|
||||
return;
|
||||
|
@ -1910,7 +1880,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||
{
|
||||
assert(m_tooltip_element == NULL);
|
||||
// Note: parent != this so that the tooltip isn't clipped by the menu rectangle
|
||||
m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
|
||||
m_tooltip_element = addStaticText(Environment, L"",core::rect<s32>(0,0,110,18));
|
||||
m_tooltip_element->enableOverrideColor(true);
|
||||
m_tooltip_element->setBackgroundColor(m_default_tooltip_bgcolor);
|
||||
m_tooltip_element->setDrawBackground(true);
|
||||
|
@ -2255,7 +2225,6 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase,
|
|||
std::wstring tooltip_text = L"";
|
||||
if (hovering && !m_selected_item) {
|
||||
tooltip_text = utf8_to_wide(item.getDefinition(m_gamedef->idef()).description);
|
||||
tooltip_text = unescape_enriched(tooltip_text);
|
||||
}
|
||||
if (tooltip_text != L"") {
|
||||
std::vector<std::wstring> tt_rows = str_split(tooltip_text, L'\n');
|
||||
|
@ -2263,7 +2232,7 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase,
|
|||
m_tooltip_element->setOverrideColor(m_default_tooltip_color);
|
||||
m_tooltip_element->setVisible(true);
|
||||
this->bringToFront(m_tooltip_element);
|
||||
m_tooltip_element->setText(tooltip_text.c_str());
|
||||
setStaticText(m_tooltip_element, tooltip_text.c_str());
|
||||
s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
|
||||
#if IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 8 && IRRLICHT_VERSION_REVISION < 2
|
||||
s32 tooltip_height = m_tooltip_element->getTextHeight() * tt_rows.size() + 5;
|
||||
|
@ -2535,8 +2504,10 @@ void GUIFormSpecMenu::drawMenu()
|
|||
iter != m_fields.end(); ++iter) {
|
||||
if (iter->fid == id && m_tooltips[iter->fname].tooltip != L"") {
|
||||
if (m_old_tooltip != m_tooltips[iter->fname].tooltip) {
|
||||
m_tooltip_element->setBackgroundColor(m_tooltips[iter->fname].bgcolor);
|
||||
m_tooltip_element->setOverrideColor(m_tooltips[iter->fname].color);
|
||||
m_old_tooltip = m_tooltips[iter->fname].tooltip;
|
||||
m_tooltip_element->setText(m_tooltips[iter->fname].tooltip.c_str());
|
||||
setStaticText(m_tooltip_element, m_tooltips[iter->fname].tooltip.c_str());
|
||||
std::vector<std::wstring> tt_rows = str_split(m_tooltips[iter->fname].tooltip, L'\n');
|
||||
s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height;
|
||||
s32 tooltip_height = m_tooltip_element->getTextHeight() * tt_rows.size() + 5;
|
||||
|
@ -2558,8 +2529,6 @@ void GUIFormSpecMenu::drawMenu()
|
|||
core::position2d<s32>(tooltip_x, tooltip_y),
|
||||
core::dimension2d<s32>(tooltip_width, tooltip_height)));
|
||||
}
|
||||
m_tooltip_element->setBackgroundColor(m_tooltips[iter->fname].bgcolor);
|
||||
m_tooltip_element->setOverrideColor(m_tooltips[iter->fname].color);
|
||||
m_tooltip_element->setVisible(true);
|
||||
this->bringToFront(m_tooltip_element);
|
||||
break;
|
||||
|
@ -2568,6 +2537,8 @@ void GUIFormSpecMenu::drawMenu()
|
|||
}
|
||||
}
|
||||
|
||||
m_tooltip_element->draw();
|
||||
|
||||
/*
|
||||
Draw dragged item stack
|
||||
*/
|
||||
|
|
|
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "guiTable.h"
|
||||
#include "network/networkprotocol.h"
|
||||
#include "util/string.h"
|
||||
#include "util/enriched_string.h"
|
||||
|
||||
class IGameDef;
|
||||
class InventoryManager;
|
||||
|
@ -202,7 +203,8 @@ class GUIFormSpecMenu : public GUIModalMenu
|
|||
fname(name),
|
||||
fid(id)
|
||||
{
|
||||
flabel = unescape_enriched(label);
|
||||
//flabel = unescape_enriched(label);
|
||||
flabel = label;
|
||||
fdefault = unescape_enriched(default_text);
|
||||
send = false;
|
||||
ftype = f_Unknown;
|
||||
|
@ -239,7 +241,8 @@ class GUIFormSpecMenu : public GUIModalMenu
|
|||
bgcolor(a_bgcolor),
|
||||
color(a_color)
|
||||
{
|
||||
tooltip = unescape_enriched(utf8_to_wide(a_tooltip));
|
||||
//tooltip = unescape_enriched(utf8_to_wide(a_tooltip));
|
||||
tooltip = utf8_to_wide(a_tooltip);
|
||||
}
|
||||
std::wstring tooltip;
|
||||
irr::video::SColor bgcolor;
|
||||
|
@ -256,7 +259,8 @@ class GUIFormSpecMenu : public GUIModalMenu
|
|||
rect(a_rect),
|
||||
parent_button(NULL)
|
||||
{
|
||||
text = unescape_enriched(a_text);
|
||||
//text = unescape_enriched(a_text);
|
||||
text = a_text;
|
||||
}
|
||||
StaticTextSpec(const std::wstring &a_text,
|
||||
const core::rect<s32> &a_rect,
|
||||
|
@ -264,7 +268,8 @@ class GUIFormSpecMenu : public GUIModalMenu
|
|||
rect(a_rect),
|
||||
parent_button(a_parent_button)
|
||||
{
|
||||
text = unescape_enriched(a_text);
|
||||
//text = unescape_enriched(a_text);
|
||||
text = a_text;
|
||||
}
|
||||
std::wstring text;
|
||||
core::rect<s32> rect;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
if (BUILD_CLIENT)
|
||||
set(client_irrlicht_changes_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/static_text.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
|
|
@ -0,0 +1,679 @@
|
|||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// Copyright (C) 2016 Nathanaël Courant:
|
||||
// Modified the functions to use EnrichedText instead of string.
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "static_text.h"
|
||||
#ifdef _IRR_COMPILE_WITH_GUI_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <IGUISkin.h>
|
||||
#include <IGUIEnvironment.h>
|
||||
#include <IGUIFont.h>
|
||||
#include <IVideoDriver.h>
|
||||
#include <rect.h>
|
||||
#include <SColor.h>
|
||||
|
||||
#if USE_FREETYPE
|
||||
#include "cguittfont/xCGUITTFont.h"
|
||||
#endif
|
||||
|
||||
#include "util/string.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
||||
#if USE_FREETYPE
|
||||
|
||||
namespace gui
|
||||
{
|
||||
//! constructor
|
||||
StaticText::StaticText(const EnrichedString &text, bool border,
|
||||
IGUIEnvironment* environment, IGUIElement* parent,
|
||||
s32 id, const core::rect<s32>& rectangle,
|
||||
bool background)
|
||||
: IGUIStaticText(environment, parent, id, rectangle),
|
||||
HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
|
||||
Border(border), OverrideColorEnabled(false), OverrideBGColorEnabled(false), WordWrap(false), Background(background),
|
||||
RestrainTextInside(true), RightToLeft(false),
|
||||
OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)),
|
||||
OverrideFont(0), LastBreakFont(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("StaticText");
|
||||
#endif
|
||||
|
||||
Text = text.c_str();
|
||||
cText = text;
|
||||
if (environment && environment->getSkin())
|
||||
{
|
||||
BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! destructor
|
||||
StaticText::~StaticText()
|
||||
{
|
||||
if (OverrideFont)
|
||||
OverrideFont->drop();
|
||||
}
|
||||
|
||||
//! draws the element and its children
|
||||
void StaticText::draw()
|
||||
{
|
||||
if (!IsVisible)
|
||||
return;
|
||||
|
||||
IGUISkin* skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
return;
|
||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||
|
||||
core::rect<s32> frameRect(AbsoluteRect);
|
||||
|
||||
// draw background
|
||||
|
||||
if (Background)
|
||||
{
|
||||
if ( !OverrideBGColorEnabled ) // skin-colors can change
|
||||
BGColor = skin->getColor(gui::EGDC_3D_FACE);
|
||||
|
||||
driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect);
|
||||
}
|
||||
|
||||
// draw the border
|
||||
|
||||
if (Border)
|
||||
{
|
||||
skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
|
||||
frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
|
||||
}
|
||||
|
||||
// draw the text
|
||||
if (cText.size())
|
||||
{
|
||||
IGUIFont* font = getActiveFont();
|
||||
|
||||
if (font)
|
||||
{
|
||||
if (!WordWrap)
|
||||
{
|
||||
// TODO: add colors here
|
||||
if (VAlign == EGUIA_LOWERRIGHT)
|
||||
{
|
||||
frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
|
||||
font->getDimension(L"A").Height - font->getKerningHeight();
|
||||
}
|
||||
if (HAlign == EGUIA_LOWERRIGHT)
|
||||
{
|
||||
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
||||
font->getDimension(cText.c_str()).Width;
|
||||
}
|
||||
|
||||
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
|
||||
tmp->draw(cText, frameRect,
|
||||
OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
|
||||
HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (font != LastBreakFont)
|
||||
breakText();
|
||||
|
||||
core::rect<s32> r = frameRect;
|
||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
||||
s32 totalHeight = height * BrokenText.size();
|
||||
if (VAlign == EGUIA_CENTER)
|
||||
{
|
||||
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
||||
}
|
||||
else if (VAlign == EGUIA_LOWERRIGHT)
|
||||
{
|
||||
r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
|
||||
}
|
||||
|
||||
irr::video::SColor previous_color(255, 255, 255, 255);
|
||||
for (u32 i=0; i<BrokenText.size(); ++i)
|
||||
{
|
||||
if (HAlign == EGUIA_LOWERRIGHT)
|
||||
{
|
||||
r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
||||
font->getDimension(BrokenText[i].c_str()).Width;
|
||||
}
|
||||
|
||||
//std::vector<irr::video::SColor> colors;
|
||||
//std::wstring str;
|
||||
EnrichedString str = BrokenText[i];
|
||||
|
||||
//str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
|
||||
//if (!colors.empty())
|
||||
// previous_color = colors[colors.size() - 1];
|
||||
|
||||
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
|
||||
tmp->draw(str, r,
|
||||
previous_color, // FIXME
|
||||
HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
||||
|
||||
r.LowerRightCorner.Y += height;
|
||||
r.UpperLeftCorner.Y += height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IGUIElement::draw();
|
||||
}
|
||||
|
||||
|
||||
//! Sets another skin independent font.
|
||||
void StaticText::setOverrideFont(IGUIFont* font)
|
||||
{
|
||||
if (OverrideFont == font)
|
||||
return;
|
||||
|
||||
if (OverrideFont)
|
||||
OverrideFont->drop();
|
||||
|
||||
OverrideFont = font;
|
||||
|
||||
if (OverrideFont)
|
||||
OverrideFont->grab();
|
||||
|
||||
breakText();
|
||||
}
|
||||
|
||||
//! Gets the override font (if any)
|
||||
IGUIFont * StaticText::getOverrideFont() const
|
||||
{
|
||||
return OverrideFont;
|
||||
}
|
||||
|
||||
//! Get the font which is used right now for drawing
|
||||
IGUIFont* StaticText::getActiveFont() const
|
||||
{
|
||||
if ( OverrideFont )
|
||||
return OverrideFont;
|
||||
IGUISkin* skin = Environment->getSkin();
|
||||
if (skin)
|
||||
return skin->getFont();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Sets another color for the text.
|
||||
void StaticText::setOverrideColor(video::SColor color)
|
||||
{
|
||||
OverrideColor = color;
|
||||
OverrideColorEnabled = true;
|
||||
}
|
||||
|
||||
|
||||
//! Sets another color for the text.
|
||||
void StaticText::setBackgroundColor(video::SColor color)
|
||||
{
|
||||
BGColor = color;
|
||||
OverrideBGColorEnabled = true;
|
||||
Background = true;
|
||||
}
|
||||
|
||||
|
||||
//! Sets whether to draw the background
|
||||
void StaticText::setDrawBackground(bool draw)
|
||||
{
|
||||
Background = draw;
|
||||
}
|
||||
|
||||
|
||||
//! Gets the background color
|
||||
video::SColor StaticText::getBackgroundColor() const
|
||||
{
|
||||
return BGColor;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if background drawing is enabled
|
||||
bool StaticText::isDrawBackgroundEnabled() const
|
||||
{
|
||||
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
|
||||
return Background;
|
||||
}
|
||||
|
||||
|
||||
//! Sets whether to draw the border
|
||||
void StaticText::setDrawBorder(bool draw)
|
||||
{
|
||||
Border = draw;
|
||||
}
|
||||
|
||||
|
||||
//! Checks if border drawing is enabled
|
||||
bool StaticText::isDrawBorderEnabled() const
|
||||
{
|
||||
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
|
||||
return Border;
|
||||
}
|
||||
|
||||
|
||||
void StaticText::setTextRestrainedInside(bool restrainTextInside)
|
||||
{
|
||||
RestrainTextInside = restrainTextInside;
|
||||
}
|
||||
|
||||
|
||||
bool StaticText::isTextRestrainedInside() const
|
||||
{
|
||||
return RestrainTextInside;
|
||||
}
|
||||
|
||||
|
||||
void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
|
||||
{
|
||||
HAlign = horizontal;
|
||||
VAlign = vertical;
|
||||
}
|
||||
|
||||
|
||||
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
|
||||
const video::SColor& StaticText::getOverrideColor() const
|
||||
#else
|
||||
video::SColor StaticText::getOverrideColor() const
|
||||
#endif
|
||||
{
|
||||
return OverrideColor;
|
||||
}
|
||||
|
||||
|
||||
//! Sets if the static text should use the overide color or the
|
||||
//! color in the gui skin.
|
||||
void StaticText::enableOverrideColor(bool enable)
|
||||
{
|
||||
OverrideColorEnabled = enable;
|
||||
}
|
||||
|
||||
|
||||
bool StaticText::isOverrideColorEnabled() const
|
||||
{
|
||||
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
|
||||
return OverrideColorEnabled;
|
||||
}
|
||||
|
||||
|
||||
//! Enables or disables word wrap for using the static text as
|
||||
//! multiline text control.
|
||||
void StaticText::setWordWrap(bool enable)
|
||||
{
|
||||
WordWrap = enable;
|
||||
breakText();
|
||||
}
|
||||
|
||||
|
||||
bool StaticText::isWordWrapEnabled() const
|
||||
{
|
||||
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
|
||||
return WordWrap;
|
||||
}
|
||||
|
||||
|
||||
void StaticText::setRightToLeft(bool rtl)
|
||||
{
|
||||
if (RightToLeft != rtl)
|
||||
{
|
||||
RightToLeft = rtl;
|
||||
breakText();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool StaticText::isRightToLeft() const
|
||||
{
|
||||
return RightToLeft;
|
||||
}
|
||||
|
||||
|
||||
//! Breaks the single text line.
|
||||
void StaticText::breakText()
|
||||
{
|
||||
if (!WordWrap)
|
||||
return;
|
||||
|
||||
BrokenText.clear();
|
||||
|
||||
IGUISkin* skin = Environment->getSkin();
|
||||
IGUIFont* font = getActiveFont();
|
||||
if (!font)
|
||||
return;
|
||||
|
||||
LastBreakFont = font;
|
||||
|
||||
EnrichedString line;
|
||||
EnrichedString word;
|
||||
EnrichedString whitespace;
|
||||
s32 size = cText.size();
|
||||
s32 length = 0;
|
||||
s32 elWidth = RelativeRect.getWidth();
|
||||
if (Border)
|
||||
elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
|
||||
wchar_t c;
|
||||
|
||||
//std::vector<irr::video::SColor> colors;
|
||||
|
||||
// We have to deal with right-to-left and left-to-right differently
|
||||
// However, most parts of the following code is the same, it's just
|
||||
// some order and boundaries which change.
|
||||
if (!RightToLeft)
|
||||
{
|
||||
// regular (left-to-right)
|
||||
for (s32 i=0; i<size; ++i)
|
||||
{
|
||||
c = cText.getString()[i];
|
||||
bool lineBreak = false;
|
||||
|
||||
if (c == L'\r') // Mac or Windows breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
//if (Text[i+1] == L'\n') // Windows breaks
|
||||
//{
|
||||
// Text.erase(i+1);
|
||||
// --size;
|
||||
//}
|
||||
c = '\0';
|
||||
}
|
||||
else if (c == L'\n') // Unix breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
c = '\0';
|
||||
}
|
||||
|
||||
bool isWhitespace = (c == L' ' || c == 0);
|
||||
if ( !isWhitespace )
|
||||
{
|
||||
// part of a word
|
||||
//word += c;
|
||||
word.addChar(cText, i);
|
||||
}
|
||||
|
||||
if ( isWhitespace || i == (size-1))
|
||||
{
|
||||
if (word.size())
|
||||
{
|
||||
// here comes the next whitespace, look if
|
||||
// we must break the last word to the next line.
|
||||
const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
|
||||
//const std::wstring sanitized = removeEscapes(word.c_str());
|
||||
const s32 wordlgth = font->getDimension(word.c_str()).Width;
|
||||
|
||||
if (wordlgth > elWidth)
|
||||
{
|
||||
// This word is too long to fit in the available space, look for
|
||||
// the Unicode Soft HYphen (SHY / 00AD) character for a place to
|
||||
// break the word at
|
||||
int where = core::stringw(word.c_str()).findFirst( wchar_t(0x00AD) );
|
||||
if (where != -1)
|
||||
{
|
||||
EnrichedString first = word.substr(0, where);
|
||||
EnrichedString second = word.substr(where, word.size() - where);
|
||||
first.addCharNoColor(L'-');
|
||||
BrokenText.push_back(line + first);
|
||||
const s32 secondLength = font->getDimension(second.c_str()).Width;
|
||||
|
||||
length = secondLength;
|
||||
line = second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No soft hyphen found, so there's nothing more we can do
|
||||
// break to next line
|
||||
if (length)
|
||||
BrokenText.push_back(line);
|
||||
length = wordlgth;
|
||||
line = word;
|
||||
}
|
||||
}
|
||||
else if (length && (length + wordlgth + whitelgth > elWidth))
|
||||
{
|
||||
// break to next line
|
||||
BrokenText.push_back(line);
|
||||
length = wordlgth;
|
||||
line = word;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add word to line
|
||||
line += whitespace;
|
||||
line += word;
|
||||
length += whitelgth + wordlgth;
|
||||
}
|
||||
|
||||
word.clear();
|
||||
whitespace.clear();
|
||||
}
|
||||
|
||||
if ( isWhitespace && c != 0)
|
||||
{
|
||||
whitespace.addChar(cText, i);
|
||||
}
|
||||
|
||||
// compute line break
|
||||
if (lineBreak)
|
||||
{
|
||||
line += whitespace;
|
||||
line += word;
|
||||
BrokenText.push_back(line);
|
||||
line.clear();
|
||||
word.clear();
|
||||
whitespace.clear();
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line += whitespace;
|
||||
line += word;
|
||||
BrokenText.push_back(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
// right-to-left
|
||||
for (s32 i=size; i>=0; --i)
|
||||
{
|
||||
c = cText.getString()[i];
|
||||
bool lineBreak = false;
|
||||
|
||||
if (c == L'\r') // Mac or Windows breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
//if ((i>0) && Text[i-1] == L'\n') // Windows breaks
|
||||
//{
|
||||
// Text.erase(i-1);
|
||||
// --size;
|
||||
//}
|
||||
c = '\0';
|
||||
}
|
||||
else if (c == L'\n') // Unix breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
c = '\0';
|
||||
}
|
||||
|
||||
if (c==L' ' || c==0 || i==0)
|
||||
{
|
||||
if (word.size())
|
||||
{
|
||||
// here comes the next whitespace, look if
|
||||
// we must break the last word to the next line.
|
||||
const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
|
||||
const s32 wordlgth = font->getDimension(word.c_str()).Width;
|
||||
|
||||
if (length && (length + wordlgth + whitelgth > elWidth))
|
||||
{
|
||||
// break to next line
|
||||
BrokenText.push_back(line);
|
||||
length = wordlgth;
|
||||
line = word;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add word to line
|
||||
line = whitespace + line;
|
||||
line = word + line;
|
||||
length += whitelgth + wordlgth;
|
||||
}
|
||||
|
||||
word.clear();
|
||||
whitespace.clear();
|
||||
}
|
||||
|
||||
if (c != 0)
|
||||
// whitespace = core::stringw(&c, 1) + whitespace;
|
||||
whitespace = cText.substr(i, 1) + whitespace;
|
||||
|
||||
// compute line break
|
||||
if (lineBreak)
|
||||
{
|
||||
line = whitespace + line;
|
||||
line = word + line;
|
||||
BrokenText.push_back(line);
|
||||
line.clear();
|
||||
word.clear();
|
||||
whitespace.clear();
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// yippee this is a word..
|
||||
//word = core::stringw(&c, 1) + word;
|
||||
word = cText.substr(i, 1) + word;
|
||||
}
|
||||
}
|
||||
|
||||
line = whitespace + line;
|
||||
line = word + line;
|
||||
BrokenText.push_back(line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Sets the new caption of this element.
|
||||
void StaticText::setText(const wchar_t* text)
|
||||
{
|
||||
setText(EnrichedString(text));
|
||||
}
|
||||
|
||||
//! Sets the new caption of this element.
|
||||
void StaticText::setText(const EnrichedString &text)
|
||||
{
|
||||
IGUIElement::setText(text.c_str());
|
||||
cText = text;
|
||||
if (text.hasBackground()) {
|
||||
setBackgroundColor(text.getBackground());
|
||||
}
|
||||
breakText();
|
||||
}
|
||||
|
||||
|
||||
void StaticText::updateAbsolutePosition()
|
||||
{
|
||||
IGUIElement::updateAbsolutePosition();
|
||||
breakText();
|
||||
}
|
||||
|
||||
|
||||
//! Returns the height of the text in pixels when it is drawn.
|
||||
s32 StaticText::getTextHeight() const
|
||||
{
|
||||
IGUIFont* font = getActiveFont();
|
||||
if (!font)
|
||||
return 0;
|
||||
|
||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
||||
|
||||
if (WordWrap)
|
||||
height *= BrokenText.size();
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
s32 StaticText::getTextWidth() const
|
||||
{
|
||||
IGUIFont * font = getActiveFont();
|
||||
if(!font)
|
||||
return 0;
|
||||
|
||||
if(WordWrap)
|
||||
{
|
||||
s32 widest = 0;
|
||||
|
||||
for(u32 line = 0; line < BrokenText.size(); ++line)
|
||||
{
|
||||
s32 width = font->getDimension(BrokenText[line].c_str()).Width;
|
||||
|
||||
if(width > widest)
|
||||
widest = width;
|
||||
}
|
||||
|
||||
return widest;
|
||||
}
|
||||
else
|
||||
{
|
||||
return font->getDimension(cText.c_str()).Width;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Writes attributes of the element.
|
||||
//! Implement this to expose the attributes of your element for
|
||||
//! scripting languages, editors, debuggers or xml serialization purposes.
|
||||
void StaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
|
||||
{
|
||||
IGUIStaticText::serializeAttributes(out,options);
|
||||
|
||||
out->addBool ("Border", Border);
|
||||
out->addBool ("OverrideColorEnabled",OverrideColorEnabled);
|
||||
out->addBool ("OverrideBGColorEnabled",OverrideBGColorEnabled);
|
||||
out->addBool ("WordWrap", WordWrap);
|
||||
out->addBool ("Background", Background);
|
||||
out->addBool ("RightToLeft", RightToLeft);
|
||||
out->addBool ("RestrainTextInside", RestrainTextInside);
|
||||
out->addColor ("OverrideColor", OverrideColor);
|
||||
out->addColor ("BGColor", BGColor);
|
||||
out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
|
||||
out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
|
||||
|
||||
// out->addFont ("OverrideFont", OverrideFont);
|
||||
}
|
||||
|
||||
|
||||
//! Reads attributes of the element
|
||||
void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
|
||||
{
|
||||
IGUIStaticText::deserializeAttributes(in,options);
|
||||
|
||||
Border = in->getAttributeAsBool("Border");
|
||||
enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
|
||||
OverrideBGColorEnabled = in->getAttributeAsBool("OverrideBGColorEnabled");
|
||||
setWordWrap(in->getAttributeAsBool("WordWrap"));
|
||||
Background = in->getAttributeAsBool("Background");
|
||||
RightToLeft = in->getAttributeAsBool("RightToLeft");
|
||||
RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
|
||||
OverrideColor = in->getAttributeAsColor("OverrideColor");
|
||||
BGColor = in->getAttributeAsColor("BGColor");
|
||||
|
||||
setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
|
||||
(EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
|
||||
|
||||
// OverrideFont = in->getAttributeAsFont("OverrideFont");
|
||||
}
|
||||
|
||||
} // end namespace gui
|
||||
|
||||
#endif // USE_FREETYPE
|
||||
|
||||
} // end namespace irr
|
||||
|
||||
|
||||
#endif // _IRR_COMPILE_WITH_GUI_
|
|
@ -0,0 +1,268 @@
|
|||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// Copyright (C) 2016 Nathanaël Courant
|
||||
// Modified this class to work with EnrichedStrings too
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_GUI_STATIC_TEXT_H_INCLUDED__
|
||||
#define __C_GUI_STATIC_TEXT_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
#ifdef _IRR_COMPILE_WITH_GUI_
|
||||
|
||||
#include "IGUIStaticText.h"
|
||||
#include "irrArray.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "util/enriched_string.h"
|
||||
#include "config.h"
|
||||
#include <IGUIEnvironment.h>
|
||||
|
||||
#if USE_FREETYPE
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
||||
namespace gui
|
||||
{
|
||||
|
||||
const EGUI_ELEMENT_TYPE EGUIET_ENRICHED_STATIC_TEXT = (EGUI_ELEMENT_TYPE)(0x1000);
|
||||
|
||||
class StaticText : public IGUIStaticText
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
StaticText(const EnrichedString &text, bool border, IGUIEnvironment* environment,
|
||||
IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
|
||||
bool background = false);
|
||||
|
||||
//! destructor
|
||||
virtual ~StaticText();
|
||||
|
||||
//! draws the element and its children
|
||||
virtual void draw();
|
||||
|
||||
//! Sets another skin independent font.
|
||||
virtual void setOverrideFont(IGUIFont* font=0);
|
||||
|
||||
//! Gets the override font (if any)
|
||||
virtual IGUIFont* getOverrideFont() const;
|
||||
|
||||
//! Get the font which is used right now for drawing
|
||||
virtual IGUIFont* getActiveFont() const;
|
||||
|
||||
//! Sets another color for the text.
|
||||
virtual void setOverrideColor(video::SColor color);
|
||||
|
||||
//! Sets another color for the background.
|
||||
virtual void setBackgroundColor(video::SColor color);
|
||||
|
||||
//! Sets whether to draw the background
|
||||
virtual void setDrawBackground(bool draw);
|
||||
|
||||
//! Gets the background color
|
||||
virtual video::SColor getBackgroundColor() const;
|
||||
|
||||
//! Checks if background drawing is enabled
|
||||
virtual bool isDrawBackgroundEnabled() const;
|
||||
|
||||
//! Sets whether to draw the border
|
||||
virtual void setDrawBorder(bool draw);
|
||||
|
||||
//! Checks if border drawing is enabled
|
||||
virtual bool isDrawBorderEnabled() const;
|
||||
|
||||
//! Sets alignment mode for text
|
||||
virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical);
|
||||
|
||||
//! Gets the override color
|
||||
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
|
||||
virtual const video::SColor& getOverrideColor() const;
|
||||
#else
|
||||
virtual video::SColor getOverrideColor() const;
|
||||
#endif
|
||||
|
||||
//! Sets if the static text should use the overide color or the
|
||||
//! color in the gui skin.
|
||||
virtual void enableOverrideColor(bool enable);
|
||||
|
||||
//! Checks if an override color is enabled
|
||||
virtual bool isOverrideColorEnabled() const;
|
||||
|
||||
//! Set whether the text in this label should be clipped if it goes outside bounds
|
||||
virtual void setTextRestrainedInside(bool restrainedInside);
|
||||
|
||||
//! Checks if the text in this label should be clipped if it goes outside bounds
|
||||
virtual bool isTextRestrainedInside() const;
|
||||
|
||||
//! Enables or disables word wrap for using the static text as
|
||||
//! multiline text control.
|
||||
virtual void setWordWrap(bool enable);
|
||||
|
||||
//! Checks if word wrap is enabled
|
||||
virtual bool isWordWrapEnabled() const;
|
||||
|
||||
//! Sets the new caption of this element.
|
||||
virtual void setText(const wchar_t* text);
|
||||
|
||||
//! Returns the height of the text in pixels when it is drawn.
|
||||
virtual s32 getTextHeight() const;
|
||||
|
||||
//! Returns the width of the current text, in the current font
|
||||
virtual s32 getTextWidth() const;
|
||||
|
||||
//! Updates the absolute position, splits text if word wrap is enabled
|
||||
virtual void updateAbsolutePosition();
|
||||
|
||||
//! Set whether the string should be interpreted as right-to-left (RTL) text
|
||||
/** \note This component does not implement the Unicode bidi standard, the
|
||||
text of the component should be already RTL if you call this. The
|
||||
main difference when RTL is enabled is that the linebreaks for multiline
|
||||
elements are performed starting from the end.
|
||||
*/
|
||||
virtual void setRightToLeft(bool rtl);
|
||||
|
||||
//! Checks if the text should be interpreted as right-to-left text
|
||||
virtual bool isRightToLeft() const;
|
||||
|
||||
//! Writes attributes of the element.
|
||||
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
|
||||
|
||||
//! Reads attributes of the element
|
||||
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
|
||||
|
||||
virtual bool hasType(EGUI_ELEMENT_TYPE t) const {
|
||||
return (t == EGUIET_ENRICHED_STATIC_TEXT) || (t == EGUIET_STATIC_TEXT);
|
||||
};
|
||||
|
||||
virtual bool hasType(EGUI_ELEMENT_TYPE t) {
|
||||
return (t == EGUIET_ENRICHED_STATIC_TEXT) || (t == EGUIET_STATIC_TEXT);
|
||||
};
|
||||
|
||||
void setText(const EnrichedString &text);
|
||||
|
||||
private:
|
||||
|
||||
//! Breaks the single text line.
|
||||
void breakText();
|
||||
|
||||
EGUI_ALIGNMENT HAlign, VAlign;
|
||||
bool Border;
|
||||
bool OverrideColorEnabled;
|
||||
bool OverrideBGColorEnabled;
|
||||
bool WordWrap;
|
||||
bool Background;
|
||||
bool RestrainTextInside;
|
||||
bool RightToLeft;
|
||||
|
||||
video::SColor OverrideColor, BGColor;
|
||||
gui::IGUIFont* OverrideFont;
|
||||
gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated.
|
||||
|
||||
EnrichedString cText;
|
||||
core::array< EnrichedString > BrokenText;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace gui
|
||||
|
||||
} // end namespace irr
|
||||
|
||||
inline irr::gui::IGUIStaticText *addStaticText(
|
||||
irr::gui::IGUIEnvironment *guienv,
|
||||
const EnrichedString &text,
|
||||
const core::rect< s32 > &rectangle,
|
||||
bool border = false,
|
||||
bool wordWrap = true,
|
||||
irr::gui::IGUIElement *parent = NULL,
|
||||
s32 id = -1,
|
||||
bool fillBackground = false)
|
||||
{
|
||||
if (parent == NULL) {
|
||||
// parent is NULL, so we must find one, or we need not to drop
|
||||
// result, but then there will be a memory leak.
|
||||
//
|
||||
// What Irrlicht does is to use guienv as a parent, but the problem
|
||||
// is that guienv is here only an IGUIEnvironment, while it is a
|
||||
// CGUIEnvironment in Irrlicht, which inherits from both IGUIElement
|
||||
// and IGUIEnvironment.
|
||||
//
|
||||
// A solution would be to dynamic_cast guienv to a
|
||||
// IGUIElement*, but Irrlicht is shipped without rtti support
|
||||
// in some distributions, causing the dymanic_cast to segfault.
|
||||
//
|
||||
// Thus, to find the parent, we create a dummy StaticText and ask
|
||||
// for its parent, and then remove it.
|
||||
irr::gui::IGUIStaticText *dummy_text =
|
||||
guienv->addStaticText(L"", rectangle, border, wordWrap,
|
||||
parent, id, fillBackground);
|
||||
parent = dummy_text->getParent();
|
||||
dummy_text->remove();
|
||||
}
|
||||
irr::gui::IGUIStaticText *result = new irr::gui::StaticText(
|
||||
text, border, guienv, parent,
|
||||
id, rectangle, fillBackground);
|
||||
|
||||
result->setWordWrap(wordWrap);
|
||||
result->drop();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedString &text)
|
||||
{
|
||||
// dynamic_cast not possible due to some distributions shipped
|
||||
// without rtti support in irrlicht
|
||||
if (static_text->hasType(irr::gui::EGUIET_ENRICHED_STATIC_TEXT)) {
|
||||
irr::gui::StaticText* stext = static_cast<irr::gui::StaticText*>(static_text);
|
||||
stext->setText(text);
|
||||
} else {
|
||||
static_text->setText(text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#else // USE_FREETYPE
|
||||
|
||||
inline irr::gui::IGUIStaticText *addStaticText(
|
||||
irr::gui::IGUIEnvironment *guienv,
|
||||
const EnrichedString &text,
|
||||
const core::rect< s32 > &rectangle,
|
||||
bool border = false,
|
||||
bool wordWrap = true,
|
||||
irr::gui::IGUIElement *parent = NULL,
|
||||
s32 id = -1,
|
||||
bool fillBackground = false)
|
||||
{
|
||||
return guienv->addStaticText(text.c_str(), rectangle, border, wordWrap, parent, id, fillBackground);
|
||||
}
|
||||
|
||||
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedString &text)
|
||||
{
|
||||
static_text->setText(text.c_str());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline irr::gui::IGUIStaticText *addStaticText(
|
||||
irr::gui::IGUIEnvironment *guienv,
|
||||
const wchar_t *text,
|
||||
const core::rect< s32 > &rectangle,
|
||||
bool border = false,
|
||||
bool wordWrap = true,
|
||||
irr::gui::IGUIElement *parent = NULL,
|
||||
s32 id = -1,
|
||||
bool fillBackground = false) {
|
||||
return addStaticText(guienv, EnrichedString(text), rectangle, border, wordWrap, parent, id, fillBackground);
|
||||
}
|
||||
|
||||
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const wchar_t *text)
|
||||
{
|
||||
setStaticText(static_text, EnrichedString(text));
|
||||
}
|
||||
|
||||
#endif // _IRR_COMPILE_WITH_GUI_
|
||||
|
||||
#endif // C_GUI_STATIC_TEXT_H_INCLUDED
|
357
src/mapgen.cpp
357
src/mapgen.cpp
|
@ -39,6 +39,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "util/numeric.h"
|
||||
#include "filesys.h"
|
||||
#include "log.h"
|
||||
#include "cavegen.h"
|
||||
#include "dungeongen.h"
|
||||
|
||||
FlagDesc flagdesc_mapgen[] = {
|
||||
{"trees", MG_TREES},
|
||||
|
@ -76,10 +78,9 @@ Mapgen::Mapgen()
|
|||
|
||||
vm = NULL;
|
||||
ndef = NULL;
|
||||
heightmap = NULL;
|
||||
biomegen = NULL;
|
||||
biomemap = NULL;
|
||||
heatmap = NULL;
|
||||
humidmap = NULL;
|
||||
heightmap = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,11 +95,10 @@ Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
|
|||
csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
|
||||
|
||||
vm = NULL;
|
||||
ndef = NULL;
|
||||
heightmap = NULL;
|
||||
ndef = emerge->ndef;
|
||||
biomegen = NULL;
|
||||
biomemap = NULL;
|
||||
heatmap = NULL;
|
||||
humidmap = NULL;
|
||||
heightmap = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -371,6 +371,323 @@ void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
|
|||
}
|
||||
|
||||
|
||||
////
|
||||
//// MapgenBasic
|
||||
////
|
||||
|
||||
MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||
: Mapgen(mapgenid, params, emerge)
|
||||
{
|
||||
this->m_emerge = emerge;
|
||||
this->m_bmgr = emerge->biomemgr;
|
||||
|
||||
//// Here, 'stride' refers to the number of elements needed to skip to index
|
||||
//// an adjacent element for that coordinate in noise/height/biome maps
|
||||
//// (*not* vmanip content map!)
|
||||
|
||||
// Note there is no X stride explicitly defined. Items adjacent in the X
|
||||
// coordinate are assumed to be adjacent in memory as well (i.e. stride of 1).
|
||||
|
||||
// Number of elements to skip to get to the next Y coordinate
|
||||
this->ystride = csize.X;
|
||||
|
||||
// Number of elements to skip to get to the next Z coordinate
|
||||
this->zstride = csize.X * csize.Y;
|
||||
|
||||
// Z-stride value for maps oversized for 1-down overgeneration
|
||||
this->zstride_1d = csize.X * (csize.Y + 1);
|
||||
|
||||
// Z-stride value for maps oversized for 1-up 1-down overgeneration
|
||||
this->zstride_1u1d = csize.X * (csize.Y + 2);
|
||||
|
||||
//// Allocate heightmap
|
||||
this->heightmap = new s16[csize.X * csize.Z];
|
||||
|
||||
//// Initialize biome generator
|
||||
// TODO(hmmmm): should we have a way to disable biomemanager biomes?
|
||||
biomegen = m_bmgr->createBiomeGen(BIOMEGEN_ORIGINAL, params->bparams, csize);
|
||||
biomemap = biomegen->biomemap;
|
||||
|
||||
//// Look up some commonly used content
|
||||
c_stone = ndef->getId("mapgen_stone");
|
||||
c_water_source = ndef->getId("mapgen_water_source");
|
||||
c_desert_stone = ndef->getId("mapgen_desert_stone");
|
||||
c_sandstone = ndef->getId("mapgen_sandstone");
|
||||
c_river_water_source = ndef->getId("mapgen_river_water_source");
|
||||
|
||||
// Fall back to more basic content if not defined
|
||||
if (c_desert_stone == CONTENT_IGNORE)
|
||||
c_desert_stone = c_stone;
|
||||
if (c_sandstone == CONTENT_IGNORE)
|
||||
c_sandstone = c_stone;
|
||||
if (c_river_water_source == CONTENT_IGNORE)
|
||||
c_river_water_source = c_water_source;
|
||||
|
||||
//// Content used for dungeon generation
|
||||
c_cobble = ndef->getId("mapgen_cobble");
|
||||
c_stair_cobble = ndef->getId("mapgen_stair_cobble");
|
||||
c_mossycobble = ndef->getId("mapgen_mossycobble");
|
||||
c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
|
||||
c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
|
||||
|
||||
// Fall back to more basic content if not defined
|
||||
if (c_mossycobble == CONTENT_IGNORE)
|
||||
c_mossycobble = c_cobble;
|
||||
if (c_stair_cobble == CONTENT_IGNORE)
|
||||
c_stair_cobble = c_cobble;
|
||||
if (c_sandstonebrick == CONTENT_IGNORE)
|
||||
c_sandstonebrick = c_sandstone;
|
||||
if (c_stair_sandstonebrick == CONTENT_IGNORE)
|
||||
c_stair_sandstonebrick = c_sandstone;
|
||||
}
|
||||
|
||||
|
||||
MapgenBasic::~MapgenBasic()
|
||||
{
|
||||
delete biomegen;
|
||||
delete []heightmap;
|
||||
}
|
||||
|
||||
|
||||
MgStoneType MapgenBasic::generateBiomes()
|
||||
{
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
MgStoneType stone_type = MGSTONE_STONE;
|
||||
|
||||
noise_filler_depth->perlinMap2D(node_min.X, node_min.Z);
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = NULL;
|
||||
u16 depth_top = 0;
|
||||
u16 base_filler = 0;
|
||||
u16 depth_water_top = 0;
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
|
||||
// Check node at base of mapchunk above, either a node of a previously
|
||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||
bool air_above = c_above == CONTENT_AIR;
|
||||
bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
|
||||
|
||||
// If there is air or water above enable top/filler placement, otherwise force
|
||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
||||
|
||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
|
||||
// Biome is recalculated each time an upper surface is detected while
|
||||
// working down a column. The selected biome then remains in effect for
|
||||
// all nodes below until the next surface and biome recalculation.
|
||||
// Biome is recalculated:
|
||||
// 1. At the surface of stone below air or water.
|
||||
// 2. At the surface of water below air.
|
||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
||||
if ((c == c_stone && (air_above || water_above || !biome))
|
||||
|| ((c == c_water_source || c == c_river_water_source)
|
||||
&& (air_above || !biome))) {
|
||||
biome = biomegen->getBiomeAtIndex(index, y);
|
||||
|
||||
depth_top = biome->depth_top;
|
||||
base_filler = MYMAX(depth_top
|
||||
+ biome->depth_filler
|
||||
+ noise_filler_depth->result[index], 0.f);
|
||||
depth_water_top = biome->depth_water_top;
|
||||
|
||||
// Detect stone type for dungeons during every biome calculation.
|
||||
// This is more efficient than detecting per-node and will not
|
||||
// miss any desert stone or sandstone biomes.
|
||||
if (biome->c_stone == c_desert_stone)
|
||||
stone_type = MGSTONE_DESERT_STONE;
|
||||
else if (biome->c_stone == c_sandstone)
|
||||
stone_type = MGSTONE_SANDSTONE;
|
||||
}
|
||||
|
||||
if (c == c_stone) {
|
||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
||||
|
||||
// If the node below isn't solid, make this node stone, so that
|
||||
// any top/filler nodes above are structurally supported.
|
||||
// This is done by aborting the cycle of top/filler placement
|
||||
// immediately by forcing nplaced to stone level.
|
||||
if (c_below == CONTENT_AIR
|
||||
|| c_below == c_water_source
|
||||
|| c_below == c_river_water_source)
|
||||
nplaced = U16_MAX;
|
||||
|
||||
if (nplaced < depth_top) {
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
nplaced++;
|
||||
} else if (nplaced < base_filler) {
|
||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
||||
nplaced++;
|
||||
} else {
|
||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
||||
}
|
||||
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
} else if (c == c_water_source) {
|
||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
|
||||
? biome->c_water_top : biome->c_water);
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = false;
|
||||
water_above = true;
|
||||
} else if (c == c_river_water_source) {
|
||||
vm->m_data[vi] = MapNode(biome->c_river_water);
|
||||
nplaced = depth_top; // Enable filler placement for next surface
|
||||
air_above = false;
|
||||
water_above = true;
|
||||
} else if (c == CONTENT_AIR) {
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = true;
|
||||
water_above = false;
|
||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
||||
nplaced = U16_MAX; // Disable top/filler placement
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
}
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return stone_type;
|
||||
}
|
||||
|
||||
|
||||
void MapgenBasic::dustTopNodes()
|
||||
{
|
||||
if (node_max.Y < water_level)
|
||||
return;
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index]);
|
||||
|
||||
if (biome->c_dust == CONTENT_IGNORE)
|
||||
continue;
|
||||
|
||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
||||
content_t c_full_max = vm->m_data[vi].getContent();
|
||||
s16 y_start;
|
||||
|
||||
if (c_full_max == CONTENT_AIR) {
|
||||
y_start = full_node_max.Y - 1;
|
||||
} else if (c_full_max == CONTENT_IGNORE) {
|
||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
||||
content_t c_max = vm->m_data[vi].getContent();
|
||||
|
||||
if (c_max == CONTENT_AIR)
|
||||
y_start = node_max.Y;
|
||||
else
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
vi = vm->m_area.index(x, y_start, z);
|
||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
||||
break;
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
||||
vm->m_area.add_y(em, vi, 1);
|
||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
|
||||
{
|
||||
if (max_stone_y < node_min.Y)
|
||||
return;
|
||||
|
||||
CavesNoiseIntersection caves_noise(ndef, m_bmgr, csize,
|
||||
&np_cave1, &np_cave2, seed, cave_width);
|
||||
|
||||
caves_noise.generateCaves(vm, node_min, node_max, biomemap);
|
||||
|
||||
if (node_max.Y > large_cave_depth)
|
||||
return;
|
||||
|
||||
PseudoRandom ps(blockseed + 21343);
|
||||
u32 bruises_count = ps.range(0, 2);
|
||||
for (u32 i = 0; i < bruises_count; i++) {
|
||||
CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
|
||||
c_water_source, CONTENT_IGNORE);
|
||||
|
||||
cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MapgenBasic::generateDungeons(s16 max_stone_y, MgStoneType stone_type)
|
||||
{
|
||||
if (max_stone_y < node_min.Y)
|
||||
return;
|
||||
|
||||
DungeonParams dp;
|
||||
|
||||
dp.seed = seed;
|
||||
|
||||
dp.np_rarity = nparams_dungeon_rarity;
|
||||
dp.np_density = nparams_dungeon_density;
|
||||
dp.np_wetness = nparams_dungeon_wetness;
|
||||
dp.c_water = c_water_source;
|
||||
|
||||
switch (stone_type) {
|
||||
default:
|
||||
case MGSTONE_STONE:
|
||||
dp.c_cobble = c_cobble;
|
||||
dp.c_moss = c_mossycobble;
|
||||
dp.c_stair = c_stair_cobble;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 3.0;
|
||||
dp.holesize = v3s16(1, 2, 1);
|
||||
dp.roomsize = v3s16(0, 0, 0);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
break;
|
||||
case MGSTONE_DESERT_STONE:
|
||||
dp.c_cobble = c_desert_stone;
|
||||
dp.c_moss = c_desert_stone;
|
||||
dp.c_stair = c_desert_stone;
|
||||
|
||||
dp.diagonal_dirs = true;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 3, 2);
|
||||
dp.roomsize = v3s16(2, 5, 2);
|
||||
dp.notifytype = GENNOTIFY_TEMPLE;
|
||||
break;
|
||||
case MGSTONE_SANDSTONE:
|
||||
dp.c_cobble = c_sandstonebrick;
|
||||
dp.c_moss = c_sandstonebrick;
|
||||
dp.c_stair = c_sandstonebrick;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 2, 2);
|
||||
dp.roomsize = v3s16(2, 0, 2);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
break;
|
||||
}
|
||||
|
||||
DungeonGen dgen(ndef, &gennotify, &dp);
|
||||
dgen.generate(vm, blockseed, full_node_min, full_node_max);
|
||||
}
|
||||
|
||||
|
||||
////
|
||||
//// GenerateNotifier
|
||||
////
|
||||
|
@ -444,6 +761,14 @@ void GenerateNotifier::getEvents(
|
|||
//// MapgenParams
|
||||
////
|
||||
|
||||
|
||||
MapgenParams::~MapgenParams()
|
||||
{
|
||||
delete bparams;
|
||||
delete sparams;
|
||||
}
|
||||
|
||||
|
||||
void MapgenParams::load(const Settings &settings)
|
||||
{
|
||||
std::string seed_str;
|
||||
|
@ -458,10 +783,13 @@ void MapgenParams::load(const Settings &settings)
|
|||
settings.getS16NoEx("water_level", water_level);
|
||||
settings.getS16NoEx("chunksize", chunksize);
|
||||
settings.getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
|
||||
settings.getNoiseParams("mg_biome_np_heat", np_biome_heat);
|
||||
settings.getNoiseParams("mg_biome_np_heat_blend", np_biome_heat_blend);
|
||||
settings.getNoiseParams("mg_biome_np_humidity", np_biome_humidity);
|
||||
settings.getNoiseParams("mg_biome_np_humidity_blend", np_biome_humidity_blend);
|
||||
|
||||
delete bparams;
|
||||
bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
|
||||
if (bparams) {
|
||||
bparams->readParams(&settings);
|
||||
bparams->seed = seed;
|
||||
}
|
||||
|
||||
delete sparams;
|
||||
MapgenFactory *mgfactory = EmergeManager::getMapgenFactory(mg_name);
|
||||
|
@ -479,10 +807,9 @@ void MapgenParams::save(Settings &settings) const
|
|||
settings.setS16("water_level", water_level);
|
||||
settings.setS16("chunksize", chunksize);
|
||||
settings.setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
|
||||
settings.setNoiseParams("mg_biome_np_heat", np_biome_heat);
|
||||
settings.setNoiseParams("mg_biome_np_heat_blend", np_biome_heat_blend);
|
||||
settings.setNoiseParams("mg_biome_np_humidity", np_biome_humidity);
|
||||
settings.setNoiseParams("mg_biome_np_humidity_blend", np_biome_humidity_blend);
|
||||
|
||||
if (bparams)
|
||||
bparams->writeParams(&settings);
|
||||
|
||||
if (sparams)
|
||||
sparams->writeParams(&settings);
|
||||
|
|
99
src/mapgen.h
99
src/mapgen.h
|
@ -44,6 +44,9 @@ extern FlagDesc flagdesc_mapgen[];
|
|||
extern FlagDesc flagdesc_gennotify[];
|
||||
|
||||
class Biome;
|
||||
class BiomeGen;
|
||||
struct BiomeParams;
|
||||
class BiomeManager;
|
||||
class EmergeManager;
|
||||
class MapBlock;
|
||||
class VoxelManipulator;
|
||||
|
@ -73,9 +76,9 @@ enum GenNotifyType {
|
|||
|
||||
// TODO(hmmmm/paramat): make stone type selection dynamic
|
||||
enum MgStoneType {
|
||||
STONE,
|
||||
DESERT_STONE,
|
||||
SANDSTONE,
|
||||
MGSTONE_STONE,
|
||||
MGSTONE_DESERT_STONE,
|
||||
MGSTONE_SANDSTONE,
|
||||
};
|
||||
|
||||
struct GenNotifyEvent {
|
||||
|
@ -115,11 +118,7 @@ struct MapgenParams {
|
|||
s16 water_level;
|
||||
u32 flags;
|
||||
|
||||
NoiseParams np_biome_heat;
|
||||
NoiseParams np_biome_heat_blend;
|
||||
NoiseParams np_biome_humidity;
|
||||
NoiseParams np_biome_humidity_blend;
|
||||
|
||||
BiomeParams *bparams;
|
||||
MapgenSpecificParams *sparams;
|
||||
|
||||
MapgenParams() :
|
||||
|
@ -128,17 +127,27 @@ struct MapgenParams {
|
|||
seed(0),
|
||||
water_level(1),
|
||||
flags(MG_CAVES | MG_LIGHT | MG_DECORATIONS),
|
||||
np_biome_heat(NoiseParams(50, 50, v3f(750.0, 750.0, 750.0), 5349, 3, 0.5, 2.0)),
|
||||
np_biome_heat_blend(NoiseParams(0, 1.5, v3f(8.0, 8.0, 8.0), 13, 2, 1.0, 2.0)),
|
||||
np_biome_humidity(NoiseParams(50, 50, v3f(750.0, 750.0, 750.0), 842, 3, 0.5, 2.0)),
|
||||
np_biome_humidity_blend(NoiseParams(0, 1.5, v3f(8.0, 8.0, 8.0), 90003, 2, 1.0, 2.0)),
|
||||
bparams(NULL),
|
||||
sparams(NULL)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MapgenParams();
|
||||
|
||||
void load(const Settings &settings);
|
||||
void save(Settings &settings) const;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Generic interface for map generators. All mapgens must inherit this class.
|
||||
If a feature exposed by a public member pointer is not supported by a
|
||||
certain mapgen, it must be set to NULL.
|
||||
|
||||
Apart from makeChunk, getGroundLevelAtPoint, and getSpawnLevelAtPoint, all
|
||||
methods can be used by constructing a Mapgen base class and setting the
|
||||
appropriate public members (e.g. vm, ndef, and so on).
|
||||
*/
|
||||
class Mapgen {
|
||||
public:
|
||||
int seed;
|
||||
|
@ -153,10 +162,9 @@ public:
|
|||
u32 blockseed;
|
||||
s16 *heightmap;
|
||||
u8 *biomemap;
|
||||
float *heatmap;
|
||||
float *humidmap;
|
||||
v3s16 csize;
|
||||
|
||||
BiomeGen *biomegen;
|
||||
GenerateNotifier gennotify;
|
||||
|
||||
Mapgen();
|
||||
|
@ -192,6 +200,67 @@ private:
|
|||
//DISABLE_CLASS_COPY(Mapgen);
|
||||
};
|
||||
|
||||
/*
|
||||
MapgenBasic is a Mapgen implementation that handles basic functionality
|
||||
the majority of conventional mapgens will probably want to use, but isn't
|
||||
generic enough to be included as part of the base Mapgen class (such as
|
||||
generating biome terrain over terrain node skeletons, generating caves,
|
||||
dungeons, etc.)
|
||||
|
||||
Inherit MapgenBasic instead of Mapgen to add this basic functionality to
|
||||
your mapgen without having to reimplement it. Feel free to override any of
|
||||
these methods if you desire different or more advanced behavior.
|
||||
|
||||
Note that you must still create your own generateTerrain implementation when
|
||||
inheriting MapgenBasic.
|
||||
*/
|
||||
class MapgenBasic : public Mapgen {
|
||||
public:
|
||||
MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||
virtual ~MapgenBasic();
|
||||
|
||||
virtual void generateCaves(s16 max_stone_y, s16 large_cave_depth);
|
||||
virtual void generateDungeons(s16 max_stone_y, MgStoneType stone_type);
|
||||
virtual MgStoneType generateBiomes();
|
||||
virtual void dustTopNodes();
|
||||
|
||||
protected:
|
||||
EmergeManager *m_emerge;
|
||||
BiomeManager *m_bmgr;
|
||||
|
||||
Noise *noise_filler_depth;
|
||||
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
v3s16 full_node_min;
|
||||
v3s16 full_node_max;
|
||||
|
||||
// Content required for generateBiomes
|
||||
content_t c_stone;
|
||||
content_t c_water_source;
|
||||
content_t c_river_water_source;
|
||||
content_t c_desert_stone;
|
||||
content_t c_sandstone;
|
||||
|
||||
// Content required for generateDungeons
|
||||
content_t c_cobble;
|
||||
content_t c_stair_cobble;
|
||||
content_t c_mossycobble;
|
||||
content_t c_sandstonebrick;
|
||||
content_t c_stair_sandstonebrick;
|
||||
|
||||
int ystride;
|
||||
int zstride;
|
||||
int zstride_1d;
|
||||
int zstride_1u1d;
|
||||
|
||||
u32 spflags;
|
||||
|
||||
NoiseParams np_cave1;
|
||||
NoiseParams np_cave2;
|
||||
float cave_width;
|
||||
};
|
||||
|
||||
struct MapgenFactory {
|
||||
virtual Mapgen *createMapgen(int mgid, MapgenParams *params,
|
||||
EmergeManager *emerge) = 0;
|
||||
|
|
|
@ -50,22 +50,8 @@ FlagDesc flagdesc_mapgen_flat[] = {
|
|||
|
||||
|
||||
MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||
: Mapgen(mapgenid, params, emerge)
|
||||
: MapgenBasic(mapgenid, params, emerge)
|
||||
{
|
||||
this->m_emerge = emerge;
|
||||
this->bmgr = emerge->biomemgr;
|
||||
|
||||
//// amount of elements to skip for the next index
|
||||
//// for noise/height/biome maps (not vmanip)
|
||||
this->ystride = csize.X;
|
||||
// 1-down overgeneration
|
||||
this->zstride_1d = csize.X * (csize.Y + 1);
|
||||
|
||||
this->biomemap = new u8[csize.X * csize.Z];
|
||||
this->heightmap = new s16[csize.X * csize.Z];
|
||||
this->heatmap = NULL;
|
||||
this->humidmap = NULL;
|
||||
|
||||
MapgenFlatParams *sp = (MapgenFlatParams *)params->sparams;
|
||||
|
||||
this->spflags = sp->spflags;
|
||||
|
@ -81,43 +67,8 @@ MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge
|
|||
noise_terrain = new Noise(&sp->np_terrain, seed, csize.X, csize.Z);
|
||||
noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
|
||||
|
||||
//// 3D noise
|
||||
// 1-down overgeneraion
|
||||
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
|
||||
//// Biome noise
|
||||
noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z);
|
||||
noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z);
|
||||
noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z);
|
||||
noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z);
|
||||
|
||||
//// Resolve nodes to be used
|
||||
INodeDefManager *ndef = emerge->ndef;
|
||||
|
||||
c_stone = ndef->getId("mapgen_stone");
|
||||
c_water_source = ndef->getId("mapgen_water_source");
|
||||
c_lava_source = ndef->getId("mapgen_lava_source");
|
||||
c_desert_stone = ndef->getId("mapgen_desert_stone");
|
||||
c_ice = ndef->getId("mapgen_ice");
|
||||
c_sandstone = ndef->getId("mapgen_sandstone");
|
||||
|
||||
c_cobble = ndef->getId("mapgen_cobble");
|
||||
c_stair_cobble = ndef->getId("mapgen_stair_cobble");
|
||||
c_mossycobble = ndef->getId("mapgen_mossycobble");
|
||||
c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
|
||||
c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
|
||||
|
||||
if (c_ice == CONTENT_IGNORE)
|
||||
c_ice = CONTENT_AIR;
|
||||
if (c_mossycobble == CONTENT_IGNORE)
|
||||
c_mossycobble = c_cobble;
|
||||
if (c_stair_cobble == CONTENT_IGNORE)
|
||||
c_stair_cobble = c_cobble;
|
||||
if (c_sandstonebrick == CONTENT_IGNORE)
|
||||
c_sandstonebrick = c_sandstone;
|
||||
if (c_stair_sandstonebrick == CONTENT_IGNORE)
|
||||
c_stair_sandstonebrick = c_sandstone;
|
||||
MapgenBasic::np_cave1 = sp->np_cave1;
|
||||
MapgenBasic::np_cave2 = sp->np_cave2;
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,16 +76,6 @@ MapgenFlat::~MapgenFlat()
|
|||
{
|
||||
delete noise_terrain;
|
||||
delete noise_filler_depth;
|
||||
delete noise_cave1;
|
||||
delete noise_cave2;
|
||||
|
||||
delete noise_heat;
|
||||
delete noise_humidity;
|
||||
delete noise_heat_blend;
|
||||
delete noise_humidity_blend;
|
||||
|
||||
delete[] heightmap;
|
||||
delete[] biomemap;
|
||||
}
|
||||
|
||||
|
||||
|
@ -243,67 +184,22 @@ void MapgenFlat::makeChunk(BlockMakeData *data)
|
|||
|
||||
blockseed = getBlockSeed2(full_node_min, seed);
|
||||
|
||||
// Make some noise
|
||||
calculateNoise();
|
||||
|
||||
// Generate base terrain, mountains, and ridges with initial heightmaps
|
||||
s16 stone_surface_max_y = generateTerrain();
|
||||
|
||||
// Create heightmap
|
||||
updateHeightmap(node_min, node_max);
|
||||
|
||||
// Create biomemap at heightmap surface
|
||||
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result,
|
||||
noise_humidity->result, heightmap, biomemap);
|
||||
|
||||
// Actually place the biome-specific nodes
|
||||
MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
|
||||
// Init biome generator, place biome-specific nodes, and build biomemap
|
||||
biomegen->calcBiomeNoise(node_min);
|
||||
biomegen->getBiomes(heightmap);
|
||||
MgStoneType stone_type = generateBiomes();
|
||||
|
||||
if (flags & MG_CAVES)
|
||||
generateCaves(stone_surface_max_y);
|
||||
generateCaves(stone_surface_max_y, large_cave_depth);
|
||||
|
||||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||
DungeonParams dp;
|
||||
|
||||
dp.np_rarity = nparams_dungeon_rarity;
|
||||
dp.np_density = nparams_dungeon_density;
|
||||
dp.np_wetness = nparams_dungeon_wetness;
|
||||
dp.c_water = c_water_source;
|
||||
if (stone_type == STONE) {
|
||||
dp.c_cobble = c_cobble;
|
||||
dp.c_moss = c_mossycobble;
|
||||
dp.c_stair = c_stair_cobble;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 3.0;
|
||||
dp.holesize = v3s16(1, 2, 1);
|
||||
dp.roomsize = v3s16(0, 0, 0);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
} else if (stone_type == DESERT_STONE) {
|
||||
dp.c_cobble = c_desert_stone;
|
||||
dp.c_moss = c_desert_stone;
|
||||
dp.c_stair = c_desert_stone;
|
||||
|
||||
dp.diagonal_dirs = true;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 3, 2);
|
||||
dp.roomsize = v3s16(2, 5, 2);
|
||||
dp.notifytype = GENNOTIFY_TEMPLE;
|
||||
} else if (stone_type == SANDSTONE) {
|
||||
dp.c_cobble = c_sandstonebrick;
|
||||
dp.c_moss = c_sandstonebrick;
|
||||
dp.c_stair = c_sandstonebrick;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 2, 2);
|
||||
dp.roomsize = v3s16(2, 0, 2);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
}
|
||||
|
||||
DungeonGen dgen(this, &dp);
|
||||
dgen.generate(blockseed, full_node_min, full_node_max);
|
||||
}
|
||||
if (flags & MG_DUNGEONS)
|
||||
generateDungeons(stone_surface_max_y, stone_type);
|
||||
|
||||
// Generate the registered decorations
|
||||
if (flags & MG_DECORATIONS)
|
||||
|
@ -330,35 +226,6 @@ void MapgenFlat::makeChunk(BlockMakeData *data)
|
|||
}
|
||||
|
||||
|
||||
void MapgenFlat::calculateNoise()
|
||||
{
|
||||
//TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
|
||||
s16 x = node_min.X;
|
||||
s16 z = node_min.Z;
|
||||
|
||||
if ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS))
|
||||
noise_terrain->perlinMap2D(x, z);
|
||||
|
||||
// Cave noises are calculated in generateCaves()
|
||||
// only if solid terrain is present in mapchunk
|
||||
|
||||
noise_filler_depth->perlinMap2D(x, z);
|
||||
noise_heat->perlinMap2D(x, z);
|
||||
noise_humidity->perlinMap2D(x, z);
|
||||
noise_heat_blend->perlinMap2D(x, z);
|
||||
noise_humidity_blend->perlinMap2D(x, z);
|
||||
|
||||
for (s32 i = 0; i < csize.X * csize.Z; i++) {
|
||||
noise_heat->result[i] += noise_heat_blend->result[i];
|
||||
noise_humidity->result[i] += noise_humidity_blend->result[i];
|
||||
}
|
||||
|
||||
heatmap = noise_heat->result;
|
||||
humidmap = noise_humidity->result;
|
||||
//printf("calculateNoise: %dus\n", t.stop());
|
||||
}
|
||||
|
||||
|
||||
s16 MapgenFlat::generateTerrain()
|
||||
{
|
||||
MapNode n_air(CONTENT_AIR);
|
||||
|
@ -369,13 +236,14 @@ s16 MapgenFlat::generateTerrain()
|
|||
s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
|
||||
u32 ni2d = 0;
|
||||
|
||||
bool use_noise = (spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS);
|
||||
if (use_noise)
|
||||
noise_terrain->perlinMap2D(node_min.X, node_min.Z);
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, ni2d++) {
|
||||
s16 stone_level = ground_level;
|
||||
float n_terrain = 0.0f;
|
||||
|
||||
if ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS))
|
||||
n_terrain = noise_terrain->result[ni2d];
|
||||
float n_terrain = use_noise ? noise_terrain->result[ni2d] : 0.0f;
|
||||
|
||||
if ((spflags & MGFLAT_LAKES) && n_terrain < lake_threshold) {
|
||||
s16 depress = (lake_threshold - n_terrain) * lake_steepness;
|
||||
|
@ -404,219 +272,3 @@ s16 MapgenFlat::generateTerrain()
|
|||
|
||||
return stone_surface_max_y;
|
||||
}
|
||||
|
||||
|
||||
MgStoneType MapgenFlat::generateBiomes(float *heat_map, float *humidity_map)
|
||||
{
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
MgStoneType stone_type = STONE;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = NULL;
|
||||
u16 depth_top = 0;
|
||||
u16 base_filler = 0;
|
||||
u16 depth_water_top = 0;
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
|
||||
// Check node at base of mapchunk above, either a node of a previously
|
||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||
bool air_above = c_above == CONTENT_AIR;
|
||||
bool water_above = c_above == c_water_source;
|
||||
|
||||
// If there is air or water above enable top/filler placement, otherwise force
|
||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
||||
|
||||
|
||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
|
||||
// Biome is recalculated each time an upper surface is detected while
|
||||
// working down a column. The selected biome then remains in effect for
|
||||
// all nodes below until the next surface and biome recalculation.
|
||||
// Biome is recalculated:
|
||||
// 1. At the surface of stone below air or water.
|
||||
// 2. At the surface of water below air.
|
||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
||||
if ((c == c_stone && (air_above || water_above || !biome)) ||
|
||||
(c == c_water_source && (air_above || !biome))) {
|
||||
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
|
||||
depth_top = biome->depth_top;
|
||||
base_filler = MYMAX(depth_top + biome->depth_filler
|
||||
+ noise_filler_depth->result[index], 0);
|
||||
depth_water_top = biome->depth_water_top;
|
||||
|
||||
// Detect stone type for dungeons during every biome calculation.
|
||||
// This is more efficient than detecting per-node and will not
|
||||
// miss any desert stone or sandstone biomes.
|
||||
if (biome->c_stone == c_desert_stone)
|
||||
stone_type = DESERT_STONE;
|
||||
else if (biome->c_stone == c_sandstone)
|
||||
stone_type = SANDSTONE;
|
||||
}
|
||||
|
||||
if (c == c_stone) {
|
||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
||||
|
||||
// If the node below isn't solid, make this node stone, so that
|
||||
// any top/filler nodes above are structurally supported.
|
||||
// This is done by aborting the cycle of top/filler placement
|
||||
// immediately by forcing nplaced to stone level.
|
||||
if (c_below == CONTENT_AIR || c_below == c_water_source)
|
||||
nplaced = U16_MAX;
|
||||
|
||||
if (nplaced < depth_top) {
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
nplaced++;
|
||||
} else if (nplaced < base_filler) {
|
||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
||||
nplaced++;
|
||||
} else {
|
||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
||||
}
|
||||
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
} else if (c == c_water_source) {
|
||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
|
||||
biome->c_water_top : biome->c_water);
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = false;
|
||||
water_above = true;
|
||||
} else if (c == CONTENT_AIR) {
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = true;
|
||||
water_above = false;
|
||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
||||
nplaced = U16_MAX; // Disable top/filler placement
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
}
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return stone_type;
|
||||
}
|
||||
|
||||
|
||||
void MapgenFlat::dustTopNodes()
|
||||
{
|
||||
if (node_max.Y < water_level)
|
||||
return;
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
||||
|
||||
if (biome->c_dust == CONTENT_IGNORE)
|
||||
continue;
|
||||
|
||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
||||
content_t c_full_max = vm->m_data[vi].getContent();
|
||||
s16 y_start;
|
||||
|
||||
if (c_full_max == CONTENT_AIR) {
|
||||
y_start = full_node_max.Y - 1;
|
||||
} else if (c_full_max == CONTENT_IGNORE) {
|
||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
||||
content_t c_max = vm->m_data[vi].getContent();
|
||||
|
||||
if (c_max == CONTENT_AIR)
|
||||
y_start = node_max.Y;
|
||||
else
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
vi = vm->m_area.index(x, y_start, z);
|
||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
||||
break;
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
||||
vm->m_area.add_y(em, vi, 1);
|
||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MapgenFlat::generateCaves(s16 max_stone_y)
|
||||
{
|
||||
if (max_stone_y < node_min.Y)
|
||||
return;
|
||||
|
||||
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index2d = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
||||
bool column_is_open = false; // Is column open to overground
|
||||
bool is_tunnel = false; // Is tunnel or tunnel floor
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
||||
(x - node_min.X);
|
||||
// Biome of column
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
||||
|
||||
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
||||
// this creates a 'roof' over the tunnel, preventing light in
|
||||
// tunnels at mapchunk borders when generating mapchunks upwards.
|
||||
// This 'roof' is removed when the mapchunk above is generated.
|
||||
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
||||
index3d -= ystride,
|
||||
vm->m_area.add_y(em, vi, -1)) {
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
||||
c == biome->c_water) {
|
||||
column_is_open = true;
|
||||
continue;
|
||||
}
|
||||
// Ground
|
||||
float d1 = contour(noise_cave1->result[index3d]);
|
||||
float d2 = contour(noise_cave2->result[index3d]);
|
||||
|
||||
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
||||
// In tunnel and ground content, excavate
|
||||
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
||||
is_tunnel = true;
|
||||
} else {
|
||||
// Not in tunnel or not ground content
|
||||
if (is_tunnel && column_is_open &&
|
||||
(c == biome->c_filler || c == biome->c_stone))
|
||||
// Tunnel entrance floor
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
|
||||
column_is_open = false;
|
||||
is_tunnel = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node_max.Y > large_cave_depth)
|
||||
return;
|
||||
|
||||
PseudoRandom ps(blockseed + 21343);
|
||||
u32 bruises_count = ps.range(0, 2);
|
||||
for (u32 i = 0; i < bruises_count; i++) {
|
||||
CaveV5 cave(this, &ps);
|
||||
cave.makeCave(node_min, node_max, max_stone_y);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,60 +53,23 @@ struct MapgenFlatParams : public MapgenSpecificParams {
|
|||
void writeParams(Settings *settings) const;
|
||||
};
|
||||
|
||||
class MapgenFlat : public Mapgen {
|
||||
class MapgenFlat : public MapgenBasic {
|
||||
public:
|
||||
EmergeManager *m_emerge;
|
||||
BiomeManager *bmgr;
|
||||
|
||||
int ystride;
|
||||
int zstride_1d;
|
||||
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
v3s16 full_node_min;
|
||||
v3s16 full_node_max;
|
||||
|
||||
u32 spflags;
|
||||
s16 ground_level;
|
||||
s16 large_cave_depth;
|
||||
float cave_width;
|
||||
float lake_threshold;
|
||||
float lake_steepness;
|
||||
float hill_threshold;
|
||||
float hill_steepness;
|
||||
Noise *noise_terrain;
|
||||
Noise *noise_filler_depth;
|
||||
Noise *noise_cave1;
|
||||
Noise *noise_cave2;
|
||||
|
||||
Noise *noise_heat;
|
||||
Noise *noise_humidity;
|
||||
Noise *noise_heat_blend;
|
||||
Noise *noise_humidity_blend;
|
||||
|
||||
content_t c_stone;
|
||||
content_t c_water_source;
|
||||
content_t c_lava_source;
|
||||
content_t c_desert_stone;
|
||||
content_t c_ice;
|
||||
content_t c_sandstone;
|
||||
|
||||
content_t c_cobble;
|
||||
content_t c_stair_cobble;
|
||||
content_t c_mossycobble;
|
||||
content_t c_sandstonebrick;
|
||||
content_t c_stair_sandstonebrick;
|
||||
|
||||
MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||
~MapgenFlat();
|
||||
|
||||
virtual void makeChunk(BlockMakeData *data);
|
||||
int getSpawnLevelAtPoint(v2s16 p);
|
||||
void calculateNoise();
|
||||
s16 generateTerrain();
|
||||
MgStoneType generateBiomes(float *heat_map, float *humidity_map);
|
||||
void dustTopNodes();
|
||||
void generateCaves(s16 max_stone_y);
|
||||
|
||||
private:
|
||||
s16 ground_level;
|
||||
s16 large_cave_depth;
|
||||
float lake_threshold;
|
||||
float lake_steepness;
|
||||
float hill_threshold;
|
||||
float hill_steepness;
|
||||
Noise *noise_terrain;
|
||||
};
|
||||
|
||||
struct MapgenFactoryFlat : public MapgenFactory {
|
||||
|
|
|
@ -48,22 +48,8 @@ FlagDesc flagdesc_mapgen_fractal[] = {
|
|||
|
||||
|
||||
MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||
: Mapgen(mapgenid, params, emerge)
|
||||
: MapgenBasic(mapgenid, params, emerge)
|
||||
{
|
||||
this->m_emerge = emerge;
|
||||
this->bmgr = emerge->biomemgr;
|
||||
|
||||
//// amount of elements to skip for the next index
|
||||
//// for noise/height/biome maps (not vmanip)
|
||||
this->ystride = csize.X;
|
||||
// 1-down overgeneration
|
||||
this->zstride_1d = csize.X * (csize.Y + 1);
|
||||
|
||||
this->biomemap = new u8[csize.X * csize.Z];
|
||||
this->heightmap = new s16[csize.X * csize.Z];
|
||||
this->heatmap = NULL;
|
||||
this->humidmap = NULL;
|
||||
|
||||
MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams;
|
||||
|
||||
this->spflags = sp->spflags;
|
||||
|
@ -82,46 +68,11 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *
|
|||
noise_seabed = new Noise(&sp->np_seabed, seed, csize.X, csize.Z);
|
||||
noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
|
||||
|
||||
//// 3D terrain noise
|
||||
// 1-down overgeneraion
|
||||
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
|
||||
//// Biome noise
|
||||
noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z);
|
||||
noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z);
|
||||
noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z);
|
||||
noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z);
|
||||
MapgenBasic::np_cave1 = sp->np_cave1;
|
||||
MapgenBasic::np_cave2 = sp->np_cave2;
|
||||
|
||||
this->formula = fractal / 2 + fractal % 2;
|
||||
this->julia = fractal % 2 == 0;
|
||||
|
||||
//// Resolve nodes to be used
|
||||
INodeDefManager *ndef = emerge->ndef;
|
||||
|
||||
c_stone = ndef->getId("mapgen_stone");
|
||||
c_water_source = ndef->getId("mapgen_water_source");
|
||||
c_lava_source = ndef->getId("mapgen_lava_source");
|
||||
c_desert_stone = ndef->getId("mapgen_desert_stone");
|
||||
c_ice = ndef->getId("mapgen_ice");
|
||||
c_sandstone = ndef->getId("mapgen_sandstone");
|
||||
|
||||
c_cobble = ndef->getId("mapgen_cobble");
|
||||
c_stair_cobble = ndef->getId("mapgen_stair_cobble");
|
||||
c_mossycobble = ndef->getId("mapgen_mossycobble");
|
||||
c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
|
||||
c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
|
||||
|
||||
if (c_ice == CONTENT_IGNORE)
|
||||
c_ice = CONTENT_AIR;
|
||||
if (c_mossycobble == CONTENT_IGNORE)
|
||||
c_mossycobble = c_cobble;
|
||||
if (c_stair_cobble == CONTENT_IGNORE)
|
||||
c_stair_cobble = c_cobble;
|
||||
if (c_sandstonebrick == CONTENT_IGNORE)
|
||||
c_sandstonebrick = c_sandstone;
|
||||
if (c_stair_sandstonebrick == CONTENT_IGNORE)
|
||||
c_stair_sandstonebrick = c_sandstone;
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,16 +80,6 @@ MapgenFractal::~MapgenFractal()
|
|||
{
|
||||
delete noise_seabed;
|
||||
delete noise_filler_depth;
|
||||
delete noise_cave1;
|
||||
delete noise_cave2;
|
||||
|
||||
delete noise_heat;
|
||||
delete noise_humidity;
|
||||
delete noise_heat_blend;
|
||||
delete noise_humidity_blend;
|
||||
|
||||
delete[] heightmap;
|
||||
delete[] biomemap;
|
||||
}
|
||||
|
||||
|
||||
|
@ -217,7 +158,7 @@ int MapgenFractal::getSpawnLevelAtPoint(v2s16 p)
|
|||
s16 search_start = MYMAX(seabed_level, water_level + 1);
|
||||
if (seabed_level > water_level)
|
||||
solid_below = true;
|
||||
|
||||
|
||||
for (s16 y = search_start; y <= search_start + 128; y++) {
|
||||
if (getFractalAtPoint(p.X, y, p.Y)) { // Fractal node
|
||||
solid_below = true;
|
||||
|
@ -259,67 +200,22 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
|
|||
|
||||
blockseed = getBlockSeed2(full_node_min, seed);
|
||||
|
||||
// Make some noise
|
||||
calculateNoise();
|
||||
|
||||
// Generate base terrain, mountains, and ridges with initial heightmaps
|
||||
s16 stone_surface_max_y = generateTerrain();
|
||||
|
||||
// Create heightmap
|
||||
updateHeightmap(node_min, node_max);
|
||||
|
||||
// Create biomemap at heightmap surface
|
||||
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result,
|
||||
noise_humidity->result, heightmap, biomemap);
|
||||
|
||||
// Actually place the biome-specific nodes
|
||||
MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
|
||||
// Init biome generator, place biome-specific nodes, and build biomemap
|
||||
biomegen->calcBiomeNoise(node_min);
|
||||
biomegen->getBiomes(heightmap);
|
||||
MgStoneType stone_type = generateBiomes();
|
||||
|
||||
if (flags & MG_CAVES)
|
||||
generateCaves(stone_surface_max_y);
|
||||
generateCaves(stone_surface_max_y, MGFRACTAL_LARGE_CAVE_DEPTH);
|
||||
|
||||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||
DungeonParams dp;
|
||||
|
||||
dp.np_rarity = nparams_dungeon_rarity;
|
||||
dp.np_density = nparams_dungeon_density;
|
||||
dp.np_wetness = nparams_dungeon_wetness;
|
||||
dp.c_water = c_water_source;
|
||||
if (stone_type == STONE) {
|
||||
dp.c_cobble = c_cobble;
|
||||
dp.c_moss = c_mossycobble;
|
||||
dp.c_stair = c_stair_cobble;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 3.0;
|
||||
dp.holesize = v3s16(1, 2, 1);
|
||||
dp.roomsize = v3s16(0, 0, 0);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
} else if (stone_type == DESERT_STONE) {
|
||||
dp.c_cobble = c_desert_stone;
|
||||
dp.c_moss = c_desert_stone;
|
||||
dp.c_stair = c_desert_stone;
|
||||
|
||||
dp.diagonal_dirs = true;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 3, 2);
|
||||
dp.roomsize = v3s16(2, 5, 2);
|
||||
dp.notifytype = GENNOTIFY_TEMPLE;
|
||||
} else if (stone_type == SANDSTONE) {
|
||||
dp.c_cobble = c_sandstonebrick;
|
||||
dp.c_moss = c_sandstonebrick;
|
||||
dp.c_stair = c_sandstonebrick;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 2, 2);
|
||||
dp.roomsize = v3s16(2, 0, 2);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
}
|
||||
|
||||
DungeonGen dgen(this, &dp);
|
||||
dgen.generate(blockseed, full_node_min, full_node_max);
|
||||
}
|
||||
if (flags & MG_DUNGEONS)
|
||||
generateDungeons(stone_surface_max_y, stone_type);
|
||||
|
||||
// Generate the registered decorations
|
||||
if (flags & MG_DECORATIONS)
|
||||
|
@ -346,34 +242,6 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
|
|||
}
|
||||
|
||||
|
||||
void MapgenFractal::calculateNoise()
|
||||
{
|
||||
//TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
|
||||
s16 x = node_min.X;
|
||||
s16 z = node_min.Z;
|
||||
|
||||
noise_seabed->perlinMap2D(x, z);
|
||||
|
||||
// Cave noises are calculated in generateCaves()
|
||||
// only if solid terrain is present in mapchunk
|
||||
|
||||
noise_filler_depth->perlinMap2D(x, z);
|
||||
noise_heat->perlinMap2D(x, z);
|
||||
noise_humidity->perlinMap2D(x, z);
|
||||
noise_heat_blend->perlinMap2D(x, z);
|
||||
noise_humidity_blend->perlinMap2D(x, z);
|
||||
|
||||
for (s32 i = 0; i < csize.X * csize.Z; i++) {
|
||||
noise_heat->result[i] += noise_heat_blend->result[i];
|
||||
noise_humidity->result[i] += noise_humidity_blend->result[i];
|
||||
}
|
||||
|
||||
heatmap = noise_heat->result;
|
||||
humidmap = noise_humidity->result;
|
||||
//printf("calculateNoise: %dus\n", t.stop());
|
||||
}
|
||||
|
||||
|
||||
bool MapgenFractal::getFractalAtPoint(s16 x, s16 y, s16 z)
|
||||
{
|
||||
float cx, cy, cz, cw, ox, oy, oz, ow;
|
||||
|
@ -503,6 +371,8 @@ s16 MapgenFractal::generateTerrain()
|
|||
s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
|
||||
u32 index2d = 0;
|
||||
|
||||
noise_seabed->perlinMap2D(node_min.X, node_min.Z);
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++) {
|
||||
for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
|
||||
u32 vi = vm->m_area.index(node_min.X, y, z);
|
||||
|
@ -528,219 +398,3 @@ s16 MapgenFractal::generateTerrain()
|
|||
|
||||
return stone_surface_max_y;
|
||||
}
|
||||
|
||||
|
||||
MgStoneType MapgenFractal::generateBiomes(float *heat_map, float *humidity_map)
|
||||
{
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
MgStoneType stone_type = STONE;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = NULL;
|
||||
u16 depth_top = 0;
|
||||
u16 base_filler = 0;
|
||||
u16 depth_water_top = 0;
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
|
||||
// Check node at base of mapchunk above, either a node of a previously
|
||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||
bool air_above = c_above == CONTENT_AIR;
|
||||
bool water_above = c_above == c_water_source;
|
||||
|
||||
// If there is air or water above enable top/filler placement, otherwise force
|
||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
||||
|
||||
|
||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
|
||||
// Biome is recalculated each time an upper surface is detected while
|
||||
// working down a column. The selected biome then remains in effect for
|
||||
// all nodes below until the next surface and biome recalculation.
|
||||
// Biome is recalculated:
|
||||
// 1. At the surface of stone below air or water.
|
||||
// 2. At the surface of water below air.
|
||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
||||
if ((c == c_stone && (air_above || water_above || !biome)) ||
|
||||
(c == c_water_source && (air_above || !biome))) {
|
||||
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
|
||||
depth_top = biome->depth_top;
|
||||
base_filler = MYMAX(depth_top + biome->depth_filler
|
||||
+ noise_filler_depth->result[index], 0);
|
||||
depth_water_top = biome->depth_water_top;
|
||||
|
||||
// Detect stone type for dungeons during every biome calculation.
|
||||
// This is more efficient than detecting per-node and will not
|
||||
// miss any desert stone or sandstone biomes.
|
||||
if (biome->c_stone == c_desert_stone)
|
||||
stone_type = DESERT_STONE;
|
||||
else if (biome->c_stone == c_sandstone)
|
||||
stone_type = SANDSTONE;
|
||||
}
|
||||
|
||||
if (c == c_stone) {
|
||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
||||
|
||||
// If the node below isn't solid, make this node stone, so that
|
||||
// any top/filler nodes above are structurally supported.
|
||||
// This is done by aborting the cycle of top/filler placement
|
||||
// immediately by forcing nplaced to stone level.
|
||||
if (c_below == CONTENT_AIR || c_below == c_water_source)
|
||||
nplaced = U16_MAX;
|
||||
|
||||
if (nplaced < depth_top) {
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
nplaced++;
|
||||
} else if (nplaced < base_filler) {
|
||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
||||
nplaced++;
|
||||
} else {
|
||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
||||
}
|
||||
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
} else if (c == c_water_source) {
|
||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
|
||||
biome->c_water_top : biome->c_water);
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = false;
|
||||
water_above = true;
|
||||
} else if (c == CONTENT_AIR) {
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = true;
|
||||
water_above = false;
|
||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
||||
nplaced = U16_MAX; // Disable top/filler placement
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
}
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return stone_type;
|
||||
}
|
||||
|
||||
|
||||
void MapgenFractal::dustTopNodes()
|
||||
{
|
||||
if (node_max.Y < water_level)
|
||||
return;
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
||||
|
||||
if (biome->c_dust == CONTENT_IGNORE)
|
||||
continue;
|
||||
|
||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
||||
content_t c_full_max = vm->m_data[vi].getContent();
|
||||
s16 y_start;
|
||||
|
||||
if (c_full_max == CONTENT_AIR) {
|
||||
y_start = full_node_max.Y - 1;
|
||||
} else if (c_full_max == CONTENT_IGNORE) {
|
||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
||||
content_t c_max = vm->m_data[vi].getContent();
|
||||
|
||||
if (c_max == CONTENT_AIR)
|
||||
y_start = node_max.Y;
|
||||
else
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
vi = vm->m_area.index(x, y_start, z);
|
||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
||||
break;
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
||||
vm->m_area.add_y(em, vi, 1);
|
||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MapgenFractal::generateCaves(s16 max_stone_y)
|
||||
{
|
||||
if (max_stone_y < node_min.Y)
|
||||
return;
|
||||
|
||||
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index2d = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
||||
bool column_is_open = false; // Is column open to overground
|
||||
bool is_tunnel = false; // Is tunnel or tunnel floor
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
||||
(x - node_min.X);
|
||||
// Biome of column
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
||||
|
||||
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
||||
// this creates a 'roof' over the tunnel, preventing light in
|
||||
// tunnels at mapchunk borders when generating mapchunks upwards.
|
||||
// This 'roof' is removed when the mapchunk above is generated.
|
||||
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
||||
index3d -= ystride,
|
||||
vm->m_area.add_y(em, vi, -1)) {
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
||||
c == biome->c_water) {
|
||||
column_is_open = true;
|
||||
continue;
|
||||
}
|
||||
// Ground
|
||||
float d1 = contour(noise_cave1->result[index3d]);
|
||||
float d2 = contour(noise_cave2->result[index3d]);
|
||||
|
||||
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
||||
// In tunnel and ground content, excavate
|
||||
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
||||
is_tunnel = true;
|
||||
} else {
|
||||
// Not in tunnel or not ground content
|
||||
if (is_tunnel && column_is_open &&
|
||||
(c == biome->c_filler || c == biome->c_stone))
|
||||
// Tunnel entrance floor
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
|
||||
column_is_open = false;
|
||||
is_tunnel = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node_max.Y > MGFRACTAL_LARGE_CAVE_DEPTH)
|
||||
return;
|
||||
|
||||
PseudoRandom ps(blockseed + 21343);
|
||||
u32 bruises_count = ps.range(0, 2);
|
||||
for (u32 i = 0; i < bruises_count; i++) {
|
||||
CaveV5 cave(this, &ps);
|
||||
cave.makeCave(node_min, node_max, max_stone_y);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,23 +57,20 @@ struct MapgenFractalParams : public MapgenSpecificParams {
|
|||
void writeParams(Settings *settings) const;
|
||||
};
|
||||
|
||||
class MapgenFractal : public Mapgen {
|
||||
class MapgenFractal : public MapgenBasic {
|
||||
public:
|
||||
EmergeManager *m_emerge;
|
||||
BiomeManager *bmgr;
|
||||
MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||
~MapgenFractal();
|
||||
|
||||
int ystride;
|
||||
int zstride_1d;
|
||||
virtual void makeChunk(BlockMakeData *data);
|
||||
int getSpawnLevelAtPoint(v2s16 p);
|
||||
bool getFractalAtPoint(s16 x, s16 y, s16 z);
|
||||
s16 generateTerrain();
|
||||
|
||||
private:
|
||||
u16 formula;
|
||||
bool julia;
|
||||
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
v3s16 full_node_min;
|
||||
v3s16 full_node_max;
|
||||
|
||||
u32 spflags;
|
||||
float cave_width;
|
||||
u16 fractal;
|
||||
u16 iterations;
|
||||
v3f scale;
|
||||
|
@ -84,39 +81,6 @@ public:
|
|||
float julia_z;
|
||||
float julia_w;
|
||||
Noise *noise_seabed;
|
||||
Noise *noise_filler_depth;
|
||||
Noise *noise_cave1;
|
||||
Noise *noise_cave2;
|
||||
|
||||
Noise *noise_heat;
|
||||
Noise *noise_humidity;
|
||||
Noise *noise_heat_blend;
|
||||
Noise *noise_humidity_blend;
|
||||
|
||||
content_t c_stone;
|
||||
content_t c_water_source;
|
||||
content_t c_lava_source;
|
||||
content_t c_desert_stone;
|
||||
content_t c_ice;
|
||||
content_t c_sandstone;
|
||||
|
||||
content_t c_cobble;
|
||||
content_t c_stair_cobble;
|
||||
content_t c_mossycobble;
|
||||
content_t c_sandstonebrick;
|
||||
content_t c_stair_sandstonebrick;
|
||||
|
||||
MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||
~MapgenFractal();
|
||||
|
||||
virtual void makeChunk(BlockMakeData *data);
|
||||
int getSpawnLevelAtPoint(v2s16 p);
|
||||
void calculateNoise();
|
||||
bool getFractalAtPoint(s16 x, s16 y, s16 z);
|
||||
s16 generateTerrain();
|
||||
MgStoneType generateBiomes(float *heat_map, float *humidity_map);
|
||||
void dustTopNodes();
|
||||
void generateCaves(s16 max_stone_y);
|
||||
};
|
||||
|
||||
struct MapgenFactoryFractal : public MapgenFactory {
|
||||
|
|
|
@ -46,22 +46,8 @@ FlagDesc flagdesc_mapgen_v5[] = {
|
|||
|
||||
|
||||
MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||
: Mapgen(mapgenid, params, emerge)
|
||||
: MapgenBasic(mapgenid, params, emerge)
|
||||
{
|
||||
this->m_emerge = emerge;
|
||||
this->bmgr = emerge->biomemgr;
|
||||
|
||||
// amount of elements to skip for the next index
|
||||
// for noise/height/biome maps (not vmanip)
|
||||
this->ystride = csize.X;
|
||||
// 1-down overgeneration
|
||||
this->zstride_1d = csize.X * (csize.Y + 1);
|
||||
|
||||
this->biomemap = new u8[csize.X * csize.Z];
|
||||
this->heightmap = new s16[csize.X * csize.Z];
|
||||
this->heatmap = NULL;
|
||||
this->humidmap = NULL;
|
||||
|
||||
MapgenV5Params *sp = (MapgenV5Params *)params->sparams;
|
||||
|
||||
this->spflags = sp->spflags;
|
||||
|
@ -75,42 +61,9 @@ MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
|||
// 3D terrain noise
|
||||
// 1-up 1-down overgeneration
|
||||
noise_ground = new Noise(&sp->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
|
||||
// 1-down overgeneraion
|
||||
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
|
||||
// Biome noise
|
||||
noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z);
|
||||
noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z);
|
||||
noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z);
|
||||
noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z);
|
||||
|
||||
//// Resolve nodes to be used
|
||||
INodeDefManager *ndef = emerge->ndef;
|
||||
|
||||
c_stone = ndef->getId("mapgen_stone");
|
||||
c_water_source = ndef->getId("mapgen_water_source");
|
||||
c_lava_source = ndef->getId("mapgen_lava_source");
|
||||
c_desert_stone = ndef->getId("mapgen_desert_stone");
|
||||
c_ice = ndef->getId("mapgen_ice");
|
||||
c_sandstone = ndef->getId("mapgen_sandstone");
|
||||
|
||||
c_cobble = ndef->getId("mapgen_cobble");
|
||||
c_stair_cobble = ndef->getId("mapgen_stair_cobble");
|
||||
c_mossycobble = ndef->getId("mapgen_mossycobble");
|
||||
c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
|
||||
c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
|
||||
|
||||
if (c_ice == CONTENT_IGNORE)
|
||||
c_ice = CONTENT_AIR;
|
||||
if (c_mossycobble == CONTENT_IGNORE)
|
||||
c_mossycobble = c_cobble;
|
||||
if (c_stair_cobble == CONTENT_IGNORE)
|
||||
c_stair_cobble = c_cobble;
|
||||
if (c_sandstonebrick == CONTENT_IGNORE)
|
||||
c_sandstonebrick = c_sandstone;
|
||||
if (c_stair_sandstonebrick == CONTENT_IGNORE)
|
||||
c_stair_sandstonebrick = c_sandstone;
|
||||
MapgenBasic::np_cave1 = sp->np_cave1;
|
||||
MapgenBasic::np_cave2 = sp->np_cave2;
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,17 +72,7 @@ MapgenV5::~MapgenV5()
|
|||
delete noise_filler_depth;
|
||||
delete noise_factor;
|
||||
delete noise_height;
|
||||
delete noise_cave1;
|
||||
delete noise_cave2;
|
||||
delete noise_ground;
|
||||
|
||||
delete noise_heat;
|
||||
delete noise_humidity;
|
||||
delete noise_heat_blend;
|
||||
delete noise_humidity_blend;
|
||||
|
||||
delete[] heightmap;
|
||||
delete[] biomemap;
|
||||
}
|
||||
|
||||
|
||||
|
@ -239,69 +182,24 @@ void MapgenV5::makeChunk(BlockMakeData *data)
|
|||
// Create a block-specific seed
|
||||
blockseed = getBlockSeed2(full_node_min, seed);
|
||||
|
||||
// Make some noise
|
||||
calculateNoise();
|
||||
|
||||
// Generate base terrain
|
||||
s16 stone_surface_max_y = generateBaseTerrain();
|
||||
|
||||
// Create heightmap
|
||||
updateHeightmap(node_min, node_max);
|
||||
|
||||
// Create biomemap at heightmap surface
|
||||
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result,
|
||||
noise_humidity->result, heightmap, biomemap);
|
||||
|
||||
// Actually place the biome-specific nodes
|
||||
MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
|
||||
// Init biome generator, place biome-specific nodes, and build biomemap
|
||||
biomegen->calcBiomeNoise(node_min);
|
||||
biomegen->getBiomes(heightmap);
|
||||
MgStoneType stone_type = generateBiomes();
|
||||
|
||||
// Generate caves
|
||||
if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y))
|
||||
generateCaves(stone_surface_max_y);
|
||||
generateCaves(stone_surface_max_y, MGV5_LARGE_CAVE_DEPTH);
|
||||
|
||||
// Generate dungeons and desert temples
|
||||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||
DungeonParams dp;
|
||||
|
||||
dp.np_rarity = nparams_dungeon_rarity;
|
||||
dp.np_density = nparams_dungeon_density;
|
||||
dp.np_wetness = nparams_dungeon_wetness;
|
||||
dp.c_water = c_water_source;
|
||||
if (stone_type == STONE) {
|
||||
dp.c_cobble = c_cobble;
|
||||
dp.c_moss = c_mossycobble;
|
||||
dp.c_stair = c_stair_cobble;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 3.0;
|
||||
dp.holesize = v3s16(1, 2, 1);
|
||||
dp.roomsize = v3s16(0, 0, 0);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
} else if (stone_type == DESERT_STONE) {
|
||||
dp.c_cobble = c_desert_stone;
|
||||
dp.c_moss = c_desert_stone;
|
||||
dp.c_stair = c_desert_stone;
|
||||
|
||||
dp.diagonal_dirs = true;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 3, 2);
|
||||
dp.roomsize = v3s16(2, 5, 2);
|
||||
dp.notifytype = GENNOTIFY_TEMPLE;
|
||||
} else if (stone_type == SANDSTONE) {
|
||||
dp.c_cobble = c_sandstonebrick;
|
||||
dp.c_moss = c_sandstonebrick;
|
||||
dp.c_stair = c_sandstonebrick;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 2, 2);
|
||||
dp.roomsize = v3s16(2, 0, 2);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
}
|
||||
|
||||
DungeonGen dgen(this, &dp);
|
||||
dgen.generate(blockseed, full_node_min, full_node_max);
|
||||
}
|
||||
if (flags & MG_DUNGEONS)
|
||||
generateDungeons(stone_surface_max_y, stone_type);
|
||||
|
||||
// Generate the registered decorations
|
||||
if (flags & MG_DECORATIONS)
|
||||
|
@ -328,37 +226,6 @@ void MapgenV5::makeChunk(BlockMakeData *data)
|
|||
}
|
||||
|
||||
|
||||
void MapgenV5::calculateNoise()
|
||||
{
|
||||
//TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
|
||||
s16 x = node_min.X;
|
||||
s16 y = node_min.Y - 1;
|
||||
s16 z = node_min.Z;
|
||||
|
||||
noise_factor->perlinMap2D(x, z);
|
||||
noise_height->perlinMap2D(x, z);
|
||||
noise_ground->perlinMap3D(x, y, z);
|
||||
|
||||
// Cave noises are calculated in generateCaves()
|
||||
// only if solid terrain is present in mapchunk
|
||||
|
||||
noise_filler_depth->perlinMap2D(x, z);
|
||||
noise_heat->perlinMap2D(x, z);
|
||||
noise_humidity->perlinMap2D(x, z);
|
||||
noise_heat_blend->perlinMap2D(x, z);
|
||||
noise_humidity_blend->perlinMap2D(x, z);
|
||||
|
||||
for (s32 i = 0; i < csize.X * csize.Z; i++) {
|
||||
noise_heat->result[i] += noise_heat_blend->result[i];
|
||||
noise_humidity->result[i] += noise_humidity_blend->result[i];
|
||||
}
|
||||
|
||||
heatmap = noise_heat->result;
|
||||
humidmap = noise_humidity->result;
|
||||
//printf("calculateNoise: %dus\n", t.stop());
|
||||
}
|
||||
|
||||
|
||||
//bool is_cave(u32 index) {
|
||||
// double d1 = contour(noise_cave1->result[index]);
|
||||
// double d2 = contour(noise_cave2->result[index]);
|
||||
|
@ -382,6 +249,10 @@ int MapgenV5::generateBaseTerrain()
|
|||
u32 index2d = 0;
|
||||
int stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
|
||||
|
||||
noise_factor->perlinMap2D(node_min.X, node_min.Z);
|
||||
noise_height->perlinMap2D(node_min.X, node_min.Z);
|
||||
noise_ground->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
|
||||
for (s16 z=node_min.Z; z<=node_max.Z; z++) {
|
||||
for (s16 y=node_min.Y - 1; y<=node_max.Y + 1; y++) {
|
||||
u32 vi = vm->m_area.index(node_min.X, y, z);
|
||||
|
@ -414,219 +285,3 @@ int MapgenV5::generateBaseTerrain()
|
|||
|
||||
return stone_surface_max_y;
|
||||
}
|
||||
|
||||
|
||||
MgStoneType MapgenV5::generateBiomes(float *heat_map, float *humidity_map)
|
||||
{
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
MgStoneType stone_type = STONE;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = NULL;
|
||||
u16 depth_top = 0;
|
||||
u16 base_filler = 0;
|
||||
u16 depth_water_top = 0;
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
|
||||
// Check node at base of mapchunk above, either a node of a previously
|
||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||
bool air_above = c_above == CONTENT_AIR;
|
||||
bool water_above = c_above == c_water_source;
|
||||
|
||||
// If there is air or water above enable top/filler placement, otherwise force
|
||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
||||
|
||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
|
||||
// Biome is recalculated each time an upper surface is detected while
|
||||
// working down a column. The selected biome then remains in effect for
|
||||
// all nodes below until the next surface and biome recalculation.
|
||||
// Biome is recalculated:
|
||||
// 1. At the surface of stone below air or water.
|
||||
// 2. At the surface of water below air.
|
||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
||||
if ((c == c_stone && (air_above || water_above || !biome)) ||
|
||||
(c == c_water_source && (air_above || !biome))) {
|
||||
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
|
||||
depth_top = biome->depth_top;
|
||||
base_filler = MYMAX(depth_top + biome->depth_filler
|
||||
+ noise_filler_depth->result[index], 0);
|
||||
depth_water_top = biome->depth_water_top;
|
||||
|
||||
// Detect stone type for dungeons during every biome calculation.
|
||||
// This is more efficient than detecting per-node and will not
|
||||
// miss any desert stone or sandstone biomes.
|
||||
if (biome->c_stone == c_desert_stone)
|
||||
stone_type = DESERT_STONE;
|
||||
else if (biome->c_stone == c_sandstone)
|
||||
stone_type = SANDSTONE;
|
||||
}
|
||||
|
||||
if (c == c_stone) {
|
||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
||||
|
||||
// If the node below isn't solid, make this node stone, so that
|
||||
// any top/filler nodes above are structurally supported.
|
||||
// This is done by aborting the cycle of top/filler placement
|
||||
// immediately by forcing nplaced to stone level.
|
||||
if (c_below == CONTENT_AIR || c_below == c_water_source)
|
||||
nplaced = U16_MAX;
|
||||
|
||||
if (nplaced < depth_top) {
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
nplaced++;
|
||||
} else if (nplaced < base_filler) {
|
||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
||||
nplaced++;
|
||||
} else {
|
||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
||||
}
|
||||
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
} else if (c == c_water_source) {
|
||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
|
||||
biome->c_water_top : biome->c_water);
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = false;
|
||||
water_above = true;
|
||||
} else if (c == CONTENT_AIR) {
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = true;
|
||||
water_above = false;
|
||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
||||
nplaced = U16_MAX; // Disable top/filler placement
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
}
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return stone_type;
|
||||
}
|
||||
|
||||
|
||||
void MapgenV5::dustTopNodes()
|
||||
{
|
||||
if (node_max.Y < water_level)
|
||||
return;
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
||||
|
||||
if (biome->c_dust == CONTENT_IGNORE)
|
||||
continue;
|
||||
|
||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
||||
content_t c_full_max = vm->m_data[vi].getContent();
|
||||
s16 y_start;
|
||||
|
||||
if (c_full_max == CONTENT_AIR) {
|
||||
y_start = full_node_max.Y - 1;
|
||||
} else if (c_full_max == CONTENT_IGNORE) {
|
||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
||||
content_t c_max = vm->m_data[vi].getContent();
|
||||
|
||||
if (c_max == CONTENT_AIR)
|
||||
y_start = node_max.Y;
|
||||
else
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
vi = vm->m_area.index(x, y_start, z);
|
||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
||||
break;
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
||||
vm->m_area.add_y(em, vi, 1);
|
||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MapgenV5::generateCaves(int max_stone_y)
|
||||
{
|
||||
if (max_stone_y < node_min.Y)
|
||||
return;
|
||||
|
||||
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index2d = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
||||
bool column_is_open = false; // Is column open to overground
|
||||
bool is_tunnel = false; // Is tunnel or tunnel floor
|
||||
// Indexes at column top (node_max.Y)
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
||||
(x - node_min.X);
|
||||
// Biome of column
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
||||
|
||||
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
||||
// this creates a 'roof' over the tunnel, preventing light in
|
||||
// tunnels at mapchunk borders when generating mapchunks upwards.
|
||||
// This 'roof' is removed when the mapchunk above is generated.
|
||||
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
||||
index3d -= ystride,
|
||||
vm->m_area.add_y(em, vi, -1)) {
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
||||
c == biome->c_water) {
|
||||
column_is_open = true;
|
||||
continue;
|
||||
}
|
||||
// Ground
|
||||
float d1 = contour(noise_cave1->result[index3d]);
|
||||
float d2 = contour(noise_cave2->result[index3d]);
|
||||
|
||||
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
||||
// In tunnel and ground content, excavate
|
||||
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
||||
is_tunnel = true;
|
||||
} else {
|
||||
// Not in tunnel or not ground content
|
||||
if (is_tunnel && column_is_open &&
|
||||
(c == biome->c_filler || c == biome->c_stone))
|
||||
// Tunnel entrance floor
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
|
||||
column_is_open = false;
|
||||
is_tunnel = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node_max.Y > MGV5_LARGE_CAVE_DEPTH)
|
||||
return;
|
||||
|
||||
PseudoRandom ps(blockseed + 21343);
|
||||
u32 bruises_count = ps.range(0, 2);
|
||||
for (u32 i = 0; i < bruises_count; i++) {
|
||||
CaveV5 cave(this, &ps);
|
||||
cave.makeCave(node_min, node_max, max_stone_y);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,56 +48,19 @@ struct MapgenV5Params : public MapgenSpecificParams {
|
|||
};
|
||||
|
||||
|
||||
class MapgenV5 : public Mapgen {
|
||||
class MapgenV5 : public MapgenBasic {
|
||||
public:
|
||||
EmergeManager *m_emerge;
|
||||
BiomeManager *bmgr;
|
||||
|
||||
int ystride;
|
||||
int zstride_1d;
|
||||
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
v3s16 full_node_min;
|
||||
v3s16 full_node_max;
|
||||
|
||||
u32 spflags;
|
||||
float cave_width;
|
||||
Noise *noise_filler_depth;
|
||||
Noise *noise_factor;
|
||||
Noise *noise_height;
|
||||
Noise *noise_cave1;
|
||||
Noise *noise_cave2;
|
||||
Noise *noise_ground;
|
||||
|
||||
Noise *noise_heat;
|
||||
Noise *noise_humidity;
|
||||
Noise *noise_heat_blend;
|
||||
Noise *noise_humidity_blend;
|
||||
|
||||
content_t c_stone;
|
||||
content_t c_water_source;
|
||||
content_t c_lava_source;
|
||||
content_t c_desert_stone;
|
||||
content_t c_ice;
|
||||
content_t c_sandstone;
|
||||
|
||||
content_t c_cobble;
|
||||
content_t c_stair_cobble;
|
||||
content_t c_mossycobble;
|
||||
content_t c_sandstonebrick;
|
||||
content_t c_stair_sandstonebrick;
|
||||
|
||||
MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||
~MapgenV5();
|
||||
|
||||
virtual void makeChunk(BlockMakeData *data);
|
||||
int getSpawnLevelAtPoint(v2s16 p);
|
||||
void calculateNoise();
|
||||
int generateBaseTerrain();
|
||||
MgStoneType generateBiomes(float *heat_map, float *humidity_map);
|
||||
void generateCaves(int max_stone_y);
|
||||
void dustTopNodes();
|
||||
|
||||
private:
|
||||
Noise *noise_factor;
|
||||
Noise *noise_height;
|
||||
Noise *noise_ground;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -559,6 +559,8 @@ void MapgenV6::makeChunk(BlockMakeData *data)
|
|||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||
DungeonParams dp;
|
||||
|
||||
dp.seed = seed;
|
||||
|
||||
dp.np_rarity = nparams_dungeon_rarity;
|
||||
dp.np_density = nparams_dungeon_density;
|
||||
dp.np_wetness = nparams_dungeon_wetness;
|
||||
|
@ -585,8 +587,8 @@ void MapgenV6::makeChunk(BlockMakeData *data)
|
|||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
}
|
||||
|
||||
DungeonGen dgen(this, &dp);
|
||||
dgen.generate(blockseed, full_node_min, full_node_max);
|
||||
DungeonGen dgen(ndef, &gennotify, &dp);
|
||||
dgen.generate(vm, blockseed, full_node_min, full_node_max);
|
||||
}
|
||||
|
||||
// Add top and bottom side of water to transforming_liquid queue
|
||||
|
@ -1066,9 +1068,10 @@ void MapgenV6::generateCaves(int max_stone_y)
|
|||
}
|
||||
|
||||
for (u32 i = 0; i < caves_count + bruises_count; i++) {
|
||||
bool large_cave = (i >= caves_count);
|
||||
CaveV6 cave(this, &ps, &ps2, large_cave);
|
||||
CavesV6 cave(ndef, &gennotify, water_level, c_water_source, c_lava_source);
|
||||
|
||||
cave.makeCave(node_min, node_max, max_stone_y);
|
||||
bool large_cave = (i >= caves_count);
|
||||
cave.makeCave(vm, node_min, node_max, &ps, &ps2,
|
||||
large_cave, max_stone_y, heightmap);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,25 +51,8 @@ FlagDesc flagdesc_mapgen_v7[] = {
|
|||
|
||||
|
||||
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||
: Mapgen(mapgenid, params, emerge)
|
||||
: MapgenBasic(mapgenid, params, emerge)
|
||||
{
|
||||
this->m_emerge = emerge;
|
||||
this->bmgr = emerge->biomemgr;
|
||||
|
||||
//// amount of elements to skip for the next index
|
||||
//// for noise/height/biome maps (not vmanip)
|
||||
this->ystride = csize.X;
|
||||
// 1-up 1-down overgeneration
|
||||
this->zstride_1u1d = csize.X * (csize.Y + 2);
|
||||
// 1-down overgeneration
|
||||
this->zstride_1d = csize.X * (csize.Y + 1);
|
||||
|
||||
this->biomemap = new u8[csize.X * csize.Z];
|
||||
this->heightmap = new s16[csize.X * csize.Z];
|
||||
this->heatmap = NULL;
|
||||
this->humidmap = NULL;
|
||||
this->ridge_heightmap = new s16[csize.X * csize.Z];
|
||||
|
||||
MapgenV7Params *sp = (MapgenV7Params *)params->sparams;
|
||||
|
||||
this->spflags = sp->spflags;
|
||||
|
@ -88,42 +71,9 @@ MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
|||
// 1-up 1-down overgeneration
|
||||
noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
|
||||
noise_ridge = new Noise(&sp->np_ridge, seed, csize.X, csize.Y + 2, csize.Z);
|
||||
// 1-down overgeneraion
|
||||
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
|
||||
//// Biome noise
|
||||
noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z);
|
||||
noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z);
|
||||
noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z);
|
||||
noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z);
|
||||
|
||||
//// Resolve nodes to be used
|
||||
INodeDefManager *ndef = emerge->ndef;
|
||||
|
||||
c_stone = ndef->getId("mapgen_stone");
|
||||
c_water_source = ndef->getId("mapgen_water_source");
|
||||
c_lava_source = ndef->getId("mapgen_lava_source");
|
||||
c_desert_stone = ndef->getId("mapgen_desert_stone");
|
||||
c_ice = ndef->getId("mapgen_ice");
|
||||
c_sandstone = ndef->getId("mapgen_sandstone");
|
||||
|
||||
c_cobble = ndef->getId("mapgen_cobble");
|
||||
c_stair_cobble = ndef->getId("mapgen_stair_cobble");
|
||||
c_mossycobble = ndef->getId("mapgen_mossycobble");
|
||||
c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
|
||||
c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
|
||||
|
||||
if (c_ice == CONTENT_IGNORE)
|
||||
c_ice = CONTENT_AIR;
|
||||
if (c_mossycobble == CONTENT_IGNORE)
|
||||
c_mossycobble = c_cobble;
|
||||
if (c_stair_cobble == CONTENT_IGNORE)
|
||||
c_stair_cobble = c_cobble;
|
||||
if (c_sandstonebrick == CONTENT_IGNORE)
|
||||
c_sandstonebrick = c_sandstone;
|
||||
if (c_stair_sandstonebrick == CONTENT_IGNORE)
|
||||
c_stair_sandstonebrick = c_sandstone;
|
||||
MapgenBasic::np_cave1 = sp->np_cave1;
|
||||
MapgenBasic::np_cave2 = sp->np_cave2;
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,17 +88,6 @@ MapgenV7::~MapgenV7()
|
|||
delete noise_ridge_uwater;
|
||||
delete noise_mountain;
|
||||
delete noise_ridge;
|
||||
delete noise_cave1;
|
||||
delete noise_cave2;
|
||||
|
||||
delete noise_heat;
|
||||
delete noise_humidity;
|
||||
delete noise_heat_blend;
|
||||
delete noise_humidity_blend;
|
||||
|
||||
delete[] ridge_heightmap;
|
||||
delete[] heightmap;
|
||||
delete[] biomemap;
|
||||
}
|
||||
|
||||
|
||||
|
@ -267,70 +206,27 @@ void MapgenV7::makeChunk(BlockMakeData *data)
|
|||
|
||||
blockseed = getBlockSeed2(full_node_min, seed);
|
||||
|
||||
// Make some noise
|
||||
calculateNoise();
|
||||
|
||||
// Generate terrain and ridges with initial heightmaps
|
||||
// Generate base and mountain terrain
|
||||
// An initial heightmap is no longer created here for use in generateRidgeTerrain()
|
||||
s16 stone_surface_max_y = generateTerrain();
|
||||
|
||||
// Generate rivers
|
||||
if (spflags & MGV7_RIDGES)
|
||||
generateRidgeTerrain();
|
||||
|
||||
// Update heightmap to include mountain terrain
|
||||
// Create heightmap
|
||||
updateHeightmap(node_min, node_max);
|
||||
|
||||
// Create biomemap at heightmap surface
|
||||
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result,
|
||||
noise_humidity->result, heightmap, biomemap);
|
||||
|
||||
// Actually place the biome-specific nodes
|
||||
MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
|
||||
// Init biome generator, place biome-specific nodes, and build biomemap
|
||||
biomegen->calcBiomeNoise(node_min);
|
||||
biomegen->getBiomes(heightmap);
|
||||
MgStoneType stone_type = generateBiomes();
|
||||
|
||||
if (flags & MG_CAVES)
|
||||
generateCaves(stone_surface_max_y);
|
||||
generateCaves(stone_surface_max_y, water_level);
|
||||
|
||||
if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
|
||||
DungeonParams dp;
|
||||
|
||||
dp.np_rarity = nparams_dungeon_rarity;
|
||||
dp.np_density = nparams_dungeon_density;
|
||||
dp.np_wetness = nparams_dungeon_wetness;
|
||||
dp.c_water = c_water_source;
|
||||
if (stone_type == STONE) {
|
||||
dp.c_cobble = c_cobble;
|
||||
dp.c_moss = c_mossycobble;
|
||||
dp.c_stair = c_stair_cobble;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 3.0;
|
||||
dp.holesize = v3s16(1, 2, 1);
|
||||
dp.roomsize = v3s16(0, 0, 0);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
} else if (stone_type == DESERT_STONE) {
|
||||
dp.c_cobble = c_desert_stone;
|
||||
dp.c_moss = c_desert_stone;
|
||||
dp.c_stair = c_desert_stone;
|
||||
|
||||
dp.diagonal_dirs = true;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 3, 2);
|
||||
dp.roomsize = v3s16(2, 5, 2);
|
||||
dp.notifytype = GENNOTIFY_TEMPLE;
|
||||
} else if (stone_type == SANDSTONE) {
|
||||
dp.c_cobble = c_sandstonebrick;
|
||||
dp.c_moss = c_sandstonebrick;
|
||||
dp.c_stair = c_sandstonebrick;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 0.0;
|
||||
dp.holesize = v3s16(2, 2, 2);
|
||||
dp.roomsize = v3s16(2, 0, 2);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
}
|
||||
|
||||
DungeonGen dgen(this, &dp);
|
||||
dgen.generate(blockseed, full_node_min, full_node_max);
|
||||
}
|
||||
if (flags & MG_DUNGEONS)
|
||||
generateDungeons(stone_surface_max_y, stone_type);
|
||||
|
||||
// Generate the registered decorations
|
||||
if (flags & MG_DECORATIONS)
|
||||
|
@ -357,62 +253,6 @@ void MapgenV7::makeChunk(BlockMakeData *data)
|
|||
}
|
||||
|
||||
|
||||
void MapgenV7::calculateNoise()
|
||||
{
|
||||
//TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
|
||||
s16 x = node_min.X;
|
||||
s16 y = node_min.Y - 1;
|
||||
s16 z = node_min.Z;
|
||||
|
||||
noise_terrain_persist->perlinMap2D(x, z);
|
||||
float *persistmap = noise_terrain_persist->result;
|
||||
|
||||
noise_terrain_base->perlinMap2D(x, z, persistmap);
|
||||
noise_terrain_alt->perlinMap2D(x, z, persistmap);
|
||||
noise_height_select->perlinMap2D(x, z);
|
||||
|
||||
if (spflags & MGV7_MOUNTAINS) {
|
||||
noise_mountain->perlinMap3D(x, y, z);
|
||||
noise_mount_height->perlinMap2D(x, z);
|
||||
}
|
||||
|
||||
if ((spflags & MGV7_RIDGES) && node_max.Y >= water_level) {
|
||||
noise_ridge->perlinMap3D(x, y, z);
|
||||
noise_ridge_uwater->perlinMap2D(x, z);
|
||||
}
|
||||
|
||||
// Cave noises are calculated in generateCaves()
|
||||
// only if solid terrain is present in mapchunk
|
||||
|
||||
noise_filler_depth->perlinMap2D(x, z);
|
||||
noise_heat->perlinMap2D(x, z);
|
||||
noise_humidity->perlinMap2D(x, z);
|
||||
noise_heat_blend->perlinMap2D(x, z);
|
||||
noise_humidity_blend->perlinMap2D(x, z);
|
||||
|
||||
for (s32 i = 0; i < csize.X * csize.Z; i++) {
|
||||
noise_heat->result[i] += noise_heat_blend->result[i];
|
||||
noise_humidity->result[i] += noise_humidity_blend->result[i];
|
||||
}
|
||||
|
||||
heatmap = noise_heat->result;
|
||||
humidmap = noise_humidity->result;
|
||||
//printf("calculateNoise: %dus\n", t.stop());
|
||||
}
|
||||
|
||||
|
||||
Biome *MapgenV7::getBiomeAtPoint(v3s16 p)
|
||||
{
|
||||
float heat = NoisePerlin2D(&noise_heat->np, p.X, p.Z, seed) +
|
||||
NoisePerlin2D(&noise_heat_blend->np, p.X, p.Z, seed);
|
||||
float humidity = NoisePerlin2D(&noise_humidity->np, p.X, p.Z, seed) +
|
||||
NoisePerlin2D(&noise_humidity_blend->np, p.X, p.Z, seed);
|
||||
s16 groundlevel = baseTerrainLevelAtPoint(p.X, p.Z);
|
||||
|
||||
return bmgr->getBiome(heat, humidity, groundlevel);
|
||||
}
|
||||
|
||||
|
||||
float MapgenV7::baseTerrainLevelAtPoint(s16 x, s16 z)
|
||||
{
|
||||
float hselect = NoisePerlin2D(&noise_height_select->np, x, z, seed);
|
||||
|
@ -472,16 +312,27 @@ int MapgenV7::generateTerrain()
|
|||
MapNode n_stone(c_stone);
|
||||
MapNode n_water(c_water_source);
|
||||
|
||||
//// Calculate noise for terrain generation
|
||||
noise_terrain_persist->perlinMap2D(node_min.X, node_min.Z);
|
||||
float *persistmap = noise_terrain_persist->result;
|
||||
|
||||
noise_terrain_base->perlinMap2D(node_min.X, node_min.Z, persistmap);
|
||||
noise_terrain_alt->perlinMap2D(node_min.X, node_min.Z, persistmap);
|
||||
noise_height_select->perlinMap2D(node_min.X, node_min.Z);
|
||||
|
||||
if (spflags & MGV7_MOUNTAINS) {
|
||||
noise_mountain->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
noise_mount_height->perlinMap2D(node_min.X, node_min.Z);
|
||||
}
|
||||
|
||||
//// Place nodes
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
|
||||
u32 index2d = 0;
|
||||
bool mountain_flag = spflags & MGV7_MOUNTAINS;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
||||
s16 surface_y = baseTerrainLevelFromMap(index2d);
|
||||
heightmap[index2d] = surface_y; // Create base terrain heightmap
|
||||
ridge_heightmap[index2d] = surface_y;
|
||||
|
||||
if (surface_y > stone_surface_max_y)
|
||||
stone_surface_max_y = surface_y;
|
||||
|
@ -493,7 +344,7 @@ int MapgenV7::generateTerrain()
|
|||
if (vm->m_data[vi].getContent() == CONTENT_IGNORE) {
|
||||
if (y <= surface_y) {
|
||||
vm->m_data[vi] = n_stone; // Base terrain
|
||||
} else if (mountain_flag &&
|
||||
} else if ((spflags & MGV7_MOUNTAINS) &&
|
||||
getMountainTerrainFromMap(index3d, index2d, y)) {
|
||||
vm->m_data[vi] = n_stone; // Mountain terrain
|
||||
if (y > stone_surface_max_y)
|
||||
|
@ -518,6 +369,9 @@ void MapgenV7::generateRidgeTerrain()
|
|||
if (node_max.Y < water_level - 16)
|
||||
return;
|
||||
|
||||
noise_ridge->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
noise_ridge_uwater->perlinMap2D(node_min.X, node_min.Z);
|
||||
|
||||
MapNode n_water(c_water_source);
|
||||
MapNode n_air(CONTENT_AIR);
|
||||
u32 index = 0;
|
||||
|
@ -529,9 +383,6 @@ void MapgenV7::generateRidgeTerrain()
|
|||
for (s16 x = node_min.X; x <= node_max.X; x++, index++, vi++) {
|
||||
int j = (z - node_min.Z) * csize.X + (x - node_min.X);
|
||||
|
||||
if (heightmap[j] < water_level - 16) // Use base terrain heightmap
|
||||
continue;
|
||||
|
||||
float uwatern = noise_ridge_uwater->result[j] * 2;
|
||||
if (fabs(uwatern) > width)
|
||||
continue;
|
||||
|
@ -544,233 +395,19 @@ void MapgenV7::generateRidgeTerrain()
|
|||
if (nridge + width_mod * height_mod < 0.6)
|
||||
continue;
|
||||
|
||||
if (y < ridge_heightmap[j])
|
||||
ridge_heightmap[j] = y - 1;
|
||||
|
||||
vm->m_data[vi] = (y > water_level) ? n_air : n_water;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MgStoneType MapgenV7::generateBiomes(float *heat_map, float *humidity_map)
|
||||
{
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
MgStoneType stone_type = STONE;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = NULL;
|
||||
u16 depth_top = 0;
|
||||
u16 base_filler = 0;
|
||||
u16 depth_water_top = 0;
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
|
||||
// Check node at base of mapchunk above, either a node of a previously
|
||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||
bool air_above = c_above == CONTENT_AIR;
|
||||
bool water_above = c_above == c_water_source;
|
||||
|
||||
// If there is air or water above enable top/filler placement, otherwise force
|
||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
||||
|
||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
|
||||
// Biome is recalculated each time an upper surface is detected while
|
||||
// working down a column. The selected biome then remains in effect for
|
||||
// all nodes below until the next surface and biome recalculation.
|
||||
// Biome is recalculated:
|
||||
// 1. At the surface of stone below air or water.
|
||||
// 2. At the surface of water below air.
|
||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
||||
if ((c == c_stone && (air_above || water_above || !biome)) ||
|
||||
(c == c_water_source && (air_above || !biome))) {
|
||||
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
|
||||
depth_top = biome->depth_top;
|
||||
base_filler = MYMAX(depth_top + biome->depth_filler
|
||||
+ noise_filler_depth->result[index], 0);
|
||||
depth_water_top = biome->depth_water_top;
|
||||
|
||||
// Detect stone type for dungeons during every biome calculation.
|
||||
// This is more efficient than detecting per-node and will not
|
||||
// miss any desert stone or sandstone biomes.
|
||||
if (biome->c_stone == c_desert_stone)
|
||||
stone_type = DESERT_STONE;
|
||||
else if (biome->c_stone == c_sandstone)
|
||||
stone_type = SANDSTONE;
|
||||
}
|
||||
|
||||
if (c == c_stone) {
|
||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
||||
|
||||
// If the node below isn't solid, make this node stone, so that
|
||||
// any top/filler nodes above are structurally supported.
|
||||
// This is done by aborting the cycle of top/filler placement
|
||||
// immediately by forcing nplaced to stone level.
|
||||
if (c_below == CONTENT_AIR || c_below == c_water_source)
|
||||
nplaced = U16_MAX;
|
||||
|
||||
if (nplaced < depth_top) {
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
nplaced++;
|
||||
} else if (nplaced < base_filler) {
|
||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
||||
nplaced++;
|
||||
} else {
|
||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
||||
}
|
||||
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
} else if (c == c_water_source) {
|
||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
|
||||
biome->c_water_top : biome->c_water);
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = false;
|
||||
water_above = true;
|
||||
} else if (c == CONTENT_AIR) {
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = true;
|
||||
water_above = false;
|
||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
||||
nplaced = U16_MAX; // Disable top/filler placement
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
}
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return stone_type;
|
||||
}
|
||||
|
||||
|
||||
void MapgenV7::dustTopNodes()
|
||||
{
|
||||
if (node_max.Y < water_level)
|
||||
return;
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
||||
|
||||
if (biome->c_dust == CONTENT_IGNORE)
|
||||
continue;
|
||||
|
||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
||||
content_t c_full_max = vm->m_data[vi].getContent();
|
||||
s16 y_start;
|
||||
|
||||
if (c_full_max == CONTENT_AIR) {
|
||||
y_start = full_node_max.Y - 1;
|
||||
} else if (c_full_max == CONTENT_IGNORE) {
|
||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
||||
content_t c_max = vm->m_data[vi].getContent();
|
||||
|
||||
if (c_max == CONTENT_AIR)
|
||||
y_start = node_max.Y;
|
||||
else
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
vi = vm->m_area.index(x, y_start, z);
|
||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
||||
break;
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
||||
vm->m_area.add_y(em, vi, 1);
|
||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MapgenV7::generateCaves(s16 max_stone_y)
|
||||
{
|
||||
if (max_stone_y < node_min.Y)
|
||||
return;
|
||||
|
||||
noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index2d = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) {
|
||||
bool column_is_open = false; // Is column open to overground
|
||||
bool is_tunnel = false; // Is tunnel or tunnel floor
|
||||
// Indexes at column top (node_max.Y)
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride +
|
||||
(x - node_min.X);
|
||||
// Biome of column
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
|
||||
|
||||
// Don't excavate the overgenerated stone at node_max.Y + 1,
|
||||
// this creates a 'roof' over the tunnel, preventing light in
|
||||
// tunnels at mapchunk borders when generating mapchunks upwards.
|
||||
// This 'roof' is removed when the mapchunk above is generated.
|
||||
for (s16 y = node_max.Y; y >= node_min.Y - 1; y--,
|
||||
index3d -= ystride,
|
||||
vm->m_area.add_y(em, vi, -1)) {
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (c == CONTENT_AIR || c == biome->c_water_top ||
|
||||
c == biome->c_water) {
|
||||
column_is_open = true;
|
||||
continue;
|
||||
}
|
||||
// Ground
|
||||
float d1 = contour(noise_cave1->result[index3d]);
|
||||
float d2 = contour(noise_cave2->result[index3d]);
|
||||
|
||||
if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) {
|
||||
// In tunnel and ground content, excavate
|
||||
vm->m_data[vi] = MapNode(CONTENT_AIR);
|
||||
is_tunnel = true;
|
||||
} else {
|
||||
// Not in tunnel or not ground content
|
||||
if (is_tunnel && column_is_open &&
|
||||
(c == biome->c_filler || c == biome->c_stone))
|
||||
// Tunnel entrance floor
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
|
||||
column_is_open = false;
|
||||
is_tunnel = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node_min.Y >= water_level)
|
||||
return;
|
||||
|
||||
PseudoRandom ps(blockseed + 21343);
|
||||
u32 bruises_count = ps.range(0, 2);
|
||||
for (u32 i = 0; i < bruises_count; i++) {
|
||||
CaveV7 cave(this, &ps);
|
||||
cave.makeCave(node_min, node_max, max_stone_y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Code Boneyard
|
||||
////
|
||||
//// Much of the stuff here has potential to become useful again at some point
|
||||
//// in the future, but we don't want it to get lost or forgotten in version
|
||||
//// control.
|
||||
////
|
||||
|
||||
#if 0
|
||||
int MapgenV7::generateMountainTerrain(s16 ymax)
|
||||
|
|
|
@ -54,75 +54,30 @@ struct MapgenV7Params : public MapgenSpecificParams {
|
|||
void writeParams(Settings *settings) const;
|
||||
};
|
||||
|
||||
class MapgenV7 : public Mapgen {
|
||||
class MapgenV7 : public MapgenBasic {
|
||||
public:
|
||||
EmergeManager *m_emerge;
|
||||
BiomeManager *bmgr;
|
||||
|
||||
int ystride;
|
||||
int zstride_1u1d;
|
||||
int zstride_1d;
|
||||
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
v3s16 full_node_min;
|
||||
v3s16 full_node_max;
|
||||
|
||||
s16 *ridge_heightmap;
|
||||
|
||||
u32 spflags;
|
||||
float cave_width;
|
||||
Noise *noise_terrain_base;
|
||||
Noise *noise_terrain_alt;
|
||||
Noise *noise_terrain_persist;
|
||||
Noise *noise_height_select;
|
||||
Noise *noise_filler_depth;
|
||||
Noise *noise_mount_height;
|
||||
Noise *noise_ridge_uwater;
|
||||
Noise *noise_mountain;
|
||||
Noise *noise_ridge;
|
||||
Noise *noise_cave1;
|
||||
Noise *noise_cave2;
|
||||
|
||||
Noise *noise_heat;
|
||||
Noise *noise_humidity;
|
||||
Noise *noise_heat_blend;
|
||||
Noise *noise_humidity_blend;
|
||||
|
||||
content_t c_stone;
|
||||
content_t c_water_source;
|
||||
content_t c_lava_source;
|
||||
content_t c_desert_stone;
|
||||
content_t c_ice;
|
||||
content_t c_sandstone;
|
||||
|
||||
content_t c_cobble;
|
||||
content_t c_stair_cobble;
|
||||
content_t c_mossycobble;
|
||||
content_t c_sandstonebrick;
|
||||
content_t c_stair_sandstonebrick;
|
||||
|
||||
MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||
~MapgenV7();
|
||||
|
||||
virtual void makeChunk(BlockMakeData *data);
|
||||
int getSpawnLevelAtPoint(v2s16 p);
|
||||
Biome *getBiomeAtPoint(v3s16 p);
|
||||
|
||||
float baseTerrainLevelAtPoint(s16 x, s16 z);
|
||||
float baseTerrainLevelFromMap(int index);
|
||||
bool getMountainTerrainAtPoint(s16 x, s16 y, s16 z);
|
||||
bool getMountainTerrainFromMap(int idx_xyz, int idx_xz, s16 y);
|
||||
|
||||
void calculateNoise();
|
||||
|
||||
int generateTerrain();
|
||||
void generateRidgeTerrain();
|
||||
|
||||
MgStoneType generateBiomes(float *heat_map, float *humidity_map);
|
||||
void dustTopNodes();
|
||||
|
||||
void generateCaves(s16 max_stone_y);
|
||||
private:
|
||||
Noise *noise_terrain_base;
|
||||
Noise *noise_terrain_alt;
|
||||
Noise *noise_terrain_persist;
|
||||
Noise *noise_height_select;
|
||||
Noise *noise_mount_height;
|
||||
Noise *noise_ridge_uwater;
|
||||
Noise *noise_mountain;
|
||||
Noise *noise_ridge;
|
||||
};
|
||||
|
||||
struct MapgenFactoryV7 : public MapgenFactory {
|
||||
|
|
|
@ -65,27 +65,16 @@ static FlagDesc flagdesc_mapgen_valleys[] = {
|
|||
|
||||
|
||||
MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge)
|
||||
: Mapgen(mapgenid, params, emerge)
|
||||
: MapgenBasic(mapgenid, params, emerge)
|
||||
{
|
||||
this->m_emerge = emerge;
|
||||
this->bmgr = emerge->biomemgr;
|
||||
|
||||
//// amount of elements to skip for the next index
|
||||
//// for noise/height/biome maps (not vmanip)
|
||||
this->ystride = csize.X;
|
||||
this->zstride = csize.X * (csize.Y + 2);
|
||||
// 1-down overgeneration
|
||||
this->zstride_1d = csize.X * (csize.Y + 1);
|
||||
|
||||
this->biomemap = new u8[csize.X * csize.Z];
|
||||
this->heightmap = new s16[csize.X * csize.Z];
|
||||
this->heatmap = NULL;
|
||||
this->humidmap = NULL;
|
||||
// NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
|
||||
this->m_bgen = (BiomeGenOriginal *)biomegen;
|
||||
|
||||
this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
|
||||
g_settings->getU16("map_generation_limit"));
|
||||
|
||||
MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
|
||||
BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
|
||||
|
||||
this->spflags = sp->spflags;
|
||||
this->altitude_chill = sp->altitude_chill;
|
||||
|
@ -113,15 +102,9 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
|
|||
noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z);
|
||||
|
||||
//// Biome noise
|
||||
noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z);
|
||||
noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z);
|
||||
noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z);
|
||||
noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z);
|
||||
|
||||
this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
|
||||
this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
|
||||
this->humidity_adjust = params->np_biome_humidity.offset - 50.f;
|
||||
this->humidity_adjust = bp->np_humidity.offset - 50.f;
|
||||
|
||||
// a small chance of overflows if the settings are very high
|
||||
this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 4) * 50;
|
||||
|
@ -129,35 +112,13 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
|
|||
|
||||
tcave_cache = new float[csize.Y + 2];
|
||||
|
||||
//// Resolve nodes to be used
|
||||
INodeDefManager *ndef = emerge->ndef;
|
||||
// Resolve content to be used
|
||||
c_lava_source = ndef->getId("mapgen_lava_source");
|
||||
c_sand = ndef->getId("mapgen_sand");
|
||||
|
||||
c_cobble = ndef->getId("mapgen_cobble");
|
||||
c_desert_stone = ndef->getId("mapgen_desert_stone");
|
||||
c_dirt = ndef->getId("mapgen_dirt");
|
||||
c_lava_source = ndef->getId("mapgen_lava_source");
|
||||
c_mossycobble = ndef->getId("mapgen_mossycobble");
|
||||
c_river_water_source = ndef->getId("mapgen_river_water_source");
|
||||
c_sand = ndef->getId("mapgen_sand");
|
||||
c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
|
||||
c_sandstone = ndef->getId("mapgen_sandstone");
|
||||
c_stair_cobble = ndef->getId("mapgen_stair_cobble");
|
||||
c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
|
||||
c_stone = ndef->getId("mapgen_stone");
|
||||
c_water_source = ndef->getId("mapgen_water_source");
|
||||
|
||||
if (c_mossycobble == CONTENT_IGNORE)
|
||||
c_mossycobble = c_cobble;
|
||||
if (c_river_water_source == CONTENT_IGNORE)
|
||||
c_river_water_source = c_water_source;
|
||||
// Fall back to more basic content if not defined
|
||||
if (c_sand == CONTENT_IGNORE)
|
||||
c_sand = c_stone;
|
||||
if (c_sandstonebrick == CONTENT_IGNORE)
|
||||
c_sandstonebrick = c_sandstone;
|
||||
if (c_stair_cobble == CONTENT_IGNORE)
|
||||
c_stair_cobble = c_cobble;
|
||||
if (c_stair_sandstonebrick == CONTENT_IGNORE)
|
||||
c_stair_sandstonebrick = c_sandstone;
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,13 +135,6 @@ MapgenValleys::~MapgenValleys()
|
|||
delete noise_valley_depth;
|
||||
delete noise_valley_profile;
|
||||
|
||||
delete noise_heat;
|
||||
delete noise_heat_blend;
|
||||
delete noise_humidity;
|
||||
delete noise_humidity_blend;
|
||||
|
||||
delete[] biomemap;
|
||||
delete[] heightmap;
|
||||
delete[] tcave_cache;
|
||||
}
|
||||
|
||||
|
@ -293,62 +247,27 @@ void MapgenValleys::makeChunk(BlockMakeData *data)
|
|||
// Generate noise maps and base terrain height.
|
||||
calculateNoise();
|
||||
|
||||
// Generate biome noises. Note this must be executed strictly before
|
||||
// generateTerrain, because generateTerrain depends on intermediate
|
||||
// biome-related noises.
|
||||
m_bgen->calcBiomeNoise(node_min);
|
||||
|
||||
// Generate base terrain with initial heightmaps
|
||||
s16 stone_surface_max_y = generateTerrain();
|
||||
|
||||
// Create biomemap at heightmap surface
|
||||
bmgr->calcBiomes(csize.X, csize.Z, heatmap, humidmap, heightmap, biomemap);
|
||||
// Build biomemap
|
||||
m_bgen->getBiomes(heightmap);
|
||||
|
||||
// Actually place the biome-specific nodes
|
||||
MgStoneType stone_type = generateBiomes(heatmap, humidmap);
|
||||
// Place biome-specific nodes
|
||||
MgStoneType stone_type = generateBiomes();
|
||||
|
||||
// Cave creation.
|
||||
if (flags & MG_CAVES)
|
||||
generateCaves(stone_surface_max_y);
|
||||
generateCaves(stone_surface_max_y, large_cave_depth);
|
||||
|
||||
// Dungeon creation
|
||||
if ((flags & MG_DUNGEONS) && node_max.Y < 50 && (stone_surface_max_y >= node_min.Y)) {
|
||||
DungeonParams dp;
|
||||
|
||||
dp.np_rarity = nparams_dungeon_rarity;
|
||||
dp.np_density = nparams_dungeon_density;
|
||||
dp.np_wetness = nparams_dungeon_wetness;
|
||||
dp.c_water = c_water_source;
|
||||
if (stone_type == STONE) {
|
||||
dp.c_cobble = c_cobble;
|
||||
dp.c_moss = c_mossycobble;
|
||||
dp.c_stair = c_stair_cobble;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 3.f;
|
||||
dp.holesize = v3s16(1, 2, 1);
|
||||
dp.roomsize = v3s16(0, 0, 0);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
} else if (stone_type == DESERT_STONE) {
|
||||
dp.c_cobble = c_desert_stone;
|
||||
dp.c_moss = c_desert_stone;
|
||||
dp.c_stair = c_desert_stone;
|
||||
|
||||
dp.diagonal_dirs = true;
|
||||
dp.mossratio = 0.f;
|
||||
dp.holesize = v3s16(2, 3, 2);
|
||||
dp.roomsize = v3s16(2, 5, 2);
|
||||
dp.notifytype = GENNOTIFY_TEMPLE;
|
||||
} else if (stone_type == SANDSTONE) {
|
||||
dp.c_cobble = c_sandstonebrick;
|
||||
dp.c_moss = c_sandstonebrick;
|
||||
dp.c_stair = c_sandstonebrick;
|
||||
|
||||
dp.diagonal_dirs = false;
|
||||
dp.mossratio = 0.f;
|
||||
dp.holesize = v3s16(2, 2, 2);
|
||||
dp.roomsize = v3s16(2, 0, 2);
|
||||
dp.notifytype = GENNOTIFY_DUNGEON;
|
||||
}
|
||||
|
||||
DungeonGen dgen(this, &dp);
|
||||
dgen.generate(blockseed, full_node_min, full_node_max);
|
||||
}
|
||||
if ((flags & MG_DUNGEONS) && node_max.Y < 50)
|
||||
generateDungeons(stone_surface_max_y, stone_type);
|
||||
|
||||
// Generate the registered decorations
|
||||
if (flags & MG_DECORATIONS)
|
||||
|
@ -390,11 +309,6 @@ void MapgenValleys::calculateNoise()
|
|||
|
||||
//TimeTaker tcn("actualNoise");
|
||||
|
||||
noise_filler_depth->perlinMap2D(x, z);
|
||||
noise_heat_blend->perlinMap2D(x, z);
|
||||
noise_heat->perlinMap2D(x, z);
|
||||
noise_humidity_blend->perlinMap2D(x, z);
|
||||
noise_humidity->perlinMap2D(x, z);
|
||||
noise_inter_valley_slope->perlinMap2D(x, z);
|
||||
noise_rivers->perlinMap2D(x, z);
|
||||
noise_terrain_height->perlinMap2D(x, z);
|
||||
|
@ -418,9 +332,8 @@ void MapgenValleys::calculateNoise()
|
|||
}
|
||||
|
||||
for (s32 index = 0; index < csize.X * csize.Z; index++) {
|
||||
noise_heat->result[index] += noise_heat_blend->result[index] + heat_offset;
|
||||
noise_humidity->result[index] *= humidity_scale;
|
||||
noise_humidity->result[index] += noise_humidity_blend->result[index];
|
||||
m_bgen->heatmap[index] += heat_offset;
|
||||
m_bgen->humidmap[index] *= humidity_scale;
|
||||
}
|
||||
|
||||
TerrainNoise tn;
|
||||
|
@ -450,9 +363,6 @@ void MapgenValleys::calculateNoise()
|
|||
float mount = terrainLevelFromNoise(&tn);
|
||||
noise_terrain_height->result[index] = mount;
|
||||
}
|
||||
|
||||
heatmap = noise_heat->result;
|
||||
humidmap = noise_humidity->result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -596,7 +506,7 @@ int MapgenValleys::generateTerrain()
|
|||
float river_y = noise_rivers->result[index_2d];
|
||||
float surface_y = noise_terrain_height->result[index_2d];
|
||||
float slope = noise_inter_valley_slope->result[index_2d];
|
||||
float t_heat = noise_heat->result[index_2d];
|
||||
float t_heat = m_bgen->heatmap[index_2d];
|
||||
|
||||
heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
|
||||
|
||||
|
@ -610,14 +520,14 @@ int MapgenValleys::generateTerrain()
|
|||
t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
|
||||
|
||||
// If humidity is low or heat is high, lower the water table.
|
||||
float delta = noise_humidity->result[index_2d] - 50.f;
|
||||
float delta = m_bgen->humidmap[index_2d] - 50.f;
|
||||
if (delta < 0.f) {
|
||||
float t_evap = (t_heat - 32.f) / evaporation;
|
||||
river_y += delta * MYMAX(t_evap, 0.08f);
|
||||
}
|
||||
}
|
||||
|
||||
u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
|
||||
u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
|
||||
u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
|
||||
|
||||
// Mapgens concern themselves with stone and water.
|
||||
|
@ -672,7 +582,7 @@ int MapgenValleys::generateTerrain()
|
|||
// Use base ground (water table) in a riverbed, to
|
||||
// avoid an unnatural rise in humidity.
|
||||
float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
|
||||
float humid = noise_humidity->result[index_2d];
|
||||
float humid = m_bgen->humidmap[index_2d];
|
||||
float water_depth = (t_alt - river_y) / humidity_dropoff;
|
||||
humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
|
||||
|
||||
|
@ -683,7 +593,7 @@ int MapgenValleys::generateTerrain()
|
|||
if (t_alt > 0.f)
|
||||
humid -= alt_to_humid * t_alt / altitude_chill;
|
||||
|
||||
noise_humidity->result[index_2d] = humid;
|
||||
m_bgen->humidmap[index_2d] = humid;
|
||||
}
|
||||
|
||||
// Assign the heat adjusted by any changed altitudes.
|
||||
|
@ -693,175 +603,16 @@ int MapgenValleys::generateTerrain()
|
|||
float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
|
||||
if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
|
||||
// The altitude hasn't changed. Use the first result.
|
||||
noise_heat->result[index_2d] = t_heat;
|
||||
m_bgen->heatmap[index_2d] = t_heat;
|
||||
else if (t_alt > 0.f)
|
||||
noise_heat->result[index_2d] -= alt_to_heat * t_alt / altitude_chill;
|
||||
m_bgen->heatmap[index_2d] -= alt_to_heat * t_alt / altitude_chill;
|
||||
}
|
||||
}
|
||||
|
||||
return surface_max_y;
|
||||
}
|
||||
|
||||
|
||||
MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
|
||||
{
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
MgStoneType stone_type = STONE;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = NULL;
|
||||
u16 depth_top = 0;
|
||||
u16 base_filler = 0;
|
||||
u16 depth_water_top = 0;
|
||||
u32 vi = vm->m_area.index(x, node_max.Y, z);
|
||||
|
||||
// Check node at base of mapchunk above, either a node of a previously
|
||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||
bool air_above = c_above == CONTENT_AIR;
|
||||
bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
|
||||
|
||||
// If there is air or water above enable top/filler placement, otherwise force
|
||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
||||
u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
|
||||
|
||||
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
|
||||
// Biome is recalculated each time an upper surface is detected while
|
||||
// working down a column. The selected biome then remains in effect for
|
||||
// all nodes below until the next surface and biome recalculation.
|
||||
// Biome is recalculated:
|
||||
// 1. At the surface of stone below air or water.
|
||||
// 2. At the surface of water below air.
|
||||
// 3. When stone or water is detected but biome has not yet been calculated.
|
||||
if ((c == c_stone && (air_above || water_above || !biome))
|
||||
|| ((c == c_water_source || c == c_river_water_source)
|
||||
&& (air_above || !biome))) {
|
||||
// Both heat and humidity have already been adjusted for altitude.
|
||||
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
|
||||
|
||||
depth_top = biome->depth_top;
|
||||
base_filler = MYMAX(depth_top
|
||||
+ biome->depth_filler
|
||||
+ noise_filler_depth->result[index], 0.f);
|
||||
depth_water_top = biome->depth_water_top;
|
||||
|
||||
// Detect stone type for dungeons during every biome calculation.
|
||||
// This is more efficient than detecting per-node and will not
|
||||
// miss any desert stone or sandstone biomes.
|
||||
if (biome->c_stone == c_desert_stone)
|
||||
stone_type = DESERT_STONE;
|
||||
else if (biome->c_stone == c_sandstone)
|
||||
stone_type = SANDSTONE;
|
||||
}
|
||||
|
||||
if (c == c_stone) {
|
||||
content_t c_below = vm->m_data[vi - em.X].getContent();
|
||||
|
||||
// If the node below isn't solid, make this node stone, so that
|
||||
// any top/filler nodes above are structurally supported.
|
||||
// This is done by aborting the cycle of top/filler placement
|
||||
// immediately by forcing nplaced to stone level.
|
||||
if (c_below == CONTENT_AIR
|
||||
|| c_below == c_water_source
|
||||
|| c_below == c_river_water_source)
|
||||
nplaced = U16_MAX;
|
||||
|
||||
if (nplaced < depth_top) {
|
||||
vm->m_data[vi] = MapNode(biome->c_top);
|
||||
nplaced++;
|
||||
} else if (nplaced < base_filler) {
|
||||
vm->m_data[vi] = MapNode(biome->c_filler);
|
||||
nplaced++;
|
||||
} else {
|
||||
vm->m_data[vi] = MapNode(biome->c_stone);
|
||||
}
|
||||
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
} else if (c == c_water_source) {
|
||||
vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
|
||||
? biome->c_water_top : biome->c_water);
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = false;
|
||||
water_above = true;
|
||||
} else if (c == c_river_water_source) {
|
||||
vm->m_data[vi] = MapNode(biome->c_river_water);
|
||||
nplaced = depth_top; // Enable filler placement for next surface
|
||||
air_above = false;
|
||||
water_above = true;
|
||||
} else if (c == CONTENT_AIR) {
|
||||
nplaced = 0; // Enable top/filler placement for next surface
|
||||
air_above = true;
|
||||
water_above = false;
|
||||
} else { // Possible various nodes overgenerated from neighbouring mapchunks
|
||||
nplaced = U16_MAX; // Disable top/filler placement
|
||||
air_above = false;
|
||||
water_above = false;
|
||||
}
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return stone_type;
|
||||
}
|
||||
|
||||
|
||||
void MapgenValleys::dustTopNodes()
|
||||
{
|
||||
if (node_max.Y < water_level)
|
||||
return;
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 index = 0;
|
||||
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
|
||||
|
||||
if (biome->c_dust == CONTENT_IGNORE)
|
||||
continue;
|
||||
|
||||
u32 vi = vm->m_area.index(x, full_node_max.Y, z);
|
||||
content_t c_full_max = vm->m_data[vi].getContent();
|
||||
s16 y_start;
|
||||
|
||||
if (c_full_max == CONTENT_AIR) {
|
||||
y_start = full_node_max.Y - 1;
|
||||
} else if (c_full_max == CONTENT_IGNORE) {
|
||||
vi = vm->m_area.index(x, node_max.Y + 1, z);
|
||||
content_t c_max = vm->m_data[vi].getContent();
|
||||
|
||||
if (c_max == CONTENT_AIR)
|
||||
y_start = node_max.Y;
|
||||
else
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
vi = vm->m_area.index(x, y_start, z);
|
||||
for (s16 y = y_start; y >= node_min.Y - 1; y--) {
|
||||
if (vm->m_data[vi].getContent() != CONTENT_AIR)
|
||||
break;
|
||||
|
||||
vm->m_area.add_y(em, vi, -1);
|
||||
}
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
||||
vm->m_area.add_y(em, vi, 1);
|
||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MapgenValleys::generateCaves(s16 max_stone_y)
|
||||
void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth)
|
||||
{
|
||||
if (max_stone_y < node_min.Y)
|
||||
return;
|
||||
|
@ -925,7 +676,7 @@ void MapgenValleys::generateCaves(s16 max_stone_y)
|
|||
u32 index_2d = 0;
|
||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||
for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
|
||||
Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]);
|
||||
Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index_2d]);
|
||||
bool tunnel_air_above = false;
|
||||
bool underground = false;
|
||||
u32 index_data = vm->m_area.index(x, node_max.Y, z);
|
||||
|
@ -1010,8 +761,10 @@ void MapgenValleys::generateCaves(s16 max_stone_y)
|
|||
if (node_max.Y <= large_cave_depth && !made_a_big_one) {
|
||||
u32 bruises_count = ps.range(0, 2);
|
||||
for (u32 i = 0; i < bruises_count; i++) {
|
||||
CaveV5 cave(this, &ps);
|
||||
cave.makeCave(node_min, node_max, max_stone_y);
|
||||
CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
|
||||
c_water_source, c_lava_source);
|
||||
|
||||
cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#define MYCUBE(x) (x) * (x) * (x)
|
||||
|
||||
class BiomeManager;
|
||||
class BiomeGenOriginal;
|
||||
|
||||
// Global profiler
|
||||
//class Profiler;
|
||||
|
@ -84,7 +85,7 @@ struct TerrainNoise {
|
|||
float inter_valley_fill;
|
||||
};
|
||||
|
||||
class MapgenValleys : public Mapgen {
|
||||
class MapgenValleys : public MapgenBasic {
|
||||
public:
|
||||
|
||||
MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge);
|
||||
|
@ -96,12 +97,7 @@ public:
|
|||
s16 large_cave_depth;
|
||||
|
||||
private:
|
||||
EmergeManager *m_emerge;
|
||||
BiomeManager *bmgr;
|
||||
|
||||
int ystride;
|
||||
int zstride;
|
||||
int zstride_1d;
|
||||
BiomeGenOriginal *m_bgen;
|
||||
|
||||
float map_gen_limit;
|
||||
|
||||
|
@ -111,12 +107,6 @@ private:
|
|||
s16 cave_water_max_height;
|
||||
s16 lava_max_height;
|
||||
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
v3s16 full_node_min;
|
||||
v3s16 full_node_max;
|
||||
|
||||
u32 spflags;
|
||||
float altitude_chill;
|
||||
s16 lava_features_lim;
|
||||
s16 massive_cave_depth;
|
||||
|
@ -124,37 +114,18 @@ private:
|
|||
float river_size_factor;
|
||||
float *tcave_cache;
|
||||
s16 water_features_lim;
|
||||
float cave_width;
|
||||
Noise *noise_filler_depth;
|
||||
Noise *noise_cave1;
|
||||
Noise *noise_cave2;
|
||||
Noise *noise_inter_valley_fill;
|
||||
Noise *noise_inter_valley_slope;
|
||||
Noise *noise_rivers;
|
||||
Noise *noise_cave1;
|
||||
Noise *noise_cave2;
|
||||
Noise *noise_massive_caves;
|
||||
Noise *noise_terrain_height;
|
||||
Noise *noise_valley_depth;
|
||||
Noise *noise_valley_profile;
|
||||
|
||||
Noise *noise_heat;
|
||||
Noise *noise_heat_blend;
|
||||
Noise *noise_humidity;
|
||||
Noise *noise_humidity_blend;
|
||||
|
||||
content_t c_cobble;
|
||||
content_t c_desert_stone;
|
||||
content_t c_dirt;
|
||||
content_t c_ice;
|
||||
content_t c_lava_source;
|
||||
content_t c_mossycobble;
|
||||
content_t c_river_water_source;
|
||||
content_t c_sand;
|
||||
content_t c_sandstone;
|
||||
content_t c_sandstonebrick;
|
||||
content_t c_stair_cobble;
|
||||
content_t c_stair_sandstonebrick;
|
||||
content_t c_stone;
|
||||
content_t c_water_source;
|
||||
|
||||
float terrainLevelAtPoint(s16 x, s16 z);
|
||||
|
||||
|
@ -164,12 +135,7 @@ private:
|
|||
float terrainLevelFromNoise(TerrainNoise *tn);
|
||||
float adjustedTerrainLevelFromNoise(TerrainNoise *tn);
|
||||
|
||||
float humidityByTerrain(float humidity_base, float mount, float rivers, float valley);
|
||||
|
||||
MgStoneType generateBiomes(float *heat_map, float *humidity_map);
|
||||
void dustTopNodes();
|
||||
|
||||
void generateCaves(s16 max_stone_y);
|
||||
virtual void generateCaves(s16 max_stone_y, s16 large_cave_depth);
|
||||
};
|
||||
|
||||
struct MapgenFactoryValleys : public MapgenFactory {
|
||||
|
|
185
src/mg_biome.cpp
185
src/mg_biome.cpp
|
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "util/numeric.h"
|
||||
#include "util/mathconstants.h"
|
||||
#include "porting.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -63,49 +64,11 @@ BiomeManager::BiomeManager(IGameDef *gamedef) :
|
|||
}
|
||||
|
||||
|
||||
|
||||
BiomeManager::~BiomeManager()
|
||||
{
|
||||
//if (biomecache)
|
||||
// delete[] biomecache;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// just a PoC, obviously needs optimization later on (precalculate this)
|
||||
void BiomeManager::calcBiomes(s16 sx, s16 sy, float *heat_map,
|
||||
float *humidity_map, s16 *height_map, u8 *biomeid_map)
|
||||
{
|
||||
for (s32 i = 0; i != sx * sy; i++) {
|
||||
Biome *biome = getBiome(heat_map[i], humidity_map[i], height_map[i]);
|
||||
biomeid_map[i] = biome->index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Biome *BiomeManager::getBiome(float heat, float humidity, s16 y)
|
||||
{
|
||||
Biome *b, *biome_closest = NULL;
|
||||
float dist_min = FLT_MAX;
|
||||
|
||||
for (size_t i = 1; i < m_objects.size(); i++) {
|
||||
b = (Biome *)m_objects[i];
|
||||
if (!b || y > b->y_max || y < b->y_min)
|
||||
continue;
|
||||
|
||||
float d_heat = heat - b->heat_point;
|
||||
float d_humidity = humidity - b->humidity_point;
|
||||
float dist = (d_heat * d_heat) +
|
||||
(d_humidity * d_humidity);
|
||||
if (dist < dist_min) {
|
||||
dist_min = dist;
|
||||
biome_closest = b;
|
||||
}
|
||||
}
|
||||
|
||||
return biome_closest ? biome_closest : (Biome *)m_objects[0];
|
||||
}
|
||||
|
||||
void BiomeManager::clear()
|
||||
{
|
||||
EmergeManager *emerge = m_gamedef->getEmergeManager();
|
||||
|
@ -118,17 +81,153 @@ void BiomeManager::clear()
|
|||
}
|
||||
|
||||
// Don't delete the first biome
|
||||
for (size_t i = 1; i < m_objects.size(); i++) {
|
||||
Biome *b = (Biome *)m_objects[i];
|
||||
delete b;
|
||||
}
|
||||
for (size_t i = 1; i < m_objects.size(); i++)
|
||||
delete (Biome *)m_objects[i];
|
||||
|
||||
m_objects.resize(1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BiomeParamsOriginal::readParams(const Settings *settings)
|
||||
{
|
||||
settings->getNoiseParams("mg_biome_np_heat", np_heat);
|
||||
settings->getNoiseParams("mg_biome_np_heat_blend", np_heat_blend);
|
||||
settings->getNoiseParams("mg_biome_np_humidity", np_humidity);
|
||||
settings->getNoiseParams("mg_biome_np_humidity_blend", np_humidity_blend);
|
||||
}
|
||||
|
||||
|
||||
void BiomeParamsOriginal::writeParams(Settings *settings) const
|
||||
{
|
||||
settings->setNoiseParams("mg_biome_np_heat", np_heat);
|
||||
settings->setNoiseParams("mg_biome_np_heat_blend", np_heat_blend);
|
||||
settings->setNoiseParams("mg_biome_np_humidity", np_humidity);
|
||||
settings->setNoiseParams("mg_biome_np_humidity_blend", np_humidity_blend);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BiomeGenOriginal::BiomeGenOriginal(BiomeManager *biomemgr,
|
||||
BiomeParamsOriginal *params, v3s16 chunksize)
|
||||
{
|
||||
m_bmgr = biomemgr;
|
||||
m_params = params;
|
||||
m_csize = chunksize;
|
||||
|
||||
noise_heat = new Noise(¶ms->np_heat,
|
||||
params->seed, m_csize.X, m_csize.Z);
|
||||
noise_humidity = new Noise(¶ms->np_humidity,
|
||||
params->seed, m_csize.X, m_csize.Z);
|
||||
noise_heat_blend = new Noise(¶ms->np_heat_blend,
|
||||
params->seed, m_csize.X, m_csize.Z);
|
||||
noise_humidity_blend = new Noise(¶ms->np_humidity_blend,
|
||||
params->seed, m_csize.X, m_csize.Z);
|
||||
|
||||
heatmap = noise_heat->result;
|
||||
humidmap = noise_humidity->result;
|
||||
biomemap = new u8[m_csize.X * m_csize.Z];
|
||||
}
|
||||
|
||||
BiomeGenOriginal::~BiomeGenOriginal()
|
||||
{
|
||||
delete []biomemap;
|
||||
|
||||
delete noise_heat;
|
||||
delete noise_humidity;
|
||||
delete noise_heat_blend;
|
||||
delete noise_humidity_blend;
|
||||
}
|
||||
|
||||
|
||||
Biome *BiomeGenOriginal::calcBiomeAtPoint(v3s16 pos) const
|
||||
{
|
||||
float heat =
|
||||
NoisePerlin2D(&m_params->np_heat, pos.X, pos.Z, m_params->seed) +
|
||||
NoisePerlin2D(&m_params->np_heat_blend, pos.X, pos.Z, m_params->seed);
|
||||
float humidity =
|
||||
NoisePerlin2D(&m_params->np_humidity, pos.X, pos.Z, m_params->seed) +
|
||||
NoisePerlin2D(&m_params->np_humidity_blend, pos.X, pos.Z, m_params->seed);
|
||||
|
||||
return calcBiomeFromNoise(heat, humidity, pos.Y);
|
||||
}
|
||||
|
||||
|
||||
void BiomeGenOriginal::calcBiomeNoise(v3s16 pmin)
|
||||
{
|
||||
m_pmin = pmin;
|
||||
|
||||
noise_heat->perlinMap2D(pmin.X, pmin.Z);
|
||||
noise_humidity->perlinMap2D(pmin.X, pmin.Z);
|
||||
noise_heat_blend->perlinMap2D(pmin.X, pmin.Z);
|
||||
noise_humidity_blend->perlinMap2D(pmin.X, pmin.Z);
|
||||
|
||||
for (s32 i = 0; i < m_csize.X * m_csize.Z; i++) {
|
||||
noise_heat->result[i] += noise_heat_blend->result[i];
|
||||
noise_humidity->result[i] += noise_humidity_blend->result[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u8 *BiomeGenOriginal::getBiomes(s16 *heightmap)
|
||||
{
|
||||
for (s32 i = 0; i != m_csize.X * m_csize.Z; i++) {
|
||||
Biome *biome = calcBiomeFromNoise(
|
||||
noise_heat->result[i],
|
||||
noise_humidity->result[i],
|
||||
heightmap[i]);
|
||||
|
||||
biomemap[i] = biome->index;
|
||||
}
|
||||
|
||||
return biomemap;
|
||||
}
|
||||
|
||||
|
||||
Biome *BiomeGenOriginal::getBiomeAtPoint(v3s16 pos) const
|
||||
{
|
||||
return getBiomeAtIndex(
|
||||
(pos.Z - m_pmin.Z) * m_csize.X + (pos.X - m_pmin.X),
|
||||
pos.Y);
|
||||
}
|
||||
|
||||
|
||||
Biome *BiomeGenOriginal::getBiomeAtIndex(size_t index, s16 y) const
|
||||
{
|
||||
return calcBiomeFromNoise(
|
||||
noise_heat->result[index],
|
||||
noise_humidity->result[index],
|
||||
y);
|
||||
}
|
||||
|
||||
|
||||
Biome *BiomeGenOriginal::calcBiomeFromNoise(float heat, float humidity, s16 y) const
|
||||
{
|
||||
Biome *b, *biome_closest = NULL;
|
||||
float dist_min = FLT_MAX;
|
||||
|
||||
for (size_t i = 1; i < m_bmgr->getNumObjects(); i++) {
|
||||
b = (Biome *)m_bmgr->getRaw(i);
|
||||
if (!b || y > b->y_max || y < b->y_min)
|
||||
continue;
|
||||
|
||||
float d_heat = heat - b->heat_point;
|
||||
float d_humidity = humidity - b->humidity_point;
|
||||
float dist = (d_heat * d_heat) +
|
||||
(d_humidity * d_humidity);
|
||||
if (dist < dist_min) {
|
||||
dist_min = dist;
|
||||
biome_closest = b;
|
||||
}
|
||||
}
|
||||
|
||||
return biome_closest ? biome_closest : (Biome *)m_bmgr->getRaw(BIOME_NONE);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Biome::resolveNodeNames()
|
||||
{
|
||||
|
|
169
src/mg_biome.h
169
src/mg_biome.h
|
@ -22,14 +22,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#include "objdef.h"
|
||||
#include "nodedef.h"
|
||||
#include "noise.h"
|
||||
|
||||
enum BiomeType
|
||||
{
|
||||
BIOME_NORMAL,
|
||||
BIOME_LIQUID,
|
||||
BIOME_NETHER,
|
||||
BIOME_AETHER,
|
||||
BIOME_FLAT
|
||||
class Settings;
|
||||
class BiomeManager;
|
||||
|
||||
////
|
||||
//// Biome
|
||||
////
|
||||
|
||||
#define BIOME_NONE ((u8)0)
|
||||
|
||||
// TODO(hmmmm): Decide whether this is obsolete or will be used in the future
|
||||
enum BiomeType {
|
||||
BIOMETYPE_NORMAL,
|
||||
BIOMETYPE_LIQUID,
|
||||
BIOMETYPE_NETHER,
|
||||
BIOMETYPE_AETHER,
|
||||
BIOMETYPE_FLAT,
|
||||
};
|
||||
|
||||
class Biome : public ObjDef, public NodeResolver {
|
||||
|
@ -56,10 +66,122 @@ public:
|
|||
virtual void resolveNodeNames();
|
||||
};
|
||||
|
||||
|
||||
////
|
||||
//// BiomeGen
|
||||
////
|
||||
|
||||
enum BiomeGenType {
|
||||
BIOMEGEN_ORIGINAL,
|
||||
};
|
||||
|
||||
struct BiomeParams {
|
||||
virtual void readParams(const Settings *settings) = 0;
|
||||
virtual void writeParams(Settings *settings) const = 0;
|
||||
virtual ~BiomeParams() {}
|
||||
|
||||
int seed;
|
||||
};
|
||||
|
||||
class BiomeGen {
|
||||
public:
|
||||
virtual ~BiomeGen() {}
|
||||
virtual BiomeGenType getType() const = 0;
|
||||
|
||||
// Calculates the biome at the exact position provided. This function can
|
||||
// be called at any time, but may be less efficient than the latter methods,
|
||||
// depending on implementation.
|
||||
virtual Biome *calcBiomeAtPoint(v3s16 pos) const = 0;
|
||||
|
||||
// Computes any intermediate results needed for biome generation. Must be
|
||||
// called before using any of: getBiomes, getBiomeAtPoint, or getBiomeAtIndex.
|
||||
// Calling this invalidates the previous results stored in biomemap.
|
||||
virtual void calcBiomeNoise(v3s16 pmin) = 0;
|
||||
|
||||
// Gets all biomes in current chunk using each corresponding element of
|
||||
// heightmap as the y position, then stores the results by biome index in
|
||||
// biomemap (also returned)
|
||||
virtual u8 *getBiomes(s16 *heightmap) = 0;
|
||||
|
||||
// Gets a single biome at the specified position, which must be contained
|
||||
// in the region formed by m_pmin and (m_pmin + m_csize - 1).
|
||||
virtual Biome *getBiomeAtPoint(v3s16 pos) const = 0;
|
||||
|
||||
// Same as above, but uses a raw numeric index correlating to the (x,z) position.
|
||||
virtual Biome *getBiomeAtIndex(size_t index, s16 y) const = 0;
|
||||
|
||||
// Result of calcBiomes bulk computation.
|
||||
u8 *biomemap;
|
||||
|
||||
protected:
|
||||
BiomeManager *m_bmgr;
|
||||
v3s16 m_pmin;
|
||||
v3s16 m_csize;
|
||||
};
|
||||
|
||||
|
||||
////
|
||||
//// BiomeGen implementations
|
||||
////
|
||||
|
||||
//
|
||||
// Original biome algorithm (Whittaker's classification + surface height)
|
||||
//
|
||||
|
||||
struct BiomeParamsOriginal : public BiomeParams {
|
||||
BiomeParamsOriginal() :
|
||||
np_heat(50, 50, v3f(750.0, 750.0, 750.0), 5349, 3, 0.5, 2.0),
|
||||
np_humidity(50, 50, v3f(750.0, 750.0, 750.0), 842, 3, 0.5, 2.0),
|
||||
np_heat_blend(0, 1.5, v3f(8.0, 8.0, 8.0), 13, 2, 1.0, 2.0),
|
||||
np_humidity_blend(0, 1.5, v3f(8.0, 8.0, 8.0), 90003, 2, 1.0, 2.0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void readParams(const Settings *settings);
|
||||
virtual void writeParams(Settings *settings) const;
|
||||
|
||||
NoiseParams np_heat;
|
||||
NoiseParams np_humidity;
|
||||
NoiseParams np_heat_blend;
|
||||
NoiseParams np_humidity_blend;
|
||||
};
|
||||
|
||||
class BiomeGenOriginal : public BiomeGen {
|
||||
public:
|
||||
BiomeGenOriginal(BiomeManager *biomemgr,
|
||||
BiomeParamsOriginal *params, v3s16 chunksize);
|
||||
virtual ~BiomeGenOriginal();
|
||||
|
||||
BiomeGenType getType() const { return BIOMEGEN_ORIGINAL; }
|
||||
|
||||
Biome *calcBiomeAtPoint(v3s16 pos) const;
|
||||
void calcBiomeNoise(v3s16 pmin);
|
||||
|
||||
u8 *getBiomes(s16 *heightmap);
|
||||
Biome *getBiomeAtPoint(v3s16 pos) const;
|
||||
Biome *getBiomeAtIndex(size_t index, s16 y) const;
|
||||
|
||||
Biome *calcBiomeFromNoise(float heat, float humidity, s16 y) const;
|
||||
|
||||
float *heatmap;
|
||||
float *humidmap;
|
||||
|
||||
private:
|
||||
BiomeParamsOriginal *m_params;
|
||||
|
||||
Noise *noise_heat;
|
||||
Noise *noise_humidity;
|
||||
Noise *noise_heat_blend;
|
||||
Noise *noise_humidity_blend;
|
||||
};
|
||||
|
||||
|
||||
////
|
||||
//// BiomeManager
|
||||
////
|
||||
|
||||
class BiomeManager : public ObjDefManager {
|
||||
public:
|
||||
static const char *OBJECT_TITLE;
|
||||
|
||||
BiomeManager(IGameDef *gamedef);
|
||||
virtual ~BiomeManager();
|
||||
|
||||
|
@ -73,15 +195,36 @@ public:
|
|||
return new Biome;
|
||||
}
|
||||
|
||||
BiomeGen *createBiomeGen(BiomeGenType type, BiomeParams *params, v3s16 chunksize)
|
||||
{
|
||||
switch (type) {
|
||||
case BIOMEGEN_ORIGINAL:
|
||||
return new BiomeGenOriginal(this,
|
||||
(BiomeParamsOriginal *)params, chunksize);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static BiomeParams *createBiomeParams(BiomeGenType type)
|
||||
{
|
||||
switch (type) {
|
||||
case BIOMEGEN_ORIGINAL:
|
||||
return new BiomeParamsOriginal;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void clear();
|
||||
|
||||
void calcBiomes(s16 sx, s16 sy, float *heat_map, float *humidity_map,
|
||||
s16 *height_map, u8 *biomeid_map);
|
||||
Biome *getBiome(float heat, float humidity, s16 y);
|
||||
// Looks for pos in the biome cache, and if non-existent, looks up by noise
|
||||
u8 getBiomeAtPoint(v3s16 pos);
|
||||
|
||||
private:
|
||||
IGameDef *m_gamedef;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -898,8 +898,10 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
|
|||
bool collisiondetection = readU8(is);
|
||||
std::string texture = deSerializeLongString(is);
|
||||
bool vertical = false;
|
||||
bool collision_removal = false;
|
||||
try {
|
||||
vertical = readU8(is);
|
||||
collision_removal = readU8(is);
|
||||
} catch (...) {}
|
||||
|
||||
ClientEvent event;
|
||||
|
@ -910,6 +912,7 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
|
|||
event.spawn_particle.expirationtime = expirationtime;
|
||||
event.spawn_particle.size = size;
|
||||
event.spawn_particle.collisiondetection = collisiondetection;
|
||||
event.spawn_particle.collision_removal = collision_removal;
|
||||
event.spawn_particle.vertical = vertical;
|
||||
event.spawn_particle.texture = new std::string(texture);
|
||||
|
||||
|
@ -942,8 +945,11 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
|
|||
*pkt >> id;
|
||||
|
||||
bool vertical = false;
|
||||
bool collision_removal = false;
|
||||
try {
|
||||
*pkt >> vertical;
|
||||
*pkt >> collision_removal;
|
||||
|
||||
} catch (...) {}
|
||||
|
||||
ClientEvent event;
|
||||
|
@ -961,6 +967,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
|
|||
event.add_particlespawner.minsize = minsize;
|
||||
event.add_particlespawner.maxsize = maxsize;
|
||||
event.add_particlespawner.collisiondetection = collisiondetection;
|
||||
event.add_particlespawner.collision_removal = collision_removal;
|
||||
event.add_particlespawner.vertical = vertical;
|
||||
event.add_particlespawner.texture = new std::string(texture);
|
||||
event.add_particlespawner.id = id;
|
||||
|
|
|
@ -71,6 +71,9 @@ static inline float CALC_DTIME(unsigned int lasttime, unsigned int curtime) {
|
|||
|
||||
#define PING_TIMEOUT 5.0
|
||||
|
||||
/* maximum number of retries for reliable packets */
|
||||
#define MAX_RELIABLE_RETRY 5
|
||||
|
||||
static u16 readPeerId(u8 *packetdata)
|
||||
{
|
||||
return readU16(&packetdata[4]);
|
||||
|
@ -1399,6 +1402,7 @@ void ConnectionSendThread::runTimeouts(float dtime)
|
|||
}
|
||||
|
||||
float resend_timeout = dynamic_cast<UDPPeer*>(&peer)->getResendTimeout();
|
||||
bool retry_count_exceeded = false;
|
||||
for(u16 i=0; i<CHANNEL_COUNT; i++)
|
||||
{
|
||||
std::list<BufferedPacket> timed_outs;
|
||||
|
@ -1438,6 +1442,13 @@ void ConnectionSendThread::runTimeouts(float dtime)
|
|||
channel->UpdateBytesLost(k->data.getSize());
|
||||
k->resend_count++;
|
||||
|
||||
if (k-> resend_count > MAX_RELIABLE_RETRY) {
|
||||
retry_count_exceeded = true;
|
||||
timeouted_peers.push_back(peer->id);
|
||||
/* no need to check additional packets if a single one did timeout*/
|
||||
break;
|
||||
}
|
||||
|
||||
LOG(derr_con<<m_connection->getDesc()
|
||||
<<"RE-SENDING timed-out RELIABLE to "
|
||||
<< k->address.serializeString()
|
||||
|
@ -1452,9 +1463,18 @@ void ConnectionSendThread::runTimeouts(float dtime)
|
|||
// do not handle rtt here as we can't decide if this packet was
|
||||
// lost or really takes more time to transmit
|
||||
}
|
||||
|
||||
if (retry_count_exceeded) {
|
||||
break; /* no need to check other channels if we already did timeout */
|
||||
}
|
||||
|
||||
channel->UpdateTimers(dtime,dynamic_cast<UDPPeer*>(&peer)->getLegacyPeer());
|
||||
}
|
||||
|
||||
/* skip to next peer if we did timeout */
|
||||
if (retry_count_exceeded)
|
||||
continue;
|
||||
|
||||
/* send ping if necessary */
|
||||
if (dynamic_cast<UDPPeer*>(&peer)->Ping(dtime,data)) {
|
||||
LOG(dout_con<<m_connection->getDesc()
|
||||
|
|
|
@ -474,6 +474,7 @@ enum ToClientCommand
|
|||
u8 bool vertical
|
||||
u32 len
|
||||
u8[len] texture
|
||||
u8 collision_removal
|
||||
*/
|
||||
|
||||
TOCLIENT_ADD_PARTICLESPAWNER = 0x47,
|
||||
|
@ -495,6 +496,7 @@ enum ToClientCommand
|
|||
u32 len
|
||||
u8[len] texture
|
||||
u32 id
|
||||
u8 collision_removal
|
||||
*/
|
||||
|
||||
TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY = 0x48,
|
||||
|
|
|
@ -54,6 +54,7 @@ Particle::Particle(
|
|||
float expirationtime,
|
||||
float size,
|
||||
bool collisiondetection,
|
||||
bool collision_removal,
|
||||
bool vertical,
|
||||
video::ITexture *texture,
|
||||
v2f texpos,
|
||||
|
@ -85,6 +86,7 @@ Particle::Particle(
|
|||
m_player = player;
|
||||
m_size = size;
|
||||
m_collisiondetection = collisiondetection;
|
||||
m_collision_removal = collision_removal;
|
||||
m_vertical = vertical;
|
||||
|
||||
// Irrlicht stuff
|
||||
|
@ -126,20 +128,21 @@ void Particle::render()
|
|||
void Particle::step(float dtime)
|
||||
{
|
||||
m_time += dtime;
|
||||
if (m_collisiondetection)
|
||||
{
|
||||
if (m_collisiondetection) {
|
||||
aabb3f box = m_collisionbox;
|
||||
v3f p_pos = m_pos*BS;
|
||||
v3f p_velocity = m_velocity*BS;
|
||||
collisionMoveSimple(m_env, m_gamedef,
|
||||
BS*0.5, box,
|
||||
0, dtime,
|
||||
&p_pos, &p_velocity, m_acceleration * BS);
|
||||
m_pos = p_pos/BS;
|
||||
m_velocity = p_velocity/BS;
|
||||
}
|
||||
else
|
||||
{
|
||||
v3f p_pos = m_pos * BS;
|
||||
v3f p_velocity = m_velocity * BS;
|
||||
collisionMoveResult r = collisionMoveSimple(m_env,
|
||||
m_gamedef, BS * 0.5, box, 0, dtime, &p_pos,
|
||||
&p_velocity, m_acceleration * BS);
|
||||
if (m_collision_removal && r.collides) {
|
||||
// force expiration of the particle
|
||||
m_expiration = -1.0;
|
||||
} else {
|
||||
m_pos = p_pos / BS;
|
||||
m_velocity = p_velocity / BS;
|
||||
}
|
||||
} else {
|
||||
m_velocity += m_acceleration * dtime;
|
||||
m_pos += m_velocity * dtime;
|
||||
}
|
||||
|
@ -210,8 +213,8 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
|
|||
u16 amount, float time,
|
||||
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
|
||||
float minexptime, float maxexptime, float minsize, float maxsize,
|
||||
bool collisiondetection, bool vertical, video::ITexture *texture, u32 id,
|
||||
ParticleManager *p_manager) :
|
||||
bool collisiondetection, bool collision_removal, bool vertical,
|
||||
video::ITexture *texture, u32 id, ParticleManager *p_manager) :
|
||||
m_particlemanager(p_manager)
|
||||
{
|
||||
m_gamedef = gamedef;
|
||||
|
@ -230,6 +233,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
|
|||
m_minsize = minsize;
|
||||
m_maxsize = maxsize;
|
||||
m_collisiondetection = collisiondetection;
|
||||
m_collision_removal = collision_removal;
|
||||
m_vertical = vertical;
|
||||
m_texture = texture;
|
||||
m_time = 0;
|
||||
|
@ -277,6 +281,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
|
|||
exptime,
|
||||
size,
|
||||
m_collisiondetection,
|
||||
m_collision_removal,
|
||||
m_vertical,
|
||||
m_texture,
|
||||
v2f(0.0, 0.0),
|
||||
|
@ -317,6 +322,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
|
|||
exptime,
|
||||
size,
|
||||
m_collisiondetection,
|
||||
m_collision_removal,
|
||||
m_vertical,
|
||||
m_texture,
|
||||
v2f(0.0, 0.0),
|
||||
|
@ -446,6 +452,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
|
|||
event->add_particlespawner.minsize,
|
||||
event->add_particlespawner.maxsize,
|
||||
event->add_particlespawner.collisiondetection,
|
||||
event->add_particlespawner.collision_removal,
|
||||
event->add_particlespawner.vertical,
|
||||
texture,
|
||||
event->add_particlespawner.id,
|
||||
|
@ -480,6 +487,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
|
|||
event->spawn_particle.expirationtime,
|
||||
event->spawn_particle.size,
|
||||
event->spawn_particle.collisiondetection,
|
||||
event->spawn_particle.collision_removal,
|
||||
event->spawn_particle.vertical,
|
||||
texture,
|
||||
v2f(0.0, 0.0),
|
||||
|
@ -555,6 +563,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
|
|||
visual_size,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
texture,
|
||||
texpos,
|
||||
texsize);
|
||||
|
|
|
@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
struct ClientEvent;
|
||||
class ParticleManager;
|
||||
class ClientEnvironment;
|
||||
|
||||
class Particle : public scene::ISceneNode
|
||||
{
|
||||
|
@ -45,6 +46,7 @@ class Particle : public scene::ISceneNode
|
|||
float expirationtime,
|
||||
float size,
|
||||
bool collisiondetection,
|
||||
bool collision_removal,
|
||||
bool vertical,
|
||||
video::ITexture *texture,
|
||||
v2f texpos,
|
||||
|
@ -97,6 +99,7 @@ private:
|
|||
float m_size;
|
||||
u8 m_light;
|
||||
bool m_collisiondetection;
|
||||
bool m_collision_removal;
|
||||
bool m_vertical;
|
||||
v3s16 m_camera_offset;
|
||||
};
|
||||
|
@ -115,6 +118,7 @@ class ParticleSpawner
|
|||
float minexptime, float maxexptime,
|
||||
float minsize, float maxsize,
|
||||
bool collisiondetection,
|
||||
bool collision_removal,
|
||||
bool vertical,
|
||||
video::ITexture *texture,
|
||||
u32 id,
|
||||
|
@ -148,6 +152,7 @@ class ParticleSpawner
|
|||
video::ITexture *m_texture;
|
||||
std::vector<float> m_spawntimes;
|
||||
bool m_collisiondetection;
|
||||
bool m_collision_removal;
|
||||
bool m_vertical;
|
||||
|
||||
};
|
||||
|
|
|
@ -249,8 +249,8 @@ bool ScriptApiSecurity::isSecure(lua_State *L)
|
|||
|
||||
#define CHECK_FILE_ERR(ret, fp) \
|
||||
if (ret) { \
|
||||
if (fp) std::fclose(fp); \
|
||||
lua_pushfstring(L, "%s: %s", path, strerror(errno)); \
|
||||
if (fp) std::fclose(fp); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
|
@ -291,20 +291,12 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path)
|
|||
// Read the file
|
||||
int ret = std::fseek(fp, 0, SEEK_END);
|
||||
CHECK_FILE_ERR(ret, fp);
|
||||
if (ret) {
|
||||
std::fclose(fp);
|
||||
lua_pushfstring(L, "%s: %s", path, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t size = std::ftell(fp) - start;
|
||||
char *code = new char[size];
|
||||
ret = std::fseek(fp, start, SEEK_SET);
|
||||
CHECK_FILE_ERR(ret, fp);
|
||||
if (ret) {
|
||||
std::fclose(fp);
|
||||
lua_pushfstring(L, "%s: %s", path, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t num_read = std::fread(code, 1, size, fp);
|
||||
if (path) {
|
||||
std::fclose(fp);
|
||||
|
|
|
@ -39,11 +39,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
struct EnumString ModApiMapgen::es_BiomeTerrainType[] =
|
||||
{
|
||||
{BIOME_NORMAL, "normal"},
|
||||
{BIOME_LIQUID, "liquid"},
|
||||
{BIOME_NETHER, "nether"},
|
||||
{BIOME_AETHER, "aether"},
|
||||
{BIOME_FLAT, "flat"},
|
||||
{BIOMETYPE_NORMAL, "normal"},
|
||||
{BIOMETYPE_LIQUID, "liquid"},
|
||||
{BIOMETYPE_NETHER, "nether"},
|
||||
{BIOMETYPE_AETHER, "aether"},
|
||||
{BIOMETYPE_FLAT, "flat"},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
|
@ -371,7 +371,7 @@ Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef)
|
|||
return NULL;
|
||||
|
||||
BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
|
||||
ModApiMapgen::es_BiomeTerrainType, BIOME_NORMAL);
|
||||
ModApiMapgen::es_BiomeTerrainType, BIOMETYPE_NORMAL);
|
||||
Biome *b = BiomeManager::create(biometype);
|
||||
|
||||
b->name = getstringfield_default(L, index, "name", "");
|
||||
|
@ -528,24 +528,26 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
case MGOBJ_BIOMEMAP: {
|
||||
if (!mg->biomemap)
|
||||
if (!mg->biomegen)
|
||||
return 0;
|
||||
|
||||
lua_newtable(L);
|
||||
for (size_t i = 0; i != maplen; i++) {
|
||||
lua_pushinteger(L, mg->biomemap[i]);
|
||||
lua_pushinteger(L, mg->biomegen->biomemap[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
case MGOBJ_HEATMAP: {
|
||||
if (!mg->heatmap)
|
||||
if (!mg->biomegen || mg->biomegen->getType() != BIOMEGEN_ORIGINAL)
|
||||
return 0;
|
||||
|
||||
BiomeGenOriginal *bg = (BiomeGenOriginal *)mg->biomegen;
|
||||
|
||||
lua_newtable(L);
|
||||
for (size_t i = 0; i != maplen; i++) {
|
||||
lua_pushnumber(L, mg->heatmap[i]);
|
||||
lua_pushnumber(L, bg->heatmap[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
|
@ -553,12 +555,14 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
|
|||
}
|
||||
|
||||
case MGOBJ_HUMIDMAP: {
|
||||
if (!mg->humidmap)
|
||||
if (!mg->biomegen || mg->biomegen->getType() != BIOMEGEN_ORIGINAL)
|
||||
return 0;
|
||||
|
||||
BiomeGenOriginal *bg = (BiomeGenOriginal *)mg->biomegen;
|
||||
|
||||
lua_newtable(L);
|
||||
for (size_t i = 0; i != maplen; i++) {
|
||||
lua_pushnumber(L, mg->humidmap[i]);
|
||||
lua_pushnumber(L, bg->humidmap[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,13 +21,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "lua_api/l_internal.h"
|
||||
#include "common/c_converter.h"
|
||||
#include "server.h"
|
||||
#include "particles.h"
|
||||
|
||||
// add_particle({pos=, velocity=, acceleration=, expirationtime=,
|
||||
// size=, collisiondetection=, vertical=, texture=, player=})
|
||||
// size=, collisiondetection=, collision_removal=, vertical=,
|
||||
// texture=, player=})
|
||||
// pos/velocity/acceleration = {x=num, y=num, z=num}
|
||||
// expirationtime = num (seconds)
|
||||
// size = num
|
||||
// collisiondetection = bool
|
||||
// collision_removal = bool
|
||||
// vertical = bool
|
||||
// texture = e.g."default_wood.png"
|
||||
int ModApiParticles::l_add_particle(lua_State *L)
|
||||
|
@ -41,8 +44,8 @@ int ModApiParticles::l_add_particle(lua_State *L)
|
|||
float expirationtime, size;
|
||||
expirationtime = size = 1;
|
||||
|
||||
bool collisiondetection, vertical;
|
||||
collisiondetection = vertical = false;
|
||||
bool collisiondetection, vertical, collision_removal;
|
||||
collisiondetection = vertical = collision_removal = false;
|
||||
|
||||
std::string texture = "";
|
||||
std::string playername = "";
|
||||
|
@ -94,12 +97,14 @@ int ModApiParticles::l_add_particle(lua_State *L)
|
|||
size = getfloatfield_default(L, 1, "size", 1);
|
||||
collisiondetection = getboolfield_default(L, 1,
|
||||
"collisiondetection", collisiondetection);
|
||||
collision_removal = getboolfield_default(L, 1,
|
||||
"collision_removal", collision_removal);
|
||||
vertical = getboolfield_default(L, 1, "vertical", vertical);
|
||||
texture = getstringfield_default(L, 1, "texture", "");
|
||||
playername = getstringfield_default(L, 1, "playername", "");
|
||||
}
|
||||
getServer(L)->spawnParticle(playername, pos, vel, acc,
|
||||
expirationtime, size, collisiondetection, vertical, texture);
|
||||
getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
|
||||
collisiondetection, collision_removal, vertical, texture);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -110,6 +115,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
|
|||
// minexptime=, maxexptime=,
|
||||
// minsize=, maxsize=,
|
||||
// collisiondetection=,
|
||||
// collision_removal=,
|
||||
// vertical=,
|
||||
// texture=,
|
||||
// player=})
|
||||
|
@ -117,6 +123,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
|
|||
// minexptime/maxexptime = num (seconds)
|
||||
// minsize/maxsize = num
|
||||
// collisiondetection = bool
|
||||
// collision_removal = bool
|
||||
// vertical = bool
|
||||
// texture = e.g."default_wood.png"
|
||||
int ModApiParticles::l_add_particlespawner(lua_State *L)
|
||||
|
@ -129,8 +136,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
|
|||
minpos= maxpos= minvel= maxvel= minacc= maxacc= v3f(0, 0, 0);
|
||||
float time, minexptime, maxexptime, minsize, maxsize;
|
||||
time= minexptime= maxexptime= minsize= maxsize= 1;
|
||||
bool collisiondetection, vertical;
|
||||
collisiondetection= vertical= false;
|
||||
bool collisiondetection, vertical, collision_removal;
|
||||
collisiondetection = vertical = collision_removal = false;
|
||||
std::string texture = "";
|
||||
std::string playername = "";
|
||||
|
||||
|
@ -189,6 +196,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
|
|||
maxsize = getfloatfield_default(L, 1, "maxsize", maxsize);
|
||||
collisiondetection = getboolfield_default(L, 1,
|
||||
"collisiondetection", collisiondetection);
|
||||
collision_removal = getboolfield_default(L, 1,
|
||||
"collision_removal", collision_removal);
|
||||
vertical = getboolfield_default(L, 1, "vertical", vertical);
|
||||
texture = getstringfield_default(L, 1, "texture", "");
|
||||
playername = getstringfield_default(L, 1, "playername", "");
|
||||
|
@ -201,6 +210,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
|
|||
minexptime, maxexptime,
|
||||
minsize, maxsize,
|
||||
collisiondetection,
|
||||
collision_removal,
|
||||
vertical,
|
||||
texture, playername);
|
||||
lua_pushnumber(L, id);
|
||||
|
|
|
@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "filesys.h"
|
||||
#include "settings.h"
|
||||
#include "util/auth.h"
|
||||
#include "util/base64.h"
|
||||
#include <algorithm>
|
||||
|
||||
// log([level,] text)
|
||||
|
@ -245,6 +246,35 @@ int ModApiUtil::l_get_hit_params(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
// check_password_entry(name, entry, password)
|
||||
int ModApiUtil::l_check_password_entry(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
std::string name = luaL_checkstring(L, 1);
|
||||
std::string entry = luaL_checkstring(L, 2);
|
||||
std::string password = luaL_checkstring(L, 3);
|
||||
|
||||
if (base64_is_valid(entry)) {
|
||||
std::string hash = translate_password(name, password);
|
||||
lua_pushboolean(L, hash == entry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string salt;
|
||||
std::string verifier;
|
||||
|
||||
if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
|
||||
// invalid format
|
||||
warningstream << "Invalid password format for " << name << std::endl;
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
std::string gen_verifier = generate_srp_verifier(name, password, salt);
|
||||
|
||||
lua_pushboolean(L, gen_verifier == verifier);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get_password_hash(name, raw_password)
|
||||
int ModApiUtil::l_get_password_hash(lua_State *L)
|
||||
{
|
||||
|
@ -320,6 +350,34 @@ int ModApiUtil::l_decompress(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
// encode_base64(string)
|
||||
int ModApiUtil::l_encode_base64(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
size_t size;
|
||||
const char *data = luaL_checklstring(L, 1, &size);
|
||||
|
||||
std::string out = base64_encode((const unsigned char *)(data), size);
|
||||
|
||||
lua_pushlstring(L, out.data(), out.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// decode_base64(string)
|
||||
int ModApiUtil::l_decode_base64(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
size_t size;
|
||||
const char *data = luaL_checklstring(L, 1, &size);
|
||||
|
||||
std::string out = base64_decode(std::string(data, size));
|
||||
|
||||
lua_pushlstring(L, out.data(), out.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// mkdir(path)
|
||||
int ModApiUtil::l_mkdir(lua_State *L)
|
||||
{
|
||||
|
@ -420,6 +478,7 @@ void ModApiUtil::Initialize(lua_State *L, int top)
|
|||
API_FCT(get_dig_params);
|
||||
API_FCT(get_hit_params);
|
||||
|
||||
API_FCT(check_password_entry);
|
||||
API_FCT(get_password_hash);
|
||||
|
||||
API_FCT(is_yes);
|
||||
|
@ -433,6 +492,9 @@ void ModApiUtil::Initialize(lua_State *L, int top)
|
|||
API_FCT(get_dir_list);
|
||||
|
||||
API_FCT(request_insecure_environment);
|
||||
|
||||
API_FCT(encode_base64);
|
||||
API_FCT(decode_base64);
|
||||
}
|
||||
|
||||
void ModApiUtil::InitializeAsync(AsyncEngine& engine)
|
||||
|
@ -459,4 +521,7 @@ void ModApiUtil::InitializeAsync(AsyncEngine& engine)
|
|||
|
||||
ASYNC_API_FCT(mkdir);
|
||||
ASYNC_API_FCT(get_dir_list);
|
||||
|
||||
ASYNC_API_FCT(encode_base64);
|
||||
ASYNC_API_FCT(decode_base64);
|
||||
}
|
||||
|
|
|
@ -74,6 +74,9 @@ private:
|
|||
// get_hit_params(groups, tool_capabilities[, time_from_last_punch])
|
||||
static int l_get_hit_params(lua_State *L);
|
||||
|
||||
// check_password_entry(name, entry, password)
|
||||
static int l_check_password_entry(lua_State *L);
|
||||
|
||||
// get_password_hash(name, raw_password)
|
||||
static int l_get_password_hash(lua_State *L);
|
||||
|
||||
|
@ -99,21 +102,11 @@ private:
|
|||
// request_insecure_environment()
|
||||
static int l_request_insecure_environment(lua_State *L);
|
||||
|
||||
#ifdef USE_CURL
|
||||
// Helpers for HTTP fetch functions
|
||||
static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req);
|
||||
static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res);
|
||||
|
||||
// http_fetch_async({url=, timeout=, post_data=})
|
||||
static int l_http_fetch_async(lua_State *L);
|
||||
|
||||
// http_fetch_async_get(handle)
|
||||
static int l_http_fetch_async_get(lua_State *L);
|
||||
|
||||
// http_fetch_sync({url=, timeout=, post_data=})
|
||||
static int l_http_fetch_sync(lua_State *L);
|
||||
#endif
|
||||
// encode_base64(string)
|
||||
static int l_encode_base64(lua_State *L);
|
||||
|
||||
// decode_base64(string)
|
||||
static int l_decode_base64(lua_State *L);
|
||||
|
||||
public:
|
||||
static void Initialize(lua_State *L, int top);
|
||||
|
|
|
@ -1673,7 +1673,8 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
|
|||
// Spawns a particle on peer with peer_id
|
||||
void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
|
||||
float expirationtime, float size, bool collisiondetection,
|
||||
bool vertical, std::string texture)
|
||||
bool collision_removal,
|
||||
bool vertical, const std::string &texture)
|
||||
{
|
||||
DSTACK(FUNCTION_NAME);
|
||||
|
||||
|
@ -1683,6 +1684,7 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
|
|||
<< size << collisiondetection;
|
||||
pkt.putLongString(texture);
|
||||
pkt << vertical;
|
||||
pkt << collision_removal;
|
||||
|
||||
if (peer_id != PEER_ID_INEXISTENT) {
|
||||
Send(&pkt);
|
||||
|
@ -1695,7 +1697,8 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
|
|||
// Adds a ParticleSpawner on peer with peer_id
|
||||
void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
|
||||
v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
|
||||
float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
|
||||
float minsize, float maxsize, bool collisiondetection, bool collision_removal,
|
||||
bool vertical, const std::string &texture, u32 id)
|
||||
{
|
||||
DSTACK(FUNCTION_NAME);
|
||||
|
||||
|
@ -1708,6 +1711,7 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
|
|||
pkt.putLongString(texture);
|
||||
|
||||
pkt << id << vertical;
|
||||
pkt << collision_removal;
|
||||
|
||||
if (peer_id != PEER_ID_INEXISTENT) {
|
||||
Send(&pkt);
|
||||
|
@ -3160,7 +3164,8 @@ void Server::notifyPlayers(const std::wstring &msg)
|
|||
void Server::spawnParticle(const std::string &playername, v3f pos,
|
||||
v3f velocity, v3f acceleration,
|
||||
float expirationtime, float size, bool
|
||||
collisiondetection, bool vertical, const std::string &texture)
|
||||
collisiondetection, bool collision_removal,
|
||||
bool vertical, const std::string &texture)
|
||||
{
|
||||
// m_env will be NULL if the server is initializing
|
||||
if (!m_env)
|
||||
|
@ -3175,13 +3180,15 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
|
|||
}
|
||||
|
||||
SendSpawnParticle(peer_id, pos, velocity, acceleration,
|
||||
expirationtime, size, collisiondetection, vertical, texture);
|
||||
expirationtime, size, collisiondetection,
|
||||
collision_removal, vertical, texture);
|
||||
}
|
||||
|
||||
u32 Server::addParticleSpawner(u16 amount, float spawntime,
|
||||
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
|
||||
float minexptime, float maxexptime, float minsize, float maxsize,
|
||||
bool collisiondetection, bool vertical, const std::string &texture,
|
||||
bool collisiondetection, bool collision_removal,
|
||||
bool vertical, const std::string &texture,
|
||||
const std::string &playername)
|
||||
{
|
||||
// m_env will be NULL if the server is initializing
|
||||
|
@ -3200,7 +3207,7 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
|
|||
SendAddParticleSpawner(peer_id, amount, spawntime,
|
||||
minpos, maxpos, minvel, maxvel, minacc, maxacc,
|
||||
minexptime, maxexptime, minsize, maxsize,
|
||||
collisiondetection, vertical, texture, id);
|
||||
collisiondetection, collision_removal, vertical, texture, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
|
12
src/server.h
12
src/server.h
|
@ -275,7 +275,8 @@ public:
|
|||
void spawnParticle(const std::string &playername,
|
||||
v3f pos, v3f velocity, v3f acceleration,
|
||||
float expirationtime, float size,
|
||||
bool collisiondetection, bool vertical, const std::string &texture);
|
||||
bool collisiondetection, bool collision_removal,
|
||||
bool vertical, const std::string &texture);
|
||||
|
||||
u32 addParticleSpawner(u16 amount, float spawntime,
|
||||
v3f minpos, v3f maxpos,
|
||||
|
@ -283,7 +284,8 @@ public:
|
|||
v3f minacc, v3f maxacc,
|
||||
float minexptime, float maxexptime,
|
||||
float minsize, float maxsize,
|
||||
bool collisiondetection, bool vertical, const std::string &texture,
|
||||
bool collisiondetection, bool collision_removal,
|
||||
bool vertical, const std::string &texture,
|
||||
const std::string &playername);
|
||||
|
||||
void deleteParticleSpawner(const std::string &playername, u32 id);
|
||||
|
@ -456,7 +458,8 @@ private:
|
|||
v3f minacc, v3f maxacc,
|
||||
float minexptime, float maxexptime,
|
||||
float minsize, float maxsize,
|
||||
bool collisiondetection, bool vertical, std::string texture, u32 id);
|
||||
bool collisiondetection, bool collision_removal,
|
||||
bool vertical, const std::string &texture, u32 id);
|
||||
|
||||
void SendDeleteParticleSpawner(u16 peer_id, u32 id);
|
||||
|
||||
|
@ -464,7 +467,8 @@ private:
|
|||
void SendSpawnParticle(u16 peer_id,
|
||||
v3f pos, v3f velocity, v3f acceleration,
|
||||
float expirationtime, float size,
|
||||
bool collisiondetection, bool vertical, std::string texture);
|
||||
bool collisiondetection, bool collision_removal,
|
||||
bool vertical, const std::string &texture);
|
||||
|
||||
u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas);
|
||||
void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true);
|
||||
|
|
|
@ -345,9 +345,11 @@ void TerminalChatConsole::step(int ch)
|
|||
if (p.first > m_log_level)
|
||||
continue;
|
||||
|
||||
m_chat_backend.addMessage(
|
||||
utf8_to_wide(Logger::getLevelLabel(p.first)),
|
||||
utf8_to_wide(p.second));
|
||||
std::wstring error_message = utf8_to_wide(Logger::getLevelLabel(p.first));
|
||||
if (!g_settings->getBool("disable_escape_sequences")) {
|
||||
error_message = L"\x1b(c@red)" + error_message + L"\x1b(c@white)";
|
||||
}
|
||||
m_chat_backend.addMessage(error_message, utf8_to_wide(p.second));
|
||||
}
|
||||
|
||||
// handle input
|
||||
|
@ -438,7 +440,7 @@ void TerminalChatConsole::draw_text()
|
|||
continue;
|
||||
for (u32 i = 0; i < line.fragments.size(); ++i) {
|
||||
const ChatFormattedFragment& fragment = line.fragments[i];
|
||||
addstr(wide_to_utf8(fragment.text).c_str());
|
||||
addstr(wide_to_utf8(fragment.text.getString()).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ set(UTIL_SRCS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/auth.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/base64.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/directiontables.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/enriched_string.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/numeric.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pointedthing.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/serialize.cpp
|
||||
|
|
|
@ -45,6 +45,6 @@ std::string encode_srp_verifier(const std::string &verifier,
|
|||
/// Reads the DB-formatted SRP verifier and gets the verifier
|
||||
/// and salt components.
|
||||
bool decode_srp_verifier_and_salt(const std::string &encoded,
|
||||
std::string *salt, std::string *bytes_v);
|
||||
std::string *verifier, std::string *salt);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
Copyright (C) 2013 xyz, Ilya Zhuravlev <whatever@xyz.is>
|
||||
Copyright (C) 2016 Nore, Nathanaël Courant <nore@mesecons.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "enriched_string.h"
|
||||
#include "util/string.h"
|
||||
#include "log.h"
|
||||
using namespace irr::video;
|
||||
|
||||
EnrichedString::EnrichedString()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
EnrichedString::EnrichedString(const std::wstring &string,
|
||||
const std::vector<SColor> &colors):
|
||||
m_string(string),
|
||||
m_colors(colors),
|
||||
m_has_background(false)
|
||||
{}
|
||||
|
||||
EnrichedString::EnrichedString(const std::wstring &s, const SColor &color)
|
||||
{
|
||||
clear();
|
||||
addAtEnd(s, color);
|
||||
}
|
||||
|
||||
EnrichedString::EnrichedString(const wchar_t *str, const SColor &color)
|
||||
{
|
||||
clear();
|
||||
addAtEnd(std::wstring(str), color);
|
||||
}
|
||||
|
||||
void EnrichedString::operator=(const wchar_t *str)
|
||||
{
|
||||
clear();
|
||||
addAtEnd(std::wstring(str), SColor(255, 255, 255, 255));
|
||||
}
|
||||
|
||||
void EnrichedString::addAtEnd(const std::wstring &s, const SColor &initial_color)
|
||||
{
|
||||
SColor color(initial_color);
|
||||
size_t i = 0;
|
||||
while (i < s.length()) {
|
||||
if (s[i] != L'\x1b') {
|
||||
m_string += s[i];
|
||||
m_colors.push_back(color);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
size_t start_index = i;
|
||||
size_t length;
|
||||
if (i == s.length()) {
|
||||
break;
|
||||
}
|
||||
if (s[i] == L'(') {
|
||||
++i;
|
||||
++start_index;
|
||||
while (i < s.length() && s[i] != L')') {
|
||||
if (s[i] == L'\\') {
|
||||
++i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
length = i - start_index;
|
||||
++i;
|
||||
} else {
|
||||
++i;
|
||||
length = 1;
|
||||
}
|
||||
std::wstring escape_sequence(s, start_index, length);
|
||||
std::vector<std::wstring> parts = split(escape_sequence, L'@');
|
||||
if (parts[0] == L"c") {
|
||||
if (parts.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
parseColorString(wide_to_utf8(parts[1]), color, true);
|
||||
} else if (parts[0] == L"b") {
|
||||
if (parts.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
parseColorString(wide_to_utf8(parts[1]), m_background, true);
|
||||
m_has_background = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
void EnrichedString::addChar(const EnrichedString &source, size_t i)
|
||||
{
|
||||
m_string += source.m_string[i];
|
||||
m_colors.push_back(source.m_colors[i]);
|
||||
}
|
||||
|
||||
void EnrichedString::addCharNoColor(wchar_t c)
|
||||
{
|
||||
m_string += c;
|
||||
if (m_colors.empty()) {
|
||||
m_colors.push_back(SColor(255, 255, 255, 255));
|
||||
} else {
|
||||
m_colors.push_back(m_colors[m_colors.size() - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
EnrichedString EnrichedString::operator+(const EnrichedString &other) const
|
||||
{
|
||||
std::vector<SColor> result;
|
||||
result.insert(result.end(), m_colors.begin(), m_colors.end());
|
||||
result.insert(result.end(), other.m_colors.begin(), other.m_colors.end());
|
||||
return EnrichedString(m_string + other.m_string, result);
|
||||
}
|
||||
|
||||
void EnrichedString::operator+=(const EnrichedString &other)
|
||||
{
|
||||
m_string += other.m_string;
|
||||
m_colors.insert(m_colors.end(), other.m_colors.begin(), other.m_colors.end());
|
||||
}
|
||||
|
||||
EnrichedString EnrichedString::substr(size_t pos, size_t len) const
|
||||
{
|
||||
if (pos == m_string.length()) {
|
||||
return EnrichedString();
|
||||
}
|
||||
if (len == std::string::npos || pos + len > m_string.length()) {
|
||||
return EnrichedString(
|
||||
m_string.substr(pos, std::string::npos),
|
||||
std::vector<SColor>(m_colors.begin() + pos, m_colors.end())
|
||||
);
|
||||
} else {
|
||||
return EnrichedString(
|
||||
m_string.substr(pos, len),
|
||||
std::vector<SColor>(m_colors.begin() + pos, m_colors.begin() + pos + len)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const wchar_t *EnrichedString::c_str() const
|
||||
{
|
||||
return m_string.c_str();
|
||||
}
|
||||
|
||||
const std::vector<SColor> &EnrichedString::getColors() const
|
||||
{
|
||||
return m_colors;
|
||||
}
|
||||
|
||||
const std::wstring &EnrichedString::getString() const
|
||||
{
|
||||
return m_string;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright (C) 2013 xyz, Ilya Zhuravlev <whatever@xyz.is>
|
||||
Copyright (C) 2016 Nore, Nathanaël Courant <nore@mesecons.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef ENRICHEDSTRING_HEADER
|
||||
#define ENRICHEDSTRING_HEADER
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <SColor.h>
|
||||
|
||||
class EnrichedString {
|
||||
public:
|
||||
EnrichedString();
|
||||
EnrichedString(const std::wstring &s,
|
||||
const irr::video::SColor &color = irr::video::SColor(255, 255, 255, 255));
|
||||
EnrichedString(const wchar_t *str,
|
||||
const irr::video::SColor &color = irr::video::SColor(255, 255, 255, 255));
|
||||
EnrichedString(const std::wstring &string,
|
||||
const std::vector<irr::video::SColor> &colors);
|
||||
void operator=(const wchar_t *str);
|
||||
void addAtEnd(const std::wstring &s, const irr::video::SColor &color);
|
||||
|
||||
// Adds the character source[i] at the end.
|
||||
// An EnrichedString should always be able to be copied
|
||||
// to the end of an existing EnrichedString that way.
|
||||
void addChar(const EnrichedString &source, size_t i);
|
||||
|
||||
// Adds a single character at the end, without specifying its
|
||||
// color. The color used will be the one from the last character.
|
||||
void addCharNoColor(wchar_t c);
|
||||
|
||||
EnrichedString substr(size_t pos = 0, size_t len = std::string::npos) const;
|
||||
EnrichedString operator+(const EnrichedString &other) const;
|
||||
void operator+=(const EnrichedString &other);
|
||||
const wchar_t *c_str() const;
|
||||
const std::vector<irr::video::SColor> &getColors() const;
|
||||
const std::wstring &getString() const;
|
||||
inline bool operator==(const EnrichedString &other) const
|
||||
{
|
||||
return (m_string == other.m_string && m_colors == other.m_colors);
|
||||
}
|
||||
inline bool operator!=(const EnrichedString &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
inline void clear()
|
||||
{
|
||||
m_string.clear();
|
||||
m_colors.clear();
|
||||
m_has_background = false;
|
||||
}
|
||||
inline bool empty() const
|
||||
{
|
||||
return m_string.empty();
|
||||
}
|
||||
inline size_t size() const
|
||||
{
|
||||
return m_string.size();
|
||||
}
|
||||
inline bool hasBackground() const
|
||||
{
|
||||
return m_has_background;
|
||||
}
|
||||
inline irr::video::SColor getBackground() const
|
||||
{
|
||||
return m_background;
|
||||
}
|
||||
private:
|
||||
std::wstring m_string;
|
||||
std::vector<irr::video::SColor> m_colors;
|
||||
bool m_has_background;
|
||||
irr::video::SColor m_background;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -519,6 +519,38 @@ std::basic_string<T> unescape_enriched(const std::basic_string<T> &s)
|
|||
return output;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<std::basic_string<T> > split(const std::basic_string<T> &s, T delim)
|
||||
{
|
||||
std::vector<std::basic_string<T> > tokens;
|
||||
|
||||
std::basic_string<T> current;
|
||||
bool last_was_escape = false;
|
||||
for (size_t i = 0; i < s.length(); i++) {
|
||||
T si = s[i];
|
||||
if (last_was_escape) {
|
||||
current += '\\';
|
||||
current += si;
|
||||
last_was_escape = false;
|
||||
} else {
|
||||
if (si == delim) {
|
||||
tokens.push_back(current);
|
||||
current = std::basic_string<T>();
|
||||
last_was_escape = false;
|
||||
} else if (si == '\\') {
|
||||
last_was_escape = true;
|
||||
} else {
|
||||
current += si;
|
||||
last_was_escape = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//push last element
|
||||
tokens.push_back(current);
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all characters in \p to_check are a decimal digits.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue