master #7
0
.editorconfig
Executable file → Normal file
5
.github/workflows/linux.yml
vendored
@ -73,7 +73,10 @@ jobs:
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
./bin/minetest --run-unittests
|
||||
mkdir nowrite
|
||||
chmod a-w nowrite
|
||||
cd nowrite
|
||||
../bin/minetest --run-unittests
|
||||
|
||||
# Older clang version (should be close to our minimum supported version)
|
||||
clang_7:
|
||||
|
13
.github/workflows/windows.yml
vendored
@ -74,7 +74,7 @@ jobs:
|
||||
env:
|
||||
VCPKG_VERSION: 8eb57355a4ffb410a2e94c07b4dca2dffbee8e50
|
||||
# 2023.10.19
|
||||
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry
|
||||
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry sdl2
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@ -124,6 +124,13 @@ jobs:
|
||||
- name: Build Minetest
|
||||
run: cmake --build . --config Release
|
||||
|
||||
- name: Unittests
|
||||
# need this workaround for stdout to work
|
||||
run: |
|
||||
$proc = start .\bin\Release\minetest.exe --run-unittests -NoNewWindow -Wait -PassThru
|
||||
exit $proc.ExitCode
|
||||
continue-on-error: true # FIXME!!
|
||||
|
||||
- name: CPack
|
||||
run: |
|
||||
If ($env:TYPE -eq "installer")
|
||||
@ -134,12 +141,10 @@ jobs:
|
||||
{
|
||||
cpack -G ZIP -B "$env:GITHUB_WORKSPACE\Package"
|
||||
}
|
||||
rm -r $env:GITHUB_WORKSPACE\Package\_CPack_Packages
|
||||
env:
|
||||
TYPE: ${{matrix.type}}
|
||||
|
||||
- name: Package Clean
|
||||
run: rm -r $env:GITHUB_WORKSPACE\Package\_CPack_Packages
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: msvc-${{ matrix.config.arch }}-${{ matrix.type }}
|
||||
|
116
.gitlab-ci.yml
@ -3,128 +3,14 @@
|
||||
# https://gitlab.com/minetest/minetest
|
||||
# Pipelines URL: https://gitlab.com/minetest/minetest/pipelines
|
||||
|
||||
stages:
|
||||
- build
|
||||
- package
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
|
||||
|
||||
.build_template:
|
||||
stage: build
|
||||
before_script:
|
||||
- apt-get update
|
||||
- DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential gettext git cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libleveldb-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev
|
||||
script:
|
||||
- git clone https://github.com/minetest/irrlicht lib/irrlichtmt --depth 1 -b $(cat misc/irrlichtmt_tag.txt)
|
||||
- mkdir build && cd build
|
||||
- cmake -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE ..
|
||||
- make -j $(($(nproc) + 1))
|
||||
- make install
|
||||
artifacts:
|
||||
when: on_success
|
||||
expire_in: 1h
|
||||
paths:
|
||||
- artifact/*
|
||||
|
||||
##
|
||||
## Ubuntu (prerequisite for AppImage build)
|
||||
##
|
||||
|
||||
build:ubuntu-20.04:
|
||||
extends: .build_template
|
||||
image: ubuntu:focal
|
||||
|
||||
##
|
||||
## MinGW for Windows
|
||||
##
|
||||
|
||||
.generic_win_template:
|
||||
image: ubuntu:focal
|
||||
before_script:
|
||||
- apt-get update
|
||||
- DEBIAN_FRONTEND=noninteractive apt-get install -y wget xz-utils unzip git cmake gettext
|
||||
- wget -nv http://minetest.kitsunemimi.pw/mingw-w64-${WIN_ARCH}_11.2.0_ubuntu20.04.tar.xz -O mingw.tar.xz
|
||||
- tar -xaf mingw.tar.xz -C /usr
|
||||
|
||||
.build_win_template:
|
||||
extends: .generic_win_template
|
||||
stage: build
|
||||
artifacts:
|
||||
expire_in: 90 day
|
||||
paths:
|
||||
- minetest-*-win*/*
|
||||
|
||||
build:win32:
|
||||
extends: .build_win_template
|
||||
script:
|
||||
- EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin32.sh build
|
||||
- unzip -q build/build/*.zip
|
||||
variables:
|
||||
WIN_ARCH: "i686"
|
||||
|
||||
build:win64:
|
||||
extends: .build_win_template
|
||||
script:
|
||||
- EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin64.sh build
|
||||
- unzip -q build/build/*.zip
|
||||
variables:
|
||||
WIN_ARCH: "x86_64"
|
||||
|
||||
##
|
||||
## Docker
|
||||
##
|
||||
|
||||
package:docker:
|
||||
stage: package
|
||||
image: docker:stable
|
||||
services:
|
||||
- docker:dind
|
||||
before_script:
|
||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
|
||||
script:
|
||||
- ./util/ci/docker.sh
|
||||
|
||||
##
|
||||
## Gitlab Pages (Lua API documentation)
|
||||
##
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
image: python:3.8
|
||||
before_script:
|
||||
- pip install -U -r doc/mkdocs/requirements.txt
|
||||
script:
|
||||
- cd doc/mkdocs && ./build.sh
|
||||
- ./misc/make_redirects.sh
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- master
|
||||
|
||||
##
|
||||
## AppImage
|
||||
##
|
||||
|
||||
package:appimage-client:
|
||||
stage: package
|
||||
image: appimagecrafters/appimage-builder
|
||||
needs:
|
||||
- build:ubuntu-20.04
|
||||
before_script:
|
||||
- apt-get update
|
||||
- apt-get install -y git
|
||||
# Collect files
|
||||
- mkdir AppDir
|
||||
- cp -a artifact/minetest/usr/ AppDir/usr/
|
||||
- cp -a clientmods AppDir/usr/share/minetest
|
||||
# Remove PrefersNonDefaultGPU property due to validation errors
|
||||
- sed -i '/PrefersNonDefaultGPU/d' AppDir/usr/share/applications/net.minetest.minetest.desktop
|
||||
script:
|
||||
- export VERSION=$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA
|
||||
- appimage-builder --skip-test --recipe misc/AppImageBuilder.yml
|
||||
artifacts:
|
||||
expire_in: 90 day
|
||||
paths:
|
||||
- ./*.AppImage
|
||||
|
@ -140,7 +140,7 @@ elseif(BUILD_CLIENT AND TARGET IrrlichtMt::IrrlichtMt)
|
||||
endif()
|
||||
message(STATUS "Found IrrlichtMt ${IrrlichtMt_VERSION}")
|
||||
|
||||
set(TARGET_VER_S 1.9.0mt13)
|
||||
set(TARGET_VER_S 1.9.0mt14)
|
||||
string(REPLACE "mt" "." TARGET_VER ${TARGET_VER_S})
|
||||
if(IrrlichtMt_VERSION VERSION_LESS ${TARGET_VER})
|
||||
message(FATAL_ERROR "At least IrrlichtMt ${TARGET_VER_S} is required to build")
|
||||
|
@ -25,11 +25,11 @@ Table of Contents
|
||||
|
||||
Further documentation
|
||||
----------------------
|
||||
- Website: https://minetest.net/
|
||||
- Website: https://www.minetest.net/
|
||||
- Wiki: https://wiki.minetest.net/
|
||||
- Developer wiki: https://dev.minetest.net/
|
||||
- Forum: https://forum.minetest.net/
|
||||
- GitHub: https://github.com/minetest/minetest/
|
||||
- [Developer documentation](doc/developing/)
|
||||
- [doc/](doc/) directory of source distribution
|
||||
|
||||
Default controls
|
||||
|
@ -85,6 +85,17 @@ public class GameActivity extends NativeActivity {
|
||||
makeFullScreen();
|
||||
}
|
||||
|
||||
private native void saveSettings();
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
// Avoid losing setting changes in case the app is onDestroy()ed later.
|
||||
// Saving stuff in onStop() is recommended in the Android activity
|
||||
// lifecycle documentation.
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Ignore the back press so Minetest can handle it
|
||||
|
@ -20,23 +20,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
package net.minetest.minetest;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import static net.minetest.minetest.UnzipService.*;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
public static final String NOTIFICATION_CHANNEL_ID = "Minetest channel";
|
||||
|
||||
private final static int versionCode = BuildConfig.VERSION_CODE;
|
||||
private static final String SETTINGS = "MinetestSettings";
|
||||
private static final String TAG_VERSION_CODE = "versionCode";
|
||||
@ -81,12 +87,18 @@ public class MainActivity extends AppCompatActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
IntentFilter filter = new IntentFilter(ACTION_UPDATE);
|
||||
registerReceiver(myReceiver, filter);
|
||||
|
||||
mProgressBar = findViewById(R.id.progressBar);
|
||||
mTextView = findViewById(R.id.textView);
|
||||
sharedPreferences = getSharedPreferences(SETTINGS, Context.MODE_PRIVATE);
|
||||
|
||||
checkAppVersion();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
createNotificationChannel();
|
||||
}
|
||||
|
||||
private void checkAppVersion() {
|
||||
@ -114,6 +126,28 @@ public class MainActivity extends AppCompatActivity {
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private void createNotificationChannel() {
|
||||
NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (notifyManager == null)
|
||||
return;
|
||||
|
||||
NotificationChannel notifyChannel = new NotificationChannel(
|
||||
NOTIFICATION_CHANNEL_ID,
|
||||
getString(R.string.notification_channel_name),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
);
|
||||
notifyChannel.setDescription(getString(R.string.notification_channel_description));
|
||||
// Configure the notification channel without sound set
|
||||
notifyChannel.setSound(null, null);
|
||||
notifyChannel.enableLights(false);
|
||||
notifyChannel.enableVibration(false);
|
||||
|
||||
// It is fine to always create the notification channel because creating a channel
|
||||
// with the same ID is the same as overriding it (only its name and description).
|
||||
notifyManager.createNotificationChannel(notifyChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Prevent abrupt interruption when copy game files from assets
|
||||
|
@ -22,7 +22,6 @@ package net.minetest.minetest;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
@ -58,9 +57,11 @@ public class UnzipService extends IntentService {
|
||||
private String failureMessage;
|
||||
|
||||
private static boolean isRunning = false;
|
||||
|
||||
public static synchronized boolean getIsRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
private static synchronized void setIsRunning(boolean v) {
|
||||
isRunning = v;
|
||||
}
|
||||
@ -99,28 +100,13 @@ public class UnzipService extends IntentService {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Notification.Builder createNotification() {
|
||||
String name = "net.minetest.minetest";
|
||||
String channelId = "Minetest channel";
|
||||
String description = "notifications from Minetest";
|
||||
Notification.Builder builder;
|
||||
if (mNotifyManager == null)
|
||||
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
int importance = NotificationManager.IMPORTANCE_LOW;
|
||||
NotificationChannel mChannel = null;
|
||||
if (mNotifyManager != null)
|
||||
mChannel = mNotifyManager.getNotificationChannel(channelId);
|
||||
if (mChannel == null) {
|
||||
mChannel = new NotificationChannel(channelId, name, importance);
|
||||
mChannel.setDescription(description);
|
||||
// Configure the notification channel, NO SOUND
|
||||
mChannel.setSound(null, null);
|
||||
mChannel.enableLights(false);
|
||||
mChannel.enableVibration(false);
|
||||
mNotifyManager.createNotificationChannel(mChannel);
|
||||
}
|
||||
builder = new Notification.Builder(this, channelId);
|
||||
builder = new Notification.Builder(this, MainActivity.NOTIFICATION_CHANNEL_ID);
|
||||
} else {
|
||||
builder = new Notification.Builder(this);
|
||||
}
|
||||
@ -135,9 +121,9 @@ public class UnzipService extends IntentService {
|
||||
PendingIntent intent = PendingIntent.getActivity(this, 0,
|
||||
notificationIntent, pendingIntentFlag);
|
||||
|
||||
builder.setContentTitle(getString(R.string.notification_title))
|
||||
builder.setContentTitle(getString(R.string.unzip_notification_title))
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setContentText(getString(R.string.notification_description))
|
||||
.setContentText(getString(R.string.unzip_notification_description))
|
||||
.setContentIntent(intent)
|
||||
.setOngoing(true)
|
||||
.setProgress(0, 0, true);
|
||||
@ -198,7 +184,7 @@ public class UnzipService extends IntentService {
|
||||
}
|
||||
}
|
||||
|
||||
private void publishProgress(@Nullable Notification.Builder notificationBuilder, @StringRes int message, int progress) {
|
||||
private void publishProgress(@Nullable Notification.Builder notificationBuilder, @StringRes int message, int progress) {
|
||||
Intent intentUpdate = new Intent(ACTION_UPDATE);
|
||||
intentUpdate.putExtra(ACTION_PROGRESS, progress);
|
||||
intentUpdate.putExtra(ACTION_PROGRESS_MESSAGE, message);
|
||||
|
@ -2,7 +2,9 @@
|
||||
<resources>
|
||||
<string name="label">Minetest</string>
|
||||
<string name="loading">Loading…</string>
|
||||
<string name="notification_title">Loading Minetest</string>
|
||||
<string name="notification_description">Less than 1 minute…</string>
|
||||
<string name="notification_channel_name">General notification</string>
|
||||
<string name="notification_channel_description">Notifications from Minetest</string>
|
||||
<string name="unzip_notification_title">Loading Minetest</string>
|
||||
<string name="unzip_notification_description">Less than 1 minute…</string>
|
||||
<string name="ime_dialog_done">Done</string>
|
||||
</resources>
|
||||
|
@ -1,4 +1,116 @@
|
||||
local jobs = {}
|
||||
-- This is an implementation of a job sheduling mechanism. It guarantees that
|
||||
-- coexisting jobs will execute primarily in order of least expiry, and
|
||||
-- secondarily in order of first registration.
|
||||
|
||||
-- These functions implement an intrusive singly linked list of one or more
|
||||
-- elements where the first element has a pointer to the last. The next pointer
|
||||
-- is stored with key list_next. The pointer to the last is with key list_end.
|
||||
|
||||
local function list_init(first)
|
||||
first.list_end = first
|
||||
end
|
||||
|
||||
local function list_append(first, append)
|
||||
first.list_end.list_next = append
|
||||
first.list_end = append
|
||||
end
|
||||
|
||||
local function list_append_list(first, first_append)
|
||||
first.list_end.list_next = first_append
|
||||
first.list_end = first_append.list_end
|
||||
end
|
||||
|
||||
-- The jobs are stored in a map from expiration times to linked lists of jobs
|
||||
-- as above. The expiration times are also stored in an array representing a
|
||||
-- binary min heap, which is a particular arrangement of binary tree. A parent
|
||||
-- at index i has children at indices i*2 and i*2+1. Out-of-bounds indices
|
||||
-- represent nonexistent children. A parent is never greater than its children.
|
||||
-- This structure means that, if there is at least one job, the next expiration
|
||||
-- time is the first item in the array.
|
||||
|
||||
-- Push element on a binary min-heap,
|
||||
-- "bubbling up" the element by swapping with larger parents.
|
||||
local function heap_push(heap, element)
|
||||
local index = #heap + 1
|
||||
while index > 1 do
|
||||
local parent_index = math.floor(index / 2)
|
||||
local parent = heap[parent_index]
|
||||
if element < parent then
|
||||
heap[index] = parent
|
||||
index = parent_index
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
heap[index] = element
|
||||
end
|
||||
|
||||
-- Pop smallest element from the heap,
|
||||
-- "sinking down" the last leaf on the last layer of the heap
|
||||
-- by swapping with the smaller child.
|
||||
local function heap_pop(heap)
|
||||
local removed_element = heap[1]
|
||||
local length = #heap
|
||||
local element = heap[length]
|
||||
heap[length] = nil
|
||||
length = length - 1
|
||||
if length > 0 then
|
||||
local index = 1
|
||||
while true do
|
||||
local old_index = index
|
||||
local smaller_element = element
|
||||
local left_index = index * 2
|
||||
local right_index = index * 2 + 1
|
||||
if left_index <= length then
|
||||
local left_element = heap[left_index]
|
||||
if left_element < smaller_element then
|
||||
index = left_index
|
||||
smaller_element = left_element
|
||||
end
|
||||
end
|
||||
if right_index <= length then
|
||||
if heap[right_index] < smaller_element then
|
||||
index = right_index
|
||||
end
|
||||
end
|
||||
if old_index ~= index then
|
||||
heap[old_index] = heap[index]
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
heap[index] = element
|
||||
end
|
||||
return removed_element
|
||||
end
|
||||
|
||||
local job_map = {}
|
||||
local expiries = {}
|
||||
|
||||
-- Adds an individual job with the given expiry.
|
||||
-- The worst-case complexity is O(log n), where n is the number of distinct
|
||||
-- expiration times.
|
||||
local function add_job(expiry, job)
|
||||
local list = job_map[expiry]
|
||||
if list then
|
||||
list_append(list, job)
|
||||
else
|
||||
list_init(job)
|
||||
job_map[expiry] = job
|
||||
heap_push(expiries, expiry)
|
||||
end
|
||||
end
|
||||
|
||||
-- Removes the next expiring jobs and returns the linked list of them.
|
||||
-- The worst-case complexity is O(log n), where n is the number of distinct
|
||||
-- expiration times.
|
||||
local function remove_first_jobs()
|
||||
local removed_expiry = heap_pop(expiries)
|
||||
local removed = job_map[removed_expiry]
|
||||
job_map[removed_expiry] = nil
|
||||
return removed
|
||||
end
|
||||
|
||||
local time = 0.0
|
||||
local time_next = math.huge
|
||||
|
||||
@ -9,42 +121,54 @@ core.register_globalstep(function(dtime)
|
||||
return
|
||||
end
|
||||
|
||||
time_next = math.huge
|
||||
-- Remove the expired jobs.
|
||||
local expired = remove_first_jobs()
|
||||
|
||||
-- Iterate backwards so that we miss any new timers added by
|
||||
-- a timer callback.
|
||||
for i = #jobs, 1, -1 do
|
||||
local job = jobs[i]
|
||||
if time >= job.expire then
|
||||
core.set_last_run_mod(job.mod_origin)
|
||||
job.func(unpack(job.arg))
|
||||
local jobs_l = #jobs
|
||||
jobs[i] = jobs[jobs_l]
|
||||
jobs[jobs_l] = nil
|
||||
elseif job.expire < time_next then
|
||||
time_next = job.expire
|
||||
-- Remove other expired jobs and append them to the list.
|
||||
while true do
|
||||
time_next = expiries[1] or math.huge
|
||||
if time_next > time then
|
||||
break
|
||||
end
|
||||
list_append_list(expired, remove_first_jobs())
|
||||
end
|
||||
|
||||
-- Run the callbacks afterward to prevent infinite loops with core.after(0, ...).
|
||||
local last_expired = expired.list_end
|
||||
while true do
|
||||
core.set_last_run_mod(expired.mod_origin)
|
||||
expired.func(unpack(expired.args, 1, expired.args.n))
|
||||
if expired == last_expired then
|
||||
break
|
||||
end
|
||||
expired = expired.list_next
|
||||
end
|
||||
end)
|
||||
|
||||
function core.after(after, func, ...)
|
||||
assert(tonumber(after) and type(func) == "function",
|
||||
"Invalid minetest.after invocation")
|
||||
local expire = time + after
|
||||
local new_job = {
|
||||
func = func,
|
||||
expire = expire,
|
||||
arg = {...},
|
||||
mod_origin = core.get_last_run_mod(),
|
||||
}
|
||||
local job_metatable = {__index = {}}
|
||||
|
||||
jobs[#jobs + 1] = new_job
|
||||
time_next = math.min(time_next, expire)
|
||||
|
||||
return {
|
||||
cancel = function()
|
||||
new_job.func = function() end
|
||||
new_job.args = {}
|
||||
end
|
||||
}
|
||||
local function dummy_func() end
|
||||
function job_metatable.__index:cancel()
|
||||
self.func = dummy_func
|
||||
self.args = {n = 0}
|
||||
end
|
||||
|
||||
function core.after(after, func, ...)
|
||||
assert(tonumber(after) and not core.is_nan(after) and type(func) == "function",
|
||||
"Invalid minetest.after invocation")
|
||||
|
||||
local new_job = {
|
||||
mod_origin = core.get_last_run_mod(),
|
||||
func = func,
|
||||
args = {
|
||||
n = select("#", ...),
|
||||
...
|
||||
},
|
||||
}
|
||||
|
||||
local expiry = time + after
|
||||
add_job(expiry, new_job)
|
||||
time_next = math.min(time_next, expiry)
|
||||
|
||||
return setmetatable(new_job, job_metatable)
|
||||
end
|
||||
|
@ -144,6 +144,8 @@ local wallmounted_to_dir = {
|
||||
vector.new(-1, 0, 0),
|
||||
vector.new( 0, 0, 1),
|
||||
vector.new( 0, 0, -1),
|
||||
vector.new( 0, 1, 0),
|
||||
vector.new( 0, -1, 0),
|
||||
}
|
||||
function core.wallmounted_to_dir(wallmounted)
|
||||
return wallmounted_to_dir[wallmounted % 8]
|
||||
|
113
builtin/common/tests/after_spec.lua
Normal file
@ -0,0 +1,113 @@
|
||||
_G.core = {}
|
||||
_G.vector = {metatable = {}}
|
||||
|
||||
dofile("builtin/common/vector.lua")
|
||||
dofile("builtin/common/misc_helpers.lua")
|
||||
|
||||
function core.get_last_run_mod() return "*test*" end
|
||||
function core.set_last_run_mod() end
|
||||
|
||||
local do_step
|
||||
function core.register_globalstep(func)
|
||||
do_step = func
|
||||
end
|
||||
|
||||
dofile("builtin/common/after.lua")
|
||||
|
||||
describe("after", function()
|
||||
it("executes callbacks when expected", function()
|
||||
local result = ""
|
||||
core.after(0, function()
|
||||
result = result .. "a"
|
||||
end)
|
||||
core.after(1, function()
|
||||
result = result .. "b"
|
||||
end)
|
||||
core.after(1, function()
|
||||
result = result .. "c"
|
||||
end)
|
||||
core.after(2, function()
|
||||
result = result .. "d"
|
||||
end)
|
||||
local cancel = core.after(2, function()
|
||||
result = result .. "e"
|
||||
end)
|
||||
do_step(0)
|
||||
assert.same("a", result)
|
||||
|
||||
do_step(1)
|
||||
assert.same("abc", result)
|
||||
|
||||
core.after(2, function()
|
||||
result = result .. "f"
|
||||
end)
|
||||
core.after(1, function()
|
||||
result = result .. "g"
|
||||
end)
|
||||
core.after(-1, function()
|
||||
result = result .. "h"
|
||||
end)
|
||||
cancel:cancel()
|
||||
do_step(1)
|
||||
assert.same("abchdg", result)
|
||||
|
||||
do_step(1)
|
||||
assert.same("abchdgf", result)
|
||||
end)
|
||||
|
||||
it("defers jobs with delay 0", function()
|
||||
local result = ""
|
||||
core.after(0, function()
|
||||
core.after(0, function()
|
||||
result = result .. "b"
|
||||
end)
|
||||
result = result .. "a"
|
||||
end)
|
||||
do_step(1)
|
||||
assert.same("a", result)
|
||||
do_step(1)
|
||||
assert.same("ab", result)
|
||||
end)
|
||||
|
||||
it("passes arguments", function()
|
||||
core.after(0, function(...)
|
||||
assert.same(0, select("#", ...))
|
||||
end)
|
||||
core.after(0, function(...)
|
||||
assert.same(4, select("#", ...))
|
||||
assert.same(1, (select(1, ...)))
|
||||
assert.same(nil, (select(2, ...)))
|
||||
assert.same("a", (select(3, ...)))
|
||||
assert.same(nil, (select(4, ...)))
|
||||
end, 1, nil, "a", nil)
|
||||
do_step(0)
|
||||
end)
|
||||
|
||||
it("rejects invalid arguments", function()
|
||||
assert.has.errors(function() core.after() end)
|
||||
assert.has.errors(function() core.after(nil, nil) end)
|
||||
assert.has.errors(function() core.after(0) end)
|
||||
assert.has.errors(function() core.after(0, nil) end)
|
||||
assert.has.errors(function() core.after(nil, function() end) end)
|
||||
assert.has.errors(function() core.after(0 / 0, function() end) end)
|
||||
end)
|
||||
|
||||
-- Make sure that the underlying heap is working correctly
|
||||
it("can be abused as a heapsort", function()
|
||||
local t = {}
|
||||
for i = 1, 1000 do
|
||||
t[i] = math.random(100)
|
||||
end
|
||||
local sorted = table.copy(t)
|
||||
table.sort(sorted)
|
||||
local i = 0
|
||||
for _, v in ipairs(t) do
|
||||
core.after(v, function()
|
||||
i = i + 1
|
||||
assert.equal(v, sorted[i])
|
||||
end)
|
||||
end
|
||||
do_step(math.max(unpack(t)))
|
||||
assert.equal(#t, i)
|
||||
end)
|
||||
end)
|
@ -92,16 +92,24 @@ core.builtin_auth_handler = {
|
||||
|
||||
core_auth.save(auth_entry)
|
||||
|
||||
-- Run grant callbacks
|
||||
for priv, _ in pairs(privileges) do
|
||||
if not prev_privs[priv] then
|
||||
for priv, value in pairs(privileges) do
|
||||
-- Warnings for improper API usage
|
||||
if value == false then
|
||||
core.log('deprecated', "`false` value given to `minetest.set_player_privs`, "..
|
||||
"this is almost certainly a bug, "..
|
||||
"granting a privilege rather than revoking it")
|
||||
elseif value ~= true then
|
||||
core.log('deprecated', "non-`true` value given to `minetest.set_player_privs`")
|
||||
end
|
||||
-- Run grant callbacks
|
||||
if prev_privs[priv] == nil then
|
||||
core.run_priv_callbacks(name, priv, nil, "grant")
|
||||
end
|
||||
end
|
||||
|
||||
-- Run revoke callbacks
|
||||
for priv, _ in pairs(prev_privs) do
|
||||
if not privileges[priv] then
|
||||
if privileges[priv] == nil then
|
||||
core.run_priv_callbacks(name, priv, nil, "revoke")
|
||||
end
|
||||
end
|
||||
@ -180,6 +188,20 @@ core.set_player_privs = auth_pass("set_privileges")
|
||||
core.remove_player_auth = auth_pass("delete_auth")
|
||||
core.auth_reload = auth_pass("reload")
|
||||
|
||||
function core.change_player_privs(name, changes)
|
||||
local privs = core.get_player_privs(name)
|
||||
for priv, change in pairs(changes) do
|
||||
if change == true then
|
||||
privs[priv] = true
|
||||
elseif change == false then
|
||||
privs[priv] = nil
|
||||
else
|
||||
error("non-bool value given to `minetest.change_player_privs`")
|
||||
end
|
||||
end
|
||||
core.set_player_privs(name, privs)
|
||||
end
|
||||
|
||||
local record_login = auth_pass("record_login")
|
||||
core.register_on_joinplayer(function(player)
|
||||
record_login(player:get_player_name())
|
||||
|
@ -150,7 +150,12 @@ core.register_entity(":__builtin:falling_node", {
|
||||
|
||||
-- Rotate entity
|
||||
if def.drawtype == "torchlike" then
|
||||
self.object:set_yaw(math.pi*0.25)
|
||||
if (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted")
|
||||
and node.param2 % 8 == 7 then
|
||||
self.object:set_yaw(-math.pi*0.25)
|
||||
else
|
||||
self.object:set_yaw(math.pi*0.25)
|
||||
end
|
||||
elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
|
||||
and (def.wield_image == "" or def.wield_image == nil))
|
||||
or def.drawtype == "signlike"
|
||||
@ -190,6 +195,10 @@ core.register_entity(":__builtin:falling_node", {
|
||||
pitch, yaw = 0, -math.pi/2
|
||||
elseif rot == 4 then
|
||||
pitch, yaw = 0, math.pi
|
||||
elseif rot == 6 then
|
||||
pitch, yaw = math.pi/2, 0
|
||||
elseif rot == 7 then
|
||||
pitch, yaw = -math.pi/2, math.pi
|
||||
end
|
||||
else
|
||||
if rot == 1 then
|
||||
@ -202,6 +211,10 @@ core.register_entity(":__builtin:falling_node", {
|
||||
pitch, yaw = math.pi/2, math.pi
|
||||
elseif rot == 5 then
|
||||
pitch, yaw = math.pi/2, 0
|
||||
elseif rot == 6 then
|
||||
pitch, yaw = math.pi, -math.pi/2
|
||||
elseif rot == 7 then
|
||||
pitch, yaw = 0, -math.pi/2
|
||||
end
|
||||
end
|
||||
if def.drawtype == "signlike" then
|
||||
@ -210,10 +223,20 @@ core.register_entity(":__builtin:falling_node", {
|
||||
yaw = yaw + math.pi/2
|
||||
elseif rot == 1 then
|
||||
yaw = yaw - math.pi/2
|
||||
elseif rot == 6 then
|
||||
yaw = yaw - math.pi/2
|
||||
pitch = pitch + math.pi
|
||||
elseif rot == 7 then
|
||||
yaw = yaw + math.pi/2
|
||||
pitch = pitch + math.pi
|
||||
end
|
||||
elseif def.drawtype == "mesh" or def.drawtype == "normal" or def.drawtype == "nodebox" then
|
||||
if rot >= 0 and rot <= 1 then
|
||||
if rot == 0 or rot == 1 then
|
||||
roll = roll + math.pi
|
||||
elseif rot == 6 or rot == 7 then
|
||||
if def.drawtype ~= "normal" then
|
||||
roll = roll - math.pi/2
|
||||
end
|
||||
else
|
||||
yaw = yaw + math.pi
|
||||
end
|
||||
|
@ -30,6 +30,11 @@ core.features = {
|
||||
sound_params_start_time = true,
|
||||
physics_overrides_v2 = true,
|
||||
hud_def_type_field = true,
|
||||
random_state_restore = true,
|
||||
after_order_expiry_registration = true,
|
||||
wallmounted_rotate = true,
|
||||
item_specific_pointabilities = true,
|
||||
blocking_pointability_type = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
@ -202,7 +202,40 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
|
||||
elseif (def.paramtype2 == "wallmounted" or
|
||||
def.paramtype2 == "colorwallmounted") and not param2 then
|
||||
local dir = vector.subtract(under, above)
|
||||
-- If you change this code, also change src/client/game.cpp
|
||||
newnode.param2 = core.dir_to_wallmounted(dir)
|
||||
if def.wallmounted_rotate_vertical and
|
||||
(newnode.param2 == 0 or newnode.param2 == 1) then
|
||||
local placer_pos = placer and placer:get_pos()
|
||||
if placer_pos then
|
||||
local pdir = {
|
||||
x = above.x - placer_pos.x,
|
||||
y = dir.y,
|
||||
z = above.z - placer_pos.z
|
||||
}
|
||||
local rotate = false
|
||||
if def.drawtype == "torchlike" then
|
||||
if not ((pdir.x < 0 and pdir.z > 0) or
|
||||
(pdir.x > 0 and pdir.z < 0)) then
|
||||
rotate = true
|
||||
end
|
||||
if pdir.y > 0 then
|
||||
rotate = not rotate
|
||||
end
|
||||
elseif def.drawtype == "signlike" then
|
||||
if math.abs(pdir.x) < math.abs(pdir.z) then
|
||||
rotate = true
|
||||
end
|
||||
else
|
||||
if math.abs(pdir.x) > math.abs(pdir.z) then
|
||||
rotate = true
|
||||
end
|
||||
end
|
||||
if rotate then
|
||||
newnode.param2 = newnode.param2 + 6
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Calculate the direction for furnaces and chests and stuff
|
||||
elseif (def.paramtype2 == "facedir" or
|
||||
def.paramtype2 == "colorfacedir" or
|
||||
|
246
builtin/locale/__builtin.eo.tr
Normal file
@ -0,0 +1,246 @@
|
||||
# textdomain: __builtin
|
||||
Invalid parameters (see /help @1).=Nevalidaj parametroj (kontrolu /help @1)
|
||||
Too many arguments, try using just /help <command>=Tro da parametroj, eble provu /help <ordono>
|
||||
Available commands: @1=Nunaj ordonoj: @1
|
||||
Use '/help <cmd>' to get more information, or '/help all' to list everything.=Uzu «/help <ordono>» por specifa informo, aŭ «/help all» por listigi ĉion.
|
||||
Available commands:=Nunaj ordonoj:
|
||||
Command not available: @1=Ordono neuzebla: @1
|
||||
[all | privs | <cmd>] [-t]=[all | privs | <ordono>]
|
||||
Get help for commands or list privileges (-t: output in chat)=Listigi helpon pri ordonoj («all» aŭ <ordono>) aŭ rajtoj («privs») (kun -t: presu en babilejo)
|
||||
Available privileges:=Nunaj rajtoj:
|
||||
Command=Ordono
|
||||
Parameters=Parametroj
|
||||
For more information, click on any entry in the list.=Por pliaj informoj, klaku ajnan listeron.
|
||||
Double-click to copy the entry to the chat history.=Dufoje-klaku por kopii listeron al la babilejo.
|
||||
Command: @1 @2=Ordono: @1 @2
|
||||
Available commands: (see also: /help <cmd>)=Nunaj ordonoj: (vidu ankaŭ: /help <ordono>)
|
||||
Close=Fermi
|
||||
Privilege=Rajto
|
||||
Description=Priskribo
|
||||
Empty command.=Malplena ordono.
|
||||
Invalid command: @1=Nevalida ordono: @1
|
||||
Invalid command usage.=Nevalida ordonouzo.
|
||||
(@1 s)= (@1 s)
|
||||
Command execution took @1 s=Ruliĝo de ordono postulis @1 s
|
||||
You don't have permission to run this command (missing privileges: @1).=Vi ne rajtas uzi tiun ĉi ordonon (mankataj rajtoj: @1)
|
||||
Unable to get position of player @1.=Ne povis akiri pozicion de ludanto @1.
|
||||
Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Nevalida loko-formo. Atendis: (x1,y1,z1) (x2,y2,z2)
|
||||
<action>=<ago>
|
||||
Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pizza')=Roli agon en la babilejo (ekz., «/me mendas picon» montras «<ludanto> mendas picon»)
|
||||
Show the name of the server owner=Montri nomon de la serviladministranto
|
||||
The administrator of this server is @1.=La adminstranto de tiu ĉi servilo estas @1.
|
||||
There's no administrator named in the config file.=Estas neniu agordita administranto en la agordodosiero.
|
||||
@1 does not have any privileges.=@1 havas neniun rajton.
|
||||
Privileges of @1: @2=Rajtoj de @1: @2
|
||||
[<name>]=[<nomo>]
|
||||
Show privileges of yourself or another player=Montri rajtojn de vi aŭ alia ludanto
|
||||
Player @1 does not exist.=Ludanto @1 ne ekzistas.
|
||||
<privilege>=<rajto>
|
||||
Return list of all online players with privilege=Listi ĉeretan ludanton kun specifa rajto
|
||||
Invalid parameters (see /help haspriv).=Nevalidaj parametroj (vidu /help haspriv).
|
||||
Unknown privilege!=Nekonata rajto!
|
||||
No online player has the "@1" privilege.=Neniu ĉeretulo havas la rajton «@1».
|
||||
Players online with the "@1" privilege: @2=Ĉeretuloj kun la rajto «@1»: @2
|
||||
Your privileges are insufficient.=Viaj rajtoj ne sufiĉas.
|
||||
Your privileges are insufficient. '@1' only allows you to grant: @2=Viaj rajtoj ne sufiĉas. «@1» sole lasas vin doni: @2
|
||||
Unknown privilege: @1=Nekonata rajto: @1
|
||||
@1 granted you privileges: @2=@1 donis al vi rajtojn: @2
|
||||
<name> (<privilege> [, <privilege2> [<...>]] | all)=<nomo> (<rajto> [, <rajto2> [<...>]] | all)
|
||||
Give privileges to player=Doni rajtojn al ludanto, aŭ aparte, aŭ ĉiun kune («all»)
|
||||
Invalid parameters (see /help grant).=Nevalidaj parametroj (vidu /help grant).
|
||||
<privilege> [, <privilege2> [<...>]] | all=<rajto> [, <rajto2> [<...>]] | all
|
||||
Grant privileges to yourself=Doni rajtojn al vi mem, aŭ aparte, aŭ ĉiun kune («all»)
|
||||
Invalid parameters (see /help grantme).=Nevalidaj parametroj (vidu /help grantme)
|
||||
Your privileges are insufficient. '@1' only allows you to revoke: @2=Viaj rajtoj ne sufiĉas. «@1» sole lasas vin repreni: @2
|
||||
Note: Cannot revoke in singleplayer: @1=Rimarko: Neeblas repreni rajton sole: @1
|
||||
Note: Cannot revoke from admin: @1=Rimarko: Neeblas repreni rajnton de administranto: @1
|
||||
No privileges were revoked.=Neniu rajto reprenita.
|
||||
@1 revoked privileges from you: @2=@1 reprenis rajtojn de vi: @2
|
||||
Remove privileges from player=Repreni rajtojn de ludanto, aŭ aparte, aŭ ĉiun kune («all»)
|
||||
Invalid parameters (see /help revoke).=Nevalidaj parametroj (vidu /help revoke)
|
||||
Revoke privileges from yourself=Repreni rajtojn de vi mem, aŭ aparte, aŭ ĉiun kune («all»)
|
||||
Invalid parameters (see /help revokeme).=Nevalidaj parametroj (vidu /help revokeme).
|
||||
<name> <password>=<nomo> <pasvorto>
|
||||
Set player's password (sent unencrypted, thus insecure)=Agordi pasvorton de ludanto (sendute senĉifre, kaj tiel malsekure)
|
||||
Name field required.=Nomo bezonata.
|
||||
Your password was cleared by @1.=Via pasvorto forviŝiĝis de @1.
|
||||
Password of player "@1" cleared.=Pasvorto de ludanto «@1» forviŝita.
|
||||
Your password was set by @1.=Via pasvorto agordiĝis de @1.
|
||||
Password of player "@1" set.=Pasvorto de ludanto «@1» agordita.
|
||||
<name>=<nomo>
|
||||
Set empty password for a player=Forviŝi pasvorton de ludanto
|
||||
Reload authentication data=Reenlegi aŭtentigajn datumojn
|
||||
Done.=Finite.
|
||||
Failed.=Malsukcese..
|
||||
Remove a player's data=Forviŝi datumojn de ludanto
|
||||
Player "@1" removed.=Ludanto «@1» forigita.
|
||||
No such player "@1" to remove.=Neniu ekzistanta ludanto «@1» forigebla.
|
||||
Player "@1" is connected, cannot remove.=Ludanto «@1» ĉeretas, do ne forigeblas.
|
||||
Unhandled remove_player return code @1.=Netraktata remove_player redonkodo @1.
|
||||
Cannot teleport out of map bounds!=Neeblas teleporti ekstermonden!
|
||||
Cannot get player with name @1.=Neeblas trovi ludanton nomitan «@1».
|
||||
Cannot teleport, @1 is attached to an object!=Ne povas teleporti @1, ĝi estas ligita al objekto!
|
||||
Teleporting @1 to @2.=Teleportante @1 al @2.
|
||||
One does not teleport to oneself.=Oni kutimas ne teleportu al si mem.
|
||||
Cannot get teleportee with name @1.=Ne trovis alteleportaton nomitan @1.
|
||||
Cannot get target player with name @1.=Ne trovis celatan ludanton nomitan @1.
|
||||
Teleporting @1 to @2 at @3.=Teleportante @1 al @2 ĉe @3.
|
||||
<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>=<X>,<Y>,<Z> | <al_nomo> | <nomo> <X>,<Y>,<Z> | <nomo> <al_nomo>
|
||||
Teleport to position or player=Teleportiĝi al pozicio aŭ ludanto
|
||||
You don't have permission to teleport other players (missing privilege: @1).=Vi ne rajtas teleporti aliajn ludantojn (mankas rajto: @1).
|
||||
([-n] <name> <value>) | <name>=([-n] <nomo> <valoro>) | <nomo>
|
||||
Set or read server configuration setting=Agordi aŭ vidi servilan agordon
|
||||
Failed. Cannot modify secure settings. Edit the settings file manually.=Malsukcese. Neeblas redakti sekurajn agordojn. Redaktu la agordodosieron permane.
|
||||
Failed. Use '/set -n <name> <value>' to create a new setting.=Malsukcese. Uzu «/set -n <nomo> <valoro>» por krei novan agordon.
|
||||
@1 @= @2=@1 @= @2
|
||||
<not set>=<ne agordita>
|
||||
Invalid parameters (see /help set).=Nevalidaj parametroj (vidu /help set).
|
||||
Finished emerging @1 blocks in @2ms.=Finenlegis @1 monderojn dum @2ms.
|
||||
emergeblocks update: @1/@2 blocks emerged (@3%)=emergeblocks ĝisdatigo: @1/@2 monderoj enlegitaj (@3%)
|
||||
(here [<radius>]) | (<pos1> <pos2>)=(here [<radius>]) | (<pos1> <pos2>)
|
||||
Load (or, if nonexistent, generate) map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Enlegi (aŭ, laŭnecese, krei) mondopecojn inter la pozicioj poz1 kaj pos2 (<poz1> kaj <poz2> devas esti inter krampoj)
|
||||
Started emerge of area ranging from @1 to @2.=Ekenlegis mondpecojn inter @1 kaj @2.
|
||||
Delete map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Forigi mondpecojn inter la pozicioj poz1 kaj poz2 (<poz1> kaj <poz2> devas esti inter krampoj)
|
||||
Successfully cleared area ranging from @1 to @2.=Sukcese forigis mondpecojn inter @1 kaj @2.
|
||||
Failed to clear one or more blocks in area.=Malsukcesis forigi unu aŭ pli da mondpecoj.
|
||||
Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in parentheses)=Reŝarĝas lumojn inter la pozicioj poz1 kaj poz2 (<poz1> kaj <poz2> devas esti inter krampoj)
|
||||
Successfully reset light in the area ranging from @1 to @2.=Sukcesis reŝarĝi lumojn inter @1 kaj @2.
|
||||
Failed to load one or more blocks in area.=Malsukcesis enlegante unu aŭ pli da monderoj.
|
||||
List mods installed on the server=Listigi modifaĵojn instalitajn de la servilo.
|
||||
No mods installed.=Neniu modifaĵ instalita.
|
||||
Cannot give an empty item.=Neeblas doni neniun portaĵon.
|
||||
Cannot give an unknown item.=Neeblas doni nekonatan portaĵon.
|
||||
Giving 'ignore' is not allowed.=Doni «ignore» estas ne permesita.
|
||||
@1 is not a known player.=@1 ne estas konata ludanto.
|
||||
@1 partially added to inventory.=@1 parte enmetiĝis al portaĵujon.
|
||||
@1 could not be added to inventory.=@1 ne enmetiĝis al portaĵujon.
|
||||
@1 added to inventory.=@1 enmetiĝis al portaĵujon.
|
||||
@1 partially added to inventory of @2.=@1 parte enmetiĝis al portaĵujon de @2.
|
||||
@1 could not be added to inventory of @2.=@1 ne enmetiĝis al portaĵujon de @2.
|
||||
@1 added to inventory of @2.=@1 enmetiĝis al portaĵujon de @2.
|
||||
<name> <ItemString> [<count> [<wear>]]=<nomo> <PortaĵNomo> [<kvanto> <portu>]]
|
||||
Give item to player=Doni portaĵon al ludanto
|
||||
Name and ItemString required.=Nomo kaj PortaĵNomo postualtaj.
|
||||
<ItemString> [<count> [<wear>]]=<PortaĵNomo> [<kvanto> [<portu>]]
|
||||
Give item to yourself=Doni portaĵon al vi mem.
|
||||
ItemString required.=PortaĵNomo postulata.
|
||||
<EntityName> [<X>,<Y>,<Z>]=<EstaĵoNomo> [<X>, <Y>, <Z>]
|
||||
Spawn entity at given (or your) position=Estigi estaĵon ĉe la donita (aŭ la via) pozicio
|
||||
EntityName required.=EstaĵNomo postulata.
|
||||
Unable to spawn entity, player is nil.=Ne povis estigi estaĵon, ĉar ludanto estas nil.
|
||||
Cannot spawn an unknown entity.=Neeblas estigi nekonatan estaĵon.
|
||||
Invalid parameters (@1).=Nevalidaj parametroj (@1).
|
||||
@1 spawned.=@1 naskiĝis.
|
||||
@1 failed to spawn.=@1 ne naskiĝis.
|
||||
Destroy item in hand=Detrui portaĵon enmanan
|
||||
Unable to pulverize, no player.=Ne povis detrui, neniu ludanto.
|
||||
Unable to pulverize, no item in hand.=Ne povis detrui, ĉar nenio estas tenata.
|
||||
An item was pulverized.=Portaĵo detruiĝis.
|
||||
[<range>] [<seconds>] [<limit>]=[<intertempo>] [<sekundoj>] [<limo>]
|
||||
Check who last touched a node or a node near it within the time specified by <seconds>. Default: range @= 0, seconds @= 86400 @= 24h, limit @= 5. Set <seconds> to inf for no time limit=Kontroli kiu lastafoje tuŝis monderon aŭ monderon proksiman al ĝi dum
|
||||
Rollback functions are disabled.=Malfaraj funkcioj estas malŝaltitaj.
|
||||
That limit is too high!=Tiu limo troaltas!
|
||||
Checking @1 ...=Kontrolas @1…
|
||||
Nobody has touched the specified location in @1 seconds.=Neniu tuŝis tiun lokon dum @1 sekundoj.
|
||||
@1 @2 @3 -> @4 @5 seconds ago.=@1 @2 @3 -> @4 @5 sekundoj antaŭe.
|
||||
Punch a node (range@=@1, seconds@=@2, limit@=@3).=Frapi monderon (intertempo@=@1, sekundoj@=@2, limo@=@3).
|
||||
(<name> [<seconds>]) | (:<actor> [<seconds>])=(<nomo> [<sekundoj>]) | (:<aganto> [<sekundoj>])
|
||||
Revert actions of a player. Default for <seconds> is 60. Set <seconds> to inf for no time limit=Malfari agojn de ludanto. Implicita valoro de <sekundoj> estas 60. Metu <sekundoj> kiel «inf» por neniu tempolimo
|
||||
Invalid parameters. See /help rollback and /help rollback_check.=Nevalidaj parametroj. Vidu /help rollback kaj /help rollback_check.
|
||||
Reverting actions of player '@1' since @2 seconds.=Malfaras agojn de ludanto «@1» ekde @2 sekundoj antaŭ nun.
|
||||
Reverting actions of @1 since @2 seconds.=Malfaras agojn de @1 ekde @2 sekundoj antaŭ nun.
|
||||
(log is too long to show)=(protokolo trolongas por montri)
|
||||
Reverting actions succeeded.=Sukcesis malfari agojn.
|
||||
Reverting actions FAILED.=MALsukcesis malfari agojn.
|
||||
Show server status=Montri staton de servilon.
|
||||
This command was disabled by a mod or game.=Tiun ordonon malŝaltis modifaĵo aŭ ludo.
|
||||
[<0..23>:<0..59> | <0..24000>]=[<0..23>:<0..59> | <0..24000>]
|
||||
Show or set time of day=Montri aŭ ŝanĝi la horon
|
||||
Current time is @1:@2.=Nun estas @1:@2.
|
||||
You don't have permission to run this command (missing privilege: @1).=Vi ne rajtas rulu tiun orodnon (mankata rajto: @1).
|
||||
Invalid time (must be between 0 and 24000).=Nevalida tempo (estu inter 0 kaj 24000)
|
||||
Time of day changed.=Horo ŝanĝita.
|
||||
Invalid hour (must be between 0 and 23 inclusive).=Nevalida horo (estu inter 0 kaj 23, inkluzive).
|
||||
Invalid minute (must be between 0 and 59 inclusive).=Nevalida minuto (estu inter 0 kaj 59, inkluzive).
|
||||
Show day count since world creation=Montri pasitajn tagojn ekde mondokreo
|
||||
Current day is @1.=Nuna tago estas @1.
|
||||
[<delay_in_seconds> | -1] [-r] [<message>]=[<prokrasto_sekunde> | -1] [-r] [<mesaĝo>]
|
||||
Shutdown server (-1 cancels a delayed shutdown, -r allows players to reconnect)=Malŝalti servilon (-1 nuligas planitan malŝalton, -r lasas ludantojn rekonektiĝi)
|
||||
Server shutting down (operator request).=Servilo malŝaltiĝas (laŭ prizorganta peto)
|
||||
Ban the IP of a player or show the ban list=Forbari la IP-adreson de ludanto, aŭ listigi forbaritojn
|
||||
The ban list is empty.=La forbaritolisto malplenas.
|
||||
Ban list: @1=Forbaritoj: @1
|
||||
You cannot ban players in singleplayer!=Vi ne povas forbari ludantojn en unuludanta reĝimo!
|
||||
Player is not online.=Ludanto ne ĉeretas.
|
||||
Failed to ban player.=Malsukcesis forbari ludanton.
|
||||
Banned @1.=Forbaris @1.
|
||||
<name> | <IP_address>=<nomo> | <IP_adreso>
|
||||
Remove IP ban belonging to a player/IP=Nuligi IP-forbaron de ludanto/IP
|
||||
Failed to unban player/IP.=Malsukcesis nuligi forbaron de ludanto/IP-adreso
|
||||
Unbanned @1.=Malforbaris @1.
|
||||
<name> [<reason>]=<nomo> [<kialo>]
|
||||
Kick a player=Elĵeti ludanton
|
||||
Failed to kick player @1.=Malsukcesis elĵeti ludanton @1.
|
||||
Kicked @1.=Elĵetis @1.
|
||||
[full | quick]=[full | quick]
|
||||
Clear all objects in world=Forigu ĉiujn lasitajn portaĵojn en la mondo
|
||||
Invalid usage, see /help clearobjects.=Nevalida uzo, vidu /help clearobjects.
|
||||
Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=Forigante ĉiun lasitan portaĵon. Tio ĉi eble postulos longan tempon. Vi eble malkonektiĝos pro tempo-elĉerpo. (de @1)
|
||||
Cleared all objects.=Forigis ĉiun lasitan portaĵon.
|
||||
<name> <message>=<nomo> <mesaĝo>
|
||||
Send a direct message to a player=Sendu rekte privatan mesaĝon al ludanto
|
||||
Invalid usage, see /help msg.=Nevalida uzo, vidu /help msg.
|
||||
The player @1 is not online.=La ludanto @1 ne ĉeretas.
|
||||
DM from @1: @2=Privata mesaĝo de @1: @2
|
||||
Message sent.=Mesaĝo sendita.
|
||||
Get the last login time of a player or yourself=Vidi la lastan salutotempon de ludanto, aŭ vi mem
|
||||
@1's last login time was @2.=Lasta salutotempo de @1 estas @2.
|
||||
@1's last login time is unknown.=Lasta salutotempo de @1 estas nesciata.
|
||||
Clear the inventory of yourself or another player=Malplenigi la portaĵujon de vi aŭ alia ludanto.
|
||||
You don't have permission to clear another player's inventory (missing privilege: @1).=Vi ne rajtas malplenigi portaĵujon de alia ludanto (mankata rajto: @1).
|
||||
@1 cleared your inventory.=@1 malplenigis vian portaĵujon.
|
||||
Cleared @1's inventory.=Malplenigis portaĵujon de @1.
|
||||
Player must be online to clear inventory!=Por malplenigi onian portaĵujon, tiu devas ĉereti!
|
||||
Players can't be killed, damage has been disabled.=Nemortigeblas ludantoj, ĉar vundado estas malŝaltita.
|
||||
Player @1 is not online.=Ludanto @1 ne ĉeretas.
|
||||
You are already dead.=Vi jam estas mortinta.
|
||||
@1 is already dead.=@1 estas mortinta.
|
||||
@1 has been killed.=@1 estas murdita.
|
||||
Kill player or yourself=Mortigi ludanton aŭ vin mem
|
||||
@1 joined the game.=@1 aliĝis la ludon.
|
||||
@1 left the game.=@1 foriris de la ludo.
|
||||
@1 left the game (timed out).=@1 foriris de la ludo (tempo-elĉerpo)
|
||||
(no description)=(neniu priskribo)
|
||||
Can interact with things and modify the world=Povas interfaci kaj redakti la mondon
|
||||
Can speak in chat=Povas paroli babileje
|
||||
Can modify basic privileges (@1)=Povas redakti bazajn rajtojn (@1)
|
||||
Can modify privileges=Povas redakti rajtojn
|
||||
Can teleport self=Povas teleporti sin
|
||||
Can teleport other players=Povas teleporti aliajn ludantojn
|
||||
Can set the time of day using /time=Povas ŝanĝi la tempon per /time
|
||||
Can do server maintenance stuff=Povas fari servilestrajn aferojn
|
||||
Can bypass node protection in the world=Povas malatenti monderajn protektojn de la mondo
|
||||
Can ban and unban players=Povas forbari kaj malforbari ludantojn
|
||||
Can kick players=Povas elĵeti ludantojn
|
||||
Can use /give and /giveme=Povas uzi /give kaj /giveme
|
||||
Can use /setpassword and /clearpassword=Povas uzi /setpassword kaj /clearpassword
|
||||
Can use fly mode=Povas ŝalti flugan reĝimon
|
||||
Can use fast mode=Povas ŝalti rapidegan reĝimon
|
||||
Can fly through solid nodes using noclip mode=Povas traflugi monderojn per trapasa reĝimo
|
||||
Can use the rollback functionality=Povas uzi malfarajn funkciojn
|
||||
Can enable wireframe=Povas ŝalti ĉirkaŭkadron
|
||||
Unknown Item=Nekonata portaĵo
|
||||
Air=Aero
|
||||
Ignore=Malatenti
|
||||
You can't place 'ignore' nodes!=Vi ne povas meti «malatentajn» monderojn!
|
||||
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filtrilo>] | dump [<filtrilo>] | save [<formo> [<filtrilo>]] | reset
|
||||
Handle the profiler and profiling data=Trakti la analizilon kaj analizajn datumojn
|
||||
Statistics written to action log.=Analizoj skribitaj al agoprotokolo.
|
||||
Statistics were reset.=Analizoj forviŝitaj.
|
||||
Usage: @1=Uzado: @1
|
||||
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Formo povas estas txt, csv, lua, json, aŭ json_pretty (struktuoj eble iam ŝanĝiĝos).
|
||||
Values below show absolute/relative times spend per server step by the instrumented function.=Valoroj subaj montras la malrelativan/relativan tempon pasigitan de la servilo je ĉiu paŝo de la funkcio.
|
||||
A total of @1 sample(s) were taken.=Sume @1 ekzemplero(j) konserviĝis.
|
||||
The output is limited to '@1'.=La eligo estas limigita al «@1».
|
||||
Saving of profile failed: @1=Konservado de profilo malsukcesis: @1
|
||||
Profile saved to @1=Profilo konservita al @1
|
@ -312,7 +312,7 @@ local function check_requirements(name, requires)
|
||||
end
|
||||
|
||||
local video_driver = core.get_active_driver()
|
||||
local shaders_support = video_driver == "opengl" or video_driver == "ogles2"
|
||||
local shaders_support = video_driver == "opengl" or video_driver == "opengl3" or video_driver == "ogles2"
|
||||
local special = {
|
||||
android = PLATFORM == "Android",
|
||||
desktop = PLATFORM ~= "Android",
|
||||
@ -608,6 +608,16 @@ local function get_formspec(dialogdata)
|
||||
end
|
||||
|
||||
|
||||
-- On Android, closing the app via the "Recents screen" won't result in a clean
|
||||
-- exit, discarding any setting changes made by the user.
|
||||
-- To avoid that, we write the settings file in more cases on Android.
|
||||
function write_settings_early()
|
||||
if PLATFORM == "Android" then
|
||||
core.settings:write()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function buttonhandler(this, fields)
|
||||
local dialogdata = this.data
|
||||
dialogdata.leftscroll = core.explode_scrollbar_event(fields.leftscroll).value or dialogdata.leftscroll
|
||||
@ -622,12 +632,15 @@ local function buttonhandler(this, fields)
|
||||
if fields.show_technical_names ~= nil then
|
||||
local value = core.is_yes(fields.show_technical_names)
|
||||
core.settings:set_bool("show_technical_names", value)
|
||||
write_settings_early()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.show_advanced ~= nil then
|
||||
local value = core.is_yes(fields.show_advanced)
|
||||
core.settings:set_bool("show_advanced", value)
|
||||
write_settings_early()
|
||||
|
||||
local suggested_page_id = update_filtered_pages(dialogdata.query)
|
||||
|
||||
@ -672,12 +685,15 @@ local function buttonhandler(this, fields)
|
||||
|
||||
for i, comp in ipairs(dialogdata.components) do
|
||||
if comp.on_submit and comp:on_submit(fields, this) then
|
||||
write_settings_early()
|
||||
|
||||
-- Clear components so they regenerate
|
||||
dialogdata.components = nil
|
||||
return true
|
||||
end
|
||||
if comp.setting and fields["reset_" .. i] then
|
||||
core.settings:remove(comp.setting.name)
|
||||
write_settings_early()
|
||||
|
||||
-- Clear components so they regenerate
|
||||
dialogdata.components = nil
|
||||
|
@ -440,7 +440,6 @@ enable_raytraced_culling (Enable Raytraced Culling) bool true
|
||||
|
||||
# Shaders allow advanced visual effects and may increase performance on some video
|
||||
# cards.
|
||||
# This only works with the OpenGL video backend.
|
||||
#
|
||||
# Requires: shaders_support
|
||||
enable_shaders (Shaders) bool true
|
||||
@ -649,7 +648,7 @@ mute_sound (Mute sound) bool false
|
||||
|
||||
[*User Interfaces]
|
||||
|
||||
# Set the language. Leave empty to use the system language.
|
||||
# Set the language. By default, the system language is used.
|
||||
# A restart is required after changing this.
|
||||
language (Language) enum ,be,bg,ca,cs,da,de,el,en,eo,es,et,eu,fi,fr,gd,gl,hu,id,it,ja,jbo,kk,ko,lt,lv,ms,nb,nl,nn,pl,pt,pt_BR,ro,ru,sk,sl,sr_Cyrl,sr_Latn,sv,sw,tr,uk,vi,zh_CN,zh_TW
|
||||
|
||||
@ -1798,8 +1797,8 @@ shader_path (Shader path) path
|
||||
# The rendering back-end.
|
||||
# Note: A restart is required after changing this!
|
||||
# OpenGL is the default for desktop, and OGLES2 for Android.
|
||||
# Shaders are supported by OpenGL and OGLES2 (experimental).
|
||||
video_driver (Video driver) enum ,opengl,ogles1,ogles2
|
||||
# Shaders are supported by everything but OGLES1.
|
||||
video_driver (Video driver) enum ,opengl,opengl3,ogles1,ogles2
|
||||
|
||||
# Distance in nodes at which transparency depth sorting is enabled
|
||||
# Use this to limit the performance impact of transparency depth sorting
|
||||
@ -1827,11 +1826,6 @@ mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50
|
||||
# Value of 0 (default) will let Minetest autodetect the number of available threads.
|
||||
mesh_generation_threads (Mapblock mesh generation threads) int 0 0 8
|
||||
|
||||
# Size of the MapBlock cache of the mesh generator. Increasing this will
|
||||
# increase the cache hit %, reducing the data being copied from the main
|
||||
# thread, thus reducing jitter.
|
||||
meshgen_block_cache_size (Mapblock mesh generator's MapBlock cache size in MB) int 20 0 1000
|
||||
|
||||
# True = 256
|
||||
# False = 128
|
||||
# Usable to make minimap smoother on slower machines.
|
||||
|
@ -14,7 +14,7 @@ centroid varying vec2 varTexCoord;
|
||||
// smoothstep - squared
|
||||
float smstsq(float f)
|
||||
{
|
||||
f = f * f * (3 - 2 * f);
|
||||
f = f * f * (3. - 2. * f);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ centroid varying vec2 varTexCoord;
|
||||
// smoothstep - squared
|
||||
float smstsq(float f)
|
||||
{
|
||||
f = f * f * (3 - 2 * f);
|
||||
f = f * f * (3. - 2. * f);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
@ -12,13 +12,13 @@ void main (void)
|
||||
//texture sampling rate
|
||||
const float step = 1.0 / 256.0;
|
||||
float tl = texture2D(normalTexture, vec2(uv.x - step, uv.y + step)).r;
|
||||
float t = texture2D(normalTexture, vec2(uv.x - step, uv.y - step)).r;
|
||||
float t = texture2D(normalTexture, vec2(uv.x, uv.y + step)).r;
|
||||
float tr = texture2D(normalTexture, vec2(uv.x + step, uv.y + step)).r;
|
||||
float r = texture2D(normalTexture, vec2(uv.x + step, uv.y)).r;
|
||||
float r = texture2D(normalTexture, vec2(uv.x + step, uv.y )).r;
|
||||
float br = texture2D(normalTexture, vec2(uv.x + step, uv.y - step)).r;
|
||||
float b = texture2D(normalTexture, vec2(uv.x, uv.y - step)).r;
|
||||
float b = texture2D(normalTexture, vec2(uv.x, uv.y - step)).r;
|
||||
float bl = texture2D(normalTexture, vec2(uv.x - step, uv.y - step)).r;
|
||||
float l = texture2D(normalTexture, vec2(uv.x - step, uv.y)).r;
|
||||
float l = texture2D(normalTexture, vec2(uv.x - step, uv.y )).r;
|
||||
float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
|
||||
float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
|
||||
vec4 bump = vec4 (normalize(vec3 (dX, dY, 0.1)),1.0);
|
||||
|
@ -1,7 +1,7 @@
|
||||
uniform sampler2D baseTexture;
|
||||
|
||||
uniform vec3 dayLight;
|
||||
uniform vec4 skyBgColor;
|
||||
uniform vec4 fogColor;
|
||||
uniform float fogDistance;
|
||||
uniform float fogShadingParameter;
|
||||
uniform vec3 eyePosition;
|
||||
@ -161,7 +161,7 @@ float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDist
|
||||
float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
|
||||
if (depth > 0.0 && f_normal_length > 0.0)
|
||||
// 5 is empirical factor that controls how fast shadow loses sharpness
|
||||
sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0);
|
||||
sharpness_factor = clamp(5.0 * depth * depth_to_blur, 0.0, 1.0);
|
||||
depth = 0.0;
|
||||
|
||||
float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
|
||||
@ -448,7 +448,7 @@ void main(void)
|
||||
// Note: clarity = (1 - fogginess)
|
||||
float clarity = clamp(fogShadingParameter
|
||||
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
||||
col = mix(skyBgColor, col, clarity);
|
||||
col = mix(fogColor, col, clarity);
|
||||
col = vec4(col.rgb, base.a);
|
||||
|
||||
gl_FragData[0] = col;
|
||||
|
@ -242,7 +242,7 @@ void main(void)
|
||||
if (f_normal_length > 0.0) {
|
||||
nNormal = normalize(vNormal);
|
||||
cosLight = max(1e-5, dot(nNormal, -v_LightDirection));
|
||||
float sinLight = pow(1 - pow(cosLight, 2.0), 0.5);
|
||||
float sinLight = pow(1.0 - pow(cosLight, 2.0), 0.5);
|
||||
normalOffsetScale = 2.0 * pFactor * pFactor * sinLight * min(f_shadowfar, 500.0) /
|
||||
xyPerspectiveBias1 / f_textureresolution;
|
||||
z_bias = 1.0 * sinLight / cosLight;
|
||||
@ -250,7 +250,7 @@ void main(void)
|
||||
else {
|
||||
nNormal = vec3(0.0);
|
||||
cosLight = clamp(dot(v_LightDirection, normalize(vec3(v_LightDirection.x, 0.0, v_LightDirection.z))), 1e-2, 1.0);
|
||||
float sinLight = pow(1 - pow(cosLight, 2.0), 0.5);
|
||||
float sinLight = pow(1.0 - pow(cosLight, 2.0), 0.5);
|
||||
normalOffsetScale = 0.0;
|
||||
z_bias = 3.6e3 * sinLight / cosLight;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
uniform sampler2D baseTexture;
|
||||
|
||||
uniform vec3 dayLight;
|
||||
uniform vec4 skyBgColor;
|
||||
uniform vec4 fogColor;
|
||||
uniform float fogDistance;
|
||||
uniform float fogShadingParameter;
|
||||
uniform vec3 eyePosition;
|
||||
@ -449,7 +449,7 @@ void main(void)
|
||||
// Note: clarity = (1 - fogginess)
|
||||
float clarity = clamp(fogShadingParameter
|
||||
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
||||
col = mix(skyBgColor, col, clarity);
|
||||
col = mix(fogColor, col, clarity);
|
||||
col = vec4(col.rgb, base.a);
|
||||
|
||||
gl_FragData[0] = col;
|
||||
|
@ -147,7 +147,7 @@ void main(void)
|
||||
if (f_normal_length > 0.0) {
|
||||
nNormal = normalize(vNormal);
|
||||
cosLight = max(1e-5, dot(nNormal, -v_LightDirection));
|
||||
float sinLight = pow(1 - pow(cosLight, 2.0), 0.5);
|
||||
float sinLight = pow(1.0 - pow(cosLight, 2.0), 0.5);
|
||||
normalOffsetScale = 0.1 * pFactor * pFactor * sinLight * min(f_shadowfar, 500.0) /
|
||||
xyPerspectiveBias1 / f_textureresolution;
|
||||
z_bias = 1e3 * sinLight / cosLight * (0.5 + f_textureresolution / 1024.0);
|
||||
@ -155,7 +155,7 @@ void main(void)
|
||||
else {
|
||||
nNormal = vec3(0.0);
|
||||
cosLight = clamp(dot(v_LightDirection, normalize(vec3(v_LightDirection.x, 0.0, v_LightDirection.z))), 1e-2, 1.0);
|
||||
float sinLight = pow(1 - pow(cosLight, 2.0), 0.5);
|
||||
float sinLight = pow(1.0 - pow(cosLight, 2.0), 0.5);
|
||||
normalOffsetScale = 0.0;
|
||||
z_bias = 3.6e3 * sinLight / cosLight;
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ due to limited capabilities of common devices. What can be done is described bel
|
||||
While you're playing the game normally (that is, no menu or inventory is
|
||||
shown), the following controls are available:
|
||||
* Look around: touch screen and slide finger
|
||||
* Tap: Place a node
|
||||
* Long tap: Dig node or use the held item
|
||||
* Tap: Place a node, punch an object or use the selected item (default)
|
||||
* Long tap: Dig a node or use the selected item (default)
|
||||
* Press back: Pause menu
|
||||
* Touch buttons: Press button
|
||||
* Buttons:
|
||||
|
@ -8,7 +8,7 @@ Introduction
|
||||
|
||||
** WARNING: The client API is currently unstable, and may break/change without warning. **
|
||||
|
||||
Content and functionality can be added to Minetest 0.4.15-dev+ by using Lua
|
||||
Content and functionality can be added to Minetest by using Lua
|
||||
scripting in run-time loaded mods.
|
||||
|
||||
A mod is a self-contained bunch of scripts, textures and other related
|
||||
@ -62,7 +62,7 @@ Generic:
|
||||
|
||||
In a run-in-place version (e.g. the distributed windows version):
|
||||
|
||||
* `minetest-0.4.x/clientmods/` (User-installed mods)
|
||||
* `minetest/clientmods/` (User-installed mods)
|
||||
|
||||
On an installed version on Linux:
|
||||
|
||||
@ -185,15 +185,9 @@ Examples of sound parameter tables:
|
||||
pos = {x = 1, y = 2, z = 3},
|
||||
gain = 1.0, -- default
|
||||
}
|
||||
-- Play connected to an object, looped
|
||||
{
|
||||
object = <an ObjectRef>,
|
||||
gain = 1.0, -- default
|
||||
loop = true,
|
||||
}
|
||||
```
|
||||
|
||||
Looped sounds must either be connected to an object or played locationless.
|
||||
Looped sounds must be played locationless.
|
||||
|
||||
### SimpleSoundSpec
|
||||
* e.g. `""`
|
||||
@ -220,387 +214,20 @@ For helper functions see "Vector helpers".
|
||||
|
||||
Flag Specifier Format
|
||||
---------------------
|
||||
Flags using the standardized flag specifier format can be specified in either of
|
||||
two ways, by string or table.
|
||||
|
||||
The string format is a comma-delimited set of flag names; whitespace and
|
||||
unrecognized flag fields are ignored. Specifying a flag in the string sets the
|
||||
flag, and specifying a flag prefixed by the string `"no"` explicitly
|
||||
clears the flag from whatever the default may be.
|
||||
|
||||
In addition to the standard string flag format, the schematic flags field can
|
||||
also be a table of flag names to boolean values representing whether or not the
|
||||
flag is set. Additionally, if a field with the flag name prefixed with `"no"`
|
||||
is present, mapped to a boolean of any value, the specified flag is unset.
|
||||
|
||||
E.g. A flag field of value
|
||||
|
||||
```lua
|
||||
{place_center_x = true, place_center_y=false, place_center_z=true}
|
||||
```
|
||||
|
||||
is equivalent to
|
||||
|
||||
```lua
|
||||
{place_center_x = true, noplace_center_y=true, place_center_z=true}
|
||||
```
|
||||
|
||||
which is equivalent to
|
||||
|
||||
```lua
|
||||
"place_center_x, noplace_center_y, place_center_z"
|
||||
```
|
||||
|
||||
or even
|
||||
|
||||
```lua
|
||||
"place_center_x, place_center_z"
|
||||
```
|
||||
|
||||
since, by default, no schematic attributes are set.
|
||||
Refer to `lua_api.md`.
|
||||
|
||||
Formspec
|
||||
--------
|
||||
|
||||
Formspec defines a menu. It is a string, with a somewhat strange format.
|
||||
|
||||
Spaces and newlines can be inserted between the blocks, as is used in the
|
||||
examples.
|
||||
|
||||
### Examples
|
||||
|
||||
#### Chest
|
||||
|
||||
size[8,9]
|
||||
list[context;main;0,0;8,4;]
|
||||
list[current_player;main;0,5;8,4;]
|
||||
|
||||
#### Furnace
|
||||
|
||||
size[8,9]
|
||||
list[context;fuel;2,3;1,1;]
|
||||
list[context;src;2,1;1,1;]
|
||||
list[context;dst;5,1;2,2;]
|
||||
list[current_player;main;0,5;8,4;]
|
||||
|
||||
#### Minecraft-like player inventory
|
||||
|
||||
size[8,7.5]
|
||||
image[1,0.6;1,2;player.png]
|
||||
list[current_player;main;0,3.5;8,4;]
|
||||
list[current_player;craft;3,0;3,3;]
|
||||
list[current_player;craftpreview;7,1;1,1;]
|
||||
|
||||
### Elements
|
||||
|
||||
#### `size[<W>,<H>,<fixed_size>]`
|
||||
* Define the size of the menu in inventory slots
|
||||
* `fixed_size`: `true`/`false` (optional)
|
||||
* deprecated: `invsize[<W>,<H>;]`
|
||||
|
||||
#### `container[<X>,<Y>]`
|
||||
* Start of a container block, moves all physical elements in the container by (X, Y)
|
||||
* Must have matching container_end
|
||||
* Containers can be nested, in which case the offsets are added
|
||||
(child containers are relative to parent containers)
|
||||
|
||||
#### `container_end[]`
|
||||
* End of a container, following elements are no longer relative to this container
|
||||
|
||||
#### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;]`
|
||||
* Show an inventory list
|
||||
|
||||
#### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
|
||||
* Show an inventory list
|
||||
|
||||
#### `listring[<inventory location>;<list name>]`
|
||||
* Allows to create a ring of inventory lists
|
||||
* Shift-clicking on items in one element of the ring
|
||||
will send them to the next inventory list inside the ring
|
||||
* The first occurrence of an element inside the ring will
|
||||
determine the inventory where items will be sent to
|
||||
|
||||
#### `listring[]`
|
||||
* Shorthand for doing `listring[<inventory location>;<list name>]`
|
||||
for the last two inventory lists added by list[...]
|
||||
|
||||
#### `listcolors[<slot_bg_normal>;<slot_bg_hover>]`
|
||||
* Sets background color of slots as `ColorString`
|
||||
* Sets background color of slots on mouse hovering
|
||||
|
||||
#### `listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>]`
|
||||
* Sets background color of slots as `ColorString`
|
||||
* Sets background color of slots on mouse hovering
|
||||
* Sets color of slots border
|
||||
|
||||
#### `listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>;<tooltip_bgcolor>;<tooltip_fontcolor>]`
|
||||
* Sets background color of slots as `ColorString`
|
||||
* Sets background color of slots on mouse hovering
|
||||
* Sets color of slots border
|
||||
* Sets default background color of tooltips
|
||||
* Sets default font color of tooltips
|
||||
|
||||
#### `tooltip[<gui_element_name>;<tooltip_text>;<bgcolor>,<fontcolor>]`
|
||||
* Adds tooltip for an element
|
||||
* `<bgcolor>` tooltip background color as `ColorString` (optional)
|
||||
* `<fontcolor>` tooltip font color as `ColorString` (optional)
|
||||
|
||||
#### `image[<X>,<Y>;<W>,<H>;<texture name>]`
|
||||
* Show an image
|
||||
* Position and size units are inventory slots
|
||||
|
||||
#### `item_image[<X>,<Y>;<W>,<H>;<item name>]`
|
||||
* Show an inventory image of registered item/node
|
||||
* Position and size units are inventory slots
|
||||
|
||||
#### `bgcolor[<color>;<fullscreen>]`
|
||||
* Sets background color of formspec as `ColorString`
|
||||
* If `true`, the background color is drawn fullscreen (does not affect the size of the formspec)
|
||||
|
||||
#### `background[<X>,<Y>;<W>,<H>;<texture name>]`
|
||||
* Use a background. Inventory rectangles are not drawn then.
|
||||
* Position and size units are inventory slots
|
||||
* Example for formspec 8x4 in 16x resolution: image shall be sized
|
||||
8 times 16px times 4 times 16px.
|
||||
|
||||
#### `background[<X>,<Y>;<W>,<H>;<texture name>;<auto_clip>]`
|
||||
* Use a background. Inventory rectangles are not drawn then.
|
||||
* Position and size units are inventory slots
|
||||
* Example for formspec 8x4 in 16x resolution:
|
||||
image shall be sized 8 times 16px times 4 times 16px
|
||||
* If `true` the background is clipped to formspec size
|
||||
(`x` and `y` are used as offset values, `w` and `h` are ignored)
|
||||
|
||||
#### `pwdfield[<X>,<Y>;<W>,<H>;<name>;<label>]`
|
||||
* Textual password style field; will be sent to server when a button is clicked
|
||||
* When enter is pressed in field, fields.key_enter_field will be sent with the name
|
||||
of this field.
|
||||
* `x` and `y` position the field relative to the top left of the menu
|
||||
* `w` and `h` are the size of the field
|
||||
* Fields are a set height, but will be vertically centered on `h`
|
||||
* Position and size units are inventory slots
|
||||
* `name` is the name of the field as returned in fields to `on_receive_fields`
|
||||
* `label`, if not blank, will be text printed on the top left above the field
|
||||
* See field_close_on_enter to stop enter closing the formspec
|
||||
|
||||
#### `field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
|
||||
* Textual field; will be sent to server when a button is clicked
|
||||
* When enter is pressed in field, fields.key_enter_field will be sent with the name
|
||||
of this field.
|
||||
* `x` and `y` position the field relative to the top left of the menu
|
||||
* `w` and `h` are the size of the field
|
||||
* Fields are a set height, but will be vertically centered on `h`
|
||||
* Position and size units are inventory slots
|
||||
* `name` is the name of the field as returned in fields to `on_receive_fields`
|
||||
* `label`, if not blank, will be text printed on the top left above the field
|
||||
* `default` is the default value of the field
|
||||
* `default` may contain variable references such as `${text}'` which
|
||||
will fill the value from the metadata value `text`
|
||||
* **Note**: no extra text or more than a single variable is supported ATM.
|
||||
* See field_close_on_enter to stop enter closing the formspec
|
||||
|
||||
#### `field[<name>;<label>;<default>]`
|
||||
* As above, but without position/size units
|
||||
* When enter is pressed in field, fields.key_enter_field will be sent with the name
|
||||
of this field.
|
||||
* Special field for creating simple forms, such as sign text input
|
||||
* Must be used without a `size[]` element
|
||||
* A "Proceed" button will be added automatically
|
||||
* See field_close_on_enter to stop enter closing the formspec
|
||||
|
||||
#### `field_close_on_enter[<name>;<close_on_enter>]`
|
||||
* <name> is the name of the field
|
||||
* if <close_on_enter> is false, pressing enter in the field will submit the form but not close it
|
||||
* defaults to true when not specified (ie: no tag for a field)
|
||||
|
||||
#### `textarea[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
|
||||
* Same as fields above, but with multi-line input
|
||||
|
||||
#### `label[<X>,<Y>;<label>]`
|
||||
* `x` and `y` work as per field
|
||||
* `label` is the text on the label
|
||||
* Position and size units are inventory slots
|
||||
|
||||
#### `vertlabel[<X>,<Y>;<label>]`
|
||||
* Textual label drawn vertically
|
||||
* `x` and `y` work as per field
|
||||
* `label` is the text on the label
|
||||
* Position and size units are inventory slots
|
||||
|
||||
#### `button[<X>,<Y>;<W>,<H>;<name>;<label>]`
|
||||
* Clickable button. When clicked, fields will be sent.
|
||||
* `x`, `y` and `name` work as per field
|
||||
* `w` and `h` are the size of the button
|
||||
* Fixed button height. It will be vertically centered on `h`
|
||||
* `label` is the text on the button
|
||||
* Position and size units are inventory slots
|
||||
|
||||
#### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
|
||||
* `x`, `y`, `w`, `h`, and `name` work as per button
|
||||
* `texture name` is the filename of an image
|
||||
* Position and size units are inventory slots
|
||||
|
||||
#### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>;<noclip>;<drawborder>;<pressed texture name>]`
|
||||
* `x`, `y`, `w`, `h`, and `name` work as per button
|
||||
* `texture name` is the filename of an image
|
||||
* Position and size units are inventory slots
|
||||
* `noclip=true` means the image button doesn't need to be within specified formsize
|
||||
* `drawborder`: draw button border or not
|
||||
* `pressed texture name` is the filename of an image on pressed state
|
||||
|
||||
#### `item_image_button[<X>,<Y>;<W>,<H>;<item name>;<name>;<label>]`
|
||||
* `x`, `y`, `w`, `h`, `name` and `label` work as per button
|
||||
* `item name` is the registered name of an item/node,
|
||||
tooltip will be made out of its description
|
||||
to override it use tooltip element
|
||||
* Position and size units are inventory slots
|
||||
|
||||
#### `button_exit[<X>,<Y>;<W>,<H>;<name>;<label>]`
|
||||
* When clicked, fields will be sent and the form will quit.
|
||||
|
||||
#### `image_button_exit[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
|
||||
* When clicked, fields will be sent and the form will quit.
|
||||
|
||||
#### `textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>]`
|
||||
* Scrollable item list showing arbitrary text elements
|
||||
* `x` and `y` position the itemlist relative to the top left of the menu
|
||||
* `w` and `h` are the size of the itemlist
|
||||
* `name` fieldname sent to server on doubleclick value is current selected element
|
||||
* `listelements` can be prepended by #color in hexadecimal format RRGGBB (only),
|
||||
* if you want a listelement to start with "#" write "##".
|
||||
|
||||
#### `textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>;<selected idx>;<transparent>]`
|
||||
* Scrollable itemlist showing arbitrary text elements
|
||||
* `x` and `y` position the item list relative to the top left of the menu
|
||||
* `w` and `h` are the size of the item list
|
||||
* `name` fieldname sent to server on doubleclick value is current selected element
|
||||
* `listelements` can be prepended by #RRGGBB (only) in hexadecimal format
|
||||
* if you want a listelement to start with "#" write "##"
|
||||
* Index to be selected within textlist
|
||||
* `true`/`false`: draw transparent background
|
||||
* See also `minetest.explode_textlist_event` (main menu: `engine.explode_textlist_event`)
|
||||
|
||||
#### `tabheader[<X>,<Y>;<name>;<caption 1>,<caption 2>,...,<caption n>;<current_tab>;<transparent>;<draw_border>]`
|
||||
* Show a tab**header** at specific position (ignores formsize)
|
||||
* `x` and `y` position the itemlist relative to the top left of the menu
|
||||
* `name` fieldname data is transferred to Lua
|
||||
* `caption 1`...: name shown on top of tab
|
||||
* `current_tab`: index of selected tab 1...
|
||||
* `transparent` (optional): show transparent
|
||||
* `draw_border` (optional): draw border
|
||||
|
||||
#### `box[<X>,<Y>;<W>,<H>;<color>]`
|
||||
* Simple colored semitransparent box
|
||||
* `x` and `y` position the box relative to the top left of the menu
|
||||
* `w` and `h` are the size of box
|
||||
* `color` is color specified as a `ColorString`
|
||||
|
||||
#### `dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>]`
|
||||
* Show a dropdown field
|
||||
* **Important note**: There are two different operation modes:
|
||||
1. handle directly on change (only changed dropdown is submitted)
|
||||
2. read the value on pressing a button (all dropdown values are available)
|
||||
* `x` and `y` position of dropdown
|
||||
* Width of dropdown
|
||||
* Fieldname data is transferred to Lua
|
||||
* Items to be shown in dropdown
|
||||
* Index of currently selected dropdown item
|
||||
|
||||
#### `checkbox[<X>,<Y>;<name>;<label>;<selected>]`
|
||||
* Show a checkbox
|
||||
* `x` and `y`: position of checkbox
|
||||
* `name` fieldname data is transferred to Lua
|
||||
* `label` to be shown left of checkbox
|
||||
* `selected` (optional): `true`/`false`
|
||||
|
||||
#### `scrollbar[<X>,<Y>;<W>,<H>;<orientation>;<name>;<value>]`
|
||||
* Show a scrollbar
|
||||
* There are two ways to use it:
|
||||
1. handle the changed event (only changed scrollbar is available)
|
||||
2. read the value on pressing a button (all scrollbars are available)
|
||||
* `x` and `y`: position of trackbar
|
||||
* `w` and `h`: width and height
|
||||
* `orientation`: `vertical`/`horizontal`
|
||||
* Fieldname data is transferred to Lua
|
||||
* Value this trackbar is set to (`0`-`1000`)
|
||||
* See also `minetest.explode_scrollbar_event` (main menu: `engine.explode_scrollbar_event`)
|
||||
|
||||
#### `table[<X>,<Y>;<W>,<H>;<name>;<cell 1>,<cell 2>,...,<cell n>;<selected idx>]`
|
||||
* Show scrollable table using options defined by the previous `tableoptions[]`
|
||||
* Displays cells as defined by the previous `tablecolumns[]`
|
||||
* `x` and `y`: position the itemlist relative to the top left of the menu
|
||||
* `w` and `h` are the size of the itemlist
|
||||
* `name`: fieldname sent to server on row select or doubleclick
|
||||
* `cell 1`...`cell n`: cell contents given in row-major order
|
||||
* `selected idx`: index of row to be selected within table (first row = `1`)
|
||||
* See also `minetest.explode_table_event` (main menu: `engine.explode_table_event`)
|
||||
|
||||
#### `tableoptions[<opt 1>;<opt 2>;...]`
|
||||
* Sets options for `table[]`
|
||||
* `color=#RRGGBB`
|
||||
* default text color (`ColorString`), defaults to `#FFFFFF`
|
||||
* `background=#RRGGBB`
|
||||
* table background color (`ColorString`), defaults to `#000000`
|
||||
* `border=<true/false>`
|
||||
* should the table be drawn with a border? (default: `true`)
|
||||
* `highlight=#RRGGBB`
|
||||
* highlight background color (`ColorString`), defaults to `#466432`
|
||||
* `highlight_text=#RRGGBB`
|
||||
* highlight text color (`ColorString`), defaults to `#FFFFFF`
|
||||
* `opendepth=<value>`
|
||||
* all subtrees up to `depth < value` are open (default value = `0`)
|
||||
* only useful when there is a column of type "tree"
|
||||
|
||||
#### `tablecolumns[<type 1>,<opt 1a>,<opt 1b>,...;<type 2>,<opt 2a>,<opt 2b>;...]`
|
||||
* Sets columns for `table[]`
|
||||
* Types: `text`, `image`, `color`, `indent`, `tree`
|
||||
* `text`: show cell contents as text
|
||||
* `image`: cell contents are an image index, use column options to define images
|
||||
* `color`: cell contents are a ColorString and define color of following cell
|
||||
* `indent`: cell contents are a number and define indentation of following cell
|
||||
* `tree`: same as indent, but user can open and close subtrees (treeview-like)
|
||||
* Column options:
|
||||
* `align=<value>`
|
||||
* for `text` and `image`: content alignment within cells.
|
||||
Available values: `left` (default), `center`, `right`, `inline`
|
||||
* `width=<value>`
|
||||
* for `text` and `image`: minimum width in em (default: `0`)
|
||||
* for `indent` and `tree`: indent width in em (default: `1.5`)
|
||||
* `padding=<value>`: padding left of the column, in em (default `0.5`).
|
||||
Exception: defaults to 0 for indent columns
|
||||
* `tooltip=<value>`: tooltip text (default: empty)
|
||||
* `image` column options:
|
||||
* `0=<value>` sets image for image index 0
|
||||
* `1=<value>` sets image for image index 1
|
||||
* `2=<value>` sets image for image index 2
|
||||
* and so on; defined indices need not be contiguous empty or
|
||||
non-numeric cells are treated as `0`.
|
||||
* `color` column options:
|
||||
* `span=<value>`: number of following columns to affect (default: infinite)
|
||||
|
||||
**Note**: do _not_ use an element name starting with `key_`; those names are reserved to
|
||||
pass key press events to formspec!
|
||||
For details, refer to `lua_api.md`.
|
||||
|
||||
Spatial Vectors
|
||||
---------------
|
||||
* `vector.new(a[, b, c])`: returns a vector:
|
||||
* A copy of `a` if `a` is a vector.
|
||||
* `{x = a, y = b, z = c}`, if all `a, b, c` are defined
|
||||
* `vector.direction(p1, p2)`: returns a vector
|
||||
* `vector.distance(p1, p2)`: returns a number
|
||||
* `vector.length(v)`: returns a number
|
||||
* `vector.normalize(v)`: returns a vector
|
||||
* `vector.floor(v)`: returns a vector, each dimension rounded down
|
||||
* `vector.round(v)`: returns a vector, each dimension rounded to nearest int
|
||||
* `vector.apply(v, func)`: returns a vector
|
||||
* `vector.combine(v, w, func)`: returns a vector
|
||||
* `vector.equals(v1, v2)`: returns a boolean
|
||||
|
||||
For the following functions `x` can be either a vector or a number:
|
||||
|
||||
* `vector.add(v, x)`: returns a vector
|
||||
* `vector.subtract(v, x)`: returns a vector
|
||||
* `vector.multiply(v, x)`: returns a scaled vector or Schur product
|
||||
* `vector.divide(v, x)`: returns a scaled vector or Schur quotient
|
||||
Refer to `lua_api.md`.
|
||||
|
||||
Helper functions
|
||||
----------------
|
||||
@ -770,6 +397,10 @@ Call these functions only at load time!
|
||||
* `minetest.after(time, func, ...)`
|
||||
* Call the function `func` after `time` seconds, may be fractional
|
||||
* Optional: Variable number of arguments that are passed to `func`
|
||||
* Jobs set for earlier times are executed earlier. If multiple jobs expire
|
||||
at exactly the same time, then they expire in the order in which they were
|
||||
registered. This basically just applies to jobs registered on the same
|
||||
step with the exact same delay.
|
||||
* `minetest.get_us_time()`
|
||||
* Returns time with microsecond precision. May not return wall time.
|
||||
* `minetest.get_timeofday()`
|
||||
@ -1152,6 +783,10 @@ Methods:
|
||||
* See [`HUD definition`](#hud-definition-hud_add-hud_get)
|
||||
* `hud_get(id)`
|
||||
* returns the [`definition`](#hud-definition-hud_add-hud_get) of the HUD with that ID number or `nil`, if non-existent.
|
||||
* `hud_get_all()`:
|
||||
* Returns a table in the form `{ [id] = HUD definition, [id] = ... }`.
|
||||
* A mod should keep track of its introduced IDs and only use this to access foreign elements.
|
||||
* It is discouraged to change foreign HUD elements.
|
||||
* `hud_remove(id)`
|
||||
* remove the HUD element of the specified id, returns `true` on success
|
||||
* `hud_change(id, stat, value)`
|
||||
@ -1319,6 +954,7 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
|
||||
```
|
||||
|
||||
### Server info
|
||||
|
||||
```lua
|
||||
{
|
||||
address = "minetest.example.org", -- The domain name/IP address of a remote server or "" for a local server.
|
||||
@ -1330,32 +966,7 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
|
||||
|
||||
### HUD Definition (`hud_add`, `hud_get`)
|
||||
|
||||
```lua
|
||||
{
|
||||
type = "image", -- see HUD element types, default "text"
|
||||
-- ^ type of HUD element, can be either of "image", "text", "statbar", or "inventory"
|
||||
hud_elem_type = "image",
|
||||
-- ^ Deprecated, same as `type`. In case both are specified `type` will be used.
|
||||
position = {x=0.5, y=0.5},
|
||||
-- ^ Left corner position of element, default `{x=0,y=0}`.
|
||||
name = "<name>", -- default ""
|
||||
scale = {x=2, y=2}, -- default {x=0,y=0}
|
||||
text = "<text>", -- default ""
|
||||
number = 2, -- default 0
|
||||
item = 3, -- default 0
|
||||
-- ^ Selected item in inventory. 0 for no item selected.
|
||||
direction = 0, -- default 0
|
||||
-- ^ Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
|
||||
alignment = {x=0, y=0}, -- default {x=0, y=0}
|
||||
-- ^ See "HUD Element Types"
|
||||
offset = {x=0, y=0}, -- default {x=0, y=0}
|
||||
-- ^ See "HUD Element Types"
|
||||
size = { x=100, y=100 }, -- default {x=0, y=0}
|
||||
-- ^ Size of element in pixels
|
||||
style = 0,
|
||||
-- ^ For "text" elements sets font style: bitfield with 1 = bold, 2 = italic, 4 = monospace
|
||||
}
|
||||
```
|
||||
Refer to `lua_api.md`.
|
||||
|
||||
Escape sequences
|
||||
----------------
|
||||
@ -1383,177 +994,17 @@ The following functions provide escape sequences:
|
||||
|
||||
`ColorString`
|
||||
-------------
|
||||
`#RGB` defines a color in hexadecimal format.
|
||||
|
||||
`#RGBA` defines a color in hexadecimal format and alpha channel.
|
||||
|
||||
`#RRGGBB` defines a color in hexadecimal format.
|
||||
|
||||
`#RRGGBBAA` defines a color in hexadecimal format and alpha channel.
|
||||
|
||||
Named colors are also supported and are equivalent to
|
||||
[CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors).
|
||||
To specify the value of the alpha channel, append `#A` or `#AA` to the end of
|
||||
the color name (e.g. `colorname#08`).
|
||||
Refer to `lua_api.md`.
|
||||
|
||||
`Color`
|
||||
-------------
|
||||
`{a = alpha, r = red, g = green, b = blue}` defines an ARGB8 color.
|
||||
|
||||
HUD element types
|
||||
-----------------
|
||||
The position field is used for all element types.
|
||||
|
||||
To account for differing resolutions, the position coordinates are the percentage
|
||||
of the screen, ranging in value from `0` to `1`.
|
||||
|
||||
The name field is not yet used, but should contain a description of what the
|
||||
HUD element represents. The direction field is the direction in which something
|
||||
is drawn.
|
||||
|
||||
`0` draws from left to right, `1` draws from right to left, `2` draws from
|
||||
top to bottom, and `3` draws from bottom to top.
|
||||
|
||||
The `alignment` field specifies how the item will be aligned. It ranges from `-1` to `1`,
|
||||
with `0` being the center, `-1` is moved to the left/up, and `1` is to the right/down.
|
||||
Fractional values can be used.
|
||||
|
||||
The `offset` field specifies a pixel offset from the position. Contrary to position,
|
||||
the offset is not scaled to screen size. This allows for some precisely-positioned
|
||||
items in the HUD.
|
||||
|
||||
**Note**: `offset` _will_ adapt to screen DPI as well as user defined scaling factor!
|
||||
|
||||
Below are the specific uses for fields in each type; fields not listed for that type are ignored.
|
||||
|
||||
**Note**: Future revisions to the HUD API may be incompatible; the HUD API is still
|
||||
in the experimental stages.
|
||||
|
||||
### `image`
|
||||
Displays an image on the HUD.
|
||||
|
||||
* `scale`: The scale of the image, with 1 being the original texture size.
|
||||
Only the X coordinate scale is used (positive values).
|
||||
Negative values represent that percentage of the screen it
|
||||
should take; e.g. `x=-100` means 100% (width).
|
||||
* `text`: The name of the texture that is displayed.
|
||||
* `alignment`: The alignment of the image.
|
||||
* `offset`: offset in pixels from position.
|
||||
|
||||
### `text`
|
||||
Displays text on the HUD.
|
||||
|
||||
* `scale`: Defines the bounding rectangle of the text.
|
||||
A value such as `{x=100, y=100}` should work.
|
||||
* `text`: The text to be displayed in the HUD element.
|
||||
* `number`: An integer containing the RGB value of the color used to draw the text.
|
||||
Specify `0xFFFFFF` for white text, `0xFF0000` for red, and so on.
|
||||
* `alignment`: The alignment of the text.
|
||||
* `offset`: offset in pixels from position.
|
||||
|
||||
### `statbar`
|
||||
Displays a horizontal bar made up of half-images.
|
||||
|
||||
* `text`: The name of the texture that is used.
|
||||
* `number`: The number of half-textures that are displayed.
|
||||
If odd, will end with a vertically center-split texture.
|
||||
* `direction`
|
||||
* `offset`: offset in pixels from position.
|
||||
* `size`: If used, will force full-image size to this value (override texture pack image size)
|
||||
|
||||
### `inventory`
|
||||
* `text`: The name of the inventory list to be displayed.
|
||||
* `number`: Number of items in the inventory to be displayed.
|
||||
* `item`: Position of item that is selected.
|
||||
* `direction`
|
||||
* `offset`: offset in pixels from position.
|
||||
|
||||
### `waypoint`
|
||||
|
||||
Displays distance to selected world position.
|
||||
|
||||
* `name`: The name of the waypoint.
|
||||
* `text`: Distance suffix. Can be blank.
|
||||
* `precision`: Waypoint precision, integer >= 0. Defaults to 10.
|
||||
If set to 0, distance is not shown. Shown value is `floor(distance*precision)/precision`.
|
||||
When the precision is an integer multiple of 10, there will be `log_10(precision)` digits after the decimal point.
|
||||
`precision = 1000`, for example, will show 3 decimal places (eg: `0.999`).
|
||||
`precision = 2` will show multiples of `0.5`; precision = 5 will show multiples of `0.2` and so on:
|
||||
`precision = n` will show multiples of `1/n`
|
||||
* `number:` An integer containing the RGB value of the color used to draw the
|
||||
text.
|
||||
* `world_pos`: World position of the waypoint.
|
||||
* `offset`: offset in pixels from position.
|
||||
* `alignment`: The alignment of the waypoint.
|
||||
|
||||
### `image_waypoint`
|
||||
|
||||
Same as `image`, but does not accept a `position`; the position is instead determined by `world_pos`, the world position of the waypoint.
|
||||
|
||||
* `scale`: The scale of the image, with 1 being the original texture size.
|
||||
Only the X coordinate scale is used (positive values).
|
||||
Negative values represent that percentage of the screen it
|
||||
should take; e.g. `x=-100` means 100% (width).
|
||||
* `text`: The name of the texture that is displayed.
|
||||
* `alignment`: The alignment of the image.
|
||||
* `world_pos`: World position of the waypoint.
|
||||
* `offset`: offset in pixels from position.
|
||||
|
||||
### Particle definition (`add_particle`)
|
||||
|
||||
```lua
|
||||
{
|
||||
pos = {x=0, y=0, z=0},
|
||||
velocity = {x=0, y=0, z=0},
|
||||
acceleration = {x=0, y=0, z=0},
|
||||
-- ^ Spawn particle at pos with velocity and acceleration
|
||||
expirationtime = 1,
|
||||
-- ^ Disappears after expirationtime seconds
|
||||
size = 1,
|
||||
collisiondetection = false,
|
||||
-- ^ collisiondetection: if true collides with physical objects
|
||||
collision_removal = false,
|
||||
-- ^ collision_removal: if true then particle is removed when it collides,
|
||||
-- ^ requires collisiondetection = true to have any effect
|
||||
vertical = false,
|
||||
-- ^ vertical: if true faces player using y axis only
|
||||
texture = "image.png",
|
||||
-- ^ Uses texture (string)
|
||||
animation = {Tile Animation definition},
|
||||
-- ^ optional, specifies how to animate the particle texture
|
||||
glow = 0
|
||||
-- ^ optional, specify particle self-luminescence in darkness
|
||||
}
|
||||
```
|
||||
As documented in `lua_api.md`, except for obvious reasons, the `playername` field is not supported.
|
||||
|
||||
### `ParticleSpawner` definition (`add_particlespawner`)
|
||||
|
||||
```lua
|
||||
{
|
||||
amount = 1,
|
||||
time = 1,
|
||||
-- ^ If time is 0 has infinite lifespan and spawns the amount on a per-second base
|
||||
minpos = {x=0, y=0, z=0},
|
||||
maxpos = {x=0, y=0, z=0},
|
||||
minvel = {x=0, y=0, z=0},
|
||||
maxvel = {x=0, y=0, z=0},
|
||||
minacc = {x=0, y=0, z=0},
|
||||
maxacc = {x=0, y=0, z=0},
|
||||
minexptime = 1,
|
||||
maxexptime = 1,
|
||||
minsize = 1,
|
||||
maxsize = 1,
|
||||
-- ^ The particle's properties are random values in between the bounds:
|
||||
-- ^ minpos/maxpos, minvel/maxvel (velocity), minacc/maxacc (acceleration),
|
||||
-- ^ minsize/maxsize, minexptime/maxexptime (expirationtime)
|
||||
collisiondetection = false,
|
||||
-- ^ collisiondetection: if true uses collision detection
|
||||
collision_removal = false,
|
||||
-- ^ collision_removal: if true then particle is removed when it collides,
|
||||
-- ^ requires collisiondetection = true to have any effect
|
||||
vertical = false,
|
||||
-- ^ vertical: if true faces player using y axis only
|
||||
texture = "image.png",
|
||||
-- ^ Uses texture (string)
|
||||
}
|
||||
```
|
||||
As documented in `lua_api.md`, except for obvious reasons, the `playername` field is not supported.
|
||||
|
@ -7,8 +7,12 @@
|
||||
| GCC | 7.5+ | or Clang 7.0.1+ |
|
||||
| CMake | 3.5+ | |
|
||||
| IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
|
||||
| libjpeg | - | (via IrrlichtMt) |
|
||||
| libpng | - | (via IrrlichtMt) |
|
||||
| SDL | 2.x | (via IrrlichtMt) |
|
||||
| Freetype | 2.0+ | |
|
||||
| SQLite3 | 3+ | |
|
||||
| Zlib | - | |
|
||||
| Zstd | 1.0+ | |
|
||||
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
|
||||
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
|
||||
@ -18,27 +22,27 @@
|
||||
|
||||
For Debian/Ubuntu users:
|
||||
|
||||
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext
|
||||
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext libsdl2-dev
|
||||
|
||||
For Fedora users:
|
||||
|
||||
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libXi-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext
|
||||
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libXi-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext SDL2-devel
|
||||
|
||||
For openSUSE users:
|
||||
|
||||
sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libXi-devel libvorbis-devel freetype2-devel
|
||||
sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libXi-devel libvorbis-devel freetype2-devel SDL2-devel
|
||||
|
||||
For Arch users:
|
||||
|
||||
sudo pacman -S --needed base-devel libcurl-gnutls cmake libxi libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext
|
||||
sudo pacman -S --needed base-devel libcurl-gnutls cmake libxi libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2
|
||||
|
||||
For Alpine users:
|
||||
|
||||
sudo apk add build-base cmake libpng-dev jpeg-dev libxi-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext
|
||||
sudo apk add build-base cmake libpng-dev jpeg-dev libxi-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext sdl2-dev
|
||||
|
||||
For Void users:
|
||||
|
||||
sudo xbps-install cmake libpng-devel jpeg-devel libXi-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel libzstd-devel gettext
|
||||
sudo xbps-install cmake libpng-devel jpeg-devel libXi-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel libzstd-devel gettext SDL2-devel
|
||||
|
||||
## Download
|
||||
|
||||
|
@ -14,7 +14,7 @@ It is highly recommended to use vcpkg as package manager.
|
||||
|
||||
After you successfully built vcpkg you can easily install the required libraries:
|
||||
```powershell
|
||||
vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry gettext --triplet x64-windows
|
||||
vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry gettext sdl2 --triplet x64-windows
|
||||
```
|
||||
|
||||
- **Don't forget about IrrlichtMt.** The easiest way is to clone it to `lib/irrlichtmt`:
|
||||
|
24
doc/developing/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# Developer documentation
|
||||
|
||||
## Wiki
|
||||
|
||||
Some important development docs are found in the wiki: https://dev.minetest.net/
|
||||
|
||||
Notable pages:
|
||||
|
||||
- [Releasing Minetest](https://dev.minetest.net/Releasing_Minetest)
|
||||
- [Engine translations](https://dev.minetest.net/Translation#Maintaining_engine_translations)
|
||||
- [Changelog](https://dev.minetest.net/Changelog)
|
||||
- [Organisation](https://dev.minetest.net/Organisation)
|
||||
- [Code style guidelines](https://dev.minetest.net/Code_style_guidelines)
|
||||
|
||||
## In this folder
|
||||
|
||||
- [Developing minetestserver with Docker](docker.md)
|
||||
- [Miscellaneous](misc.md)
|
||||
|
||||
## IRC
|
||||
|
||||
Oftentimes knowledge hasn't been written down (yet) and your best bet is to ask someone experienced and/or the core developers.
|
||||
|
||||
Feel free to join the [#minetest-dev IRC](https://wiki.minetest.net/IRC) and ask questions related to **engine development**.
|
65
doc/developing/misc.md
Normal file
@ -0,0 +1,65 @@
|
||||
# Miscellaneous
|
||||
|
||||
## Sign the Android APK from CI
|
||||
|
||||
The [Github Actions Workflow](https://github.com/minetest/minetest/actions?query=workflow%3Aandroid+event%3Apush)
|
||||
automatically produces an APK for each architecture.
|
||||
Before installing them onto a device they however need to be signed.
|
||||
|
||||
This requires an installation of the Android SDK and `adb`.
|
||||
```bash
|
||||
.../android-sdk/build-tools/30.0.3/apksigner sign --ks ~/.android/debug.keystore \
|
||||
app-arm64-v8a-release-unsigned.apk
|
||||
# Enter 'android' (without quotes) when asked for a password
|
||||
```
|
||||
|
||||
Note that the `debug.keystore` will not exist if you have never compiled an
|
||||
Android app on your system (probably).
|
||||
|
||||
After that installing it will work:
|
||||
```bash
|
||||
adb install -r -d ./app-arm64-v8a-release-unsigned.apk
|
||||
```
|
||||
|
||||
## How to get debug output from Minetest on Android
|
||||
|
||||
In case debug.txt isn't enough (e.g. when debugging a crash), you can get debug
|
||||
output using logcat:
|
||||
|
||||
`adb logcat -s 'Minetest:*' '*:F'`
|
||||
|
||||
Note that you can do this even *after* the app has crashed,
|
||||
since Android keeps an internal buffer.
|
||||
|
||||
A segmentation fault for example looks like this:
|
||||
|
||||
```
|
||||
01-10 17:20:22.215 19308 20560 F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 20560 (MinetestNativeT), pid 19308 (netest.minetest)
|
||||
01-10 17:20:22.287 20576 20576 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
|
||||
01-10 17:20:22.287 20576 20576 F DEBUG : Build fingerprint: '...'
|
||||
01-10 17:20:22.287 20576 20576 F DEBUG : Revision: '4'
|
||||
01-10 17:20:22.287 20576 20576 F DEBUG : ABI: 'arm64'
|
||||
01-10 17:20:22.288 20576 20576 F DEBUG : Timestamp: 2024-01-10 17:20:22+0100
|
||||
01-10 17:20:22.288 20576 20576 F DEBUG : pid: 19308, tid: 20560, name: MinetestNativeT >>> net.minetest.minetest <<<
|
||||
01-10 17:20:22.288 20576 20576 F DEBUG : uid: 10385
|
||||
01-10 17:20:22.288 20576 20576 F DEBUG : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
|
||||
[ ... more information follows ... ]
|
||||
```
|
||||
|
||||
## Profiling Minetest on Linux
|
||||
|
||||
We will be using a tool called "perf", which you can get by installing `perf` or `linux-perf` or `linux-tools-common`.
|
||||
|
||||
For best results build Minetest and Irrlicht with debug symbols
|
||||
(`-DCMAKE_BUILD_TYPE=RelWithDebInfo` or `-DCMAKE_BUILD_TYPE=Debug`).
|
||||
|
||||
Run the client (or server) like this and do whatever you wanted to test:
|
||||
```bash
|
||||
perf record -z --call-graph dwarf -- ./bin/minetest
|
||||
```
|
||||
|
||||
This will leave a file called "perf.data".
|
||||
|
||||
You can open this file with perf built-in tools but much more interesting
|
||||
is the visualization using a GUI tool: **[Hotspot](https://github.com/KDAB/hotspot)**.
|
||||
It will give you flamegraphs, per-thread, per-function views and much more.
|
182
doc/lua_api.md
@ -246,15 +246,15 @@ The format is documented in `builtin/settingtypes.txt`.
|
||||
It is parsed by the main menu settings dialogue to list mod-specific
|
||||
settings in the "Mods" category.
|
||||
|
||||
`minetest.settings` can be used to read custom or engine settings.
|
||||
See [`Settings`].
|
||||
|
||||
### `init.lua`
|
||||
|
||||
The main Lua script. Running this script should register everything it
|
||||
wants to register. Subsequent execution depends on minetest calling the
|
||||
wants to register. Subsequent execution depends on Minetest calling the
|
||||
registered callbacks.
|
||||
|
||||
`minetest.settings` can be used to read custom or existing settings at load
|
||||
time, if necessary. (See [`Settings`])
|
||||
|
||||
### `textures`, `sounds`, `media`, `models`, `locale`
|
||||
|
||||
Media files (textures, sounds, whatever) that will be transferred to the
|
||||
@ -1270,11 +1270,15 @@ The function of `param2` is determined by `paramtype2` in node definition.
|
||||
* The rotation of the node is stored in `param2`
|
||||
* Node is 'mounted'/facing towards one of 6 directions
|
||||
* You can make this value by using `minetest.dir_to_wallmounted()`
|
||||
* Values range 0 - 5
|
||||
* Values range 0 - 7
|
||||
* The value denotes at which direction the node is "mounted":
|
||||
0 = y+, 1 = y-, 2 = x+, 3 = x-, 4 = z+, 5 = z-
|
||||
6 = y+, but rotated by 90°
|
||||
7 = y-, but rotated by -90°
|
||||
* By default, on placement the param2 is automatically set to the
|
||||
appropriate rotation, depending on which side was pointed at
|
||||
appropriate rotation (0 to 5), depending on which side was
|
||||
pointed at. With the node field `wallmounted_rotate_vertical = true`,
|
||||
the param2 values 6 and 7 might additionally be set
|
||||
* `paramtype2 = "facedir"`
|
||||
* Supported drawtypes: "normal", "nodebox", "mesh"
|
||||
* The rotation of the node is stored in `param2`.
|
||||
@ -1678,10 +1682,12 @@ type are ignored.
|
||||
|
||||
Displays an image on the HUD.
|
||||
|
||||
* `scale`: The scale of the image, with 1 being the original texture size.
|
||||
Only the X coordinate scale is used (positive values).
|
||||
Negative values represent that percentage of the screen it
|
||||
should take; e.g. `x=-100` means 100% (width).
|
||||
* `scale`: The scale of the image, with `{x = 1, y = 1}` being the original texture size.
|
||||
The `x` and `y` fields apply to the respective axes.
|
||||
Positive values scale the source image.
|
||||
Negative values represent percentages relative to screen dimensions.
|
||||
Example: `{x = -20, y = 3}` means the image will be drawn 20% of screen width wide,
|
||||
and 3 times as high as the source image is.
|
||||
* `text`: The name of the texture that is displayed.
|
||||
* `alignment`: The alignment of the image.
|
||||
* `offset`: offset in pixels from position.
|
||||
@ -1748,10 +1754,12 @@ Displays distance to selected world position.
|
||||
|
||||
Same as `image`, but does not accept a `position`; the position is instead determined by `world_pos`, the world position of the waypoint.
|
||||
|
||||
* `scale`: The scale of the image, with 1 being the original texture size.
|
||||
Only the X coordinate scale is used (positive values).
|
||||
Negative values represent that percentage of the screen it
|
||||
should take; e.g. `x=-100` means 100% (width).
|
||||
* `scale`: The scale of the image, with `{x = 1, y = 1}` being the original texture size.
|
||||
The `x` and `y` fields apply to the respective axes.
|
||||
Positive values scale the source image.
|
||||
Negative values represent percentages relative to screen dimensions.
|
||||
Example: `{x = -20, y = 3}` means the image will be drawn 20% of screen width wide,
|
||||
and 3 times as high as the source image is.
|
||||
* `text`: The name of the texture that is displayed.
|
||||
* `alignment`: The alignment of the image.
|
||||
* `world_pos`: World position of the waypoint.
|
||||
@ -5280,6 +5288,20 @@ Utilities
|
||||
physics_overrides_v2 = true,
|
||||
-- In HUD definitions the field `type` is used and `hud_elem_type` is deprecated (5.9.0)
|
||||
hud_def_type_field = true,
|
||||
-- PseudoRandom and PcgRandom state is restorable
|
||||
-- PseudoRandom has get_state method
|
||||
-- PcgRandom has get_state and set_state methods (5.9.0)
|
||||
random_state_restore = true,
|
||||
-- minetest.after guarantees that coexisting jobs are executed primarily
|
||||
-- in order of expiry and secondarily in order of registration (5.9.0)
|
||||
after_order_expiry_registration = true,
|
||||
-- wallmounted nodes mounted at floor or ceiling may additionally
|
||||
-- be rotated by 90° with special param2 values (5.9.0)
|
||||
wallmounted_rotate = true,
|
||||
-- Availability of the `pointabilities` property in the item definition (5.9.0)
|
||||
item_specific_pointabilities = true,
|
||||
-- Nodes `pointable` property can be `"blocking"` (5.9.0)
|
||||
blocking_pointability_type = true,
|
||||
}
|
||||
```
|
||||
|
||||
@ -5768,7 +5790,7 @@ Setting-related
|
||||
---------------
|
||||
|
||||
* `minetest.settings`: Settings object containing all of the settings from the
|
||||
main config file (`minetest.conf`).
|
||||
main config file (`minetest.conf`). See [`Settings`].
|
||||
* `minetest.setting_get_pos(name)`: Loads a setting from the main settings and
|
||||
parses it as a position (in the format `(1,2,3)`). Returns a position or nil.
|
||||
|
||||
@ -5819,8 +5841,20 @@ Authentication
|
||||
* `name`: string; if omitted, all auth data should be considered modified
|
||||
* `minetest.set_player_password(name, password_hash)`: Set password hash of
|
||||
player `name`.
|
||||
* `minetest.set_player_privs(name, {priv1=true,...})`: Set privileges of player
|
||||
`name`.
|
||||
* `minetest.set_player_privs(name, privs)`: Set privileges of player `name`.
|
||||
* `privs` is a **set** of privileges:
|
||||
A table where the keys are names of privileges and the values are `true`.
|
||||
* Example: `minetest.set_player_privs("singleplayer", {interact = true, fly = true})`.
|
||||
This **sets** the player privileges to `interact` and `fly`;
|
||||
`singleplayer` will only have these two privileges afterwards.
|
||||
* `minetest.change_player_privs(name, changes)`: Helper to grant or revoke privileges.
|
||||
* `changes`: Table of changes to make.
|
||||
A field `[privname] = true` grants a privilege,
|
||||
whereas `[privname] = false` revokes a privilege.
|
||||
* Example: `minetest.change_player_privs("singleplayer", {interact = true, fly = false})`
|
||||
will grant singleplayer the `interact` privilege
|
||||
and revoke singleplayer's `fly` privilege.
|
||||
All other privileges will remain unchanged.
|
||||
* `minetest.auth_reload()`
|
||||
* See `reload()` in authentication handler definition
|
||||
|
||||
@ -6450,6 +6484,8 @@ Timing
|
||||
* `minetest.after(time, func, ...)`: returns job table to use as below.
|
||||
* Call the function `func` after `time` seconds, may be fractional
|
||||
* Optional: Variable number of arguments that are passed to `func`
|
||||
* Jobs set for earlier times are executed earlier. If multiple jobs expire
|
||||
at exactly the same time, then they are executed in registration order.
|
||||
|
||||
* `job:cancel()`
|
||||
* Cancels the job function from being called
|
||||
@ -7799,6 +7835,10 @@ child will follow movement and rotation of that bone.
|
||||
* `stat` supports the same keys as in the hud definition table except for
|
||||
`"type"` (or the deprecated `"hud_elem_type"`).
|
||||
* `hud_get(id)`: gets the HUD element definition structure of the specified ID
|
||||
* `hud_get_all()`:
|
||||
* Returns a table in the form `{ [id] = HUD definition, [id] = ... }`.
|
||||
* A mod should keep track of its introduced IDs and only use this to access foreign elements.
|
||||
* It is discouraged to change foreign HUD elements.
|
||||
* `hud_set_flags(flags)`: sets specified HUD flags of player.
|
||||
* `flags`: A table with the following fields set to boolean values
|
||||
* `hotbar`
|
||||
@ -7852,8 +7892,7 @@ child will follow movement and rotation of that bone.
|
||||
whether `set_sky` accepts this format. Check the legacy format otherwise.
|
||||
* Passing no arguments resets the sky to its default values.
|
||||
* `sky_parameters` is a table with the following optional fields:
|
||||
* `base_color`: ColorSpec, changes fog in "skybox" and "plain".
|
||||
(default: `#ffffff`)
|
||||
* `base_color`: ColorSpec, meaning depends on `type` (default: `#ffffff`)
|
||||
* `body_orbit_tilt`: Float, rotation angle of sun/moon orbit in degrees.
|
||||
By default, orbit is controlled by a client-side setting, and this field is not set.
|
||||
After a value is assigned, it can only be changed to another float value.
|
||||
@ -7910,6 +7949,9 @@ child will follow movement and rotation of that bone.
|
||||
Any value between [0.0, 0.99] set the fog_start as a fraction of the viewing_range.
|
||||
Any value < 0, resets the behavior to being client-controlled.
|
||||
(default: -1)
|
||||
* `fog_color`: ColorSpec, override the color of the fog.
|
||||
Unlike `base_color` above this will apply regardless of the skybox type.
|
||||
(default: `"#00000000"`, which means no override)
|
||||
* `set_sky(base_color, type, {texture names}, clouds)`
|
||||
* Deprecated. Use `set_sky(sky_parameters)`
|
||||
* `base_color`: ColorSpec, defaults to white
|
||||
@ -8048,7 +8090,7 @@ child will follow movement and rotation of that bone.
|
||||
* `get_lighting()`: returns the current state of lighting for the player.
|
||||
* Result is a table with the same fields as `light_definition` in `set_lighting`.
|
||||
* `respawn()`: Respawns the player using the same mechanism as the death screen,
|
||||
including calling on_respawnplayer callbacks.
|
||||
including calling `on_respawnplayer` callbacks.
|
||||
|
||||
`PcgRandom`
|
||||
-----------
|
||||
@ -8057,7 +8099,9 @@ A 32-bit pseudorandom number generator.
|
||||
Uses PCG32, an algorithm of the permuted congruential generator family,
|
||||
offering very strong randomness.
|
||||
|
||||
It can be created via `PcgRandom(seed)` or `PcgRandom(seed, sequence)`.
|
||||
* constructor `PcgRandom(seed, [seq])`
|
||||
* `seed`: 64-bit unsigned seed
|
||||
* `seq`: 64-bit unsigned sequence, optional
|
||||
|
||||
### Methods
|
||||
|
||||
@ -8069,6 +8113,8 @@ It can be created via `PcgRandom(seed)` or `PcgRandom(seed, sequence)`.
|
||||
* `mean = (max - min) / 2`, and
|
||||
* `variance = (((max - min + 1) ^ 2) - 1) / (12 * num_trials)`
|
||||
* Increasing `num_trials` improves accuracy of the approximation
|
||||
* `get_state()`: return generator state encoded in string
|
||||
* `set_state(state_string)`: restore generator state from encoded string
|
||||
|
||||
`PerlinNoise`
|
||||
-------------
|
||||
@ -8152,14 +8198,22 @@ Can be obtained using `player:get_meta()`.
|
||||
A 16-bit pseudorandom number generator.
|
||||
Uses a well-known LCG algorithm introduced by K&R.
|
||||
|
||||
It can be created via `PseudoRandom(seed)`.
|
||||
**Note**:
|
||||
`PseudoRandom` is slower and has worse random distribution than `PcgRandom`.
|
||||
Use `PseudoRandom` only if you need output to match the well-known LCG algorithm introduced by K&R.
|
||||
Otherwise, use `PcgRandom`.
|
||||
|
||||
* constructor `PseudoRandom(seed)`
|
||||
* `seed`: 32-bit signed number
|
||||
|
||||
### Methods
|
||||
|
||||
* `next()`: return next integer random number [`0`...`32767`]
|
||||
* `next(min, max)`: return next integer random number [`min`...`max`]
|
||||
* `((max - min) == 32767) or ((max-min) <= 6553))` must be true
|
||||
due to the simple implementation making bad distribution otherwise.
|
||||
* Either `max - min == 32767` or `max - min <= 6553` must be true
|
||||
due to the simple implementation making a bad distribution otherwise.
|
||||
* `get_state()`: return state of pseudorandom generator as number
|
||||
* use returned number as seed in PseudoRandom constructor to restore
|
||||
|
||||
`Raycast`
|
||||
---------
|
||||
@ -8225,37 +8279,47 @@ secure random device cannot be found on the system.
|
||||
|
||||
An interface to read config files in the format of `minetest.conf`.
|
||||
|
||||
It can be created via `Settings(filename)`.
|
||||
`minetest.settings` is a `Settings` instance that can be used to access the
|
||||
main config file (`minetest.conf`). Instances for other config files can be
|
||||
created via `Settings(filename)`.
|
||||
|
||||
Engine settings on the `minetest.settings` object have internal defaults that
|
||||
will be returned if a setting is unset.
|
||||
The engine does *not* (yet) read `settingtypes.txt` for this purpose. This
|
||||
means that no defaults will be returned for mod settings.
|
||||
|
||||
### Methods
|
||||
|
||||
* `get(key)`: returns a value
|
||||
* Returns `nil` if `key` is not found.
|
||||
* `get_bool(key, [default])`: returns a boolean
|
||||
* `default` is the value returned if `key` is not found.
|
||||
* Returns `nil` if `key` is not found and `default` not specified.
|
||||
* `get_np_group(key)`: returns a NoiseParams table
|
||||
* Returns `nil` if `key` is not found.
|
||||
* `get_flags(key)`:
|
||||
* Returns `{flag = true/false, ...}` according to the set flags.
|
||||
* Is currently limited to mapgen flags `mg_flags` and mapgen-specific
|
||||
flags like `mgv5_spflags`.
|
||||
* Returns `nil` if `key` is not found.
|
||||
* `set(key, value)`
|
||||
* Setting names can't contain whitespace or any of `="{}#`.
|
||||
* Setting values can't contain the sequence `\n"""`.
|
||||
* Setting names starting with "secure." can't be set on the main settings
|
||||
object (`minetest.settings`).
|
||||
* `set_bool(key, value)`
|
||||
* See documentation for set() above.
|
||||
* See documentation for `set()` above.
|
||||
* `set_np_group(key, value)`
|
||||
* `value` is a NoiseParams table.
|
||||
* Also, see documentation for set() above.
|
||||
* Also, see documentation for `set()` above.
|
||||
* `remove(key)`: returns a boolean (`true` for success)
|
||||
* `get_names()`: returns `{key1,...}`
|
||||
* `has(key)`:
|
||||
* Returns a boolean indicating whether `key` exists.
|
||||
* Note that for the main settings object (`minetest.settings`), `get(key)`
|
||||
might return a value even if `has(key)` returns `false`. That's because
|
||||
`get` can fall back to the so-called parent of the `Settings` object, i.e.
|
||||
the default values.
|
||||
* In contrast to the various getter functions, `has()` doesn't consider
|
||||
any default values.
|
||||
* This means that on the main settings object (`minetest.settings`),
|
||||
`get(key)` might return a value even if `has(key)` returns `false`.
|
||||
* `write()`: returns a boolean (`true` for success)
|
||||
* Writes changes to file.
|
||||
* `to_table()`: returns `{[key1]=value1,...}`
|
||||
@ -8336,7 +8400,9 @@ Player properties need to be saved manually.
|
||||
|
||||
|
||||
pointable = true,
|
||||
-- Whether the object can be pointed at
|
||||
-- Can be `true` if it is pointable, `false` if it can be pointed through,
|
||||
-- or `"blocking"` if it is pointable but not selectable.
|
||||
-- Can be overridden by the `pointabilities` of the held item.
|
||||
|
||||
visual = "cube" / "sprite" / "upright_sprite" / "mesh" / "wielditem" / "item",
|
||||
-- "cube" is a node-sized cube.
|
||||
@ -8700,6 +8766,27 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
|
||||
-- If true, item can point to all liquid nodes (`liquidtype ~= "none"`),
|
||||
-- even those for which `pointable = false`
|
||||
|
||||
pointabilities = {
|
||||
nodes = {
|
||||
["default:stone"] = "blocking",
|
||||
["group:leaves"] = false,
|
||||
},
|
||||
objects = {
|
||||
["modname:entityname"] = true,
|
||||
["group:ghosty"] = true, -- (an armor group)
|
||||
}
|
||||
},
|
||||
-- Contains lists to override the `pointable` property of pointed nodes and objects.
|
||||
-- The index can be a node/entity name or a group with the prefix `"group:"`.
|
||||
-- (For objects `armor_groups` are used and for players the entity name is irrelevant.)
|
||||
-- If multiple fields fit, the following priority order is applied:
|
||||
-- 1. value of matching node/entity name
|
||||
-- 2. `true` for any group
|
||||
-- 3. `false` for any group
|
||||
-- 4. `"blocking"` for any group
|
||||
-- 5. `liquids_pointable` if it is a liquid node
|
||||
-- 6. `pointable` property of the node or object
|
||||
|
||||
light_source = 0,
|
||||
-- When used for nodes: Defines amount of light emitted by node.
|
||||
-- Otherwise: Defines texture glow when viewed as a dropped item
|
||||
@ -8741,6 +8828,20 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
|
||||
-- Otherwise should be name of node which the client immediately places
|
||||
-- upon digging. Server will always update with actual result shortly.
|
||||
|
||||
touch_interaction = {
|
||||
-- Only affects touchscreen clients.
|
||||
-- Defines the meaning of short and long taps with the item in hand.
|
||||
-- The fields in this table have two valid values:
|
||||
-- * "long_dig_short_place" (long tap = dig, short tap = place)
|
||||
-- * "short_dig_long_place" (short tap = dig, long tap = place)
|
||||
-- The field to be used is selected according to the current
|
||||
-- `pointed_thing`.
|
||||
|
||||
pointed_nothing = "long_dig_short_place",
|
||||
pointed_node = "long_dig_short_place",
|
||||
pointed_object = "short_dig_long_place",
|
||||
},
|
||||
|
||||
sound = {
|
||||
-- Definition of item sounds to be played at various events.
|
||||
-- All fields in this table are optional.
|
||||
@ -8892,6 +8993,13 @@ Used by `minetest.register_node`.
|
||||
place_param2 = 0,
|
||||
-- Value for param2 that is set when player places node
|
||||
|
||||
wallmounted_rotate_vertical = false,
|
||||
-- If true, place_param2 is nil, and this is a wallmounted node,
|
||||
-- this node might use the special 90° rotation when placed
|
||||
-- on the floor or ceiling, depending on the direction.
|
||||
-- See the explanation about wallmounted for details.
|
||||
-- Otherwise, the rotation is always the same on vertical placement.
|
||||
|
||||
is_ground_content = true,
|
||||
-- If false, the cave generator and dungeon generator will not carve
|
||||
-- through this node.
|
||||
@ -8904,7 +9012,11 @@ Used by `minetest.register_node`.
|
||||
|
||||
walkable = true, -- If true, objects collide with node
|
||||
|
||||
pointable = true, -- If true, can be pointed at
|
||||
pointable = true,
|
||||
-- Can be `true` if it is pointable, `false` if it can be pointed through,
|
||||
-- or `"blocking"` if it is pointable but not selectable.
|
||||
-- Can be overridden by the `pointabilities` of the held item.
|
||||
-- A client may be able to point non-pointable nodes, since it isn't checked server-side.
|
||||
|
||||
diggable = true, -- If false, can never be dug
|
||||
|
||||
@ -10647,8 +10759,8 @@ Used by `minetest.register_authentication_handler`.
|
||||
|
||||
set_privileges = function(name, privileges),
|
||||
-- Set privileges of player `name`.
|
||||
-- `privileges` is in table form, auth data should be created if not
|
||||
-- present.
|
||||
-- `privileges` is in table form: keys are privilege names, values are `true`;
|
||||
-- auth data should be created if not present.
|
||||
|
||||
reload = function(),
|
||||
-- Reload authentication data from the storage location.
|
||||
|
@ -17,6 +17,7 @@ markdown_extensions:
|
||||
- pymdownx.superfences
|
||||
- pymdownx.highlight:
|
||||
css_class: codehilite
|
||||
- gfm_admonition
|
||||
plugins:
|
||||
- search:
|
||||
separator: '[\s\-\.\(]+'
|
||||
|
@ -1,3 +1,4 @@
|
||||
mkdocs~=1.4.3
|
||||
pygments~=2.15.1
|
||||
pymdown-extensions~=10.3
|
||||
markdown-gfm-admonition~=0.1.0
|
@ -27,6 +27,7 @@ read_globals = {
|
||||
"Settings",
|
||||
"check",
|
||||
"PseudoRandom",
|
||||
"PcgRandom",
|
||||
|
||||
string = {fields = {"split", "trim"}},
|
||||
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
|
||||
|
@ -1,3 +1,4 @@
|
||||
dofile(minetest.get_modpath("testentities").."/visuals.lua")
|
||||
dofile(minetest.get_modpath("testentities").."/selectionbox.lua")
|
||||
dofile(minetest.get_modpath("testentities").."/armor.lua")
|
||||
dofile(minetest.get_modpath("testentities").."/pointable.lua")
|
||||
|
23
games/devtest/mods/testentities/pointable.lua
Normal file
@ -0,0 +1,23 @@
|
||||
-- Pointability test Entities
|
||||
|
||||
-- Register wrapper for compactness
|
||||
local function register_pointable_testentity(name, pointable)
|
||||
local texture = "testnodes_"..name..".png"
|
||||
minetest.register_entity("testentities:"..name, {
|
||||
initial_properties = {
|
||||
visual = "cube",
|
||||
visual_size = {x = 0.6, y = 0.6, z = 0.6},
|
||||
textures = {
|
||||
texture, texture, texture, texture, texture, texture
|
||||
},
|
||||
pointable = pointable,
|
||||
},
|
||||
on_activate = function(self)
|
||||
self.object:set_armor_groups({[name.."_test"] = 1})
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
register_pointable_testentity("pointable", true)
|
||||
register_pointable_testentity("not_pointable", false)
|
||||
register_pointable_testentity("blocking_pointable", "blocking")
|
@ -152,7 +152,8 @@ minetest.register_chatcommand("hudwaypoints", {
|
||||
type = "image_waypoint",
|
||||
text = "testhud_waypoint.png",
|
||||
world_pos = player:get_pos(),
|
||||
scale = {x = 3, y = 3},
|
||||
-- 20% of screen width, 3x image height
|
||||
scale = {x = -20, y = 3},
|
||||
offset = {x = 0, y = -32}
|
||||
}
|
||||
if not player_waypoints[name] then
|
||||
@ -209,3 +210,23 @@ minetest.register_on_leaveplayer(function(player)
|
||||
player_font_huds[player:get_player_name()] = nil
|
||||
player_waypoints[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("hudprint", {
|
||||
description = "Writes all used Lua HUD elements into chat.",
|
||||
func = function(name, params)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "No player."
|
||||
end
|
||||
|
||||
local s = "HUD elements:"
|
||||
for k, elem in pairs(player:hud_get_all()) do
|
||||
local ename = dump(elem.name)
|
||||
local etype = dump(elem.type)
|
||||
local epos = "{x="..elem.position.x..", y="..elem.position.y.."}"
|
||||
s = s.."\n["..k.."] type = "..etype.." | name = "..ename.." | pos = ".. epos
|
||||
end
|
||||
|
||||
return true, s
|
||||
end
|
||||
})
|
||||
|
@ -163,7 +163,7 @@ minetest.register_node("testnodes:torchlike", {
|
||||
|
||||
minetest.register_node("testnodes:torchlike_wallmounted", {
|
||||
description = S("Wallmounted \"torchlike\" Drawtype Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "torchlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
@ -179,6 +179,24 @@ minetest.register_node("testnodes:torchlike_wallmounted", {
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:torchlike_wallmounted_rot", {
|
||||
description = S("Wallmounted Rotatable Torchlike Drawtype Test Node"),
|
||||
drawtype = "torchlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
tiles = {
|
||||
"testnodes_torchlike_floor.png^[colorize:#FFFF00:40",
|
||||
"testnodes_torchlike_ceiling.png^[colorize:#FFFF00:40",
|
||||
"testnodes_torchlike_wall.png^[colorize:#FFFF00:40",
|
||||
},
|
||||
|
||||
|
||||
walkable = false,
|
||||
sunlight_propagates = true,
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:signlike", {
|
||||
description = S("Floor \"signlike\" Drawtype Test Node").."\n"..
|
||||
S("Always on floor"),
|
||||
@ -186,16 +204,14 @@ minetest.register_node("testnodes:signlike", {
|
||||
paramtype = "light",
|
||||
tiles = { "testnodes_signlike.png^[colorize:#FF0000:64" },
|
||||
|
||||
|
||||
walkable = false,
|
||||
groups = { dig_immediate = 3 },
|
||||
sunlight_propagates = true,
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
|
||||
minetest.register_node("testnodes:signlike_wallmounted", {
|
||||
description = S("Wallmounted \"signlike\" Drawtype Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "signlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
@ -207,6 +223,22 @@ minetest.register_node("testnodes:signlike_wallmounted", {
|
||||
sunlight_propagates = true,
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:signlike_rot", {
|
||||
description = S("Wallmounted Rotatable Signlike Drawtype Test Node"),
|
||||
drawtype = "signlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
tiles = { "testnodes_signlike.png^[colorize:#FFFF00:40" },
|
||||
|
||||
|
||||
walkable = false,
|
||||
groups = { dig_immediate = 3 },
|
||||
sunlight_propagates = true,
|
||||
})
|
||||
|
||||
|
||||
|
||||
minetest.register_node("testnodes:plantlike", {
|
||||
description = S("\"plantlike\" Drawtype Test Node"),
|
||||
drawtype = "plantlike",
|
||||
@ -235,7 +267,7 @@ minetest.register_node("testnodes:plantlike_waving", {
|
||||
|
||||
minetest.register_node("testnodes:plantlike_wallmounted", {
|
||||
description = S("Wallmounted \"plantlike\" Drawtype Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "plantlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
@ -366,7 +398,7 @@ minetest.register_node("testnodes:plantlike_rooted", {
|
||||
|
||||
minetest.register_node("testnodes:plantlike_rooted_wallmounted", {
|
||||
description = S("Wallmounted \"rooted_plantlike\" Drawtype Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "plantlike_rooted",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
|
@ -92,7 +92,7 @@ minetest.register_node("testnodes:mesh_color4dir", {
|
||||
-- Wallmounted mesh: pyramid
|
||||
minetest.register_node("testnodes:mesh_wallmounted", {
|
||||
description = S("Wallmounted Mesh Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "mesh",
|
||||
mesh = "testnodes_pyramid.obj",
|
||||
tiles = {"testnodes_mesh_stripes9.png"},
|
||||
@ -105,7 +105,7 @@ minetest.register_node("testnodes:mesh_wallmounted", {
|
||||
|
||||
minetest.register_node("testnodes:mesh_colorwallmounted", {
|
||||
description = S("Color Wallmounted Mesh Test Node").."\n"..
|
||||
S("param2 = color + wallmounted rotation (0..5, 8..13, ...)"),
|
||||
S("param2 = color + wallmounted rotation (0..7, 8..15, ...)"),
|
||||
drawtype = "mesh",
|
||||
mesh = "testnodes_pyramid.obj",
|
||||
tiles = {"testnodes_mesh_stripes10.png"},
|
||||
|
@ -180,3 +180,63 @@ minetest.register_node("testnodes:facedir_to_connect_to", {
|
||||
paramtype2 = "facedir",
|
||||
connect_sides = {"left", "top"},
|
||||
})
|
||||
|
||||
-- 3D sign and button:
|
||||
-- These are example nodes for more realistic example uses
|
||||
-- of wallmounted_rotate_vertical
|
||||
minetest.register_node("testnodes:sign3d", {
|
||||
description = S("Nodebox Sign, Nodebox Type \"fixed\""),
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
tiles = {
|
||||
"testnodes_sign3d.png",
|
||||
},
|
||||
groups = { dig_immediate = 3 },
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:sign3d_wallmounted", {
|
||||
description = S("Nodebox Sign, Nodebox Type \"wallmounted\""),
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
tiles = {
|
||||
"testnodes_sign3d.png^[colorize:#ff0000:127",
|
||||
},
|
||||
groups = { dig_immediate = 3 },
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.4375, 0.4375, -0.3125, 0.4375, 0.5, 0.3125},
|
||||
wall_bottom = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125},
|
||||
wall_side = {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:button", {
|
||||
description = S("Button Nodebox Test Node"),
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
tiles = {
|
||||
"testnodes_nodebox.png",
|
||||
},
|
||||
groups = { dig_immediate = 3 },
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = { -4/16, -8/16, -2/16, 4/16, -6/16, 2/16 },
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -80,7 +80,7 @@ minetest.register_node("testnodes:4dir_nodebox", {
|
||||
|
||||
minetest.register_node("testnodes:wallmounted", {
|
||||
description = S("Wallmounted Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_1w.png",
|
||||
@ -94,9 +94,25 @@ minetest.register_node("testnodes:wallmounted", {
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:wallmounted_rot", {
|
||||
description = S("Wallmounted Rotatable Test Node"),
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
tiles = {
|
||||
"testnodes_1w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_2w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_3w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_4w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_5w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_6w.png^[colorize:#FFFF00:40",
|
||||
},
|
||||
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:wallmounted_nodebox", {
|
||||
description = S("Wallmounted Nodebox Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
paramtype2 = "wallmounted",
|
||||
paramtype = "light",
|
||||
tiles = {
|
||||
@ -118,6 +134,30 @@ minetest.register_node("testnodes:wallmounted_nodebox", {
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:wallmounted_nodebox_rot", {
|
||||
description = S("Wallmounted Rotatable Nodebox Test Node"),
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
paramtype = "light",
|
||||
tiles = {
|
||||
"testnodes_1w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_2w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_3w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_4w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_5w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_6w.png^[colorize:#FFFF00:40",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = { -0.5, 0, -0.5, 0.5, 0.5, 0.5 },
|
||||
wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 },
|
||||
wall_side = { -0.5, -0.5, -0.5, 0, 0.5, 0.5 },
|
||||
},
|
||||
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:color", {
|
||||
description = S("Color Test Node").."\n"..
|
||||
S("param2 = color (0..255)"),
|
||||
@ -212,7 +252,7 @@ minetest.register_node("testnodes:color4dir_nodebox", {
|
||||
|
||||
minetest.register_node("testnodes:colorwallmounted", {
|
||||
description = S("Color Wallmounted Test Node").."\n"..
|
||||
S("param2 = color + wallmounted rotation (0..5, 8..13, ...)"),
|
||||
S("param2 = color + wallmounted rotation (0..7, 8..15, ...)"),
|
||||
paramtype2 = "colorwallmounted",
|
||||
paramtype = "light",
|
||||
palette = "testnodes_palette_wallmounted.png",
|
||||
@ -230,7 +270,7 @@ minetest.register_node("testnodes:colorwallmounted", {
|
||||
|
||||
minetest.register_node("testnodes:colorwallmounted_nodebox", {
|
||||
description = S("Color Wallmounted Nodebox Test Node").."\n"..
|
||||
S("param2 = color + wallmounted rotation (0..5, 8..13, ...)"),
|
||||
S("param2 = color + wallmounted rotation (0..7, 8..15, ...)"),
|
||||
paramtype2 = "colorwallmounted",
|
||||
paramtype = "light",
|
||||
palette = "testnodes_palette_wallmounted.png",
|
||||
|
@ -61,8 +61,8 @@ minetest.register_node("testnodes:attached", {
|
||||
-- when the node it attaches to is gone.
|
||||
minetest.register_node("testnodes:attached_wallmounted", {
|
||||
description = S("Wallmounted Attached Node").."\n"..
|
||||
S("Attaches to wall; drops as item if neighbor node is gone").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("Attaches to solid node it was placed on; drops as item if neighbor node is gone").."\n"..
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_attachedw_top.png",
|
||||
@ -72,9 +72,29 @@ minetest.register_node("testnodes:attached_wallmounted", {
|
||||
groups = { attached_node = 1, dig_immediate = 3 },
|
||||
})
|
||||
|
||||
-- This node attaches to the side of a node and drops as item
|
||||
-- when the node it attaches to is gone.
|
||||
-- Also adds vertical 90° rotation variants.
|
||||
minetest.register_node("testnodes:attached_wallmounted_rot", {
|
||||
description = S("Rotatable Wallmounted Attached Node").."\n"..
|
||||
S("Attaches to solid node it was placed on; drops as item if neighbor node is gone").."\n"..
|
||||
S("param2 = wallmounted rotation (0..7)").."\n"..
|
||||
S("May be rotated by 90° if placed at floor or ceiling"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_attachedwr_top.png",
|
||||
"testnodes_attachedwr_bottom.png",
|
||||
"testnodes_attachedwr_side.png",
|
||||
},
|
||||
wallmounted_rotate_vertical = true,
|
||||
groups = { attached_node = 1, dig_immediate = 3 },
|
||||
})
|
||||
|
||||
-- Wallmounted node that always attaches to the floor
|
||||
minetest.register_node("testnodes:attached_wallmounted_floor", {
|
||||
description = S("Floor-Attached Wallmounted Node"),
|
||||
description = S("Floor-Attached Wallmounted Node").."\n"..
|
||||
S("Drops as item if no solid node below (regardless of rotation)").."\n"..
|
||||
S("param2 = wallmounted rotation (visual only) (0..7)"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_attached_top.png",
|
||||
@ -85,10 +105,28 @@ minetest.register_node("testnodes:attached_wallmounted_floor", {
|
||||
color = "#FF8080",
|
||||
})
|
||||
|
||||
-- Wallmounted node that always attaches to the floor.
|
||||
-- Also adds 90° rotation variants.
|
||||
minetest.register_node("testnodes:attached_wallmounted_floor_rot", {
|
||||
description = S("Rotatable Floor-Attached Wallmounted Node").."\n"..
|
||||
S("Drops as item if no solid node below (regardless of rotation)").."\n"..
|
||||
S("param2 = wallmounted rotation (visual only) (0..7)").."\n"..
|
||||
S("May be rotated by 90° if placed at floor or ceiling"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_attachedfr_top.png",
|
||||
"testnodes_attachedfr_bottom.png",
|
||||
"testnodes_attachedfr_side.png",
|
||||
},
|
||||
wallmounted_rotate_vertical = true,
|
||||
groups = { attached_node = 3, dig_immediate = 3 },
|
||||
})
|
||||
|
||||
-- This node attaches to the ceiling and drops as item
|
||||
-- when the ceiling is gone.
|
||||
minetest.register_node("testnodes:attached_top", {
|
||||
description = S("Ceiling-Attached Node"),
|
||||
description = S("Ceiling-Attached Node").."\n"..
|
||||
S("Drops as item if no solid node above"),
|
||||
tiles = {
|
||||
"testnodes_attached_bottom.png",
|
||||
"testnodes_attached_top.png",
|
||||
@ -99,7 +137,9 @@ minetest.register_node("testnodes:attached_top", {
|
||||
|
||||
-- Same as wallmounted attached, but for facedir
|
||||
minetest.register_node("testnodes:attached_facedir", {
|
||||
description = S("Facedir Attached Node"),
|
||||
description = S("Facedir Attached Node").."\n"..
|
||||
S("Attaches to a neighboring solid node; drops as item if that node is gone").."\n"..
|
||||
S("param2 = facedir rotation (0..23)"),
|
||||
paramtype2 = "facedir",
|
||||
tiles = {
|
||||
"testnodes_attachedf_side.png^[transformR180",
|
||||
@ -114,7 +154,9 @@ minetest.register_node("testnodes:attached_facedir", {
|
||||
|
||||
-- Same as facedir attached, but for 4dir
|
||||
minetest.register_node("testnodes:attached_4dir", {
|
||||
description = S("4dir Attached Node"),
|
||||
description = S("4dir Attached Node").."\n"..
|
||||
S("Attaches to the side of a solid node; drops as item if that node is gone").."\n"..
|
||||
S("param2 = 4dir rotation (0..3)"),
|
||||
paramtype2 = "4dir",
|
||||
tiles = {
|
||||
"testnodes_attached4_side.png^[transformR180",
|
||||
@ -621,3 +663,23 @@ minetest.register_node("testnodes:post_effect_color_shaded_true", {
|
||||
is_ground_content = false,
|
||||
groups = {dig_immediate=3},
|
||||
})
|
||||
|
||||
-- Pointability
|
||||
|
||||
-- Register wrapper for compactness
|
||||
local function register_pointable_test_node(name, description, pointable)
|
||||
local texture = "testnodes_"..name..".png"
|
||||
minetest.register_node("testnodes:"..name, {
|
||||
description = S(description),
|
||||
tiles = {texture},
|
||||
drawtype = "glasslike_framed",
|
||||
paramtype = "light",
|
||||
walkable = false,
|
||||
pointable = pointable,
|
||||
groups = {dig_immediate=3, [name.."_test"]=1},
|
||||
})
|
||||
end
|
||||
|
||||
register_pointable_test_node("pointable", "Pointable Node", true)
|
||||
register_pointable_test_node("not_pointable", "Not Pointable Node", false)
|
||||
register_pointable_test_node("blocking_pointable", "Blocking Pointable Node", "blocking")
|
||||
|
After Width: | Height: | Size: 106 B |
After Width: | Height: | Size: 103 B |
After Width: | Height: | Size: 93 B |
After Width: | Height: | Size: 265 B |
After Width: | Height: | Size: 173 B |
After Width: | Height: | Size: 153 B |
After Width: | Height: | Size: 150 B |
After Width: | Height: | Size: 152 B |
BIN
games/devtest/mods/testnodes/textures/testnodes_pointable.png
Normal file
After Width: | Height: | Size: 144 B |
BIN
games/devtest/mods/testnodes/textures/testnodes_sign3d.png
Normal file
After Width: | Height: | Size: 214 B |
@ -7,6 +7,20 @@ dofile(minetest.get_modpath("testtools") .. "/light.lua")
|
||||
dofile(minetest.get_modpath("testtools") .. "/privatizer.lua")
|
||||
dofile(minetest.get_modpath("testtools") .. "/particles.lua")
|
||||
|
||||
local pointabilities_nodes = {
|
||||
nodes = {
|
||||
["group:blocking_pointable_test"] = true,
|
||||
["group:not_pointable_test"] = true,
|
||||
},
|
||||
}
|
||||
|
||||
local pointabilities_objects = {
|
||||
objects = {
|
||||
["group:blocking_pointable_test"] = true,
|
||||
["group:not_pointable_test"] = true,
|
||||
},
|
||||
}
|
||||
|
||||
minetest.register_tool("testtools:param2tool", {
|
||||
description = S("Param2 Tool") .."\n"..
|
||||
S("Modify param2 value of nodes") .."\n"..
|
||||
@ -16,6 +30,7 @@ minetest.register_tool("testtools:param2tool", {
|
||||
S("Sneak+Place: -8"),
|
||||
inventory_image = "testtools_param2tool.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_nodes,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
if pointed_thing.type ~= "node" or (not pos) then
|
||||
@ -58,6 +73,7 @@ minetest.register_tool("testtools:node_setter", {
|
||||
S("Place in air: Manually select a node"),
|
||||
inventory_image = "testtools_node_setter.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_nodes,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
if pointed_thing.type == "nothing" then
|
||||
@ -118,6 +134,10 @@ minetest.register_tool("testtools:remover", {
|
||||
S("Punch: Remove pointed node or object"),
|
||||
inventory_image = "testtools_remover.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = {
|
||||
nodes = pointabilities_nodes.nodes,
|
||||
objects = pointabilities_objects.objects,
|
||||
},
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
if pointed_thing.type == "node" and pos ~= nil then
|
||||
@ -139,6 +159,7 @@ minetest.register_tool("testtools:falling_node_tool", {
|
||||
S("Place: Move pointed node 2 units upwards, then make it fall"),
|
||||
inventory_image = "testtools_falling_node_tool.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_nodes,
|
||||
on_place = function(itemstack, user, pointed_thing)
|
||||
-- Teleport node 1-2 units upwards (if possible) and make it fall
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
@ -192,6 +213,7 @@ minetest.register_tool("testtools:rotator", {
|
||||
S("Aux1+Punch: Roll"),
|
||||
inventory_image = "testtools_entity_rotator.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if pointed_thing.type ~= "object" then
|
||||
return
|
||||
@ -250,6 +272,7 @@ minetest.register_tool("testtools:object_mover", {
|
||||
S("Sneak+Place: Decrease distance"),
|
||||
inventory_image = "testtools_object_mover.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_place = mover_config,
|
||||
on_secondary_use = mover_config,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
@ -296,6 +319,7 @@ minetest.register_tool("testtools:entity_scaler", {
|
||||
S("Sneak+Punch: Decrease scale"),
|
||||
inventory_image = "testtools_entity_scaler.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if pointed_thing.type ~= "object" then
|
||||
return
|
||||
@ -355,6 +379,7 @@ minetest.register_tool("testtools:branding_iron", {
|
||||
S("Devices that accept the returned name also accept \"player:<playername>\" for players."),
|
||||
inventory_image = "testtools_branding_iron.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(_itemstack, user, pointed_thing)
|
||||
local obj
|
||||
local msg
|
||||
@ -499,6 +524,7 @@ minetest.register_tool("testtools:object_editor", {
|
||||
S("Punch air: Edit yourself"),
|
||||
inventory_image = "testtools_object_editor.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if user and user:is_player() then
|
||||
local name = user:get_player_name()
|
||||
@ -586,6 +612,7 @@ minetest.register_tool("testtools:object_attacher", {
|
||||
S("Aux1+Sneak+Place: Decrease attachment rotation"),
|
||||
inventory_image = "testtools_object_attacher.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_place = attacher_config,
|
||||
on_secondary_use = attacher_config,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
@ -679,6 +706,7 @@ minetest.register_tool("testtools:children_getter", {
|
||||
S("Punch air to show your own 'children'"),
|
||||
inventory_image = "testtools_children_getter.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if user and user:is_player() then
|
||||
local name = user:get_player_name()
|
||||
@ -998,3 +1026,41 @@ minetest.register_on_leaveplayer(function(player)
|
||||
meta_latest_keylist[name] = nil
|
||||
node_meta_posses[name] = nil
|
||||
end)
|
||||
|
||||
-- Pointing Staffs
|
||||
|
||||
minetest.register_tool("testtools:blocked_pointing_staff", {
|
||||
description = S("Blocked Pointing Staff").."\n"..
|
||||
S("Can point the Blocking Pointable Node/Object and "..
|
||||
"the Pointable Node/Object is point blocking."),
|
||||
inventory_image = "testtools_blocked_pointing_staff.png",
|
||||
pointabilities = {
|
||||
nodes = {
|
||||
["testnodes:blocking_pointable"] = true,
|
||||
["group:pointable_test"] = "blocking"
|
||||
},
|
||||
objects = {
|
||||
["testentities:blocking_pointable"] = true,
|
||||
["group:pointable_test"] = "blocking"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_tool("testtools:ultimate_pointing_staff", {
|
||||
description = S("Ultimate Pointing Staff").."\n"..
|
||||
S("Can point all pointable test nodes, objects and liquids."),
|
||||
inventory_image = "testtools_ultimate_pointing_staff.png",
|
||||
liquids_pointable = true,
|
||||
pointabilities = {
|
||||
nodes = {
|
||||
["group:blocking_pointable_test"] = true,
|
||||
["group:pointable_test"] = true,
|
||||
["testnodes:not_pointable"] = true
|
||||
},
|
||||
objects = {
|
||||
["group:blocking_pointable_test"] = true,
|
||||
["group:pointable_test"] = true,
|
||||
["testentities:not_pointable"] = true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
After Width: | Height: | Size: 136 B |
After Width: | Height: | Size: 136 B |
@ -1,10 +1,37 @@
|
||||
local function test_random()
|
||||
-- Try out PseudoRandom
|
||||
local pseudo = PseudoRandom(13)
|
||||
assert(pseudo:next() == 22290)
|
||||
assert(pseudo:next() == 13854)
|
||||
local function test_pseudo_random()
|
||||
-- We have comprehensive unit tests in C++, this is just to make sure the API code isn't messing up
|
||||
local gen1 = PseudoRandom(13)
|
||||
assert(gen1:next() == 22290)
|
||||
assert(gen1:next() == 13854)
|
||||
|
||||
local gen2 = PseudoRandom(gen1:get_state())
|
||||
for n = 0, 16 do
|
||||
assert(gen1:next() == gen2:next())
|
||||
end
|
||||
|
||||
local pr3 = PseudoRandom(-101)
|
||||
assert(pr3:next(0, 100) == 35)
|
||||
-- unusual case that is normally disallowed:
|
||||
assert(pr3:next(10000, 42767) == 12485)
|
||||
end
|
||||
unittests.register("test_random", test_random)
|
||||
unittests.register("test_pseudo_random", test_pseudo_random)
|
||||
|
||||
local function test_pcg_random()
|
||||
-- We have comprehensive unit tests in C++, this is just to make sure the API code isn't messing up
|
||||
local gen1 = PcgRandom(55)
|
||||
|
||||
for n = 0, 16 do
|
||||
gen1:next()
|
||||
end
|
||||
|
||||
local gen2 = PcgRandom(26)
|
||||
gen2:set_state(gen1:get_state())
|
||||
|
||||
for n = 16, 32 do
|
||||
assert(gen1:next() == gen2:next())
|
||||
end
|
||||
end
|
||||
unittests.register("test_pcg_random", test_pcg_random)
|
||||
|
||||
local function test_dynamic_media(cb, player)
|
||||
if core.get_player_information(player:get_player_name()).protocol_version < 40 then
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Catch v2.13.9
|
||||
* Generated: 2022-04-12 22:37:23.260201
|
||||
* Catch v2.13.10
|
||||
* Generated: 2022-10-16 11:01:23.452308
|
||||
* ----------------------------------------------------------
|
||||
* This file has been merged from multiple headers. Please don't edit it directly
|
||||
* Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved.
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 13
|
||||
#define CATCH_VERSION_PATCH 9
|
||||
#define CATCH_VERSION_PATCH 10
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang system_header
|
||||
@ -7395,8 +7395,6 @@ namespace Catch {
|
||||
template <typename T, bool Destruct>
|
||||
struct ObjectStorage
|
||||
{
|
||||
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
||||
|
||||
ObjectStorage() : data() {}
|
||||
|
||||
ObjectStorage(const ObjectStorage& other)
|
||||
@ -7439,7 +7437,7 @@ namespace Catch {
|
||||
return *static_cast<T*>(static_cast<void*>(&data));
|
||||
}
|
||||
|
||||
TStorage data;
|
||||
struct { alignas(T) unsigned char data[sizeof(T)]; } data;
|
||||
};
|
||||
}
|
||||
|
||||
@ -7949,7 +7947,7 @@ namespace Catch {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
|
||||
#elif defined(__aarch64__)
|
||||
#define CATCH_TRAP() __asm__(".inst 0xd4200000")
|
||||
#define CATCH_TRAP() __asm__(".inst 0xd43e0000")
|
||||
#endif
|
||||
|
||||
#elif defined(CATCH_PLATFORM_IPHONE)
|
||||
@ -13558,7 +13556,7 @@ namespace Catch {
|
||||
|
||||
// Handle list request
|
||||
if( Option<std::size_t> listed = list( m_config ) )
|
||||
return static_cast<int>( *listed );
|
||||
return (std::min) (MaxExitCode, static_cast<int>(*listed));
|
||||
|
||||
TestGroup tests { m_config };
|
||||
auto const totals = tests.execute();
|
||||
@ -15391,7 +15389,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 2, 13, 9, "", 0 );
|
||||
static Version version( 2, 13, 10, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
@ -16314,7 +16312,7 @@ class Duration {
|
||||
Unit m_units;
|
||||
|
||||
public:
|
||||
explicit Duration(double inNanoseconds, Unit units = Unit::Microseconds)
|
||||
explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
|
||||
: m_inNanoseconds(inNanoseconds),
|
||||
m_units(units) {
|
||||
if (m_units == Unit::Auto) {
|
||||
@ -16364,7 +16362,7 @@ public:
|
||||
|
||||
}
|
||||
friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
|
||||
return os << std::fixed << duration.value() << ' ' << duration.unitsAsString();
|
||||
return os << duration.value() << ' ' << duration.unitsAsString();
|
||||
}
|
||||
};
|
||||
} // end anon namespace
|
||||
@ -17526,12 +17524,20 @@ namespace Catch {
|
||||
|
||||
#ifndef __OBJC__
|
||||
|
||||
#ifndef CATCH_INTERNAL_CDECL
|
||||
#ifdef _MSC_VER
|
||||
#define CATCH_INTERNAL_CDECL __cdecl
|
||||
#else
|
||||
#define CATCH_INTERNAL_CDECL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
|
||||
// Standard C/C++ Win32 Unicode wmain entry point
|
||||
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
|
||||
extern "C" int CATCH_INTERNAL_CDECL wmain (int argc, wchar_t * argv[], wchar_t * []) {
|
||||
#else
|
||||
// Standard C/C++ main entry point
|
||||
int main (int argc, char * argv[]) {
|
||||
int CATCH_INTERNAL_CDECL main (int argc, char * argv[]) {
|
||||
#endif
|
||||
|
||||
return Catch::Session().run( argc, argv );
|
||||
|
@ -1,27 +1,39 @@
|
||||
/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
|
||||
|
||||
Contributed to the GNU project by Niels Möller
|
||||
Additional functionalities and improvements by Marco Bodrato.
|
||||
|
||||
Copyright 1991-1997, 1999-2019 Free Software Foundation, Inc.
|
||||
Copyright 1991-1997, 1999-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU MP Library.
|
||||
|
||||
The GNU MP Library 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 3 of the License, or (at your
|
||||
option) any later version.
|
||||
it under the terms of either:
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any
|
||||
later version.
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
The GNU MP Library 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.
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
||||
You should have received copies of the GNU General Public License and the
|
||||
GNU Lesser General Public License along with the GNU MP Library. If not,
|
||||
see https://www.gnu.org/licenses/. */
|
||||
|
||||
/* NOTE: All functions in this file which are not declared in
|
||||
mini-gmp.h are internal, and are not intended to be compatible
|
||||
neither with GMP nor with future versions of mini-gmp. */
|
||||
with GMP or with future versions of mini-gmp. */
|
||||
|
||||
/* Much of the material copied from GMP files, including: gmp-impl.h,
|
||||
longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
|
||||
@ -43,7 +55,7 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Macros */
|
||||
#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
|
||||
|
||||
@ -79,6 +91,7 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
||||
#define gmp_assert_nocarry(x) do { \
|
||||
mp_limb_t __cy = (x); \
|
||||
assert (__cy == 0); \
|
||||
(void) (__cy); \
|
||||
} while (0)
|
||||
|
||||
#define gmp_clz(count, x) do { \
|
||||
@ -137,6 +150,7 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
||||
mp_limb_t __x0, __x1, __x2, __x3; \
|
||||
unsigned __ul, __vl, __uh, __vh; \
|
||||
mp_limb_t __u = (u), __v = (v); \
|
||||
assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t)); \
|
||||
\
|
||||
__ul = __u & GMP_LLIMB_MASK; \
|
||||
__uh = __u >> (GMP_LIMB_BITS / 2); \
|
||||
@ -158,12 +172,19 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* If mp_limb_t is of size smaller than int, plain u*v implies
|
||||
automatic promotion to *signed* int, and then multiply may overflow
|
||||
and cause undefined behavior. Explicitly cast to unsigned int for
|
||||
that case. */
|
||||
#define gmp_umullo_limb(u, v) \
|
||||
((sizeof(mp_limb_t) >= sizeof(int)) ? (u)*(v) : (unsigned int)(u) * (v))
|
||||
|
||||
#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \
|
||||
do { \
|
||||
mp_limb_t _qh, _ql, _r, _mask; \
|
||||
gmp_umul_ppmm (_qh, _ql, (nh), (di)); \
|
||||
gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \
|
||||
_r = (nl) - _qh * (d); \
|
||||
_r = (nl) - gmp_umullo_limb (_qh, (d)); \
|
||||
_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \
|
||||
_qh += _mask; \
|
||||
_r += _mask & (d); \
|
||||
@ -184,7 +205,7 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
||||
gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \
|
||||
\
|
||||
/* Compute the two most significant limbs of n - q'd */ \
|
||||
(r1) = (n1) - (d1) * (q); \
|
||||
(r1) = (n1) - gmp_umullo_limb ((d1), (q)); \
|
||||
gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \
|
||||
gmp_umul_ppmm (_t1, _t0, (d0), (q)); \
|
||||
gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \
|
||||
@ -340,20 +361,27 @@ mp_set_memory_functions (void *(*alloc_func) (size_t),
|
||||
gmp_free_func = free_func;
|
||||
}
|
||||
|
||||
#define gmp_xalloc(size) ((*gmp_allocate_func)((size)))
|
||||
#define gmp_free(p) ((*gmp_free_func) ((p), 0))
|
||||
#define gmp_alloc(size) ((*gmp_allocate_func)((size)))
|
||||
#define gmp_free(p, size) ((*gmp_free_func) ((p), (size)))
|
||||
#define gmp_realloc(ptr, old_size, size) ((*gmp_reallocate_func)(ptr, old_size, size))
|
||||
|
||||
static mp_ptr
|
||||
gmp_xalloc_limbs (mp_size_t size)
|
||||
gmp_alloc_limbs (mp_size_t size)
|
||||
{
|
||||
return (mp_ptr) gmp_xalloc (size * sizeof (mp_limb_t));
|
||||
return (mp_ptr) gmp_alloc (size * sizeof (mp_limb_t));
|
||||
}
|
||||
|
||||
static mp_ptr
|
||||
gmp_xrealloc_limbs (mp_ptr old, mp_size_t size)
|
||||
gmp_realloc_limbs (mp_ptr old, mp_size_t old_size, mp_size_t size)
|
||||
{
|
||||
assert (size > 0);
|
||||
return (mp_ptr) (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
|
||||
return (mp_ptr) gmp_realloc (old, old_size * sizeof (mp_limb_t), size * sizeof (mp_limb_t));
|
||||
}
|
||||
|
||||
static void
|
||||
gmp_free_limbs (mp_ptr old, mp_size_t size)
|
||||
{
|
||||
gmp_free (old, size * sizeof (mp_limb_t));
|
||||
}
|
||||
|
||||
|
||||
@ -765,6 +793,7 @@ mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
|
||||
mp_limb_t p, ql;
|
||||
unsigned ul, uh, qh;
|
||||
|
||||
assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t));
|
||||
/* For notation, let b denote the half-limb base, so that B = b^2.
|
||||
Split u1 = b uh + ul. */
|
||||
ul = u1 & GMP_LLIMB_MASK;
|
||||
@ -945,11 +974,17 @@ mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
|
||||
mp_limb_t d, di;
|
||||
mp_limb_t r;
|
||||
mp_ptr tp = NULL;
|
||||
mp_size_t tn = 0;
|
||||
|
||||
if (inv->shift > 0)
|
||||
{
|
||||
/* Shift, reusing qp area if possible. In-place shift if qp == np. */
|
||||
tp = qp ? qp : gmp_xalloc_limbs (nn);
|
||||
tp = qp;
|
||||
if (!tp)
|
||||
{
|
||||
tn = nn;
|
||||
tp = gmp_alloc_limbs (tn);
|
||||
}
|
||||
r = mpn_lshift (tp, np, nn, inv->shift);
|
||||
np = tp;
|
||||
}
|
||||
@ -966,8 +1001,8 @@ mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
|
||||
if (qp)
|
||||
qp[nn] = q;
|
||||
}
|
||||
if ((inv->shift > 0) && (tp != qp))
|
||||
gmp_free (tp);
|
||||
if (tn)
|
||||
gmp_free_limbs (tp, tn);
|
||||
|
||||
return r >> inv->shift;
|
||||
}
|
||||
@ -1125,13 +1160,13 @@ mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
|
||||
mpn_div_qr_invert (&inv, dp, dn);
|
||||
if (dn > 2 && inv.shift > 0)
|
||||
{
|
||||
tp = gmp_xalloc_limbs (dn);
|
||||
tp = gmp_alloc_limbs (dn);
|
||||
gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
|
||||
dp = tp;
|
||||
}
|
||||
mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
|
||||
if (tp)
|
||||
gmp_free (tp);
|
||||
gmp_free_limbs (tp, dn);
|
||||
}
|
||||
|
||||
|
||||
@ -1307,29 +1342,26 @@ mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
|
||||
unsigned bits)
|
||||
{
|
||||
mp_size_t rn;
|
||||
size_t j;
|
||||
mp_limb_t limb;
|
||||
unsigned shift;
|
||||
|
||||
for (j = sn, rn = 0, shift = 0; j-- > 0; )
|
||||
for (limb = 0, rn = 0, shift = 0; sn-- > 0; )
|
||||
{
|
||||
if (shift == 0)
|
||||
limb |= (mp_limb_t) sp[sn] << shift;
|
||||
shift += bits;
|
||||
if (shift >= GMP_LIMB_BITS)
|
||||
{
|
||||
rp[rn++] = sp[j];
|
||||
shift += bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
rp[rn-1] |= (mp_limb_t) sp[j] << shift;
|
||||
shift += bits;
|
||||
if (shift >= GMP_LIMB_BITS)
|
||||
{
|
||||
shift -= GMP_LIMB_BITS;
|
||||
if (shift > 0)
|
||||
rp[rn++] = (mp_limb_t) sp[j] >> (bits - shift);
|
||||
}
|
||||
shift -= GMP_LIMB_BITS;
|
||||
rp[rn++] = limb;
|
||||
/* Next line is correct also if shift == 0,
|
||||
bits == 8, and mp_limb_t == unsigned char. */
|
||||
limb = (unsigned int) sp[sn] >> (bits - shift);
|
||||
}
|
||||
}
|
||||
rn = mpn_normalized_size (rp, rn);
|
||||
if (limb != 0)
|
||||
rp[rn++] = limb;
|
||||
else
|
||||
rn = mpn_normalized_size (rp, rn);
|
||||
return rn;
|
||||
}
|
||||
|
||||
@ -1417,14 +1449,14 @@ mpz_init2 (mpz_t r, mp_bitcnt_t bits)
|
||||
|
||||
r->_mp_alloc = rn;
|
||||
r->_mp_size = 0;
|
||||
r->_mp_d = gmp_xalloc_limbs (rn);
|
||||
r->_mp_d = gmp_alloc_limbs (rn);
|
||||
}
|
||||
|
||||
void
|
||||
mpz_clear (mpz_t r)
|
||||
{
|
||||
if (r->_mp_alloc)
|
||||
gmp_free (r->_mp_d);
|
||||
gmp_free_limbs (r->_mp_d, r->_mp_alloc);
|
||||
}
|
||||
|
||||
static mp_ptr
|
||||
@ -1433,9 +1465,9 @@ mpz_realloc (mpz_t r, mp_size_t size)
|
||||
size = GMP_MAX (size, 1);
|
||||
|
||||
if (r->_mp_alloc)
|
||||
r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size);
|
||||
r->_mp_d = gmp_realloc_limbs (r->_mp_d, r->_mp_alloc, size);
|
||||
else
|
||||
r->_mp_d = gmp_xalloc_limbs (size);
|
||||
r->_mp_d = gmp_alloc_limbs (size);
|
||||
r->_mp_alloc = size;
|
||||
|
||||
if (GMP_ABS (r->_mp_size) > size)
|
||||
@ -1530,8 +1562,7 @@ mpz_init_set (mpz_t r, const mpz_t x)
|
||||
int
|
||||
mpz_fits_slong_p (const mpz_t u)
|
||||
{
|
||||
return (LONG_MAX + LONG_MIN == 0 || mpz_cmp_ui (u, LONG_MAX) <= 0) &&
|
||||
mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, LONG_MIN)) <= 0;
|
||||
return mpz_cmp_si (u, LONG_MAX) <= 0 && mpz_cmp_si (u, LONG_MIN) >= 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1554,6 +1585,30 @@ mpz_fits_ulong_p (const mpz_t u)
|
||||
return us >= 0 && mpn_absfits_ulong_p (u->_mp_d, us);
|
||||
}
|
||||
|
||||
int
|
||||
mpz_fits_sint_p (const mpz_t u)
|
||||
{
|
||||
return mpz_cmp_si (u, INT_MAX) <= 0 && mpz_cmp_si (u, INT_MIN) >= 0;
|
||||
}
|
||||
|
||||
int
|
||||
mpz_fits_uint_p (const mpz_t u)
|
||||
{
|
||||
return u->_mp_size >= 0 && mpz_cmpabs_ui (u, UINT_MAX) <= 0;
|
||||
}
|
||||
|
||||
int
|
||||
mpz_fits_sshort_p (const mpz_t u)
|
||||
{
|
||||
return mpz_cmp_si (u, SHRT_MAX) <= 0 && mpz_cmp_si (u, SHRT_MIN) >= 0;
|
||||
}
|
||||
|
||||
int
|
||||
mpz_fits_ushort_p (const mpz_t u)
|
||||
{
|
||||
return u->_mp_size >= 0 && mpz_cmpabs_ui (u, USHRT_MAX) <= 0;
|
||||
}
|
||||
|
||||
long int
|
||||
mpz_get_si (const mpz_t u)
|
||||
{
|
||||
@ -1891,9 +1946,8 @@ mpz_neg (mpz_t r, const mpz_t u)
|
||||
void
|
||||
mpz_swap (mpz_t u, mpz_t v)
|
||||
{
|
||||
MP_SIZE_T_SWAP (u->_mp_size, v->_mp_size);
|
||||
MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc);
|
||||
MP_PTR_SWAP (u->_mp_d, v->_mp_d);
|
||||
MPN_PTR_SWAP (u->_mp_d, u->_mp_size, v->_mp_d, v->_mp_size);
|
||||
}
|
||||
|
||||
|
||||
@ -2676,7 +2730,7 @@ mpz_make_odd (mpz_t r)
|
||||
|
||||
assert (r->_mp_size > 0);
|
||||
/* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
|
||||
shift = mpn_common_scan (r->_mp_d[0], 0, r->_mp_d, 0, 0);
|
||||
shift = mpn_scan1 (r->_mp_d, 0);
|
||||
mpz_tdiv_q_2exp (r, r, shift);
|
||||
|
||||
return shift;
|
||||
@ -2733,9 +2787,13 @@ mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v)
|
||||
|
||||
if (tv->_mp_size == 1)
|
||||
{
|
||||
mp_limb_t vl = tv->_mp_d[0];
|
||||
mp_limb_t ul = mpz_tdiv_ui (tu, vl);
|
||||
mpz_set_ui (g, mpn_gcd_11 (ul, vl));
|
||||
mp_limb_t *gp;
|
||||
|
||||
mpz_tdiv_r (tu, tu, tv);
|
||||
gp = MPZ_REALLOC (g, 1); /* gp = mpz_limbs_modify (g, 1); */
|
||||
*gp = mpn_gcd_11 (tu->_mp_d[0], tv->_mp_d[0]);
|
||||
|
||||
g->_mp_size = *gp != 0; /* mpz_limbs_finish (g, 1); */
|
||||
break;
|
||||
}
|
||||
mpz_sub (tu, tu, tv);
|
||||
@ -2824,7 +2882,6 @@ mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
|
||||
* s0 = 0, s1 = 2^vz
|
||||
*/
|
||||
|
||||
mpz_setbit (t0, uz);
|
||||
mpz_tdiv_qr (t1, tu, tu, tv);
|
||||
mpz_mul_2exp (t1, t1, uz);
|
||||
|
||||
@ -2835,8 +2892,7 @@ mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
|
||||
{
|
||||
mp_bitcnt_t shift;
|
||||
shift = mpz_make_odd (tu);
|
||||
mpz_mul_2exp (t0, t0, shift);
|
||||
mpz_mul_2exp (s0, s0, shift);
|
||||
mpz_setbit (t0, uz + shift);
|
||||
power += shift;
|
||||
|
||||
for (;;)
|
||||
@ -2874,6 +2930,8 @@ mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
|
||||
power += shift;
|
||||
}
|
||||
}
|
||||
else
|
||||
mpz_setbit (t0, uz);
|
||||
|
||||
/* Now tv = odd part of gcd, and -s0 and t0 are corresponding
|
||||
cofactors. */
|
||||
@ -3048,7 +3106,7 @@ mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
|
||||
|
||||
if (en == 0)
|
||||
{
|
||||
mpz_set_ui (r, 1);
|
||||
mpz_set_ui (r, mpz_cmpabs_ui (m, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3062,7 +3120,7 @@ mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
|
||||
one, using a *normalized* m. */
|
||||
minv.shift = 0;
|
||||
|
||||
tp = gmp_xalloc_limbs (mn);
|
||||
tp = gmp_alloc_limbs (mn);
|
||||
gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
|
||||
mp = tp;
|
||||
}
|
||||
@ -3128,7 +3186,7 @@ mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
|
||||
tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
|
||||
}
|
||||
if (tp)
|
||||
gmp_free (tp);
|
||||
gmp_free_limbs (tp, mn);
|
||||
|
||||
mpz_swap (r, tr);
|
||||
mpz_clear (tr);
|
||||
@ -3150,6 +3208,7 @@ void
|
||||
mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
|
||||
{
|
||||
int sgn;
|
||||
mp_bitcnt_t bc;
|
||||
mpz_t t, u;
|
||||
|
||||
sgn = y->_mp_size < 0;
|
||||
@ -3168,7 +3227,8 @@ mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
|
||||
|
||||
mpz_init (u);
|
||||
mpz_init (t);
|
||||
mpz_setbit (t, mpz_sizeinbase (y, 2) / z + 1);
|
||||
bc = (mpz_sizeinbase (y, 2) - 1) / z + 1;
|
||||
mpz_setbit (t, bc);
|
||||
|
||||
if (z == 2) /* simplify sqrt loop: z-1 == 1 */
|
||||
do {
|
||||
@ -3339,13 +3399,15 @@ gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b)
|
||||
gmp_ctz(c, a);
|
||||
a >>= 1;
|
||||
|
||||
do
|
||||
for (;;)
|
||||
{
|
||||
a >>= c;
|
||||
/* (2/b) = -1 if b = 3 or 5 mod 8 */
|
||||
bit ^= c & (b ^ (b >> 1));
|
||||
if (a < b)
|
||||
{
|
||||
if (a == 0)
|
||||
return bit & 1 ? -1 : 1;
|
||||
bit ^= a & b;
|
||||
a = b - a;
|
||||
b -= a;
|
||||
@ -3359,9 +3421,6 @@ gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b)
|
||||
gmp_ctz(c, a);
|
||||
++c;
|
||||
}
|
||||
while (b > 0);
|
||||
|
||||
return bit & 1 ? -1 : 1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3407,7 +3466,7 @@ gmp_lucas_mod (mpz_t V, mpz_t Qk, long Q,
|
||||
gmp_lucas_step_k_2k (V, Qk, n);
|
||||
|
||||
/* A step k->k+1 is performed if the bit in $n$ is 1 */
|
||||
/* mpz_tstbit(n,bs) or the the bit is 0 in $n$ but */
|
||||
/* mpz_tstbit(n,bs) or the bit is 0 in $n$ but */
|
||||
/* should be 1 in $n+1$ (bs == b0) */
|
||||
if (b0 == bs || mpz_tstbit (n, bs))
|
||||
{
|
||||
@ -3476,7 +3535,8 @@ gmp_stronglucas (const mpz_t x, mpz_t Qk)
|
||||
mpz_init (V);
|
||||
|
||||
/* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
|
||||
b0 = mpz_scan0 (n, 0);
|
||||
b0 = mpn_common_scan (~ n->_mp_d[0], 0, n->_mp_d, n->_mp_size, GMP_LIMB_MAX);
|
||||
/* b0 = mpz_scan0 (n, 0); */
|
||||
|
||||
/* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
|
||||
Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2);
|
||||
@ -3508,11 +3568,6 @@ gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y,
|
||||
mpz_powm_ui (y, y, 2, n);
|
||||
if (mpz_cmp (y, nm1) == 0)
|
||||
return 1;
|
||||
/* y == 1 means that the previous y was a non-trivial square root
|
||||
of 1 (mod n). y == 0 means that n is a power of the base.
|
||||
In either case, n is not prime. */
|
||||
if (mpz_cmp_ui (y, 1) <= 0)
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -3558,7 +3613,8 @@ mpz_probab_prime_p (const mpz_t n, int reps)
|
||||
/* Find q and k, where q is odd and n = 1 + 2**k * q. */
|
||||
mpz_abs (nm1, n);
|
||||
nm1->_mp_d[0] -= 1;
|
||||
k = mpz_scan1 (nm1, 0);
|
||||
/* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
|
||||
k = mpn_scan1 (nm1->_mp_d, 0);
|
||||
mpz_tdiv_q_2exp (q, nm1, k);
|
||||
|
||||
/* BPSW test */
|
||||
@ -4133,7 +4189,7 @@ mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
|
||||
size_t
|
||||
mpz_sizeinbase (const mpz_t u, int base)
|
||||
{
|
||||
mp_size_t un;
|
||||
mp_size_t un, tn;
|
||||
mp_srcptr up;
|
||||
mp_ptr tp;
|
||||
mp_bitcnt_t bits;
|
||||
@ -4166,20 +4222,21 @@ mpz_sizeinbase (const mpz_t u, int base)
|
||||
10. */
|
||||
}
|
||||
|
||||
tp = gmp_xalloc_limbs (un);
|
||||
tp = gmp_alloc_limbs (un);
|
||||
mpn_copyi (tp, up, un);
|
||||
mpn_div_qr_1_invert (&bi, base);
|
||||
|
||||
tn = un;
|
||||
ndigits = 0;
|
||||
do
|
||||
{
|
||||
ndigits++;
|
||||
mpn_div_qr_1_preinv (tp, tp, un, &bi);
|
||||
un -= (tp[un-1] == 0);
|
||||
mpn_div_qr_1_preinv (tp, tp, tn, &bi);
|
||||
tn -= (tp[tn-1] == 0);
|
||||
}
|
||||
while (un > 0);
|
||||
while (tn > 0);
|
||||
|
||||
gmp_free (tp);
|
||||
gmp_free_limbs (tp, un);
|
||||
return ndigits;
|
||||
}
|
||||
|
||||
@ -4189,7 +4246,7 @@ mpz_get_str (char *sp, int base, const mpz_t u)
|
||||
unsigned bits;
|
||||
const char *digits;
|
||||
mp_size_t un;
|
||||
size_t i, sn;
|
||||
size_t i, sn, osn;
|
||||
|
||||
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
if (base > 1)
|
||||
@ -4210,15 +4267,19 @@ mpz_get_str (char *sp, int base, const mpz_t u)
|
||||
|
||||
sn = 1 + mpz_sizeinbase (u, base);
|
||||
if (!sp)
|
||||
sp = (char *) gmp_xalloc (1 + sn);
|
||||
|
||||
{
|
||||
osn = 1 + sn;
|
||||
sp = (char *) gmp_alloc (osn);
|
||||
}
|
||||
else
|
||||
osn = 0;
|
||||
un = GMP_ABS (u->_mp_size);
|
||||
|
||||
if (un == 0)
|
||||
{
|
||||
sp[0] = '0';
|
||||
sp[1] = '\0';
|
||||
return sp;
|
||||
sn = 1;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
@ -4237,17 +4298,20 @@ mpz_get_str (char *sp, int base, const mpz_t u)
|
||||
mp_ptr tp;
|
||||
|
||||
mpn_get_base_info (&info, base);
|
||||
tp = gmp_xalloc_limbs (un);
|
||||
tp = gmp_alloc_limbs (un);
|
||||
mpn_copyi (tp, u->_mp_d, un);
|
||||
|
||||
sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un);
|
||||
gmp_free (tp);
|
||||
gmp_free_limbs (tp, un);
|
||||
}
|
||||
|
||||
for (; i < sn; i++)
|
||||
sp[i] = digits[(unsigned char) sp[i]];
|
||||
|
||||
ret:
|
||||
sp[sn] = '\0';
|
||||
if (osn && osn != sn + 1)
|
||||
sp = (char*) gmp_realloc (sp, osn, sn + 1);
|
||||
return sp;
|
||||
}
|
||||
|
||||
@ -4257,7 +4321,7 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
||||
unsigned bits, value_of_a;
|
||||
mp_size_t rn, alloc;
|
||||
mp_ptr rp;
|
||||
size_t dn;
|
||||
size_t dn, sn;
|
||||
int sign;
|
||||
unsigned char *dp;
|
||||
|
||||
@ -4295,7 +4359,8 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
||||
r->_mp_size = 0;
|
||||
return -1;
|
||||
}
|
||||
dp = (unsigned char *) gmp_xalloc (strlen (sp));
|
||||
sn = strlen(sp);
|
||||
dp = (unsigned char *) gmp_alloc (sn);
|
||||
|
||||
value_of_a = (base > 36) ? 36 : 10;
|
||||
for (dn = 0; *sp; sp++)
|
||||
@ -4315,7 +4380,7 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
||||
|
||||
if (digit >= (unsigned) base)
|
||||
{
|
||||
gmp_free (dp);
|
||||
gmp_free (dp, sn);
|
||||
r->_mp_size = 0;
|
||||
return -1;
|
||||
}
|
||||
@ -4325,7 +4390,7 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
||||
|
||||
if (!dn)
|
||||
{
|
||||
gmp_free (dp);
|
||||
gmp_free (dp, sn);
|
||||
r->_mp_size = 0;
|
||||
return -1;
|
||||
}
|
||||
@ -4349,7 +4414,7 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
||||
rn -= rp[rn-1] == 0;
|
||||
}
|
||||
assert (rn <= alloc);
|
||||
gmp_free (dp);
|
||||
gmp_free (dp, sn);
|
||||
|
||||
r->_mp_size = sign ? - rn : rn;
|
||||
|
||||
@ -4367,13 +4432,15 @@ size_t
|
||||
mpz_out_str (FILE *stream, int base, const mpz_t x)
|
||||
{
|
||||
char *str;
|
||||
size_t len;
|
||||
size_t len, n;
|
||||
|
||||
str = mpz_get_str (NULL, base, x);
|
||||
if (!str)
|
||||
return 0;
|
||||
len = strlen (str);
|
||||
len = fwrite (str, 1, len, stream);
|
||||
gmp_free (str);
|
||||
return len;
|
||||
n = fwrite (str, 1, len, stream);
|
||||
gmp_free (str, len + 1);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
@ -4462,7 +4529,7 @@ mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
|
||||
mp_size_t un;
|
||||
|
||||
if (nails != 0)
|
||||
gmp_die ("mpz_import: Nails not supported.");
|
||||
gmp_die ("mpz_export: Nails not supported.");
|
||||
|
||||
assert (order == 1 || order == -1);
|
||||
assert (endian >= -1 && endian <= 1);
|
||||
@ -4477,7 +4544,7 @@ mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
|
||||
ptrdiff_t word_step;
|
||||
/* The current (partial) limb. */
|
||||
mp_limb_t limb;
|
||||
/* The number of bytes left to to in this limb. */
|
||||
/* The number of bytes left to do in this limb. */
|
||||
size_t bytes;
|
||||
/* The index where the limb was read. */
|
||||
mp_size_t i;
|
||||
@ -4501,7 +4568,7 @@ mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
|
||||
count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;
|
||||
|
||||
if (!r)
|
||||
r = gmp_xalloc (count * size);
|
||||
r = gmp_alloc (count * size);
|
||||
|
||||
if (endian == 0)
|
||||
endian = gmp_detect_endian ();
|
||||
|
@ -1,21 +1,32 @@
|
||||
/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
|
||||
|
||||
Copyright 2011-2015, 2017, 2019 Free Software Foundation, Inc.
|
||||
Copyright 2011-2015, 2017, 2019-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU MP Library.
|
||||
|
||||
The GNU MP Library 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 3 of the License, or (at your
|
||||
option) any later version.
|
||||
it under the terms of either:
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any
|
||||
later version.
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
The GNU MP Library 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.
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
||||
You should have received copies of the GNU General Public License and the
|
||||
GNU Lesser General Public License along with the GNU MP Library. If not,
|
||||
see https://www.gnu.org/licenses/. */
|
||||
|
||||
/* About mini-gmp: This is a minimal implementation of a subset of the
|
||||
GMP interface. It is intended for inclusion into applications which
|
||||
@ -233,6 +244,10 @@ mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);
|
||||
|
||||
int mpz_fits_slong_p (const mpz_t);
|
||||
int mpz_fits_ulong_p (const mpz_t);
|
||||
int mpz_fits_sint_p (const mpz_t);
|
||||
int mpz_fits_uint_p (const mpz_t);
|
||||
int mpz_fits_sshort_p (const mpz_t);
|
||||
int mpz_fits_ushort_p (const mpz_t);
|
||||
long int mpz_get_si (const mpz_t);
|
||||
unsigned long int mpz_get_ui (const mpz_t);
|
||||
double mpz_get_d (const mpz_t);
|
||||
@ -280,7 +295,9 @@ int mpz_init_set_str (mpz_t, const char *, int);
|
||||
|| defined (_MSL_STDIO_H) /* Metrowerks */ \
|
||||
|| defined (_STDIO_H_INCLUDED) /* QNX4 */ \
|
||||
|| defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \
|
||||
|| defined (__STDIO_LOADED) /* VMS */
|
||||
|| defined (__STDIO_LOADED) /* VMS */ \
|
||||
|| defined (_STDIO) /* HPE NonStop */ \
|
||||
|| defined (__DEFINED_FILE) /* musl */
|
||||
size_t mpz_out_str (FILE *, int, const mpz_t);
|
||||
#endif
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
cd ..
|
||||
git clone https://github.com/open-source-parsers/jsoncpp -b 1.9.4 --depth 1
|
||||
git clone https://github.com/open-source-parsers/jsoncpp -b 1.9.5 --depth 1
|
||||
cd jsoncpp
|
||||
python amalgamate.py
|
||||
./amalgamate.py
|
||||
cp -R dist/json ../json
|
||||
cp dist/jsoncpp.cpp ..
|
||||
|
@ -94,10 +94,10 @@ license you like.
|
||||
// 3. /CMakeLists.txt
|
||||
// IMPORTANT: also update the SOVERSION!!
|
||||
|
||||
#define JSONCPP_VERSION_STRING "1.9.4"
|
||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
||||
#define JSONCPP_VERSION_MAJOR 1
|
||||
#define JSONCPP_VERSION_MINOR 9
|
||||
#define JSONCPP_VERSION_PATCH 3
|
||||
#define JSONCPP_VERSION_PATCH 5
|
||||
#define JSONCPP_VERSION_QUALIFIER
|
||||
#define JSONCPP_VERSION_HEXA \
|
||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||
@ -162,11 +162,10 @@ public:
|
||||
* Release memory which was allocated for N items at pointer P.
|
||||
*
|
||||
* The memory block is filled with zeroes before being released.
|
||||
* The pointer argument is tagged as "volatile" to prevent the
|
||||
* compiler optimizing out this critical step.
|
||||
*/
|
||||
void deallocate(volatile pointer p, size_type n) {
|
||||
std::memset(p, 0, n * sizeof(T));
|
||||
void deallocate(pointer p, size_type n) {
|
||||
// memset_s is used because memset may be optimized away by the compiler
|
||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||
// free using "global operator delete"
|
||||
::operator delete(p);
|
||||
}
|
||||
|
@ -93,10 +93,10 @@ license you like.
|
||||
// 3. /CMakeLists.txt
|
||||
// IMPORTANT: also update the SOVERSION!!
|
||||
|
||||
#define JSONCPP_VERSION_STRING "1.9.4"
|
||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
||||
#define JSONCPP_VERSION_MAJOR 1
|
||||
#define JSONCPP_VERSION_MINOR 9
|
||||
#define JSONCPP_VERSION_PATCH 3
|
||||
#define JSONCPP_VERSION_PATCH 5
|
||||
#define JSONCPP_VERSION_QUALIFIER
|
||||
#define JSONCPP_VERSION_HEXA \
|
||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||
@ -161,11 +161,10 @@ public:
|
||||
* Release memory which was allocated for N items at pointer P.
|
||||
*
|
||||
* The memory block is filled with zeroes before being released.
|
||||
* The pointer argument is tagged as "volatile" to prevent the
|
||||
* compiler optimizing out this critical step.
|
||||
*/
|
||||
void deallocate(volatile pointer p, size_type n) {
|
||||
std::memset(p, 0, n * sizeof(T));
|
||||
void deallocate(pointer p, size_type n) {
|
||||
// memset_s is used because memset may be optimized away by the compiler
|
||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||
// free using "global operator delete"
|
||||
::operator delete(p);
|
||||
}
|
||||
@ -575,7 +574,7 @@ public:
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4251 4275)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push, 8)
|
||||
@ -788,10 +787,10 @@ private:
|
||||
CZString(ArrayIndex index);
|
||||
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
||||
CZString(CZString const& other);
|
||||
CZString(CZString&& other);
|
||||
CZString(CZString&& other) noexcept;
|
||||
~CZString();
|
||||
CZString& operator=(const CZString& other);
|
||||
CZString& operator=(CZString&& other);
|
||||
CZString& operator=(CZString&& other) noexcept;
|
||||
|
||||
bool operator<(CZString const& other) const;
|
||||
bool operator==(CZString const& other) const;
|
||||
@ -869,13 +868,13 @@ public:
|
||||
Value(bool value);
|
||||
Value(std::nullptr_t ptr) = delete;
|
||||
Value(const Value& other);
|
||||
Value(Value&& other);
|
||||
Value(Value&& other) noexcept;
|
||||
~Value();
|
||||
|
||||
/// \note Overwrite existing comments. To preserve comments, use
|
||||
/// #swapPayload().
|
||||
Value& operator=(const Value& other);
|
||||
Value& operator=(Value&& other);
|
||||
Value& operator=(Value&& other) noexcept;
|
||||
|
||||
/// Swap everything.
|
||||
void swap(Value& other);
|
||||
@ -1160,9 +1159,9 @@ private:
|
||||
public:
|
||||
Comments() = default;
|
||||
Comments(const Comments& that);
|
||||
Comments(Comments&& that);
|
||||
Comments(Comments&& that) noexcept;
|
||||
Comments& operator=(const Comments& that);
|
||||
Comments& operator=(Comments&& that);
|
||||
Comments& operator=(Comments&& that) noexcept;
|
||||
bool has(CommentPlacement slot) const;
|
||||
String get(CommentPlacement slot) const;
|
||||
void set(CommentPlacement slot, String comment);
|
||||
@ -1443,8 +1442,8 @@ public:
|
||||
* because the returned references/pointers can be used
|
||||
* to change state of the base class.
|
||||
*/
|
||||
reference operator*() { return deref(); }
|
||||
pointer operator->() { return &deref(); }
|
||||
reference operator*() const { return const_cast<reference>(deref()); }
|
||||
pointer operator->() const { return const_cast<pointer>(&deref()); }
|
||||
};
|
||||
|
||||
inline void swap(Value& a, Value& b) { a.swap(b); }
|
||||
@ -1507,8 +1506,7 @@ namespace Json {
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
|
||||
class JSONCPP_DEPRECATED(
|
||||
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
|
||||
class JSON_API Reader {
|
||||
public:
|
||||
using Char = char;
|
||||
using Location = const Char*;
|
||||
@ -1525,13 +1523,13 @@ public:
|
||||
};
|
||||
|
||||
/** \brief Constructs a Reader allowing all features for parsing.
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
|
||||
Reader();
|
||||
|
||||
/** \brief Constructs a Reader allowing the specified feature set for parsing.
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
|
||||
Reader(const Features& features);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
@ -1798,6 +1796,9 @@ public:
|
||||
* - `"allowSpecialFloats": false or true`
|
||||
* - If true, special float values (NaNs and infinities) are allowed and
|
||||
* their values are lossfree restorable.
|
||||
* - `"skipBom": false or true`
|
||||
* - If true, if the input starts with the Unicode byte order mark (BOM),
|
||||
* it is skipped.
|
||||
*
|
||||
* You can examine 'settings_` yourself to see the defaults. You can also
|
||||
* write and read them just like any JSON Value.
|
||||
@ -2001,6 +2002,8 @@ public:
|
||||
* - Number of precision digits for formatting of real values.
|
||||
* - "precisionType": "significant"(default) or "decimal"
|
||||
* - Type of precision for formatting of real values.
|
||||
* - "emitUTF8": false or true
|
||||
* - If true, outputs raw UTF8 strings instead of escaping them.
|
||||
|
||||
* You can examine 'settings_` yourself
|
||||
* to see the defaults. You can also write and read them just like any
|
||||
@ -2036,7 +2039,7 @@ public:
|
||||
/** \brief Abstract class for writers.
|
||||
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
||||
*/
|
||||
class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer {
|
||||
class JSON_API Writer {
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
@ -2056,7 +2059,7 @@ public:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
|
||||
class JSON_API FastWriter
|
||||
: public Writer {
|
||||
public:
|
||||
FastWriter();
|
||||
@ -2116,7 +2119,7 @@ private:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
||||
class JSON_API
|
||||
StyledWriter : public Writer {
|
||||
public:
|
||||
StyledWriter();
|
||||
@ -2185,7 +2188,7 @@ private:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
||||
class JSON_API
|
||||
StyledStreamWriter {
|
||||
public:
|
||||
/**
|
||||
|
@ -202,14 +202,18 @@ template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
|
||||
* Return iterator that would be the new end of the range [begin,end), if we
|
||||
* were to delete zeros in the end of string, but not the last zero before '.'.
|
||||
*/
|
||||
template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
|
||||
template <typename Iter>
|
||||
Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
|
||||
for (; begin != end; --end) {
|
||||
if (*(end - 1) != '0') {
|
||||
return end;
|
||||
}
|
||||
// Don't delete the last zero before the decimal point.
|
||||
if (begin != (end - 1) && *(end - 2) == '.') {
|
||||
return end;
|
||||
if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
|
||||
if (precision) {
|
||||
return end;
|
||||
}
|
||||
return end - 2;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
@ -338,8 +342,7 @@ bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
|
||||
|
||||
// Since String is reference-counted, this at least does not
|
||||
// create an extra copy.
|
||||
String doc;
|
||||
std::getline(is, doc, static_cast<char> EOF);
|
||||
String doc(std::istreambuf_iterator<char>(is), {});
|
||||
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
|
||||
}
|
||||
|
||||
@ -2155,7 +2158,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const {
|
||||
if (valid_keys.count(key))
|
||||
continue;
|
||||
if (invalid)
|
||||
(*invalid)[std::move(key)] = *si;
|
||||
(*invalid)[key] = *si;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@ -2670,7 +2673,7 @@ Value::CZString::CZString(const CZString& other) {
|
||||
storage_.length_ = other.storage_.length_;
|
||||
}
|
||||
|
||||
Value::CZString::CZString(CZString&& other)
|
||||
Value::CZString::CZString(CZString&& other) noexcept
|
||||
: cstr_(other.cstr_), index_(other.index_) {
|
||||
other.cstr_ = nullptr;
|
||||
}
|
||||
@ -2696,7 +2699,7 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value::CZString& Value::CZString::operator=(CZString&& other) {
|
||||
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
|
||||
cstr_ = other.cstr_;
|
||||
index_ = other.index_;
|
||||
other.cstr_ = nullptr;
|
||||
@ -2844,7 +2847,7 @@ Value::Value(const Value& other) {
|
||||
dupMeta(other);
|
||||
}
|
||||
|
||||
Value::Value(Value&& other) {
|
||||
Value::Value(Value&& other) noexcept {
|
||||
initBasic(nullValue);
|
||||
swap(other);
|
||||
}
|
||||
@ -2859,7 +2862,7 @@ Value& Value::operator=(const Value& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value& Value::operator=(Value&& other) {
|
||||
Value& Value::operator=(Value&& other) noexcept {
|
||||
other.swap(*this);
|
||||
return *this;
|
||||
}
|
||||
@ -3323,7 +3326,8 @@ void Value::resize(ArrayIndex newSize) {
|
||||
if (newSize == 0)
|
||||
clear();
|
||||
else if (newSize > oldSize)
|
||||
this->operator[](newSize - 1);
|
||||
for (ArrayIndex i = oldSize; i < newSize; ++i)
|
||||
(*this)[i];
|
||||
else {
|
||||
for (ArrayIndex index = newSize; index < oldSize; ++index) {
|
||||
value_.map_->erase(index);
|
||||
@ -3784,14 +3788,15 @@ bool Value::isObject() const { return type() == objectValue; }
|
||||
Value::Comments::Comments(const Comments& that)
|
||||
: ptr_{cloneUnique(that.ptr_)} {}
|
||||
|
||||
Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
|
||||
Value::Comments::Comments(Comments&& that) noexcept
|
||||
: ptr_{std::move(that.ptr_)} {}
|
||||
|
||||
Value::Comments& Value::Comments::operator=(const Comments& that) {
|
||||
ptr_ = cloneUnique(that.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value::Comments& Value::Comments::operator=(Comments&& that) {
|
||||
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
|
||||
ptr_ = std::move(that.ptr_);
|
||||
return *this;
|
||||
}
|
||||
@ -3807,13 +3812,11 @@ String Value::Comments::get(CommentPlacement slot) const {
|
||||
}
|
||||
|
||||
void Value::Comments::set(CommentPlacement slot, String comment) {
|
||||
if (!ptr_) {
|
||||
if (slot >= CommentPlacement::numberOfCommentPlacement)
|
||||
return;
|
||||
if (!ptr_)
|
||||
ptr_ = std::unique_ptr<Array>(new Array());
|
||||
}
|
||||
// check comments array boundry.
|
||||
if (slot < CommentPlacement::numberOfCommentPlacement) {
|
||||
(*ptr_)[slot] = std::move(comment);
|
||||
}
|
||||
(*ptr_)[slot] = std::move(comment);
|
||||
}
|
||||
|
||||
void Value::setComment(String comment, CommentPlacement placement) {
|
||||
@ -4127,7 +4130,7 @@ Value& Path::make(Value& root) const {
|
||||
|
||||
#if !defined(isnan)
|
||||
// IEEE standard states that NaN values will not compare to themselves
|
||||
#define isnan(x) (x != x)
|
||||
#define isnan(x) ((x) != (x))
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
@ -4213,16 +4216,18 @@ String valueToString(double value, bool useSpecialFloats,
|
||||
|
||||
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
|
||||
|
||||
// strip the zero padding from the right
|
||||
if (precisionType == PrecisionType::decimalPlaces) {
|
||||
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
|
||||
}
|
||||
|
||||
// try to ensure we preserve the fact that this was given to us as a double on
|
||||
// input
|
||||
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
|
||||
buffer += ".0";
|
||||
}
|
||||
|
||||
// strip the zero padding from the right
|
||||
if (precisionType == PrecisionType::decimalPlaces) {
|
||||
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision),
|
||||
buffer.end());
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
} // namespace
|
||||
@ -4329,7 +4334,7 @@ static void appendHex(String& result, unsigned ch) {
|
||||
result.append("\\u").append(toHex16Bit(ch));
|
||||
}
|
||||
|
||||
static String valueToQuotedStringN(const char* value, unsigned length,
|
||||
static String valueToQuotedStringN(const char* value, size_t length,
|
||||
bool emitUTF8 = false) {
|
||||
if (value == nullptr)
|
||||
return "";
|
||||
@ -4407,7 +4412,7 @@ static String valueToQuotedStringN(const char* value, unsigned length,
|
||||
}
|
||||
|
||||
String valueToQuotedString(const char* value) {
|
||||
return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
|
||||
return valueToQuotedStringN(value, strlen(value));
|
||||
}
|
||||
|
||||
// Class Writer
|
||||
@ -4456,7 +4461,7 @@ void FastWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
|
||||
document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
|
||||
break;
|
||||
}
|
||||
case booleanValue:
|
||||
@ -4479,8 +4484,7 @@ void FastWriter::writeValue(const Value& value) {
|
||||
const String& name = *it;
|
||||
if (it != members.begin())
|
||||
document_ += ',';
|
||||
document_ += valueToQuotedStringN(name.data(),
|
||||
static_cast<unsigned>(name.length()));
|
||||
document_ += valueToQuotedStringN(name.data(), name.length());
|
||||
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
|
||||
writeValue(value[name]);
|
||||
}
|
||||
@ -4525,7 +4529,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@ -4566,7 +4570,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
}
|
||||
|
||||
void StyledWriter::writeArrayValue(const Value& value) {
|
||||
unsigned size = value.size();
|
||||
size_t size = value.size();
|
||||
if (size == 0)
|
||||
pushValue("[]");
|
||||
else {
|
||||
@ -4575,7 +4579,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
||||
writeWithIndent("[");
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index = 0;
|
||||
ArrayIndex index = 0;
|
||||
for (;;) {
|
||||
const Value& childValue = value[index];
|
||||
writeCommentBeforeValue(childValue);
|
||||
@ -4598,7 +4602,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
||||
{
|
||||
assert(childValues_.size() == size);
|
||||
document_ += "[ ";
|
||||
for (unsigned index = 0; index < size; ++index) {
|
||||
for (size_t index = 0; index < size; ++index) {
|
||||
if (index > 0)
|
||||
document_ += ", ";
|
||||
document_ += childValues_[index];
|
||||
@ -4743,7 +4747,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@ -5017,8 +5021,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
|
||||
emitUTF8_));
|
||||
pushValue(
|
||||
valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@ -5041,8 +5045,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
String const& name = *it;
|
||||
Value const& childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(valueToQuotedStringN(
|
||||
name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
|
||||
writeWithIndent(
|
||||
valueToQuotedStringN(name.data(), name.length(), emitUTF8_));
|
||||
*sout_ << colonSymbol_;
|
||||
writeValue(childValue);
|
||||
if (++it == members.end()) {
|
||||
@ -5276,7 +5280,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const {
|
||||
if (valid_keys.count(key))
|
||||
continue;
|
||||
if (invalid)
|
||||
(*invalid)[std::move(key)] = *si;
|
||||
(*invalid)[key] = *si;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
1.9.0mt13
|
||||
1.9.0mt14
|
||||
|
53
misc/make_redirects.sh
Executable file
@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
rm -rf public
|
||||
mkdir public
|
||||
|
||||
redirect() {
|
||||
dir=$(dirname "public$1")
|
||||
mkdir -p $dir
|
||||
cp misc/redirect.html "public$1"
|
||||
|
||||
url=${1/\/index.html/\/}
|
||||
sed -i "s|URL|$url|g" "public$1"
|
||||
}
|
||||
|
||||
redirect /inventory/index.html
|
||||
redirect /definition-tables/index.html
|
||||
redirect /aliases/index.html
|
||||
redirect /items/index.html
|
||||
redirect /registered-definitions/index.html
|
||||
redirect /colors/index.html
|
||||
redirect /decoration-types/index.html
|
||||
redirect /hud/index.html
|
||||
redirect /index.html
|
||||
redirect /spatial-vectors/index.html
|
||||
redirect /metadata/index.html
|
||||
redirect /perlin-noise/index.html
|
||||
redirect /translations/index.html
|
||||
redirect /tool-capabilities/index.html
|
||||
redirect /l-system-trees/index.html
|
||||
redirect /entity-damage-mechanism/index.html
|
||||
redirect /escape-sequences/index.html
|
||||
redirect /registered-entities/index.html
|
||||
redirect /flag-specifier-format/index.html
|
||||
redirect /minetest-namespace-reference/index.html
|
||||
redirect /ores/index.html
|
||||
redirect /search.html
|
||||
redirect /representations-of-simple-things/index.html
|
||||
redirect /nodes/index.html
|
||||
redirect /lua-voxel-manipulator/index.html
|
||||
redirect /helper-functions/index.html
|
||||
redirect /formspec/index.html
|
||||
redirect /games/index.html
|
||||
redirect /sounds/index.html
|
||||
redirect /textures/index.html
|
||||
redirect /map-terminology-and-coordinates/index.html
|
||||
redirect /schematics/index.html
|
||||
redirect /groups/index.html
|
||||
redirect /privileges/index.html
|
||||
redirect /class-reference/index.html
|
||||
redirect /mods/index.html
|
||||
redirect /mapgen-objects/index.html
|
14
misc/redirect.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Minetest API documentation</title>
|
||||
|
||||
<link rel="canonical" href="https://api.minetest.netURL">
|
||||
<meta http-equiv="refresh" content="0; url=https://api.minetest.netURL">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Redirecting…</h1>
|
||||
<a href="https://api.minetest.netURL">Click here if you are not redirected.</a>
|
||||
</body>
|
||||
</html>
|
@ -47,7 +47,7 @@ option(ENABLE_CURL "Enable cURL support for fetching media" TRUE)
|
||||
set(USE_CURL FALSE)
|
||||
|
||||
if(ENABLE_CURL)
|
||||
find_package(CURL)
|
||||
find_package(CURL 7.28.0)
|
||||
if (CURL_FOUND)
|
||||
message(STATUS "cURL support enabled.")
|
||||
set(USE_CURL TRUE)
|
||||
@ -326,6 +326,9 @@ if(HAVE_LINK_ATOMIC)
|
||||
set(PLATFORM_LIBS ${PLATFORM_LIBS} "-latomic")
|
||||
endif()
|
||||
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY)
|
||||
|
||||
check_include_files(endian.h HAVE_ENDIAN_H)
|
||||
|
||||
configure_file(
|
||||
@ -363,9 +366,7 @@ set(common_SRCS
|
||||
${mapgen_SRCS}
|
||||
${server_SRCS}
|
||||
${content_SRCS}
|
||||
ban.cpp
|
||||
chat.cpp
|
||||
clientiface.cpp
|
||||
collision.cpp
|
||||
content_mapnode.cpp
|
||||
content_nodemeta.cpp
|
||||
@ -410,12 +411,10 @@ set(common_SRCS
|
||||
raycast.cpp
|
||||
reflowscan.cpp
|
||||
remoteplayer.cpp
|
||||
rollback.cpp
|
||||
rollback_interface.cpp
|
||||
serialization.cpp
|
||||
server.cpp
|
||||
serverenvironment.cpp
|
||||
serverlist.cpp
|
||||
settings.cpp
|
||||
staticobject.cpp
|
||||
terminal_chat_console.cpp
|
||||
@ -693,7 +692,6 @@ endif()
|
||||
# Set some optimizations and tweaks
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckSymbolExists)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${LUA_INCLUDE_DIR})
|
||||
if(USE_LUAJIT)
|
||||
|
@ -19,10 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "debug.h"
|
||||
#include "util/container.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "util/basic_macros.h"
|
||||
|
||||
@ -52,24 +51,19 @@ public:
|
||||
|
||||
void clear()
|
||||
{
|
||||
while (!m_active_objects.empty())
|
||||
removeObject(m_active_objects.begin()->first);
|
||||
// on_destruct could add new objects so this has to be a loop
|
||||
do {
|
||||
for (auto &it : m_active_objects.iter()) {
|
||||
if (!it.second)
|
||||
continue;
|
||||
m_active_objects.remove(it.first);
|
||||
}
|
||||
} while (!m_active_objects.empty());
|
||||
}
|
||||
|
||||
T *getActiveObject(u16 id)
|
||||
{
|
||||
auto it = m_active_objects.find(id);
|
||||
return it != m_active_objects.end() ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
std::vector<u16> getAllIds() const
|
||||
{
|
||||
std::vector<u16> ids;
|
||||
ids.reserve(m_active_objects.size());
|
||||
for (auto &it : m_active_objects) {
|
||||
ids.push_back(it.first);
|
||||
}
|
||||
return ids;
|
||||
return m_active_objects.get(id).get();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -88,11 +82,9 @@ protected:
|
||||
|
||||
bool isFreeId(u16 id) const
|
||||
{
|
||||
return id != 0 && m_active_objects.find(id) == m_active_objects.end();
|
||||
return id != 0 && !m_active_objects.get(id);
|
||||
}
|
||||
|
||||
// ordered to fix #10985
|
||||
// Note: ActiveObjects can access the ActiveObjectMgr. Only erase objects using
|
||||
// removeObject()!
|
||||
std::map<u16, std::unique_ptr<T>> m_active_objects;
|
||||
// Note that this is ordered to fix #10985
|
||||
ModifySafeMap<u16, std::unique_ptr<T>> m_active_objects;
|
||||
};
|
||||
|
@ -3,6 +3,7 @@ set (BENCHMARK_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_lighting.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_serialize.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_mapblock.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_mapmodify.cpp
|
||||
PARENT_SCOPE)
|
||||
|
||||
set (BENCHMARK_CLIENT_SRCS
|
||||
|
152
src/benchmark/benchmark_mapmodify.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
Minetest
|
||||
Copyright (C) 2023 sfan5
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "benchmark_setup.h"
|
||||
#include "util/container.h"
|
||||
|
||||
// Testing the standard library is not useful except to compare
|
||||
//#define TEST_STDLIB
|
||||
|
||||
using TestMap = ModifySafeMap<u16, void*>;
|
||||
|
||||
static inline void fill(TestMap &map, size_t n)
|
||||
{
|
||||
map.clear();
|
||||
for (size_t i = 0; i < n; i++)
|
||||
map.put(i, reinterpret_cast<TestMap::mapped_type>(0x40000U + i));
|
||||
}
|
||||
|
||||
static inline void pollute(TestMap &map)
|
||||
{
|
||||
auto dummy = reinterpret_cast<TestMap::mapped_type>(123);
|
||||
// produce some garbage to avoid best case behaviour
|
||||
map.put(0xffff, dummy);
|
||||
for (auto it : map.iter()) {
|
||||
(void)it;
|
||||
map.remove(0xffff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void remove(TestMap &map, size_t offset, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
map.remove(static_cast<TestMap::key_type>(i + offset));
|
||||
}
|
||||
|
||||
#define BENCH_ITERATE_(_label, _count, _best) \
|
||||
BENCHMARK_ADVANCED(_label)(Catch::Benchmark::Chronometer meter) { \
|
||||
TestMap map; \
|
||||
fill(map, _count); \
|
||||
if (!_best) pollute(map); \
|
||||
meter.measure([&] { \
|
||||
size_t x = map.size(); \
|
||||
for (auto &it : map.iter()) { \
|
||||
if (!it.second) \
|
||||
continue; \
|
||||
x ^= reinterpret_cast<intptr_t>(it.second); \
|
||||
} \
|
||||
return x; \
|
||||
}); \
|
||||
};
|
||||
|
||||
#define BENCH_ITERATE(_count) \
|
||||
BENCH_ITERATE_("iterate_" #_count, _count, 0) \
|
||||
BENCH_ITERATE_("iterate_bestcase_" #_count, _count, 1)
|
||||
|
||||
#define BENCH_REMOVE(_count) \
|
||||
BENCHMARK_ADVANCED("remove_" #_count)(Catch::Benchmark::Chronometer meter) { \
|
||||
TestMap map; \
|
||||
fill(map, _count); \
|
||||
meter.measure([&] { \
|
||||
for (auto it : map.iter()) { \
|
||||
(void)it; \
|
||||
remove(map, (_count) / 7, (_count) / 2); /* delete half */ \
|
||||
break; \
|
||||
} \
|
||||
}); \
|
||||
};
|
||||
|
||||
TEST_CASE("ModifySafeMap") {
|
||||
BENCH_ITERATE(50)
|
||||
BENCH_ITERATE(400)
|
||||
BENCH_ITERATE(1000)
|
||||
|
||||
BENCH_REMOVE(50)
|
||||
BENCH_REMOVE(400)
|
||||
BENCH_REMOVE(1000)
|
||||
}
|
||||
|
||||
using TestMap2 = std::map<u16, void*>;
|
||||
|
||||
static inline void fill2(TestMap2 &map, size_t n)
|
||||
{
|
||||
map.clear();
|
||||
for (size_t i = 0; i < n; i++)
|
||||
map.emplace(i, reinterpret_cast<TestMap2::mapped_type>(0x40000U + i));
|
||||
}
|
||||
|
||||
static inline void remove2(TestMap2 &map, size_t offset, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
map.erase(static_cast<TestMap2::key_type>(i + offset));
|
||||
}
|
||||
|
||||
#define BENCH2_ITERATE(_count) \
|
||||
BENCHMARK_ADVANCED("iterate_" #_count)(Catch::Benchmark::Chronometer meter) { \
|
||||
TestMap2 map; \
|
||||
fill2(map, _count); \
|
||||
meter.measure([&] { \
|
||||
size_t x = map.size(); \
|
||||
/* mirrors what ActiveObjectMgr::step used to do */ \
|
||||
std::vector<TestMap2::key_type> keys; \
|
||||
keys.reserve(x); \
|
||||
for (auto &it : map) \
|
||||
keys.push_back(it.first); \
|
||||
for (auto key : keys) { \
|
||||
auto it = map.find(key); \
|
||||
if (it == map.end()) \
|
||||
continue; \
|
||||
x ^= reinterpret_cast<intptr_t>(it->second); \
|
||||
} \
|
||||
return x; \
|
||||
}); \
|
||||
};
|
||||
|
||||
#define BENCH2_REMOVE(_count) \
|
||||
BENCHMARK_ADVANCED("remove_" #_count)(Catch::Benchmark::Chronometer meter) { \
|
||||
TestMap2 map; \
|
||||
fill2(map, _count); \
|
||||
meter.measure([&] { \
|
||||
/* no overhead so no fake iteration */ \
|
||||
remove2(map, (_count) / 7, (_count) / 2); \
|
||||
}); \
|
||||
};
|
||||
|
||||
#ifdef TEST_STDLIB
|
||||
TEST_CASE("std::map") {
|
||||
BENCH2_ITERATE(50)
|
||||
BENCH2_ITERATE(400)
|
||||
BENCH2_ITERATE(1000)
|
||||
|
||||
BENCH2_REMOVE(50)
|
||||
BENCH2_REMOVE(400)
|
||||
BENCH2_REMOVE(1000)
|
||||
}
|
||||
#endif
|
@ -775,9 +775,9 @@ void ChatPrompt::clampView()
|
||||
|
||||
|
||||
ChatBackend::ChatBackend():
|
||||
m_console_buffer(500),
|
||||
m_console_buffer(1500),
|
||||
m_recent_buffer(6),
|
||||
m_prompt(L"]", 500)
|
||||
m_prompt(L"]", 1500)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -37,17 +37,14 @@ ActiveObjectMgr::~ActiveObjectMgr()
|
||||
void ActiveObjectMgr::step(
|
||||
float dtime, const std::function<void(ClientActiveObject *)> &f)
|
||||
{
|
||||
g_profiler->avg("ActiveObjectMgr: CAO count [#]", m_active_objects.size());
|
||||
|
||||
// Same as in server activeobjectmgr.
|
||||
std::vector<u16> ids = getAllIds();
|
||||
|
||||
for (u16 id : ids) {
|
||||
auto it = m_active_objects.find(id);
|
||||
if (it == m_active_objects.end())
|
||||
continue; // obj was removed
|
||||
f(it->second.get());
|
||||
size_t count = 0;
|
||||
for (auto &ao_it : m_active_objects.iter()) {
|
||||
if (!ao_it.second)
|
||||
continue;
|
||||
count++;
|
||||
f(ao_it.second.get());
|
||||
}
|
||||
g_profiler->avg("ActiveObjectMgr: CAO count [#]", count);
|
||||
}
|
||||
|
||||
bool ActiveObjectMgr::registerObject(std::unique_ptr<ClientActiveObject> obj)
|
||||
@ -71,7 +68,7 @@ bool ActiveObjectMgr::registerObject(std::unique_ptr<ClientActiveObject> obj)
|
||||
}
|
||||
infostream << "Client::ActiveObjectMgr::registerObject(): "
|
||||
<< "added (id=" << obj->getId() << ")" << std::endl;
|
||||
m_active_objects[obj->getId()] = std::move(obj);
|
||||
m_active_objects.put(obj->getId(), std::move(obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -79,16 +76,14 @@ void ActiveObjectMgr::removeObject(u16 id)
|
||||
{
|
||||
verbosestream << "Client::ActiveObjectMgr::removeObject(): "
|
||||
<< "id=" << id << std::endl;
|
||||
auto it = m_active_objects.find(id);
|
||||
if (it == m_active_objects.end()) {
|
||||
|
||||
std::unique_ptr<ClientActiveObject> obj = m_active_objects.take(id);
|
||||
if (!obj) {
|
||||
infostream << "Client::ActiveObjectMgr::removeObject(): "
|
||||
<< "id=" << id << " not found" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<ClientActiveObject> obj = std::move(it->second);
|
||||
m_active_objects.erase(it);
|
||||
|
||||
obj->removeFromScene(true);
|
||||
}
|
||||
|
||||
@ -96,8 +91,10 @@ void ActiveObjectMgr::getActiveObjects(const v3f &origin, f32 max_d,
|
||||
std::vector<DistanceSortedActiveObject> &dest)
|
||||
{
|
||||
f32 max_d2 = max_d * max_d;
|
||||
for (auto &ao_it : m_active_objects) {
|
||||
for (auto &ao_it : m_active_objects.iter()) {
|
||||
ClientActiveObject *obj = ao_it.second.get();
|
||||
if (!obj)
|
||||
continue;
|
||||
|
||||
f32 d2 = (obj->getPosition() - origin).getLengthSQ();
|
||||
|
||||
@ -114,8 +111,10 @@ std::vector<DistanceSortedActiveObject> ActiveObjectMgr::getActiveSelectableObje
|
||||
f32 max_d = shootline.getLength();
|
||||
v3f dir = shootline.getVector().normalize();
|
||||
|
||||
for (auto &ao_it : m_active_objects) {
|
||||
for (auto &ao_it : m_active_objects.iter()) {
|
||||
ClientActiveObject *obj = ao_it.second.get();
|
||||
if (!obj)
|
||||
continue;
|
||||
|
||||
aabb3f selection_box;
|
||||
if (!obj->getSelectionBox(&selection_box))
|
||||
|
@ -83,8 +83,10 @@ u32 PacketCounter::sum() const
|
||||
void PacketCounter::print(std::ostream &o) const
|
||||
{
|
||||
for (const auto &it : m_packets) {
|
||||
auto name = it.first >= TOCLIENT_NUM_MSG_TYPES ? "?"
|
||||
auto name = it.first >= TOCLIENT_NUM_MSG_TYPES ? nullptr
|
||||
: toClientCommandTable[it.first].name;
|
||||
if (!name)
|
||||
name = "?";
|
||||
o << "cmd " << it.first << " (" << name << ") count "
|
||||
<< it.second << std::endl;
|
||||
}
|
||||
@ -991,27 +993,25 @@ inline void Client::handleCommand(NetworkPacket* pkt)
|
||||
void Client::ProcessData(NetworkPacket *pkt)
|
||||
{
|
||||
ToClientCommand command = (ToClientCommand) pkt->getCommand();
|
||||
u32 sender_peer_id = pkt->getPeerId();
|
||||
|
||||
//infostream<<"Client: received command="<<command<<std::endl;
|
||||
m_packetcounter.add((u16)command);
|
||||
m_packetcounter.add(static_cast<u16>(command));
|
||||
g_profiler->graphAdd("client_received_packets", 1);
|
||||
|
||||
/*
|
||||
If this check is removed, be sure to change the queue
|
||||
system to know the ids
|
||||
*/
|
||||
if(sender_peer_id != PEER_ID_SERVER) {
|
||||
if (pkt->getPeerId() != PEER_ID_SERVER) {
|
||||
infostream << "Client::ProcessData(): Discarding data not "
|
||||
"coming from server: peer_id=" << sender_peer_id << " command=" << pkt->getCommand()
|
||||
<< std::endl;
|
||||
"coming from server: peer_id=" << static_cast<int>(pkt->getPeerId())
|
||||
<< " command=" << static_cast<unsigned>(command) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Command must be handled into ToClientCommandHandler
|
||||
if (command >= TOCLIENT_NUM_MSG_TYPES) {
|
||||
infostream << "Client: Ignoring unknown command "
|
||||
<< command << std::endl;
|
||||
<< static_cast<unsigned>(command) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1020,31 +1020,26 @@ void Client::ProcessData(NetworkPacket *pkt)
|
||||
* But we must use the new ToClientConnectionState in the future,
|
||||
* as a byte mask
|
||||
*/
|
||||
if(toClientCommandTable[command].state == TOCLIENT_STATE_NOT_CONNECTED) {
|
||||
if (toClientCommandTable[command].state == TOCLIENT_STATE_NOT_CONNECTED) {
|
||||
handleCommand(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_server_ser_ver == SER_FMT_VER_INVALID) {
|
||||
if (m_server_ser_ver == SER_FMT_VER_INVALID) {
|
||||
infostream << "Client: Server serialization"
|
||||
" format invalid or not initialized."
|
||||
" Skipping incoming command=" << command << std::endl;
|
||||
" format invalid. Skipping incoming command "
|
||||
<< static_cast<unsigned>(command) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Handle runtime commands
|
||||
*/
|
||||
|
||||
handleCommand(pkt);
|
||||
}
|
||||
|
||||
void Client::Send(NetworkPacket* pkt)
|
||||
{
|
||||
m_con->Send(PEER_ID_SERVER,
|
||||
serverCommandFactoryTable[pkt->getCommand()].channel,
|
||||
pkt,
|
||||
serverCommandFactoryTable[pkt->getCommand()].reliable);
|
||||
auto &scf = serverCommandFactoryTable[pkt->getCommand()];
|
||||
FATAL_ERROR_IF(!scf.name, "packet type missing in table");
|
||||
m_con->Send(PEER_ID_SERVER, scf.channel, pkt, scf.reliable);
|
||||
}
|
||||
|
||||
// Will fill up 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 bytes
|
||||
|
@ -47,10 +47,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
class CAOShaderConstantSetter : public IShaderConstantSetter
|
||||
{
|
||||
public:
|
||||
CAOShaderConstantSetter():
|
||||
m_emissive_color_setting("emissiveColor")
|
||||
{}
|
||||
|
||||
~CAOShaderConstantSetter() override = default;
|
||||
|
||||
void onSetConstants(video::IMaterialRendererServices *services) override
|
||||
@ -74,7 +70,8 @@ public:
|
||||
|
||||
private:
|
||||
video::SColor m_emissive_color;
|
||||
CachedPixelShaderSetting<float, 4> m_emissive_color_setting;
|
||||
CachedPixelShaderSetting<float, 4>
|
||||
m_emissive_color_setting{"emissiveColor"};
|
||||
};
|
||||
|
||||
class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory
|
||||
@ -492,7 +489,8 @@ ClientEnvEvent ClientEnvironment::getClientEnvEvent()
|
||||
|
||||
void ClientEnvironment::getSelectedActiveObjects(
|
||||
const core::line3d<f32> &shootline_on_map,
|
||||
std::vector<PointedThing> &objects)
|
||||
std::vector<PointedThing> &objects,
|
||||
const std::optional<Pointabilities> &pointabilities)
|
||||
{
|
||||
auto allObjects = m_ao_manager.getActiveSelectableObjects(shootline_on_map);
|
||||
const v3f line_vector = shootline_on_map.getVector();
|
||||
@ -519,9 +517,23 @@ void ClientEnvironment::getSelectedActiveObjects(
|
||||
current_raw_normal = current_normal;
|
||||
}
|
||||
if (collision) {
|
||||
current_intersection += obj->getPosition();
|
||||
objects.emplace_back(obj->getId(), current_intersection, current_normal, current_raw_normal,
|
||||
(current_intersection - shootline_on_map.start).getLengthSQ());
|
||||
PointabilityType pointable;
|
||||
if (pointabilities) {
|
||||
if (gcao->isPlayer()) {
|
||||
pointable = pointabilities->matchPlayer(gcao->getGroups()).value_or(
|
||||
gcao->getProperties().pointable);
|
||||
} else {
|
||||
pointable = pointabilities->matchObject(gcao->getName(),
|
||||
gcao->getGroups()).value_or(gcao->getProperties().pointable);
|
||||
}
|
||||
} else {
|
||||
pointable = gcao->getProperties().pointable;
|
||||
}
|
||||
if (pointable != PointabilityType::POINTABLE_NOT) {
|
||||
current_intersection += obj->getPosition();
|
||||
objects.emplace_back(obj->getId(), current_intersection, current_normal, current_raw_normal,
|
||||
(current_intersection - shootline_on_map.start).getLengthSQ(), pointable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,8 @@ public:
|
||||
|
||||
virtual void getSelectedActiveObjects(
|
||||
const core::line3d<f32> &shootline_on_map,
|
||||
std::vector<PointedThing> &objects
|
||||
std::vector<PointedThing> &objects,
|
||||
const std::optional<Pointabilities> &pointabilities
|
||||
);
|
||||
|
||||
const std::set<std::string> &getPlayerNames() { return m_player_names; }
|
||||
|
@ -27,13 +27,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "chat.h"
|
||||
#include "gettext.h"
|
||||
#include "profiler.h"
|
||||
#include "serverlist.h"
|
||||
#include "gui/guiEngine.h"
|
||||
#include "fontengine.h"
|
||||
#include "clientlauncher.h"
|
||||
#include "version.h"
|
||||
#include "renderingengine.h"
|
||||
#include "network/networkexceptions.h"
|
||||
#include <IGUISpriteBank.h>
|
||||
#include <ICameraSceneNode.h>
|
||||
|
||||
#if USE_SOUND
|
||||
#include "sound/sound_openal.h"
|
||||
@ -106,13 +107,6 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Speed tests (done after irrlicht is loaded to get timer)
|
||||
if (cmd_args.getFlag("speedtests")) {
|
||||
dstream << "Running speed tests" << std::endl;
|
||||
speed_tests();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_rendering_engine->get_video_driver() == NULL) {
|
||||
errorstream << "Could not initialize video driver." << std::endl;
|
||||
return false;
|
||||
@ -213,7 +207,8 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
m_rendering_engine->get_raw_device()->
|
||||
setWindowCaption((utf8_to_wide(PROJECT_NAME_C) +
|
||||
L" " + utf8_to_wide(g_version_hash) +
|
||||
L" [" + wstrgettext("Main Menu") + L"]").c_str());
|
||||
L" [" + wstrgettext("Main Menu") + L"]" +
|
||||
L" [" + m_rendering_engine->getVideoDriver()->getName() + L"]" ).c_str());
|
||||
|
||||
try { // This is used for catching disconnects
|
||||
|
||||
@ -247,11 +242,8 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
}
|
||||
|
||||
// Break out of menu-game loop to shut down cleanly
|
||||
if (!m_rendering_engine->run() || *kill) {
|
||||
if (!g_settings_path.empty())
|
||||
g_settings->updateConfigFile(g_settings_path.c_str());
|
||||
if (!m_rendering_engine->run() || *kill)
|
||||
break;
|
||||
}
|
||||
|
||||
m_rendering_engine->get_video_driver()->setTextureCreationFlag(
|
||||
video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
|
||||
@ -275,6 +267,10 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
error_message = gettext("Connection error (timed out?)");
|
||||
errorstream << error_message << std::endl;
|
||||
}
|
||||
catch (ShaderException &e) {
|
||||
error_message = e.what();
|
||||
errorstream << error_message << std::endl;
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
catch (std::exception &e) {
|
||||
@ -292,6 +288,16 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
receiver->m_touchscreengui = NULL;
|
||||
#endif
|
||||
|
||||
/* Save the settings when leaving the game.
|
||||
* This makes sure that setting changes made in-game are persisted even
|
||||
* in case of a later unclean exit from the mainmenu.
|
||||
* This is especially useful on Android because closing the app from the
|
||||
* "Recents screen" results in an unclean exit.
|
||||
* Caveat: This means that the settings are saved twice when exiting Minetest.
|
||||
*/
|
||||
if (!g_settings_path.empty())
|
||||
g_settings->updateConfigFile(g_settings_path.c_str());
|
||||
|
||||
// If no main menu, show error and exit
|
||||
if (skip_main_menu) {
|
||||
if (!error_message.empty()) {
|
||||
@ -380,7 +386,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
|
||||
if (cmd_args.exists("password-file")) {
|
||||
std::ifstream passfile(cmd_args.get("password-file"));
|
||||
if (passfile.good()) {
|
||||
getline(passfile, start_data.password);
|
||||
std::getline(passfile, start_data.password);
|
||||
} else {
|
||||
error_message = gettext("Provided password file "
|
||||
"failed to open: ")
|
||||
@ -437,8 +443,6 @@ bool ClientLauncher::launch_game(std::string &error_message,
|
||||
|
||||
int world_index = menudata.selected_world;
|
||||
if (world_index >= 0 && world_index < (int)worldspecs.size()) {
|
||||
g_settings->set("selected_world_path",
|
||||
worldspecs[world_index].path);
|
||||
start_data.world_spec = worldspecs[world_index];
|
||||
}
|
||||
|
||||
@ -510,15 +514,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (porting::signal_handler_killstatus())
|
||||
return true;
|
||||
|
||||
if (!start_data.game_spec.isValid()) {
|
||||
error_message = gettext("Invalid gamespec.");
|
||||
error_message += " (world.gameid=" + worldspec.gameid + ")";
|
||||
errorstream << error_message << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
start_data.world_path = start_data.world_spec.path;
|
||||
@ -542,118 +538,27 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
|
||||
}
|
||||
infostream << "Waited for other menus" << std::endl;
|
||||
|
||||
#ifndef ANDROID
|
||||
// Cursor can be non-visible when coming from the game
|
||||
m_rendering_engine->get_raw_device()->getCursorControl()->setVisible(true);
|
||||
|
||||
// Set absolute mouse mode
|
||||
m_rendering_engine->get_raw_device()->getCursorControl()->setRelativeMode(false);
|
||||
#endif
|
||||
auto *cur_control = m_rendering_engine->get_raw_device()->getCursorControl();
|
||||
if (cur_control) {
|
||||
// Cursor can be non-visible when coming from the game
|
||||
cur_control->setVisible(true);
|
||||
// Set absolute mouse mode
|
||||
cur_control->setRelativeMode(false);
|
||||
}
|
||||
|
||||
/* show main menu */
|
||||
GUIEngine mymenu(&input->joystick, guiroot, m_rendering_engine, &g_menumgr, menudata, *kill);
|
||||
|
||||
/* leave scene manager in a clean state */
|
||||
m_rendering_engine->get_scene_manager()->clear();
|
||||
}
|
||||
|
||||
void ClientLauncher::speed_tests()
|
||||
{
|
||||
// volatile to avoid some potential compiler optimisations
|
||||
volatile static s16 temp16;
|
||||
volatile static f32 tempf;
|
||||
// Silence compiler warning
|
||||
(void)temp16;
|
||||
static v3f tempv3f1;
|
||||
static v3f tempv3f2;
|
||||
static std::string tempstring;
|
||||
static std::string tempstring2;
|
||||
|
||||
tempv3f1 = v3f();
|
||||
tempv3f2 = v3f();
|
||||
tempstring.clear();
|
||||
tempstring2.clear();
|
||||
|
||||
{
|
||||
infostream << "The following test should take around 20ms." << std::endl;
|
||||
TimeTaker timer("Testing std::string speed");
|
||||
const u32 jj = 10000;
|
||||
for (u32 j = 0; j < jj; j++) {
|
||||
tempstring.clear();
|
||||
tempstring2.clear();
|
||||
const u32 ii = 10;
|
||||
for (u32 i = 0; i < ii; i++) {
|
||||
tempstring2 += "asd";
|
||||
}
|
||||
for (u32 i = 0; i < ii+1; i++) {
|
||||
tempstring += "asd";
|
||||
if (tempstring == tempstring2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
infostream << "All of the following tests should take around 100ms each."
|
||||
<< std::endl;
|
||||
|
||||
{
|
||||
TimeTaker timer("Testing floating-point conversion speed");
|
||||
tempf = 0.001;
|
||||
for (u32 i = 0; i < 4000000; i++) {
|
||||
temp16 += tempf;
|
||||
tempf += 0.001;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TimeTaker timer("Testing floating-point vector speed");
|
||||
|
||||
tempv3f1 = v3f(1, 2, 3);
|
||||
tempv3f2 = v3f(4, 5, 6);
|
||||
for (u32 i = 0; i < 10000000; i++) {
|
||||
tempf += tempv3f1.dotProduct(tempv3f2);
|
||||
tempv3f2 += v3f(7, 8, 9);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TimeTaker timer("Testing std::map speed");
|
||||
|
||||
std::map<v2s16, f32> map1;
|
||||
tempf = -324;
|
||||
const s16 ii = 300;
|
||||
for (s16 y = 0; y < ii; y++) {
|
||||
for (s16 x = 0; x < ii; x++) {
|
||||
map1[v2s16(x, y)] = tempf;
|
||||
tempf += 1;
|
||||
}
|
||||
}
|
||||
for (s16 y = ii - 1; y >= 0; y--) {
|
||||
for (s16 x = 0; x < ii; x++) {
|
||||
tempf = map1[v2s16(x, y)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
infostream << "Around 5000/ms should do well here." << std::endl;
|
||||
TimeTaker timer("Testing mutex speed");
|
||||
|
||||
std::mutex m;
|
||||
u32 n = 0;
|
||||
u32 i = 0;
|
||||
do {
|
||||
n += 10000;
|
||||
for (; i < n; i++) {
|
||||
m.lock();
|
||||
m.unlock();
|
||||
}
|
||||
}
|
||||
// Do at least 10ms
|
||||
while(timer.getTimerTime() < 10);
|
||||
|
||||
u32 dtime = timer.stop();
|
||||
u32 per_ms = n / dtime;
|
||||
infostream << "Done. " << dtime << "ms, " << per_ms << "/ms" << std::endl;
|
||||
}
|
||||
|
||||
/* Save the settings when leaving the mainmenu.
|
||||
* This makes sure that setting changes made in the mainmenu are persisted
|
||||
* even in case of a later unclean exit from the game.
|
||||
* This is especially useful on Android because closing the app from the
|
||||
* "Recents screen" results in an unclean exit.
|
||||
* Caveat: This means that the settings are saved twice when exiting Minetest.
|
||||
*/
|
||||
if (!g_settings_path.empty())
|
||||
g_settings->updateConfigFile(g_settings_path.c_str());
|
||||
}
|
||||
|
@ -44,8 +44,6 @@ private:
|
||||
|
||||
void main_menu(MainMenuData *menudata);
|
||||
|
||||
void speed_tests();
|
||||
|
||||
bool skip_main_menu = false;
|
||||
bool random_input = false;
|
||||
RenderingEngine *m_rendering_engine = nullptr;
|
||||
|
@ -329,7 +329,7 @@ void ClientMap::updateDrawList()
|
||||
MapBlockVect sectorblocks;
|
||||
|
||||
for (auto §or_it : m_sectors) {
|
||||
MapSector *sector = sector_it.second;
|
||||
const MapSector *sector = sector_it.second;
|
||||
v2s16 sp = sector->getPos();
|
||||
|
||||
blocks_loaded += sector->size();
|
||||
@ -339,18 +339,16 @@ void ClientMap::updateDrawList()
|
||||
continue;
|
||||
}
|
||||
|
||||
sectorblocks.clear();
|
||||
sector->getBlocks(sectorblocks);
|
||||
|
||||
// Loop through blocks in sector
|
||||
for (MapBlock *block : sectorblocks) {
|
||||
for (const auto &entry : sector->getBlocks()) {
|
||||
MapBlock *block = entry.second.get();
|
||||
MapBlockMesh *mesh = block->mesh;
|
||||
|
||||
// Calculate the coordinates for range and frustum culling
|
||||
v3f mesh_sphere_center;
|
||||
f32 mesh_sphere_radius;
|
||||
|
||||
v3s16 block_pos_nodes = block->getPos() * MAP_BLOCKSIZE;
|
||||
v3s16 block_pos_nodes = block->getPosRelative();
|
||||
|
||||
if (mesh) {
|
||||
mesh_sphere_center = intToFloat(block_pos_nodes, BS)
|
||||
@ -649,7 +647,7 @@ void ClientMap::touchMapBlocks()
|
||||
u32 blocks_in_range_with_mesh = 0;
|
||||
|
||||
for (const auto §or_it : m_sectors) {
|
||||
MapSector *sector = sector_it.second;
|
||||
const MapSector *sector = sector_it.second;
|
||||
v2s16 sp = sector->getPos();
|
||||
|
||||
blocks_loaded += sector->size();
|
||||
@ -659,21 +657,19 @@ void ClientMap::touchMapBlocks()
|
||||
continue;
|
||||
}
|
||||
|
||||
MapBlockVect sectorblocks;
|
||||
sector->getBlocks(sectorblocks);
|
||||
|
||||
/*
|
||||
Loop through blocks in sector
|
||||
*/
|
||||
|
||||
for (MapBlock *block : sectorblocks) {
|
||||
for (const auto &entry : sector->getBlocks()) {
|
||||
MapBlock *block = entry.second.get();
|
||||
MapBlockMesh *mesh = block->mesh;
|
||||
|
||||
// Calculate the coordinates for range and frustum culling
|
||||
v3f mesh_sphere_center;
|
||||
f32 mesh_sphere_radius;
|
||||
|
||||
v3s16 block_pos_nodes = block->getPos() * MAP_BLOCKSIZE;
|
||||
v3s16 block_pos_nodes = block->getPosRelative();
|
||||
|
||||
if (mesh) {
|
||||
mesh_sphere_center = intToFloat(block_pos_nodes, BS)
|
||||
@ -1249,11 +1245,6 @@ void ClientMap::updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir,
|
||||
{
|
||||
ScopeProfiler sp(g_profiler, "CM::updateDrawListShadow()", SPT_AVG);
|
||||
|
||||
v3s16 cam_pos_nodes = floatToInt(shadow_light_pos, BS);
|
||||
v3s16 p_blocks_min;
|
||||
v3s16 p_blocks_max;
|
||||
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max, radius + length);
|
||||
|
||||
for (auto &i : m_drawlist_shadow) {
|
||||
MapBlock *block = i.second;
|
||||
block->refDrop();
|
||||
@ -1266,25 +1257,23 @@ void ClientMap::updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir,
|
||||
u32 blocks_in_range_with_mesh = 0;
|
||||
|
||||
for (auto §or_it : m_sectors) {
|
||||
MapSector *sector = sector_it.second;
|
||||
const MapSector *sector = sector_it.second;
|
||||
if (!sector)
|
||||
continue;
|
||||
blocks_loaded += sector->size();
|
||||
|
||||
MapBlockVect sectorblocks;
|
||||
sector->getBlocks(sectorblocks);
|
||||
|
||||
/*
|
||||
Loop through blocks in sector
|
||||
*/
|
||||
for (MapBlock *block : sectorblocks) {
|
||||
for (const auto &entry : sector->getBlocks()) {
|
||||
MapBlock *block = entry.second.get();
|
||||
MapBlockMesh *mesh = block->mesh;
|
||||
if (!mesh) {
|
||||
// Ignore if mesh doesn't exist
|
||||
continue;
|
||||
}
|
||||
|
||||
v3f block_pos = intToFloat(block->getPos() * MAP_BLOCKSIZE, BS) + mesh->getBoundingSphereCenter();
|
||||
v3f block_pos = intToFloat(block->getPosRelative(), BS) + mesh->getBoundingSphereCenter();
|
||||
v3f projection = shadow_light_pos + shadow_light_dir * shadow_light_dir.dotProduct(block_pos - shadow_light_pos);
|
||||
if (projection.getDistanceFrom(block_pos) > (radius + mesh->getBoundingRadius()))
|
||||
continue;
|
||||
|
@ -165,9 +165,11 @@ void Clouds::render()
|
||||
driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
||||
fog_pixelfog, fog_rangefog);
|
||||
|
||||
// Set our own fog
|
||||
driver->setFog(fog_color, fog_type, cloud_full_radius * 0.5,
|
||||
// Set our own fog, unless it was already disabled
|
||||
if (fog_start < FOG_RANGE_ALL) {
|
||||
driver->setFog(fog_color, fog_type, cloud_full_radius * 0.5,
|
||||
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
|
||||
}
|
||||
|
||||
// Read noise
|
||||
|
||||
|
@ -411,8 +411,7 @@ GenericCAO::~GenericCAO()
|
||||
|
||||
bool GenericCAO::getSelectionBox(aabb3f *toset) const
|
||||
{
|
||||
if (!m_prop.is_visible || !m_is_visible || m_is_local_player
|
||||
|| !m_prop.pointable) {
|
||||
if (!m_prop.is_visible || !m_is_visible || m_is_local_player) {
|
||||
return false;
|
||||
}
|
||||
*toset = m_selection_box;
|
||||
@ -620,6 +619,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||
|
||||
infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl;
|
||||
|
||||
m_material_type_param = 0.5f; // May cut off alpha < 128 depending on m_material_type
|
||||
|
||||
if (m_enable_shaders) {
|
||||
IShaderSource *shader_source = m_client->getShaderSource();
|
||||
MaterialType material_type;
|
||||
@ -634,8 +635,12 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
||||
u32 shader_id = shader_source->getShader("object_shader", material_type, NDT_NORMAL);
|
||||
m_material_type = shader_source->getShaderInfo(shader_id).material;
|
||||
} else {
|
||||
m_material_type = (m_prop.use_texture_alpha) ?
|
||||
video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
if (m_prop.use_texture_alpha) {
|
||||
m_material_type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
m_material_type_param = 1.0f / 256.f; // minimal alpha for texture rendering
|
||||
} else {
|
||||
m_material_type = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
}
|
||||
}
|
||||
|
||||
auto grabMatrixNode = [this] {
|
||||
@ -1341,7 +1346,7 @@ void GenericCAO::updateTextures(std::string mod)
|
||||
|
||||
video::SMaterial &material = m_spritenode->getMaterial(0);
|
||||
material.MaterialType = m_material_type;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
material.MaterialTypeParam = m_material_type_param;
|
||||
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
||||
|
||||
// This allows setting per-material colors. However, until a real lighting
|
||||
@ -1377,7 +1382,7 @@ void GenericCAO::updateTextures(std::string mod)
|
||||
// Set material flags and texture
|
||||
video::SMaterial &material = m_animated_meshnode->getMaterial(i);
|
||||
material.MaterialType = m_material_type;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
material.MaterialTypeParam = m_material_type_param;
|
||||
material.TextureLayers[0].Texture = texture;
|
||||
material.Lighting = true;
|
||||
material.BackfaceCulling = m_prop.backface_culling;
|
||||
@ -1421,7 +1426,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.MaterialTypeParam = 0.5f;
|
||||
material.MaterialTypeParam = m_material_type_param;
|
||||
material.Lighting = false;
|
||||
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
||||
material.getTextureMatrix(0).makeIdentity();
|
||||
|
@ -130,6 +130,7 @@ private:
|
||||
bool m_is_visible = false;
|
||||
// Material
|
||||
video::E_MATERIAL_TYPE m_material_type;
|
||||
f32 m_material_type_param;
|
||||
// Settings
|
||||
bool m_enable_shaders = false;
|
||||
|
||||
@ -173,6 +174,8 @@ public:
|
||||
|
||||
inline const ObjectProperties &getProperties() const { return m_prop; }
|
||||
|
||||
inline const std::string &getName() const { return m_name; }
|
||||
|
||||
scene::ISceneNode *getSceneNode() const override;
|
||||
|
||||
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const override;
|
||||
@ -207,6 +210,11 @@ public:
|
||||
return m_is_local_player;
|
||||
}
|
||||
|
||||
inline bool isPlayer() const
|
||||
{
|
||||
return m_is_player;
|
||||
}
|
||||
|
||||
inline bool isVisible() const
|
||||
{
|
||||
return m_is_visible;
|
||||
|
@ -1008,7 +1008,9 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
||||
switch (wall) {
|
||||
case DWM_YP: tileindex = 1; break; // ceiling
|
||||
case DWM_YN: tileindex = 0; break; // floor
|
||||
default: tileindex = 2; // side (or invalid—should we care?)
|
||||
case DWM_S1: tileindex = 1; break; // ceiling, but rotated
|
||||
case DWM_S2: tileindex = 0; break; // floor, but rotated
|
||||
default: tileindex = 2; // side (or invalid, shouldn't happen)
|
||||
}
|
||||
useTile(tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
|
||||
@ -1044,6 +1046,17 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
||||
case DWM_ZN:
|
||||
vertex.X += -size + BS/2;
|
||||
vertex.rotateXZBy(-90);
|
||||
break;
|
||||
case DWM_S1:
|
||||
// same as DWM_YP, but rotated 90°
|
||||
vertex.Y += -size + BS/2;
|
||||
vertex.rotateXZBy(45);
|
||||
break;
|
||||
case DWM_S2:
|
||||
// same as DWM_YN, but rotated -90°
|
||||
vertex.Y += size - BS/2;
|
||||
vertex.rotateXZBy(-45);
|
||||
break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices);
|
||||
@ -1077,6 +1090,10 @@ void MapblockMeshGenerator::drawSignlikeNode()
|
||||
vertex.rotateXZBy( 90); break;
|
||||
case DWM_ZN:
|
||||
vertex.rotateXZBy(-90); break;
|
||||
case DWM_S1:
|
||||
vertex.rotateXYBy( 90); vertex.rotateXZBy(90); break;
|
||||
case DWM_S2:
|
||||
vertex.rotateXYBy(-90); vertex.rotateXZBy(-90); break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices);
|
||||
|
@ -74,6 +74,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "script/scripting_client.h"
|
||||
#include "hud.h"
|
||||
#include "clientdynamicinfo.h"
|
||||
#include <IAnimatedMeshSceneNode.h>
|
||||
|
||||
#if USE_SOUND
|
||||
#include "client/sound/sound_openal.h"
|
||||
@ -373,43 +374,55 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
||||
bool *m_force_fog_off;
|
||||
f32 *m_fog_range;
|
||||
bool m_fog_enabled;
|
||||
CachedPixelShaderSetting<float, 4> m_sky_bg_color;
|
||||
CachedPixelShaderSetting<float> m_fog_distance;
|
||||
CachedPixelShaderSetting<float> m_fog_shading_parameter;
|
||||
CachedVertexShaderSetting<float> m_animation_timer_vertex;
|
||||
CachedPixelShaderSetting<float> m_animation_timer_pixel;
|
||||
CachedVertexShaderSetting<float> m_animation_timer_delta_vertex;
|
||||
CachedPixelShaderSetting<float> m_animation_timer_delta_pixel;
|
||||
CachedPixelShaderSetting<float, 3> m_day_light;
|
||||
CachedPixelShaderSetting<float, 4> m_star_color;
|
||||
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
|
||||
CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
|
||||
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
|
||||
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
|
||||
CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture0;
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture1;
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture2;
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture3;
|
||||
CachedVertexShaderSetting<float, 2> m_texel_size0_vertex;
|
||||
CachedPixelShaderSetting<float, 2> m_texel_size0_pixel;
|
||||
CachedPixelShaderSetting<float, 4> m_fog_color{"fogColor"};
|
||||
CachedPixelShaderSetting<float> m_fog_distance{"fogDistance"};
|
||||
CachedPixelShaderSetting<float>
|
||||
m_fog_shading_parameter{"fogShadingParameter"};
|
||||
CachedVertexShaderSetting<float> m_animation_timer_vertex{"animationTimer"};
|
||||
CachedPixelShaderSetting<float> m_animation_timer_pixel{"animationTimer"};
|
||||
CachedVertexShaderSetting<float>
|
||||
m_animation_timer_delta_vertex{"animationTimerDelta"};
|
||||
CachedPixelShaderSetting<float>
|
||||
m_animation_timer_delta_pixel{"animationTimerDelta"};
|
||||
CachedPixelShaderSetting<float, 3> m_day_light{"dayLight"};
|
||||
CachedPixelShaderSetting<float, 4> m_star_color{"starColor"};
|
||||
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"};
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture0{"texture0"};
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture1{"texture1"};
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture2{"texture2"};
|
||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture3{"texture3"};
|
||||
CachedVertexShaderSetting<float, 2> m_texel_size0_vertex{"texelSize0"};
|
||||
CachedPixelShaderSetting<float, 2> m_texel_size0_pixel{"texelSize0"};
|
||||
std::array<float, 2> m_texel_size0_values;
|
||||
CachedStructPixelShaderSetting<float, 7> m_exposure_params_pixel;
|
||||
CachedStructPixelShaderSetting<float, 7> m_exposure_params_pixel{
|
||||
"exposureParams",
|
||||
std::array<const char*, 7> {
|
||||
"luminanceMin", "luminanceMax", "exposureCorrection",
|
||||
"speedDarkBright", "speedBrightDark", "centerWeightPower",
|
||||
"compensationFactor"
|
||||
}};
|
||||
float m_user_exposure_compensation;
|
||||
bool m_bloom_enabled;
|
||||
CachedPixelShaderSetting<float> m_bloom_intensity_pixel;
|
||||
CachedPixelShaderSetting<float> m_bloom_intensity_pixel{"bloomIntensity"};
|
||||
float m_bloom_intensity;
|
||||
CachedPixelShaderSetting<float> m_bloom_strength_pixel;
|
||||
CachedPixelShaderSetting<float> m_bloom_strength_pixel{"bloomStrength"};
|
||||
float m_bloom_strength;
|
||||
CachedPixelShaderSetting<float> m_bloom_radius_pixel;
|
||||
CachedPixelShaderSetting<float> m_bloom_radius_pixel{"bloomRadius"};
|
||||
float m_bloom_radius;
|
||||
CachedPixelShaderSetting<float> m_saturation_pixel;
|
||||
CachedPixelShaderSetting<float> m_saturation_pixel{"saturation"};
|
||||
bool m_volumetric_light_enabled;
|
||||
CachedPixelShaderSetting<float, 3> m_sun_position_pixel;
|
||||
CachedPixelShaderSetting<float> m_sun_brightness_pixel;
|
||||
CachedPixelShaderSetting<float, 3> m_moon_position_pixel;
|
||||
CachedPixelShaderSetting<float> m_moon_brightness_pixel;
|
||||
CachedPixelShaderSetting<float> m_volumetric_light_strength_pixel;
|
||||
CachedPixelShaderSetting<float, 3>
|
||||
m_sun_position_pixel{"sunPositionScreen"};
|
||||
CachedPixelShaderSetting<float> m_sun_brightness_pixel{"sunBrightness"};
|
||||
CachedPixelShaderSetting<float, 3>
|
||||
m_moon_position_pixel{"moonPositionScreen"};
|
||||
CachedPixelShaderSetting<float> m_moon_brightness_pixel{"moonBrightness"};
|
||||
CachedPixelShaderSetting<float>
|
||||
m_volumetric_light_strength_pixel{"volumetricLightStrength"};
|
||||
|
||||
public:
|
||||
void onSettingsChange(const std::string &name)
|
||||
@ -438,41 +451,7 @@ public:
|
||||
m_sky(sky),
|
||||
m_client(client),
|
||||
m_force_fog_off(force_fog_off),
|
||||
m_fog_range(fog_range),
|
||||
m_sky_bg_color("skyBgColor"),
|
||||
m_fog_distance("fogDistance"),
|
||||
m_fog_shading_parameter("fogShadingParameter"),
|
||||
m_animation_timer_vertex("animationTimer"),
|
||||
m_animation_timer_pixel("animationTimer"),
|
||||
m_animation_timer_delta_vertex("animationTimerDelta"),
|
||||
m_animation_timer_delta_pixel("animationTimerDelta"),
|
||||
m_day_light("dayLight"),
|
||||
m_star_color("starColor"),
|
||||
m_eye_position_pixel("eyePosition"),
|
||||
m_eye_position_vertex("eyePosition"),
|
||||
m_minimap_yaw("yawVec"),
|
||||
m_camera_offset_pixel("cameraOffset"),
|
||||
m_camera_offset_vertex("cameraOffset"),
|
||||
m_texture0("texture0"),
|
||||
m_texture1("texture1"),
|
||||
m_texture2("texture2"),
|
||||
m_texture3("texture3"),
|
||||
m_texel_size0_vertex("texelSize0"),
|
||||
m_texel_size0_pixel("texelSize0"),
|
||||
m_exposure_params_pixel("exposureParams",
|
||||
std::array<const char*, 7> {
|
||||
"luminanceMin", "luminanceMax", "exposureCorrection",
|
||||
"speedDarkBright", "speedBrightDark", "centerWeightPower", "compensationFactor"
|
||||
}),
|
||||
m_bloom_intensity_pixel("bloomIntensity"),
|
||||
m_bloom_strength_pixel("bloomStrength"),
|
||||
m_bloom_radius_pixel("bloomRadius"),
|
||||
m_saturation_pixel("saturation"),
|
||||
m_sun_position_pixel("sunPositionScreen"),
|
||||
m_sun_brightness_pixel("sunBrightness"),
|
||||
m_moon_position_pixel("moonPositionScreen"),
|
||||
m_moon_brightness_pixel("moonBrightness"),
|
||||
m_volumetric_light_strength_pixel("volumetricLightStrength")
|
||||
m_fog_range(fog_range)
|
||||
{
|
||||
g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
|
||||
g_settings->registerChangedCallback("exposure_compensation", settingsCallback, this);
|
||||
@ -496,20 +475,13 @@ public:
|
||||
|
||||
void onSetConstants(video::IMaterialRendererServices *services) override
|
||||
{
|
||||
// Background color
|
||||
video::SColor bgcolor = m_sky->getBgColor();
|
||||
video::SColorf bgcolorf(bgcolor);
|
||||
float bgcolorfa[4] = {
|
||||
bgcolorf.r,
|
||||
bgcolorf.g,
|
||||
bgcolorf.b,
|
||||
bgcolorf.a,
|
||||
video::SColorf fogcolorf(m_sky->getFogColor());
|
||||
float fogcolorfa[4] = {
|
||||
fogcolorf.r, fogcolorf.g, fogcolorf.b, fogcolorf.a,
|
||||
};
|
||||
m_sky_bg_color.set(bgcolorfa, services);
|
||||
m_fog_color.set(fogcolorfa, services);
|
||||
|
||||
// Fog distance
|
||||
float fog_distance = 10000 * BS;
|
||||
|
||||
if (m_fog_enabled && !*m_force_fog_off)
|
||||
fog_distance = *m_fog_range;
|
||||
|
||||
@ -862,6 +834,7 @@ protected:
|
||||
* the camera position. This also gives the maximal distance
|
||||
* of the search.
|
||||
* @param[in] liquids_pointable if false, liquids are ignored
|
||||
* @param[in] pointabilities item specific pointable overriding
|
||||
* @param[in] look_for_object if false, objects are ignored
|
||||
* @param[in] camera_offset offset of the camera
|
||||
* @param[out] selected_object the selected object or
|
||||
@ -869,6 +842,7 @@ protected:
|
||||
*/
|
||||
PointedThing updatePointedThing(
|
||||
const core::line3d<f32> &shootline, bool liquids_pointable,
|
||||
const std::optional<Pointabilities> &pointabilities,
|
||||
bool look_for_object, const v3s16 &camera_offset);
|
||||
void handlePointingAtNothing(const ItemStack &playerItem);
|
||||
void handlePointingAtNode(const PointedThing &pointed,
|
||||
@ -1002,7 +976,6 @@ private:
|
||||
bool *kill;
|
||||
std::string *error_message;
|
||||
bool *reconnect_requested;
|
||||
scene::ISceneNode *skybox;
|
||||
PausedNodesList paused_animated_nodes;
|
||||
|
||||
bool simple_singleplayer_mode;
|
||||
@ -1541,7 +1514,6 @@ bool Game::createClient(const GameStartData &start_data)
|
||||
*/
|
||||
sky = new Sky(-1, m_rendering_engine, texture_src, shader_src);
|
||||
scsf->setSky(sky);
|
||||
skybox = NULL; // This is used/set later on in the main run loop
|
||||
|
||||
/* Pre-calculated values
|
||||
*/
|
||||
@ -1771,7 +1743,7 @@ bool Game::getServerContent(bool *aborted)
|
||||
// End condition
|
||||
if (client->mediaReceived() && client->itemdefReceived() &&
|
||||
client->nodedefReceived()) {
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Error conditions
|
||||
@ -1830,7 +1802,9 @@ bool Game::getServerContent(bool *aborted)
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
*aborted = true;
|
||||
infostream << "Connect aborted [device]" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -2635,23 +2609,27 @@ void Game::checkZoomEnabled()
|
||||
|
||||
void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
|
||||
{
|
||||
#ifndef __ANDROID__
|
||||
if (isMenuActive())
|
||||
device->getCursorControl()->setRelativeMode(false);
|
||||
else
|
||||
device->getCursorControl()->setRelativeMode(true);
|
||||
auto *cur_control = device->getCursorControl();
|
||||
|
||||
/* With CIrrDeviceSDL on Linux and Windows, enabling relative mouse mode
|
||||
somehow results in simulated mouse events being generated from touch events,
|
||||
although SDL_HINT_MOUSE_TOUCH_EVENTS and SDL_HINT_TOUCH_MOUSE_EVENTS are set to 0.
|
||||
Since Minetest has its own code to synthesize mouse events from touch events,
|
||||
this results in duplicated input. To avoid that, we don't enable relative
|
||||
mouse mode if we're in touchscreen mode. */
|
||||
#ifndef HAVE_TOUCHSCREENGUI
|
||||
if (cur_control)
|
||||
cur_control->setRelativeMode(!isMenuActive());
|
||||
#endif
|
||||
|
||||
if ((device->isWindowActive() && device->isWindowFocused()
|
||||
&& !isMenuActive()) || input->isRandom()) {
|
||||
|
||||
#ifndef __ANDROID__
|
||||
if (!input->isRandom()) {
|
||||
if (cur_control && !input->isRandom()) {
|
||||
// Mac OSX gets upset if this is set every frame
|
||||
if (device->getCursorControl()->isVisible())
|
||||
device->getCursorControl()->setVisible(false);
|
||||
if (cur_control->isVisible())
|
||||
cur_control->setVisible(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_first_loop_after_window_activation) {
|
||||
m_first_loop_after_window_activation = false;
|
||||
@ -2663,15 +2641,11 @@ void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
#ifndef ANDROID
|
||||
// Mac OSX gets upset if this is set every frame
|
||||
if (!device->getCursorControl()->isVisible())
|
||||
device->getCursorControl()->setVisible(true);
|
||||
#endif
|
||||
if (cur_control && !cur_control->isVisible())
|
||||
cur_control->setVisible(true);
|
||||
|
||||
m_first_loop_after_window_activation = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -3048,6 +3022,9 @@ void Game::handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *ca
|
||||
CASE_SET(HUD_STAT_TEXT2, text2, sdata);
|
||||
|
||||
CASE_SET(HUD_STAT_STYLE, style, data);
|
||||
|
||||
case HudElementStat_END:
|
||||
break;
|
||||
}
|
||||
|
||||
#undef CASE_SET
|
||||
@ -3061,10 +3038,6 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam)
|
||||
// Whether clouds are visible in front of a custom skybox.
|
||||
sky->setCloudsEnabled(event->set_sky->clouds);
|
||||
|
||||
if (skybox) {
|
||||
skybox->remove();
|
||||
skybox = NULL;
|
||||
}
|
||||
// Clear the old textures out in case we switch rendering type.
|
||||
sky->clearSkyboxTextures();
|
||||
// Handle according to type
|
||||
@ -3124,6 +3097,8 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam)
|
||||
else
|
||||
sky->setFogStart(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
|
||||
|
||||
sky->setFogColor(event->set_sky->fog_color);
|
||||
|
||||
delete event->set_sky;
|
||||
}
|
||||
|
||||
@ -3361,12 +3336,18 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
|
||||
|
||||
PointedThing pointed = updatePointedThing(shootline,
|
||||
selected_def.liquids_pointable,
|
||||
selected_def.pointabilities,
|
||||
!runData.btn_down_for_dig,
|
||||
camera_offset);
|
||||
|
||||
if (pointed != runData.pointed_old)
|
||||
infostream << "Pointing at " << pointed.dump() << std::endl;
|
||||
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (g_touchscreengui)
|
||||
g_touchscreengui->applyContextControls(selected_def.touch_interaction.getMode(pointed));
|
||||
#endif
|
||||
|
||||
// Note that updating the selection mesh every frame is not particularly efficient,
|
||||
// but the halo rendering code is already inefficient so there's no point in optimizing it here
|
||||
hud->updateSelectionMesh(camera_offset);
|
||||
@ -3467,6 +3448,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
|
||||
PointedThing Game::updatePointedThing(
|
||||
const core::line3d<f32> &shootline,
|
||||
bool liquids_pointable,
|
||||
const std::optional<Pointabilities> &pointabilities,
|
||||
bool look_for_object,
|
||||
const v3s16 &camera_offset)
|
||||
{
|
||||
@ -3483,7 +3465,7 @@ PointedThing Game::updatePointedThing(
|
||||
runData.selected_object = NULL;
|
||||
hud->pointing_at_object = false;
|
||||
|
||||
RaycastState s(shootline, look_for_object, liquids_pointable);
|
||||
RaycastState s(shootline, look_for_object, liquids_pointable, pointabilities);
|
||||
PointedThing result;
|
||||
env.continueRaycast(&s, &result);
|
||||
if (result.type == POINTEDTHING_OBJECT) {
|
||||
@ -3725,7 +3707,36 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
|
||||
v3s16 dir = nodepos - neighborpos;
|
||||
|
||||
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
|
||||
predicted_node.setParam2(dir.Y < 0 ? 1 : 0);
|
||||
// If you change this code, also change builtin/game/item.lua
|
||||
u8 predicted_param2 = dir.Y < 0 ? 1 : 0;
|
||||
if (selected_def.wallmounted_rotate_vertical) {
|
||||
bool rotate90 = false;
|
||||
v3f fnodepos = v3f(neighborpos.X, neighborpos.Y, neighborpos.Z);
|
||||
v3f ppos = client->getEnv().getLocalPlayer()->getPosition() / BS;
|
||||
v3f pdir = fnodepos - ppos;
|
||||
switch (predicted_f.drawtype) {
|
||||
case NDT_TORCHLIKE: {
|
||||
rotate90 = !((pdir.X < 0 && pdir.Z > 0) ||
|
||||
(pdir.X > 0 && pdir.Z < 0));
|
||||
if (dir.Y > 0) {
|
||||
rotate90 = !rotate90;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case NDT_SIGNLIKE: {
|
||||
rotate90 = abs(pdir.X) < abs(pdir.Z);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
rotate90 = abs(pdir.X) > abs(pdir.Z);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rotate90) {
|
||||
predicted_param2 += 6;
|
||||
}
|
||||
}
|
||||
predicted_node.setParam2(predicted_param2);
|
||||
} else if (abs(dir.X) > abs(dir.Z)) {
|
||||
predicted_node.setParam2(dir.X < 0 ? 3 : 2);
|
||||
} else {
|
||||
@ -4035,7 +4046,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
||||
draw_control->wanted_range = MYMIN(draw_control->wanted_range, sky->getFogDistance());
|
||||
}
|
||||
if (draw_control->range_all && sky->getFogDistance() < 0) {
|
||||
runData.fog_range = 100000 * BS;
|
||||
runData.fog_range = FOG_RANGE_ALL;
|
||||
} else {
|
||||
runData.fog_range = draw_control->wanted_range * BS;
|
||||
}
|
||||
@ -4196,7 +4207,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
||||
/*
|
||||
==================== Drawing begins ====================
|
||||
*/
|
||||
if (RenderingEngine::shouldRender())
|
||||
if (device->isWindowVisible())
|
||||
drawScene(graph, stats);
|
||||
/*
|
||||
==================== End scene ====================
|
||||
@ -4277,7 +4288,7 @@ void Game::updateShadows()
|
||||
|
||||
void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
|
||||
{
|
||||
const video::SColor bg_color = this->sky->getBgColor();
|
||||
const video::SColor fog_color = this->sky->getFogColor();
|
||||
const video::SColor sky_color = this->sky->getSkyColor();
|
||||
|
||||
/*
|
||||
@ -4285,21 +4296,21 @@ void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
|
||||
*/
|
||||
if (this->m_cache_enable_fog) {
|
||||
this->driver->setFog(
|
||||
bg_color,
|
||||
fog_color,
|
||||
video::EFT_FOG_LINEAR,
|
||||
this->runData.fog_range * this->sky->getFogStart(),
|
||||
this->runData.fog_range * 1.0f,
|
||||
0.01f,
|
||||
0.f, // unused
|
||||
false, // pixel fog
|
||||
true // range fog
|
||||
);
|
||||
} else {
|
||||
this->driver->setFog(
|
||||
bg_color,
|
||||
fog_color,
|
||||
video::EFT_FOG_LINEAR,
|
||||
100000 * BS,
|
||||
110000 * BS,
|
||||
0.01f,
|
||||
FOG_RANGE_ALL,
|
||||
FOG_RANGE_ALL + 100 * BS,
|
||||
0.f, // unused
|
||||
false, // pixel fog
|
||||
false // range fog
|
||||
);
|
||||
@ -4473,8 +4484,8 @@ void Game::showPauseMenu()
|
||||
static const std::string control_text = strgettext("Controls:\n"
|
||||
"No menu open:\n"
|
||||
"- slide finger: look around\n"
|
||||
"- tap: place/use\n"
|
||||
"- long tap: dig/punch/use\n"
|
||||
"- tap: place/punch/use (default)\n"
|
||||
"- long tap: dig/use (default)\n"
|
||||
"Menu/inventory open:\n"
|
||||
"- double tap (outside):\n"
|
||||
" --> close\n"
|
||||
|
@ -416,7 +416,9 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
|
||||
(e->number >> 0) & 0xFF);
|
||||
std::wstring text = unescape_translate(utf8_to_wide(e->name));
|
||||
const std::string &unit = e->text;
|
||||
// waypoints reuse the item field to store precision, item = precision + 1
|
||||
// Waypoints reuse the item field to store precision,
|
||||
// item = precision + 1 and item = 0 <=> precision = 10 for backwards compatibility.
|
||||
// Also see `push_hud_element`.
|
||||
u32 item = e->item;
|
||||
float precision = (item == 0) ? 10.0f : (item - 1.f);
|
||||
bool draw_precision = precision > 0;
|
||||
|
@ -54,7 +54,6 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client):
|
||||
{
|
||||
m_cache_enable_shaders = g_settings->getBool("enable_shaders");
|
||||
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
|
||||
m_meshgen_block_cache_size = g_settings->getS32("meshgen_block_cache_size");
|
||||
}
|
||||
|
||||
MeshUpdateQueue::~MeshUpdateQueue()
|
||||
|
@ -87,7 +87,6 @@ private:
|
||||
// TODO: Add callback to update these when g_settings changes
|
||||
bool m_cache_enable_shaders;
|
||||
bool m_cache_smooth_lighting;
|
||||
int m_meshgen_block_cache_size;
|
||||
|
||||
void fillDataFromMapBlocks(QueuedMeshUpdate *q);
|
||||
void cleanupCache();
|
||||
|
@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
*/
|
||||
|
||||
#include <optional>
|
||||
#include <IrrlichtDevice.h>
|
||||
#include <irrlicht.h>
|
||||
#include "fontengine.h"
|
||||
#include "client.h"
|
||||
#include "clouds.h"
|
||||
@ -292,15 +292,16 @@ std::vector<video::E_DRIVER_TYPE> RenderingEngine::getSupportedVideoDrivers()
|
||||
// Order by preference (best first)
|
||||
static const video::E_DRIVER_TYPE glDrivers[] = {
|
||||
video::EDT_OPENGL,
|
||||
video::EDT_OPENGL3,
|
||||
video::EDT_OGLES2,
|
||||
video::EDT_OGLES1,
|
||||
video::EDT_NULL,
|
||||
};
|
||||
std::vector<video::E_DRIVER_TYPE> drivers;
|
||||
|
||||
for (u32 i = 0; i < ARRLEN(glDrivers); i++) {
|
||||
if (IrrlichtDevice::isDriverSupported(glDrivers[i]))
|
||||
drivers.push_back(glDrivers[i]);
|
||||
for (video::E_DRIVER_TYPE driver: glDrivers) {
|
||||
if (IrrlichtDevice::isDriverSupported(driver))
|
||||
drivers.push_back(driver);
|
||||
}
|
||||
|
||||
return drivers;
|
||||
@ -328,6 +329,7 @@ const VideoDriverInfo &RenderingEngine::getVideoDriverInfo(irr::video::E_DRIVER_
|
||||
static const std::unordered_map<int, VideoDriverInfo> driver_info_map = {
|
||||
{(int)video::EDT_NULL, {"null", "NULL Driver"}},
|
||||
{(int)video::EDT_OPENGL, {"opengl", "OpenGL"}},
|
||||
{(int)video::EDT_OPENGL3, {"opengl3", "OpenGL 3+"}},
|
||||
{(int)video::EDT_OGLES1, {"ogles1", "OpenGL ES1"}},
|
||||
{(int)video::EDT_OGLES2, {"ogles2", "OpenGL ES2"}},
|
||||
};
|
||||
|
@ -43,6 +43,9 @@ class Minimap;
|
||||
|
||||
class RenderingCore;
|
||||
|
||||
// Instead of a mechanism to disable fog we just set it to be really far away
|
||||
#define FOG_RANGE_ALL (100000 * BS)
|
||||
|
||||
class RenderingEngine
|
||||
{
|
||||
public:
|
||||
@ -138,17 +141,6 @@ public:
|
||||
const irr::core::dimension2d<u32> initial_screen_size,
|
||||
const bool initial_window_maximized);
|
||||
|
||||
static bool shouldRender()
|
||||
{
|
||||
// On Android, pause rendering while the app is in background (generally not visible).
|
||||
// Don't do this on desktop because windows can be partially visible.
|
||||
#ifdef __ANDROID__
|
||||
return get_raw_device()->isWindowActive();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
};
|
||||
|
||||
private:
|
||||
v2u32 _getWindowSize() const;
|
||||
|
||||
|
@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <IShaderConstantSetCallBack.h>
|
||||
#include "client/renderingengine.h"
|
||||
#include "EShaderTypes.h"
|
||||
#include "gettext.h"
|
||||
#include "log.h"
|
||||
#include "gamedef.h"
|
||||
#include "client/tile.h"
|
||||
@ -210,51 +211,36 @@ public:
|
||||
|
||||
class MainShaderConstantSetter : public IShaderConstantSetter
|
||||
{
|
||||
CachedVertexShaderSetting<f32, 16> m_world_view_proj;
|
||||
CachedVertexShaderSetting<f32, 16> m_world;
|
||||
CachedVertexShaderSetting<f32, 16> m_world_view_proj{"mWorldViewProj"};
|
||||
CachedVertexShaderSetting<f32, 16> m_world{"mWorld"};
|
||||
|
||||
// Shadow-related
|
||||
CachedPixelShaderSetting<f32, 16> m_shadow_view_proj;
|
||||
CachedPixelShaderSetting<f32, 3> m_light_direction;
|
||||
CachedPixelShaderSetting<f32> m_texture_res;
|
||||
CachedPixelShaderSetting<f32> m_shadow_strength;
|
||||
CachedPixelShaderSetting<f32> m_time_of_day;
|
||||
CachedPixelShaderSetting<f32> m_shadowfar;
|
||||
CachedPixelShaderSetting<f32, 4> m_camera_pos;
|
||||
CachedPixelShaderSetting<s32> m_shadow_texture;
|
||||
CachedVertexShaderSetting<f32> m_perspective_bias0_vertex;
|
||||
CachedPixelShaderSetting<f32> m_perspective_bias0_pixel;
|
||||
CachedVertexShaderSetting<f32> m_perspective_bias1_vertex;
|
||||
CachedPixelShaderSetting<f32> m_perspective_bias1_pixel;
|
||||
CachedVertexShaderSetting<f32> m_perspective_zbias_vertex;
|
||||
CachedPixelShaderSetting<f32> m_perspective_zbias_pixel;
|
||||
CachedPixelShaderSetting<f32, 16> m_shadow_view_proj{"m_ShadowViewProj"};
|
||||
CachedPixelShaderSetting<f32, 3> m_light_direction{"v_LightDirection"};
|
||||
CachedPixelShaderSetting<f32> m_texture_res{"f_textureresolution"};
|
||||
CachedPixelShaderSetting<f32> m_shadow_strength{"f_shadow_strength"};
|
||||
CachedPixelShaderSetting<f32> m_time_of_day{"f_timeofday"};
|
||||
CachedPixelShaderSetting<f32> m_shadowfar{"f_shadowfar"};
|
||||
CachedPixelShaderSetting<f32, 4> m_camera_pos{"CameraPos"};
|
||||
CachedPixelShaderSetting<s32> m_shadow_texture{"ShadowMapSampler"};
|
||||
CachedVertexShaderSetting<f32>
|
||||
m_perspective_bias0_vertex{"xyPerspectiveBias0"};
|
||||
CachedPixelShaderSetting<f32>
|
||||
m_perspective_bias0_pixel{"xyPerspectiveBias0"};
|
||||
CachedVertexShaderSetting<f32>
|
||||
m_perspective_bias1_vertex{"xyPerspectiveBias1"};
|
||||
CachedPixelShaderSetting<f32>
|
||||
m_perspective_bias1_pixel{"xyPerspectiveBias1"};
|
||||
CachedVertexShaderSetting<f32>
|
||||
m_perspective_zbias_vertex{"zPerspectiveBias"};
|
||||
CachedPixelShaderSetting<f32> m_perspective_zbias_pixel{"zPerspectiveBias"};
|
||||
|
||||
// Modelview matrix
|
||||
CachedVertexShaderSetting<float, 16> m_world_view;
|
||||
CachedVertexShaderSetting<float, 16> m_world_view{"mWorldView"};
|
||||
// Texture matrix
|
||||
CachedVertexShaderSetting<float, 16> m_texture;
|
||||
CachedVertexShaderSetting<float, 16> m_texture{"mTexture"};
|
||||
|
||||
public:
|
||||
MainShaderConstantSetter() :
|
||||
m_world_view_proj("mWorldViewProj")
|
||||
, m_world("mWorld")
|
||||
, m_shadow_view_proj("m_ShadowViewProj")
|
||||
, m_light_direction("v_LightDirection")
|
||||
, m_texture_res("f_textureresolution")
|
||||
, m_shadow_strength("f_shadow_strength")
|
||||
, m_time_of_day("f_timeofday")
|
||||
, m_shadowfar("f_shadowfar")
|
||||
, m_camera_pos("CameraPos")
|
||||
, m_shadow_texture("ShadowMapSampler")
|
||||
, m_perspective_bias0_vertex("xyPerspectiveBias0")
|
||||
, m_perspective_bias0_pixel("xyPerspectiveBias0")
|
||||
, m_perspective_bias1_vertex("xyPerspectiveBias1")
|
||||
, m_perspective_bias1_pixel("xyPerspectiveBias1")
|
||||
, m_perspective_zbias_vertex("zPerspectiveBias")
|
||||
, m_perspective_zbias_pixel("zPerspectiveBias")
|
||||
, m_world_view("mWorldView")
|
||||
, m_texture("mTexture")
|
||||
{}
|
||||
~MainShaderConstantSetter() = default;
|
||||
|
||||
virtual void onSetConstants(video::IMaterialRendererServices *services) override
|
||||
@ -276,7 +262,7 @@ public:
|
||||
worldViewProj *= worldView;
|
||||
m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
|
||||
|
||||
if (driver->getDriverType() == video::EDT_OGLES2) {
|
||||
if (driver->getDriverType() == video::EDT_OGLES2 || driver->getDriverType() == video::EDT_OPENGL3) {
|
||||
core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
|
||||
m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
|
||||
m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
|
||||
@ -603,23 +589,25 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||
|
||||
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||
if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
|
||||
errorstream << "Shaders are enabled but GLSL is not supported by the driver\n";
|
||||
return shaderinfo;
|
||||
throw ShaderException(gettext("Shaders are enabled but GLSL is not "
|
||||
"supported by the driver."));
|
||||
}
|
||||
video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
|
||||
|
||||
// Create shaders header
|
||||
bool use_gles = driver->getDriverType() == video::EDT_OGLES2;
|
||||
bool fully_programmable = driver->getDriverType() == video::EDT_OGLES2 || driver->getDriverType() == video::EDT_OPENGL3;
|
||||
std::stringstream shaders_header;
|
||||
shaders_header
|
||||
<< std::noboolalpha
|
||||
<< std::showpoint // for GLSL ES
|
||||
;
|
||||
std::string vertex_header, fragment_header, geometry_header;
|
||||
if (use_gles) {
|
||||
shaders_header << R"(
|
||||
#version 100
|
||||
)";
|
||||
if (fully_programmable) {
|
||||
if (driver->getDriverType() == video::EDT_OPENGL3) {
|
||||
shaders_header << "#version 150\n";
|
||||
} else {
|
||||
shaders_header << "#version 100\n";
|
||||
}
|
||||
vertex_header = R"(
|
||||
precision mediump float;
|
||||
|
||||
@ -673,7 +661,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||
abort();
|
||||
}
|
||||
|
||||
bool use_discard = use_gles;
|
||||
bool use_discard = fully_programmable;
|
||||
// For renderers that should use discard instead of GL_ALPHA_TEST
|
||||
const char *renderer = reinterpret_cast<const char*>(GL.GetString(GL.RENDERER));
|
||||
if (strstr(renderer, "GC7000"))
|
||||
@ -805,7 +793,9 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||
dumpShaderProgram(warningstream, "Vertex", vertex_shader);
|
||||
dumpShaderProgram(warningstream, "Fragment", fragment_shader);
|
||||
dumpShaderProgram(warningstream, "Geometry", geometry_shader);
|
||||
return shaderinfo;
|
||||
throw ShaderException(
|
||||
fmtgettext("Failed to compile the \"%s\" shader.", name.c_str()) +
|
||||
strgettext("\nCheck debug.txt for details."));
|
||||
}
|
||||
|
||||
// Apply the newly created material type
|
||||
|
@ -39,16 +39,12 @@ private:
|
||||
class shadowScreenQuadCB : public video::IShaderConstantSetCallBack
|
||||
{
|
||||
public:
|
||||
shadowScreenQuadCB() :
|
||||
m_sm_client_map_setting("ShadowMapClientMap"),
|
||||
m_sm_client_map_trans_setting("ShadowMapClientMapTraslucent"),
|
||||
m_sm_dynamic_sampler_setting("ShadowMapSamplerdynamic")
|
||||
{}
|
||||
|
||||
virtual void OnSetConstants(video::IMaterialRendererServices *services,
|
||||
s32 userData);
|
||||
private:
|
||||
CachedPixelShaderSetting<s32> m_sm_client_map_setting;
|
||||
CachedPixelShaderSetting<s32> m_sm_client_map_trans_setting;
|
||||
CachedPixelShaderSetting<s32> m_sm_dynamic_sampler_setting;
|
||||
CachedPixelShaderSetting<s32> m_sm_client_map_setting{"ShadowMapClientMap"};
|
||||
CachedPixelShaderSetting<s32>
|
||||
m_sm_client_map_trans_setting{"ShadowMapClientMapTraslucent"};
|
||||
CachedPixelShaderSetting<s32>
|
||||
m_sm_dynamic_sampler_setting{"ShadowMapSamplerdynamic"};
|
||||
};
|
||||
|
@ -26,17 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
class ShadowDepthShaderCB : public video::IShaderConstantSetCallBack
|
||||
{
|
||||
public:
|
||||
ShadowDepthShaderCB() :
|
||||
m_light_mvp_setting("LightMVP"),
|
||||
m_map_resolution_setting("MapResolution"),
|
||||
m_max_far_setting("MaxFar"),
|
||||
m_color_map_sampler_setting("ColorMapSampler"),
|
||||
m_perspective_bias0("xyPerspectiveBias0"),
|
||||
m_perspective_bias1("xyPerspectiveBias1"),
|
||||
m_perspective_zbias("zPerspectiveBias"),
|
||||
m_cam_pos_setting("CameraPos")
|
||||
{}
|
||||
|
||||
void OnSetMaterial(const video::SMaterial &material) override {}
|
||||
|
||||
void OnSetConstants(video::IMaterialRendererServices *services,
|
||||
@ -47,12 +36,13 @@ public:
|
||||
v3f CameraPos;
|
||||
|
||||
private:
|
||||
CachedVertexShaderSetting<f32, 16> m_light_mvp_setting;
|
||||
CachedVertexShaderSetting<f32> m_map_resolution_setting;
|
||||
CachedVertexShaderSetting<f32> m_max_far_setting;
|
||||
CachedPixelShaderSetting<s32> m_color_map_sampler_setting;
|
||||
CachedVertexShaderSetting<f32> m_perspective_bias0;
|
||||
CachedVertexShaderSetting<f32> m_perspective_bias1;
|
||||
CachedVertexShaderSetting<f32> m_perspective_zbias;
|
||||
CachedVertexShaderSetting<f32, 4> m_cam_pos_setting;
|
||||
CachedVertexShaderSetting<f32, 16> m_light_mvp_setting{"LightMVP"};
|
||||
CachedVertexShaderSetting<f32> m_map_resolution_setting{"MapResolution"};
|
||||
CachedVertexShaderSetting<f32> m_max_far_setting{"MaxFar"};
|
||||
CachedPixelShaderSetting<s32>
|
||||
m_color_map_sampler_setting{"ColorMapSampler"};
|
||||
CachedVertexShaderSetting<f32> m_perspective_bias0{"xyPerspectiveBias0"};
|
||||
CachedVertexShaderSetting<f32> m_perspective_bias1{"xyPerspectiveBias1"};
|
||||
CachedVertexShaderSetting<f32> m_perspective_zbias{"zPerspectiveBias"};
|
||||
CachedVertexShaderSetting<f32, 4> m_cam_pos_setting{"CameraPos"};
|
||||
};
|
||||
|
@ -54,12 +54,12 @@ public:
|
||||
|
||||
float getBrightness() { return m_brightness; }
|
||||
|
||||
const video::SColor &getBgColor() const
|
||||
video::SColor getBgColor() const
|
||||
{
|
||||
return m_visible ? m_bgcolor : m_fallback_bg_color;
|
||||
}
|
||||
|
||||
const video::SColor &getSkyColor() const
|
||||
video::SColor getSkyColor() const
|
||||
{
|
||||
return m_visible ? m_skycolor : m_fallback_bg_color;
|
||||
}
|
||||
@ -90,6 +90,7 @@ public:
|
||||
const video::SColorf &getCloudColor() const { return m_cloudcolor_f; }
|
||||
|
||||
void setVisible(bool visible) { m_visible = visible; }
|
||||
|
||||
// Set only from set_sky API
|
||||
void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; }
|
||||
void setFallbackBgColor(video::SColor fallback_bg_color)
|
||||
@ -111,17 +112,23 @@ public:
|
||||
const std::string &use_sun_tint);
|
||||
void setInClouds(bool clouds) { m_in_clouds = clouds; }
|
||||
void clearSkyboxTextures() { m_sky_params.textures.clear(); }
|
||||
void addTextureToSkybox(const std::string &texture, int material_id,
|
||||
void addTextureToSkybox(const std::string &texture, int material_id,
|
||||
ITextureSource *tsrc);
|
||||
const video::SColorf &getCurrentStarColor() const { return m_star_color; }
|
||||
|
||||
// Note: the Sky class doesn't use these values. It just stores them.
|
||||
void setFogDistance(s16 fog_distance) { m_sky_params.fog_distance = fog_distance; }
|
||||
s16 getFogDistance() const { return m_sky_params.fog_distance; }
|
||||
|
||||
void setFogStart(float fog_start) { m_sky_params.fog_start = fog_start; }
|
||||
float getFogStart() const { return m_sky_params.fog_start; }
|
||||
|
||||
void setVolumetricLightStrength(float volumetric_light_strength) { m_sky_params.volumetric_light_strength = volumetric_light_strength; }
|
||||
float getVolumetricLightStrength() const { return m_sky_params.volumetric_light_strength; }
|
||||
void setFogColor(video::SColor v) { m_sky_params.fog_color = v; }
|
||||
video::SColor getFogColor() const {
|
||||
if (m_sky_params.fog_color.getAlpha() > 0)
|
||||
return m_sky_params.fog_color;
|
||||
return getBgColor();
|
||||
}
|
||||
|
||||
private:
|
||||
aabb3f m_box;
|
||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <algorithm>
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <IVideoDriver.h>
|
||||
#include <IFileSystem.h>
|
||||
#include "util/string.h"
|
||||
#include "util/container.h"
|
||||
#include "util/thread.h"
|
||||
@ -38,7 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
/*
|
||||
A cache from texture name to texture path
|
||||
*/
|
||||
MutexedMap<std::string, std::string> g_texturename_to_path_cache;
|
||||
static MutexedMap<std::string, std::string> g_texturename_to_path_cache;
|
||||
|
||||
/*
|
||||
Replaces the filename extension.
|
||||
@ -185,11 +186,11 @@ struct TextureInfo
|
||||
TextureInfo(
|
||||
const std::string &name_,
|
||||
video::ITexture *texture_,
|
||||
std::set<std::string> &sourceImages_
|
||||
std::set<std::string> &&sourceImages_
|
||||
):
|
||||
name(name_),
|
||||
texture(texture_),
|
||||
sourceImages(sourceImages_)
|
||||
sourceImages(std::move(sourceImages_))
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -486,8 +487,6 @@ TextureSource::~TextureSource()
|
||||
|
||||
u32 TextureSource::getTextureId(const std::string &name)
|
||||
{
|
||||
//infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
|
||||
|
||||
{
|
||||
/*
|
||||
See if texture already exists
|
||||
@ -552,16 +551,16 @@ static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
|
||||
// color alpha with the destination alpha.
|
||||
// Otherwise, any pixels that are not fully transparent get the color alpha.
|
||||
static void apply_colorize(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||
const video::SColor &color, int ratio, bool keep_alpha);
|
||||
const video::SColor color, int ratio, bool keep_alpha);
|
||||
|
||||
// paint a texture using the given color
|
||||
static void apply_multiplication(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||
const video::SColor &color);
|
||||
const video::SColor color);
|
||||
|
||||
// Perform a Screen blend with the given color. The opposite effect of a
|
||||
// Multiply blend.
|
||||
static void apply_screen(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||
const video::SColor &color);
|
||||
const video::SColor color);
|
||||
|
||||
// Adjust the hue, saturation, and lightness of destination. Like
|
||||
// "Hue-Saturation" in GIMP.
|
||||
@ -607,8 +606,6 @@ void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
|
||||
*/
|
||||
u32 TextureSource::generateTexture(const std::string &name)
|
||||
{
|
||||
//infostream << "generateTexture(): name=\"" << name << "\"" << std::endl;
|
||||
|
||||
// Empty name means texture 0
|
||||
if (name.empty()) {
|
||||
infostream<<"generateTexture(): name is empty"<<std::endl;
|
||||
@ -620,8 +617,7 @@ u32 TextureSource::generateTexture(const std::string &name)
|
||||
See if texture already exists
|
||||
*/
|
||||
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||
std::map<std::string, u32>::iterator n;
|
||||
n = m_name_to_id.find(name);
|
||||
auto n = m_name_to_id.find(name);
|
||||
if (n != m_name_to_id.end()) {
|
||||
return n->second;
|
||||
}
|
||||
@ -660,8 +656,8 @@ u32 TextureSource::generateTexture(const std::string &name)
|
||||
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||
|
||||
u32 id = m_textureinfo_cache.size();
|
||||
TextureInfo ti(name, tex, source_image_names);
|
||||
m_textureinfo_cache.push_back(ti);
|
||||
TextureInfo ti(name, tex, std::move(source_image_names));
|
||||
m_textureinfo_cache.emplace_back(std::move(ti));
|
||||
m_name_to_id[name] = id;
|
||||
|
||||
return id;
|
||||
@ -707,7 +703,7 @@ video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *
|
||||
const bool filter_needed =
|
||||
m_setting_mipmap || m_setting_trilinear_filter ||
|
||||
m_setting_bilinear_filter || m_setting_anisotropic_filter;
|
||||
if (filter_needed)
|
||||
if (filter_needed && !name.empty())
|
||||
return getTexture(name + "^[applyfiltersformesh", id);
|
||||
return getTexture(name, id);
|
||||
}
|
||||
@ -779,19 +775,12 @@ void TextureSource::processQueue()
|
||||
GetRequest<std::string, u32, std::thread::id, u8>
|
||||
request = m_get_texture_queue.pop();
|
||||
|
||||
/*infostream<<"TextureSource::processQueue(): "
|
||||
<<"got texture request with "
|
||||
<<"name=\""<<request.key<<"\""
|
||||
<<std::endl;*/
|
||||
|
||||
m_get_texture_queue.pushResult(request, generateTexture(request.key));
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSource::insertSourceImage(const std::string &name, video::IImage *img)
|
||||
{
|
||||
//infostream<<"TextureSource::insertSourceImage(): name="<<name<<std::endl;
|
||||
|
||||
sanity_check(std::this_thread::get_id() == m_main_thread);
|
||||
|
||||
m_sourcecache.insert(name, img, true);
|
||||
@ -838,8 +827,7 @@ void TextureSource::rebuildImagesAndTextures()
|
||||
|
||||
void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
|
||||
{
|
||||
if (ti.name.empty())
|
||||
return; // this shouldn't happen, just a precaution
|
||||
assert(!ti.name.empty());
|
||||
|
||||
// replaces the previous sourceImages
|
||||
// shouldn't really need to be done, but can't hurt
|
||||
@ -856,7 +844,7 @@ void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
|
||||
video::ITexture *t_old = ti.texture;
|
||||
// Replace texture
|
||||
ti.texture = t;
|
||||
ti.sourceImages = source_image_names;
|
||||
ti.sourceImages = std::move(source_image_names);
|
||||
|
||||
if (t_old)
|
||||
m_texture_trash.push_back(t_old);
|
||||
@ -1074,6 +1062,12 @@ video::IImage* TextureSource::generateImage(const std::string &name, std::set<st
|
||||
if (baseimg == NULL) {
|
||||
errorstream << "generateImage(): baseimg is NULL (attempted to"
|
||||
" create texture \"" << name << "\")" << std::endl;
|
||||
} else if (baseimg->getDimension().Width == 0 ||
|
||||
baseimg->getDimension().Height == 0) {
|
||||
errorstream << "generateImage(): zero-sized image was created?! "
|
||||
"(attempted to create texture \"" << name << "\")" << std::endl;
|
||||
baseimg->drop();
|
||||
baseimg = nullptr;
|
||||
}
|
||||
|
||||
return baseimg;
|
||||
@ -1182,6 +1176,31 @@ void blitBaseImage(video::IImage* &src, video::IImage* &dst)
|
||||
blit_with_alpha(src, dst, pos_from, pos_to, dim_dst);
|
||||
}
|
||||
|
||||
#define CHECK_BASEIMG() \
|
||||
do { \
|
||||
if (!baseimg) { \
|
||||
errorstream << "generateImagePart(): baseimg == NULL" \
|
||||
<< " for part_of_name=\"" << part_of_name \
|
||||
<< "\", cancelling." << std::endl; \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define COMPLAIN_INVALID(description) \
|
||||
do { \
|
||||
errorstream << "generateImagePart(): invalid " << (description) \
|
||||
<< " for part_of_name=\"" << part_of_name \
|
||||
<< "\", cancelling." << std::endl; \
|
||||
return false; \
|
||||
} while(0)
|
||||
|
||||
#define CHECK_DIM(w, h) \
|
||||
do { \
|
||||
if ((w) <= 0 || (h) <= 0 || (w) >= 0xffff || (h) >= 0xffff) { \
|
||||
COMPLAIN_INVALID("width or height"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
video::IImage *& baseimg, std::set<std::string> &source_image_names)
|
||||
{
|
||||
@ -1189,48 +1208,44 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||
sanity_check(driver);
|
||||
|
||||
if (baseimg && (baseimg->getDimension().Width == 0 ||
|
||||
baseimg->getDimension().Height == 0)) {
|
||||
errorstream << "generateImagePart(): baseimg is zero-sized?!"
|
||||
<< std::endl;
|
||||
baseimg->drop();
|
||||
baseimg = nullptr;
|
||||
}
|
||||
|
||||
// Stuff starting with [ are special commands
|
||||
if (part_of_name.empty() || part_of_name[0] != '[') {
|
||||
source_image_names.insert(part_of_name);
|
||||
video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
|
||||
if (image == NULL) {
|
||||
if (!part_of_name.empty()) {
|
||||
if (!image) {
|
||||
// Do not create the dummy texture
|
||||
if (part_of_name.empty())
|
||||
return true;
|
||||
|
||||
// Do not create normalmap dummies
|
||||
if (part_of_name.find("_normal.png") != std::string::npos) {
|
||||
warningstream << "generateImage(): Could not load normal map \""
|
||||
<< part_of_name << "\"" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
errorstream << "generateImage(): Could not load image \""
|
||||
<< part_of_name << "\" while building texture; "
|
||||
"Creating a dummy image" << std::endl;
|
||||
// Do not create normalmap dummies
|
||||
if (str_ends_with(part_of_name, "_normal.png")) {
|
||||
warningstream << "generateImagePart(): Could not load normal map \""
|
||||
<< part_of_name << "\"" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Just create a dummy image
|
||||
//core::dimension2d<u32> dim(2,2);
|
||||
errorstream << "generateImagePart(): Could not load image \""
|
||||
<< part_of_name << "\" while building texture; "
|
||||
"Creating a dummy image" << std::endl;
|
||||
|
||||
core::dimension2d<u32> dim(1,1);
|
||||
image = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
sanity_check(image != NULL);
|
||||
/*image->setPixel(0,0, video::SColor(255,255,0,0));
|
||||
image->setPixel(1,0, video::SColor(255,0,255,0));
|
||||
image->setPixel(0,1, video::SColor(255,0,0,255));
|
||||
image->setPixel(1,1, video::SColor(255,255,0,255));*/
|
||||
image->setPixel(0,0, video::SColor(255,myrand()%256,
|
||||
myrand()%256,myrand()%256));
|
||||
/*image->setPixel(1,0, video::SColor(255,myrand()%256,
|
||||
myrand()%256,myrand()%256));
|
||||
image->setPixel(0,1, video::SColor(255,myrand()%256,
|
||||
myrand()%256,myrand()%256));
|
||||
image->setPixel(1,1, video::SColor(255,myrand()%256,
|
||||
myrand()%256,myrand()%256));*/
|
||||
}
|
||||
|
||||
// If base image is NULL, load as base.
|
||||
if (baseimg == NULL)
|
||||
{
|
||||
//infostream<<"Setting "<<part_of_name<<" as base"<<std::endl;
|
||||
/*
|
||||
Copy it this way to get an alpha channel.
|
||||
Otherwise images with alpha cannot be blitted on
|
||||
@ -1245,17 +1260,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
{
|
||||
blitBaseImage(image, baseimg);
|
||||
}
|
||||
//cleanup
|
||||
|
||||
image->drop();
|
||||
}
|
||||
else
|
||||
{
|
||||
// A special texture modification
|
||||
|
||||
/*infostream<<"generateImage(): generating special "
|
||||
<<"modification \""<<part_of_name<<"\""
|
||||
<<std::endl;*/
|
||||
|
||||
/*
|
||||
[crack:N:P
|
||||
[cracko:N:P
|
||||
@ -1264,12 +1275,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
if (str_starts_with(part_of_name, "[crack"))
|
||||
{
|
||||
if (baseimg == NULL) {
|
||||
errorstream<<"generateImagePart(): baseimg == NULL "
|
||||
<<"for part_of_name=\""<<part_of_name
|
||||
<<"\", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
// Crack image number and overlay option
|
||||
// Format: crack[o][:<tiles>]:<frame_count>:<frame>
|
||||
@ -1317,6 +1323,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
sf.next(":");
|
||||
u32 w0 = stoi(sf.next("x"));
|
||||
u32 h0 = stoi(sf.next(":"));
|
||||
CHECK_DIM(w0, h0);
|
||||
core::dimension2d<u32> dim(w0,h0);
|
||||
if (baseimg == NULL) {
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
@ -1326,9 +1333,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
u32 x = stoi(sf.next(","));
|
||||
u32 y = stoi(sf.next("="));
|
||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||
|
||||
if (x >= w0 || y >= h0)
|
||||
COMPLAIN_INVALID("X or Y offset");
|
||||
infostream<<"Adding \""<<filename
|
||||
<<"\" to combined ("<<x<<","<<y<<")"
|
||||
<<std::endl;
|
||||
|
||||
video::IImage *img = generateImage(filename, source_image_names);
|
||||
if (img) {
|
||||
core::dimension2d<u32> dim = img->getDimension();
|
||||
@ -1337,10 +1348,6 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
img->copyTo(img2);
|
||||
img->drop();
|
||||
/*img2->copyToWithAlpha(baseimg, pos_base,
|
||||
core::rect<s32>(v2s32(0,0), dim),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);*/
|
||||
blit_with_alpha(img2, baseimg, v2s32(0,0), pos_base, dim);
|
||||
img2->drop();
|
||||
} else {
|
||||
@ -1357,8 +1364,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[fill"))
|
||||
{
|
||||
s32 x = 0;
|
||||
s32 y = 0;
|
||||
u32 x = 0;
|
||||
u32 y = 0;
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
@ -1377,6 +1384,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
}
|
||||
core::dimension2d<u32> dim(width, height);
|
||||
|
||||
CHECK_DIM(dim.Width, dim.Height);
|
||||
if (baseimg) {
|
||||
auto basedim = baseimg->getDimension();
|
||||
if (x >= basedim.Width || y >= basedim.Height)
|
||||
COMPLAIN_INVALID("X or Y offset");
|
||||
}
|
||||
|
||||
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
img->fill(color);
|
||||
|
||||
@ -1392,12 +1406,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[brighten"))
|
||||
{
|
||||
if (baseimg == NULL) {
|
||||
errorstream<<"generateImagePart(): baseimg==NULL "
|
||||
<<"for part_of_name=\""<<part_of_name
|
||||
<<"\", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
brighten(baseimg);
|
||||
}
|
||||
@ -1410,13 +1419,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[noalpha"))
|
||||
{
|
||||
if (baseimg == NULL){
|
||||
errorstream<<"generateImagePart(): baseimg==NULL "
|
||||
<<"for part_of_name=\""<<part_of_name
|
||||
<<"\", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_BASEIMG();
|
||||
core::dimension2d<u32> dim = baseimg->getDimension();
|
||||
|
||||
// Set alpha to full
|
||||
@ -1434,12 +1437,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[makealpha:"))
|
||||
{
|
||||
if (baseimg == NULL) {
|
||||
errorstream<<"generateImagePart(): baseimg == NULL "
|
||||
<<"for part_of_name=\""<<part_of_name
|
||||
<<"\", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name.substr(11));
|
||||
u32 r1 = stoi(sf.next(","));
|
||||
@ -1448,12 +1446,6 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
|
||||
core::dimension2d<u32> dim = baseimg->getDimension();
|
||||
|
||||
/*video::IImage *oldbaseimg = baseimg;
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
oldbaseimg->copyTo(baseimg);
|
||||
oldbaseimg->drop();*/
|
||||
|
||||
// Set alpha to full
|
||||
for (u32 y=0; y<dim.Height; y++)
|
||||
for (u32 x=0; x<dim.Width; x++)
|
||||
{
|
||||
@ -1489,12 +1481,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[transform"))
|
||||
{
|
||||
if (baseimg == NULL) {
|
||||
errorstream<<"generateImagePart(): baseimg == NULL "
|
||||
<<"for part_of_name=\""<<part_of_name
|
||||
<<"\", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
u32 transform = parseImageTransform(part_of_name.substr(10));
|
||||
core::dimension2d<u32> dim = imageTransformDimension(
|
||||
@ -1516,7 +1503,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[inventorycube"))
|
||||
{
|
||||
if (baseimg != NULL){
|
||||
if (baseimg) {
|
||||
errorstream<<"generateImagePart(): baseimg != NULL "
|
||||
<<"for part_of_name=\""<<part_of_name
|
||||
<<"\", cancelling."<<std::endl;
|
||||
@ -1539,8 +1526,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
errorstream << "generateImagePart(): Failed to create textures"
|
||||
<< " for inventorycube \"" << part_of_name << "\""
|
||||
<< std::endl;
|
||||
baseimg = generateImage(imagename_top, source_image_names);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
baseimg = createInventoryCubeImage(img_top, img_left, img_right);
|
||||
@ -1560,30 +1546,26 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
{
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
u32 percent = stoi(sf.next(":"));
|
||||
u32 percent = stoi(sf.next(":"), 0, 100);
|
||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||
|
||||
if (baseimg == NULL)
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
|
||||
video::IImage *img = generateImage(filename, source_image_names);
|
||||
if (img)
|
||||
{
|
||||
if (img) {
|
||||
core::dimension2d<u32> dim = img->getDimension();
|
||||
if (!baseimg)
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
|
||||
core::position2d<s32> pos_base(0, 0);
|
||||
video::IImage *img2 =
|
||||
driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
img->copyTo(img2);
|
||||
img->drop();
|
||||
core::position2d<s32> clippos(0, 0);
|
||||
clippos.Y = dim.Height * (100-percent) / 100;
|
||||
core::dimension2d<u32> clipdim = dim;
|
||||
clipdim.Height = clipdim.Height * percent / 100 + 1;
|
||||
core::rect<s32> cliprect(clippos, clipdim);
|
||||
img2->copyToWithAlpha(baseimg, pos_base,
|
||||
img->copyToWithAlpha(baseimg, pos_base,
|
||||
core::rect<s32>(v2s32(0,0), dim),
|
||||
video::SColor(255,255,255,255),
|
||||
&cliprect);
|
||||
img2->drop();
|
||||
img->drop();
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -1593,6 +1575,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[verticalframe:"))
|
||||
{
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
u32 frame_count = stoi(sf.next(":"));
|
||||
@ -1604,25 +1588,14 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
<< "\", using frame_count = 1 instead." << std::endl;
|
||||
frame_count = 1;
|
||||
}
|
||||
|
||||
if (baseimg == NULL){
|
||||
errorstream<<"generateImagePart(): baseimg != NULL "
|
||||
<<"for part_of_name=\""<<part_of_name
|
||||
<<"\", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
if (frame_index >= frame_count)
|
||||
frame_index = frame_count - 1;
|
||||
|
||||
v2u32 frame_size = baseimg->getDimension();
|
||||
frame_size.Y /= frame_count;
|
||||
|
||||
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8,
|
||||
frame_size);
|
||||
if (!img){
|
||||
errorstream<<"generateImagePart(): Could not create image "
|
||||
<<"for part_of_name=\""<<part_of_name
|
||||
<<"\", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill target image with transparency
|
||||
img->fill(video::SColor(0,0,0,0));
|
||||
@ -1644,12 +1617,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[mask:"))
|
||||
{
|
||||
if (baseimg == NULL) {
|
||||
errorstream << "generateImage(): baseimg == NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||
@ -1660,8 +1629,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
img->getDimension());
|
||||
img->drop();
|
||||
} else {
|
||||
errorstream << "generateImage(): Failed to load \""
|
||||
<< filename << "\".";
|
||||
errorstream << "generateImagePart(): Failed to load image \""
|
||||
<< filename << "\" for [mask" << std::endl;
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -1680,12 +1649,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
sf.next(":");
|
||||
std::string color_str = sf.next(":");
|
||||
|
||||
if (baseimg == NULL) {
|
||||
errorstream << "generateImagePart(): baseimg != NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
video::SColor color;
|
||||
|
||||
@ -1711,12 +1675,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
std::string color_str = sf.next(":");
|
||||
std::string ratio_str = sf.next(":");
|
||||
|
||||
if (baseimg == NULL) {
|
||||
errorstream << "generateImagePart(): baseimg != NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
video::SColor color;
|
||||
int ratio = -1;
|
||||
@ -1741,12 +1700,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
/* IMPORTANT: When changing this, getTextureForMesh() needs to be
|
||||
* updated too. */
|
||||
|
||||
if (!baseimg) {
|
||||
errorstream << "generateImagePart(): baseimg == NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
// Apply the "clean transparent" filter, if needed
|
||||
if (m_setting_mipmap || m_setting_bilinear_filter ||
|
||||
@ -1768,12 +1722,6 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
* equal to the target minimum. If e.g. this is a vertical frames
|
||||
* animation, the short dimension will be the real size.
|
||||
*/
|
||||
if (dim.Width == 0 || dim.Height == 0) {
|
||||
errorstream << "generateImagePart(): Illegal 0 dimension "
|
||||
<< "for part_of_name=\""<< part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
u32 xscale = scaleto / dim.Width;
|
||||
u32 yscale = scaleto / dim.Height;
|
||||
const s32 scale = std::max(xscale, yscale);
|
||||
@ -1797,21 +1745,16 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[resize"))
|
||||
{
|
||||
if (baseimg == NULL) {
|
||||
errorstream << "generateImagePart(): baseimg == NULL "
|
||||
<< "for part_of_name=\""<< part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
u32 width = stoi(sf.next("x"));
|
||||
u32 height = stoi(sf.next(""));
|
||||
core::dimension2d<u32> dim(width, height);
|
||||
CHECK_DIM(width, height);
|
||||
|
||||
video::IImage *image = RenderingEngine::get_video_driver()->
|
||||
createImage(video::ECF_A8R8G8B8, dim);
|
||||
video::IImage *image = driver->
|
||||
createImage(video::ECF_A8R8G8B8, {width, height});
|
||||
baseimg->copyToScaling(image);
|
||||
baseimg->drop();
|
||||
baseimg = image;
|
||||
@ -1824,12 +1767,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
255 means totally opaque.
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[opacity:")) {
|
||||
if (baseimg == NULL) {
|
||||
errorstream << "generateImagePart(): baseimg == NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
@ -1854,12 +1792,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
will be inverted.
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[invert:")) {
|
||||
if (baseimg == NULL) {
|
||||
errorstream << "generateImagePart(): baseimg == NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
@ -1891,13 +1824,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
from the base image it assumes to be a
|
||||
tilesheet with dimensions W,H (in tiles).
|
||||
*/
|
||||
else if (part_of_name.substr(0,7) == "[sheet:") {
|
||||
if (baseimg == NULL) {
|
||||
errorstream << "generateImagePart(): baseimg != NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
else if (str_starts_with(part_of_name, "[sheet:")) {
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
@ -1906,26 +1834,21 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
u32 x0 = stoi(sf.next(","));
|
||||
u32 y0 = stoi(sf.next(":"));
|
||||
|
||||
if (w0 == 0 || h0 == 0) {
|
||||
errorstream << "generateImagePart(): invalid width or height "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_DIM(w0, h0);
|
||||
if (x0 >= w0 || y0 >= h0)
|
||||
COMPLAIN_INVALID("tile position (X,Y)");
|
||||
|
||||
core::dimension2d<u32> img_dim = baseimg->getDimension();
|
||||
core::dimension2d<u32> tile_dim(v2u32(img_dim) / v2u32(w0, h0));
|
||||
if (tile_dim.Width == 0)
|
||||
tile_dim.Width = 1;
|
||||
if (tile_dim.Height == 0)
|
||||
tile_dim.Height = 1;
|
||||
|
||||
video::IImage *img = driver->createImage(
|
||||
video::ECF_A8R8G8B8, tile_dim);
|
||||
if (!img) {
|
||||
errorstream << "generateImagePart(): Could not create image "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
img->fill(video::SColor(0,0,0,0));
|
||||
|
||||
v2u32 vdim(tile_dim);
|
||||
core::rect<s32> rect(v2s32(x0 * vdim.X, y0 * vdim.Y), tile_dim);
|
||||
baseimg->copyToWithAlpha(img, v2s32(0), rect,
|
||||
@ -1942,15 +1865,12 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
to produce a valid string.
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[png:")) {
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
std::string png;
|
||||
{
|
||||
std::string blob = sf.next("");
|
||||
std::string blob = part_of_name.substr(5);
|
||||
if (!base64_is_valid(blob)) {
|
||||
errorstream << "generateImagePart(): "
|
||||
<< "malformed base64 in '[png'"
|
||||
<< std::endl;
|
||||
<< "malformed base64 in [png" << std::endl;
|
||||
return false;
|
||||
}
|
||||
png = base64_decode(blob);
|
||||
@ -1995,12 +1915,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
else if (str_starts_with(part_of_name, "[hsl:") ||
|
||||
str_starts_with(part_of_name, "[colorizehsl:")) {
|
||||
|
||||
if (baseimg == nullptr) {
|
||||
errorstream << "generateImagePart(): baseimg == NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
bool colorize = str_starts_with(part_of_name, "[colorizehsl:");
|
||||
|
||||
@ -2037,12 +1952,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
else if (str_starts_with(part_of_name, "[overlay:") ||
|
||||
str_starts_with(part_of_name, "[hardlight:")) {
|
||||
|
||||
if (baseimg == nullptr) {
|
||||
errorstream << "generateImage(): baseimg == NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||
@ -2056,8 +1967,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
img->getDimension(), hardlight);
|
||||
img->drop();
|
||||
} else {
|
||||
errorstream << "generateImage(): Failed to load \""
|
||||
<< filename << "\".";
|
||||
errorstream << "generateImage(): Failed to load image \""
|
||||
<< filename << "\" for [overlay or [hardlight" << std::endl;
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -2071,12 +1982,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
*/
|
||||
else if (str_starts_with(part_of_name, "[contrast:")) {
|
||||
|
||||
if (baseimg == nullptr) {
|
||||
errorstream << "generateImagePart(): baseimg == NULL "
|
||||
<< "for part_of_name=\"" << part_of_name
|
||||
<< "\", cancelling." << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_BASEIMG();
|
||||
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
@ -2096,6 +2002,12 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef CHECK_BASEIMG
|
||||
|
||||
#undef COMPLAIN_INVALID
|
||||
|
||||
#undef CHECK_DIM
|
||||
|
||||
/*
|
||||
Calculate the color of a single pixel drawn on top of another pixel.
|
||||
|
||||
@ -2104,7 +2016,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
pixel with alpha=64 drawn atop a pixel with alpha=128 should yield a
|
||||
pixel with alpha=160, while getInterpolated would yield alpha=96.
|
||||
*/
|
||||
static inline video::SColor blitPixel(const video::SColor &src_c, const video::SColor &dst_c, u32 ratio)
|
||||
static inline video::SColor blitPixel(const video::SColor src_c, const video::SColor dst_c, u32 ratio)
|
||||
{
|
||||
if (dst_c.getAlpha() == 0)
|
||||
return src_c;
|
||||
@ -2197,7 +2109,7 @@ static void blit_with_interpolate_overlay(video::IImage *src, video::IImage *dst
|
||||
Apply color to destination, using a weighted interpolation blend
|
||||
*/
|
||||
static void apply_colorize(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||
const video::SColor &color, int ratio, bool keep_alpha)
|
||||
const video::SColor color, int ratio, bool keep_alpha)
|
||||
{
|
||||
u32 alpha = color.getAlpha();
|
||||
video::SColor dst_c;
|
||||
@ -2235,7 +2147,7 @@ static void apply_colorize(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||
Apply color to destination, using a Multiply blend mode
|
||||
*/
|
||||
static void apply_multiplication(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||
const video::SColor &color)
|
||||
const video::SColor color)
|
||||
{
|
||||
video::SColor dst_c;
|
||||
|
||||
@ -2256,7 +2168,7 @@ static void apply_multiplication(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||
Apply color to destination, using a Screen blend mode
|
||||
*/
|
||||
static void apply_screen(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||
const video::SColor &color)
|
||||
const video::SColor color)
|
||||
{
|
||||
video::SColor dst_c;
|
||||
|
||||
@ -2466,6 +2378,10 @@ video::IImage *create_crack_image(video::IImage *crack, s32 frame_index,
|
||||
core::dimension2d<u32> size, u8 tiles, video::IVideoDriver *driver)
|
||||
{
|
||||
core::dimension2d<u32> strip_size = crack->getDimension();
|
||||
|
||||
if (tiles == 0 || strip_size.getArea() == 0)
|
||||
return nullptr;
|
||||
|
||||
core::dimension2d<u32> frame_size(strip_size.Width, strip_size.Width);
|
||||
core::dimension2d<u32> tile_size(size / tiles);
|
||||
s32 frame_count = strip_size.Height / strip_size.Width;
|
||||
@ -2474,7 +2390,7 @@ video::IImage *create_crack_image(video::IImage *crack, s32 frame_index,
|
||||
core::rect<s32> frame(v2s32(0, frame_index * frame_size.Height), frame_size);
|
||||
video::IImage *result = nullptr;
|
||||
|
||||
// extract crack frame
|
||||
// extract crack frame
|
||||
video::IImage *crack_tile = driver->createImage(video::ECF_A8R8G8B8, tile_size);
|
||||
if (!crack_tile)
|
||||
return nullptr;
|
||||
@ -2491,7 +2407,7 @@ video::IImage *create_crack_image(video::IImage *crack, s32 frame_index,
|
||||
if (tiles == 1)
|
||||
return crack_tile;
|
||||
|
||||
// tile it
|
||||
// tile it
|
||||
result = driver->createImage(video::ECF_A8R8G8B8, size);
|
||||
if (!result)
|
||||
goto exit__has_tile;
|
||||
@ -2695,7 +2611,7 @@ namespace {
|
||||
return v / 12.92f;
|
||||
}
|
||||
|
||||
v3f srgb_to_linear(const video::SColor &col_srgb)
|
||||
v3f srgb_to_linear(const video::SColor col_srgb)
|
||||
{
|
||||
v3f col(col_srgb.getRed(), col_srgb.getGreen(), col_srgb.getBlue());
|
||||
col /= 255.0f;
|
||||
@ -2705,7 +2621,7 @@ namespace {
|
||||
return col;
|
||||
}
|
||||
|
||||
video::SColor linear_to_srgb(const v3f &col_linear)
|
||||
video::SColor linear_to_srgb(const v3f col_linear)
|
||||
{
|
||||
v3f col;
|
||||
col.X = linear_to_srgb_component(col_linear.X);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#cmakedefine01 USE_SYSTEM_JSONCPP
|
||||
#cmakedefine01 USE_REDIS
|
||||
#cmakedefine01 HAVE_ENDIAN_H
|
||||
#cmakedefine01 HAVE_STRLCPY
|
||||
#cmakedefine01 CURSES_HAVE_CURSES_H
|
||||
#cmakedefine01 CURSES_HAVE_NCURSES_H
|
||||
#cmakedefine01 CURSES_HAVE_NCURSES_NCURSES_H
|
||||
|
@ -42,11 +42,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#define CONNECTION_TIMEOUT 30
|
||||
|
||||
#define RESEND_TIMEOUT_MIN 0.1
|
||||
#define RESEND_TIMEOUT_MAX 3.0
|
||||
// resend_timeout = avg_rtt * this
|
||||
#define RESEND_TIMEOUT_FACTOR 4
|
||||
|
||||
/*
|
||||
Server
|
||||
*/
|
||||
|
@ -46,7 +46,6 @@ void set_default_settings()
|
||||
settings->setDefault("enable_mesh_cache", "false");
|
||||
settings->setDefault("mesh_generation_interval", "0");
|
||||
settings->setDefault("mesh_generation_threads", "0");
|
||||
settings->setDefault("meshgen_block_cache_size", "20");
|
||||
settings->setDefault("enable_vbo", "true");
|
||||
settings->setDefault("free_move", "false");
|
||||
settings->setDefault("pitch_move", "false");
|
||||
|