Merge branch 'master' into doc-refactor-2

This commit is contained in:
Bituvo 2024-04-07 10:53:46 -04:00
commit 14cbce2303
29 changed files with 278 additions and 89 deletions

View File

@ -490,6 +490,9 @@ end
function table.insert_all(t, other)
if table.move then -- LuaJIT
return table.move(other, 1, #other, #t + 1, t)
end
for i=1, #other do
t[#t + 1] = other[i]
end

View File

@ -39,6 +39,7 @@ core.features = {
dynamic_add_media_filepath = true,
lsystem_decoration_type = true,
item_meta_range = true,
node_interaction_actor = true,
}
function core.has_feature(arg)

View File

@ -26,7 +26,15 @@ do
core.print = nil -- don't pollute our namespace
end
end
math.randomseed(os.time())
do
-- Note that PUC Lua just calls srand() which is already initialized by C++,
-- but we don't want to rely on this implementation detail.
local seed = 1048576 * (os.time() % 1048576)
seed = seed + core.get_us_time() % 1048576
math.randomseed(seed)
end
minetest = core
-- Load other files

View File

@ -98,15 +98,12 @@ local function download_and_extract(param)
local tempfolder = core.get_temp_path()
if tempfolder ~= "" then
tempfolder = tempfolder .. DIR_DELIM .. "MT_" .. math.random(1, 1024000)
if not core.extract_zip(filename, tempfolder) then
tempfolder = nil
end
else
tempfolder = nil
end
os.remove(filename)
if not tempfolder then
if not tempfolder or tempfolder == "" then
return {
msg = fgettext_ne("Failed to extract \"$1\" (unsupported file type or broken archive)", package.title),
}

View File

@ -80,7 +80,8 @@ local WEIGHT_SORT = 2
-- how much the estimated latency contributes to the final ranking
local WEIGHT_LATENCY = 1
local function order_server_list(list)
--- @param list of servers, will be modified.
local function order_server_list_internal(list)
-- calculate the scores
local s1 = Normalizer:new()
local s2 = Normalizer:new()
@ -99,22 +100,36 @@ local function order_server_list(list)
s1 = s1:calc()
s2 = s2:calc()
-- make a shallow copy and pre-calculate ordering
local res, order = {}, {}
for i = 1, #list do
local fav = list[i]
res[i] = fav
local n = s1[fav] * WEIGHT_SORT + s2[fav] * WEIGHT_LATENCY
order[fav] = n
-- pre-calculate ordering
local order = {}
for _, fav in ipairs(list) do
order[fav] = s1[fav] * WEIGHT_SORT + s2[fav] * WEIGHT_LATENCY
end
-- now sort the list
table.sort(res, function(fav1, fav2)
table.sort(list, function(fav1, fav2)
return order[fav1] > order[fav2]
end)
end
return res
local function order_server_list(list)
-- split the list into two parts and sort them separately, to keep empty
-- servers at the bottom.
local nonempty, empty = {}, {}
for _, fav in ipairs(list) do
if (fav.clients or 0) > 0 then
table.insert(nonempty, fav)
else
table.insert(empty, fav)
end
end
order_server_list_internal(nonempty)
order_server_list_internal(empty)
table.insert_all(nonempty, empty)
return nonempty
end
local public_downloading = false

View File

@ -1,7 +1,7 @@
uniform vec4 fogColor;
uniform lowp vec4 fogColor;
uniform float fogDistance;
uniform float fogShadingParameter;
varying vec3 eyeVec;
varying highp vec3 eyeVec;
varying lowp vec4 varColor;

View File

@ -1,8 +1,8 @@
uniform vec4 emissiveColor;
uniform lowp vec4 emissiveColor;
varying lowp vec4 varColor;
varying vec3 eyeVec;
varying highp vec3 eyeVec;
void main(void)
{

View File

@ -1,13 +1,12 @@
uniform sampler2D baseTexture;
uniform vec3 dayLight;
uniform vec4 fogColor;
uniform lowp vec4 fogColor;
uniform float fogDistance;
uniform float fogShadingParameter;
uniform vec3 eyePosition;
// The cameraOffset is the current center of the visible world.
uniform vec3 cameraOffset;
uniform highp vec3 cameraOffset;
uniform float animationTimer;
#ifdef ENABLE_DYNAMIC_SHADOWS
// shadow texture
@ -44,11 +43,8 @@ varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec;
varying highp vec3 eyeVec;
varying float nightRatio;
varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
#ifdef ENABLE_DYNAMIC_SHADOWS

View File

@ -1,10 +1,9 @@
uniform mat4 mWorld;
// Color of the light emitted by the sun.
uniform vec3 dayLight;
uniform vec3 eyePosition;
// The cameraOffset is the current center of the visible world.
uniform vec3 cameraOffset;
uniform highp vec3 cameraOffset;
uniform float animationTimer;
varying vec3 vNormal;
@ -44,7 +43,7 @@ centroid varying vec2 varTexCoord;
varying float area_enable_parallax;
varying vec3 eyeVec;
varying highp vec3 eyeVec;
varying float nightRatio;
// Color of the light emitted by the light sources.
const vec3 artificialLight = vec3(1.04, 1.04, 1.04);

View File

@ -1,13 +1,12 @@
uniform sampler2D baseTexture;
uniform vec3 dayLight;
uniform vec4 fogColor;
uniform lowp vec4 fogColor;
uniform float fogDistance;
uniform float fogShadingParameter;
uniform vec3 eyePosition;
// The cameraOffset is the current center of the visible world.
uniform vec3 cameraOffset;
uniform highp vec3 cameraOffset;
uniform float animationTimer;
#ifdef ENABLE_DYNAMIC_SHADOWS
// shadow texture
@ -44,7 +43,7 @@ varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec;
varying highp vec3 eyeVec;
varying float nightRatio;
varying float vIDiff;

View File

@ -1,10 +1,7 @@
uniform mat4 mWorld;
uniform vec3 dayLight;
uniform vec3 eyePosition;
uniform float animationTimer;
uniform vec4 emissiveColor;
uniform vec3 cameraOffset;
uniform lowp vec4 emissiveColor;
varying vec3 vNormal;
varying vec3 vPosition;
@ -33,7 +30,7 @@ centroid varying vec2 varTexCoord;
varying float perspective_factor;
#endif
varying vec3 eyeVec;
varying highp vec3 eyeVec;
varying float nightRatio;
// Color of the light emitted by the light sources.
const vec3 artificialLight = vec3(1.04, 1.04, 1.04);

View File

@ -1,4 +1,4 @@
uniform vec4 emissiveColor;
uniform lowp vec4 emissiveColor;
void main(void)
{

View File

@ -5348,6 +5348,9 @@ Minetest includes the following settings to control behavior of privileges:
lsystem_decoration_type = true,
-- Overrideable pointing range using the itemstack meta key `"range"` (5.9.0)
item_meta_range = true,
-- Allow passing an optional "actor" ObjectRef to the following functions:
-- minetest.place_node, minetest.dig_node, minetest.punch_node (5.9.0)
node_interaction_actor = true,
}
```
@ -5977,13 +5980,16 @@ handler.
* Returns a number between `0` and `15`
* Currently it's the same as `math.floor(param1 / 16)`, except that it
ensures compatibility.
* `minetest.place_node(pos, node)`
* `minetest.place_node(pos, node[, placer])`
* Place node with the same effects that a player would cause
* `minetest.dig_node(pos)`
* `placer`: The ObjectRef that places the node (optional)
* `minetest.dig_node(pos[, digger])`
* Dig node with the same effects that a player would cause
* `digger`: The ObjectRef that digs the node (optional)
* Returns `true` if successful, `false` on failure (e.g. protected location)
* `minetest.punch_node(pos)`
* `minetest.punch_node(pos[, puncher])`
* Punch node with the same effects that a player would cause
* `puncher`: The ObjectRef that punches the node (optional)
* `minetest.spawn_falling_node(pos)`
* Change node into falling node
* Returns `true` and the ObjectRef of the spawned entity if successful, `false` on failure

View File

@ -90,8 +90,8 @@ The "gamedata" table is read when calling `core.start()`. It should contain:
registered in the core (possible in async calls)
* `core.get_cache_path()` -> path of cache
* `core.get_temp_path([param])` (possible in async calls)
* `param`=true: returns path to a temporary file
otherwise: returns path to the temporary folder
* `param == true`: returns path to a newly created temporary file
* otherwise: returns path to a newly created temporary folder

View File

@ -698,11 +698,13 @@ include(CheckCSourceCompiles)
set(CMAKE_REQUIRED_INCLUDES ${LUA_INCLUDE_DIR})
if(USE_LUAJIT)
set(CMAKE_REQUIRED_LIBRARIES ${LUA_LIBRARY})
# libm usually required if statically linking
set(CMAKE_REQUIRED_LIBRARIES ${LUA_LIBRARY} m)
# LuaJIT provides exactly zero ways to determine how recent it is (the version
# is unchanged since 2017), however it happens that string buffers were added
# after the changes which we care about so that works as an indicator.
# (https://github.com/LuaJIT/LuaJIT/commit/4c6b669 March 2021)
# Note: This is no longer true as of August 2023, but we're keeping the old check.
unset(HAVE_RECENT_LJ CACHE)
check_symbol_exists(luaopen_string_buffer "lualib.h" HAVE_RECENT_LJ)
if(NOT HAVE_RECENT_LJ)

View File

@ -1795,6 +1795,11 @@ float Client::mediaReceiveProgress()
return 1.0; // downloader only exists when not yet done
}
void Client::drawLoadScreen(const std::wstring &text, float dtime, int percent) {
m_rendering_engine->run();
m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, dtime, percent);
}
struct TextureUpdateArgs {
gui::IGUIEnvironment *guienv;
u64 last_time_ms;

View File

@ -356,6 +356,7 @@ public:
float mediaReceiveProgress();
void drawLoadScreen(const std::wstring &text, float dtime, int percent);
void afterContentReceived();
void showUpdateProgressTexture(void *args, u32 progress, u32 max_progress);

View File

@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "clientmedia.h"
#include "gettext.h"
#include "httpfetch.h"
#include "client.h"
#include "filecache.h"
@ -184,6 +185,11 @@ void ClientMediaDownloader::step(Client *client)
void ClientMediaDownloader::initialStep(Client *client)
{
std::wstring loading_text = wstrgettext("Media...");
// Tradeoff between responsiveness during media loading and media loading speed
const u64 chunk_time_ms = 33;
u64 last_time = porting::getTimeMs();
// Check media cache
m_uncached_count = m_files.size();
for (auto &file_it : m_files) {
@ -195,6 +201,13 @@ void ClientMediaDownloader::initialStep(Client *client)
filestatus->received = true;
m_uncached_count--;
}
u64 cur_time = porting::getTimeMs();
u64 dtime = porting::getDeltaMs(last_time, cur_time);
if (dtime >= chunk_time_ms) {
client->drawLoadScreen(loading_text, dtime / 1000.0f, 30);
last_time = cur_time;
}
}
assert(m_uncached_received_count == 0);

View File

@ -66,6 +66,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "shader.h"
#include "sky.h"
#include "threading/lambda.h"
#include "translation.h"
#include "util/basic_macros.h"
#include "util/directiontables.h"
@ -381,11 +382,9 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<float>
m_animation_timer_delta_pixel{"animationTimerDelta"};
CachedPixelShaderSetting<float, 3> m_day_light{"dayLight"};
CachedPixelShaderSetting<float, 3> m_eye_position_pixel{"eyePosition"};
CachedVertexShaderSetting<float, 3> m_eye_position_vertex{"eyePosition"};
CachedPixelShaderSetting<float, 3> m_minimap_yaw{"yawVec"};
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel{"cameraOffset"};
CachedPixelShaderSetting<float, 3> m_camera_offset_vertex{"cameraOffset"};
CachedVertexShaderSetting<float, 3> m_camera_offset_vertex{"cameraOffset"};
CachedPixelShaderSetting<SamplerLayer_t> m_texture0{"texture0"};
CachedPixelShaderSetting<SamplerLayer_t> m_texture1{"texture1"};
CachedPixelShaderSetting<SamplerLayer_t> m_texture2{"texture2"};
@ -483,10 +482,6 @@ public:
m_animation_timer_delta_vertex.set(&animation_timer_delta_f, services);
m_animation_timer_delta_pixel.set(&animation_timer_delta_f, services);
v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
m_eye_position_pixel.set(epos, services);
m_eye_position_vertex.set(epos, services);
if (m_client->getMinimap()) {
v3f minimap_yaw = m_client->getMinimap()->getYawVec();
m_minimap_yaw.set(minimap_yaw, services);
@ -1020,12 +1015,6 @@ Game::Game() :
Game::~Game()
{
delete client;
delete soundmaker;
sound_manager.reset();
delete server; // deleted first to stop all server threads
delete hud;
delete camera;
delete quicktune;
@ -1274,6 +1263,28 @@ void Game::shutdown()
sleep_ms(100);
}
}
delete client;
delete soundmaker;
sound_manager.reset();
auto stop_thread = runInThread([=] {
delete server;
}, "ServerStop");
FpsControl fps_control;
fps_control.reset();
while (stop_thread->isRunning()) {
m_rendering_engine->run();
f32 dtime;
fps_control.limit(device, &dtime);
showOverlayMessage(N_("Shutting down..."), dtime, 0, false);
}
stop_thread->rethrow();
// to be continued in Game::~Game
}
@ -1379,11 +1390,33 @@ bool Game::createSingleplayerServer(const std::string &map_dir,
server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr,
false, nullptr, error_message);
server->start();
copyServerClientCache();
auto start_thread = runInThread([=] {
server->start();
copyServerClientCache();
}, "ServerStart");
return true;
input->clear();
bool success = true;
FpsControl fps_control;
fps_control.reset();
while (start_thread->isRunning()) {
if (!m_rendering_engine->run() || input->cancelPressed())
success = false;
f32 dtime;
fps_control.limit(device, &dtime);
if (success)
showOverlayMessage(N_("Creating server..."), dtime, 5);
else
showOverlayMessage(N_("Shutting down..."), dtime, 0, false);
}
start_thread->rethrow();
return success;
}
void Game::copyServerClientCache()

View File

@ -801,7 +801,7 @@ void Hud::drawCrosshair()
core::dimension2di orig_size(tex->getOriginalSize());
// Integer scaling to avoid artifacts, floor instead of round since too
// small looks better than too large in this case.
core::dimension2di scaled_size = orig_size * std::floor(m_scale_factor);
core::dimension2di scaled_size = orig_size * std::max(std::floor(m_scale_factor), 1.0f);
core::rect<s32> src_rect(orig_size);
core::position2d pos(m_displaycenter.X - scaled_size.Width / 2,

View File

@ -19,7 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
#include <iostream>
#include <exception>
#include <cassert>
#include "gettime.h"

View File

@ -223,6 +223,16 @@ std::string CreateTempFile()
return path;
}
std::string CreateTempDir()
{
std::string path = TempPath() + DIR_DELIM "MT_XXXXXX";
_mktemp_s(&path[0], path.size() + 1); // modifies path
// will error if it already exists
if (!CreateDirectory(path.c_str(), nullptr))
return "";
return path;
}
bool CopyFileContents(const std::string &source, const std::string &target)
{
BOOL ok = CopyFileEx(source.c_str(), target.c_str(), nullptr, nullptr,
@ -446,6 +456,15 @@ std::string CreateTempFile()
return path;
}
std::string CreateTempDir()
{
std::string path = TempPath() + DIR_DELIM "MT_XXXXXX";
auto r = mkdtemp(&path[0]); // modifies path
if (!r)
return "";
return path;
}
namespace {
struct FileDeleter {
void operator()(FILE *stream) {

View File

@ -75,13 +75,19 @@ bool RecursiveDelete(const std::string &path);
bool DeleteSingleFileOrEmptyDirectory(const std::string &path);
// Returns path to temp directory, can return "" on error
/// Returns path to temp directory.
/// You probably don't want to use this directly, see `CreateTempFile` or `CreateTempDir`.
/// @return path or "" on error
std::string TempPath();
// Returns path to securely-created temporary file (will already exist when this function returns)
// can return "" on error
/// Returns path to securely-created temporary file (will already exist when this function returns).
/// @return path or "" on error
std::string CreateTempFile();
/// Returns path to securely-created temporary directory (will already exist when this function returns).
/// @return path or "" on error
std::string CreateTempDir();
/* Returns a list of subdirectories, including the path itself, but excluding
hidden directories (whose names start with . or _)
*/

View File

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_nodetimer.h"
#include "lua_api/l_noise.h"
#include "lua_api/l_vmanip.h"
#include "lua_api/l_object.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "scripting_server.h"
@ -416,7 +417,7 @@ int ModApiEnv::l_get_natural_light(lua_State *L)
return 1;
}
// place_node(pos, node)
// place_node(pos, node, [placer])
// pos = {x=num, y=num, z=num}
int ModApiEnv::l_place_node(lua_State *L)
{
@ -436,6 +437,7 @@ int ModApiEnv::l_place_node(lua_State *L)
lua_pushboolean(L, false);
return 1;
}
// Create item to place
std::optional<ItemStack> item = ItemStack(ndef->get(n).name, 1, 0, idef);
// Make pointed position
@ -443,13 +445,22 @@ int ModApiEnv::l_place_node(lua_State *L)
pointed.type = POINTEDTHING_NODE;
pointed.node_abovesurface = pos;
pointed.node_undersurface = pos + v3s16(0,-1,0);
// Place it with a NULL placer (appears in Lua as nil)
bool success = scriptIfaceItem->item_OnPlace(item, nullptr, pointed);
ServerActiveObject *placer = nullptr;
if (!lua_isnoneornil(L, 3)) {
ObjectRef *ref = checkObject<ObjectRef>(L, 3);
placer = ObjectRef::getobject(ref);
}
// Place it with a nullptr placer (appears in Lua as nil)
// or the given ObjectRef
bool success = scriptIfaceItem->item_OnPlace(item, placer, pointed);
lua_pushboolean(L, success);
return 1;
}
// dig_node(pos)
// dig_node(pos, [digger])
// pos = {x=num, y=num, z=num}
int ModApiEnv::l_dig_node(lua_State *L)
{
@ -465,14 +476,23 @@ int ModApiEnv::l_dig_node(lua_State *L)
lua_pushboolean(L, false);
return 1;
}
// Dig it out with a NULL digger (appears in Lua as a
// non-functional ObjectRef)
bool success = scriptIfaceNode->node_on_dig(pos, n, NULL);
ServerActiveObject *digger = nullptr;
if (!lua_isnoneornil(L, 2)) {
ObjectRef *ref = checkObject<ObjectRef>(L, 2);
digger = ObjectRef::getobject(ref);
}
// Dig it out with a nullptr digger
// (appears in Lua as a non-functional ObjectRef)
// or the given ObjectRef
bool success = scriptIfaceNode->node_on_dig(pos, n, digger);
lua_pushboolean(L, success);
return 1;
}
// punch_node(pos)
// punch_node(pos, [puncher])
// pos = {x=num, y=num, z=num}
int ModApiEnv::l_punch_node(lua_State *L)
{
@ -488,9 +508,19 @@ int ModApiEnv::l_punch_node(lua_State *L)
lua_pushboolean(L, false);
return 1;
}
// Punch it with a NULL puncher (appears in Lua as a non-functional
// ObjectRef)
bool success = scriptIfaceNode->node_on_punch(pos, n, NULL, PointedThing());
ServerActiveObject *puncher = nullptr;
if (!lua_isnoneornil(L, 2)) {
ObjectRef *ref = checkObject<ObjectRef>(L, 2);
puncher = ObjectRef::getobject(ref);
}
// Punch it with a nullptr puncher
// (appears in Lua as a non-functional ObjectRef)
// or the given ObjectRef
// TODO: custom PointedThing (requires a converter function)
bool success = scriptIfaceNode->node_on_punch(pos, n, puncher, PointedThing());
lua_pushboolean(L, success);
return 1;
}

View File

@ -89,15 +89,15 @@ private:
// timeofday: nil = current time, 0 = night, 0.5 = day
static int l_get_natural_light(lua_State *L);
// place_node(pos, node)
// place_node(pos, node, [placer])
// pos = {x=num, y=num, z=num}
static int l_place_node(lua_State *L);
// dig_node(pos)
// dig_node(pos, [digger])
// pos = {x=num, y=num, z=num}
static int l_dig_node(lua_State *L);
// punch_node(pos)
// punch_node(pos, [puncher])
// pos = {x=num, y=num, z=num}
static int l_punch_node(lua_State *L);

View File

@ -729,7 +729,7 @@ int ModApiMainMenu::l_get_cache_path(lua_State *L)
int ModApiMainMenu::l_get_temp_path(lua_State *L)
{
if (lua_isnoneornil(L, 1) || !lua_toboolean(L, 1))
lua_pushstring(L, fs::TempPath().c_str());
lua_pushstring(L, fs::CreateTempDir().c_str());
else
lua_pushstring(L, fs::CreateTempFile().c_str());
return 1;

64
src/threading/lambda.h Normal file
View File

@ -0,0 +1,64 @@
// Minetest
// SPDX-License-Identifier: LGPL-2.1-or-later
#pragma once
#include <exception>
#include <functional>
#include <memory>
#include "debug.h"
#include "threading/thread.h"
/**
* Class returned by `runInThread`.
*
* Provides the usual thread methods along with `rethrow()`.
*/
class LambdaThread : public Thread
{
friend std::unique_ptr<LambdaThread> runInThread(
const std::function<void()> &, const std::string &);
public:
/// Re-throw a caught exception, if any. Can only be called after thread exit.
void rethrow()
{
sanity_check(!isRunning());
if (m_exptr)
std::rethrow_exception(m_exptr);
}
private:
// hide methods
LambdaThread(const std::string &name="") : Thread(name) {}
using Thread::start;
std::function<void()> m_fn;
std::exception_ptr m_exptr;
void *run()
{
try {
m_fn();
} catch(...) {
m_exptr = std::current_exception();
}
return nullptr;
};
};
/**
* Run a lambda in a separate thread.
*
* Exceptions will be caught.
* @param fn function to run
* @param thread_name name for thread
* @return thread object of type `LambdaThread`
*/
std::unique_ptr<LambdaThread> runInThread(const std::function<void()> &fn,
const std::string &thread_name = "")
{
std::unique_ptr<LambdaThread> t(new LambdaThread(thread_name));
t->m_fn = fn;
t->start();
return t;
}

View File

@ -59,6 +59,7 @@ public:
Thread(const std::string &name="");
virtual ~Thread();
DISABLE_CLASS_COPY(Thread)
// Note: class cannot be moved since other references exist
/*
* Begins execution of a new thread at the pure virtual method Thread::run().

View File

@ -324,13 +324,8 @@ std::string TestBase::getTestTempDirectory()
if (!m_test_dir.empty())
return m_test_dir;
char buf[32];
porting::mt_snprintf(buf, sizeof(buf), "%08X", myrand());
m_test_dir = fs::TempPath() + DIR_DELIM "mttest_" + buf;
if (!fs::CreateDir(m_test_dir))
UASSERT(false);
m_test_dir = fs::CreateTempDir();
UASSERT(!m_test_dir.empty());
return m_test_dir;
}