From 75862e33b6bfe6b3805310152c66af1430ac3666 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 13 Apr 2025 16:07:01 +0100 Subject: [PATCH 001/131] ContentDB: Add reviews tab (#15254) --- LICENSE.txt | 5 ++ builtin/async/mainmenu.lua | 13 +++ builtin/mainmenu/content/contentdb.lua | 93 +++++++++----------- builtin/mainmenu/content/dlg_package.lua | 65 +++++++++++--- textures/base/pack/contentdb_neutral.png | Bin 0 -> 169 bytes textures/base/pack/contentdb_thumb_down.png | Bin 0 -> 348 bytes textures/base/pack/contentdb_thumb_up.png | Bin 0 -> 411 bytes 7 files changed, 110 insertions(+), 66 deletions(-) create mode 100644 textures/base/pack/contentdb_neutral.png create mode 100644 textures/base/pack/contentdb_thumb_down.png create mode 100644 textures/base/pack/contentdb_thumb_up.png diff --git a/LICENSE.txt b/LICENSE.txt index 772f86728..5c01e2c3b 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -106,6 +106,11 @@ grorp: textures/base/pack/place_btn.png derived by editing the text in aux1_btn.svg +Material Design, Google (Apache license v2.0): + textures/base/pack/contentdb_thumb_up.png + textures/base/pack/contentdb_thumb_down.png + textures/base/pack/contentdb_neutral.png + License of Luanti source code ------------------------------- diff --git a/builtin/async/mainmenu.lua b/builtin/async/mainmenu.lua index 0e9c222d1..c1d8618b4 100644 --- a/builtin/async/mainmenu.lua +++ b/builtin/async/mainmenu.lua @@ -1,5 +1,6 @@ core.log("info", "Initializing asynchronous environment") + function core.job_processor(func, serialized_param) local param = core.deserialize(serialized_param) @@ -7,3 +8,15 @@ function core.job_processor(func, serialized_param) return retval or core.serialize(nil) end + + +function core.get_http_accept_languages() + local languages + local current_language = core.get_language() + if current_language ~= "" then + languages = { current_language, "en;q=0.8" } + else + languages = { "en" } + end + return "Accept-Language: " .. table.concat(languages, ", ") +end diff --git a/builtin/mainmenu/content/contentdb.lua b/builtin/mainmenu/content/contentdb.lua index 963400a12..856924bd4 100644 --- a/builtin/mainmenu/content/contentdb.lua +++ b/builtin/mainmenu/content/contentdb.lua @@ -41,6 +41,7 @@ contentdb = { REASON_DEPENDENCY = "dependency", } +-- API documentation: https://content.luanti.org/help/api/ local function get_download_url(package, reason) local base_url = core.settings:get("contentdb_url") @@ -398,7 +399,6 @@ local function fetch_pkgs() local url = base_url .. "/api/packages/?type=mod&type=game&type=txp&protocol_version=" .. core.get_max_supp_proto() .. "&engine_version=" .. core.urlencode(version.string) - for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do item = item:trim() if item ~= "" then @@ -406,19 +406,11 @@ local function fetch_pkgs() end end - local languages - local current_language = core.get_language() - if current_language ~= "" then - languages = { current_language, "en;q=0.8" } - else - languages = { "en" } - end - local http = core.get_http_api() local response = http.fetch_sync({ url = url, extra_headers = { - "Accept-Language: " .. table.concat(languages, ", ") + core.get_http_accept_languages() }, }) if not response.succeeded then @@ -596,57 +588,54 @@ function contentdb.filter_packages(query, by_type) end -function contentdb.get_full_package_info(package, callback) - assert(package) - if package.full_info then - callback(package.full_info) - return - end - - local function fetch(params) - local version = core.get_version() - local base_url = core.settings:get("contentdb_url") - - local languages - local current_language = core.get_language() - if current_language ~= "" then - languages = { current_language, "en;q=0.8" } - else - languages = { "en" } +local function get_package_info(key, path) + return function(package, callback) + assert(package) + if package[key] then + callback(package[key]) + return end - local url = base_url .. - "/api/packages/" .. params.package.url_part .. "/for-client/?" .. - "protocol_version=" .. core.urlencode(core.get_max_supp_proto()) .. - "&engine_version=" .. core.urlencode(version.string) .. - "&formspec_version=" .. core.urlencode(core.get_formspec_version()) .. - "&include_images=false" - local http = core.get_http_api() - local response = http.fetch_sync({ - url = url, - extra_headers = { - "Accept-Language: " .. table.concat(languages, ", ") - }, - }) - if not response.succeeded then - return nil + local function fetch(params) + local version = core.get_version() + local base_url = core.settings:get("contentdb_url") + local url = base_url .. + "/api/packages/" .. params.package.url_part .. params.path .. "?" .. + "protocol_version=" .. core.urlencode(core.get_max_supp_proto()) .. + "&engine_version=" .. core.urlencode(version.string) .. + "&formspec_version=" .. core.urlencode(core.get_formspec_version()) .. + "&include_images=false" + local http = core.get_http_api() + local response = http.fetch_sync({ + url = url, + extra_headers = { + core.get_http_accept_languages() + }, + }) + if not response.succeeded then + return nil + end + + return core.parse_json(response.data) end - return core.parse_json(response.data) - end + local function my_callback(value) + package[key] = value + callback(value) + end - local function my_callback(value) - package.full_info = value - callback(value) - end - - if not core.handle_async(fetch, { package = package }, my_callback) then - core.log("error", "ERROR: async event failed") - callback(nil) + if not core.handle_async(fetch, { package = package, path = path }, my_callback) then + core.log("error", "ERROR: async event failed") + callback(nil) + end end end +contentdb.get_full_package_info = get_package_info("full_info", "/for-client/") +contentdb.get_package_reviews = get_package_info("reviews", "/for-client/reviews/") + + function contentdb.get_formspec_padding() -- Padding is increased on Android to account for notches -- TODO: use Android API to determine size of cut outs diff --git a/builtin/mainmenu/content/dlg_package.lua b/builtin/mainmenu/content/dlg_package.lua index 7edbf678f..d8fc057c1 100644 --- a/builtin/mainmenu/content/dlg_package.lua +++ b/builtin/mainmenu/content/dlg_package.lua @@ -32,6 +32,7 @@ end local function get_formspec(data) + local package = data.package local window_padding = contentdb.get_formspec_padding() local size = contentdb.get_formspec_size() size.x = math.min(size.x, 20) @@ -42,7 +43,7 @@ local function get_formspec(data) if not data.loading and not data.loading_error then data.loading = true - contentdb.get_full_package_info(data.package, function(info) + contentdb.get_full_package_info(package, function(info) data.loading = false if info == nil then @@ -61,7 +62,7 @@ local function get_formspec(data) -- check to see if that happened if not data.info then if data.loading_error then - return get_info_formspec(size, window_padding, fgettext("No packages could be retrieved")) + return get_info_formspec(size, window_padding, fgettext("Error loading package information")) end return get_info_formspec(size, window_padding, fgettext("Loading...")) end @@ -103,15 +104,15 @@ local function get_formspec(data) local left_button_rect = "0,0;2.875,1" local right_button_rect = "3.125,0;2.875,1" - if data.package.downloading then + if package.downloading then formspec[#formspec + 1] = "animated_image[5,0;1,1;downloading;" formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir) formspec[#formspec + 1] = "cdb_downloading.png;3;400;]" - elseif data.package.queued then + elseif package.queued then formspec[#formspec + 1] = "style[queued;border=false]" formspec[#formspec + 1] = "image_button[5,0;1,1;" .. core.formspec_escape(defaulttexturedir) formspec[#formspec + 1] = "cdb_queued.png;queued;]" - elseif not data.package.path then + elseif not package.path then formspec[#formspec + 1] = "style[install;bgcolor=green]" formspec[#formspec + 1] = "button[" formspec[#formspec + 1] = right_button_rect @@ -119,7 +120,7 @@ local function get_formspec(data) formspec[#formspec + 1] = fgettext("Install [$1]", info.download_size) formspec[#formspec + 1] = "]" else - if data.package.installed_release < data.package.release then + if package.installed_release < package.release then -- The install_ action also handles updating formspec[#formspec + 1] = "style[install;bgcolor=#28ccdf]" formspec[#formspec + 1] = "button[" @@ -137,10 +138,12 @@ local function get_formspec(data) formspec[#formspec + 1] = "]" end + local review_count = info.reviews.positive + info.reviews.neutral + info.reviews.negative local current_tab = data.current_tab or 1 local tab_titles = { fgettext("Description"), fgettext("Information"), + fgettext("Reviews") .. core.formspec_escape(" [" .. review_count .. "]"), } local tab_body_height = bottom_buttons_y - 2.8 @@ -162,8 +165,8 @@ local function get_formspec(data) local winfo = core.get_window_info() local fs_to_px = winfo.size.x / winfo.max_formspec_size.x for i, ss in ipairs(info.screenshots) do - local path = get_screenshot(data.package, ss.url, 2) - hypertext = hypertext .. "" if i ~= #info.screenshots then @@ -194,22 +197,54 @@ local function get_formspec(data) hypertext = hypertext .. "\n\n" .. info.long_description.body + -- Fix the path to blank.png. This is needed for bullet indentation. hypertext = hypertext:gsub("", + "") + hypertext = hypertext:gsub("", + "") + hypertext = hypertext:gsub("", + "") + table.insert_all(formspec, { + "hypertext[0,0;", W, ",", tab_body_height - 0.375, + ";reviews;", core.formspec_escape(hypertext), "]", + }) + elseif data.reviews_error then + table.insert_all(formspec, {"label[2,2;", fgettext("Error loading reviews"), "]"} ) + else + table.insert_all(formspec, {"label[2,2;", fgettext("Loading..."), "]"} ) + end else error("Unknown tab " .. current_tab) end @@ -269,9 +304,10 @@ local function handle_submit(this, fields) end if fields.open_contentdb then - local url = ("%s/packages/%s/?protocol_version=%d"):format( - core.settings:get("contentdb_url"), package.url_part, - core.get_max_supp_proto()) + local version = core.get_version() + local url = core.settings:get("contentdb_url") .. "/packages/" .. package.url_part .. + "/?protocol_version=" .. core.urlencode(core.get_max_supp_proto()) .. + "&engine_version=" .. core.urlencode(version.string) core.open_url(url) return true end @@ -295,7 +331,8 @@ local function handle_submit(this, fields) end if handle_hypertext_event(this, fields.desc, info.long_description) or - handle_hypertext_event(this, fields.info, info.info_hypertext) then + handle_hypertext_event(this, fields.info, info.info_hypertext) or + (package.reviews and handle_hypertext_event(this, fields.reviews, package.reviews)) then return true end end diff --git a/textures/base/pack/contentdb_neutral.png b/textures/base/pack/contentdb_neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..a73e30bcd34066231558709f701435395026b2ee GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(a8A!&?{Fw`+_yc@GT!HlSS8rdwe*668>ld%y zuKD}b4=BV^666=m5L(|b=XcHxAm7!~#W5tK@$DH$-UA8(3`nEQl-ild6t3eGAn zDy}QIskrMntl+5Pq~fgNvVyCMn~M7q4l0f+PAfR8xTv_QxUJy+103G`XIK{SWHl>u zVb08n`JCpC`MUKj6F!)CW`A>j<&D`fTjr1A<&|Z^2lLMCneXCtV8?8k4YN%6D&Azs z&g_}DIrotrvt>5SGU02UF!IjqnKx#~d=-x)8)ljC!Mrnj_zrRxCw9!1*)Yq54=i{V uNA}DcJ?zD#Vqw|Nn2Ic!IWa$&e`B7Vr4%?A@oSO*0000ufGF(HyNCAsbdCI3ApSuR7c}S=?#GzF|Yv;iLd!DIRE5GeTnc)K+Adg4BXk_?`%elF{r5}E+JOt9Pl literal 0 HcmV?d00001 From 60c47c51e0b41bc99cb78654a65688c0ad6978ef Mon Sep 17 00:00:00 2001 From: DS Date: Mon, 14 Apr 2025 17:18:21 +0200 Subject: [PATCH 002/131] Optimize name-id-lookup for MapBlock serialization (#16000) --- src/mapblock.cpp | 86 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 27 deletions(-) diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 6987c36a6..348c02a1e 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -24,6 +24,55 @@ #include "util/serialize.h" #include "util/basic_macros.h" +// Like a std::unordered_map, but faster. +// +// Unassigned entries are marked with 0xFFFF. +// +// The static memory requires about 65535 * 2 bytes RAM in order to be +// sure we can handle all content ids. +class IdIdMapping +{ + static_assert(sizeof(content_t) == 2, "content_t must be 16-bit"); + +private: + std::unique_ptr m_mapping; + std::vector m_dirty; + +public: + IdIdMapping() + { + m_mapping = std::make_unique(CONTENT_MAX + 1); + memset(m_mapping.get(), 0xFF, (CONTENT_MAX + 1) * sizeof(content_t)); + } + + DISABLE_CLASS_COPY(IdIdMapping) + + content_t get(content_t k) const + { + return m_mapping[k]; + } + + void set(content_t k, content_t v) + { + m_mapping[k] = v; + m_dirty.push_back(k); + } + + void clear() + { + for (auto k : m_dirty) + m_mapping[k] = 0xFFFF; + m_dirty.clear(); + } + + static IdIdMapping &giveClearedThreadLocalInstance() + { + static thread_local IdIdMapping tl_ididmapping; + tl_ididmapping.clear(); + return tl_ididmapping; + } +}; + static const char *modified_reason_strings[] = { "reallocate or initial", "setIsUnderground", @@ -212,16 +261,7 @@ void MapBlock::expireIsAirCache() static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes, const NodeDefManager *nodedef) { - // The static memory requires about 65535 * 2 bytes RAM in order to be - // sure we can handle all content ids. But it's absolutely worth it as it's - // a speedup of 4 for one of the major time consuming functions on storing - // mapblocks. - thread_local std::unique_ptr mapping; - static_assert(sizeof(content_t) == 2, "content_t must be 16-bit"); - if (!mapping) - mapping = std::make_unique(CONTENT_MAX + 1); - - memset(mapping.get(), 0xFF, (CONTENT_MAX + 1) * sizeof(content_t)); + IdIdMapping &mapping = IdIdMapping::giveClearedThreadLocalInstance(); content_t id_counter = 0; for (u32 i = 0; i < MapBlock::nodecount; i++) { @@ -229,12 +269,12 @@ static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes, content_t id = CONTENT_IGNORE; // Try to find an existing mapping - if (mapping[global_id] != 0xFFFF) { - id = mapping[global_id]; + if (auto found = mapping.get(global_id); found != 0xFFFF) { + id = found; } else { // We have to assign a new mapping id = id_counter++; - mapping[global_id] = id; + mapping.set(global_id, id); const auto &name = nodedef->get(global_id).name; nimap->set(id, name); @@ -259,25 +299,20 @@ static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes, std::unordered_set unnamed_contents; std::unordered_set unallocatable_contents; - bool previous_exists = false; - content_t previous_local_id = CONTENT_IGNORE; - content_t previous_global_id = CONTENT_IGNORE; + // Used to cache local to global id lookup. + IdIdMapping &mapping_cache = IdIdMapping::giveClearedThreadLocalInstance(); for (u32 i = 0; i < MapBlock::nodecount; i++) { content_t local_id = nodes[i].getContent(); - // If previous node local_id was found and same than before, don't lookup maps - // apply directly previous resolved id - // This permits to massively improve loading performance when nodes are similar - // example: default:air, default:stone are massively present - if (previous_exists && local_id == previous_local_id) { - nodes[i].setContent(previous_global_id); + + if (auto found = mapping_cache.get(local_id); found != 0xFFFF) { + nodes[i].setContent(found); continue; } std::string name; if (!nimap->getName(local_id, name)) { unnamed_contents.insert(local_id); - previous_exists = false; continue; } @@ -286,16 +321,13 @@ static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes, global_id = gamedef->allocateUnknownNodeId(name); if (global_id == CONTENT_IGNORE) { unallocatable_contents.insert(name); - previous_exists = false; continue; } } nodes[i].setContent(global_id); // Save previous node local_id & global_id result - previous_local_id = local_id; - previous_global_id = global_id; - previous_exists = true; + mapping_cache.set(local_id, global_id); } for (const content_t c: unnamed_contents) { From bdaabad53c3e15c19163e2ecc6ce3952a298e9a9 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 14 Apr 2025 17:18:33 +0200 Subject: [PATCH 003/131] Warn if async engine seems stuck (#16010) --- src/script/cpp_api/s_async.cpp | 47 ++++++++++++++++++++++++++-------- src/script/cpp_api/s_async.h | 23 +++++++++++++++++ 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp index 4cb46f6bb..982fb825e 100644 --- a/src/script/cpp_api/s_async.cpp +++ b/src/script/cpp_api/s_async.cpp @@ -24,6 +24,11 @@ extern "C" { #endif #include "lua_api/l_base.h" +// if a job is waiting for this duration, an additional thread will be spawned +static constexpr int AUTOSCALE_DELAY_MS = 1000; +// if jobs are waiting for this duration, a warning is printed +static constexpr int STUCK_DELAY_MS = 11500; + /******************************************************************************/ AsyncEngine::~AsyncEngine() { @@ -156,6 +161,7 @@ void AsyncEngine::step(lua_State *L) { stepJobResults(L); stepAutoscale(); + stepStuckWarning(); } void AsyncEngine::stepJobResults(lua_State *L) @@ -203,11 +209,9 @@ void AsyncEngine::stepAutoscale() if (autoscaleTimer && porting::getTimeMs() >= autoscaleTimer) { autoscaleTimer = 0; // Determine overlap with previous snapshot - unsigned int n = 0; - for (const auto &it : jobQueue) - n += autoscaleSeenJobs.count(it.id); - autoscaleSeenJobs.clear(); - infostream << "AsyncEngine: " << n << " jobs were still waiting after 1s" << std::endl; + size_t n = compareJobs(autoscaleSeenJobs); + infostream << "AsyncEngine: " << n << " jobs were still waiting after " + << AUTOSCALE_DELAY_MS << "ms, adding more threads." << std::endl; // Start this many new threads while (workerThreads.size() < autoscaleMaxWorkers && n > 0) { addWorkerThread(); @@ -216,13 +220,34 @@ void AsyncEngine::stepAutoscale() return; } - // 1) Check if there's anything in the queue + // 1) Check queue contents if (!autoscaleTimer && !jobQueue.empty()) { - // Take a snapshot of all jobs we have seen - for (const auto &it : jobQueue) - autoscaleSeenJobs.emplace(it.id); - // and set a timer for 1 second - autoscaleTimer = porting::getTimeMs() + 1000; + autoscaleSeenJobs.clear(); + snapshotJobs(autoscaleSeenJobs); + autoscaleTimer = porting::getTimeMs() + AUTOSCALE_DELAY_MS; + } +} + +void AsyncEngine::stepStuckWarning() +{ + MutexAutoLock autolock(jobQueueMutex); + + // 2) If the timer elapsed, check again + if (stuckTimer && porting::getTimeMs() >= stuckTimer) { + stuckTimer = 0; + size_t n = compareJobs(stuckSeenJobs); + if (n > 0) { + warningstream << "AsyncEngine: " << n << " jobs seem to be stuck in queue" + " (" << workerThreads.size() << " workers active)" << std::endl; + } + // fallthrough + } + + // 1) Check queue contents + if (!stuckTimer && !jobQueue.empty()) { + stuckSeenJobs.clear(); + snapshotJobs(stuckSeenJobs); + stuckTimer = porting::getTimeMs() + STUCK_DELAY_MS; } } diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h index d2a6913ef..1b6743dea 100644 --- a/src/script/cpp_api/s_async.h +++ b/src/script/cpp_api/s_async.h @@ -138,6 +138,11 @@ protected: */ void stepAutoscale(); + /** + * Print warning message if too many jobs are stuck + */ + void stepStuckWarning(); + /** * Initialize environment with current registred functions * this function adds all functions registred by registerFunction to the @@ -149,6 +154,21 @@ protected: bool prepareEnvironment(lua_State* L, int top); private: + template + inline void snapshotJobs(T &to) + { + for (const auto &it : jobQueue) + to.emplace(it.id); + } + template + inline size_t compareJobs(const T &from) + { + size_t overlap = 0; + for (const auto &it : jobQueue) + overlap += from.count(it.id); + return overlap; + } + // Variable locking the engine against further modification bool initDone = false; @@ -158,6 +178,9 @@ private: u64 autoscaleTimer = 0; std::unordered_set autoscaleSeenJobs; + u64 stuckTimer = 0; + std::unordered_set stuckSeenJobs; + // Only set for the server async environment (duh) Server *server = nullptr; From a9c197b1e5d7265e88219aacef53965a22257fda Mon Sep 17 00:00:00 2001 From: sfence Date: Tue, 15 Apr 2025 21:42:12 +0200 Subject: [PATCH 004/131] Expand usable range of fill_ratio to about 2.3e-10 (#16026) --- src/mapgen/mg_decoration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mapgen/mg_decoration.cpp b/src/mapgen/mg_decoration.cpp index 8810a654d..298184a10 100644 --- a/src/mapgen/mg_decoration.cpp +++ b/src/mapgen/mg_decoration.cpp @@ -163,7 +163,7 @@ void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) deco_count = deco_count_f; } else if (deco_count_f > 0.0f) { // For very low density calculate a chance for 1 decoration - if (ps.range(1000) <= deco_count_f * 1000.0f) + if (ps.next() <= deco_count_f * PcgRandom::RANDOM_RANGE) deco_count = 1; } } From 37d2bc8a5fad4fe84b1361ba38c1c9faac2c1660 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 15 Apr 2025 21:42:39 +0200 Subject: [PATCH 005/131] Reuse some allocations in ClientMap rendering --- src/client/clientmap.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 497c3452f..5098818ec 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -120,6 +120,11 @@ namespace { inline T subtract_or_zero(T a, T b) { return b >= a ? T(0) : (a - b); } + + // file-scope thread-local instances of the above two data structures, because + // allocating memory in a hot path can be expensive. + thread_local MeshBufListMaps tl_meshbuflistmaps; + thread_local DrawDescriptorList tl_drawdescriptorlist; } void CachedMeshBuffer::drop() @@ -978,8 +983,10 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) */ TimeTaker tt_collect(""); - MeshBufListMaps grouped_buffers; - DrawDescriptorList draw_order; + MeshBufListMaps &grouped_buffers = tl_meshbuflistmaps; + DrawDescriptorList &draw_order = tl_drawdescriptorlist; + grouped_buffers.clear(); + draw_order.clear(); auto is_frustum_culled = m_client->getCamera()->getFrustumCuller(); @@ -1375,8 +1382,10 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, return intToFloat(mesh_grid.getMeshPos(pos) * MAP_BLOCKSIZE - m_camera_offset, BS); }; - MeshBufListMaps grouped_buffers; - DrawDescriptorList draw_order; + MeshBufListMaps &grouped_buffers = tl_meshbuflistmaps; + DrawDescriptorList &draw_order = tl_drawdescriptorlist; + grouped_buffers.clear(); + draw_order.clear(); std::size_t count = 0; std::size_t meshes_per_frame = m_drawlist_shadow.size() / total_frames + 1; From cf07b56235dfd14148f614bf535838023dbef143 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 13 Apr 2025 17:20:41 +0200 Subject: [PATCH 006/131] Expand workarounds for format inconsistency with BGRA8888 extension on GLES fixes #16011 --- irr/src/COpenGLCoreTexture.h | 22 +++++++++++++++------- irr/src/OpenGLES2/Driver.cpp | 4 ++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/irr/src/COpenGLCoreTexture.h b/irr/src/COpenGLCoreTexture.h index 51b122075..ba9ad89c3 100644 --- a/irr/src/COpenGLCoreTexture.h +++ b/irr/src/COpenGLCoreTexture.h @@ -165,9 +165,8 @@ public: } #ifndef IRR_COMPILE_GL_COMMON - // On GLES 3.0 we must use sized internal formats for textures in certain - // cases (e.g. with ETT_2D_MS). However ECF_A8R8G8B8 is mapped to GL_BGRA - // (an unsized format). + // On GLES 3.0 we must use sized internal formats for textures when calling + // glTexStorage. But ECF_A8R8G8B8 might be mapped to GL_BGRA (an unsized format). // Since we don't upload to RTT we can safely pick a different combo that works. if (InternalFormat == GL_BGRA && Driver->Version.Major >= 3) { InternalFormat = GL_RGBA8; @@ -271,7 +270,7 @@ public: // For OpenGL an array texture is basically just a 3D texture internally. // So if we call glGetTexImage() we would download the entire array, // except the caller only wants a single layer. - // To do this properly we could have to use glGetTextureSubImage() [4.5] + // To do this properly we could use glGetTextureSubImage() [4.5] // or some trickery with glTextureView() [4.3]. // Also neither of those will work on GLES. @@ -522,10 +521,18 @@ protected: } // reference: + bool use_tex_storage = Driver->getFeature().TexStorage; + +#ifndef IRR_COMPILE_GL_COMMON + // On GLES 3.0 if we don't have a sized format suitable for glTexStorage, + // just avoid using it. Only affects the extension that provides BGRA. + if (InternalFormat == GL_BGRA && Driver->Version.Major >= 3) + use_tex_storage = false; +#endif switch (Type) { case ETT_2D: - if (Driver->getFeature().TexStorage) { + if (use_tex_storage) { GL.TexStorage2D(TextureType, levels, InternalFormat, Size.Width, Size.Height); } else { @@ -541,6 +548,7 @@ protected: // glTexImage2DMultisample is supported by OpenGL 3.2+ // glTexStorage2DMultisample is supported by OpenGL 4.3+ and OpenGL ES 3.1+ + // so pick the most compatible one #ifdef IRR_COMPILE_GL_COMMON // legacy driver constexpr bool use_gl_impl = true; #else @@ -557,7 +565,7 @@ protected: case ETT_CUBEMAP: for (u32 i = 0; i < 6; i++) { GLenum target = getTextureTarget(i); - if (Driver->getFeature().TexStorage) { + if (use_tex_storage) { GL.TexStorage2D(target, levels, InternalFormat, Size.Width, Size.Height); } else { @@ -568,7 +576,7 @@ protected: } break; case ETT_2D_ARRAY: - if (Driver->getFeature().TexStorage) { + if (use_tex_storage) { GL.TexStorage3D(TextureType, levels, InternalFormat, Size.Width, Size.Height, layers); } else { diff --git a/irr/src/OpenGLES2/Driver.cpp b/irr/src/OpenGLES2/Driver.cpp index 2db021088..84e702a8f 100644 --- a/irr/src/OpenGLES2/Driver.cpp +++ b/irr/src/OpenGLES2/Driver.cpp @@ -63,8 +63,8 @@ void COpenGLES2Driver::initFeatures() TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}; // NOTE a recent (2024) revision of EXT_texture_format_BGRA8888 also - // adds a sized format GL_BGRA8_EXT. We have a workaround in place to - // fix up the InternalFormat in case of render targets. + // adds a sized format GL_BGRA8_EXT. Because we can't rely on that we + // have stupid workarounds in place on texture creation... if (FeatureAvailable[IRR_GL_EXT_texture_format_BGRA8888] || FeatureAvailable[IRR_GL_APPLE_texture_format_BGRA8888]) TextureFormats[ECF_A8R8G8B8] = {GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE}; From 04e82749db3c3d08d525e2ab05296da593c27010 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 13 Apr 2025 17:34:45 +0200 Subject: [PATCH 007/131] Make ETLF_FLIP_Y_UP_RTT work for texture download on GLES --- irr/src/COpenGLCoreTexture.h | 41 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/irr/src/COpenGLCoreTexture.h b/irr/src/COpenGLCoreTexture.h index ba9ad89c3..bc9a7e919 100644 --- a/irr/src/COpenGLCoreTexture.h +++ b/irr/src/COpenGLCoreTexture.h @@ -289,24 +289,8 @@ public: GL.GetTexImage(tmpTextureType, MipLevelStored, PixelFormat, PixelType, tmpImage->getData()); TEST_GL_ERROR(Driver); - if (IsRenderTarget && lockFlags == ETLF_FLIP_Y_UP_RTT) { - const s32 pitch = tmpImage->getPitch(); - - u8 *srcA = static_cast(tmpImage->getData()); - u8 *srcB = srcA + (tmpImage->getDimension().Height - 1) * pitch; - - u8 *tmpBuffer = new u8[pitch]; - - for (u32 i = 0; i < tmpImage->getDimension().Height; i += 2) { - memcpy(tmpBuffer, srcA, pitch); - memcpy(srcA, srcB, pitch); - memcpy(srcB, tmpBuffer, pitch); - srcA += pitch; - srcB -= pitch; - } - - delete[] tmpBuffer; - } + if (IsRenderTarget && lockFlags == ETLF_FLIP_Y_UP_RTT) + flipImageY(tmpImage); } else { @@ -337,11 +321,12 @@ public: TEST_GL_ERROR(Driver); + if (IsRenderTarget && lockFlags == ETLF_FLIP_Y_UP_RTT) + flipImageY(tmpImage); + void *src = tmpImage->getData(); void *dest = LockImage->getData(); - // FIXME: what about ETLF_FLIP_Y_UP_RTT - switch (ColorFormat) { case ECF_A1R5G5B5: CColorConverter::convert_A8R8G8B8toA1B5G5R5(src, tmpImage->getDimension().getArea(), dest); @@ -507,6 +492,22 @@ protected: Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8; } + static void flipImageY(IImage *image) + { + const u32 pitch = image->getPitch(); + u8 *srcA = static_cast(image->getData()); + u8 *srcB = srcA + (image->getDimension().Height - 1) * pitch; + + std::vector tmpBuffer(pitch); + for (u32 i = 0; i < image->getDimension().Height; i += 2) { + memcpy(tmpBuffer.data(), srcA, pitch); + memcpy(srcA, srcB, pitch); + memcpy(srcB, tmpBuffer.data(), pitch); + srcA += pitch; + srcB -= pitch; + } + } + void initTexture(u32 layers) { // Compressed textures cannot be pre-allocated and are initialized on upload From fd857374603e63ab1092034dc8b82f7a3927caff Mon Sep 17 00:00:00 2001 From: Vincent Robinson Date: Wed, 16 Apr 2025 16:20:39 -0700 Subject: [PATCH 008/131] Add `allow_close[]` element to formspecs (#15971) --- README.md | 1 + doc/lua_api.md | 11 +++- games/devtest/mods/testformspec/formspec.lua | 9 ++- src/client/game.cpp | 8 +-- src/client/game_formspec.cpp | 3 + src/client/inputhandler.cpp | 4 ++ src/gui/guiEngine.cpp | 2 +- src/gui/guiFormSpecMenu.cpp | 67 ++++++++++---------- src/gui/guiFormSpecMenu.h | 10 +-- 9 files changed, 71 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 33340053a..2d5cdf890 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Some can be changed in the key config dialog in the settings tab. | T | Chat | | / | Command | | Esc | Pause menu/abort/exit (pauses only singleplayer game) | +| Ctrl + Esc | Exit directly to main menu from anywhere, bypassing pause menu | | + | Increase view range | | - | Decrease view range | | K | Enable/disable fly mode (needs fly privilege) | diff --git a/doc/lua_api.md b/doc/lua_api.md index 882bfe341..d8e58fcde 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -2903,6 +2903,13 @@ Elements * For information on converting forms to the new coordinate system, see `Migrating to Real Coordinates`. +### `allow_close[]` + +* When set to false, the formspec will not close when the user tries to close + it with the Escape key or similar. Default true. +* The formspec can still be closed with `*_exit[]` elements and + `core.close_formspec()`, regardless of this setting. + ### `container[,]` * Start of a container block, moves all physical elements in the container by @@ -6206,8 +6213,10 @@ Call these functions only at load time! * `table`: See `core.explode_table_event` * `scrollbar`: See `core.explode_scrollbar_event` * Special case: `["quit"]="true"` is sent when the user actively - closed the form by mouse click, keypress or through a button_exit[] + closed the form by mouse click, keypress or through a `button_exit[]` element. + * Special case: `["try_quit"]="true"` is sent when the user tries to + close the formspec, but the formspec used `allow_close[false]`. * Special case: `["key_enter"]="true"` is sent when the user pressed the Enter key and the focus was either nowhere (causing the formspec to be closed) or on a button. If the focus was on a text field, diff --git a/games/devtest/mods/testformspec/formspec.lua b/games/devtest/mods/testformspec/formspec.lua index 29014f1f2..f2f632fa0 100644 --- a/games/devtest/mods/testformspec/formspec.lua +++ b/games/devtest/mods/testformspec/formspec.lua @@ -339,10 +339,11 @@ local pages = { [[ formspec_version[3] size[12,13] + allow_close[false] image_button[0,0;1,1;logo.png;rc_image_button_1x1;1x1] - image_button[1,0;2,2;logo.png;rc_image_button_2x2;2x2] + image_button_exit[1,0;2,2;logo.png;rc_image_button_2x2;2x2 exit] button[0,2;1,1;rc_button_1x1;1x1] - button[1,2;2,2;rc_button_2x2;2x2] + button_exit[1,2;2,2;rc_button_2x2;2x2 exit] item_image[0,4;1,1;air] item_image[1,4;2,2;air] item_image_button[0,6;1,1;testformspec:node;rc_item_image_button_1x1;1x1] @@ -575,6 +576,10 @@ core.register_on_player_receive_fields(function(player, formname, fields) if fields.submit_window then show_test_formspec(player:get_player_name()) end + + if fields.try_quit then + core.chat_send_player(player:get_player_name(), "Quit attempt received") + end end) core.register_chatcommand("test_formspec", { diff --git a/src/client/game.cpp b/src/client/game.cpp index ee6cd0af4..78d009c7e 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1050,10 +1050,6 @@ void Game::shutdown() if (g_touchcontrols) g_touchcontrols->hide(); - // only if the shutdown progress bar isn't shown yet - if (m_shutdown_progress == 0.0f) - showOverlayMessage(N_("Shutting down..."), 0, 0); - clouds.reset(); gui_chat_console.reset(); @@ -1065,6 +1061,10 @@ void Game::shutdown() g_menumgr.deleteFront(); } + // only if the shutdown progress bar isn't shown yet + if (m_shutdown_progress == 0.0f) + showOverlayMessage(N_("Shutting down..."), 0, 0); + chat_backend->addMessage(L"", L"# Disconnected."); chat_backend->addMessage(L"", L""); diff --git a/src/client/game_formspec.cpp b/src/client/game_formspec.cpp index 4bd1a42bd..dc4be3699 100644 --- a/src/client/game_formspec.cpp +++ b/src/client/game_formspec.cpp @@ -205,6 +205,9 @@ void GameFormSpec::init(Client *client, RenderingEngine *rendering_engine, Input m_input = input; m_pause_script = std::make_unique(client); m_pause_script->loadBuiltin(); + + // Make sure any remaining game callback requests are cleared out. + *g_gamecallback = MainGameCallback(); } void GameFormSpec::deleteFormspec() diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp index 492f2fd6c..e7bdd4f30 100644 --- a/src/client/inputhandler.cpp +++ b/src/client/inputhandler.cpp @@ -148,6 +148,10 @@ bool MyEventReceiver::OnEvent(const SEvent &event) } fullscreen_is_down = event.KeyInput.PressedDown; return true; + } else if (keyCode == EscapeKey && + event.KeyInput.PressedDown && event.KeyInput.Control) { + g_gamecallback->disconnect(); + return true; } } diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp index a83a913ec..860fce665 100644 --- a/src/gui/guiEngine.cpp +++ b/src/gui/guiEngine.cpp @@ -168,7 +168,7 @@ GUIEngine::GUIEngine(JoystickController *joystick, "", false); - m_menu->allowClose(false); + m_menu->defaultAllowClose(false); m_menu->lockSize(true,v2u32(800,600)); // Initialize scripting diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 59d6dc5a7..39d8797b4 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -105,7 +105,6 @@ GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick, current_keys_pending.key_down = false; current_keys_pending.key_up = false; current_keys_pending.key_enter = false; - current_keys_pending.key_escape = false; m_tooltip_show_delay = (u32)g_settings->getS32("tooltip_show_delay"); m_tooltip_append_itemname = g_settings->getBool("tooltip_append_itemname"); @@ -2833,6 +2832,11 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element) m_fields.push_back(spec); } +void GUIFormSpecMenu::parseAllowClose(parserData *data, const std::string &element) +{ + m_allowclose = is_yes(element); +} + void GUIFormSpecMenu::removeAll() { // Remove children @@ -2901,6 +2905,7 @@ const std::unordered_mapgotText(fields); return; + } else if (quitmode == quit_mode_try) { + fields["try_quit"] = "true"; } if (current_keys_pending.key_down) { @@ -3816,11 +3822,6 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode) current_field_enter_pending.clear(); } - if (current_keys_pending.key_escape) { - fields["key_escape"] = "true"; - current_keys_pending.key_escape = false; - } - for (const GUIFormSpecMenu::FieldSpec &s : m_fields) { if (s.send) { std::string name = s.fname; @@ -3997,6 +3998,8 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) if (m_allowclose) { acceptInput(quit_mode_accept); quitMenu(); + } else { + acceptInput(quit_mode_try); } } } @@ -4013,6 +4016,7 @@ void GUIFormSpecMenu::tryClose() acceptInput(quit_mode_cancel); quitMenu(); } else { + acceptInput(quit_mode_try); m_text_dst->gotText(L"MenuQuit"); } } @@ -4059,9 +4063,13 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) FATAL_ERROR("Reached a source line that can't ever been reached"); break; } - if (current_keys_pending.key_enter && m_allowclose) { - acceptInput(quit_mode_accept); - quitMenu(); + if (current_keys_pending.key_enter) { + if (m_allowclose) { + acceptInput(quit_mode_accept); + quitMenu(); + } else { + acceptInput(quit_mode_try); + } } else { acceptInput(); } @@ -4806,14 +4814,9 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) s32 caller_id = event.GUIEvent.Caller->getID(); if (caller_id == 257) { - if (m_allowclose) { - acceptInput(quit_mode_accept); - quitMenu(); - } else { - acceptInput(); - m_text_dst->gotText(L"ExitButton"); - } - // quitMenu deallocates menu + acceptInput(quit_mode_accept); + m_text_dst->gotText(L"ExitButton"); + quitMenu(); return true; } @@ -4842,12 +4845,9 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) } if (s.is_exit) { - if (m_allowclose) { - acceptInput(quit_mode_accept); - quitMenu(); - } else { - m_text_dst->gotText(L"ExitButton"); - } + acceptInput(quit_mode_accept); + m_text_dst->gotText(L"ExitButton"); + quitMenu(); return true; } @@ -4910,15 +4910,18 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) } } - if (m_allowclose && close_on_enter) { - current_keys_pending.key_enter = true; - acceptInput(quit_mode_accept); - quitMenu(); + current_keys_pending.key_enter = true; + + if (close_on_enter) { + if (m_allowclose) { + acceptInput(quit_mode_accept); + quitMenu(); + } else { + acceptInput(quit_mode_try); + } } else { - current_keys_pending.key_enter = true; acceptInput(); } - // quitMenu deallocates menu return true; } } diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h index 04b65a967..3cfd79cae 100644 --- a/src/gui/guiFormSpecMenu.h +++ b/src/gui/guiFormSpecMenu.h @@ -47,7 +47,8 @@ enum FormspecFieldType { enum FormspecQuitMode { quit_mode_no, quit_mode_accept, - quit_mode_cancel + quit_mode_cancel, + quit_mode_try, }; enum ButtonEventType : u8 @@ -203,9 +204,9 @@ public: m_text_dst = text_dst; } - void allowClose(bool value) + void defaultAllowClose(bool value) { - m_allowclose = value; + m_default_allowclose = value; } void setDebugView(bool value) @@ -363,6 +364,7 @@ protected: u64 m_hovered_time = 0; s32 m_old_tooltip_id = -1; + bool m_default_allowclose = true; bool m_allowclose = true; bool m_lock = false; v2u32 m_lockscreensize; @@ -422,7 +424,6 @@ private: bool key_up; bool key_down; bool key_enter; - bool key_escape; }; fs_key_pending current_keys_pending; @@ -484,6 +485,7 @@ private: void parseStyle(parserData *data, const std::string &element); void parseSetFocus(parserData *, const std::string &element); void parseModel(parserData *data, const std::string &element); + void parseAllowClose(parserData *data, const std::string &element); bool parseMiddleRect(const std::string &value, core::rect *parsed_rect); From 7375358afd6cdea664a52da60d8b89ad0269e316 Mon Sep 17 00:00:00 2001 From: sfence Date: Thu, 17 Apr 2025 12:35:14 +0200 Subject: [PATCH 009/131] Fix warning in mg_decoration.cpp --- src/mapgen/mg_decoration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mapgen/mg_decoration.cpp b/src/mapgen/mg_decoration.cpp index 298184a10..1e3b7ec53 100644 --- a/src/mapgen/mg_decoration.cpp +++ b/src/mapgen/mg_decoration.cpp @@ -163,7 +163,7 @@ void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) deco_count = deco_count_f; } else if (deco_count_f > 0.0f) { // For very low density calculate a chance for 1 decoration - if (ps.next() <= deco_count_f * PcgRandom::RANDOM_RANGE) + if (ps.next() <= deco_count_f * static_cast(PcgRandom::RANDOM_RANGE)) deco_count = 1; } } From 0695541bf59b305cc6661deb5d57a30e92cb9c6c Mon Sep 17 00:00:00 2001 From: Travis Wrightsman Date: Thu, 17 Apr 2025 12:35:31 +0200 Subject: [PATCH 010/131] Fix cross-building by ensuring output path is set --- src/CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88c0c5a45..d772c10ad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -591,9 +591,12 @@ if(USE_CURL) endif() -# When cross-compiling assume the user doesn't want to run the executable anyway, -# otherwise place it in /bin/ since Luanti can only run from there. -if(NOT CMAKE_CROSSCOMPILING) +# When cross-compiling place the executable in /bin so that multiple +# targets can be built from the same source folder. Otherwise, place it in +# /bin/ since Luanti can only run from there. +if(CMAKE_CROSSCOMPILING) + set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin") +else() set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin") endif() From 2bb7ed208c75c3f0bcfd0fc6caa5dc62ef46a271 Mon Sep 17 00:00:00 2001 From: y5nw <37980625+y5nw@users.noreply.github.com> Date: Sun, 20 Apr 2025 13:28:31 +0200 Subject: [PATCH 011/131] Add vcpkg.json (#15863) --- .github/workflows/windows.yml | 10 ++-------- vcpkg.json | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 vcpkg.json diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e9698c93b..979ab0144 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -71,9 +71,7 @@ jobs: name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }} runs-on: windows-2019 env: - VCPKG_VERSION: d5ec528843d29e3a52d745a64b469f810b2cedbf - # 2025.02.14 - vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp sdl2 + VCPKG_DEFAULT_TRIPLET: ${{matrix.config.vcpkg_triplet}} strategy: fail-fast: false matrix: @@ -97,13 +95,9 @@ jobs: - uses: actions/checkout@v4 - name: Restore from cache and run vcpkg - uses: lukka/run-vcpkg@v7 + uses: lukka/run-vcpkg@v11 with: - vcpkgArguments: ${{env.vcpkg_packages}} vcpkgDirectory: '${{ github.workspace }}\vcpkg' - appendedCacheKey: ${{ matrix.config.vcpkg_triplet }} - vcpkgGitCommitId: ${{ env.VCPKG_VERSION }} - vcpkgTriplet: ${{ matrix.config.vcpkg_triplet }} - name: CMake # Note: See #15976 for why CMAKE_POLICY_VERSION_MINIMUM=3.5 is set. diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 000000000..213f4514a --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,29 @@ +{ + "builtin-baseline": "d5ec528843d29e3a52d745a64b469f810b2cedbf", + "dependencies": [ + "zlib", + "zstd", + { + "name": "curl", + "features": [ + "winssl" + ] + }, + "openal-soft", + "libvorbis", + "libogg", + "libjpeg-turbo", + "sqlite3", + "freetype", + "luajit", + "gmp", + "jsoncpp", + { + "name": "gettext", + "features": [ + "tools" + ] + }, + "sdl2" + ] +} From bf15036831e5bfcf548bc6d4b2f93c93fa8f373a Mon Sep 17 00:00:00 2001 From: y5nw <37980625+y5nw@users.noreply.github.com> Date: Sun, 20 Apr 2025 20:20:22 +0200 Subject: [PATCH 012/131] Show SDL version in the About tab (#16046) --- irr/include/IrrlichtDevice.h | 7 +++++++ irr/src/CIrrDeviceSDL.h | 8 ++++++++ src/script/lua_api/l_mainmenu.cpp | 9 ++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/irr/include/IrrlichtDevice.h b/irr/include/IrrlichtDevice.h index 6ae21a212..d159142c4 100644 --- a/irr/include/IrrlichtDevice.h +++ b/irr/include/IrrlichtDevice.h @@ -16,6 +16,7 @@ #include "IrrCompileConfig.h" #include "position2d.h" #include "SColor.h" // video::ECOLOR_FORMAT +#include #include namespace irr @@ -332,6 +333,12 @@ public: used. */ virtual E_DEVICE_TYPE getType() const = 0; + //! Get the version string of the underlying system (e.g. SDL) + virtual std::string getVersionString() const + { + return ""; + } + //! Get the display density in dots per inch. //! Returns 0.0f on failure. virtual float getDisplayDensity() const = 0; diff --git a/irr/src/CIrrDeviceSDL.h b/irr/src/CIrrDeviceSDL.h index 8a7e5f680..33d97ce56 100644 --- a/irr/src/CIrrDeviceSDL.h +++ b/irr/src/CIrrDeviceSDL.h @@ -109,6 +109,14 @@ public: return EIDT_SDL; } + //! Get the SDL version + std::string getVersionString() const override + { + SDL_version ver; + SDL_GetVersion(&ver); + return std::to_string(ver.major) + "." + std::to_string(ver.minor) + "." + std::to_string(ver.patch); + } + //! Get the display density in dots per inch. float getDisplayDensity() const override; diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 7070952e6..240927a4a 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -945,8 +945,9 @@ int ModApiMainMenu::l_get_active_renderer(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_get_active_irrlicht_device(lua_State *L) { - const char *device_name = [] { - switch (RenderingEngine::get_raw_device()->getType()) { + auto device = RenderingEngine::get_raw_device(); + std::string device_name = [device] { + switch (device->getType()) { case EIDT_WIN32: return "WIN32"; case EIDT_X11: return "X11"; case EIDT_OSX: return "OSX"; @@ -955,7 +956,9 @@ int ModApiMainMenu::l_get_active_irrlicht_device(lua_State *L) default: return "Unknown"; } }(); - lua_pushstring(L, device_name); + if (auto version = device->getVersionString(); !version.empty()) + device_name.append(" " + version); + lua_pushstring(L, device_name.c_str()); return 1; } From c1d2124102f1dc29c7daa2d21532fa6f170477c5 Mon Sep 17 00:00:00 2001 From: y5nw <37980625+y5nw@users.noreply.github.com> Date: Sun, 20 Apr 2025 20:20:33 +0200 Subject: [PATCH 013/131] SDL: Send events for X1 and X2 mouse buttons (#16025) --- irr/src/CIrrDeviceSDL.cpp | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index 536eda96e..28a92f450 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -766,12 +766,7 @@ bool CIrrDeviceSDL::run() SDL_Keymod keymod = SDL_GetModState(); irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT; - irrevent.MouseInput.X = static_cast(SDL_event.button.x * ScaleX); - irrevent.MouseInput.Y = static_cast(SDL_event.button.y * ScaleY); - irrevent.MouseInput.Shift = (keymod & KMOD_SHIFT) != 0; - irrevent.MouseInput.Control = (keymod & KMOD_CTRL) != 0; - - irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED; + irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED; // value to be ignored #ifdef _IRR_EMSCRIPTEN_PLATFORM_ // Handle mouselocking in emscripten in Windowed mode. @@ -834,11 +829,29 @@ bool CIrrDeviceSDL::run() MouseButtonStates &= ~irr::EMBSM_MIDDLE; } break; + + // Since Irrlicht does not have event types for X1/X2 buttons, we simply pass + // those as keycodes instead. This is relatively hacky but avoids the effort of + // adding more mouse events that will be discarded anyway once we switch to SDL + case SDL_BUTTON_X1: + irrevent.EventType = irr::EET_KEY_INPUT_EVENT; + irrevent.KeyInput.Key = irr::KEY_XBUTTON1; + break; + + case SDL_BUTTON_X2: + irrevent.EventType = irr::EET_KEY_INPUT_EVENT; + irrevent.KeyInput.Key = irr::KEY_XBUTTON2; + break; } - irrevent.MouseInput.ButtonStates = MouseButtonStates; - - if (irrevent.MouseInput.Event != irr::EMIE_MOUSE_MOVED) { + bool shift = (keymod & KMOD_SHIFT) != 0; + bool control = (keymod & KMOD_CTRL) != 0; + if (irrevent.EventType == irr::EET_MOUSE_INPUT_EVENT && irrevent.MouseInput.Event != irr::EMIE_MOUSE_MOVED) { + irrevent.MouseInput.ButtonStates = MouseButtonStates; + irrevent.MouseInput.X = static_cast(SDL_event.button.x * ScaleX); + irrevent.MouseInput.Y = static_cast(SDL_event.button.y * ScaleY); + irrevent.MouseInput.Shift = shift; + irrevent.MouseInput.Control = control; postEventFromUser(irrevent); if (irrevent.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && irrevent.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN) { @@ -851,6 +864,12 @@ bool CIrrDeviceSDL::run() postEventFromUser(irrevent); } } + } else if (irrevent.EventType == irr::EET_KEY_INPUT_EVENT) { + irrevent.KeyInput.Char = 0; + irrevent.KeyInput.PressedDown = SDL_event.type == SDL_MOUSEBUTTONDOWN; + irrevent.KeyInput.Shift = shift; + irrevent.KeyInput.Control = control; + postEventFromUser(irrevent); } break; } From 23bfb2db72638f4de5681e0b69d41fd8b0a8bda7 Mon Sep 17 00:00:00 2001 From: y5nw <37980625+y5nw@users.noreply.github.com> Date: Sun, 20 Apr 2025 20:20:49 +0200 Subject: [PATCH 014/131] Move keybinding settings to (Lua-based) setting menu (#15791) --- .luacheckrc | 12 + builtin/common/menu.lua | 11 + builtin/common/settings/components.lua | 54 +++ builtin/common/settings/dlg_settings.lua | 33 +- builtin/common/settings/settingtypes.lua | 6 +- builtin/mainmenu/init.lua | 9 +- builtin/pause_menu/init.lua | 1 + builtin/settingtypes.txt | 467 ++++++++++++----------- doc/menu_lua_api.md | 1 - src/client/game_formspec.cpp | 12 - src/client/inputhandler.cpp | 2 + src/client/inputhandler.h | 14 + src/gui/CMakeLists.txt | 2 +- src/gui/guiButtonKey.cpp | 141 +++++++ src/gui/guiButtonKey.h | 75 ++++ src/gui/guiFormSpecMenu.cpp | 14 +- src/gui/guiKeyChangeMenu.cpp | 401 ------------------- src/gui/guiKeyChangeMenu.h | 63 --- src/gui/mainmenumanager.h | 14 - src/script/lua_api/l_mainmenu.cpp | 18 - src/script/lua_api/l_mainmenu.h | 2 - src/script/lua_api/l_menu_common.cpp | 10 + src/script/lua_api/l_menu_common.h | 1 + src/script/lua_api/l_pause_menu.cpp | 9 +- src/script/lua_api/l_pause_menu.h | 1 - 25 files changed, 591 insertions(+), 782 deletions(-) create mode 100644 builtin/common/menu.lua create mode 100644 src/gui/guiButtonKey.cpp create mode 100644 src/gui/guiButtonKey.h delete mode 100644 src/gui/guiKeyChangeMenu.cpp delete mode 100644 src/gui/guiKeyChangeMenu.h diff --git a/.luacheckrc b/.luacheckrc index de45f0413..670c84325 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -33,6 +33,13 @@ globals = { "_", } +stds.menu_common = { + globals = { + "mt_color_grey", "mt_color_blue", "mt_color_lightblue", "mt_color_green", + "mt_color_dark_green", "mt_color_orange", "mt_color_red", + }, +} + files["builtin/client/register.lua"] = { globals = { debug = {fields={"getinfo"}}, @@ -73,11 +80,16 @@ files["builtin/common/filterlist.lua"] = { } files["builtin/mainmenu"] = { + std = "+menu_common", globals = { "gamedata", }, } +files["builtin/common/settings"] = { + std = "+menu_common", +} + files["builtin/common/tests"] = { read_globals = { "describe", diff --git a/builtin/common/menu.lua b/builtin/common/menu.lua new file mode 100644 index 000000000..165286470 --- /dev/null +++ b/builtin/common/menu.lua @@ -0,0 +1,11 @@ +-- Luanti +-- SPDX-License-Identifier: LGPL-2.1-or-later + +-- These colors are used by the main menu and the settings menu +mt_color_grey = "#AAAAAA" +mt_color_blue = "#6389FF" +mt_color_lightblue = "#99CCFF" +mt_color_green = "#72FF63" +mt_color_dark_green = "#25C191" +mt_color_orange = "#FF8800" +mt_color_red = "#FF3300" diff --git a/builtin/common/settings/components.lua b/builtin/common/settings/components.lua index de7a63fee..b3035fd51 100644 --- a/builtin/common/settings/components.lua +++ b/builtin/common/settings/components.lua @@ -37,6 +37,7 @@ local make = {} -- * `fs` is a string for the formspec. -- Components should be relative to `0,0`, and not exceed `avail_w` or the returned `used_height`. -- * `used_height` is the space used by components in `fs`. +-- * `spacing`: (Optional) the vertical margin to be added before the component (default 0.25) -- * `on_submit = function(self, fields, parent)`: -- * `fields`: submitted formspec fields -- * `parent`: the fstk element for the settings UI, use to show dialogs @@ -442,6 +443,59 @@ local function make_noise_params(setting) } end +function make.key(setting) + local btn_bind = "bind_" .. setting.name + local btn_clear = "unbind_" .. setting.name + local function add_conflict_warnings(fs, height) + local value = core.settings:get(setting.name) + if value == "" then + return height + end + for _, o in ipairs(core.full_settingtypes) do + if o.type == "key" and o.name ~= setting.name and core.are_keycodes_equal(core.settings:get(o.name), value) then + table.insert(fs, ("label[0,%f;%s]"):format(height + 0.3, + core.colorize(mt_color_orange, fgettext([[Conflicts with "$1"]], fgettext(o.readable_name))))) + height = height + 0.6 + end + end + return height + end + return { + info_text = setting.comment, + setting = setting, + spacing = 0.1, + + get_formspec = function(self, avail_w) + self.resettable = core.settings:has(setting.name) + local btn_bind_width = math.max(2.5, avail_w/2) + local value = core.settings:get(setting.name) + local fs = { + ("label[0,0.4;%s]"):format(get_label(setting)), + ("button_key[%f,0;%f,0.8;%s;%s]"):format( + btn_bind_width, btn_bind_width-0.8, + btn_bind, core.formspec_escape(value)), + ("image_button[%f,0;0.8,0.8;%s;%s;]"):format(avail_w - 0.8, + core.formspec_escape(defaulttexturedir .. "clear.png"), + btn_clear), + ("tooltip[%s;%s]"):format(btn_clear, fgettext("Remove keybinding")), + } + local height = 0.8 + height = add_conflict_warnings(fs, height) + return table.concat(fs), height + end, + + on_submit = function(self, fields) + if fields[btn_bind] then + core.settings:set(setting.name, fields[btn_bind]) + return true + elseif fields[btn_clear] then + core.settings:set(setting.name, "") + return true + end + end, + } +end + if INIT == "pause_menu" then -- Making the noise parameter dialog work in the pause menu settings would -- require porting "FSTK" (at least the dialog API) from the mainmenu formspec diff --git a/builtin/common/settings/dlg_settings.lua b/builtin/common/settings/dlg_settings.lua index b43d9ebdc..8d4a8b6de 100644 --- a/builtin/common/settings/dlg_settings.lua +++ b/builtin/common/settings/dlg_settings.lua @@ -22,7 +22,6 @@ local component_funcs = dofile(path .. "components.lua") local shadows_component = dofile(path .. "shadows_component.lua") local loaded = false -local full_settings local info_icon_path = core.formspec_escape(defaulttexturedir .. "settings_info.png") local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png") local all_pages = {} @@ -32,7 +31,7 @@ local filtered_page_by_id = page_by_id local function get_setting_info(name) - for _, entry in ipairs(full_settings) do + for _, entry in ipairs(core.full_settingtypes) do if entry.type ~= "category" and entry.name == name then return entry end @@ -70,7 +69,7 @@ local function load_settingtypes() end end - for _, entry in ipairs(full_settings) do + for _, entry in ipairs(core.full_settingtypes) do if entry.type == "category" then if entry.level == 0 then section = entry.name @@ -104,24 +103,7 @@ local function load() end loaded = true - full_settings = settingtypes.parse_config_file(false, true) - - local change_keys = { - query_text = "Controls", - requires = { - keyboard_mouse = true, - }, - context = "client", - get_formspec = function(self, avail_w) - local btn_w = math.min(avail_w, 3) - return ("button[0,0;%f,0.8;btn_change_keys;%s]"):format(btn_w, fgettext("Controls")), 0.8 - end, - on_submit = function(self, fields) - if fields.btn_change_keys then - core.show_keys_menu() - end - end, - } + core.full_settingtypes = settingtypes.parse_config_file(false, true) local touchscreen_layout = { query_text = "Touchscreen layout", @@ -166,7 +148,6 @@ local function load() load_settingtypes() - table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys) -- insert after "touch_controls" table.insert(page_by_id.controls_touchscreen.content, 2, touchscreen_layout) do @@ -665,7 +646,13 @@ local function get_formspec(dialogdata) fs[#fs + 1] = "container_end[]" if used_h > 0 then - y = y + used_h + 0.25 + local spacing = 0.25 + local next_comp = dialogdata.components[i + 1] + if next_comp and next_comp.spacing then + spacing = next_comp.spacing + end + + y = y + used_h + spacing end end diff --git a/builtin/common/settings/settingtypes.lua b/builtin/common/settings/settingtypes.lua index 39a50e1f4..90ff8975c 100644 --- a/builtin/common/settings/settingtypes.lua +++ b/builtin/common/settings/settingtypes.lua @@ -249,9 +249,9 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se if not default then return "Invalid string setting" end - if setting_type == "key" and not read_all then - -- ignore key type if read_all is false - return + + if setting_type == "key" then + requires.keyboard_mouse = true end table.insert(settings, { diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index ec33f33b3..acf1f738d 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -15,14 +15,6 @@ --with this program; if not, write to the Free Software Foundation, Inc., --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -mt_color_grey = "#AAAAAA" -mt_color_blue = "#6389FF" -mt_color_lightblue = "#99CCFF" -mt_color_green = "#72FF63" -mt_color_dark_green = "#25C191" -mt_color_orange = "#FF8800" -mt_color_red = "#FF3300" - MAIN_TAB_W = 15.5 MAIN_TAB_H = 7.1 TABHEADER_H = 0.85 @@ -35,6 +27,7 @@ local basepath = core.get_builtin_path() defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" .. DIR_DELIM .. "pack" .. DIR_DELIM +dofile(basepath .. "common" .. DIR_DELIM .. "menu.lua") dofile(basepath .. "common" .. DIR_DELIM .. "filterlist.lua") dofile(basepath .. "fstk" .. DIR_DELIM .. "buttonbar.lua") dofile(basepath .. "fstk" .. DIR_DELIM .. "dialog.lua") diff --git a/builtin/pause_menu/init.lua b/builtin/pause_menu/init.lua index 035d2ba99..01c5dc856 100644 --- a/builtin/pause_menu/init.lua +++ b/builtin/pause_menu/init.lua @@ -8,5 +8,6 @@ defaulttexturedir = "" local builtin_shared = {} assert(loadfile(commonpath .. "register.lua"))(builtin_shared) +assert(loadfile(commonpath .. "menu.lua"))(builtin_shared) assert(loadfile(pausepath .. "register.lua"))(builtin_shared) dofile(commonpath .. "settings" .. DIR_DELIM .. "init.lua") diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 825a85b97..83d0b48e0 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -31,7 +31,7 @@ # - enum # - path # - filepath -# - key (will be ignored in GUI, since a special key change dialog exists) +# - key # - flags # - noise_params_2d # - noise_params_3d @@ -91,6 +91,8 @@ # * touchscreen / keyboard_mouse # * opengl / gles # * You can negate any requirement by prepending with ! +# * The "keyboard_mouse" requirement is automatically added to settings with the +# "key" type. # # Sections are marked by a single line in the format: [Section Name] # Sub-section are marked by adding * in front of the section name: [*Sub-section] @@ -178,6 +180,228 @@ enable_hotbar_mouse_wheel (Hotbar: Enable mouse wheel for selection) bool true # Requires: keyboard_mouse invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false +[**Keybindings] + +# Key for moving the player forward. +keymap_forward (Move forward) key KEY_KEY_W + +# Key for moving the player backward. +# Will also disable autoforward, when active. +keymap_backward (Move backward) key KEY_KEY_S + +# Key for moving the player left. +keymap_left (Move left) key KEY_KEY_A + +# Key for moving the player right. +keymap_right (Move right) key KEY_KEY_D + +# Key for jumping. +keymap_jump (Jump) key KEY_SPACE + +# Key for sneaking. +# Also used for climbing down and descending in water if aux1_descends is disabled. +keymap_sneak (Sneak) key KEY_LSHIFT + +# Key for digging, punching or using something. +# (Note: The actual meaning might vary on a per-game basis.) +keymap_dig (Dig/punch/use) key KEY_LBUTTON + +# Key for placing an item/block or for using something. +# (Note: The actual meaning might vary on a per-game basis.) +keymap_place (Place/use) key KEY_RBUTTON + +# Key for opening the inventory. +keymap_inventory (Open inventory) key KEY_KEY_I + +# Key for moving fast in fast mode. +keymap_aux1 (Aux1) key KEY_KEY_E + +# Key for opening the chat window. +keymap_chat (Open chat) key KEY_KEY_T + +# Key for opening the chat window to type commands. +keymap_cmd (Command) key / + +# Key for opening the chat window to type local commands. +keymap_cmd_local (Local command) key . + +# Key for toggling unlimited view range. +keymap_rangeselect (Range select) key + +# Key for toggling flying. +keymap_freemove (Toggle fly) key KEY_KEY_K + +# Key for toggling pitch move mode. +keymap_pitchmove (Toggle pitchmove) key + +# Key for toggling fast mode. +keymap_fastmove (Toggle fast) key KEY_KEY_J + +# Key for toggling noclip mode. +keymap_noclip (Toggle noclip) key KEY_KEY_H + +# Key for selecting the next item in the hotbar. +keymap_hotbar_next (Hotbar: select next item) key KEY_KEY_N + +# Key for selecting the previous item in the hotbar. +keymap_hotbar_previous (Hotbar: select previous item) key KEY_KEY_B + +# Key for muting the game. +keymap_mute (Mute) key KEY_KEY_M + +# Key for increasing the volume. +keymap_increase_volume (Increase volume) key + +# Key for decreasing the volume. +keymap_decrease_volume (Decrease volume) key + +# Key for toggling autoforward. +keymap_autoforward (Toggle automatic forward) key + +# Key for toggling cinematic mode. +keymap_cinematic (Toggle cinematic mode) key + +# Key for toggling display of minimap. +keymap_minimap (Toggle minimap) key KEY_KEY_V + +# Key for taking screenshots. +keymap_screenshot (Screenshot) key KEY_F12 + +# Key for toggling fullscreen mode. +keymap_fullscreen (Toggle fullscreen) key KEY_F11 + +# Key for dropping the currently selected item. +keymap_drop (Drop item) key KEY_KEY_Q + +# Key to use view zoom when possible. +keymap_zoom (Zoom) key KEY_KEY_Z + +# Key for toggling the display of the HUD. +keymap_toggle_hud (Toggle HUD) key KEY_F1 + +# Key for toggling the display of chat. +keymap_toggle_chat (Toggle chat log) key KEY_F2 + +# Key for toggling the display of the large chat console. +keymap_console (Large chat console) key KEY_F10 + +# Key for toggling the display of fog. +keymap_toggle_fog (Toggle fog) key KEY_F3 + +# Key for toggling the display of debug info. +keymap_toggle_debug (Toggle debug info) key KEY_F5 + +# Key for toggling the display of the profiler. Used for development. +keymap_toggle_profiler (Toggle profiler) key KEY_F6 + +# Key for toggling the display of mapblock boundaries. +keymap_toggle_block_bounds (Toggle block bounds) key + +# Key for switching between first- and third-person camera. +keymap_camera_mode (Toggle camera mode) key KEY_KEY_C + +# Key for increasing the viewing range. +keymap_increase_viewing_range_min (Increase view range) key + + +# Key for decreasing the viewing range. +keymap_decrease_viewing_range_min (Decrease view range) key - + +# Key for selecting the first hotbar slot. +keymap_slot1 (Hotbar slot 1) key KEY_KEY_1 + +# Key for selecting the second hotbar slot. +keymap_slot2 (Hotbar slot 2) key KEY_KEY_2 + +# Key for selecting the third hotbar slot. +keymap_slot3 (Hotbar slot 3) key KEY_KEY_3 + +# Key for selecting the fourth hotbar slot. +keymap_slot4 (Hotbar slot 4) key KEY_KEY_4 + +# Key for selecting the fifth hotbar slot. +keymap_slot5 (Hotbar slot 5) key KEY_KEY_5 + +# Key for selecting the sixth hotbar slot. +keymap_slot6 (Hotbar slot 6) key KEY_KEY_6 + +# Key for selecting the seventh hotbar slot. +keymap_slot7 (Hotbar slot 7) key KEY_KEY_7 + +# Key for selecting the eighth hotbar slot. +keymap_slot8 (Hotbar slot 8) key KEY_KEY_8 + +# Key for selecting the ninth hotbar slot. +keymap_slot9 (Hotbar slot 9) key KEY_KEY_9 + +# Key for selecting the tenth hotbar slot. +keymap_slot10 (Hotbar slot 10) key KEY_KEY_0 + +# Key for selecting the 11th hotbar slot. +keymap_slot11 (Hotbar slot 11) key + +# Key for selecting the 12th hotbar slot. +keymap_slot12 (Hotbar slot 12) key + +# Key for selecting the 13th hotbar slot. +keymap_slot13 (Hotbar slot 13) key + +# Key for selecting the 14th hotbar slot. +keymap_slot14 (Hotbar slot 14) key + +# Key for selecting the 15th hotbar slot. +keymap_slot15 (Hotbar slot 15) key + +# Key for selecting the 16th hotbar slot. +keymap_slot16 (Hotbar slot 16) key + +# Key for selecting the 17th hotbar slot. +keymap_slot17 (Hotbar slot 17) key + +# Key for selecting the 18th hotbar slot. +keymap_slot18 (Hotbar slot 18) key + +# Key for selecting the 19th hotbar slot. +keymap_slot19 (Hotbar slot 19) key + +# Key for selecting the 20th hotbar slot. +keymap_slot20 (Hotbar slot 20) key + +# Key for selecting the 21st hotbar slot. +keymap_slot21 (Hotbar slot 21) key + +# Key for selecting the 22nd hotbar slot. +keymap_slot22 (Hotbar slot 22) key + +# Key for selecting the 23rd hotbar slot. +keymap_slot23 (Hotbar slot 23) key + +# Key for selecting the 24th hotbar slot. +keymap_slot24 (Hotbar slot 24) key + +# Key for selecting the 25th hotbar slot. +keymap_slot25 (Hotbar slot 25) key + +# Key for selecting the 26th hotbar slot. +keymap_slot26 (Hotbar slot 26) key + +# Key for selecting the 27th hotbar slot. +keymap_slot27 (Hotbar slot 27) key + +# Key for selecting the 28th hotbar slot. +keymap_slot28 (Hotbar slot 28) key + +# Key for selecting the 29th hotbar slot. +keymap_slot29 (Hotbar slot 29) key + +# Key for selecting the 30th hotbar slot. +keymap_slot30 (Hotbar slot 30) key + +# Key for selecting the 31st hotbar slot. +keymap_slot31 (Hotbar slot 31) key + +# Key for selecting the 32nd hotbar slot. +keymap_slot32 (Hotbar slot 32) key + [*Touchscreen] # Enables the touchscreen controls, allowing you to play the game with a touchscreen. @@ -1825,7 +2049,6 @@ instrument.profiler (Profiler) bool false # 0 = disable. Useful for developers. profiler_print_interval (Engine profiling data print interval) int 0 0 - [*Advanced] [**Graphics] [client] @@ -2219,6 +2442,23 @@ curl_parallel_limit (cURL parallel limit) int 8 1 2147483647 # Maximum time a file download (e.g. a mod download) may take, stated in milliseconds. curl_file_download_timeout (cURL file download timeout) int 300000 5000 2147483647 +[**Client Debugging] [client] + +# Key for toggling the camera update. Only usable with 'debug' privilege. +keymap_toggle_update_camera (Toggle camera update) key + +# Key for switching to the previous entry in Quicktune. +keymap_quicktune_prev (Quicktune: select previous entry) key + +# Key for switching to the next entry in Quicktune. +keymap_quicktune_next (Quicktune: select next entry) key + +# Key for decrementing the selected value in Quicktune. +keymap_quicktune_dec (Quicktune: decrement value) key + +# Key for incrementing the selected value in Quicktune. +keymap_quicktune_inc (Quicktune: increment value) key + [**Miscellaneous] # Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output. @@ -2345,226 +2585,3 @@ show_technical_names (Show technical names) bool false # Controlled by a checkbox in the settings menu. show_advanced (Show advanced settings) bool false - -# Key for moving the player forward. -keymap_forward (Forward key) key KEY_KEY_W - -# Key for moving the player backward. -# Will also disable autoforward, when active. -keymap_backward (Backward key) key KEY_KEY_S - -# Key for moving the player left. -keymap_left (Left key) key KEY_KEY_A - -# Key for moving the player right. -keymap_right (Right key) key KEY_KEY_D - -# Key for jumping. -keymap_jump (Jump key) key KEY_SPACE - -# Key for sneaking. -# Also used for climbing down and descending in water if aux1_descends is disabled. -keymap_sneak (Sneak key) key KEY_LSHIFT - -# Key for digging, punching or using something. -# (Note: The actual meaning might vary on a per-game basis.) -keymap_dig (Dig/punch/use key) key KEY_LBUTTON - -# Key for placing an item/block or for using something. -# (Note: The actual meaning might vary on a per-game basis.) -keymap_place (Place/use key) key KEY_RBUTTON - -# Key for opening the inventory. -keymap_inventory (Inventory key) key KEY_KEY_I - -# Key for moving fast in fast mode. -keymap_aux1 (Aux1 key) key KEY_KEY_E - -# Key for opening the chat window. -keymap_chat (Chat key) key KEY_KEY_T - -# Key for opening the chat window to type commands. -keymap_cmd (Command key) key / - -# Key for opening the chat window to type local commands. -keymap_cmd_local (Command key) key . - -# Key for toggling unlimited view range. -keymap_rangeselect (Range select key) key - -# Key for toggling flying. -keymap_freemove (Fly key) key KEY_KEY_K - -# Key for toggling pitch move mode. -keymap_pitchmove (Pitch move key) key - -# Key for toggling fast mode. -keymap_fastmove (Fast key) key KEY_KEY_J - -# Key for toggling noclip mode. -keymap_noclip (Noclip key) key KEY_KEY_H - -# Key for selecting the next item in the hotbar. -keymap_hotbar_next (Hotbar next key) key KEY_KEY_N - -# Key for selecting the previous item in the hotbar. -keymap_hotbar_previous (Hotbar previous key) key KEY_KEY_B - -# Key for muting the game. -keymap_mute (Mute key) key KEY_KEY_M - -# Key for increasing the volume. -keymap_increase_volume (Inc. volume key) key - -# Key for decreasing the volume. -keymap_decrease_volume (Dec. volume key) key - -# Key for toggling autoforward. -keymap_autoforward (Automatic forward key) key - -# Key for toggling cinematic mode. -keymap_cinematic (Cinematic mode key) key - -# Key for toggling display of minimap. -keymap_minimap (Minimap key) key KEY_KEY_V - -# Key for taking screenshots. -keymap_screenshot (Screenshot) key KEY_F12 - -# Key for toggling fullscreen mode. -keymap_fullscreen (Fullscreen key) key KEY_F11 - -# Key for dropping the currently selected item. -keymap_drop (Drop item key) key KEY_KEY_Q - -# Key to use view zoom when possible. -keymap_zoom (View zoom key) key KEY_KEY_Z - -# Key for selecting the first hotbar slot. -keymap_slot1 (Hotbar slot 1 key) key KEY_KEY_1 - -# Key for selecting the second hotbar slot. -keymap_slot2 (Hotbar slot 2 key) key KEY_KEY_2 - -# Key for selecting the third hotbar slot. -keymap_slot3 (Hotbar slot 3 key) key KEY_KEY_3 - -# Key for selecting the fourth hotbar slot. -keymap_slot4 (Hotbar slot 4 key) key KEY_KEY_4 - -# Key for selecting the fifth hotbar slot. -keymap_slot5 (Hotbar slot 5 key) key KEY_KEY_5 - -# Key for selecting the sixth hotbar slot. -keymap_slot6 (Hotbar slot 6 key) key KEY_KEY_6 - -# Key for selecting the seventh hotbar slot. -keymap_slot7 (Hotbar slot 7 key) key KEY_KEY_7 - -# Key for selecting the eighth hotbar slot. -keymap_slot8 (Hotbar slot 8 key) key KEY_KEY_8 - -# Key for selecting the ninth hotbar slot. -keymap_slot9 (Hotbar slot 9 key) key KEY_KEY_9 - -# Key for selecting the tenth hotbar slot. -keymap_slot10 (Hotbar slot 10 key) key KEY_KEY_0 - -# Key for selecting the 11th hotbar slot. -keymap_slot11 (Hotbar slot 11 key) key - -# Key for selecting the 12th hotbar slot. -keymap_slot12 (Hotbar slot 12 key) key - -# Key for selecting the 13th hotbar slot. -keymap_slot13 (Hotbar slot 13 key) key - -# Key for selecting the 14th hotbar slot. -keymap_slot14 (Hotbar slot 14 key) key - -# Key for selecting the 15th hotbar slot. -keymap_slot15 (Hotbar slot 15 key) key - -# Key for selecting the 16th hotbar slot. -keymap_slot16 (Hotbar slot 16 key) key - -# Key for selecting the 17th hotbar slot. -keymap_slot17 (Hotbar slot 17 key) key - -# Key for selecting the 18th hotbar slot. -keymap_slot18 (Hotbar slot 18 key) key - -# Key for selecting the 19th hotbar slot. -keymap_slot19 (Hotbar slot 19 key) key - -# Key for selecting the 20th hotbar slot. -keymap_slot20 (Hotbar slot 20 key) key - -# Key for selecting the 21st hotbar slot. -keymap_slot21 (Hotbar slot 21 key) key - -# Key for selecting the 22nd hotbar slot. -keymap_slot22 (Hotbar slot 22 key) key - -# Key for selecting the 23rd hotbar slot. -keymap_slot23 (Hotbar slot 23 key) key - -# Key for selecting the 24th hotbar slot. -keymap_slot24 (Hotbar slot 24 key) key - -# Key for selecting the 25th hotbar slot. -keymap_slot25 (Hotbar slot 25 key) key - -# Key for selecting the 26th hotbar slot. -keymap_slot26 (Hotbar slot 26 key) key - -# Key for selecting the 27th hotbar slot. -keymap_slot27 (Hotbar slot 27 key) key - -# Key for selecting the 28th hotbar slot. -keymap_slot28 (Hotbar slot 28 key) key - -# Key for selecting the 29th hotbar slot. -keymap_slot29 (Hotbar slot 29 key) key - -# Key for selecting the 30th hotbar slot. -keymap_slot30 (Hotbar slot 30 key) key - -# Key for selecting the 31st hotbar slot. -keymap_slot31 (Hotbar slot 31 key) key - -# Key for selecting the 32nd hotbar slot. -keymap_slot32 (Hotbar slot 32 key) key - -# Key for toggling the display of the HUD. -keymap_toggle_hud (HUD toggle key) key KEY_F1 - -# Key for toggling the display of chat. -keymap_toggle_chat (Chat toggle key) key KEY_F2 - -# Key for toggling the display of the large chat console. -keymap_console (Large chat console key) key KEY_F10 - -# Key for toggling the display of fog. -keymap_toggle_fog (Fog toggle key) key KEY_F3 - -# Key for toggling the camera update. Only usable with 'debug' privilege. -keymap_toggle_update_camera (Camera update toggle key) key - -# Key for toggling the display of debug info. -keymap_toggle_debug (Debug info toggle key) key KEY_F5 - -# Key for toggling the display of the profiler. Used for development. -keymap_toggle_profiler (Profiler toggle key) key KEY_F6 - -# Key for toggling the display of mapblock boundaries. -keymap_toggle_block_bounds (Block bounds toggle key) key - -# Key for switching between first- and third-person camera. -keymap_camera_mode (Toggle camera mode key) key KEY_KEY_C - -# Key for increasing the viewing range. -keymap_increase_viewing_range_min (View range increase key) key + - -# Key for decreasing the viewing range. -keymap_decrease_viewing_range_min (View range decrease key) key - diff --git a/doc/menu_lua_api.md b/doc/menu_lua_api.md index 0fccf37a3..38940a7ed 100644 --- a/doc/menu_lua_api.md +++ b/doc/menu_lua_api.md @@ -217,7 +217,6 @@ GUI doing tiling (background only) * `core.set_clouds()` * `core.set_topleft_text(text)` -* `core.show_keys_menu()` * `core.show_touchscreen_layout()` * `core.show_path_select_dialog(formname, caption, is_file_select)` * shows a path select dialog diff --git a/src/client/game_formspec.cpp b/src/client/game_formspec.cpp index dc4be3699..3b86ae7e3 100644 --- a/src/client/game_formspec.cpp +++ b/src/client/game_formspec.cpp @@ -16,7 +16,6 @@ #include "gui/touchcontrols.h" #include "gui/touchscreeneditor.h" #include "gui/guiPasswordChange.h" -#include "gui/guiKeyChangeMenu.h" #include "gui/guiPasswordChange.h" #include "gui/guiOpenURL.h" #include "gui/guiVolumeChange.h" @@ -538,12 +537,6 @@ bool GameFormSpec::handleCallbacks() g_gamecallback->changevolume_requested = false; } - if (g_gamecallback->keyconfig_requested) { - (void)make_irr(guienv, guiroot, -1, - &g_menumgr, texture_src); - g_gamecallback->keyconfig_requested = false; - } - if (g_gamecallback->touchscreenlayout_requested) { (new GUITouchscreenLayout(guienv, guiroot, -1, &g_menumgr, texture_src))->drop(); @@ -556,11 +549,6 @@ bool GameFormSpec::handleCallbacks() g_gamecallback->show_open_url_dialog.clear(); } - if (g_gamecallback->keyconfig_changed) { - m_input->reloadKeybindings(); // update the cache with new settings - g_gamecallback->keyconfig_changed = false; - } - return true; } diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp index e7bdd4f30..64c9cc968 100644 --- a/src/client/inputhandler.cpp +++ b/src/client/inputhandler.cpp @@ -14,6 +14,8 @@ void MyEventReceiver::reloadKeybindings() { + clearKeyCache(); + keybindings[KeyType::FORWARD] = getKeySetting("keymap_forward"); keybindings[KeyType::BACKWARD] = getKeySetting("keymap_backward"); keybindings[KeyType::LEFT] = getKeySetting("keymap_left"); diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h index fec52a74d..85da30ff8 100644 --- a/src/client/inputhandler.h +++ b/src/client/inputhandler.h @@ -12,6 +12,8 @@ #include #include #include "keycode.h" +#include "settings.h" +#include "util/string.h" class InputHandler; @@ -132,6 +134,13 @@ private: class InputHandler { public: + InputHandler() + { + for (const auto &name: Settings::getLayer(SL_DEFAULTS)->getNames()) + if (str_starts_with(name, "keymap_")) + g_settings->registerChangedCallback(name, &settingChangedCallback, this); + } + virtual ~InputHandler() = default; virtual bool isRandom() const @@ -163,6 +172,11 @@ public: virtual void clear() {} virtual void releaseAllKeys() {} + static void settingChangedCallback(const std::string &name, void *data) + { + static_cast(data)->reloadKeybindings(); + } + JoystickController joystick; }; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 26fd5bfcf..0c1db2ae0 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -5,6 +5,7 @@ set(gui_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/guiButton.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiButtonImage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiButtonItemImage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/guiButtonKey.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiEditBox.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp @@ -12,7 +13,6 @@ set(gui_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiInventoryList.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiItemImage.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/guiKeyChangeMenu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiOpenURL.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiPathSelectMenu.cpp diff --git a/src/gui/guiButtonKey.cpp b/src/gui/guiButtonKey.cpp new file mode 100644 index 000000000..85e3719b1 --- /dev/null +++ b/src/gui/guiButtonKey.cpp @@ -0,0 +1,141 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "guiButtonKey.h" +using namespace irr::gui; + +GUIButtonKey *GUIButtonKey::addButton(IGUIEnvironment *environment, + const core::rect &rectangle, ISimpleTextureSource *tsrc, + IGUIElement *parent, s32 id, const wchar_t *text, + const wchar_t *tooltiptext) +{ + auto button = make_irr(environment, + parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc); + + if (text) + button->setText(text); + + if (tooltiptext) + button->setToolTipText(tooltiptext); + + return button.get(); +} + +void GUIButtonKey::setKey(KeyPress kp) +{ + key_value = kp; + keysym = utf8_to_wide(kp.sym()); + super::setText(wstrgettext(kp.name()).c_str()); +} + +void GUIButtonKey::sendKey() +{ + if (Parent) { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = nullptr; + e.GUIEvent.EventType = EGET_BUTTON_CLICKED; + Parent->OnEvent(e); + } +} + +bool GUIButtonKey::OnEvent(const SEvent & event) +{ + switch(event.EventType) + { + case EET_KEY_INPUT_EVENT: + if (!event.KeyInput.PressedDown) { + bool wasPressed = isPressed(); + setPressed(false); + if (capturing) { + cancelCapture(); + if (event.KeyInput.Key != KEY_ESCAPE) + sendKey(); + return true; + } else if (wasPressed && (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) { + startCapture(); + return true; + } + break; + } else if (capturing) { + if (event.KeyInput.Key != KEY_ESCAPE) { + setPressed(true); + setKey(KeyPress(event.KeyInput)); + } + return true; + } else if (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE) { + setPressed(true); + return true; + } + break; + case EET_MOUSE_INPUT_EVENT: { + auto in_rect = AbsoluteClippingRect.isPointInside( + core::position2d(event.MouseInput.X, event.MouseInput.Y)); + switch (event.MouseInput.Event) + { + case EMIE_LMOUSE_LEFT_UP: + if (!capturing && in_rect) { + setPressed(false); + startCapture(); + return true; + } + [[fallthrough]]; + case EMIE_MMOUSE_LEFT_UP: [[fallthrough]]; + case EMIE_RMOUSE_LEFT_UP: + setPressed(false); + if (capturing) { + cancelCapture(); + sendKey(); + return true; + } + break; + case EMIE_LMOUSE_PRESSED_DOWN: + if (capturing) { + if (event.MouseInput.Simulated) { + cancelCapture(true); + if (in_rect) + return true; + } else { + setPressed(true); + setKey(LMBKey); + return true; + } + } else if (in_rect) { + Environment->setFocus(this); + setPressed(true); + return true; + } + break; + case EMIE_MMOUSE_PRESSED_DOWN: + if (capturing) { + setPressed(true); + setKey(MMBKey); + return true; + } + break; + case EMIE_RMOUSE_PRESSED_DOWN: + if (capturing) { + setPressed(true); + setKey(RMBKey); + return true; + } + break; + default: + break; + } + break; + } + case EET_GUI_EVENT: + if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) { + if (capturing) + return true; + else + nostart = false; // lift nostart restriction if "mouse" (finger) is released outside the button + } + default: + break; + } + + return Parent ? Parent->OnEvent(event) : false; +} diff --git a/src/gui/guiButtonKey.h b/src/gui/guiButtonKey.h new file mode 100644 index 000000000..75d0d56ee --- /dev/null +++ b/src/gui/guiButtonKey.h @@ -0,0 +1,75 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include "guiButton.h" +#include "client/keycode.h" +#include "util/string.h" +#include "gettext.h" + +using namespace irr; + +class GUIButtonKey : public GUIButton +{ + using super = GUIButton; + +public: + //! Constructor + GUIButtonKey(gui::IGUIEnvironment *environment, gui::IGUIElement *parent, + s32 id, core::rect rectangle, ISimpleTextureSource *tsrc, + bool noclip = false) + : GUIButton(environment, parent, id, rectangle, tsrc, noclip) {} + + //! Sets the text for the key field + virtual void setText(const wchar_t *text) override + { + setKey(wide_to_utf8(text)); + } + + //! Gets the value for the key field + virtual const wchar_t *getText() const override + { + return keysym.c_str(); + } + + //! Do not drop returned handle + static GUIButtonKey *addButton(gui::IGUIEnvironment *environment, + const core::rect &rectangle, ISimpleTextureSource *tsrc, + IGUIElement *parent, s32 id, const wchar_t *text = L"", + const wchar_t *tooltiptext = L""); + + //! Called if an event happened + virtual bool OnEvent(const SEvent &event) override; + +private: + void sendKey(); + + //! Start key capture + void startCapture() + { + if (nostart) { + nostart = false; + return; + } + capturing = true; + super::setText(wstrgettext("Press Button").c_str()); + } + + //! Cancel key capture + // inhibit_restart: whether the next call to startCapture should be inhibited + void cancelCapture(bool inhibit_restart = false) + { + capturing = false; + nostart |= inhibit_restart; + super::setText(wstrgettext(key_value.name()).c_str()); + } + + //! Sets the captured key and stop capturing + void setKey(KeyPress key); + + bool capturing = false; + bool nostart = false; + KeyPress key_value = {}; + std::wstring keysym; +}; diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 39d8797b4..3c5a9ffde 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -47,6 +47,7 @@ #include "guiButton.h" #include "guiButtonImage.h" #include "guiButtonItemImage.h" +#include "guiButtonKey.h" #include "guiEditBoxWithScrollbar.h" #include "guiInventoryList.h" #include "guiItemImage.h" @@ -1025,8 +1026,16 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element) if (data->type == "button_url" || data->type == "button_url_exit") spec.url = url; - GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc, - data->current_parent, spec.fid, spec.flabel.c_str()); + GUIButton *e; + + if (data->type == "button_key") { + spec.ftype = f_Unknown; + e = GUIButtonKey::addButton(Environment, rect, m_tsrc, + data->current_parent, spec.fid, spec.flabel.c_str()); + } else { + e = GUIButton::addButton(Environment, rect, m_tsrc, + data->current_parent, spec.fid, spec.flabel.c_str()); + } auto style = getStyleForElement(data->type, name, (data->type != "button") ? "button" : ""); @@ -2873,6 +2882,7 @@ const std::unordered_map -// Copyright (C) 2013 Ciaran Gultnieks -// Copyright (C) 2013 teddydestodes - -#include "guiKeyChangeMenu.h" -#include "debug.h" -#include "guiButton.h" -#include -#include -#include -#include -#include -#include -#include -#include "settings.h" -#include "gettext.h" - -#include "mainmenumanager.h" // for g_gamecallback - -#define KMaxButtonPerColumns 12 - -extern MainGameCallback *g_gamecallback; - -enum -{ - GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR, - // buttons - GUI_ID_KEY_FORWARD_BUTTON, - GUI_ID_KEY_BACKWARD_BUTTON, - GUI_ID_KEY_LEFT_BUTTON, - GUI_ID_KEY_RIGHT_BUTTON, - GUI_ID_KEY_AUX1_BUTTON, - GUI_ID_KEY_FLY_BUTTON, - GUI_ID_KEY_FAST_BUTTON, - GUI_ID_KEY_JUMP_BUTTON, - GUI_ID_KEY_NOCLIP_BUTTON, - GUI_ID_KEY_PITCH_MOVE, - GUI_ID_KEY_CHAT_BUTTON, - GUI_ID_KEY_CMD_BUTTON, - GUI_ID_KEY_CMD_LOCAL_BUTTON, - GUI_ID_KEY_CONSOLE_BUTTON, - GUI_ID_KEY_SNEAK_BUTTON, - GUI_ID_KEY_DROP_BUTTON, - GUI_ID_KEY_INVENTORY_BUTTON, - GUI_ID_KEY_HOTBAR_PREV_BUTTON, - GUI_ID_KEY_HOTBAR_NEXT_BUTTON, - GUI_ID_KEY_MUTE_BUTTON, - GUI_ID_KEY_DEC_VOLUME_BUTTON, - GUI_ID_KEY_INC_VOLUME_BUTTON, - GUI_ID_KEY_RANGE_BUTTON, - GUI_ID_KEY_ZOOM_BUTTON, - GUI_ID_KEY_CAMERA_BUTTON, - GUI_ID_KEY_MINIMAP_BUTTON, - GUI_ID_KEY_SCREENSHOT_BUTTON, - GUI_ID_KEY_CHATLOG_BUTTON, - GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, - GUI_ID_KEY_HUD_BUTTON, - GUI_ID_KEY_FOG_BUTTON, - GUI_ID_KEY_DEC_RANGE_BUTTON, - GUI_ID_KEY_INC_RANGE_BUTTON, - GUI_ID_KEY_AUTOFWD_BUTTON, - // other - GUI_ID_CB_AUX1_DESCENDS, - GUI_ID_CB_DOUBLETAP_JUMP, - GUI_ID_CB_AUTOJUMP, -}; - -GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env, - gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, - ISimpleTextureSource *tsrc) : - GUIModalMenu(env, parent, id, menumgr), - m_tsrc(tsrc) -{ - init_keys(); -} - -GUIKeyChangeMenu::~GUIKeyChangeMenu() -{ - removeAllChildren(); - key_used_text = nullptr; - - for (key_setting *ks : key_settings) { - delete ks; - } - key_settings.clear(); -} - -void GUIKeyChangeMenu::regenerateGui(v2u32 screensize) -{ - removeAllChildren(); - key_used_text = nullptr; - - ScalingInfo info = getScalingInfo(screensize, v2u32(835, 430)); - const float s = info.scale; - DesiredRect = info.rect; - recalculateAbsolutePosition(false); - - v2s32 size = DesiredRect.getSize(); - v2s32 topleft(0, 0); - - { - core::rect rect(0, 0, 600 * s, 40 * s); - rect += topleft + v2s32(25 * s, 3 * s); - //gui::IGUIStaticText *t = - gui::StaticText::add(Environment, wstrgettext("Keybindings."), rect, - false, true, this, -1); - //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT); - } - - // Build buttons - - v2s32 offset(25 * s, 60 * s); - - for(size_t i = 0; i < key_settings.size(); i++) - { - key_setting *k = key_settings.at(i); - { - core::rect rect(0, 0, 150 * s, 20 * s); - rect += topleft + v2s32(offset.X, offset.Y); - gui::StaticText::add(Environment, k->button_name, rect, - false, true, this, -1); - } - - { - core::rect rect(0, 0, 100 * s, 30 * s); - rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s); - k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, - wstrgettext(k->key.name()).c_str()); - } - if ((i + 1) % KMaxButtonPerColumns == 0) { - offset.X += 260 * s; - offset.Y = 60 * s; - } else { - offset += v2s32(0, 25 * s); - } - } - - { - s32 option_x = offset.X; - s32 option_y = offset.Y + 5 * s; - u32 option_w = 180 * s; - { - core::rect rect(0, 0, option_w, 30 * s); - rect += topleft + v2s32(option_x, option_y); - Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this, - GUI_ID_CB_AUX1_DESCENDS, wstrgettext("\"Aux1\" = climb down").c_str()); - } - offset += v2s32(0, 25 * s); - } - - { - s32 option_x = offset.X; - s32 option_y = offset.Y + 5 * s; - u32 option_w = 280 * s; - { - core::rect rect(0, 0, option_w, 30 * s); - rect += topleft + v2s32(option_x, option_y); - Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this, - GUI_ID_CB_DOUBLETAP_JUMP, wstrgettext("Double tap \"jump\" to toggle fly").c_str()); - } - offset += v2s32(0, 25 * s); - } - - { - s32 option_x = offset.X; - s32 option_y = offset.Y + 5 * s; - u32 option_w = 280; - { - core::rect rect(0, 0, option_w, 30 * s); - rect += topleft + v2s32(option_x, option_y); - Environment->addCheckBox(g_settings->getBool("autojump"), rect, this, - GUI_ID_CB_AUTOJUMP, wstrgettext("Automatic jumping").c_str()); - } - offset += v2s32(0, 25); - } - - { - core::rect rect(0, 0, 100 * s, 30 * s); - rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s); - GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, - wstrgettext("Save").c_str()); - } - { - core::rect rect(0, 0, 100 * s, 30 * s); - rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s); - GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, - wstrgettext("Cancel").c_str()); - } -} - -void GUIKeyChangeMenu::drawMenu() -{ - gui::IGUISkin* skin = Environment->getSkin(); - if (!skin) - return; - video::IVideoDriver* driver = Environment->getVideoDriver(); - - video::SColor bgcolor(140, 0, 0, 0); - driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); - - gui::IGUIElement::draw(); -} - -bool GUIKeyChangeMenu::acceptInput() -{ - clearKeyCache(); - - for (key_setting *k : key_settings) { - std::string default_key; - Settings::getLayer(SL_DEFAULTS)->getNoEx(k->setting_name, default_key); - - if (k->key.sym() != default_key) - g_settings->set(k->setting_name, k->key.sym()); - else - g_settings->remove(k->setting_name); - } - - { - gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS); - if(e && e->getType() == gui::EGUIET_CHECK_BOX) - g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked()); - } - { - gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP); - if(e && e->getType() == gui::EGUIET_CHECK_BOX) - g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked()); - } - { - gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP); - if(e && e->getType() == gui::EGUIET_CHECK_BOX) - g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked()); - } - - g_gamecallback->signalKeyConfigChange(); - - return true; -} - -bool GUIKeyChangeMenu::resetMenu() -{ - if (active_key) { - active_key->button->setText(wstrgettext(active_key->key.name()).c_str()); - active_key = nullptr; - return false; - } - return true; -} -bool GUIKeyChangeMenu::OnEvent(const SEvent& event) -{ - if (event.EventType == EET_KEY_INPUT_EVENT && active_key - && event.KeyInput.PressedDown) { - - KeyPress kp(event.KeyInput); - - if (event.KeyInput.Key == irr::KEY_DELETE) - kp = KeyPress(""); // To erase key settings - else if (event.KeyInput.Key == irr::KEY_ESCAPE) - kp = active_key->key; // Cancel - - bool shift_went_down = false; - if(!shift_down && - (event.KeyInput.Key == irr::KEY_SHIFT || - event.KeyInput.Key == irr::KEY_LSHIFT || - event.KeyInput.Key == irr::KEY_RSHIFT)) - shift_went_down = true; - - // Display Key already in use message - bool key_in_use = false; - if (kp) { - for (key_setting *ks : key_settings) { - if (ks != active_key && ks->key == kp) { - key_in_use = true; - break; - } - } - } - - if (key_in_use && !this->key_used_text) { - core::rect rect(0, 0, 600, 40); - rect += v2s32(0, 0) + v2s32(25, 30); - this->key_used_text = gui::StaticText::add(Environment, - wstrgettext("Key already in use"), - rect, false, true, this, -1); - } else if (!key_in_use && this->key_used_text) { - this->key_used_text->remove(); - this->key_used_text = nullptr; - } - - // But go on - { - active_key->key = kp; - active_key->button->setText(wstrgettext(kp.name()).c_str()); - - // Allow characters made with shift - if (shift_went_down){ - shift_down = true; - return false; - } - - active_key = nullptr; - return true; - } - } else if (event.EventType == EET_KEY_INPUT_EVENT && !active_key - && event.KeyInput.PressedDown - && event.KeyInput.Key == irr::KEY_ESCAPE) { - quitMenu(); - return true; - } else if (event.EventType == EET_GUI_EVENT) { - if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST - && isVisible()) - { - if (!canTakeFocus(event.GUIEvent.Element)) - { - infostream << "GUIKeyChangeMenu: Not allowing focus change." - << std::endl; - // Returning true disables focus change - return true; - } - } - if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED) - { - switch (event.GUIEvent.Caller->getID()) - { - case GUI_ID_BACK_BUTTON: //back - acceptInput(); - quitMenu(); - return true; - case GUI_ID_ABORT_BUTTON: //abort - quitMenu(); - return true; - default: - resetMenu(); - for (key_setting *ks : key_settings) { - if (ks->id == event.GUIEvent.Caller->getID()) { - active_key = ks; - break; - } - } - FATAL_ERROR_IF(!active_key, "Key setting not found"); - - shift_down = false; - active_key->button->setText(wstrgettext("press key").c_str()); - break; - } - Environment->setFocus(this); - } - } - return Parent ? Parent->OnEvent(event) : false; -} - -void GUIKeyChangeMenu::add_key(int id, std::wstring button_name, const std::string &setting_name) -{ - key_setting *k = new key_setting; - k->id = id; - - k->button_name = std::move(button_name); - k->setting_name = setting_name; - k->key = getKeySetting(k->setting_name.c_str()); - key_settings.push_back(k); -} - -// compare with button_titles in touchcontrols.cpp -void GUIKeyChangeMenu::init_keys() -{ - this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wstrgettext("Forward"), "keymap_forward"); - this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wstrgettext("Backward"), "keymap_backward"); - this->add_key(GUI_ID_KEY_LEFT_BUTTON, wstrgettext("Left"), "keymap_left"); - this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wstrgettext("Right"), "keymap_right"); - this->add_key(GUI_ID_KEY_AUX1_BUTTON, wstrgettext("Aux1"), "keymap_aux1"); - this->add_key(GUI_ID_KEY_JUMP_BUTTON, wstrgettext("Jump"), "keymap_jump"); - this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wstrgettext("Sneak"), "keymap_sneak"); - this->add_key(GUI_ID_KEY_DROP_BUTTON, wstrgettext("Drop"), "keymap_drop"); - this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wstrgettext("Inventory"), "keymap_inventory"); - this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON, wstrgettext("Prev. item"), "keymap_hotbar_previous"); - this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON, wstrgettext("Next item"), "keymap_hotbar_next"); - this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wstrgettext("Zoom"), "keymap_zoom"); - this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wstrgettext("Change camera"), "keymap_camera_mode"); - this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wstrgettext("Toggle minimap"), "keymap_minimap"); - this->add_key(GUI_ID_KEY_FLY_BUTTON, wstrgettext("Toggle fly"), "keymap_freemove"); - this->add_key(GUI_ID_KEY_PITCH_MOVE, wstrgettext("Toggle pitchmove"), "keymap_pitchmove"); - this->add_key(GUI_ID_KEY_FAST_BUTTON, wstrgettext("Toggle fast"), "keymap_fastmove"); - this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wstrgettext("Toggle noclip"), "keymap_noclip"); - this->add_key(GUI_ID_KEY_MUTE_BUTTON, wstrgettext("Mute"), "keymap_mute"); - this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON, wstrgettext("Dec. volume"), "keymap_decrease_volume"); - this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON, wstrgettext("Inc. volume"), "keymap_increase_volume"); - this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wstrgettext("Autoforward"), "keymap_autoforward"); - this->add_key(GUI_ID_KEY_CHAT_BUTTON, wstrgettext("Chat"), "keymap_chat"); - this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON, wstrgettext("Screenshot"), "keymap_screenshot"); - this->add_key(GUI_ID_KEY_RANGE_BUTTON, wstrgettext("Range select"), "keymap_rangeselect"); - this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wstrgettext("Dec. range"), "keymap_decrease_viewing_range_min"); - this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wstrgettext("Inc. range"), "keymap_increase_viewing_range_min"); - this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wstrgettext("Console"), "keymap_console"); - this->add_key(GUI_ID_KEY_CMD_BUTTON, wstrgettext("Command"), "keymap_cmd"); - this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wstrgettext("Local command"), "keymap_cmd_local"); - this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, wstrgettext("Block bounds"), "keymap_toggle_block_bounds"); - this->add_key(GUI_ID_KEY_HUD_BUTTON, wstrgettext("Toggle HUD"), "keymap_toggle_hud"); - this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wstrgettext("Toggle chat log"), "keymap_toggle_chat"); - this->add_key(GUI_ID_KEY_FOG_BUTTON, wstrgettext("Toggle fog"), "keymap_toggle_fog"); -} diff --git a/src/gui/guiKeyChangeMenu.h b/src/gui/guiKeyChangeMenu.h deleted file mode 100644 index c858b2c93..000000000 --- a/src/gui/guiKeyChangeMenu.h +++ /dev/null @@ -1,63 +0,0 @@ -// Luanti -// SPDX-License-Identifier: LGPL-2.1-or-later -// Copyright (C) 2010-2013 celeron55, Perttu Ahola -// Copyright (C) 2013 Ciaran Gultnieks -// Copyright (C) 2013 teddydestodes - -#pragma once - -#include "modalMenu.h" -#include "client/keycode.h" -#include -#include -#include - -class ISimpleTextureSource; - -struct key_setting -{ - int id; - std::wstring button_name; - KeyPress key; - std::string setting_name; - gui::IGUIButton *button; -}; - -class GUIKeyChangeMenu : public GUIModalMenu -{ -public: - GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, - IMenuManager *menumgr, ISimpleTextureSource *tsrc); - ~GUIKeyChangeMenu(); - - /* - Remove and re-add (or reposition) stuff - */ - void regenerateGui(v2u32 screensize); - - void drawMenu(); - - bool acceptInput(); - - bool OnEvent(const SEvent &event); - - bool pausesGame() { return true; } - -protected: - std::wstring getLabelByID(s32 id) { return L""; } - std::string getNameByID(s32 id) { return ""; } - -private: - void init_keys(); - - bool resetMenu(); - - void add_key(int id, std::wstring button_name, const std::string &setting_name); - - bool shift_down = false; - - key_setting *active_key = nullptr; - gui::IGUIStaticText *key_used_text = nullptr; - std::vector key_settings; - ISimpleTextureSource *m_tsrc; -}; diff --git a/src/gui/mainmenumanager.h b/src/gui/mainmenumanager.h index 2ac00fee7..9b5bea5f7 100644 --- a/src/gui/mainmenumanager.h +++ b/src/gui/mainmenumanager.h @@ -22,12 +22,10 @@ class IGameCallback public: virtual void exitToOS() = 0; virtual void openSettings() = 0; - virtual void keyConfig() = 0; virtual void disconnect() = 0; virtual void changePassword() = 0; virtual void changeVolume() = 0; virtual void showOpenURLDialog(const std::string &url) = 0; - virtual void signalKeyConfigChange() = 0; virtual void touchscreenLayout() = 0; }; @@ -136,16 +134,6 @@ public: changevolume_requested = true; } - void keyConfig() override - { - keyconfig_requested = true; - } - - void signalKeyConfigChange() override - { - keyconfig_changed = true; - } - void touchscreenLayout() override { touchscreenlayout_requested = true; @@ -160,10 +148,8 @@ public: bool settings_requested = false; bool changepassword_requested = false; bool changevolume_requested = false; - bool keyconfig_requested = false; bool touchscreenlayout_requested = false; bool shutdown_requested = false; - bool keyconfig_changed = false; std::string show_open_url_dialog = ""; }; diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 240927a4a..3d096e018 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -9,7 +9,6 @@ #include "scripting_mainmenu.h" #include "gui/guiEngine.h" #include "gui/guiMainMenu.h" -#include "gui/guiKeyChangeMenu.h" #include "gui/guiPathSelectMenu.h" #include "gui/touchscreeneditor.h" #include "version.h" @@ -538,22 +537,6 @@ int ModApiMainMenu::l_get_content_translation(lua_State *L) return 1; } -/******************************************************************************/ -int ModApiMainMenu::l_show_keys_menu(lua_State *L) -{ - GUIEngine *engine = getGuiEngine(L); - sanity_check(engine != NULL); - - GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu( - engine->m_rendering_engine->get_gui_env(), - engine->m_parent, - -1, - engine->m_menumanager, - engine->m_texture_source.get()); - kmenu->drop(); - return 0; -} - /******************************************************************************/ int ModApiMainMenu::l_show_touchscreen_layout(lua_State *L) { @@ -1070,7 +1053,6 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(get_content_translation); API_FCT(start); API_FCT(close); - API_FCT(show_keys_menu); API_FCT(show_touchscreen_layout); API_FCT(create_world); API_FCT(delete_world); diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 63f45d74b..fc2d90af8 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -65,8 +65,6 @@ private: //gui - static int l_show_keys_menu(lua_State *L); - static int l_show_touchscreen_layout(lua_State *L); static int l_show_path_select_dialog(lua_State *L); diff --git a/src/script/lua_api/l_menu_common.cpp b/src/script/lua_api/l_menu_common.cpp index 19c97c042..8b3ffda4e 100644 --- a/src/script/lua_api/l_menu_common.cpp +++ b/src/script/lua_api/l_menu_common.cpp @@ -35,11 +35,21 @@ int ModApiMenuCommon::l_irrlicht_device_supports_touch(lua_State *L) } +int ModApiMenuCommon::l_are_keycodes_equal(lua_State *L) +{ + auto k1 = luaL_checkstring(L, 1); + auto k2 = luaL_checkstring(L, 2); + lua_pushboolean(L, KeyPress(k1) == KeyPress(k2)); + return 1; +} + + void ModApiMenuCommon::Initialize(lua_State *L, int top) { API_FCT(gettext); API_FCT(get_active_driver); API_FCT(irrlicht_device_supports_touch); + API_FCT(are_keycodes_equal); } diff --git a/src/script/lua_api/l_menu_common.h b/src/script/lua_api/l_menu_common.h index e94e562e1..8cbd58f11 100644 --- a/src/script/lua_api/l_menu_common.h +++ b/src/script/lua_api/l_menu_common.h @@ -13,6 +13,7 @@ private: static int l_gettext(lua_State *L); static int l_get_active_driver(lua_State *L); static int l_irrlicht_device_supports_touch(lua_State *L); + static int l_are_keycodes_equal(lua_State *L); public: static void Initialize(lua_State *L, int top); diff --git a/src/script/lua_api/l_pause_menu.cpp b/src/script/lua_api/l_pause_menu.cpp index c2a9a81e5..b1aaae185 100644 --- a/src/script/lua_api/l_pause_menu.cpp +++ b/src/script/lua_api/l_pause_menu.cpp @@ -3,18 +3,12 @@ // Copyright (C) 2025 grorp #include "l_pause_menu.h" +#include "client/keycode.h" #include "gui/mainmenumanager.h" #include "lua_api/l_internal.h" #include "client/client.h" -int ModApiPauseMenu::l_show_keys_menu(lua_State *L) -{ - g_gamecallback->keyConfig(); - return 0; -} - - int ModApiPauseMenu::l_show_touchscreen_layout(lua_State *L) { g_gamecallback->touchscreenLayout(); @@ -31,7 +25,6 @@ int ModApiPauseMenu::l_is_internal_server(lua_State *L) void ModApiPauseMenu::Initialize(lua_State *L, int top) { - API_FCT(show_keys_menu); API_FCT(show_touchscreen_layout); API_FCT(is_internal_server); } diff --git a/src/script/lua_api/l_pause_menu.h b/src/script/lua_api/l_pause_menu.h index 2d7eb62d7..8bb6fe8c3 100644 --- a/src/script/lua_api/l_pause_menu.h +++ b/src/script/lua_api/l_pause_menu.h @@ -9,7 +9,6 @@ class ModApiPauseMenu: public ModApiBase { private: - static int l_show_keys_menu(lua_State *L); static int l_show_touchscreen_layout(lua_State *L); static int l_is_internal_server(lua_State *L); From 2f464843cb57832b71ff617f39aa274a8493a8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20R=C3=BChle?= Date: Sun, 20 Apr 2025 20:48:48 +0200 Subject: [PATCH 015/131] Make it more convenient to customize node drops (#15872) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Provide tool and digger to get_node_drops This gives games/mods the ability to modify node drops depending on item and/or player metadata without overriding node_dig or other workarounds. * Copy wielded item to prevent modification in get_node_drops * Also pass node pos to get_node_drops Allowing properties of the node and its surroundings to affect node drops. * Copy pos to prevent modification in get_node_drops Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> * Don't pass empty item stack to get_node_drops if wielded is nil --------- Co-authored-by: sfan5 Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- builtin/game/item.lua | 3 ++- doc/lua_api.md | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/builtin/game/item.lua b/builtin/game/item.lua index 5dd5312aa..4d68f1136 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -513,7 +513,8 @@ function core.node_dig(pos, node, digger) .. node.name .. " at " .. core.pos_to_string(pos)) local wielded = digger and digger:get_wielded_item() - local drops = core.get_node_drops(node, wielded and wielded:get_name()) + local drops = core.get_node_drops(node, wielded and wielded:get_name(), + wielded and ItemStack(wielded), digger, vector.copy(pos)) if wielded then local wdef = wielded:get_definition() diff --git a/doc/lua_api.md b/doc/lua_api.md index d8e58fcde..e2a55b7e1 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6910,11 +6910,16 @@ Item handling given `param2` value. * Returns `nil` if the given `paramtype2` does not contain color information. -* `core.get_node_drops(node, toolname)` - * Returns list of itemstrings that are dropped by `node` when dug - with the item `toolname` (not limited to tools). +* `core.get_node_drops(node, toolname[, tool, digger, pos])` + * Returns list of itemstrings that are dropped by `node` when dug with the + item `toolname` (not limited to tools). The default implementation doesn't + use `tool`, `digger`, and `pos`, but these are provided by `core.node_dig` + since 5.12.0 for games/mods implementing customized drops. * `node`: node as table or node name * `toolname`: name of the item used to dig (can be `nil`) + * `tool`: `ItemStack` used to dig (can be `nil`) + * `digger`: the ObjectRef that digs the node (can be `nil`) + * `pos`: the pos of the dug node (can be `nil`) * `core.get_craft_result(input)`: returns `output, decremented_input` * `input.method` = `"normal"` or `"cooking"` or `"fuel"` * `input.width` = for example `3` From 5f1ff453c95013af1017ed35c04e067eff7afbaa Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Fri, 4 Apr 2025 01:26:02 +0200 Subject: [PATCH 016/131] Replace `_IRR_DEBUG_BREAK_IF` with assertions --- irr/include/IMeshBuffer.h | 5 +++-- irr/include/IReferenceCounted.h | 3 ++- irr/include/ISceneNode.h | 3 ++- irr/include/SSkinMeshBuffer.h | 3 ++- irr/include/irrArray.h | 17 +++++++-------- irr/include/irrString.h | 7 ++++--- irr/include/irrTypes.h | 23 ++++---------------- irr/include/matrix4.h | 35 ++++++++++++++++--------------- irr/include/vector2d.h | 1 + irr/include/vector3d.h | 1 + irr/src/CGLTFMeshFileLoader.cpp | 3 ++- irr/src/CImage.cpp | 4 +++- irr/src/CIrrDeviceLinux.cpp | 4 ++-- irr/src/CIrrDeviceSDL.cpp | 8 ++++--- irr/src/CMakeLists.txt | 4 ++-- irr/src/CMeshManipulator.cpp | 6 ++++-- irr/src/CNullDriver.cpp | 8 ++++--- irr/src/COpenGLCoreCacheHandler.h | 4 +++- irr/src/COpenGLCoreTexture.h | 22 ++++++++++--------- irr/src/COpenGLDriver.cpp | 16 +++++++------- irr/src/CSceneManager.cpp | 3 ++- irr/src/SkinnedMesh.cpp | 7 ++++--- 22 files changed, 96 insertions(+), 91 deletions(-) diff --git a/irr/include/IMeshBuffer.h b/irr/include/IMeshBuffer.h index 55c05211a..afcf28943 100644 --- a/irr/include/IMeshBuffer.h +++ b/irr/include/IMeshBuffer.h @@ -11,6 +11,7 @@ #include "IIndexBuffer.h" #include "EHardwareBufferFlags.h" #include "EPrimitiveTypes.h" +#include namespace irr { @@ -121,7 +122,7 @@ public: /** \return Pointer to indices array. */ inline const u16 *getIndices() const { - _IRR_DEBUG_BREAK_IF(getIndexBuffer()->getType() != video::EIT_16BIT); + assert(getIndexBuffer()->getType() == video::EIT_16BIT); return static_cast(getIndexBuffer()->getData()); } @@ -129,7 +130,7 @@ public: /** \return Pointer to indices array. */ inline u16 *getIndices() { - _IRR_DEBUG_BREAK_IF(getIndexBuffer()->getType() != video::EIT_16BIT); + assert(getIndexBuffer()->getType() == video::EIT_16BIT); return static_cast(getIndexBuffer()->getData()); } diff --git a/irr/include/IReferenceCounted.h b/irr/include/IReferenceCounted.h index 65c991db2..80454f9ea 100644 --- a/irr/include/IReferenceCounted.h +++ b/irr/include/IReferenceCounted.h @@ -5,6 +5,7 @@ #pragma once #include "irrTypes.h" +#include namespace irr { @@ -118,7 +119,7 @@ public: bool drop() const { // someone is doing bad reference counting. - _IRR_DEBUG_BREAK_IF(ReferenceCounter <= 0) + assert(ReferenceCounter > 0); --ReferenceCounter; if (!ReferenceCounter) { diff --git a/irr/include/ISceneNode.h b/irr/include/ISceneNode.h index c80ff4b48..f91fd6499 100644 --- a/irr/include/ISceneNode.h +++ b/irr/include/ISceneNode.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace irr { @@ -268,7 +269,7 @@ public: return false; // The iterator must be set since the parent is not null. - _IRR_DEBUG_BREAK_IF(!child->ThisIterator.has_value()); + assert(child->ThisIterator.has_value()); auto it = *child->ThisIterator; child->ThisIterator = std::nullopt; child->Parent = nullptr; diff --git a/irr/include/SSkinMeshBuffer.h b/irr/include/SSkinMeshBuffer.h index eb3f7371f..8b2e26882 100644 --- a/irr/include/SSkinMeshBuffer.h +++ b/irr/include/SSkinMeshBuffer.h @@ -8,6 +8,7 @@ #include "CVertexBuffer.h" #include "CIndexBuffer.h" #include "S3DVertex.h" +#include namespace irr { @@ -200,7 +201,7 @@ public: //! append the vertices and indices to the current buffer void append(const void *const vertices, u32 numVertices, const u16 *const indices, u32 numIndices) override { - _IRR_DEBUG_BREAK_IF(true); + assert(false); } //! Describe what kind of primitive geometry is used by the meshbuffer diff --git a/irr/include/irrArray.h b/irr/include/irrArray.h index 834dc825c..2542d0542 100644 --- a/irr/include/irrArray.h +++ b/irr/include/irrArray.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "irrTypes.h" #include "irrMath.h" @@ -108,7 +109,7 @@ public: \param index: Where position to insert the new element. */ void insert(const T &element, u32 index = 0) { - _IRR_DEBUG_BREAK_IF(index > m_data.size()) // access violation + assert(index <= m_data.size()); auto pos = std::next(m_data.begin(), index); m_data.insert(pos, element); is_sorted = false; @@ -190,32 +191,28 @@ public: //! Direct access operator T &operator[](u32 index) { - _IRR_DEBUG_BREAK_IF(index >= m_data.size()) // access violation - + assert(index < m_data.size()); return m_data[index]; } //! Direct const access operator const T &operator[](u32 index) const { - _IRR_DEBUG_BREAK_IF(index >= m_data.size()) // access violation - + assert(index < m_data.size()); return m_data[index]; } //! Gets last element. T &getLast() { - _IRR_DEBUG_BREAK_IF(m_data.empty()) // access violation - + assert(!m_data.empty()); return m_data.back(); } //! Gets last element const T &getLast() const { - _IRR_DEBUG_BREAK_IF(m_data.empty()) // access violation - + assert(!m_data.empty()); return m_data.back(); } @@ -365,7 +362,7 @@ public: \param index: Index of element to be erased. */ void erase(u32 index) { - _IRR_DEBUG_BREAK_IF(index >= m_data.size()) // access violation + assert(index < m_data.size()); auto it = std::next(m_data.begin(), index); m_data.erase(it); } diff --git a/irr/include/irrString.h b/irr/include/irrString.h index 76e0548d3..465664e87 100644 --- a/irr/include/irrString.h +++ b/irr/include/irrString.h @@ -11,6 +11,7 @@ #include #include #include +#include /* HACK: import these string methods from MT's util/string.h */ extern std::wstring utf8_to_wide(std::string_view input); @@ -174,9 +175,9 @@ public: } if constexpr (sizeof(T) != sizeof(B)) { - _IRR_DEBUG_BREAK_IF( - (uintptr_t)c >= (uintptr_t)(str.data()) && - (uintptr_t)c < (uintptr_t)(str.data() + str.size())); + assert( + (uintptr_t)c < (uintptr_t)(str.data()) || + (uintptr_t)c >= (uintptr_t)(str.data() + str.size())); } if ((void *)c == (void *)c_str()) diff --git a/irr/include/irrTypes.h b/irr/include/irrTypes.h index 910991689..9e71d0771 100644 --- a/irr/include/irrTypes.h +++ b/irr/include/irrTypes.h @@ -5,6 +5,7 @@ #pragma once #include +#include namespace irr { @@ -65,22 +66,6 @@ typedef char fschar_t; } // end namespace irr -//! define a break macro for debugging. -#if defined(_DEBUG) -#if defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) -#include -#define _IRR_DEBUG_BREAK_IF(_CONDITION_) \ - if (_CONDITION_) { \ - _CrtDbgBreak(); \ - } -#else -#include -#define _IRR_DEBUG_BREAK_IF(_CONDITION_) assert(!(_CONDITION_)); -#endif -#else -#define _IRR_DEBUG_BREAK_IF(_CONDITION_) -#endif - //! deprecated macro for virtual function override /** prefer to use the override keyword for new code */ #define _IRR_OVERRIDE_ override @@ -89,13 +74,13 @@ typedef char fschar_t; // Note: an assert(false) is included first to catch this in debug builds #if defined(__cpp_lib_unreachable) #include -#define IRR_CODE_UNREACHABLE() do { _IRR_DEBUG_BREAK_IF(1) std::unreachable(); } while(0) +#define IRR_CODE_UNREACHABLE() do { assert(false); std::unreachable(); } while(0) #elif defined(__has_builtin) #if __has_builtin(__builtin_unreachable) -#define IRR_CODE_UNREACHABLE() do { _IRR_DEBUG_BREAK_IF(1) __builtin_unreachable(); } while(0) +#define IRR_CODE_UNREACHABLE() do { assert(false); __builtin_unreachable(); } while(0) #endif #elif defined(_MSC_VER) -#define IRR_CODE_UNREACHABLE() do { _IRR_DEBUG_BREAK_IF(1) __assume(false); } while(0) +#define IRR_CODE_UNREACHABLE() do { assert(false); __assume(false); } while(0) #endif #ifndef IRR_CODE_UNREACHABLE #define IRR_CODE_UNREACHABLE() (void)0 diff --git a/irr/include/matrix4.h b/irr/include/matrix4.h index 40fb41e57..6fc8cf6f8 100644 --- a/irr/include/matrix4.h +++ b/irr/include/matrix4.h @@ -12,6 +12,7 @@ #include "aabbox3d.h" #include "rect.h" #include "IrrCompileConfig.h" // for IRRLICHT_API +#include namespace irr { @@ -1198,10 +1199,10 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveFovRH( f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero) { const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5)); - _IRR_DEBUG_BREAK_IF(aspectRatio == 0.f); // divide by zero + assert(aspectRatio != 0.f); // divide by zero const T w = static_cast(h / aspectRatio); - _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero + assert(zNear != zFar); // divide by zero M[0] = w; M[1] = 0; M[2] = 0; @@ -1240,10 +1241,10 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveFovLH( f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero) { const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5)); - _IRR_DEBUG_BREAK_IF(aspectRatio == 0.f); // divide by zero + assert(aspectRatio != 0.f); // divide by zero const T w = static_cast(h / aspectRatio); - _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero + assert(zNear != zFar); // divide by zero M[0] = w; M[1] = 0; M[2] = 0; @@ -1282,7 +1283,7 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveFovInfinityLH( f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon) { const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5)); - _IRR_DEBUG_BREAK_IF(aspectRatio == 0.f); // divide by zero + assert(aspectRatio != 0.f); // divide by zero const T w = static_cast(h / aspectRatio); M[0] = w; @@ -1313,9 +1314,9 @@ template inline CMatrix4 &CMatrix4::buildProjectionMatrixOrthoLH( f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero) { - _IRR_DEBUG_BREAK_IF(widthOfViewVolume == 0.f); // divide by zero - _IRR_DEBUG_BREAK_IF(heightOfViewVolume == 0.f); // divide by zero - _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero + assert(widthOfViewVolume != 0.f); // divide by zero + assert(heightOfViewVolume != 0.f); // divide by zero + assert(zNear != zFar); // divide by zero M[0] = (T)(2 / widthOfViewVolume); M[1] = 0; M[2] = 0; @@ -1352,9 +1353,9 @@ template inline CMatrix4 &CMatrix4::buildProjectionMatrixOrthoRH( f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero) { - _IRR_DEBUG_BREAK_IF(widthOfViewVolume == 0.f); // divide by zero - _IRR_DEBUG_BREAK_IF(heightOfViewVolume == 0.f); // divide by zero - _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero + assert(widthOfViewVolume != 0.f); // divide by zero + assert(heightOfViewVolume != 0.f); // divide by zero + assert(zNear != zFar); // divide by zero M[0] = (T)(2 / widthOfViewVolume); M[1] = 0; M[2] = 0; @@ -1391,9 +1392,9 @@ template inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveRH( f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero) { - _IRR_DEBUG_BREAK_IF(widthOfViewVolume == 0.f); // divide by zero - _IRR_DEBUG_BREAK_IF(heightOfViewVolume == 0.f); // divide by zero - _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero + assert(widthOfViewVolume != 0.f); // divide by zero + assert(heightOfViewVolume != 0.f); // divide by zero + assert(zNear != zFar); // divide by zero M[0] = (T)(2 * zNear / widthOfViewVolume); M[1] = 0; M[2] = 0; @@ -1431,9 +1432,9 @@ template inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveLH( f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero) { - _IRR_DEBUG_BREAK_IF(widthOfViewVolume == 0.f); // divide by zero - _IRR_DEBUG_BREAK_IF(heightOfViewVolume == 0.f); // divide by zero - _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero + assert(widthOfViewVolume != 0.f); // divide by zero + assert(heightOfViewVolume != 0.f); // divide by zero + assert(zNear != zFar); // divide by zero M[0] = (T)(2 * zNear / widthOfViewVolume); M[1] = 0; M[2] = 0; diff --git a/irr/include/vector2d.h b/irr/include/vector2d.h index 63be1f246..821885719 100644 --- a/irr/include/vector2d.h +++ b/irr/include/vector2d.h @@ -9,6 +9,7 @@ #include #include +#include namespace irr { diff --git a/irr/include/vector3d.h b/irr/include/vector3d.h index 780686c7a..c9c96fabf 100644 --- a/irr/include/vector3d.h +++ b/irr/include/vector3d.h @@ -8,6 +8,7 @@ #include #include +#include namespace irr { diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index b32ba5692..32fa4829c 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -797,7 +798,7 @@ std::optional> SelfType::MeshExtractor::getIndices( if (index == std::numeric_limits::max()) throw std::runtime_error("invalid index"); } else { - _IRR_DEBUG_BREAK_IF(!std::holds_alternative>(accessor)); + assert(std::holds_alternative>(accessor)); u32 indexWide = std::get>(accessor).get(elemIdx); // Use >= here for consistency. if (indexWide >= std::numeric_limits::max()) diff --git a/irr/src/CImage.cpp b/irr/src/CImage.cpp index 29c115c8a..4366809ae 100644 --- a/irr/src/CImage.cpp +++ b/irr/src/CImage.cpp @@ -9,6 +9,8 @@ #include "os.h" #include "SoftwareDriver2_helper.h" +#include + namespace irr { namespace video @@ -20,7 +22,7 @@ CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d &size, void *d IImage(format, size, deleteMemory) { if (ownForeignMemory) { - _IRR_DEBUG_BREAK_IF(!data) + assert(data); Data = reinterpret_cast(data); if (reinterpret_cast(data) % sizeof(u32) != 0) os::Printer::log("CImage created with foreign memory that's not aligned", ELL_WARNING); diff --git a/irr/src/CIrrDeviceLinux.cpp b/irr/src/CIrrDeviceLinux.cpp index 7c5d9cf0b..f72ccc7a1 100644 --- a/irr/src/CIrrDeviceLinux.cpp +++ b/irr/src/CIrrDeviceLinux.cpp @@ -1680,10 +1680,10 @@ const c8 *CIrrDeviceLinux::getTextFromSelection(Atom selection, core::stringc &t }, (XPointer)&args); - _IRR_DEBUG_BREAK_IF(!(event_ret.type == SelectionNotify && + assert(event_ret.type == SelectionNotify && event_ret.xselection.requestor == XWindow && event_ret.xselection.selection == selection && - event_ret.xselection.target == X_ATOM_UTF8_STRING)); + event_ret.xselection.target == X_ATOM_UTF8_STRING); Atom property_set = event_ret.xselection.property; if (event_ret.xselection.property == None) { diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index 28a92f450..bc7627f73 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -16,11 +16,13 @@ #include "irrString.h" #include "Keycodes.h" #include "COSOperator.h" -#include -#include #include "SIrrCreationParameters.h" #include +#include +#include +#include + #ifdef _IRR_EMSCRIPTEN_PLATFORM_ #include #endif @@ -599,7 +601,7 @@ bool CIrrDeviceSDL::createWindowWithContext() SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); break; default: - _IRR_DEBUG_BREAK_IF(1); + assert(false); } if (CreationParams.DriverDebug) { diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index 820af4fe9..8b6f71b3a 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -521,10 +521,10 @@ target_link_libraries(IrrlichtMt PRIVATE ) if(WIN32) - target_compile_definitions(IrrlichtMt INTERFACE _IRR_WINDOWS_API_) # used in _IRR_DEBUG_BREAK_IF definition in a public header + target_compile_definitions(IrrlichtMt INTERFACE _IRR_WINDOWS_API_) endif() if(CMAKE_BUILD_TYPE STREQUAL "Debug") - target_compile_definitions(IrrlichtMt INTERFACE _DEBUG) # same + target_compile_definitions(IrrlichtMt INTERFACE _DEBUG) endif() if(APPLE OR ANDROID OR EMSCRIPTEN) target_compile_definitions(IrrlichtMt PUBLIC IRR_MOBILE_PATHS) diff --git a/irr/src/CMeshManipulator.cpp b/irr/src/CMeshManipulator.cpp index 63157403b..659e8dff8 100644 --- a/irr/src/CMeshManipulator.cpp +++ b/irr/src/CMeshManipulator.cpp @@ -9,6 +9,8 @@ #include "SAnimatedMesh.h" #include "os.h" +#include + namespace irr { namespace scene @@ -118,14 +120,14 @@ void CMeshManipulator::recalculateNormals(scene::IMesh *mesh, bool smooth, bool template void copyVertices(const scene::IVertexBuffer *src, scene::CVertexBuffer *dst) { - _IRR_DEBUG_BREAK_IF(T::getType() != src->getType()); + assert(T::getType() == src->getType()); auto *data = static_cast(src->getData()); dst->Data.assign(data, data + src->getCount()); } static void copyIndices(const scene::IIndexBuffer *src, scene::SIndexBuffer *dst) { - _IRR_DEBUG_BREAK_IF(src->getType() != video::EIT_16BIT); + assert(src->getType() == video::EIT_16BIT); auto *data = static_cast(src->getData()); dst->Data.assign(data, data + src->getCount()); } diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index 21346e6ed..f54f7a418 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -17,6 +17,8 @@ #include "IReferenceCounted.h" #include "IRenderTarget.h" +#include + namespace irr { namespace video @@ -1092,7 +1094,7 @@ void CNullDriver::drawBuffers(const scene::IVertexBuffer *vb, if (vb->getHWBuffer() || ib->getHWBuffer()) { // subclass is supposed to override this if it supports hw buffers - _IRR_DEBUG_BREAK_IF(1); + assert(false); } drawVertexPrimitiveList(vb->getData(), vb->getCount(), ib->getData(), @@ -1138,7 +1140,7 @@ CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IIndexBuffer void CNullDriver::registerHardwareBuffer(SHWBufferLink *HWBuffer) { - _IRR_DEBUG_BREAK_IF(!HWBuffer) + assert(HWBuffer); HWBuffer->ListPosition = HWBufferList.size(); HWBufferList.push_back(HWBuffer); } @@ -1168,7 +1170,7 @@ void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer) if (!HWBuffer) return; const size_t pos = HWBuffer->ListPosition; - _IRR_DEBUG_BREAK_IF(HWBufferList.at(pos) != HWBuffer) + assert(HWBufferList.at(pos) == HWBuffer); if (HWBufferList.size() < 2 || pos == HWBufferList.size() - 1) { HWBufferList.erase(HWBufferList.begin() + pos); } else { diff --git a/irr/src/COpenGLCoreCacheHandler.h b/irr/src/COpenGLCoreCacheHandler.h index bf588aa8a..8302f182a 100644 --- a/irr/src/COpenGLCoreCacheHandler.h +++ b/irr/src/COpenGLCoreCacheHandler.h @@ -9,6 +9,8 @@ #include "mt_opengl.h" +#include + namespace irr { namespace video @@ -101,7 +103,7 @@ class COpenGLCoreCacheHandler #endif auto name = static_cast(texture)->getOpenGLTextureName(); - _IRR_DEBUG_BREAK_IF(name == 0) + assert(name != 0); GL.BindTexture(curTextureType, name); } else { texture = 0; diff --git a/irr/src/COpenGLCoreTexture.h b/irr/src/COpenGLCoreTexture.h index bc9a7e919..b2b7403c2 100644 --- a/irr/src/COpenGLCoreTexture.h +++ b/irr/src/COpenGLCoreTexture.h @@ -5,6 +5,8 @@ #pragma once #include +#include + #include "SMaterialLayer.h" #include "ITexture.h" #include "EDriverFeatures.h" @@ -48,10 +50,10 @@ public: TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), MSAA(0), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0), KeepImage(false), MipLevelStored(0) { - _IRR_DEBUG_BREAK_IF(srcImages.empty()) + assert(!srcImages.empty()); DriverType = Driver->getDriverType(); - _IRR_DEBUG_BREAK_IF(Type == ETT_2D_MS) // not supported by this constructor + assert(Type != ETT_2D_MS); // not supported by this constructor TextureType = TextureTypeIrrToGL(Type); HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); KeepImage = Driver->getTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY); @@ -142,7 +144,7 @@ public: MipLevelStored(0) { DriverType = Driver->getDriverType(); - _IRR_DEBUG_BREAK_IF(Type == ETT_2D_ARRAY) // not supported by this constructor + assert(Type != ETT_2D_ARRAY); // not supported by this constructor TextureType = TextureTypeIrrToGL(Type); HasMipMaps = false; IsRenderTarget = true; @@ -242,7 +244,7 @@ public: MipLevelStored = mipmapLevel; if (KeepImage) { - _IRR_DEBUG_BREAK_IF(LockLayer > Images.size()) + assert(LockLayer < Images.size()); if (mipmapLevel == 0) { LockImage = Images[LockLayer]; @@ -252,7 +254,7 @@ public: if (!LockImage) { core::dimension2d lockImageSize(IImage::getMipMapsSize(Size, MipLevelStored)); - _IRR_DEBUG_BREAK_IF(lockImageSize.Width == 0 || lockImageSize.Height == 0) + assert(lockImageSize.Width > 0 && lockImageSize.Height > 0); LockImage = Driver->createImage(ColorFormat, lockImageSize); @@ -512,7 +514,7 @@ protected: { // Compressed textures cannot be pre-allocated and are initialized on upload if (IImage::isCompressedFormat(ColorFormat)) { - _IRR_DEBUG_BREAK_IF(IsRenderTarget) + assert(!IsRenderTarget); return; } @@ -587,7 +589,7 @@ protected: TEST_GL_ERROR(Driver); break; default: - _IRR_DEBUG_BREAK_IF(1) + assert(false); break; } } @@ -628,7 +630,7 @@ protected: GL.TexSubImage3D(tmpTextureType, level, 0, 0, layer, width, height, 1, PixelFormat, PixelType, tmpData); break; default: - _IRR_DEBUG_BREAK_IF(1) + assert(false); break; } TEST_GL_ERROR(Driver); @@ -643,7 +645,7 @@ protected: Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data); break; default: - _IRR_DEBUG_BREAK_IF(1) + assert(false); break; } TEST_GL_ERROR(Driver); @@ -671,7 +673,7 @@ protected: { GLenum tmp = TextureType; if (tmp == GL_TEXTURE_CUBE_MAP) { - _IRR_DEBUG_BREAK_IF(layer > 5) + assert(layer < 6); tmp = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; } return tmp; diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index 50e097362..9c37e2f79 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -710,7 +710,7 @@ void COpenGLDriver::drawVertexPrimitiveList(const void *vertices, u32 vertexCoun } } else { // avoid passing broken pointer to OpenGL - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + assert(!ColorBuffer.empty()); glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); } } @@ -983,7 +983,7 @@ void COpenGLDriver::draw2DVertexPrimitiveList(const void *vertices, u32 vertexCo } } else { // avoid passing broken pointer to OpenGL - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + assert(!ColorBuffer.empty()); glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); } } @@ -1124,7 +1124,7 @@ void COpenGLDriver::draw2DImage(const video::ITexture *texture, const core::posi if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); else { - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + assert(!ColorBuffer.empty()); glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); } @@ -1204,7 +1204,7 @@ void COpenGLDriver::draw2DImage(const video::ITexture *texture, const core::rect if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); else { - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + assert(!ColorBuffer.empty()); glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); } @@ -1352,7 +1352,7 @@ void COpenGLDriver::draw2DImageBatch(const video::ITexture *texture, if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); else { - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + assert(!ColorBuffer.empty()); glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); } @@ -1519,7 +1519,7 @@ void COpenGLDriver::draw2DRectangle(const core::rect &position, if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); else { - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + assert(!ColorBuffer.empty()); glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); } @@ -1555,7 +1555,7 @@ void COpenGLDriver::draw2DLine(const core::position2d &start, if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); else { - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + assert(!ColorBuffer.empty()); glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); } @@ -2478,7 +2478,7 @@ void COpenGLDriver::draw3DLine(const core::vector3df &start, if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); else { - _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + assert(!ColorBuffer.empty()); glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); } diff --git a/irr/src/CSceneManager.cpp b/irr/src/CSceneManager.cpp index 23e5335ce..41c59fe66 100644 --- a/irr/src/CSceneManager.cpp +++ b/irr/src/CSceneManager.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in irrlicht.h #include +#include #include "CSceneManager.h" #include "IVideoDriver.h" @@ -305,7 +306,7 @@ void CSceneManager::render() //! returns the axis aligned bounding box of this node const core::aabbox3d &CSceneManager::getBoundingBox() const { - _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used. + assert(false); // Bounding Box of Scene Manager should never be used. static const core::aabbox3d dummy{{0.0f, 0.0f, 0.0f}}; return dummy; diff --git a/irr/src/SkinnedMesh.cpp b/irr/src/SkinnedMesh.cpp index ebf84cec5..938a50e17 100644 --- a/irr/src/SkinnedMesh.cpp +++ b/irr/src/SkinnedMesh.cpp @@ -9,6 +9,7 @@ #include "SSkinMeshBuffer.h" #include "os.h" #include +#include namespace irr { @@ -620,19 +621,19 @@ SkinnedMesh::SJoint *SkinnedMeshBuilder::addJoint(SJoint *parent) void SkinnedMeshBuilder::addPositionKey(SJoint *joint, f32 frame, core::vector3df pos) { - _IRR_DEBUG_BREAK_IF(!joint); + assert(joint); joint->keys.position.pushBack(frame, pos); } void SkinnedMeshBuilder::addScaleKey(SJoint *joint, f32 frame, core::vector3df scale) { - _IRR_DEBUG_BREAK_IF(!joint); + assert(joint); joint->keys.scale.pushBack(frame, scale); } void SkinnedMeshBuilder::addRotationKey(SJoint *joint, f32 frame, core::quaternion rot) { - _IRR_DEBUG_BREAK_IF(!joint); + assert(joint); joint->keys.rotation.pushBack(frame, rot); } From 695d526764206b4a37ddb84ce0937314eb781422 Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Fri, 4 Apr 2025 16:32:52 +0200 Subject: [PATCH 017/131] Get rid of `_IRR_OVERRIDE_` macro --- irr/include/irrTypes.h | 4 ---- irr/src/CIrrDeviceSDL.h | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/irr/include/irrTypes.h b/irr/include/irrTypes.h index 9e71d0771..9018dd151 100644 --- a/irr/include/irrTypes.h +++ b/irr/include/irrTypes.h @@ -66,10 +66,6 @@ typedef char fschar_t; } // end namespace irr -//! deprecated macro for virtual function override -/** prefer to use the override keyword for new code */ -#define _IRR_OVERRIDE_ override - // Invokes undefined behavior for unreachable code optimization // Note: an assert(false) is included first to catch this in debug builds #if defined(__cpp_lib_unreachable) diff --git a/irr/src/CIrrDeviceSDL.h b/irr/src/CIrrDeviceSDL.h index 33d97ce56..1faaad7a7 100644 --- a/irr/src/CIrrDeviceSDL.h +++ b/irr/src/CIrrDeviceSDL.h @@ -206,7 +206,7 @@ public: { } - virtual void setRelativeMode(bool relative) _IRR_OVERRIDE_ + virtual void setRelativeMode(bool relative) override { // Only change it when necessary, as it flushes mouse motion when enabled if (relative != static_cast(SDL_GetRelativeMouseMode())) { From e1143783e5b1a4021aa16293e232cd3ef9d72492 Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Fri, 4 Apr 2025 17:09:12 +0200 Subject: [PATCH 018/131] Fix some (MSVC) compiler warnings --- irr/include/irrMath.h | 2 +- irr/src/CGLTFMeshFileLoader.cpp | 10 ++++------ irr/src/OpenGL/ExtensionHandler.h | 2 +- src/client/minimap.cpp | 4 ++-- src/client/shadows/dynamicshadowsrender.cpp | 4 ++-- src/client/shadows/dynamicshadowsrender.h | 2 +- src/script/common/c_content.cpp | 2 +- src/unittest/test_utilities.cpp | 2 +- 8 files changed, 13 insertions(+), 15 deletions(-) diff --git a/irr/include/irrMath.h b/irr/include/irrMath.h index e11d47360..4e74381a6 100644 --- a/irr/include/irrMath.h +++ b/irr/include/irrMath.h @@ -25,7 +25,7 @@ constexpr f64 ROUNDING_ERROR_f64 = 0.00000001; #undef PI #endif //! Constant for PI. -constexpr f32 PI = M_PI; +constexpr f32 PI = static_cast(M_PI); #ifdef PI64 // make sure we don't collide with a define #undef PI64 diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index 32fa4829c..87712595a 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -549,12 +549,10 @@ void SelfType::MeshExtractor::deferAddMesh( static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, SkinnedMesh::SJoint *joint) { - // Note: Under the hood, this casts these doubles to floats. - core::matrix4 mat = convertHandedness(core::matrix4( - m[0], m[1], m[2], m[3], - m[4], m[5], m[6], m[7], - m[8], m[9], m[10], m[11], - m[12], m[13], m[14], m[15])); + core::matrix4 mat; + for (size_t i = 0; i < m.size(); ++i) + mat[i] = static_cast(m[i]); + mat = convertHandedness(mat); // Decompose the matrix into translation, scale, and rotation. joint->Animatedposition = mat.getTranslation(); diff --git a/irr/src/OpenGL/ExtensionHandler.h b/irr/src/OpenGL/ExtensionHandler.h index 413ab7f23..2ee3543d5 100644 --- a/irr/src/OpenGL/ExtensionHandler.h +++ b/irr/src/OpenGL/ExtensionHandler.h @@ -166,7 +166,7 @@ public: inline void irrGlObjectLabel(GLenum identifier, GLuint name, const char *label) { if (KHRDebugSupported) { - u32 len = strlen(label); + u32 len = static_cast(strlen(label)); // Since our texture strings can get quite long we also truncate // to a hardcoded limit of 82 len = std::min(len, std::min(MaxLabelLength, 82U)); diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index e60608688..0d44f9d00 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -704,8 +704,8 @@ void Minimap::updateActiveMarkers() continue; } - m_active_markers.emplace_back(((float)pos.X / (float)MINIMAP_MAX_SX) - 0.5, - (1.0 - (float)pos.Z / (float)MINIMAP_MAX_SY) - 0.5); + m_active_markers.emplace_back(((float)pos.X / (float)MINIMAP_MAX_SX) - 0.5f, + (1.0f - (float)pos.Z / (float)MINIMAP_MAX_SY) - 0.5f); } } diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index a7d21d647..70bc2d2cf 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -36,7 +36,7 @@ ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) : m_shadow_map_max_distance = g_settings->getFloat("shadow_map_max_distance"); - m_shadow_map_texture_size = g_settings->getFloat("shadow_map_texture_size"); + m_shadow_map_texture_size = g_settings->getU32("shadow_map_texture_size"); m_shadow_map_texture_32bit = g_settings->getBool("shadow_map_texture_32bit"); m_shadow_map_colored = g_settings->getBool("shadow_map_color"); @@ -273,7 +273,7 @@ void ShadowRenderer::updateSMTextures() // Static shader values. for (auto cb : {m_shadow_depth_cb, m_shadow_depth_entity_cb, m_shadow_depth_trans_cb}) { if (cb) { - cb->MapRes = (f32)m_shadow_map_texture_size; + cb->MapRes = (u32)m_shadow_map_texture_size; cb->MaxFar = (f32)m_shadow_map_max_distance * BS; cb->PerspectiveBiasXY = getPerspectiveBiasXY(); cb->PerspectiveBiasZ = getPerspectiveBiasZ(); diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index 1c7b6e482..7026e39a9 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -124,7 +124,7 @@ private: video::SColor m_shadow_tint; float m_shadow_strength_gamma; float m_shadow_map_max_distance; - float m_shadow_map_texture_size; + u32 m_shadow_map_texture_size; float m_time_day; int m_shadow_samples; bool m_shadow_map_texture_32bit; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 0e802d9c7..e4d94b3fc 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -104,7 +104,7 @@ void read_item_definition(lua_State* L, int index, } else if (lua_isstring(L, -1)) { video::SColor color; read_color(L, -1, &color); - def.wear_bar_params = WearBarParams({{0.0, color}}, + def.wear_bar_params = WearBarParams({{0.0f, color}}, WearBarParams::BLEND_MODE_CONSTANT); } diff --git a/src/unittest/test_utilities.cpp b/src/unittest/test_utilities.cpp index 1a810c06d..7a07c37fe 100644 --- a/src/unittest/test_utilities.cpp +++ b/src/unittest/test_utilities.cpp @@ -320,7 +320,7 @@ void TestUtilities::testUTF8() // try to check that the conversion function does not accidentally keep // its internal state across invocations. // \xC4\x81 is UTF-8 for \u0101 - utf8_to_wide("\xC4"); + static_cast(utf8_to_wide("\xC4")); UASSERT(utf8_to_wide("\x81") != L"\u0101"); } From c0d10b24a46b5473bad791f2689e4c97b75157e9 Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Sat, 5 Apr 2025 01:19:52 +0200 Subject: [PATCH 019/131] Use SPDX-License-Identifiers in builtin --- builtin/common/filterlist.lua | 19 +++-------------- builtin/common/settings/components.lua | 19 +++-------------- .../settings/dlg_change_mapgen_flags.lua | 19 +++-------------- builtin/common/settings/dlg_settings.lua | 19 +++-------------- builtin/common/settings/init.lua | 19 +++-------------- builtin/common/settings/settingtypes.lua | 19 +++-------------- builtin/common/settings/shadows_component.lua | 21 ++++--------------- builtin/fstk/buttonbar.lua | 21 ++++--------------- builtin/fstk/dialog.lua | 19 +++-------------- builtin/fstk/tabview.lua | 19 +++-------------- builtin/fstk/ui.lua | 19 +++-------------- builtin/mainmenu/common.lua | 19 +++-------------- builtin/mainmenu/content/contentdb.lua | 19 +++-------------- builtin/mainmenu/content/dlg_contentdb.lua | 19 +++-------------- builtin/mainmenu/content/dlg_install.lua | 19 +++-------------- builtin/mainmenu/content/dlg_overwrite.lua | 19 +++-------------- builtin/mainmenu/content/dlg_package.lua | 19 +++-------------- builtin/mainmenu/content/init.lua | 19 +++-------------- builtin/mainmenu/content/pkgmgr.lua | 19 +++-------------- builtin/mainmenu/content/screenshots.lua | 19 +++-------------- .../mainmenu/content/tests/pkgmgr_spec.lua | 19 +++-------------- builtin/mainmenu/content/update_detector.lua | 19 +++-------------- builtin/mainmenu/dlg_config_world.lua | 19 +++-------------- builtin/mainmenu/dlg_create_world.lua | 19 +++-------------- builtin/mainmenu/dlg_delete_content.lua | 19 +++-------------- builtin/mainmenu/dlg_delete_world.lua | 19 +++-------------- builtin/mainmenu/dlg_register.lua | 19 +++-------------- builtin/mainmenu/dlg_reinstall_mtg.lua | 19 +++-------------- builtin/mainmenu/dlg_rename_modpack.lua | 19 +++-------------- builtin/mainmenu/game_theme.lua | 19 +++-------------- builtin/mainmenu/init.lua | 19 +++-------------- builtin/mainmenu/serverlistmgr.lua | 19 +++-------------- builtin/mainmenu/tab_about.lua | 19 +++-------------- builtin/mainmenu/tab_content.lua | 21 ++++--------------- builtin/mainmenu/tab_local.lua | 19 +++-------------- builtin/mainmenu/tab_online.lua | 19 +++-------------- builtin/profiler/init.lua | 19 +++-------------- builtin/profiler/instrumentation.lua | 19 +++-------------- builtin/profiler/reporter.lua | 19 +++-------------- builtin/profiler/sampling.lua | 19 +++-------------- 40 files changed, 123 insertions(+), 643 deletions(-) diff --git a/builtin/common/filterlist.lua b/builtin/common/filterlist.lua index c323a0d55..058a573c6 100644 --- a/builtin/common/filterlist.lua +++ b/builtin/common/filterlist.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2013 sapier --- ---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. +-- Luanti +-- Copyright (C) 2013 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later -------------------------------------------------------------------------------- -- TODO improve doc -- diff --git a/builtin/common/settings/components.lua b/builtin/common/settings/components.lua index b3035fd51..99fb0cd76 100644 --- a/builtin/common/settings/components.lua +++ b/builtin/common/settings/components.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2022 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2022 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local make = {} diff --git a/builtin/common/settings/dlg_change_mapgen_flags.lua b/builtin/common/settings/dlg_change_mapgen_flags.lua index 31dd40bd8..de96c75e3 100644 --- a/builtin/common/settings/dlg_change_mapgen_flags.lua +++ b/builtin/common/settings/dlg_change_mapgen_flags.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2015 PilzAdam --- ---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. +-- Luanti +-- Copyright (C) 2015 PilzAdam +-- SPDX-License-Identifier: LGPL-2.1-or-later local checkboxes = {} diff --git a/builtin/common/settings/dlg_settings.lua b/builtin/common/settings/dlg_settings.lua index 8d4a8b6de..7f519f9c3 100644 --- a/builtin/common/settings/dlg_settings.lua +++ b/builtin/common/settings/dlg_settings.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2022 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2022 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local path = core.get_builtin_path() .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM diff --git a/builtin/common/settings/init.lua b/builtin/common/settings/init.lua index d475e0c96..71a95424b 100644 --- a/builtin/common/settings/init.lua +++ b/builtin/common/settings/init.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2022 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2022 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local path = core.get_builtin_path() .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM diff --git a/builtin/common/settings/settingtypes.lua b/builtin/common/settings/settingtypes.lua index 90ff8975c..db3b5a609 100644 --- a/builtin/common/settings/settingtypes.lua +++ b/builtin/common/settings/settingtypes.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2015 PilzAdam --- ---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. +-- Luanti +-- Copyright (C) 2015 PilzAdam +-- SPDX-License-Identifier: LGPL-2.1-or-later settingtypes = {} diff --git a/builtin/common/settings/shadows_component.lua b/builtin/common/settings/shadows_component.lua index 405517058..59b152ab8 100644 --- a/builtin/common/settings/shadows_component.lua +++ b/builtin/common/settings/shadows_component.lua @@ -1,20 +1,7 @@ ---Luanti ---Copyright (C) 2021-2 x2048 ---Copyright (C) 2022-3 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2021-2 x2048 +-- Copyright (C) 2022-3 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local shadow_levels_labels = { diff --git a/builtin/fstk/buttonbar.lua b/builtin/fstk/buttonbar.lua index 577eb7c6d..461babc1f 100644 --- a/builtin/fstk/buttonbar.lua +++ b/builtin/fstk/buttonbar.lua @@ -1,20 +1,7 @@ ---Luanti ---Copyright (C) 2014 sapier ---Copyright (C) 2023 Gregor Parzefall --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- Copyright (C) 2023 Gregor Parzefall +-- SPDX-License-Identifier: LGPL-2.1-or-later local BASE_SPACING = 0.1 diff --git a/builtin/fstk/dialog.lua b/builtin/fstk/dialog.lua index 7043646a4..f0b7cf14b 100644 --- a/builtin/fstk/dialog.lua +++ b/builtin/fstk/dialog.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later local function dialog_event_handler(self,event) if self.user_eventhandler == nil or diff --git a/builtin/fstk/tabview.lua b/builtin/fstk/tabview.lua index c88c4917a..13a96abff 100644 --- a/builtin/fstk/tabview.lua +++ b/builtin/fstk/tabview.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later -------------------------------------------------------------------------------- diff --git a/builtin/fstk/ui.lua b/builtin/fstk/ui.lua index b5b95d0e4..47b9d086c 100644 --- a/builtin/fstk/ui.lua +++ b/builtin/fstk/ui.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later ui = {} ui.childlist = {} diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua index d9edd745b..e7b4d90d1 100644 --- a/builtin/mainmenu/common.lua +++ b/builtin/mainmenu/common.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later -- Global menu data menudata = {} diff --git a/builtin/mainmenu/content/contentdb.lua b/builtin/mainmenu/content/contentdb.lua index 856924bd4..be148841a 100644 --- a/builtin/mainmenu/content/contentdb.lua +++ b/builtin/mainmenu/content/contentdb.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2018-24 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2018-24 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later if not core.get_http_api then return diff --git a/builtin/mainmenu/content/dlg_contentdb.lua b/builtin/mainmenu/content/dlg_contentdb.lua index 3c3f7987d..872fab113 100644 --- a/builtin/mainmenu/content/dlg_contentdb.lua +++ b/builtin/mainmenu/content/dlg_contentdb.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2018-20 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2018-20 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later if not core.get_http_api then function create_contentdb_dlg() diff --git a/builtin/mainmenu/content/dlg_install.lua b/builtin/mainmenu/content/dlg_install.lua index ef201f56a..3d9e45760 100644 --- a/builtin/mainmenu/content/dlg_install.lua +++ b/builtin/mainmenu/content/dlg_install.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2018-24 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2018-24 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local function is_still_visible(dlg) local this = ui.find_by_name("install_dialog") diff --git a/builtin/mainmenu/content/dlg_overwrite.lua b/builtin/mainmenu/content/dlg_overwrite.lua index 5baaa5cd2..08d49bce3 100644 --- a/builtin/mainmenu/content/dlg_overwrite.lua +++ b/builtin/mainmenu/content/dlg_overwrite.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2018-24 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2018-24 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later function get_formspec(data) local package = data.package diff --git a/builtin/mainmenu/content/dlg_package.lua b/builtin/mainmenu/content/dlg_package.lua index d8fc057c1..500fb3f6c 100644 --- a/builtin/mainmenu/content/dlg_package.lua +++ b/builtin/mainmenu/content/dlg_package.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2018-24 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2018-24 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local function get_info_formspec(size, padding, text) diff --git a/builtin/mainmenu/content/init.lua b/builtin/mainmenu/content/init.lua index dbf4cc888..e35ca1734 100644 --- a/builtin/mainmenu/content/init.lua +++ b/builtin/mainmenu/content/init.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2023 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2023 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local path = core.get_mainmenu_path() .. DIR_DELIM .. "content" diff --git a/builtin/mainmenu/content/pkgmgr.lua b/builtin/mainmenu/content/pkgmgr.lua index 986d80398..2863e2a5f 100644 --- a/builtin/mainmenu/content/pkgmgr.lua +++ b/builtin/mainmenu/content/pkgmgr.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2013 sapier --- ---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. +-- Luanti +-- Copyright (C) 2013 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later -------------------------------------------------------------------------------- local function get_last_folder(text,count) diff --git a/builtin/mainmenu/content/screenshots.lua b/builtin/mainmenu/content/screenshots.lua index 718666085..e53f03ed0 100644 --- a/builtin/mainmenu/content/screenshots.lua +++ b/builtin/mainmenu/content/screenshots.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2023-24 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2023-24 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later -- Screenshot diff --git a/builtin/mainmenu/content/tests/pkgmgr_spec.lua b/builtin/mainmenu/content/tests/pkgmgr_spec.lua index 8870bb68f..5532764d9 100644 --- a/builtin/mainmenu/content/tests/pkgmgr_spec.lua +++ b/builtin/mainmenu/content/tests/pkgmgr_spec.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2022 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2022 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local mods_dir = "/tmp/.minetest/mods" local games_dir = "/tmp/.minetest/games" diff --git a/builtin/mainmenu/content/update_detector.lua b/builtin/mainmenu/content/update_detector.lua index 4d0c1196b..1479328f7 100644 --- a/builtin/mainmenu/content/update_detector.lua +++ b/builtin/mainmenu/content/update_detector.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2023 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2023 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later update_detector = {} diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua index 416a4a6f3..36cc5580c 100644 --- a/builtin/mainmenu/dlg_config_world.lua +++ b/builtin/mainmenu/dlg_config_world.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2013 sapier --- ---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. +-- Luanti +-- Copyright (C) 2013 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later -------------------------------------------------------------------------------- diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua index 4844c85fe..27fe68050 100644 --- a/builtin/mainmenu/dlg_create_world.lua +++ b/builtin/mainmenu/dlg_create_world.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later local function table_to_flags(ftable) -- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves" diff --git a/builtin/mainmenu/dlg_delete_content.lua b/builtin/mainmenu/dlg_delete_content.lua index a36bcb2d7..799050d0b 100644 --- a/builtin/mainmenu/dlg_delete_content.lua +++ b/builtin/mainmenu/dlg_delete_content.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later -------------------------------------------------------------------------------- diff --git a/builtin/mainmenu/dlg_delete_world.lua b/builtin/mainmenu/dlg_delete_world.lua index 531b4927d..25e9dd0fc 100644 --- a/builtin/mainmenu/dlg_delete_world.lua +++ b/builtin/mainmenu/dlg_delete_world.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later local function delete_world_formspec(dialogdata) diff --git a/builtin/mainmenu/dlg_register.lua b/builtin/mainmenu/dlg_register.lua index 88a449ae3..5047eda3c 100644 --- a/builtin/mainmenu/dlg_register.lua +++ b/builtin/mainmenu/dlg_register.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2022 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2022 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later -------------------------------------------------------------------------------- diff --git a/builtin/mainmenu/dlg_reinstall_mtg.lua b/builtin/mainmenu/dlg_reinstall_mtg.lua index 11b20f637..4defa6646 100644 --- a/builtin/mainmenu/dlg_reinstall_mtg.lua +++ b/builtin/mainmenu/dlg_reinstall_mtg.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2023 Gregor Parzefall --- ---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. +-- Luanti +-- Copyright (C) 2023 Gregor Parzefall +-- SPDX-License-Identifier: LGPL-2.1-or-later ---- IMPORTANT ---- -- This whole file can be removed after a while. diff --git a/builtin/mainmenu/dlg_rename_modpack.lua b/builtin/mainmenu/dlg_rename_modpack.lua index 09df92d25..830c3cef3 100644 --- a/builtin/mainmenu/dlg_rename_modpack.lua +++ b/builtin/mainmenu/dlg_rename_modpack.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later -------------------------------------------------------------------------------- diff --git a/builtin/mainmenu/game_theme.lua b/builtin/mainmenu/game_theme.lua index 7c6408157..729110025 100644 --- a/builtin/mainmenu/game_theme.lua +++ b/builtin/mainmenu/game_theme.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2013 sapier --- ---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. +-- Luanti +-- Copyright (C) 2013 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later mm_game_theme = {} diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index acf1f738d..1394d13f1 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later MAIN_TAB_W = 15.5 MAIN_TAB_H = 7.1 diff --git a/builtin/mainmenu/serverlistmgr.lua b/builtin/mainmenu/serverlistmgr.lua index 1b69d7a55..34eca287a 100644 --- a/builtin/mainmenu/serverlistmgr.lua +++ b/builtin/mainmenu/serverlistmgr.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2020 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2020 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later serverlistmgr = { -- continent code we detected for ourselves diff --git a/builtin/mainmenu/tab_about.lua b/builtin/mainmenu/tab_about.lua index 86c811457..5d2e606df 100644 --- a/builtin/mainmenu/tab_about.lua +++ b/builtin/mainmenu/tab_about.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2013 sapier --- ---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. +-- Luanti +-- Copyright (C) 2013 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later local function prepare_credits(dest, source) diff --git a/builtin/mainmenu/tab_content.lua b/builtin/mainmenu/tab_content.lua index cd384c905..8a6fc5b01 100644 --- a/builtin/mainmenu/tab_content.lua +++ b/builtin/mainmenu/tab_content.lua @@ -1,20 +1,7 @@ ---Luanti ---Copyright (C) 2014 sapier ---Copyright (C) 2018 rubenwardy --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- Copyright (C) 2018 rubenwardy +-- SPDX-License-Identifier: LGPL-2.1-or-later local function get_content_icons(packages_with_updates) diff --git a/builtin/mainmenu/tab_local.lua b/builtin/mainmenu/tab_local.lua index 083f9a50a..0d0b20ff1 100644 --- a/builtin/mainmenu/tab_local.lua +++ b/builtin/mainmenu/tab_local.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later local current_game, singleplayer_refresh_gamebar diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index f3f19c50f..ab5ddfe11 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2014 sapier --- ---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. +-- Luanti +-- Copyright (C) 2014 sapier +-- SPDX-License-Identifier: LGPL-2.1-or-later local function get_sorted_servers() local servers = { diff --git a/builtin/profiler/init.lua b/builtin/profiler/init.lua index f5b4b7c7e..ede9e0e7e 100644 --- a/builtin/profiler/init.lua +++ b/builtin/profiler/init.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2016 T4im --- ---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. +-- Luanti +-- Copyright (C) 2016 T4im +-- SPDX-License-Identifier: LGPL-2.1-or-later local S = core.get_translator("__builtin") diff --git a/builtin/profiler/instrumentation.lua b/builtin/profiler/instrumentation.lua index e012f07a0..613d3d692 100644 --- a/builtin/profiler/instrumentation.lua +++ b/builtin/profiler/instrumentation.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2016 T4im --- ---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. +-- Luanti +-- Copyright (C) 2016 T4im +-- SPDX-License-Identifier: LGPL-2.1-or-later local format, pairs, type = string.format, pairs, type local core, get_current_modname = core, core.get_current_modname diff --git a/builtin/profiler/reporter.lua b/builtin/profiler/reporter.lua index 7bc1b235d..b2bad7560 100644 --- a/builtin/profiler/reporter.lua +++ b/builtin/profiler/reporter.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2016 T4im --- ---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. +-- Luanti +-- Copyright (C) 2016 T4im +-- SPDX-License-Identifier: LGPL-2.1-or-later local S = core.get_translator("__builtin") -- Note: In this file, only messages are translated diff --git a/builtin/profiler/sampling.lua b/builtin/profiler/sampling.lua index 16d6c2012..5f1f5414c 100644 --- a/builtin/profiler/sampling.lua +++ b/builtin/profiler/sampling.lua @@ -1,19 +1,6 @@ ---Luanti ---Copyright (C) 2016 T4im --- ---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. +-- Luanti +-- Copyright (C) 2016 T4im +-- SPDX-License-Identifier: LGPL-2.1-or-later local setmetatable = setmetatable local pairs, format = pairs, string.format local min, max, huge = math.min, math.max, math.huge From 1c5776d13a9d22241a08dd2611e6ec799e3a28ea Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Sat, 12 Apr 2025 02:29:53 +0200 Subject: [PATCH 020/131] `FATAL_ERROR` for orphan object refs in `objectrefGetOrCreate` --- src/script/cpp_api/s_base.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index 9022cd8c3..ba931b22a 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -5,6 +5,7 @@ #include "cpp_api/s_base.h" #include "cpp_api/s_internal.h" #include "cpp_api/s_security.h" +#include "debug.h" #include "lua_api/l_object.h" #include "common/c_converter.h" #include "server/player_sao.h" @@ -467,12 +468,8 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj) if (!cobj) { ObjectRef::create(L, nullptr); // dummy reference } else if (cobj->getId() == 0) { - // TODO after 5.10.0: convert this to a FATAL_ERROR - errorstream << "ScriptApiBase::objectrefGetOrCreate(): " - << "Pushing orphan ObjectRef. Please open a bug report for this." - << std::endl; - assert(0); - ObjectRef::create(L, cobj); + FATAL_ERROR("ScriptApiBase::objectrefGetOrCreate(): " + "Pushing orphan ObjectRef. Please open a bug report for this."); } else { push_objectRef(L, cobj->getId()); if (cobj->isGone()) From 4c4e2962748b9f2b30c0b74b4527034b82891875 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 21 Apr 2025 12:31:44 +0200 Subject: [PATCH 021/131] Handle texture filtering sanely to avoid blurriness (#16034) --- builtin/settingtypes.txt | 4 +- doc/lua_api.md | 9 +++++ src/client/content_cao.cpp | 77 +++++++++++++++----------------------- src/client/imagesource.cpp | 25 ++++++++----- src/client/wieldmesh.cpp | 9 ++--- src/constants.h | 6 +++ src/defaultsettings.cpp | 2 +- src/nodedef.cpp | 3 +- 8 files changed, 70 insertions(+), 65 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 83d0b48e0..9462f616d 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -2106,7 +2106,7 @@ world_aligned_mode (World-aligned textures mode) enum enable disable,enable,forc # World-aligned textures may be scaled to span several nodes. However, # the server may not send the scale you want, especially if you use # a specially-designed texture pack; with this option, the client tries -# to determine the scale automatically basing on the texture size. +# to determine the scale automatically based on the texture size. # See also texture_min_size. # Warning: This option is EXPERIMENTAL! autoscale_mode (Autoscaling mode) enum disable disable,enable,force @@ -2118,7 +2118,7 @@ autoscale_mode (Autoscaling mode) enum disable disable,enable,force # This setting is ONLY applied if any of the mentioned filters are enabled. # This is also used as the base node texture size for world-aligned # texture autoscaling. -texture_min_size (Base texture size) int 64 1 32768 +texture_min_size (Base texture size) int 192 192 16384 # Side length of a cube of map blocks that the client will consider together # when generating meshes. diff --git a/doc/lua_api.md b/doc/lua_api.md index e2a55b7e1..31eb35dd2 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -518,6 +518,15 @@ stripping out the file extension: Supported texture formats are PNG (`.png`), JPEG (`.jpg`) and Targa (`.tga`). +Luanti generally uses nearest-neighbor upscaling for textures to preserve the crisp +look of pixel art (low-res textures). +Users can optionally enable bilinear and/or trilinear filtering. However, to avoid +everything becoming blurry, textures smaller than 192px will either not be filtered, +or will be upscaled to that minimum resolution first without filtering. + +This is subject to change to move more control to the Lua API, but you can rely on +low-res textures not suddenly becoming filtered. + Texture modifiers ----------------- diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 624ed4b5b..02e980cab 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -144,6 +144,31 @@ void SmoothTranslatorWrappedv3f::translate(f32 dtime) Other stuff */ +static bool setMaterialTextureAndFilters(video::SMaterial &material, + const std::string &texturestring, ITextureSource *tsrc) +{ + bool use_trilinear_filter = g_settings->getBool("trilinear_filter"); + bool use_bilinear_filter = g_settings->getBool("bilinear_filter"); + bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter"); + + video::ITexture *texture = tsrc->getTextureForMesh(texturestring); + if (!texture) + return false; + + material.setTexture(0, texture); + + // don't filter low-res textures, makes them look blurry + const core::dimension2d &size = texture->getOriginalSize(); + if (std::min(size.Width, size.Height) < TEXTURE_FILTER_MIN_SIZE) + use_trilinear_filter = use_bilinear_filter = false; + + material.forEachTexture([=] (auto &tex) { + setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, + use_anisotropic_filter); + }); + return true; +} + static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill, float txs, float tys, int col, int row) { @@ -1238,10 +1263,6 @@ void GenericCAO::updateTextures(std::string mod) { ITextureSource *tsrc = m_client->tsrc(); - bool use_trilinear_filter = g_settings->getBool("trilinear_filter"); - bool use_bilinear_filter = g_settings->getBool("bilinear_filter"); - bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter"); - m_previous_texture_modifier = m_current_texture_modifier; m_current_texture_modifier = mod; @@ -1254,12 +1275,7 @@ void GenericCAO::updateTextures(std::string mod) video::SMaterial &material = m_spritenode->getMaterial(0); material.MaterialType = m_material_type; - material.setTexture(0, tsrc->getTextureForMesh(texturestring)); - - material.forEachTexture([=] (auto &tex) { - setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, - use_anisotropic_filter); - }); + setMaterialTextureAndFilters(material, texturestring, tsrc); } } @@ -1273,29 +1289,12 @@ void GenericCAO::updateTextures(std::string mod) if (texturestring.empty()) continue; // Empty texture string means don't modify that material texturestring += mod; - video::ITexture *texture = tsrc->getTextureForMesh(texturestring); - if (!texture) { - errorstream<<"GenericCAO::updateTextures(): Could not load texture "<getMaterial(i); material.MaterialType = m_material_type; - material.TextureLayers[0].Texture = texture; material.BackfaceCulling = m_prop.backface_culling; - - // don't filter low-res textures, makes them look blurry - // player models have a res of 64 - const core::dimension2d &size = texture->getOriginalSize(); - const u32 res = std::min(size.Height, size.Width); - use_trilinear_filter &= res > 64; - use_bilinear_filter &= res > 64; - - material.forEachTexture([=] (auto &tex) { - setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, - use_anisotropic_filter); - }); + setMaterialTextureAndFilters(material, texturestring, tsrc); } } } @@ -1313,13 +1312,7 @@ void GenericCAO::updateTextures(std::string mod) // Set material flags and texture video::SMaterial &material = m_meshnode->getMaterial(i); material.MaterialType = m_material_type; - material.setTexture(0, tsrc->getTextureForMesh(texturestring)); - material.getTextureMatrix(0).makeIdentity(); - - material.forEachTexture([=] (auto &tex) { - setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, - use_anisotropic_filter); - }); + setMaterialTextureAndFilters(material, texturestring, tsrc); } } else if (m_prop.visual == OBJECTVISUAL_UPRIGHT_SPRITE) { scene::IMesh *mesh = m_meshnode->getMesh(); @@ -1330,12 +1323,7 @@ void GenericCAO::updateTextures(std::string mod) tname += mod; auto &material = m_meshnode->getMaterial(0); - material.setTexture(0, tsrc->getTextureForMesh(tname)); - - material.forEachTexture([=] (auto &tex) { - setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, - use_anisotropic_filter); - }); + setMaterialTextureAndFilters(material, tname, tsrc); } { std::string tname = "no_texture.png"; @@ -1346,12 +1334,7 @@ void GenericCAO::updateTextures(std::string mod) tname += mod; auto &material = m_meshnode->getMaterial(1); - material.setTexture(0, tsrc->getTextureForMesh(tname)); - - material.forEachTexture([=] (auto &tex) { - setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, - use_anisotropic_filter); - }); + setMaterialTextureAndFilters(material, tname, tsrc); } // Set mesh color (only if lighting is disabled) if (m_prop.glow < 0) diff --git a/src/client/imagesource.cpp b/src/client/imagesource.cpp index 3e55dd386..e39dc2955 100644 --- a/src/client/imagesource.cpp +++ b/src/client/imagesource.cpp @@ -1479,21 +1479,28 @@ bool ImageSource::generateImagePart(std::string_view part_of_name, /* Upscale textures to user's requested minimum size. This is a trick to make * filters look as good on low-res textures as on high-res ones, by making - * low-res textures BECOME high-res ones. This is helpful for worlds that + * low-res textures BECOME high-res ones. This is helpful for worlds that * mix high- and low-res textures, or for mods with least-common-denominator * textures that don't have the resources to offer high-res alternatives. + * + * Q: why not just enable/disable filtering depending on texture size? + * A: large texture resolutions apparently allow getting rid of the Moire + * effect way better than anisotropic filtering alone could. + * see and related + * linked discussions. */ const bool filter = m_setting_trilinear_filter || m_setting_bilinear_filter; - const s32 scaleto = filter ? g_settings->getU16("texture_min_size") : 1; - if (scaleto > 1) { - const core::dimension2d dim = baseimg->getDimension(); + if (filter) { + const f32 scaleto = rangelim(g_settings->getU16("texture_min_size"), + TEXTURE_FILTER_MIN_SIZE, 16384); - /* Calculate scaling needed to make the shortest texture dimension - * equal to the target minimum. If e.g. this is a vertical frames - * animation, the short dimension will be the real size. + /* Calculate integer-scaling needed to make the shortest texture + * dimension equal to the target minimum. If this is e.g. a + * vertical frames animation, the short dimension will be the real size. */ - u32 xscale = scaleto / dim.Width; - u32 yscale = scaleto / dim.Height; + const auto &dim = baseimg->getDimension(); + u32 xscale = std::ceil(scaleto / dim.Width); + u32 yscale = std::ceil(scaleto / dim.Height); const s32 scale = std::max(xscale, yscale); // Never downscale; only scale up by 2x or more. diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 11116a5c3..baa72f1d9 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -281,12 +281,11 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, material.MaterialType = m_material_type; material.MaterialTypeParam = 0.5f; material.BackfaceCulling = true; - // Enable bi/trilinear filtering only for high resolution textures - bool bilinear_filter = dim.Width > 32 && m_bilinear_filter; - bool trilinear_filter = dim.Width > 32 && m_trilinear_filter; + // don't filter low-res textures, makes them look blurry + bool f_ok = std::min(dim.Width, dim.Height) >= TEXTURE_FILTER_MIN_SIZE; material.forEachTexture([=] (auto &tex) { - setMaterialFilters(tex, bilinear_filter, trilinear_filter, - m_anisotropic_filter); + setMaterialFilters(tex, m_bilinear_filter && f_ok, + m_trilinear_filter && f_ok, m_anisotropic_filter); }); // mipmaps cause "thin black line" artifacts material.UseMipMaps = false; diff --git a/src/constants.h b/src/constants.h index 4a8ed4471..e97bd0507 100644 --- a/src/constants.h +++ b/src/constants.h @@ -99,3 +99,9 @@ #define SCREENSHOT_MAX_SERIAL_TRIES 1000 #define TTF_DEFAULT_FONT_SIZE (16) + +// Minimum texture size enforced/checked for enabling linear filtering +// This serves as the minimum for `texture_min_size`. +// The intent is to ensure that the rendering doesn't turn terribly blurry +// when filtering is enabled. +#define TEXTURE_FILTER_MIN_SIZE 192U diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 205fe5934..67b090bc6 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -246,7 +246,7 @@ void set_default_settings() settings->setDefault("undersampling", "1"); settings->setDefault("world_aligned_mode", "enable"); settings->setDefault("autoscale_mode", "disable"); - settings->setDefault("texture_min_size", "64"); + settings->setDefault("texture_min_size", std::to_string(TEXTURE_FILTER_MIN_SIZE)); settings->setDefault("enable_fog", "true"); settings->setDefault("fog_start", "0.4"); settings->setDefault("3d_mode", "none"); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 8ef6f8493..45fc8b55d 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -272,7 +272,8 @@ void TextureSettings::readSettings() connected_glass = g_settings->getBool("connected_glass"); translucent_liquids = g_settings->getBool("translucent_liquids"); enable_minimap = g_settings->getBool("enable_minimap"); - node_texture_size = std::max(g_settings->getU16("texture_min_size"), 1); + node_texture_size = rangelim(g_settings->getU16("texture_min_size"), + TEXTURE_FILTER_MIN_SIZE, 16384); std::string leaves_style_str = g_settings->get("leaves_style"); std::string world_aligned_mode_str = g_settings->get("world_aligned_mode"); std::string autoscale_mode_str = g_settings->get("autoscale_mode"); From b2c2a6ff4708362986acc65c62e95a23c1312165 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 17 Apr 2025 22:15:14 +0200 Subject: [PATCH 022/131] Rename IShaderConstantSetter --- src/client/clientlauncher.cpp | 2 +- src/client/game.cpp | 30 +++++++++---------- src/client/renderingengine.cpp | 8 ++--- src/client/renderingengine.h | 6 ++-- src/client/shader.cpp | 30 +++++++++---------- src/client/shader.h | 16 +++++----- src/client/shadows/dynamicshadowsrender.cpp | 2 +- src/client/shadows/shadowsshadercallbacks.cpp | 2 +- src/client/shadows/shadowsshadercallbacks.h | 14 ++++----- 9 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 725ff4323..dc6a91831 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -126,7 +126,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) // This is only global so it can be used by RenderingEngine::draw_load_screen(). assert(!g_menucloudsmgr && !g_menuclouds); std::unique_ptr ssrc(createShaderSource()); - ssrc->addShaderConstantSetterFactory(new FogShaderConstantSetterFactory()); + ssrc->addShaderUniformSetterFactory(new FogShaderUniformSetterFactory()); g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager(); g_menuclouds = new Clouds(g_menucloudsmgr, ssrc.get(), -1, rand()); g_menuclouds->setHeight(100.0f); diff --git a/src/client/game.cpp b/src/client/game.cpp index 78d009c7e..61d067ef3 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -188,7 +188,7 @@ public: typedef s32 SamplerLayer_t; -class GameGlobalShaderConstantSetter : public IShaderConstantSetter +class GameGlobalShaderUniformSetter : public IShaderUniformSetter { Sky *m_sky; Client *m_client; @@ -247,12 +247,12 @@ public: static void settingsCallback(const std::string &name, void *userdata) { - reinterpret_cast(userdata)->onSettingsChange(name); + reinterpret_cast(userdata)->onSettingsChange(name); } void setSky(Sky *sky) { m_sky = sky; } - GameGlobalShaderConstantSetter(Sky *sky, Client *client) : + GameGlobalShaderUniformSetter(Sky *sky, Client *client) : m_sky(sky), m_client(client) { @@ -264,12 +264,12 @@ public: m_volumetric_light_enabled = g_settings->getBool("enable_volumetric_lighting") && m_bloom_enabled; } - ~GameGlobalShaderConstantSetter() + ~GameGlobalShaderUniformSetter() { g_settings->deregisterAllChangedCallbacks(this); } - void onSetConstants(video::IMaterialRendererServices *services) override + void onSetUniforms(video::IMaterialRendererServices *services) override { u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio(); video::SColorf sunlight; @@ -395,28 +395,28 @@ public: }; -class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory +class GameGlobalShaderUniformSetterFactory : public IShaderUniformSetterFactory { Sky *m_sky = nullptr; Client *m_client; - std::vector created_nosky; + std::vector created_nosky; public: - GameGlobalShaderConstantSetterFactory(Client *client) : + GameGlobalShaderUniformSetterFactory(Client *client) : m_client(client) {} void setSky(Sky *sky) { m_sky = sky; - for (GameGlobalShaderConstantSetter *ggscs : created_nosky) { + for (GameGlobalShaderUniformSetter *ggscs : created_nosky) { ggscs->setSky(m_sky); } created_nosky.clear(); } - virtual IShaderConstantSetter* create() + virtual IShaderUniformSetter* create() { - auto *scs = new GameGlobalShaderConstantSetter(m_sky, m_client); + auto *scs = new GameGlobalShaderUniformSetter(m_sky, m_client); if (!m_sky) created_nosky.push_back(scs); return scs; @@ -1289,11 +1289,11 @@ bool Game::createClient(const GameStartData &start_data) return false; } - auto *scsf = new GameGlobalShaderConstantSetterFactory(client); - shader_src->addShaderConstantSetterFactory(scsf); + auto *scsf = new GameGlobalShaderUniformSetterFactory(client); + shader_src->addShaderUniformSetterFactory(scsf); - shader_src->addShaderConstantSetterFactory( - new FogShaderConstantSetterFactory()); + shader_src->addShaderUniformSetterFactory( + new FogShaderUniformSetterFactory()); ShadowRenderer::preInit(shader_src); diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 643898eac..3b3d114ea 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -67,14 +67,14 @@ void FpsControl::limit(IrrlichtDevice *device, f32 *dtime) last_time = time; } -class FogShaderConstantSetter : public IShaderConstantSetter +class FogShaderUniformSetter : public IShaderUniformSetter { CachedPixelShaderSetting m_fog_color{"fogColor"}; CachedPixelShaderSetting m_fog_distance{"fogDistance"}; CachedPixelShaderSetting m_fog_shading_parameter{"fogShadingParameter"}; public: - void onSetConstants(video::IMaterialRendererServices *services) override + void onSetUniforms(video::IMaterialRendererServices *services) override { auto *driver = services->getVideoDriver(); assert(driver); @@ -101,9 +101,9 @@ public: } }; -IShaderConstantSetter *FogShaderConstantSetterFactory::create() +IShaderUniformSetter *FogShaderUniformSetterFactory::create() { - return new FogShaderConstantSetter(); + return new FogShaderUniformSetter(); } /* Other helpers */ diff --git a/src/client/renderingengine.h b/src/client/renderingengine.h index d76b19abe..34918ec7a 100644 --- a/src/client/renderingengine.h +++ b/src/client/renderingengine.h @@ -54,11 +54,11 @@ struct FpsControl { }; // Populates fogColor, fogDistance, fogShadingParameter with values from Irrlicht -class FogShaderConstantSetterFactory : public IShaderConstantSetterFactory +class FogShaderUniformSetterFactory : public IShaderUniformSetterFactory { public: - FogShaderConstantSetterFactory() {}; - virtual IShaderConstantSetter *create(); + FogShaderUniformSetterFactory() {}; + virtual IShaderUniformSetter *create(); }; /* Rendering engine class */ diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 3ecbb4f38..39ea7c46d 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -159,7 +159,7 @@ private: class ShaderCallback : public video::IShaderConstantSetCallBack { - std::vector> m_setters; + std::vector> m_setters; public: template @@ -175,7 +175,7 @@ public: virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override { for (auto &&setter : m_setters) - setter->onSetConstants(services); + setter->onSetUniforms(services); } virtual void OnSetMaterial(const video::SMaterial& material) override @@ -187,10 +187,10 @@ public: /* - MainShaderConstantSetter: Set basic constants required for almost everything + MainShaderUniformSetter: Set basic uniforms required for almost everything */ -class MainShaderConstantSetter : public IShaderConstantSetter +class MainShaderUniformSetter : public IShaderUniformSetter { CachedVertexShaderSetting m_world_view_proj{"mWorldViewProj"}; CachedVertexShaderSetting m_world{"mWorld"}; @@ -205,14 +205,14 @@ class MainShaderConstantSetter : public IShaderConstantSetter CachedPixelShaderSetting m_material_color_setting{"materialColor"}; public: - ~MainShaderConstantSetter() = default; + ~MainShaderUniformSetter() = default; virtual void onSetMaterial(const video::SMaterial& material) override { m_material_color = material.ColorParam; } - virtual void onSetConstants(video::IMaterialRendererServices *services) override + virtual void onSetUniforms(video::IMaterialRendererServices *services) override { video::IVideoDriver *driver = services->getVideoDriver(); assert(driver); @@ -243,11 +243,11 @@ public: }; -class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory +class MainShaderUniformSetterFactory : public IShaderUniformSetterFactory { public: - virtual IShaderConstantSetter* create() - { return new MainShaderConstantSetter(); } + virtual IShaderUniformSetter* create() + { return new MainShaderUniformSetter(); } }; @@ -306,9 +306,9 @@ public: // Shall be called from the main thread. void rebuildShaders() override; - void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) override + void addShaderUniformSetterFactory(IShaderUniformSetterFactory *setter) override { - m_setter_factories.emplace_back(setter); + m_uniform_factories.emplace_back(setter); } private: @@ -331,8 +331,8 @@ private: RequestQueue m_get_shader_queue; #endif - // Global constant setter factories - std::vector> m_setter_factories; + // Global uniform setter factories + std::vector> m_uniform_factories; // Generate shader given the shader name. ShaderInfo generateShader(const std::string &name, @@ -352,7 +352,7 @@ ShaderSource::ShaderSource() m_shaderinfo_cache.emplace_back(); // Add main global constant setter - addShaderConstantSetterFactory(new MainShaderConstantSetterFactory()); + addShaderUniformSetterFactory(new MainShaderUniformSetterFactory()); } ShaderSource::~ShaderSource() @@ -773,7 +773,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, geometry_shader_ptr = geometry_shader.c_str(); } - auto cb = make_irr(m_setter_factories); + auto cb = make_irr(m_uniform_factories); infostream << "Compiling high level shaders for " << log_name << std::endl; s32 shadermat = gpu->addHighLevelShaderMaterial( vertex_shader.c_str(), fragment_shader.c_str(), geometry_shader_ptr, diff --git a/src/client/shader.h b/src/client/shader.h index c78b0078a..731cd4b21 100644 --- a/src/client/shader.h +++ b/src/client/shader.h @@ -40,7 +40,7 @@ struct ShaderInfo { }; /* - Setter of constants for shaders + Abstraction for updating uniforms used by shaders */ namespace irr::video { @@ -48,19 +48,19 @@ namespace irr::video { } -class IShaderConstantSetter { +class IShaderUniformSetter { public: - virtual ~IShaderConstantSetter() = default; - virtual void onSetConstants(video::IMaterialRendererServices *services) = 0; + virtual ~IShaderUniformSetter() = default; + virtual void onSetUniforms(video::IMaterialRendererServices *services) = 0; virtual void onSetMaterial(const video::SMaterial& material) { } }; -class IShaderConstantSetterFactory { +class IShaderUniformSetterFactory { public: - virtual ~IShaderConstantSetterFactory() = default; - virtual IShaderConstantSetter* create() = 0; + virtual ~IShaderUniformSetterFactory() = default; + virtual IShaderUniformSetter* create() = 0; }; @@ -236,7 +236,7 @@ public: virtual void rebuildShaders()=0; /// @note Takes ownership of @p setter. - virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0; + virtual void addShaderUniformSetterFactory(IShaderUniformSetterFactory *setter) = 0; }; IWritableShaderSource *createShaderSource(); diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 70bc2d2cf..1297bf175 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -107,7 +107,7 @@ void ShadowRenderer::disable() void ShadowRenderer::preInit(IWritableShaderSource *shsrc) { if (g_settings->getBool("enable_dynamic_shadows")) { - shsrc->addShaderConstantSetterFactory(new ShadowConstantSetterFactory()); + shsrc->addShaderUniformSetterFactory(new ShadowUniformSetterFactory()); } } diff --git a/src/client/shadows/shadowsshadercallbacks.cpp b/src/client/shadows/shadowsshadercallbacks.cpp index f662d21e7..add5f8a09 100644 --- a/src/client/shadows/shadowsshadercallbacks.cpp +++ b/src/client/shadows/shadowsshadercallbacks.cpp @@ -5,7 +5,7 @@ #include "client/shadows/shadowsshadercallbacks.h" #include "client/renderingengine.h" -void ShadowConstantSetter::onSetConstants(video::IMaterialRendererServices *services) +void ShadowUniformSetter::onSetUniforms(video::IMaterialRendererServices *services) { auto *shadow = RenderingEngine::get_shadow_renderer(); if (!shadow) diff --git a/src/client/shadows/shadowsshadercallbacks.h b/src/client/shadows/shadowsshadercallbacks.h index 4fc462b11..cd1ff3916 100644 --- a/src/client/shadows/shadowsshadercallbacks.h +++ b/src/client/shadows/shadowsshadercallbacks.h @@ -9,7 +9,7 @@ // Used by main game rendering -class ShadowConstantSetter : public IShaderConstantSetter +class ShadowUniformSetter : public IShaderUniformSetter { CachedPixelShaderSetting m_shadow_view_proj{"m_ShadowViewProj"}; CachedPixelShaderSetting m_light_direction{"v_LightDirection"}; @@ -33,17 +33,17 @@ class ShadowConstantSetter : public IShaderConstantSetter CachedPixelShaderSetting m_perspective_zbias_pixel{"zPerspectiveBias"}; public: - ShadowConstantSetter() = default; - ~ShadowConstantSetter() = default; + ShadowUniformSetter() = default; + ~ShadowUniformSetter() = default; - virtual void onSetConstants(video::IMaterialRendererServices *services) override; + virtual void onSetUniforms(video::IMaterialRendererServices *services) override; }; -class ShadowConstantSetterFactory : public IShaderConstantSetterFactory +class ShadowUniformSetterFactory : public IShaderUniformSetterFactory { public: - virtual IShaderConstantSetter *create() { - return new ShadowConstantSetter(); + virtual IShaderUniformSetter *create() { + return new ShadowUniformSetter(); } }; From baa4c7cd21fe434a53e27a7de2d2df0159f964cb Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 17 Apr 2025 23:13:44 +0200 Subject: [PATCH 023/131] Introduce IShaderConstantSetter abstraction --- src/client/shader.cpp | 310 +++++++++++++++++++++++++----------------- src/client/shader.h | 26 +++- 2 files changed, 206 insertions(+), 130 deletions(-) diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 39ea7c46d..46dd9a1f2 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -186,6 +186,154 @@ public: }; +/* + MainShaderConstantSetter: Set some random general constants + NodeShaderConstantSetter: Set constants for node rendering +*/ + +class MainShaderConstantSetter : public IShaderConstantSetter +{ +public: + MainShaderConstantSetter() = default; + ~MainShaderConstantSetter() = default; + + void onGenerate(const std::string &name, ShaderConstants &constants) override + { + constants["ENABLE_TONE_MAPPING"] = g_settings->getBool("tone_mapping") ? 1 : 0; + + if (g_settings->getBool("enable_dynamic_shadows")) { + constants["ENABLE_DYNAMIC_SHADOWS"] = 1; + if (g_settings->getBool("shadow_map_color")) + constants["COLORED_SHADOWS"] = 1; + + if (g_settings->getBool("shadow_poisson_filter")) + constants["POISSON_FILTER"] = 1; + + if (g_settings->getBool("enable_water_reflections")) + constants["ENABLE_WATER_REFLECTIONS"] = 1; + + if (g_settings->getBool("enable_translucent_foliage")) + constants["ENABLE_TRANSLUCENT_FOLIAGE"] = 1; + + if (g_settings->getBool("enable_node_specular")) + constants["ENABLE_NODE_SPECULAR"] = 1; + + s32 shadow_filter = g_settings->getS32("shadow_filters"); + constants["SHADOW_FILTER"] = shadow_filter; + + float shadow_soft_radius = std::max(1.f, + g_settings->getFloat("shadow_soft_radius")); + constants["SOFTSHADOWRADIUS"] = shadow_soft_radius; + } + + if (g_settings->getBool("enable_bloom")) { + constants["ENABLE_BLOOM"] = 1; + if (g_settings->getBool("enable_bloom_debug")) + constants["ENABLE_BLOOM_DEBUG"] = 1; + } + + if (g_settings->getBool("enable_auto_exposure")) + constants["ENABLE_AUTO_EXPOSURE"] = 1; + + if (g_settings->get("antialiasing") == "ssaa") { + constants["ENABLE_SSAA"] = 1; + u16 ssaa_scale = std::max(2, g_settings->getU16("fsaa")); + constants["SSAA_SCALE"] = ssaa_scale; + } + + if (g_settings->getBool("debanding")) + constants["ENABLE_DITHERING"] = 1; + + if (g_settings->getBool("enable_volumetric_lighting")) + constants["VOLUMETRIC_LIGHT"] = 1; + } +}; + + +class NodeShaderConstantSetter : public IShaderConstantSetter +{ +public: + NodeShaderConstantSetter() = default; + ~NodeShaderConstantSetter() = default; + + void onGenerate(const std::string &name, ShaderConstants &constants) override + { + if (constants.find("DRAWTYPE") == constants.end()) + return; // not a node shader + [[maybe_unused]] const auto drawtype = + static_cast(std::get(constants["DRAWTYPE"])); + [[maybe_unused]] const auto material_type = + static_cast(std::get(constants["MATERIAL_TYPE"])); + +#define PROVIDE(constant) constants[ #constant ] = (int)constant + + PROVIDE(NDT_NORMAL); + PROVIDE(NDT_AIRLIKE); + PROVIDE(NDT_LIQUID); + PROVIDE(NDT_FLOWINGLIQUID); + PROVIDE(NDT_GLASSLIKE); + PROVIDE(NDT_ALLFACES); + PROVIDE(NDT_ALLFACES_OPTIONAL); + PROVIDE(NDT_TORCHLIKE); + PROVIDE(NDT_SIGNLIKE); + PROVIDE(NDT_PLANTLIKE); + PROVIDE(NDT_FENCELIKE); + PROVIDE(NDT_RAILLIKE); + PROVIDE(NDT_NODEBOX); + PROVIDE(NDT_GLASSLIKE_FRAMED); + PROVIDE(NDT_FIRELIKE); + PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL); + PROVIDE(NDT_PLANTLIKE_ROOTED); + + PROVIDE(TILE_MATERIAL_BASIC); + PROVIDE(TILE_MATERIAL_ALPHA); + PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT); + PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE); + PROVIDE(TILE_MATERIAL_WAVING_LEAVES); + PROVIDE(TILE_MATERIAL_WAVING_PLANTS); + PROVIDE(TILE_MATERIAL_OPAQUE); + PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC); + PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT); + PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE); + PROVIDE(TILE_MATERIAL_PLAIN); + PROVIDE(TILE_MATERIAL_PLAIN_ALPHA); + +#undef PROVIDE + + bool enable_waving_water = g_settings->getBool("enable_waving_water"); + constants["ENABLE_WAVING_WATER"] = enable_waving_water ? 1 : 0; + if (enable_waving_water) { + constants["WATER_WAVE_HEIGHT"] = g_settings->getFloat("water_wave_height"); + constants["WATER_WAVE_LENGTH"] = g_settings->getFloat("water_wave_length"); + constants["WATER_WAVE_SPEED"] = g_settings->getFloat("water_wave_speed"); + } + switch (material_type) { + case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: + case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: + case TILE_MATERIAL_WAVING_LIQUID_BASIC: + constants["MATERIAL_WAVING_LIQUID"] = 1; + break; + default: + constants["MATERIAL_WAVING_LIQUID"] = 0; + break; + } + switch (material_type) { + case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: + case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: + case TILE_MATERIAL_WAVING_LIQUID_BASIC: + case TILE_MATERIAL_LIQUID_TRANSPARENT: + constants["MATERIAL_WATER_REFLECTIONS"] = 1; + break; + default: + constants["MATERIAL_WATER_REFLECTIONS"] = 0; + break; + } + + constants["ENABLE_WAVING_LEAVES"] = g_settings->getBool("enable_waving_leaves") ? 1 : 0; + constants["ENABLE_WAVING_PLANTS"] = g_settings->getBool("enable_waving_plants") ? 1 : 0; + } +}; + /* MainShaderUniformSetter: Set basic uniforms required for almost everything */ @@ -306,6 +454,11 @@ public: // Shall be called from the main thread. void rebuildShaders() override; + void addShaderConstantSetter(IShaderConstantSetter *setter) override + { + m_constant_setters.emplace_back(setter); + } + void addShaderUniformSetterFactory(IShaderUniformSetterFactory *setter) override { m_uniform_factories.emplace_back(setter); @@ -331,6 +484,9 @@ private: RequestQueue m_get_shader_queue; #endif + // Global constant setter factories + std::vector> m_constant_setters; + // Global uniform setter factories std::vector> m_uniform_factories; @@ -351,7 +507,9 @@ ShaderSource::ShaderSource() // Add a dummy ShaderInfo as the first index, named "" m_shaderinfo_cache.emplace_back(); - // Add main global constant setter + // Add global stuff + addShaderConstantSetter(new MainShaderConstantSetter()); + addShaderConstantSetter(new NodeShaderConstantSetter()); addShaderUniformSetterFactory(new MainShaderUniformSetterFactory()); } @@ -613,12 +771,16 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, /// Unique name of this shader, for debug/logging std::string log_name = name; - /* Define constants for node and object shaders */ - const bool node_shader = drawtype != NodeDrawType_END; - if (node_shader) { + ShaderConstants constants; - log_name.append(" mat=").append(itos(material_type)) - .append(" draw=").append(itos(drawtype)); + // Temporary plumbing <-> NodeShaderConstantSetter + if (drawtype != NodeDrawType_END) { + constants["DRAWTYPE"] = (int)drawtype; + constants["MATERIAL_TYPE"] = (int)material_type; + + log_name.append(" mat=").append(itos(material_type)) + .append(" draw=").append(itos(drawtype)); + } bool use_discard = fully_programmable; if (!use_discard) { @@ -629,133 +791,25 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, } if (use_discard) { if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL) - shaders_header << "#define USE_DISCARD 1\n"; + constants["USE_DISCARD"] = 1; else if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF) - shaders_header << "#define USE_DISCARD_REF 1\n"; + constants["USE_DISCARD_REF"] = 1; } -#define PROVIDE(constant) shaders_header << "#define " #constant " " << (int)constant << "\n" - - PROVIDE(NDT_NORMAL); - PROVIDE(NDT_AIRLIKE); - PROVIDE(NDT_LIQUID); - PROVIDE(NDT_FLOWINGLIQUID); - PROVIDE(NDT_GLASSLIKE); - PROVIDE(NDT_ALLFACES); - PROVIDE(NDT_ALLFACES_OPTIONAL); - PROVIDE(NDT_TORCHLIKE); - PROVIDE(NDT_SIGNLIKE); - PROVIDE(NDT_PLANTLIKE); - PROVIDE(NDT_FENCELIKE); - PROVIDE(NDT_RAILLIKE); - PROVIDE(NDT_NODEBOX); - PROVIDE(NDT_GLASSLIKE_FRAMED); - PROVIDE(NDT_FIRELIKE); - PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL); - PROVIDE(NDT_PLANTLIKE_ROOTED); - - PROVIDE(TILE_MATERIAL_BASIC); - PROVIDE(TILE_MATERIAL_ALPHA); - PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT); - PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE); - PROVIDE(TILE_MATERIAL_WAVING_LEAVES); - PROVIDE(TILE_MATERIAL_WAVING_PLANTS); - PROVIDE(TILE_MATERIAL_OPAQUE); - PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC); - PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT); - PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE); - PROVIDE(TILE_MATERIAL_PLAIN); - PROVIDE(TILE_MATERIAL_PLAIN_ALPHA); - -#undef PROVIDE - - shaders_header << "#define MATERIAL_TYPE " << (int)material_type << "\n"; - shaders_header << "#define DRAW_TYPE " << (int)drawtype << "\n"; - - bool enable_waving_water = g_settings->getBool("enable_waving_water"); - shaders_header << "#define ENABLE_WAVING_WATER " << enable_waving_water << "\n"; - if (enable_waving_water) { - shaders_header << "#define WATER_WAVE_HEIGHT " << g_settings->getFloat("water_wave_height") << "\n"; - shaders_header << "#define WATER_WAVE_LENGTH " << g_settings->getFloat("water_wave_length") << "\n"; - shaders_header << "#define WATER_WAVE_SPEED " << g_settings->getFloat("water_wave_speed") << "\n"; - } - switch (material_type) { - case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: - case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: - case TILE_MATERIAL_WAVING_LIQUID_BASIC: - shaders_header << "#define MATERIAL_WAVING_LIQUID 1\n"; - break; - default: - shaders_header << "#define MATERIAL_WAVING_LIQUID 0\n"; - break; - } - switch (material_type) { - case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: - case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: - case TILE_MATERIAL_WAVING_LIQUID_BASIC: - case TILE_MATERIAL_LIQUID_TRANSPARENT: - shaders_header << "#define MATERIAL_WATER_REFLECTIONS 1\n"; - break; - default: - shaders_header << "#define MATERIAL_WATER_REFLECTIONS 0\n"; - break; + /* Let the constant setters do their job and emit constants */ + for (auto &setter : m_constant_setters) { + setter->onGenerate(name, constants); } - shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n"; - shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n"; - - } - - /* Other constants */ - - shaders_header << "#define ENABLE_TONE_MAPPING " << g_settings->getBool("tone_mapping") << "\n"; - - if (g_settings->getBool("enable_dynamic_shadows")) { - shaders_header << "#define ENABLE_DYNAMIC_SHADOWS 1\n"; - if (g_settings->getBool("shadow_map_color")) - shaders_header << "#define COLORED_SHADOWS 1\n"; - - if (g_settings->getBool("shadow_poisson_filter")) - shaders_header << "#define POISSON_FILTER 1\n"; - - if (g_settings->getBool("enable_water_reflections")) - shaders_header << "#define ENABLE_WATER_REFLECTIONS 1\n"; - - if (g_settings->getBool("enable_translucent_foliage")) - shaders_header << "#define ENABLE_TRANSLUCENT_FOLIAGE 1\n"; - - if (g_settings->getBool("enable_node_specular")) - shaders_header << "#define ENABLE_NODE_SPECULAR 1\n"; - - s32 shadow_filter = g_settings->getS32("shadow_filters"); - shaders_header << "#define SHADOW_FILTER " << shadow_filter << "\n"; - - float shadow_soft_radius = g_settings->getFloat("shadow_soft_radius"); - if (shadow_soft_radius < 1.0f) - shadow_soft_radius = 1.0f; - shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n"; - } - - if (g_settings->getBool("enable_bloom")) { - shaders_header << "#define ENABLE_BLOOM 1\n"; - if (g_settings->getBool("enable_bloom_debug")) - shaders_header << "#define ENABLE_BLOOM_DEBUG 1\n"; - } - - if (g_settings->getBool("enable_auto_exposure")) - shaders_header << "#define ENABLE_AUTO_EXPOSURE 1\n"; - - if (g_settings->get("antialiasing") == "ssaa") { - shaders_header << "#define ENABLE_SSAA 1\n"; - u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa")); - shaders_header << "#define SSAA_SCALE " << ssaa_scale << ".\n"; - } - - if (g_settings->getBool("debanding")) - shaders_header << "#define ENABLE_DITHERING 1\n"; - - if (g_settings->getBool("enable_volumetric_lighting")) { - shaders_header << "#define VOLUMETRIC_LIGHT 1\n"; + for (auto &it : constants) { + // spaces could cause duplicates + assert(trim(it.first) == it.first); + shaders_header << "#define " << it.first << ' '; + if (auto *ival = std::get_if(&it.second); ival) + shaders_header << *ival; + else + shaders_header << std::get(it.second); + shaders_header << '\n'; } std::string common_header = shaders_header.str(); diff --git a/src/client/shader.h b/src/client/shader.h index 731cd4b21..0dc6d29ff 100644 --- a/src/client/shader.h +++ b/src/client/shader.h @@ -8,10 +8,10 @@ #include "irrlichttypes_bloated.h" #include #include +#include +#include #include "nodedef.h" -class IGameDef; - /* shader.{h,cpp}: Shader handling stuff. */ @@ -39,6 +39,25 @@ struct ShaderInfo { virtual ~ShaderInfo() = default; }; +/* + Abstraction for pushing constants (or what we pretend is) into + shaders. These end up as `#define` prepended to the shader source. +*/ + +// Shader constants are either an int or a float in GLSL +typedef std::map> ShaderConstants; + +class IShaderConstantSetter { +public: + virtual ~IShaderConstantSetter() = default; + /** + * Called when the final shader source is being generated + * @param name name of the shader + * @param constants current set of constants, free to modify + */ + virtual void onGenerate(const std::string &name, ShaderConstants &constants) = 0; +}; + /* Abstraction for updating uniforms used by shaders */ @@ -235,6 +254,9 @@ public: const std::string &filename, const std::string &program)=0; virtual void rebuildShaders()=0; + /// @note Takes ownership of @p setter. + virtual void addShaderConstantSetter(IShaderConstantSetter *setter) = 0; + /// @note Takes ownership of @p setter. virtual void addShaderUniformSetterFactory(IShaderUniformSetterFactory *setter) = 0; }; From f3c2bbfb4833fdbdd8b3bda0a0f102c72d12bcbc Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 17 Apr 2025 23:48:08 +0200 Subject: [PATCH 024/131] Change shaders to be defined by input constants rather than drawtype/material type --- src/client/shader.cpp | 161 +++++++++++++++++++++++------------------- src/client/shader.h | 55 ++++++++++----- 2 files changed, 127 insertions(+), 89 deletions(-) diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 46dd9a1f2..643c381c0 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -410,14 +410,13 @@ public: ~ShaderSource() override; /* - - If shader material specified by name is found from cache, - return the cached id. + - If shader material is found from cache, return the cached id. - Otherwise generate the shader material, add to cache and return id. The id 0 points to a null shader. Its material is EMT_SOLID. */ - u32 getShaderIdDirect(const std::string &name, - MaterialType material_type, NodeDrawType drawtype); + u32 getShaderIdDirect(const std::string &name, const ShaderConstants &input_const, + video::E_MATERIAL_TYPE base_mat); /* If shader specified by the name pointed by the id doesn't @@ -427,19 +426,10 @@ public: and not found in cache, the call is queued to the main thread for processing. */ - u32 getShader(const std::string &name, - MaterialType material_type, NodeDrawType drawtype) override; + u32 getShader(const std::string &name, const ShaderConstants &input_const, + video::E_MATERIAL_TYPE base_mat) override; - u32 getShaderRaw(const std::string &name, bool blendAlpha) override - { - // TODO: the shader system should be refactored to be much more generic. - // Just let callers pass arbitrary constants, this would also deal with - // runtime changes cleanly. - return getShader(name, blendAlpha ? TILE_MATERIAL_ALPHA : TILE_MATERIAL_BASIC, - NodeDrawType_END); - } - - ShaderInfo getShaderInfo(u32 id) override; + const ShaderInfo &getShaderInfo(u32 id) override; // Processes queued shader requests from other threads. // Shall be called from the main thread. @@ -492,7 +482,16 @@ private: // Generate shader given the shader name. ShaderInfo generateShader(const std::string &name, - MaterialType material_type, NodeDrawType drawtype); + const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat); + + /// @brief outputs a constant to an ostream + inline void putConstant(std::ostream &os, const ShaderConstants::mapped_type &it) + { + if (auto *ival = std::get_if(&it); ival) + os << *ival; + else + os << std::get(it); + } }; IWritableShaderSource *createShaderSource() @@ -520,22 +519,27 @@ ShaderSource::~ShaderSource() // Delete materials auto *gpu = RenderingEngine::get_video_driver()->getGPUProgrammingServices(); assert(gpu); + u32 n = 0; for (ShaderInfo &i : m_shaderinfo_cache) { - if (!i.name.empty()) + if (!i.name.empty()) { gpu->deleteShaderMaterial(i.material); + n++; + } } m_shaderinfo_cache.clear(); + + infostream << "~ShaderSource() cleaned up " << n << " materials" << std::endl; } u32 ShaderSource::getShader(const std::string &name, - MaterialType material_type, NodeDrawType drawtype) + const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat) { /* Get shader */ if (std::this_thread::get_id() == m_main_thread) { - return getShaderIdDirect(name, material_type, drawtype); + return getShaderIdDirect(name, input_const, base_mat); } errorstream << "ShaderSource::getShader(): getting from " @@ -573,7 +577,7 @@ u32 ShaderSource::getShader(const std::string &name, This method generates all the shaders */ u32 ShaderSource::getShaderIdDirect(const std::string &name, - MaterialType material_type, NodeDrawType drawtype) + const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat) { // Empty name means shader 0 if (name.empty()) { @@ -582,10 +586,10 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name, } // Check if already have such instance - for(u32 i=0; iname == name && info->material_type == material_type && - info->drawtype == drawtype) + for (u32 i = 0; i < m_shaderinfo_cache.size(); i++) { + auto &info = m_shaderinfo_cache[i]; + if (info.name == name && info.base_material == base_mat && + info.input_constants == input_const) return i; } @@ -598,7 +602,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name, return 0; } - ShaderInfo info = generateShader(name, material_type, drawtype); + ShaderInfo info = generateShader(name, input_const, base_mat); /* Add shader to caches (add dummy shaders too) @@ -607,19 +611,19 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name, MutexAutoLock lock(m_shaderinfo_cache_mutex); u32 id = m_shaderinfo_cache.size(); - m_shaderinfo_cache.push_back(info); - + m_shaderinfo_cache.push_back(std::move(info)); return id; } -ShaderInfo ShaderSource::getShaderInfo(u32 id) +const ShaderInfo &ShaderSource::getShaderInfo(u32 id) { MutexAutoLock lock(m_shaderinfo_cache_mutex); - if(id >= m_shaderinfo_cache.size()) - return ShaderInfo(); - + if (id >= m_shaderinfo_cache.size()) { + static ShaderInfo empty; + return empty; + } return m_shaderinfo_cache[id]; } @@ -655,46 +659,31 @@ void ShaderSource::rebuildShaders() } } + infostream << "ShaderSource: recreating " << m_shaderinfo_cache.size() + << " shaders" << std::endl; + // Recreate shaders for (ShaderInfo &i : m_shaderinfo_cache) { ShaderInfo *info = &i; if (!info->name.empty()) { - *info = generateShader(info->name, info->material_type, info->drawtype); + *info = generateShader(info->name, info->input_constants, info->base_material); } } } ShaderInfo ShaderSource::generateShader(const std::string &name, - MaterialType material_type, NodeDrawType drawtype) + const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat) { ShaderInfo shaderinfo; shaderinfo.name = name; - shaderinfo.material_type = material_type; - shaderinfo.drawtype = drawtype; - switch (material_type) { - case TILE_MATERIAL_OPAQUE: - case TILE_MATERIAL_LIQUID_OPAQUE: - case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: - shaderinfo.base_material = video::EMT_SOLID; - break; - case TILE_MATERIAL_ALPHA: - case TILE_MATERIAL_PLAIN_ALPHA: - case TILE_MATERIAL_LIQUID_TRANSPARENT: - case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: - shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - break; - case TILE_MATERIAL_BASIC: - case TILE_MATERIAL_PLAIN: - case TILE_MATERIAL_WAVING_LEAVES: - case TILE_MATERIAL_WAVING_PLANTS: - case TILE_MATERIAL_WAVING_LIQUID_BASIC: - shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - break; - } + shaderinfo.input_constants = input_const; + // fixed pipeline materials don't make sense here + assert(base_mat != video::EMT_TRANSPARENT_VERTEX_ALPHA && base_mat != video::EMT_ONETEXTURE_BLEND); + shaderinfo.base_material = base_mat; shaderinfo.material = shaderinfo.base_material; - video::IVideoDriver *driver = RenderingEngine::get_video_driver(); + auto *driver = RenderingEngine::get_video_driver(); // The null driver doesn't support shaders (duh), but we can pretend it does. if (driver->getDriverType() == video::EDT_NULL) return shaderinfo; @@ -770,18 +759,18 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, /// Unique name of this shader, for debug/logging std::string log_name = name; - - ShaderConstants constants; - - // Temporary plumbing <-> NodeShaderConstantSetter - if (drawtype != NodeDrawType_END) { - constants["DRAWTYPE"] = (int)drawtype; - constants["MATERIAL_TYPE"] = (int)material_type; - - log_name.append(" mat=").append(itos(material_type)) - .append(" draw=").append(itos(drawtype)); + for (auto &it : input_const) { + if (log_name.size() > 60) { // it shouldn't be too long + log_name.append("..."); + break; + } + std::ostringstream oss; + putConstant(oss, it.second); + log_name.append(" ").append(it.first).append("=").append(oss.str()); } + ShaderConstants constants = input_const; + bool use_discard = fully_programmable; if (!use_discard) { // workaround for a certain OpenGL implementation lacking GL_ALPHA_TEST @@ -805,10 +794,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, // spaces could cause duplicates assert(trim(it.first) == it.first); shaders_header << "#define " << it.first << ' '; - if (auto *ival = std::get_if(&it.second); ival) - shaders_header << *ival; - else - shaders_header << std::get(it.second); + putConstant(shaders_header, it.second); shaders_header << '\n'; } @@ -849,6 +835,39 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, return shaderinfo; } +/* + Other functions and helpers +*/ + +u32 IShaderSource::getShader(const std::string &name, + MaterialType material_type, NodeDrawType drawtype) +{ + ShaderConstants input_const; + input_const["MATERIAL_TYPE"] = (int)material_type; + input_const["DRAWTYPE"] = (int)drawtype; + + video::E_MATERIAL_TYPE base_mat = video::EMT_SOLID; + switch (material_type) { + case TILE_MATERIAL_ALPHA: + case TILE_MATERIAL_PLAIN_ALPHA: + case TILE_MATERIAL_LIQUID_TRANSPARENT: + case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: + base_mat = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + break; + case TILE_MATERIAL_BASIC: + case TILE_MATERIAL_PLAIN: + case TILE_MATERIAL_WAVING_LEAVES: + case TILE_MATERIAL_WAVING_PLANTS: + case TILE_MATERIAL_WAVING_LIQUID_BASIC: + base_mat = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + break; + default: + break; + } + + return getShader(name, input_const, base_mat); +} + void dumpShaderProgram(std::ostream &output_stream, const std::string &program_type, std::string_view program) { diff --git a/src/client/shader.h b/src/client/shader.h index 0dc6d29ff..c4e37bb2e 100644 --- a/src/client/shader.h +++ b/src/client/shader.h @@ -28,17 +28,6 @@ std::string getShaderPath(const std::string &name_of_shader, const std::string &filename); -struct ShaderInfo { - std::string name = ""; - video::E_MATERIAL_TYPE base_material = video::EMT_SOLID; - video::E_MATERIAL_TYPE material = video::EMT_SOLID; - NodeDrawType drawtype = NDT_NORMAL; - MaterialType material_type = TILE_MATERIAL_BASIC; - - ShaderInfo() = default; - virtual ~ShaderInfo() = default; -}; - /* Abstraction for pushing constants (or what we pretend is) into shaders. These end up as `#define` prepended to the shader source. @@ -218,7 +207,18 @@ using CachedStructPixelShaderSetting = CachedStructShaderSetting Date: Fri, 18 Apr 2025 10:09:00 +0200 Subject: [PATCH 025/131] Move NodeShaderConstantSetter to game.cpp --- src/client/game.cpp | 105 ++++++++++++++++---- src/client/shader.cpp | 105 ++++---------------- src/client/shadows/dynamicshadowsrender.cpp | 3 + 3 files changed, 107 insertions(+), 106 deletions(-) diff --git a/src/client/game.cpp b/src/client/game.cpp index 61d067ef3..08be9c809 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -204,10 +204,6 @@ class GameGlobalShaderUniformSetter : public IShaderUniformSetter CachedVertexShaderSetting m_camera_offset_vertex{"cameraOffset"}; CachedPixelShaderSetting m_camera_position_pixel{ "cameraPosition" }; CachedVertexShaderSetting m_camera_position_vertex{ "cameraPosition" }; - CachedPixelShaderSetting m_texture0{"texture0"}; - CachedPixelShaderSetting m_texture1{"texture1"}; - CachedPixelShaderSetting m_texture2{"texture2"}; - CachedPixelShaderSetting m_texture3{"texture3"}; CachedVertexShaderSetting m_texel_size0_vertex{"texelSize0"}; CachedPixelShaderSetting m_texel_size0_pixel{"texelSize0"}; v2f m_texel_size0; @@ -298,16 +294,6 @@ public: m_camera_position_pixel.set(camera_position, services); m_camera_position_pixel.set(camera_position, services); - SamplerLayer_t tex_id; - tex_id = 0; - m_texture0.set(&tex_id, services); - tex_id = 1; - m_texture1.set(&tex_id, services); - tex_id = 2; - m_texture2.set(&tex_id, services); - tex_id = 3; - m_texture3.set(&tex_id, services); - m_texel_size0_vertex.set(m_texel_size0, services); m_texel_size0_pixel.set(m_texel_size0, services); @@ -423,6 +409,90 @@ public: } }; +class NodeShaderConstantSetter : public IShaderConstantSetter +{ +public: + NodeShaderConstantSetter() = default; + ~NodeShaderConstantSetter() = default; + + void onGenerate(const std::string &name, ShaderConstants &constants) override + { + if (constants.find("DRAWTYPE") == constants.end()) + return; // not a node shader + [[maybe_unused]] const auto drawtype = + static_cast(std::get(constants["DRAWTYPE"])); + [[maybe_unused]] const auto material_type = + static_cast(std::get(constants["MATERIAL_TYPE"])); + +#define PROVIDE(constant) constants[ #constant ] = (int)constant + + PROVIDE(NDT_NORMAL); + PROVIDE(NDT_AIRLIKE); + PROVIDE(NDT_LIQUID); + PROVIDE(NDT_FLOWINGLIQUID); + PROVIDE(NDT_GLASSLIKE); + PROVIDE(NDT_ALLFACES); + PROVIDE(NDT_ALLFACES_OPTIONAL); + PROVIDE(NDT_TORCHLIKE); + PROVIDE(NDT_SIGNLIKE); + PROVIDE(NDT_PLANTLIKE); + PROVIDE(NDT_FENCELIKE); + PROVIDE(NDT_RAILLIKE); + PROVIDE(NDT_NODEBOX); + PROVIDE(NDT_GLASSLIKE_FRAMED); + PROVIDE(NDT_FIRELIKE); + PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL); + PROVIDE(NDT_PLANTLIKE_ROOTED); + + PROVIDE(TILE_MATERIAL_BASIC); + PROVIDE(TILE_MATERIAL_ALPHA); + PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT); + PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE); + PROVIDE(TILE_MATERIAL_WAVING_LEAVES); + PROVIDE(TILE_MATERIAL_WAVING_PLANTS); + PROVIDE(TILE_MATERIAL_OPAQUE); + PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC); + PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT); + PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE); + PROVIDE(TILE_MATERIAL_PLAIN); + PROVIDE(TILE_MATERIAL_PLAIN_ALPHA); + +#undef PROVIDE + + bool enable_waving_water = g_settings->getBool("enable_waving_water"); + constants["ENABLE_WAVING_WATER"] = enable_waving_water ? 1 : 0; + if (enable_waving_water) { + constants["WATER_WAVE_HEIGHT"] = g_settings->getFloat("water_wave_height"); + constants["WATER_WAVE_LENGTH"] = g_settings->getFloat("water_wave_length"); + constants["WATER_WAVE_SPEED"] = g_settings->getFloat("water_wave_speed"); + } + switch (material_type) { + case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: + case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: + case TILE_MATERIAL_WAVING_LIQUID_BASIC: + constants["MATERIAL_WAVING_LIQUID"] = 1; + break; + default: + constants["MATERIAL_WAVING_LIQUID"] = 0; + break; + } + switch (material_type) { + case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: + case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: + case TILE_MATERIAL_WAVING_LIQUID_BASIC: + case TILE_MATERIAL_LIQUID_TRANSPARENT: + constants["MATERIAL_WATER_REFLECTIONS"] = 1; + break; + default: + constants["MATERIAL_WATER_REFLECTIONS"] = 0; + break; + } + + constants["ENABLE_WAVING_LEAVES"] = g_settings->getBool("enable_waving_leaves") ? 1 : 0; + constants["ENABLE_WAVING_PLANTS"] = g_settings->getBool("enable_waving_plants") ? 1 : 0; + } +}; + /**************************************************************************** ****************************************************************************/ @@ -837,11 +907,6 @@ Game::Game() : } - -/**************************************************************************** - MinetestApp Public - ****************************************************************************/ - Game::~Game() { delete client; @@ -1289,6 +1354,8 @@ bool Game::createClient(const GameStartData &start_data) return false; } + shader_src->addShaderConstantSetter(new NodeShaderConstantSetter()); + auto *scsf = new GameGlobalShaderUniformSetterFactory(client); shader_src->addShaderUniformSetterFactory(scsf); diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 643c381c0..e2985e66b 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -187,8 +187,7 @@ public: /* - MainShaderConstantSetter: Set some random general constants - NodeShaderConstantSetter: Set constants for node rendering + MainShaderConstantSetter: Sets some random general constants */ class MainShaderConstantSetter : public IShaderConstantSetter @@ -250,96 +249,14 @@ public: }; -class NodeShaderConstantSetter : public IShaderConstantSetter -{ -public: - NodeShaderConstantSetter() = default; - ~NodeShaderConstantSetter() = default; - - void onGenerate(const std::string &name, ShaderConstants &constants) override - { - if (constants.find("DRAWTYPE") == constants.end()) - return; // not a node shader - [[maybe_unused]] const auto drawtype = - static_cast(std::get(constants["DRAWTYPE"])); - [[maybe_unused]] const auto material_type = - static_cast(std::get(constants["MATERIAL_TYPE"])); - -#define PROVIDE(constant) constants[ #constant ] = (int)constant - - PROVIDE(NDT_NORMAL); - PROVIDE(NDT_AIRLIKE); - PROVIDE(NDT_LIQUID); - PROVIDE(NDT_FLOWINGLIQUID); - PROVIDE(NDT_GLASSLIKE); - PROVIDE(NDT_ALLFACES); - PROVIDE(NDT_ALLFACES_OPTIONAL); - PROVIDE(NDT_TORCHLIKE); - PROVIDE(NDT_SIGNLIKE); - PROVIDE(NDT_PLANTLIKE); - PROVIDE(NDT_FENCELIKE); - PROVIDE(NDT_RAILLIKE); - PROVIDE(NDT_NODEBOX); - PROVIDE(NDT_GLASSLIKE_FRAMED); - PROVIDE(NDT_FIRELIKE); - PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL); - PROVIDE(NDT_PLANTLIKE_ROOTED); - - PROVIDE(TILE_MATERIAL_BASIC); - PROVIDE(TILE_MATERIAL_ALPHA); - PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT); - PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE); - PROVIDE(TILE_MATERIAL_WAVING_LEAVES); - PROVIDE(TILE_MATERIAL_WAVING_PLANTS); - PROVIDE(TILE_MATERIAL_OPAQUE); - PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC); - PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT); - PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE); - PROVIDE(TILE_MATERIAL_PLAIN); - PROVIDE(TILE_MATERIAL_PLAIN_ALPHA); - -#undef PROVIDE - - bool enable_waving_water = g_settings->getBool("enable_waving_water"); - constants["ENABLE_WAVING_WATER"] = enable_waving_water ? 1 : 0; - if (enable_waving_water) { - constants["WATER_WAVE_HEIGHT"] = g_settings->getFloat("water_wave_height"); - constants["WATER_WAVE_LENGTH"] = g_settings->getFloat("water_wave_length"); - constants["WATER_WAVE_SPEED"] = g_settings->getFloat("water_wave_speed"); - } - switch (material_type) { - case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: - case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: - case TILE_MATERIAL_WAVING_LIQUID_BASIC: - constants["MATERIAL_WAVING_LIQUID"] = 1; - break; - default: - constants["MATERIAL_WAVING_LIQUID"] = 0; - break; - } - switch (material_type) { - case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: - case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: - case TILE_MATERIAL_WAVING_LIQUID_BASIC: - case TILE_MATERIAL_LIQUID_TRANSPARENT: - constants["MATERIAL_WATER_REFLECTIONS"] = 1; - break; - default: - constants["MATERIAL_WATER_REFLECTIONS"] = 0; - break; - } - - constants["ENABLE_WAVING_LEAVES"] = g_settings->getBool("enable_waving_leaves") ? 1 : 0; - constants["ENABLE_WAVING_PLANTS"] = g_settings->getBool("enable_waving_plants") ? 1 : 0; - } -}; - /* MainShaderUniformSetter: Set basic uniforms required for almost everything */ class MainShaderUniformSetter : public IShaderUniformSetter { + using SamplerLayer_t = s32; + CachedVertexShaderSetting m_world_view_proj{"mWorldViewProj"}; CachedVertexShaderSetting m_world{"mWorld"}; @@ -348,6 +265,11 @@ class MainShaderUniformSetter : public IShaderUniformSetter // Texture matrix CachedVertexShaderSetting m_texture{"mTexture"}; + CachedPixelShaderSetting m_texture0{"texture0"}; + CachedPixelShaderSetting m_texture1{"texture1"}; + CachedPixelShaderSetting m_texture2{"texture2"}; + CachedPixelShaderSetting m_texture3{"texture3"}; + // commonly used way to pass material color to shader video::SColor m_material_color; CachedPixelShaderSetting m_material_color_setting{"materialColor"}; @@ -385,6 +307,16 @@ public: m_texture.set(texture, services); } + SamplerLayer_t tex_id; + tex_id = 0; + m_texture0.set(&tex_id, services); + tex_id = 1; + m_texture1.set(&tex_id, services); + tex_id = 2; + m_texture2.set(&tex_id, services); + tex_id = 3; + m_texture3.set(&tex_id, services); + video::SColorf colorf(m_material_color); m_material_color_setting.set(colorf, services); } @@ -508,7 +440,6 @@ ShaderSource::ShaderSource() // Add global stuff addShaderConstantSetter(new MainShaderConstantSetter()); - addShaderConstantSetter(new NodeShaderConstantSetter()); addShaderUniformSetterFactory(new MainShaderUniformSetterFactory()); } diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 1297bf175..17260e21d 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -514,6 +514,9 @@ void ShadowRenderer::mixShadowsQuad() * Shaders system with custom IShaderConstantSetCallBack without messing up the * code too much. If anyone knows how to integrate this with the standard MT * shaders, please feel free to change it. + * + * TODO: as of now (2025) it should be possible to hook these up to the normal + * shader system. */ void ShadowRenderer::createShaders() From c0e42c65881cb26dbbcdc8206a736fd407beae51 Mon Sep 17 00:00:00 2001 From: Linn16 Date: Mon, 21 Apr 2025 12:32:58 +0200 Subject: [PATCH 026/131] Use map_compression_level_disk from minetest.conf for --recompress (#16037) --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index d62ee1f21..bf01db71b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1280,6 +1280,7 @@ static bool recompress_map_database(const GameParams &game_params, const Setting u64 last_update_time = 0; bool &kill = *porting::signal_handler_killstatus(); const u8 serialize_as_ver = SER_FMT_VER_HIGHEST_WRITE; + const s16 map_compression_level = rangelim(g_settings->getS16("map_compression_level_disk"), -1, 9); // This is ok because the server doesn't actually run std::vector blocks; @@ -1307,7 +1308,7 @@ static bool recompress_map_database(const GameParams &game_params, const Setting oss.str(""); oss.clear(); writeU8(oss, serialize_as_ver); - mb.serialize(oss, serialize_as_ver, true, -1); + mb.serialize(oss, serialize_as_ver, true, map_compression_level); } db->saveBlock(*it, oss.str()); From 5c6e4d35b0195e97fcb3dbfdd4b20df6dcbad13d Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Mon, 21 Apr 2025 12:33:19 +0200 Subject: [PATCH 027/131] Client: protect against circular attachments (#16038) The server already includes such check. There must be a desync issue that causes an ID mismatch, resulting in client crashes. Any such crash must be prevented. --- src/client/content_cao.cpp | 26 ++++++++++++++++++++++++++ src/server/unit_sao.cpp | 6 ++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 02e980cab..e0ac5fff0 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -411,6 +411,32 @@ void GenericCAO::setChildrenVisible(bool toset) void GenericCAO::setAttachment(object_t parent_id, const std::string &bone, v3f position, v3f rotation, bool force_visible) { + // Do checks to avoid circular references + // See similar check in `UnitSAO::setAttachment` (but with different types). + { + auto *obj = m_env->getActiveObject(parent_id); + if (obj == this) { + assert(false); + return; + } + bool problem = false; + if (obj) { + // The chain of wanted parent must not refer or contain "this" + for (obj = obj->getParent(); obj; obj = obj->getParent()) { + if (obj == this) { + problem = true; + break; + } + } + } + if (problem) { + warningstream << "Network or mod bug: " + << "Attempted to attach object " << m_id << " to parent " + << parent_id << " but former is an (in)direct parent of latter." << std::endl; + return; + } + } + const auto old_parent = m_attachment_parent_id; m_attachment_parent_id = parent_id; m_attachment_bone = bone; diff --git a/src/server/unit_sao.cpp b/src/server/unit_sao.cpp index d7fff69bf..35c92063d 100644 --- a/src/server/unit_sao.cpp +++ b/src/server/unit_sao.cpp @@ -128,8 +128,9 @@ void UnitSAO::setAttachment(const object_t new_parent, const std::string &bone, }; // Do checks to avoid circular references + // See similar check in `GenericCAO::setAttachment` (but with different types). { - auto *obj = new_parent ? m_env->getActiveObject(new_parent) : nullptr; + auto *obj = m_env->getActiveObject(new_parent); if (obj == this) { assert(false); return; @@ -145,7 +146,8 @@ void UnitSAO::setAttachment(const object_t new_parent, const std::string &bone, } } if (problem) { - warningstream << "Mod bug: Attempted to attach object " << m_id << " to parent " + warningstream << "Mod bug: " + << "Attempted to attach object " << m_id << " to parent " << new_parent << " but former is an (in)direct parent of latter." << std::endl; return; } From 0cf1c47f6c7fe4fd507e97c1dc9462cfe0a81d3c Mon Sep 17 00:00:00 2001 From: grorp Date: Mon, 21 Apr 2025 06:33:41 -0400 Subject: [PATCH 028/131] Fix scrollbar on ContentDB grid by adding an area label (#16042) Co-authored-by: rubenwardy --- builtin/mainmenu/content/dlg_contentdb.lua | 23 ++-- doc/lua_api.md | 15 +++ src/gui/guiFormSpecMenu.cpp | 128 ++++++++++++--------- src/network/networkprotocol.cpp | 2 +- 4 files changed, 108 insertions(+), 60 deletions(-) diff --git a/builtin/mainmenu/content/dlg_contentdb.lua b/builtin/mainmenu/content/dlg_contentdb.lua index 872fab113..7f389135b 100644 --- a/builtin/mainmenu/content/dlg_contentdb.lua +++ b/builtin/mainmenu/content/dlg_contentdb.lua @@ -310,9 +310,17 @@ local function get_formspec(dlgdata) }) local img_w = cell_h * 3 / 2 + -- Use as much of the available space as possible (so no padding on the + -- right/bottom), but don't quite allow the text to touch the border. + local text_w = cell_w - img_w - 0.25 - 0.025 + local text_h = cell_h - 0.25 - 0.025 + local start_idx = (cur_page - 1) * num_per_page + 1 for i=start_idx, math.min(#contentdb.packages, start_idx+num_per_page-1) do local package = contentdb.packages[i] + local text = core.colorize(mt_color_green, package.title) .. + core.colorize("#BFBFBF", " by " .. package.author) .. "\n" .. + package.short_description table.insert_all(formspec, { "container[", @@ -327,13 +335,14 @@ local function get_formspec(dlgdata) "image[0,0;", img_w, ",", cell_h, ";", core.formspec_escape(get_screenshot(package, package.thumbnail, 2)), "]", - "label[", img_w + 0.25 + 0.05, ",0.5;", - core.formspec_escape( - core.colorize(mt_color_green, package.title) .. - core.colorize("#BFBFBF", " by " .. package.author)), "]", + "label[", img_w + 0.25, ",0.25;", text_w, ",", text_h, ";", + core.formspec_escape(text), "]", - "textarea[", img_w + 0.25, ",0.75;", cell_w - img_w - 0.25, ",", cell_h - 0.75, ";;;", - core.formspec_escape(package.short_description), "]", + -- Add a tooltip in case the label overflows and the short description is cut off. + "tooltip[", img_w + 0.25, ",0.25;", text_w, ",", text_h, ";", + -- Text in tooltips doesn't wrap automatically, so we do it manually to + -- avoid everything being one long line. + core.formspec_escape(core.wrap_text(package.short_description, 80)), "]", "style[view_", i, ";border=false]", "style[view_", i, ":hovered;bgimg=", core.formspec_escape(defaulttexturedir .. "button_hover_semitrans.png"), "]", @@ -349,7 +358,7 @@ local function get_formspec(dlgdata) end table.insert_all(formspec, { - "container[", cell_w - 0.625,",", 0.25, "]", + "container[", cell_w - 0.625,",", 0.125, "]", }) if package.downloading then diff --git a/doc/lua_api.md b/doc/lua_api.md index 31eb35dd2..6943dec16 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -2842,6 +2842,9 @@ Version History * Add field_enter_after_edit[] (experimental) * Formspec version 8 (5.10.0) * scroll_container[]: content padding parameter +* Formspec version 9 (5.12.0) + * Add allow_close[] + * label[]: Add "area label" variant Elements -------- @@ -3154,9 +3157,11 @@ Elements ### `textarea[,;,;;