mirror of https://github.com/minetest/minetest.git
Merge branch 'master' into doc-refactor-2
This commit is contained in:
commit
14cbce2303
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
uniform vec4 emissiveColor;
|
||||
uniform lowp vec4 emissiveColor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 _)
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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().
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue