master #7
0
.editorconfig
Executable file → Normal file
5
.github/workflows/linux.yml
vendored
@ -73,7 +73,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
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)
|
# Older clang version (should be close to our minimum supported version)
|
||||||
clang_7:
|
clang_7:
|
||||||
|
13
.github/workflows/windows.yml
vendored
@ -74,7 +74,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
VCPKG_VERSION: 8eb57355a4ffb410a2e94c07b4dca2dffbee8e50
|
VCPKG_VERSION: 8eb57355a4ffb410a2e94c07b4dca2dffbee8e50
|
||||||
# 2023.10.19
|
# 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:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@ -124,6 +124,13 @@ jobs:
|
|||||||
- name: Build Minetest
|
- name: Build Minetest
|
||||||
run: cmake --build . --config Release
|
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
|
- name: CPack
|
||||||
run: |
|
run: |
|
||||||
If ($env:TYPE -eq "installer")
|
If ($env:TYPE -eq "installer")
|
||||||
@ -134,12 +141,10 @@ jobs:
|
|||||||
{
|
{
|
||||||
cpack -G ZIP -B "$env:GITHUB_WORKSPACE\Package"
|
cpack -G ZIP -B "$env:GITHUB_WORKSPACE\Package"
|
||||||
}
|
}
|
||||||
|
rm -r $env:GITHUB_WORKSPACE\Package\_CPack_Packages
|
||||||
env:
|
env:
|
||||||
TYPE: ${{matrix.type}}
|
TYPE: ${{matrix.type}}
|
||||||
|
|
||||||
- name: Package Clean
|
|
||||||
run: rm -r $env:GITHUB_WORKSPACE\Package\_CPack_Packages
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: msvc-${{ matrix.config.arch }}-${{ matrix.type }}
|
name: msvc-${{ matrix.config.arch }}-${{ matrix.type }}
|
||||||
|
116
.gitlab-ci.yml
@ -3,128 +3,14 @@
|
|||||||
# https://gitlab.com/minetest/minetest
|
# https://gitlab.com/minetest/minetest
|
||||||
# Pipelines URL: https://gitlab.com/minetest/minetest/pipelines
|
# 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:
|
pages:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
image: python:3.8
|
image: python:3.8
|
||||||
before_script:
|
|
||||||
- pip install -U -r doc/mkdocs/requirements.txt
|
|
||||||
script:
|
script:
|
||||||
- cd doc/mkdocs && ./build.sh
|
- ./misc/make_redirects.sh
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- public
|
- public
|
||||||
only:
|
only:
|
||||||
- master
|
- 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()
|
endif()
|
||||||
message(STATUS "Found IrrlichtMt ${IrrlichtMt_VERSION}")
|
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})
|
string(REPLACE "mt" "." TARGET_VER ${TARGET_VER_S})
|
||||||
if(IrrlichtMt_VERSION VERSION_LESS ${TARGET_VER})
|
if(IrrlichtMt_VERSION VERSION_LESS ${TARGET_VER})
|
||||||
message(FATAL_ERROR "At least IrrlichtMt ${TARGET_VER_S} is required to build")
|
message(FATAL_ERROR "At least IrrlichtMt ${TARGET_VER_S} is required to build")
|
||||||
|
@ -25,11 +25,11 @@ Table of Contents
|
|||||||
|
|
||||||
Further documentation
|
Further documentation
|
||||||
----------------------
|
----------------------
|
||||||
- Website: https://minetest.net/
|
- Website: https://www.minetest.net/
|
||||||
- Wiki: https://wiki.minetest.net/
|
- Wiki: https://wiki.minetest.net/
|
||||||
- Developer wiki: https://dev.minetest.net/
|
|
||||||
- Forum: https://forum.minetest.net/
|
- Forum: https://forum.minetest.net/
|
||||||
- GitHub: https://github.com/minetest/minetest/
|
- GitHub: https://github.com/minetest/minetest/
|
||||||
|
- [Developer documentation](doc/developing/)
|
||||||
- [doc/](doc/) directory of source distribution
|
- [doc/](doc/) directory of source distribution
|
||||||
|
|
||||||
Default controls
|
Default controls
|
||||||
|
@ -85,6 +85,17 @@ public class GameActivity extends NativeActivity {
|
|||||||
makeFullScreen();
|
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
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
// Ignore the back press so Minetest can handle it
|
// 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;
|
package net.minetest.minetest;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import static net.minetest.minetest.UnzipService.*;
|
import static net.minetest.minetest.UnzipService.*;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
public static final String NOTIFICATION_CHANNEL_ID = "Minetest channel";
|
||||||
|
|
||||||
private final static int versionCode = BuildConfig.VERSION_CODE;
|
private final static int versionCode = BuildConfig.VERSION_CODE;
|
||||||
private static final String SETTINGS = "MinetestSettings";
|
private static final String SETTINGS = "MinetestSettings";
|
||||||
private static final String TAG_VERSION_CODE = "versionCode";
|
private static final String TAG_VERSION_CODE = "versionCode";
|
||||||
@ -81,12 +87,18 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter(ACTION_UPDATE);
|
IntentFilter filter = new IntentFilter(ACTION_UPDATE);
|
||||||
registerReceiver(myReceiver, filter);
|
registerReceiver(myReceiver, filter);
|
||||||
|
|
||||||
mProgressBar = findViewById(R.id.progressBar);
|
mProgressBar = findViewById(R.id.progressBar);
|
||||||
mTextView = findViewById(R.id.textView);
|
mTextView = findViewById(R.id.textView);
|
||||||
sharedPreferences = getSharedPreferences(SETTINGS, Context.MODE_PRIVATE);
|
sharedPreferences = getSharedPreferences(SETTINGS, Context.MODE_PRIVATE);
|
||||||
|
|
||||||
checkAppVersion();
|
checkAppVersion();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
|
createNotificationChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAppVersion() {
|
private void checkAppVersion() {
|
||||||
@ -114,6 +126,28 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
startActivity(intent);
|
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
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
// Prevent abrupt interruption when copy game files from assets
|
// Prevent abrupt interruption when copy game files from assets
|
||||||
|
@ -22,7 +22,6 @@ package net.minetest.minetest;
|
|||||||
|
|
||||||
import android.app.IntentService;
|
import android.app.IntentService;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -58,9 +57,11 @@ public class UnzipService extends IntentService {
|
|||||||
private String failureMessage;
|
private String failureMessage;
|
||||||
|
|
||||||
private static boolean isRunning = false;
|
private static boolean isRunning = false;
|
||||||
|
|
||||||
public static synchronized boolean getIsRunning() {
|
public static synchronized boolean getIsRunning() {
|
||||||
return isRunning;
|
return isRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static synchronized void setIsRunning(boolean v) {
|
private static synchronized void setIsRunning(boolean v) {
|
||||||
isRunning = v;
|
isRunning = v;
|
||||||
}
|
}
|
||||||
@ -99,28 +100,13 @@ public class UnzipService extends IntentService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
private Notification.Builder createNotification() {
|
private Notification.Builder createNotification() {
|
||||||
String name = "net.minetest.minetest";
|
|
||||||
String channelId = "Minetest channel";
|
|
||||||
String description = "notifications from Minetest";
|
|
||||||
Notification.Builder builder;
|
Notification.Builder builder;
|
||||||
if (mNotifyManager == null)
|
if (mNotifyManager == null)
|
||||||
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
int importance = NotificationManager.IMPORTANCE_LOW;
|
builder = new Notification.Builder(this, MainActivity.NOTIFICATION_CHANNEL_ID);
|
||||||
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);
|
|
||||||
} else {
|
} else {
|
||||||
builder = new Notification.Builder(this);
|
builder = new Notification.Builder(this);
|
||||||
}
|
}
|
||||||
@ -135,9 +121,9 @@ public class UnzipService extends IntentService {
|
|||||||
PendingIntent intent = PendingIntent.getActivity(this, 0,
|
PendingIntent intent = PendingIntent.getActivity(this, 0,
|
||||||
notificationIntent, pendingIntentFlag);
|
notificationIntent, pendingIntentFlag);
|
||||||
|
|
||||||
builder.setContentTitle(getString(R.string.notification_title))
|
builder.setContentTitle(getString(R.string.unzip_notification_title))
|
||||||
.setSmallIcon(R.mipmap.ic_launcher)
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
.setContentText(getString(R.string.notification_description))
|
.setContentText(getString(R.string.unzip_notification_description))
|
||||||
.setContentIntent(intent)
|
.setContentIntent(intent)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setProgress(0, 0, true);
|
.setProgress(0, 0, true);
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="label">Minetest</string>
|
<string name="label">Minetest</string>
|
||||||
<string name="loading">Loading…</string>
|
<string name="loading">Loading…</string>
|
||||||
<string name="notification_title">Loading Minetest</string>
|
<string name="notification_channel_name">General notification</string>
|
||||||
<string name="notification_description">Less than 1 minute…</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>
|
<string name="ime_dialog_done">Done</string>
|
||||||
</resources>
|
</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 = 0.0
|
||||||
local time_next = math.huge
|
local time_next = math.huge
|
||||||
|
|
||||||
@ -9,42 +121,54 @@ core.register_globalstep(function(dtime)
|
|||||||
return
|
return
|
||||||
end
|
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
|
-- Remove other expired jobs and append them to the list.
|
||||||
-- a timer callback.
|
while true do
|
||||||
for i = #jobs, 1, -1 do
|
time_next = expiries[1] or math.huge
|
||||||
local job = jobs[i]
|
if time_next > time then
|
||||||
if time >= job.expire then
|
break
|
||||||
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
|
|
||||||
end
|
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
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
local job_metatable = {__index = {}}
|
||||||
|
|
||||||
|
local function dummy_func() end
|
||||||
|
function job_metatable.__index:cancel()
|
||||||
|
self.func = dummy_func
|
||||||
|
self.args = {n = 0}
|
||||||
|
end
|
||||||
|
|
||||||
function core.after(after, func, ...)
|
function core.after(after, func, ...)
|
||||||
assert(tonumber(after) and type(func) == "function",
|
assert(tonumber(after) and not core.is_nan(after) and type(func) == "function",
|
||||||
"Invalid minetest.after invocation")
|
"Invalid minetest.after invocation")
|
||||||
local expire = time + after
|
|
||||||
local new_job = {
|
local new_job = {
|
||||||
func = func,
|
|
||||||
expire = expire,
|
|
||||||
arg = {...},
|
|
||||||
mod_origin = core.get_last_run_mod(),
|
mod_origin = core.get_last_run_mod(),
|
||||||
|
func = func,
|
||||||
|
args = {
|
||||||
|
n = select("#", ...),
|
||||||
|
...
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
jobs[#jobs + 1] = new_job
|
local expiry = time + after
|
||||||
time_next = math.min(time_next, expire)
|
add_job(expiry, new_job)
|
||||||
|
time_next = math.min(time_next, expiry)
|
||||||
|
|
||||||
return {
|
return setmetatable(new_job, job_metatable)
|
||||||
cancel = function()
|
|
||||||
new_job.func = function() end
|
|
||||||
new_job.args = {}
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
@ -144,6 +144,8 @@ local wallmounted_to_dir = {
|
|||||||
vector.new(-1, 0, 0),
|
vector.new(-1, 0, 0),
|
||||||
vector.new( 0, 0, 1),
|
vector.new( 0, 0, 1),
|
||||||
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)
|
function core.wallmounted_to_dir(wallmounted)
|
||||||
return wallmounted_to_dir[wallmounted % 8]
|
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)
|
core_auth.save(auth_entry)
|
||||||
|
|
||||||
|
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
|
-- Run grant callbacks
|
||||||
for priv, _ in pairs(privileges) do
|
if prev_privs[priv] == nil then
|
||||||
if not prev_privs[priv] then
|
|
||||||
core.run_priv_callbacks(name, priv, nil, "grant")
|
core.run_priv_callbacks(name, priv, nil, "grant")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Run revoke callbacks
|
-- Run revoke callbacks
|
||||||
for priv, _ in pairs(prev_privs) do
|
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")
|
core.run_priv_callbacks(name, priv, nil, "revoke")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -180,6 +188,20 @@ core.set_player_privs = auth_pass("set_privileges")
|
|||||||
core.remove_player_auth = auth_pass("delete_auth")
|
core.remove_player_auth = auth_pass("delete_auth")
|
||||||
core.auth_reload = auth_pass("reload")
|
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")
|
local record_login = auth_pass("record_login")
|
||||||
core.register_on_joinplayer(function(player)
|
core.register_on_joinplayer(function(player)
|
||||||
record_login(player:get_player_name())
|
record_login(player:get_player_name())
|
||||||
|
@ -150,7 +150,12 @@ core.register_entity(":__builtin:falling_node", {
|
|||||||
|
|
||||||
-- Rotate entity
|
-- Rotate entity
|
||||||
if def.drawtype == "torchlike" then
|
if def.drawtype == "torchlike" then
|
||||||
|
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)
|
self.object:set_yaw(math.pi*0.25)
|
||||||
|
end
|
||||||
elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
|
elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
|
||||||
and (def.wield_image == "" or def.wield_image == nil))
|
and (def.wield_image == "" or def.wield_image == nil))
|
||||||
or def.drawtype == "signlike"
|
or def.drawtype == "signlike"
|
||||||
@ -190,6 +195,10 @@ core.register_entity(":__builtin:falling_node", {
|
|||||||
pitch, yaw = 0, -math.pi/2
|
pitch, yaw = 0, -math.pi/2
|
||||||
elseif rot == 4 then
|
elseif rot == 4 then
|
||||||
pitch, yaw = 0, math.pi
|
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
|
end
|
||||||
else
|
else
|
||||||
if rot == 1 then
|
if rot == 1 then
|
||||||
@ -202,6 +211,10 @@ core.register_entity(":__builtin:falling_node", {
|
|||||||
pitch, yaw = math.pi/2, math.pi
|
pitch, yaw = math.pi/2, math.pi
|
||||||
elseif rot == 5 then
|
elseif rot == 5 then
|
||||||
pitch, yaw = math.pi/2, 0
|
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
|
||||||
end
|
end
|
||||||
if def.drawtype == "signlike" then
|
if def.drawtype == "signlike" then
|
||||||
@ -210,10 +223,20 @@ core.register_entity(":__builtin:falling_node", {
|
|||||||
yaw = yaw + math.pi/2
|
yaw = yaw + math.pi/2
|
||||||
elseif rot == 1 then
|
elseif rot == 1 then
|
||||||
yaw = yaw - math.pi/2
|
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
|
end
|
||||||
elseif def.drawtype == "mesh" or def.drawtype == "normal" or def.drawtype == "nodebox" then
|
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
|
roll = roll + math.pi
|
||||||
|
elseif rot == 6 or rot == 7 then
|
||||||
|
if def.drawtype ~= "normal" then
|
||||||
|
roll = roll - math.pi/2
|
||||||
|
end
|
||||||
else
|
else
|
||||||
yaw = yaw + math.pi
|
yaw = yaw + math.pi
|
||||||
end
|
end
|
||||||
|
@ -30,6 +30,11 @@ core.features = {
|
|||||||
sound_params_start_time = true,
|
sound_params_start_time = true,
|
||||||
physics_overrides_v2 = true,
|
physics_overrides_v2 = true,
|
||||||
hud_def_type_field = 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)
|
function core.has_feature(arg)
|
||||||
|
@ -202,7 +202,40 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
|
|||||||
elseif (def.paramtype2 == "wallmounted" or
|
elseif (def.paramtype2 == "wallmounted" or
|
||||||
def.paramtype2 == "colorwallmounted") and not param2 then
|
def.paramtype2 == "colorwallmounted") and not param2 then
|
||||||
local dir = vector.subtract(under, above)
|
local dir = vector.subtract(under, above)
|
||||||
|
-- If you change this code, also change src/client/game.cpp
|
||||||
newnode.param2 = core.dir_to_wallmounted(dir)
|
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
|
-- Calculate the direction for furnaces and chests and stuff
|
||||||
elseif (def.paramtype2 == "facedir" or
|
elseif (def.paramtype2 == "facedir" or
|
||||||
def.paramtype2 == "colorfacedir" 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
|
end
|
||||||
|
|
||||||
local video_driver = core.get_active_driver()
|
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 = {
|
local special = {
|
||||||
android = PLATFORM == "Android",
|
android = PLATFORM == "Android",
|
||||||
desktop = PLATFORM ~= "Android",
|
desktop = PLATFORM ~= "Android",
|
||||||
@ -608,6 +608,16 @@ local function get_formspec(dialogdata)
|
|||||||
end
|
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 function buttonhandler(this, fields)
|
||||||
local dialogdata = this.data
|
local dialogdata = this.data
|
||||||
dialogdata.leftscroll = core.explode_scrollbar_event(fields.leftscroll).value or dialogdata.leftscroll
|
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
|
if fields.show_technical_names ~= nil then
|
||||||
local value = core.is_yes(fields.show_technical_names)
|
local value = core.is_yes(fields.show_technical_names)
|
||||||
core.settings:set_bool("show_technical_names", value)
|
core.settings:set_bool("show_technical_names", value)
|
||||||
|
write_settings_early()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.show_advanced ~= nil then
|
if fields.show_advanced ~= nil then
|
||||||
local value = core.is_yes(fields.show_advanced)
|
local value = core.is_yes(fields.show_advanced)
|
||||||
core.settings:set_bool("show_advanced", value)
|
core.settings:set_bool("show_advanced", value)
|
||||||
|
write_settings_early()
|
||||||
|
|
||||||
local suggested_page_id = update_filtered_pages(dialogdata.query)
|
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
|
for i, comp in ipairs(dialogdata.components) do
|
||||||
if comp.on_submit and comp:on_submit(fields, this) then
|
if comp.on_submit and comp:on_submit(fields, this) then
|
||||||
|
write_settings_early()
|
||||||
|
|
||||||
-- Clear components so they regenerate
|
-- Clear components so they regenerate
|
||||||
dialogdata.components = nil
|
dialogdata.components = nil
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if comp.setting and fields["reset_" .. i] then
|
if comp.setting and fields["reset_" .. i] then
|
||||||
core.settings:remove(comp.setting.name)
|
core.settings:remove(comp.setting.name)
|
||||||
|
write_settings_early()
|
||||||
|
|
||||||
-- Clear components so they regenerate
|
-- Clear components so they regenerate
|
||||||
dialogdata.components = nil
|
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
|
# Shaders allow advanced visual effects and may increase performance on some video
|
||||||
# cards.
|
# cards.
|
||||||
# This only works with the OpenGL video backend.
|
|
||||||
#
|
#
|
||||||
# Requires: shaders_support
|
# Requires: shaders_support
|
||||||
enable_shaders (Shaders) bool true
|
enable_shaders (Shaders) bool true
|
||||||
@ -649,7 +648,7 @@ mute_sound (Mute sound) bool false
|
|||||||
|
|
||||||
[*User Interfaces]
|
[*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.
|
# 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
|
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.
|
# The rendering back-end.
|
||||||
# Note: A restart is required after changing this!
|
# Note: A restart is required after changing this!
|
||||||
# OpenGL is the default for desktop, and OGLES2 for Android.
|
# OpenGL is the default for desktop, and OGLES2 for Android.
|
||||||
# Shaders are supported by OpenGL and OGLES2 (experimental).
|
# Shaders are supported by everything but OGLES1.
|
||||||
video_driver (Video driver) enum ,opengl,ogles1,ogles2
|
video_driver (Video driver) enum ,opengl,opengl3,ogles1,ogles2
|
||||||
|
|
||||||
# Distance in nodes at which transparency depth sorting is enabled
|
# Distance in nodes at which transparency depth sorting is enabled
|
||||||
# Use this to limit the performance impact of transparency depth sorting
|
# 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.
|
# Value of 0 (default) will let Minetest autodetect the number of available threads.
|
||||||
mesh_generation_threads (Mapblock mesh generation threads) int 0 0 8
|
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
|
# True = 256
|
||||||
# False = 128
|
# False = 128
|
||||||
# Usable to make minimap smoother on slower machines.
|
# Usable to make minimap smoother on slower machines.
|
||||||
|
@ -14,7 +14,7 @@ centroid varying vec2 varTexCoord;
|
|||||||
// smoothstep - squared
|
// smoothstep - squared
|
||||||
float smstsq(float f)
|
float smstsq(float f)
|
||||||
{
|
{
|
||||||
f = f * f * (3 - 2 * f);
|
f = f * f * (3. - 2. * f);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ centroid varying vec2 varTexCoord;
|
|||||||
// smoothstep - squared
|
// smoothstep - squared
|
||||||
float smstsq(float f)
|
float smstsq(float f)
|
||||||
{
|
{
|
||||||
f = f * f * (3 - 2 * f);
|
f = f * f * (3. - 2. * f);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ void main (void)
|
|||||||
//texture sampling rate
|
//texture sampling rate
|
||||||
const float step = 1.0 / 256.0;
|
const float step = 1.0 / 256.0;
|
||||||
float tl = texture2D(normalTexture, vec2(uv.x - step, uv.y + step)).r;
|
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 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 br = texture2D(normalTexture, vec2(uv.x + step, uv.y - step)).r;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
uniform sampler2D baseTexture;
|
uniform sampler2D baseTexture;
|
||||||
|
|
||||||
uniform vec3 dayLight;
|
uniform vec3 dayLight;
|
||||||
uniform vec4 skyBgColor;
|
uniform vec4 fogColor;
|
||||||
uniform float fogDistance;
|
uniform float fogDistance;
|
||||||
uniform float fogShadingParameter;
|
uniform float fogShadingParameter;
|
||||||
uniform vec3 eyePosition;
|
uniform vec3 eyePosition;
|
||||||
@ -161,7 +161,7 @@ float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDist
|
|||||||
float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
|
float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
|
||||||
if (depth > 0.0 && f_normal_length > 0.0)
|
if (depth > 0.0 && f_normal_length > 0.0)
|
||||||
// 5 is empirical factor that controls how fast shadow loses sharpness
|
// 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;
|
depth = 0.0;
|
||||||
|
|
||||||
float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
|
float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
|
||||||
@ -448,7 +448,7 @@ void main(void)
|
|||||||
// Note: clarity = (1 - fogginess)
|
// Note: clarity = (1 - fogginess)
|
||||||
float clarity = clamp(fogShadingParameter
|
float clarity = clamp(fogShadingParameter
|
||||||
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
||||||
col = mix(skyBgColor, col, clarity);
|
col = mix(fogColor, col, clarity);
|
||||||
col = vec4(col.rgb, base.a);
|
col = vec4(col.rgb, base.a);
|
||||||
|
|
||||||
gl_FragData[0] = col;
|
gl_FragData[0] = col;
|
||||||
|
@ -242,7 +242,7 @@ void main(void)
|
|||||||
if (f_normal_length > 0.0) {
|
if (f_normal_length > 0.0) {
|
||||||
nNormal = normalize(vNormal);
|
nNormal = normalize(vNormal);
|
||||||
cosLight = max(1e-5, dot(nNormal, -v_LightDirection));
|
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) /
|
normalOffsetScale = 2.0 * pFactor * pFactor * sinLight * min(f_shadowfar, 500.0) /
|
||||||
xyPerspectiveBias1 / f_textureresolution;
|
xyPerspectiveBias1 / f_textureresolution;
|
||||||
z_bias = 1.0 * sinLight / cosLight;
|
z_bias = 1.0 * sinLight / cosLight;
|
||||||
@ -250,7 +250,7 @@ void main(void)
|
|||||||
else {
|
else {
|
||||||
nNormal = vec3(0.0);
|
nNormal = vec3(0.0);
|
||||||
cosLight = clamp(dot(v_LightDirection, normalize(vec3(v_LightDirection.x, 0.0, v_LightDirection.z))), 1e-2, 1.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;
|
normalOffsetScale = 0.0;
|
||||||
z_bias = 3.6e3 * sinLight / cosLight;
|
z_bias = 3.6e3 * sinLight / cosLight;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
uniform sampler2D baseTexture;
|
uniform sampler2D baseTexture;
|
||||||
|
|
||||||
uniform vec3 dayLight;
|
uniform vec3 dayLight;
|
||||||
uniform vec4 skyBgColor;
|
uniform vec4 fogColor;
|
||||||
uniform float fogDistance;
|
uniform float fogDistance;
|
||||||
uniform float fogShadingParameter;
|
uniform float fogShadingParameter;
|
||||||
uniform vec3 eyePosition;
|
uniform vec3 eyePosition;
|
||||||
@ -449,7 +449,7 @@ void main(void)
|
|||||||
// Note: clarity = (1 - fogginess)
|
// Note: clarity = (1 - fogginess)
|
||||||
float clarity = clamp(fogShadingParameter
|
float clarity = clamp(fogShadingParameter
|
||||||
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
||||||
col = mix(skyBgColor, col, clarity);
|
col = mix(fogColor, col, clarity);
|
||||||
col = vec4(col.rgb, base.a);
|
col = vec4(col.rgb, base.a);
|
||||||
|
|
||||||
gl_FragData[0] = col;
|
gl_FragData[0] = col;
|
||||||
|
@ -147,7 +147,7 @@ void main(void)
|
|||||||
if (f_normal_length > 0.0) {
|
if (f_normal_length > 0.0) {
|
||||||
nNormal = normalize(vNormal);
|
nNormal = normalize(vNormal);
|
||||||
cosLight = max(1e-5, dot(nNormal, -v_LightDirection));
|
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) /
|
normalOffsetScale = 0.1 * pFactor * pFactor * sinLight * min(f_shadowfar, 500.0) /
|
||||||
xyPerspectiveBias1 / f_textureresolution;
|
xyPerspectiveBias1 / f_textureresolution;
|
||||||
z_bias = 1e3 * sinLight / cosLight * (0.5 + f_textureresolution / 1024.0);
|
z_bias = 1e3 * sinLight / cosLight * (0.5 + f_textureresolution / 1024.0);
|
||||||
@ -155,7 +155,7 @@ void main(void)
|
|||||||
else {
|
else {
|
||||||
nNormal = vec3(0.0);
|
nNormal = vec3(0.0);
|
||||||
cosLight = clamp(dot(v_LightDirection, normalize(vec3(v_LightDirection.x, 0.0, v_LightDirection.z))), 1e-2, 1.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;
|
normalOffsetScale = 0.0;
|
||||||
z_bias = 3.6e3 * sinLight / cosLight;
|
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
|
While you're playing the game normally (that is, no menu or inventory is
|
||||||
shown), the following controls are available:
|
shown), the following controls are available:
|
||||||
* Look around: touch screen and slide finger
|
* Look around: touch screen and slide finger
|
||||||
* Tap: Place a node
|
* Tap: Place a node, punch an object or use the selected item (default)
|
||||||
* Long tap: Dig node or use the held item
|
* Long tap: Dig a node or use the selected item (default)
|
||||||
* Press back: Pause menu
|
* Press back: Pause menu
|
||||||
* Touch buttons: Press button
|
* Touch buttons: Press button
|
||||||
* Buttons:
|
* Buttons:
|
||||||
|
@ -8,7 +8,7 @@ Introduction
|
|||||||
|
|
||||||
** WARNING: The client API is currently unstable, and may break/change without warning. **
|
** 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.
|
scripting in run-time loaded mods.
|
||||||
|
|
||||||
A mod is a self-contained bunch of scripts, textures and other related
|
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):
|
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:
|
On an installed version on Linux:
|
||||||
|
|
||||||
@ -185,15 +185,9 @@ Examples of sound parameter tables:
|
|||||||
pos = {x = 1, y = 2, z = 3},
|
pos = {x = 1, y = 2, z = 3},
|
||||||
gain = 1.0, -- default
|
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
|
### SimpleSoundSpec
|
||||||
* e.g. `""`
|
* e.g. `""`
|
||||||
@ -220,387 +214,20 @@ For helper functions see "Vector helpers".
|
|||||||
|
|
||||||
Flag Specifier Format
|
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
|
Refer to `lua_api.md`.
|
||||||
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.
|
|
||||||
|
|
||||||
Formspec
|
Formspec
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Formspec defines a menu. It is a string, with a somewhat strange format.
|
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
|
For details, refer to `lua_api.md`.
|
||||||
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!
|
|
||||||
|
|
||||||
Spatial Vectors
|
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:
|
Refer to `lua_api.md`.
|
||||||
|
|
||||||
* `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
|
|
||||||
|
|
||||||
Helper functions
|
Helper functions
|
||||||
----------------
|
----------------
|
||||||
@ -770,6 +397,10 @@ Call these functions only at load time!
|
|||||||
* `minetest.after(time, func, ...)`
|
* `minetest.after(time, func, ...)`
|
||||||
* Call the function `func` after `time` seconds, may be fractional
|
* Call the function `func` after `time` seconds, may be fractional
|
||||||
* Optional: Variable number of arguments that are passed to `func`
|
* 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()`
|
* `minetest.get_us_time()`
|
||||||
* Returns time with microsecond precision. May not return wall time.
|
* Returns time with microsecond precision. May not return wall time.
|
||||||
* `minetest.get_timeofday()`
|
* `minetest.get_timeofday()`
|
||||||
@ -1152,6 +783,10 @@ Methods:
|
|||||||
* See [`HUD definition`](#hud-definition-hud_add-hud_get)
|
* See [`HUD definition`](#hud-definition-hud_add-hud_get)
|
||||||
* `hud_get(id)`
|
* `hud_get(id)`
|
||||||
* returns the [`definition`](#hud-definition-hud_add-hud_get) of the HUD with that ID number or `nil`, if non-existent.
|
* 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)`
|
* `hud_remove(id)`
|
||||||
* remove the HUD element of the specified id, returns `true` on success
|
* remove the HUD element of the specified id, returns `true` on success
|
||||||
* `hud_change(id, stat, value)`
|
* `hud_change(id, stat, value)`
|
||||||
@ -1319,6 +954,7 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Server info
|
### Server info
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
{
|
{
|
||||||
address = "minetest.example.org", -- The domain name/IP address of a remote server or "" for a local server.
|
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`)
|
### HUD Definition (`hud_add`, `hud_get`)
|
||||||
|
|
||||||
```lua
|
Refer to `lua_api.md`.
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Escape sequences
|
Escape sequences
|
||||||
----------------
|
----------------
|
||||||
@ -1383,177 +994,17 @@ The following functions provide escape sequences:
|
|||||||
|
|
||||||
`ColorString`
|
`ColorString`
|
||||||
-------------
|
-------------
|
||||||
`#RGB` defines a color in hexadecimal format.
|
|
||||||
|
|
||||||
`#RGBA` defines a color in hexadecimal format and alpha channel.
|
Refer to `lua_api.md`.
|
||||||
|
|
||||||
`#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`).
|
|
||||||
|
|
||||||
`Color`
|
`Color`
|
||||||
-------------
|
-------------
|
||||||
`{a = alpha, r = red, g = green, b = blue}` defines an ARGB8 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`)
|
### Particle definition (`add_particle`)
|
||||||
|
|
||||||
```lua
|
As documented in `lua_api.md`, except for obvious reasons, the `playername` field is not supported.
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `ParticleSpawner` definition (`add_particlespawner`)
|
### `ParticleSpawner` definition (`add_particlespawner`)
|
||||||
|
|
||||||
```lua
|
As documented in `lua_api.md`, except for obvious reasons, the `playername` field is not supported.
|
||||||
{
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
@ -7,8 +7,12 @@
|
|||||||
| GCC | 7.5+ | or Clang 7.0.1+ |
|
| GCC | 7.5+ | or Clang 7.0.1+ |
|
||||||
| CMake | 3.5+ | |
|
| CMake | 3.5+ | |
|
||||||
| IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
|
| 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+ | |
|
| Freetype | 2.0+ | |
|
||||||
| SQLite3 | 3+ | |
|
| SQLite3 | 3+ | |
|
||||||
|
| Zlib | - | |
|
||||||
| Zstd | 1.0+ | |
|
| Zstd | 1.0+ | |
|
||||||
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
|
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
|
||||||
| GMP | 5.0.0+ | Bundled mini-GMP 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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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
|
## 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:
|
After you successfully built vcpkg you can easily install the required libraries:
|
||||||
```powershell
|
```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`:
|
- **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
|
It is parsed by the main menu settings dialogue to list mod-specific
|
||||||
settings in the "Mods" category.
|
settings in the "Mods" category.
|
||||||
|
|
||||||
|
`minetest.settings` can be used to read custom or engine settings.
|
||||||
|
See [`Settings`].
|
||||||
|
|
||||||
### `init.lua`
|
### `init.lua`
|
||||||
|
|
||||||
The main Lua script. Running this script should register everything it
|
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.
|
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`
|
### `textures`, `sounds`, `media`, `models`, `locale`
|
||||||
|
|
||||||
Media files (textures, sounds, whatever) that will be transferred to the
|
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`
|
* The rotation of the node is stored in `param2`
|
||||||
* Node is 'mounted'/facing towards one of 6 directions
|
* Node is 'mounted'/facing towards one of 6 directions
|
||||||
* You can make this value by using `minetest.dir_to_wallmounted()`
|
* 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":
|
* The value denotes at which direction the node is "mounted":
|
||||||
0 = y+, 1 = y-, 2 = x+, 3 = x-, 4 = z+, 5 = z-
|
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
|
* 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"`
|
* `paramtype2 = "facedir"`
|
||||||
* Supported drawtypes: "normal", "nodebox", "mesh"
|
* Supported drawtypes: "normal", "nodebox", "mesh"
|
||||||
* The rotation of the node is stored in `param2`.
|
* The rotation of the node is stored in `param2`.
|
||||||
@ -1678,10 +1682,12 @@ type are ignored.
|
|||||||
|
|
||||||
Displays an image on the HUD.
|
Displays an image on the HUD.
|
||||||
|
|
||||||
* `scale`: The scale of the image, with 1 being the original texture size.
|
* `scale`: The scale of the image, with `{x = 1, y = 1}` being the original texture size.
|
||||||
Only the X coordinate scale is used (positive values).
|
The `x` and `y` fields apply to the respective axes.
|
||||||
Negative values represent that percentage of the screen it
|
Positive values scale the source image.
|
||||||
should take; e.g. `x=-100` means 100% (width).
|
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.
|
* `text`: The name of the texture that is displayed.
|
||||||
* `alignment`: The alignment of the image.
|
* `alignment`: The alignment of the image.
|
||||||
* `offset`: offset in pixels from position.
|
* `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.
|
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.
|
* `scale`: The scale of the image, with `{x = 1, y = 1}` being the original texture size.
|
||||||
Only the X coordinate scale is used (positive values).
|
The `x` and `y` fields apply to the respective axes.
|
||||||
Negative values represent that percentage of the screen it
|
Positive values scale the source image.
|
||||||
should take; e.g. `x=-100` means 100% (width).
|
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.
|
* `text`: The name of the texture that is displayed.
|
||||||
* `alignment`: The alignment of the image.
|
* `alignment`: The alignment of the image.
|
||||||
* `world_pos`: World position of the waypoint.
|
* `world_pos`: World position of the waypoint.
|
||||||
@ -5280,6 +5288,20 @@ Utilities
|
|||||||
physics_overrides_v2 = true,
|
physics_overrides_v2 = true,
|
||||||
-- In HUD definitions the field `type` is used and `hud_elem_type` is deprecated (5.9.0)
|
-- In HUD definitions the field `type` is used and `hud_elem_type` is deprecated (5.9.0)
|
||||||
hud_def_type_field = true,
|
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
|
* `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
|
* `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.
|
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
|
* `name`: string; if omitted, all auth data should be considered modified
|
||||||
* `minetest.set_player_password(name, password_hash)`: Set password hash of
|
* `minetest.set_player_password(name, password_hash)`: Set password hash of
|
||||||
player `name`.
|
player `name`.
|
||||||
* `minetest.set_player_privs(name, {priv1=true,...})`: Set privileges of player
|
* `minetest.set_player_privs(name, privs)`: Set privileges of player `name`.
|
||||||
`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()`
|
* `minetest.auth_reload()`
|
||||||
* See `reload()` in authentication handler definition
|
* See `reload()` in authentication handler definition
|
||||||
|
|
||||||
@ -6450,6 +6484,8 @@ Timing
|
|||||||
* `minetest.after(time, func, ...)`: returns job table to use as below.
|
* `minetest.after(time, func, ...)`: returns job table to use as below.
|
||||||
* Call the function `func` after `time` seconds, may be fractional
|
* Call the function `func` after `time` seconds, may be fractional
|
||||||
* Optional: Variable number of arguments that are passed to `func`
|
* 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()`
|
* `job:cancel()`
|
||||||
* Cancels the job function from being called
|
* 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
|
* `stat` supports the same keys as in the hud definition table except for
|
||||||
`"type"` (or the deprecated `"hud_elem_type"`).
|
`"type"` (or the deprecated `"hud_elem_type"`).
|
||||||
* `hud_get(id)`: gets the HUD element definition structure of the specified ID
|
* `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.
|
* `hud_set_flags(flags)`: sets specified HUD flags of player.
|
||||||
* `flags`: A table with the following fields set to boolean values
|
* `flags`: A table with the following fields set to boolean values
|
||||||
* `hotbar`
|
* `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.
|
whether `set_sky` accepts this format. Check the legacy format otherwise.
|
||||||
* Passing no arguments resets the sky to its default values.
|
* Passing no arguments resets the sky to its default values.
|
||||||
* `sky_parameters` is a table with the following optional fields:
|
* `sky_parameters` is a table with the following optional fields:
|
||||||
* `base_color`: ColorSpec, changes fog in "skybox" and "plain".
|
* `base_color`: ColorSpec, meaning depends on `type` (default: `#ffffff`)
|
||||||
(default: `#ffffff`)
|
|
||||||
* `body_orbit_tilt`: Float, rotation angle of sun/moon orbit in degrees.
|
* `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.
|
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.
|
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 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.
|
Any value < 0, resets the behavior to being client-controlled.
|
||||||
(default: -1)
|
(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)`
|
* `set_sky(base_color, type, {texture names}, clouds)`
|
||||||
* Deprecated. Use `set_sky(sky_parameters)`
|
* Deprecated. Use `set_sky(sky_parameters)`
|
||||||
* `base_color`: ColorSpec, defaults to white
|
* `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.
|
* `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`.
|
* 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,
|
* `respawn()`: Respawns the player using the same mechanism as the death screen,
|
||||||
including calling on_respawnplayer callbacks.
|
including calling `on_respawnplayer` callbacks.
|
||||||
|
|
||||||
`PcgRandom`
|
`PcgRandom`
|
||||||
-----------
|
-----------
|
||||||
@ -8057,7 +8099,9 @@ A 32-bit pseudorandom number generator.
|
|||||||
Uses PCG32, an algorithm of the permuted congruential generator family,
|
Uses PCG32, an algorithm of the permuted congruential generator family,
|
||||||
offering very strong randomness.
|
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
|
### Methods
|
||||||
|
|
||||||
@ -8069,6 +8113,8 @@ It can be created via `PcgRandom(seed)` or `PcgRandom(seed, sequence)`.
|
|||||||
* `mean = (max - min) / 2`, and
|
* `mean = (max - min) / 2`, and
|
||||||
* `variance = (((max - min + 1) ^ 2) - 1) / (12 * num_trials)`
|
* `variance = (((max - min + 1) ^ 2) - 1) / (12 * num_trials)`
|
||||||
* Increasing `num_trials` improves accuracy of the approximation
|
* 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`
|
`PerlinNoise`
|
||||||
-------------
|
-------------
|
||||||
@ -8152,14 +8198,22 @@ Can be obtained using `player:get_meta()`.
|
|||||||
A 16-bit pseudorandom number generator.
|
A 16-bit pseudorandom number generator.
|
||||||
Uses a well-known LCG algorithm introduced by K&R.
|
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
|
### Methods
|
||||||
|
|
||||||
* `next()`: return next integer random number [`0`...`32767`]
|
* `next()`: return next integer random number [`0`...`32767`]
|
||||||
* `next(min, max)`: return next integer random number [`min`...`max`]
|
* `next(min, max)`: return next integer random number [`min`...`max`]
|
||||||
* `((max - min) == 32767) or ((max-min) <= 6553))` must be true
|
* Either `max - min == 32767` or `max - min <= 6553` must be true
|
||||||
due to the simple implementation making bad distribution otherwise.
|
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`
|
`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`.
|
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
|
### Methods
|
||||||
|
|
||||||
* `get(key)`: returns a value
|
* `get(key)`: returns a value
|
||||||
|
* Returns `nil` if `key` is not found.
|
||||||
* `get_bool(key, [default])`: returns a boolean
|
* `get_bool(key, [default])`: returns a boolean
|
||||||
* `default` is the value returned if `key` is not found.
|
* `default` is the value returned if `key` is not found.
|
||||||
* Returns `nil` if `key` is not found and `default` not specified.
|
* Returns `nil` if `key` is not found and `default` not specified.
|
||||||
* `get_np_group(key)`: returns a NoiseParams table
|
* `get_np_group(key)`: returns a NoiseParams table
|
||||||
|
* Returns `nil` if `key` is not found.
|
||||||
* `get_flags(key)`:
|
* `get_flags(key)`:
|
||||||
* Returns `{flag = true/false, ...}` according to the set flags.
|
* Returns `{flag = true/false, ...}` according to the set flags.
|
||||||
* Is currently limited to mapgen flags `mg_flags` and mapgen-specific
|
* Is currently limited to mapgen flags `mg_flags` and mapgen-specific
|
||||||
flags like `mgv5_spflags`.
|
flags like `mgv5_spflags`.
|
||||||
|
* Returns `nil` if `key` is not found.
|
||||||
* `set(key, value)`
|
* `set(key, value)`
|
||||||
* Setting names can't contain whitespace or any of `="{}#`.
|
* Setting names can't contain whitespace or any of `="{}#`.
|
||||||
* Setting values can't contain the sequence `\n"""`.
|
* Setting values can't contain the sequence `\n"""`.
|
||||||
* Setting names starting with "secure." can't be set on the main settings
|
* Setting names starting with "secure." can't be set on the main settings
|
||||||
object (`minetest.settings`).
|
object (`minetest.settings`).
|
||||||
* `set_bool(key, value)`
|
* `set_bool(key, value)`
|
||||||
* See documentation for set() above.
|
* See documentation for `set()` above.
|
||||||
* `set_np_group(key, value)`
|
* `set_np_group(key, value)`
|
||||||
* `value` is a NoiseParams table.
|
* `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)
|
* `remove(key)`: returns a boolean (`true` for success)
|
||||||
* `get_names()`: returns `{key1,...}`
|
* `get_names()`: returns `{key1,...}`
|
||||||
* `has(key)`:
|
* `has(key)`:
|
||||||
* Returns a boolean indicating whether `key` exists.
|
* Returns a boolean indicating whether `key` exists.
|
||||||
* Note that for the main settings object (`minetest.settings`), `get(key)`
|
* In contrast to the various getter functions, `has()` doesn't consider
|
||||||
might return a value even if `has(key)` returns `false`. That's because
|
any default values.
|
||||||
`get` can fall back to the so-called parent of the `Settings` object, i.e.
|
* This means that on the main settings object (`minetest.settings`),
|
||||||
the default values.
|
`get(key)` might return a value even if `has(key)` returns `false`.
|
||||||
* `write()`: returns a boolean (`true` for success)
|
* `write()`: returns a boolean (`true` for success)
|
||||||
* Writes changes to file.
|
* Writes changes to file.
|
||||||
* `to_table()`: returns `{[key1]=value1,...}`
|
* `to_table()`: returns `{[key1]=value1,...}`
|
||||||
@ -8336,7 +8400,9 @@ Player properties need to be saved manually.
|
|||||||
|
|
||||||
|
|
||||||
pointable = true,
|
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",
|
visual = "cube" / "sprite" / "upright_sprite" / "mesh" / "wielditem" / "item",
|
||||||
-- "cube" is a node-sized cube.
|
-- "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"`),
|
-- If true, item can point to all liquid nodes (`liquidtype ~= "none"`),
|
||||||
-- even those for which `pointable = false`
|
-- 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,
|
light_source = 0,
|
||||||
-- When used for nodes: Defines amount of light emitted by node.
|
-- When used for nodes: Defines amount of light emitted by node.
|
||||||
-- Otherwise: Defines texture glow when viewed as a dropped item
|
-- 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
|
-- Otherwise should be name of node which the client immediately places
|
||||||
-- upon digging. Server will always update with actual result shortly.
|
-- 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 = {
|
sound = {
|
||||||
-- Definition of item sounds to be played at various events.
|
-- Definition of item sounds to be played at various events.
|
||||||
-- All fields in this table are optional.
|
-- All fields in this table are optional.
|
||||||
@ -8892,6 +8993,13 @@ Used by `minetest.register_node`.
|
|||||||
place_param2 = 0,
|
place_param2 = 0,
|
||||||
-- Value for param2 that is set when player places node
|
-- 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,
|
is_ground_content = true,
|
||||||
-- If false, the cave generator and dungeon generator will not carve
|
-- If false, the cave generator and dungeon generator will not carve
|
||||||
-- through this node.
|
-- through this node.
|
||||||
@ -8904,7 +9012,11 @@ Used by `minetest.register_node`.
|
|||||||
|
|
||||||
walkable = true, -- If true, objects collide with 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
|
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 = function(name, privileges),
|
||||||
-- Set privileges of player `name`.
|
-- Set privileges of player `name`.
|
||||||
-- `privileges` is in table form, auth data should be created if not
|
-- `privileges` is in table form: keys are privilege names, values are `true`;
|
||||||
-- present.
|
-- auth data should be created if not present.
|
||||||
|
|
||||||
reload = function(),
|
reload = function(),
|
||||||
-- Reload authentication data from the storage location.
|
-- Reload authentication data from the storage location.
|
||||||
|
@ -17,6 +17,7 @@ markdown_extensions:
|
|||||||
- pymdownx.superfences
|
- pymdownx.superfences
|
||||||
- pymdownx.highlight:
|
- pymdownx.highlight:
|
||||||
css_class: codehilite
|
css_class: codehilite
|
||||||
|
- gfm_admonition
|
||||||
plugins:
|
plugins:
|
||||||
- search:
|
- search:
|
||||||
separator: '[\s\-\.\(]+'
|
separator: '[\s\-\.\(]+'
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
mkdocs~=1.4.3
|
mkdocs~=1.4.3
|
||||||
pygments~=2.15.1
|
pygments~=2.15.1
|
||||||
pymdown-extensions~=10.3
|
pymdown-extensions~=10.3
|
||||||
|
markdown-gfm-admonition~=0.1.0
|
@ -27,6 +27,7 @@ read_globals = {
|
|||||||
"Settings",
|
"Settings",
|
||||||
"check",
|
"check",
|
||||||
"PseudoRandom",
|
"PseudoRandom",
|
||||||
|
"PcgRandom",
|
||||||
|
|
||||||
string = {fields = {"split", "trim"}},
|
string = {fields = {"split", "trim"}},
|
||||||
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
|
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
dofile(minetest.get_modpath("testentities").."/visuals.lua")
|
dofile(minetest.get_modpath("testentities").."/visuals.lua")
|
||||||
dofile(minetest.get_modpath("testentities").."/selectionbox.lua")
|
dofile(minetest.get_modpath("testentities").."/selectionbox.lua")
|
||||||
dofile(minetest.get_modpath("testentities").."/armor.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",
|
type = "image_waypoint",
|
||||||
text = "testhud_waypoint.png",
|
text = "testhud_waypoint.png",
|
||||||
world_pos = player:get_pos(),
|
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}
|
offset = {x = 0, y = -32}
|
||||||
}
|
}
|
||||||
if not player_waypoints[name] then
|
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_font_huds[player:get_player_name()] = nil
|
||||||
player_waypoints[player:get_player_name()] = nil
|
player_waypoints[player:get_player_name()] = nil
|
||||||
end)
|
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", {
|
minetest.register_node("testnodes:torchlike_wallmounted", {
|
||||||
description = S("Wallmounted \"torchlike\" Drawtype Test Node").."\n"..
|
description = S("Wallmounted \"torchlike\" Drawtype Test Node").."\n"..
|
||||||
S("param2 = wallmounted rotation (0..5)"),
|
S("param2 = wallmounted rotation (0..7)"),
|
||||||
drawtype = "torchlike",
|
drawtype = "torchlike",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "wallmounted",
|
paramtype2 = "wallmounted",
|
||||||
@ -179,6 +179,24 @@ minetest.register_node("testnodes:torchlike_wallmounted", {
|
|||||||
groups = { dig_immediate = 3 },
|
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", {
|
minetest.register_node("testnodes:signlike", {
|
||||||
description = S("Floor \"signlike\" Drawtype Test Node").."\n"..
|
description = S("Floor \"signlike\" Drawtype Test Node").."\n"..
|
||||||
S("Always on floor"),
|
S("Always on floor"),
|
||||||
@ -186,16 +204,14 @@ minetest.register_node("testnodes:signlike", {
|
|||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
tiles = { "testnodes_signlike.png^[colorize:#FF0000:64" },
|
tiles = { "testnodes_signlike.png^[colorize:#FF0000:64" },
|
||||||
|
|
||||||
|
|
||||||
walkable = false,
|
walkable = false,
|
||||||
groups = { dig_immediate = 3 },
|
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
|
groups = { dig_immediate = 3 },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
minetest.register_node("testnodes:signlike_wallmounted", {
|
minetest.register_node("testnodes:signlike_wallmounted", {
|
||||||
description = S("Wallmounted \"signlike\" Drawtype Test Node").."\n"..
|
description = S("Wallmounted \"signlike\" Drawtype Test Node").."\n"..
|
||||||
S("param2 = wallmounted rotation (0..5)"),
|
S("param2 = wallmounted rotation (0..7)"),
|
||||||
drawtype = "signlike",
|
drawtype = "signlike",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "wallmounted",
|
paramtype2 = "wallmounted",
|
||||||
@ -207,6 +223,22 @@ minetest.register_node("testnodes:signlike_wallmounted", {
|
|||||||
sunlight_propagates = true,
|
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", {
|
minetest.register_node("testnodes:plantlike", {
|
||||||
description = S("\"plantlike\" Drawtype Test Node"),
|
description = S("\"plantlike\" Drawtype Test Node"),
|
||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
@ -235,7 +267,7 @@ minetest.register_node("testnodes:plantlike_waving", {
|
|||||||
|
|
||||||
minetest.register_node("testnodes:plantlike_wallmounted", {
|
minetest.register_node("testnodes:plantlike_wallmounted", {
|
||||||
description = S("Wallmounted \"plantlike\" Drawtype Test Node").."\n"..
|
description = S("Wallmounted \"plantlike\" Drawtype Test Node").."\n"..
|
||||||
S("param2 = wallmounted rotation (0..5)"),
|
S("param2 = wallmounted rotation (0..7)"),
|
||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "wallmounted",
|
paramtype2 = "wallmounted",
|
||||||
@ -366,7 +398,7 @@ minetest.register_node("testnodes:plantlike_rooted", {
|
|||||||
|
|
||||||
minetest.register_node("testnodes:plantlike_rooted_wallmounted", {
|
minetest.register_node("testnodes:plantlike_rooted_wallmounted", {
|
||||||
description = S("Wallmounted \"rooted_plantlike\" Drawtype Test Node").."\n"..
|
description = S("Wallmounted \"rooted_plantlike\" Drawtype Test Node").."\n"..
|
||||||
S("param2 = wallmounted rotation (0..5)"),
|
S("param2 = wallmounted rotation (0..7)"),
|
||||||
drawtype = "plantlike_rooted",
|
drawtype = "plantlike_rooted",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "wallmounted",
|
paramtype2 = "wallmounted",
|
||||||
|
@ -92,7 +92,7 @@ minetest.register_node("testnodes:mesh_color4dir", {
|
|||||||
-- Wallmounted mesh: pyramid
|
-- Wallmounted mesh: pyramid
|
||||||
minetest.register_node("testnodes:mesh_wallmounted", {
|
minetest.register_node("testnodes:mesh_wallmounted", {
|
||||||
description = S("Wallmounted Mesh Test Node").."\n"..
|
description = S("Wallmounted Mesh Test Node").."\n"..
|
||||||
S("param2 = wallmounted rotation (0..5)"),
|
S("param2 = wallmounted rotation (0..7)"),
|
||||||
drawtype = "mesh",
|
drawtype = "mesh",
|
||||||
mesh = "testnodes_pyramid.obj",
|
mesh = "testnodes_pyramid.obj",
|
||||||
tiles = {"testnodes_mesh_stripes9.png"},
|
tiles = {"testnodes_mesh_stripes9.png"},
|
||||||
@ -105,7 +105,7 @@ minetest.register_node("testnodes:mesh_wallmounted", {
|
|||||||
|
|
||||||
minetest.register_node("testnodes:mesh_colorwallmounted", {
|
minetest.register_node("testnodes:mesh_colorwallmounted", {
|
||||||
description = S("Color Wallmounted Mesh Test Node").."\n"..
|
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",
|
drawtype = "mesh",
|
||||||
mesh = "testnodes_pyramid.obj",
|
mesh = "testnodes_pyramid.obj",
|
||||||
tiles = {"testnodes_mesh_stripes10.png"},
|
tiles = {"testnodes_mesh_stripes10.png"},
|
||||||
|
@ -180,3 +180,63 @@ minetest.register_node("testnodes:facedir_to_connect_to", {
|
|||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
connect_sides = {"left", "top"},
|
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", {
|
minetest.register_node("testnodes:wallmounted", {
|
||||||
description = S("Wallmounted Test Node").."\n"..
|
description = S("Wallmounted Test Node").."\n"..
|
||||||
S("param2 = wallmounted rotation (0..5)"),
|
S("param2 = wallmounted rotation (0..7)"),
|
||||||
paramtype2 = "wallmounted",
|
paramtype2 = "wallmounted",
|
||||||
tiles = {
|
tiles = {
|
||||||
"testnodes_1w.png",
|
"testnodes_1w.png",
|
||||||
@ -94,9 +94,25 @@ minetest.register_node("testnodes:wallmounted", {
|
|||||||
groups = { dig_immediate = 3 },
|
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", {
|
minetest.register_node("testnodes:wallmounted_nodebox", {
|
||||||
description = S("Wallmounted Nodebox Test Node").."\n"..
|
description = S("Wallmounted Nodebox Test Node").."\n"..
|
||||||
S("param2 = wallmounted rotation (0..5)"),
|
S("param2 = wallmounted rotation (0..7)"),
|
||||||
paramtype2 = "wallmounted",
|
paramtype2 = "wallmounted",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
tiles = {
|
tiles = {
|
||||||
@ -118,6 +134,30 @@ minetest.register_node("testnodes:wallmounted_nodebox", {
|
|||||||
groups = { dig_immediate = 3 },
|
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", {
|
minetest.register_node("testnodes:color", {
|
||||||
description = S("Color Test Node").."\n"..
|
description = S("Color Test Node").."\n"..
|
||||||
S("param2 = color (0..255)"),
|
S("param2 = color (0..255)"),
|
||||||
@ -212,7 +252,7 @@ minetest.register_node("testnodes:color4dir_nodebox", {
|
|||||||
|
|
||||||
minetest.register_node("testnodes:colorwallmounted", {
|
minetest.register_node("testnodes:colorwallmounted", {
|
||||||
description = S("Color Wallmounted Test Node").."\n"..
|
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",
|
paramtype2 = "colorwallmounted",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
palette = "testnodes_palette_wallmounted.png",
|
palette = "testnodes_palette_wallmounted.png",
|
||||||
@ -230,7 +270,7 @@ minetest.register_node("testnodes:colorwallmounted", {
|
|||||||
|
|
||||||
minetest.register_node("testnodes:colorwallmounted_nodebox", {
|
minetest.register_node("testnodes:colorwallmounted_nodebox", {
|
||||||
description = S("Color Wallmounted Nodebox Test Node").."\n"..
|
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",
|
paramtype2 = "colorwallmounted",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
palette = "testnodes_palette_wallmounted.png",
|
palette = "testnodes_palette_wallmounted.png",
|
||||||
|
@ -61,8 +61,8 @@ minetest.register_node("testnodes:attached", {
|
|||||||
-- when the node it attaches to is gone.
|
-- when the node it attaches to is gone.
|
||||||
minetest.register_node("testnodes:attached_wallmounted", {
|
minetest.register_node("testnodes:attached_wallmounted", {
|
||||||
description = S("Wallmounted Attached Node").."\n"..
|
description = S("Wallmounted Attached Node").."\n"..
|
||||||
S("Attaches to wall; drops as item if neighbor node is gone").."\n"..
|
S("Attaches to solid node it was placed on; drops as item if neighbor node is gone").."\n"..
|
||||||
S("param2 = wallmounted rotation (0..5)"),
|
S("param2 = wallmounted rotation (0..7)"),
|
||||||
paramtype2 = "wallmounted",
|
paramtype2 = "wallmounted",
|
||||||
tiles = {
|
tiles = {
|
||||||
"testnodes_attachedw_top.png",
|
"testnodes_attachedw_top.png",
|
||||||
@ -72,9 +72,29 @@ minetest.register_node("testnodes:attached_wallmounted", {
|
|||||||
groups = { attached_node = 1, dig_immediate = 3 },
|
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
|
-- Wallmounted node that always attaches to the floor
|
||||||
minetest.register_node("testnodes:attached_wallmounted_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",
|
paramtype2 = "wallmounted",
|
||||||
tiles = {
|
tiles = {
|
||||||
"testnodes_attached_top.png",
|
"testnodes_attached_top.png",
|
||||||
@ -85,10 +105,28 @@ minetest.register_node("testnodes:attached_wallmounted_floor", {
|
|||||||
color = "#FF8080",
|
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
|
-- This node attaches to the ceiling and drops as item
|
||||||
-- when the ceiling is gone.
|
-- when the ceiling is gone.
|
||||||
minetest.register_node("testnodes:attached_top", {
|
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 = {
|
tiles = {
|
||||||
"testnodes_attached_bottom.png",
|
"testnodes_attached_bottom.png",
|
||||||
"testnodes_attached_top.png",
|
"testnodes_attached_top.png",
|
||||||
@ -99,7 +137,9 @@ minetest.register_node("testnodes:attached_top", {
|
|||||||
|
|
||||||
-- Same as wallmounted attached, but for facedir
|
-- Same as wallmounted attached, but for facedir
|
||||||
minetest.register_node("testnodes:attached_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",
|
paramtype2 = "facedir",
|
||||||
tiles = {
|
tiles = {
|
||||||
"testnodes_attachedf_side.png^[transformR180",
|
"testnodes_attachedf_side.png^[transformR180",
|
||||||
@ -114,7 +154,9 @@ minetest.register_node("testnodes:attached_facedir", {
|
|||||||
|
|
||||||
-- Same as facedir attached, but for 4dir
|
-- Same as facedir attached, but for 4dir
|
||||||
minetest.register_node("testnodes:attached_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",
|
paramtype2 = "4dir",
|
||||||
tiles = {
|
tiles = {
|
||||||
"testnodes_attached4_side.png^[transformR180",
|
"testnodes_attached4_side.png^[transformR180",
|
||||||
@ -621,3 +663,23 @@ minetest.register_node("testnodes:post_effect_color_shaded_true", {
|
|||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
groups = {dig_immediate=3},
|
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") .. "/privatizer.lua")
|
||||||
dofile(minetest.get_modpath("testtools") .. "/particles.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", {
|
minetest.register_tool("testtools:param2tool", {
|
||||||
description = S("Param2 Tool") .."\n"..
|
description = S("Param2 Tool") .."\n"..
|
||||||
S("Modify param2 value of nodes") .."\n"..
|
S("Modify param2 value of nodes") .."\n"..
|
||||||
@ -16,6 +30,7 @@ minetest.register_tool("testtools:param2tool", {
|
|||||||
S("Sneak+Place: -8"),
|
S("Sneak+Place: -8"),
|
||||||
inventory_image = "testtools_param2tool.png",
|
inventory_image = "testtools_param2tool.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_nodes,
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||||
if pointed_thing.type ~= "node" or (not pos) then
|
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"),
|
S("Place in air: Manually select a node"),
|
||||||
inventory_image = "testtools_node_setter.png",
|
inventory_image = "testtools_node_setter.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_nodes,
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||||
if pointed_thing.type == "nothing" then
|
if pointed_thing.type == "nothing" then
|
||||||
@ -118,6 +134,10 @@ minetest.register_tool("testtools:remover", {
|
|||||||
S("Punch: Remove pointed node or object"),
|
S("Punch: Remove pointed node or object"),
|
||||||
inventory_image = "testtools_remover.png",
|
inventory_image = "testtools_remover.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = {
|
||||||
|
nodes = pointabilities_nodes.nodes,
|
||||||
|
objects = pointabilities_objects.objects,
|
||||||
|
},
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||||
if pointed_thing.type == "node" and pos ~= nil then
|
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"),
|
S("Place: Move pointed node 2 units upwards, then make it fall"),
|
||||||
inventory_image = "testtools_falling_node_tool.png",
|
inventory_image = "testtools_falling_node_tool.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_nodes,
|
||||||
on_place = function(itemstack, user, pointed_thing)
|
on_place = function(itemstack, user, pointed_thing)
|
||||||
-- Teleport node 1-2 units upwards (if possible) and make it fall
|
-- Teleport node 1-2 units upwards (if possible) and make it fall
|
||||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||||
@ -192,6 +213,7 @@ minetest.register_tool("testtools:rotator", {
|
|||||||
S("Aux1+Punch: Roll"),
|
S("Aux1+Punch: Roll"),
|
||||||
inventory_image = "testtools_entity_rotator.png",
|
inventory_image = "testtools_entity_rotator.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_objects,
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
if pointed_thing.type ~= "object" then
|
if pointed_thing.type ~= "object" then
|
||||||
return
|
return
|
||||||
@ -250,6 +272,7 @@ minetest.register_tool("testtools:object_mover", {
|
|||||||
S("Sneak+Place: Decrease distance"),
|
S("Sneak+Place: Decrease distance"),
|
||||||
inventory_image = "testtools_object_mover.png",
|
inventory_image = "testtools_object_mover.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_objects,
|
||||||
on_place = mover_config,
|
on_place = mover_config,
|
||||||
on_secondary_use = mover_config,
|
on_secondary_use = mover_config,
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
@ -296,6 +319,7 @@ minetest.register_tool("testtools:entity_scaler", {
|
|||||||
S("Sneak+Punch: Decrease scale"),
|
S("Sneak+Punch: Decrease scale"),
|
||||||
inventory_image = "testtools_entity_scaler.png",
|
inventory_image = "testtools_entity_scaler.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_objects,
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
if pointed_thing.type ~= "object" then
|
if pointed_thing.type ~= "object" then
|
||||||
return
|
return
|
||||||
@ -355,6 +379,7 @@ minetest.register_tool("testtools:branding_iron", {
|
|||||||
S("Devices that accept the returned name also accept \"player:<playername>\" for players."),
|
S("Devices that accept the returned name also accept \"player:<playername>\" for players."),
|
||||||
inventory_image = "testtools_branding_iron.png",
|
inventory_image = "testtools_branding_iron.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_objects,
|
||||||
on_use = function(_itemstack, user, pointed_thing)
|
on_use = function(_itemstack, user, pointed_thing)
|
||||||
local obj
|
local obj
|
||||||
local msg
|
local msg
|
||||||
@ -499,6 +524,7 @@ minetest.register_tool("testtools:object_editor", {
|
|||||||
S("Punch air: Edit yourself"),
|
S("Punch air: Edit yourself"),
|
||||||
inventory_image = "testtools_object_editor.png",
|
inventory_image = "testtools_object_editor.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_objects,
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
if user and user:is_player() then
|
if user and user:is_player() then
|
||||||
local name = user:get_player_name()
|
local name = user:get_player_name()
|
||||||
@ -586,6 +612,7 @@ minetest.register_tool("testtools:object_attacher", {
|
|||||||
S("Aux1+Sneak+Place: Decrease attachment rotation"),
|
S("Aux1+Sneak+Place: Decrease attachment rotation"),
|
||||||
inventory_image = "testtools_object_attacher.png",
|
inventory_image = "testtools_object_attacher.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_objects,
|
||||||
on_place = attacher_config,
|
on_place = attacher_config,
|
||||||
on_secondary_use = attacher_config,
|
on_secondary_use = attacher_config,
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
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'"),
|
S("Punch air to show your own 'children'"),
|
||||||
inventory_image = "testtools_children_getter.png",
|
inventory_image = "testtools_children_getter.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
|
pointabilities = pointabilities_objects,
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
if user and user:is_player() then
|
if user and user:is_player() then
|
||||||
local name = user:get_player_name()
|
local name = user:get_player_name()
|
||||||
@ -998,3 +1026,41 @@ minetest.register_on_leaveplayer(function(player)
|
|||||||
meta_latest_keylist[name] = nil
|
meta_latest_keylist[name] = nil
|
||||||
node_meta_posses[name] = nil
|
node_meta_posses[name] = nil
|
||||||
end)
|
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()
|
local function test_pseudo_random()
|
||||||
-- Try out PseudoRandom
|
-- We have comprehensive unit tests in C++, this is just to make sure the API code isn't messing up
|
||||||
local pseudo = PseudoRandom(13)
|
local gen1 = PseudoRandom(13)
|
||||||
assert(pseudo:next() == 22290)
|
assert(gen1:next() == 22290)
|
||||||
assert(pseudo:next() == 13854)
|
assert(gen1:next() == 13854)
|
||||||
|
|
||||||
|
local gen2 = PseudoRandom(gen1:get_state())
|
||||||
|
for n = 0, 16 do
|
||||||
|
assert(gen1:next() == gen2:next())
|
||||||
end
|
end
|
||||||
unittests.register("test_random", test_random)
|
|
||||||
|
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_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)
|
local function test_dynamic_media(cb, player)
|
||||||
if core.get_player_information(player:get_player_name()).protocol_version < 40 then
|
if core.get_player_information(player:get_player_name()).protocol_version < 40 then
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Catch v2.13.9
|
* Catch v2.13.10
|
||||||
* Generated: 2022-04-12 22:37:23.260201
|
* Generated: 2022-10-16 11:01:23.452308
|
||||||
* ----------------------------------------------------------
|
* ----------------------------------------------------------
|
||||||
* This file has been merged from multiple headers. Please don't edit it directly
|
* This file has been merged from multiple headers. Please don't edit it directly
|
||||||
* Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved.
|
* Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved.
|
||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#define CATCH_VERSION_MAJOR 2
|
#define CATCH_VERSION_MAJOR 2
|
||||||
#define CATCH_VERSION_MINOR 13
|
#define CATCH_VERSION_MINOR 13
|
||||||
#define CATCH_VERSION_PATCH 9
|
#define CATCH_VERSION_PATCH 10
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
# pragma clang system_header
|
# pragma clang system_header
|
||||||
@ -7395,8 +7395,6 @@ namespace Catch {
|
|||||||
template <typename T, bool Destruct>
|
template <typename T, bool Destruct>
|
||||||
struct ObjectStorage
|
struct ObjectStorage
|
||||||
{
|
{
|
||||||
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
|
||||||
|
|
||||||
ObjectStorage() : data() {}
|
ObjectStorage() : data() {}
|
||||||
|
|
||||||
ObjectStorage(const ObjectStorage& other)
|
ObjectStorage(const ObjectStorage& other)
|
||||||
@ -7439,7 +7437,7 @@ namespace Catch {
|
|||||||
return *static_cast<T*>(static_cast<void*>(&data));
|
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__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
|
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
#define CATCH_TRAP() __asm__(".inst 0xd4200000")
|
#define CATCH_TRAP() __asm__(".inst 0xd43e0000")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(CATCH_PLATFORM_IPHONE)
|
#elif defined(CATCH_PLATFORM_IPHONE)
|
||||||
@ -13558,7 +13556,7 @@ namespace Catch {
|
|||||||
|
|
||||||
// Handle list request
|
// Handle list request
|
||||||
if( Option<std::size_t> listed = list( m_config ) )
|
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 };
|
TestGroup tests { m_config };
|
||||||
auto const totals = tests.execute();
|
auto const totals = tests.execute();
|
||||||
@ -15391,7 +15389,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version const& libraryVersion() {
|
Version const& libraryVersion() {
|
||||||
static Version version( 2, 13, 9, "", 0 );
|
static Version version( 2, 13, 10, "", 0 );
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16314,7 +16312,7 @@ class Duration {
|
|||||||
Unit m_units;
|
Unit m_units;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Duration(double inNanoseconds, Unit units = Unit::Microseconds)
|
explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
|
||||||
: m_inNanoseconds(inNanoseconds),
|
: m_inNanoseconds(inNanoseconds),
|
||||||
m_units(units) {
|
m_units(units) {
|
||||||
if (m_units == Unit::Auto) {
|
if (m_units == Unit::Auto) {
|
||||||
@ -16364,7 +16362,7 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
|
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
|
} // end anon namespace
|
||||||
@ -17526,12 +17524,20 @@ namespace Catch {
|
|||||||
|
|
||||||
#ifndef __OBJC__
|
#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)
|
#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
|
||||||
// Standard C/C++ Win32 Unicode wmain entry point
|
// 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
|
#else
|
||||||
// Standard C/C++ main entry point
|
// Standard C/C++ main entry point
|
||||||
int main (int argc, char * argv[]) {
|
int CATCH_INTERNAL_CDECL main (int argc, char * argv[]) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return Catch::Session().run( argc, argv );
|
return Catch::Session().run( argc, argv );
|
||||||
|
@ -1,27 +1,39 @@
|
|||||||
/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
|
/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
|
||||||
|
|
||||||
Contributed to the GNU project by Niels Möller
|
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.
|
This file is part of the GNU MP Library.
|
||||||
|
|
||||||
The GNU MP Library is free software; you can redistribute it and/or modify
|
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
|
it under the terms of either:
|
||||||
the Free Software Foundation; either version 3 of the License, or (at your
|
|
||||||
|
* 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.
|
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
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
License for more details.
|
for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received copies of the GNU General Public License and the
|
||||||
along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
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
|
/* NOTE: All functions in this file which are not declared in
|
||||||
mini-gmp.h are internal, and are not intended to be compatible
|
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,
|
/* Much of the material copied from GMP files, including: gmp-impl.h,
|
||||||
longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
|
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>
|
#include <float.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Macros */
|
/* Macros */
|
||||||
#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
|
#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 { \
|
#define gmp_assert_nocarry(x) do { \
|
||||||
mp_limb_t __cy = (x); \
|
mp_limb_t __cy = (x); \
|
||||||
assert (__cy == 0); \
|
assert (__cy == 0); \
|
||||||
|
(void) (__cy); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define gmp_clz(count, x) do { \
|
#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; \
|
mp_limb_t __x0, __x1, __x2, __x3; \
|
||||||
unsigned __ul, __vl, __uh, __vh; \
|
unsigned __ul, __vl, __uh, __vh; \
|
||||||
mp_limb_t __u = (u), __v = (v); \
|
mp_limb_t __u = (u), __v = (v); \
|
||||||
|
assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t)); \
|
||||||
\
|
\
|
||||||
__ul = __u & GMP_LLIMB_MASK; \
|
__ul = __u & GMP_LLIMB_MASK; \
|
||||||
__uh = __u >> (GMP_LIMB_BITS / 2); \
|
__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)
|
} 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) \
|
#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \
|
||||||
do { \
|
do { \
|
||||||
mp_limb_t _qh, _ql, _r, _mask; \
|
mp_limb_t _qh, _ql, _r, _mask; \
|
||||||
gmp_umul_ppmm (_qh, _ql, (nh), (di)); \
|
gmp_umul_ppmm (_qh, _ql, (nh), (di)); \
|
||||||
gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \
|
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 */ \
|
_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \
|
||||||
_qh += _mask; \
|
_qh += _mask; \
|
||||||
_r += _mask & (d); \
|
_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)); \
|
gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \
|
||||||
\
|
\
|
||||||
/* Compute the two most significant limbs of n - q'd */ \
|
/* 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_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \
|
||||||
gmp_umul_ppmm (_t1, _t0, (d0), (q)); \
|
gmp_umul_ppmm (_t1, _t0, (d0), (q)); \
|
||||||
gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \
|
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;
|
gmp_free_func = free_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define gmp_xalloc(size) ((*gmp_allocate_func)((size)))
|
#define gmp_alloc(size) ((*gmp_allocate_func)((size)))
|
||||||
#define gmp_free(p) ((*gmp_free_func) ((p), 0))
|
#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
|
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
|
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);
|
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;
|
mp_limb_t p, ql;
|
||||||
unsigned ul, uh, qh;
|
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.
|
/* For notation, let b denote the half-limb base, so that B = b^2.
|
||||||
Split u1 = b uh + ul. */
|
Split u1 = b uh + ul. */
|
||||||
ul = u1 & GMP_LLIMB_MASK;
|
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 d, di;
|
||||||
mp_limb_t r;
|
mp_limb_t r;
|
||||||
mp_ptr tp = NULL;
|
mp_ptr tp = NULL;
|
||||||
|
mp_size_t tn = 0;
|
||||||
|
|
||||||
if (inv->shift > 0)
|
if (inv->shift > 0)
|
||||||
{
|
{
|
||||||
/* Shift, reusing qp area if possible. In-place shift if qp == np. */
|
/* 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);
|
r = mpn_lshift (tp, np, nn, inv->shift);
|
||||||
np = tp;
|
np = tp;
|
||||||
}
|
}
|
||||||
@ -966,8 +1001,8 @@ mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
|
|||||||
if (qp)
|
if (qp)
|
||||||
qp[nn] = q;
|
qp[nn] = q;
|
||||||
}
|
}
|
||||||
if ((inv->shift > 0) && (tp != qp))
|
if (tn)
|
||||||
gmp_free (tp);
|
gmp_free_limbs (tp, tn);
|
||||||
|
|
||||||
return r >> inv->shift;
|
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);
|
mpn_div_qr_invert (&inv, dp, dn);
|
||||||
if (dn > 2 && inv.shift > 0)
|
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));
|
gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
|
||||||
dp = tp;
|
dp = tp;
|
||||||
}
|
}
|
||||||
mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
|
mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
|
||||||
if (tp)
|
if (tp)
|
||||||
gmp_free (tp);
|
gmp_free_limbs (tp, dn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1307,28 +1342,25 @@ mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
|
|||||||
unsigned bits)
|
unsigned bits)
|
||||||
{
|
{
|
||||||
mp_size_t rn;
|
mp_size_t rn;
|
||||||
size_t j;
|
mp_limb_t limb;
|
||||||
unsigned shift;
|
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;
|
||||||
{
|
|
||||||
rp[rn++] = sp[j];
|
|
||||||
shift += bits;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rp[rn-1] |= (mp_limb_t) sp[j] << shift;
|
|
||||||
shift += bits;
|
shift += bits;
|
||||||
if (shift >= GMP_LIMB_BITS)
|
if (shift >= GMP_LIMB_BITS)
|
||||||
{
|
{
|
||||||
shift -= GMP_LIMB_BITS;
|
shift -= GMP_LIMB_BITS;
|
||||||
if (shift > 0)
|
rp[rn++] = limb;
|
||||||
rp[rn++] = (mp_limb_t) sp[j] >> (bits - shift);
|
/* Next line is correct also if shift == 0,
|
||||||
}
|
bits == 8, and mp_limb_t == unsigned char. */
|
||||||
|
limb = (unsigned int) sp[sn] >> (bits - shift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (limb != 0)
|
||||||
|
rp[rn++] = limb;
|
||||||
|
else
|
||||||
rn = mpn_normalized_size (rp, rn);
|
rn = mpn_normalized_size (rp, rn);
|
||||||
return rn;
|
return rn;
|
||||||
}
|
}
|
||||||
@ -1417,14 +1449,14 @@ mpz_init2 (mpz_t r, mp_bitcnt_t bits)
|
|||||||
|
|
||||||
r->_mp_alloc = rn;
|
r->_mp_alloc = rn;
|
||||||
r->_mp_size = 0;
|
r->_mp_size = 0;
|
||||||
r->_mp_d = gmp_xalloc_limbs (rn);
|
r->_mp_d = gmp_alloc_limbs (rn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mpz_clear (mpz_t r)
|
mpz_clear (mpz_t r)
|
||||||
{
|
{
|
||||||
if (r->_mp_alloc)
|
if (r->_mp_alloc)
|
||||||
gmp_free (r->_mp_d);
|
gmp_free_limbs (r->_mp_d, r->_mp_alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mp_ptr
|
static mp_ptr
|
||||||
@ -1433,9 +1465,9 @@ mpz_realloc (mpz_t r, mp_size_t size)
|
|||||||
size = GMP_MAX (size, 1);
|
size = GMP_MAX (size, 1);
|
||||||
|
|
||||||
if (r->_mp_alloc)
|
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
|
else
|
||||||
r->_mp_d = gmp_xalloc_limbs (size);
|
r->_mp_d = gmp_alloc_limbs (size);
|
||||||
r->_mp_alloc = size;
|
r->_mp_alloc = size;
|
||||||
|
|
||||||
if (GMP_ABS (r->_mp_size) > size)
|
if (GMP_ABS (r->_mp_size) > size)
|
||||||
@ -1530,8 +1562,7 @@ mpz_init_set (mpz_t r, const mpz_t x)
|
|||||||
int
|
int
|
||||||
mpz_fits_slong_p (const mpz_t u)
|
mpz_fits_slong_p (const mpz_t u)
|
||||||
{
|
{
|
||||||
return (LONG_MAX + LONG_MIN == 0 || mpz_cmp_ui (u, LONG_MAX) <= 0) &&
|
return mpz_cmp_si (u, LONG_MAX) <= 0 && mpz_cmp_si (u, LONG_MIN) >= 0;
|
||||||
mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, LONG_MIN)) <= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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);
|
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
|
long int
|
||||||
mpz_get_si (const mpz_t u)
|
mpz_get_si (const mpz_t u)
|
||||||
{
|
{
|
||||||
@ -1891,9 +1946,8 @@ mpz_neg (mpz_t r, const mpz_t u)
|
|||||||
void
|
void
|
||||||
mpz_swap (mpz_t u, mpz_t v)
|
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_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);
|
assert (r->_mp_size > 0);
|
||||||
/* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
|
/* 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);
|
mpz_tdiv_q_2exp (r, r, shift);
|
||||||
|
|
||||||
return 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)
|
if (tv->_mp_size == 1)
|
||||||
{
|
{
|
||||||
mp_limb_t vl = tv->_mp_d[0];
|
mp_limb_t *gp;
|
||||||
mp_limb_t ul = mpz_tdiv_ui (tu, vl);
|
|
||||||
mpz_set_ui (g, mpn_gcd_11 (ul, vl));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
mpz_sub (tu, tu, tv);
|
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
|
* s0 = 0, s1 = 2^vz
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mpz_setbit (t0, uz);
|
|
||||||
mpz_tdiv_qr (t1, tu, tu, tv);
|
mpz_tdiv_qr (t1, tu, tu, tv);
|
||||||
mpz_mul_2exp (t1, t1, uz);
|
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;
|
mp_bitcnt_t shift;
|
||||||
shift = mpz_make_odd (tu);
|
shift = mpz_make_odd (tu);
|
||||||
mpz_mul_2exp (t0, t0, shift);
|
mpz_setbit (t0, uz + shift);
|
||||||
mpz_mul_2exp (s0, s0, shift);
|
|
||||||
power += shift;
|
power += shift;
|
||||||
|
|
||||||
for (;;)
|
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;
|
power += shift;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
mpz_setbit (t0, uz);
|
||||||
|
|
||||||
/* Now tv = odd part of gcd, and -s0 and t0 are corresponding
|
/* Now tv = odd part of gcd, and -s0 and t0 are corresponding
|
||||||
cofactors. */
|
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)
|
if (en == 0)
|
||||||
{
|
{
|
||||||
mpz_set_ui (r, 1);
|
mpz_set_ui (r, mpz_cmpabs_ui (m, 1));
|
||||||
return;
|
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. */
|
one, using a *normalized* m. */
|
||||||
minv.shift = 0;
|
minv.shift = 0;
|
||||||
|
|
||||||
tp = gmp_xalloc_limbs (mn);
|
tp = gmp_alloc_limbs (mn);
|
||||||
gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
|
gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
|
||||||
mp = tp;
|
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);
|
tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
|
||||||
}
|
}
|
||||||
if (tp)
|
if (tp)
|
||||||
gmp_free (tp);
|
gmp_free_limbs (tp, mn);
|
||||||
|
|
||||||
mpz_swap (r, tr);
|
mpz_swap (r, tr);
|
||||||
mpz_clear (tr);
|
mpz_clear (tr);
|
||||||
@ -3150,6 +3208,7 @@ void
|
|||||||
mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
|
mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
|
||||||
{
|
{
|
||||||
int sgn;
|
int sgn;
|
||||||
|
mp_bitcnt_t bc;
|
||||||
mpz_t t, u;
|
mpz_t t, u;
|
||||||
|
|
||||||
sgn = y->_mp_size < 0;
|
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 (u);
|
||||||
mpz_init (t);
|
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 */
|
if (z == 2) /* simplify sqrt loop: z-1 == 1 */
|
||||||
do {
|
do {
|
||||||
@ -3339,13 +3399,15 @@ gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b)
|
|||||||
gmp_ctz(c, a);
|
gmp_ctz(c, a);
|
||||||
a >>= 1;
|
a >>= 1;
|
||||||
|
|
||||||
do
|
for (;;)
|
||||||
{
|
{
|
||||||
a >>= c;
|
a >>= c;
|
||||||
/* (2/b) = -1 if b = 3 or 5 mod 8 */
|
/* (2/b) = -1 if b = 3 or 5 mod 8 */
|
||||||
bit ^= c & (b ^ (b >> 1));
|
bit ^= c & (b ^ (b >> 1));
|
||||||
if (a < b)
|
if (a < b)
|
||||||
{
|
{
|
||||||
|
if (a == 0)
|
||||||
|
return bit & 1 ? -1 : 1;
|
||||||
bit ^= a & b;
|
bit ^= a & b;
|
||||||
a = b - a;
|
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);
|
gmp_ctz(c, a);
|
||||||
++c;
|
++c;
|
||||||
}
|
}
|
||||||
while (b > 0);
|
|
||||||
|
|
||||||
return bit & 1 ? -1 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
gmp_lucas_step_k_2k (V, Qk, n);
|
||||||
|
|
||||||
/* A step k->k+1 is performed if the bit in $n$ is 1 */
|
/* 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) */
|
/* should be 1 in $n+1$ (bs == b0) */
|
||||||
if (b0 == bs || mpz_tstbit (n, bs))
|
if (b0 == bs || mpz_tstbit (n, bs))
|
||||||
{
|
{
|
||||||
@ -3476,7 +3535,8 @@ gmp_stronglucas (const mpz_t x, mpz_t Qk)
|
|||||||
mpz_init (V);
|
mpz_init (V);
|
||||||
|
|
||||||
/* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
|
/* 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 */
|
/* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
|
||||||
Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2);
|
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);
|
mpz_powm_ui (y, y, 2, n);
|
||||||
if (mpz_cmp (y, nm1) == 0)
|
if (mpz_cmp (y, nm1) == 0)
|
||||||
return 1;
|
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;
|
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. */
|
/* Find q and k, where q is odd and n = 1 + 2**k * q. */
|
||||||
mpz_abs (nm1, n);
|
mpz_abs (nm1, n);
|
||||||
nm1->_mp_d[0] -= 1;
|
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);
|
mpz_tdiv_q_2exp (q, nm1, k);
|
||||||
|
|
||||||
/* BPSW test */
|
/* BPSW test */
|
||||||
@ -4133,7 +4189,7 @@ mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
|
|||||||
size_t
|
size_t
|
||||||
mpz_sizeinbase (const mpz_t u, int base)
|
mpz_sizeinbase (const mpz_t u, int base)
|
||||||
{
|
{
|
||||||
mp_size_t un;
|
mp_size_t un, tn;
|
||||||
mp_srcptr up;
|
mp_srcptr up;
|
||||||
mp_ptr tp;
|
mp_ptr tp;
|
||||||
mp_bitcnt_t bits;
|
mp_bitcnt_t bits;
|
||||||
@ -4166,20 +4222,21 @@ mpz_sizeinbase (const mpz_t u, int base)
|
|||||||
10. */
|
10. */
|
||||||
}
|
}
|
||||||
|
|
||||||
tp = gmp_xalloc_limbs (un);
|
tp = gmp_alloc_limbs (un);
|
||||||
mpn_copyi (tp, up, un);
|
mpn_copyi (tp, up, un);
|
||||||
mpn_div_qr_1_invert (&bi, base);
|
mpn_div_qr_1_invert (&bi, base);
|
||||||
|
|
||||||
|
tn = un;
|
||||||
ndigits = 0;
|
ndigits = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
ndigits++;
|
ndigits++;
|
||||||
mpn_div_qr_1_preinv (tp, tp, un, &bi);
|
mpn_div_qr_1_preinv (tp, tp, tn, &bi);
|
||||||
un -= (tp[un-1] == 0);
|
tn -= (tp[tn-1] == 0);
|
||||||
}
|
}
|
||||||
while (un > 0);
|
while (tn > 0);
|
||||||
|
|
||||||
gmp_free (tp);
|
gmp_free_limbs (tp, un);
|
||||||
return ndigits;
|
return ndigits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4189,7 +4246,7 @@ mpz_get_str (char *sp, int base, const mpz_t u)
|
|||||||
unsigned bits;
|
unsigned bits;
|
||||||
const char *digits;
|
const char *digits;
|
||||||
mp_size_t un;
|
mp_size_t un;
|
||||||
size_t i, sn;
|
size_t i, sn, osn;
|
||||||
|
|
||||||
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
if (base > 1)
|
if (base > 1)
|
||||||
@ -4210,15 +4267,19 @@ mpz_get_str (char *sp, int base, const mpz_t u)
|
|||||||
|
|
||||||
sn = 1 + mpz_sizeinbase (u, base);
|
sn = 1 + mpz_sizeinbase (u, base);
|
||||||
if (!sp)
|
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);
|
un = GMP_ABS (u->_mp_size);
|
||||||
|
|
||||||
if (un == 0)
|
if (un == 0)
|
||||||
{
|
{
|
||||||
sp[0] = '0';
|
sp[0] = '0';
|
||||||
sp[1] = '\0';
|
sn = 1;
|
||||||
return sp;
|
goto ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -4237,17 +4298,20 @@ mpz_get_str (char *sp, int base, const mpz_t u)
|
|||||||
mp_ptr tp;
|
mp_ptr tp;
|
||||||
|
|
||||||
mpn_get_base_info (&info, base);
|
mpn_get_base_info (&info, base);
|
||||||
tp = gmp_xalloc_limbs (un);
|
tp = gmp_alloc_limbs (un);
|
||||||
mpn_copyi (tp, u->_mp_d, un);
|
mpn_copyi (tp, u->_mp_d, un);
|
||||||
|
|
||||||
sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, 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++)
|
for (; i < sn; i++)
|
||||||
sp[i] = digits[(unsigned char) sp[i]];
|
sp[i] = digits[(unsigned char) sp[i]];
|
||||||
|
|
||||||
|
ret:
|
||||||
sp[sn] = '\0';
|
sp[sn] = '\0';
|
||||||
|
if (osn && osn != sn + 1)
|
||||||
|
sp = (char*) gmp_realloc (sp, osn, sn + 1);
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4257,7 +4321,7 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
|||||||
unsigned bits, value_of_a;
|
unsigned bits, value_of_a;
|
||||||
mp_size_t rn, alloc;
|
mp_size_t rn, alloc;
|
||||||
mp_ptr rp;
|
mp_ptr rp;
|
||||||
size_t dn;
|
size_t dn, sn;
|
||||||
int sign;
|
int sign;
|
||||||
unsigned char *dp;
|
unsigned char *dp;
|
||||||
|
|
||||||
@ -4295,7 +4359,8 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
|||||||
r->_mp_size = 0;
|
r->_mp_size = 0;
|
||||||
return -1;
|
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;
|
value_of_a = (base > 36) ? 36 : 10;
|
||||||
for (dn = 0; *sp; sp++)
|
for (dn = 0; *sp; sp++)
|
||||||
@ -4315,7 +4380,7 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
|||||||
|
|
||||||
if (digit >= (unsigned) base)
|
if (digit >= (unsigned) base)
|
||||||
{
|
{
|
||||||
gmp_free (dp);
|
gmp_free (dp, sn);
|
||||||
r->_mp_size = 0;
|
r->_mp_size = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -4325,7 +4390,7 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
|||||||
|
|
||||||
if (!dn)
|
if (!dn)
|
||||||
{
|
{
|
||||||
gmp_free (dp);
|
gmp_free (dp, sn);
|
||||||
r->_mp_size = 0;
|
r->_mp_size = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -4349,7 +4414,7 @@ mpz_set_str (mpz_t r, const char *sp, int base)
|
|||||||
rn -= rp[rn-1] == 0;
|
rn -= rp[rn-1] == 0;
|
||||||
}
|
}
|
||||||
assert (rn <= alloc);
|
assert (rn <= alloc);
|
||||||
gmp_free (dp);
|
gmp_free (dp, sn);
|
||||||
|
|
||||||
r->_mp_size = sign ? - rn : rn;
|
r->_mp_size = sign ? - rn : rn;
|
||||||
|
|
||||||
@ -4367,13 +4432,15 @@ size_t
|
|||||||
mpz_out_str (FILE *stream, int base, const mpz_t x)
|
mpz_out_str (FILE *stream, int base, const mpz_t x)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
size_t len;
|
size_t len, n;
|
||||||
|
|
||||||
str = mpz_get_str (NULL, base, x);
|
str = mpz_get_str (NULL, base, x);
|
||||||
|
if (!str)
|
||||||
|
return 0;
|
||||||
len = strlen (str);
|
len = strlen (str);
|
||||||
len = fwrite (str, 1, len, stream);
|
n = fwrite (str, 1, len, stream);
|
||||||
gmp_free (str);
|
gmp_free (str, len + 1);
|
||||||
return len;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4462,7 +4529,7 @@ mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
|
|||||||
mp_size_t un;
|
mp_size_t un;
|
||||||
|
|
||||||
if (nails != 0)
|
if (nails != 0)
|
||||||
gmp_die ("mpz_import: Nails not supported.");
|
gmp_die ("mpz_export: Nails not supported.");
|
||||||
|
|
||||||
assert (order == 1 || order == -1);
|
assert (order == 1 || order == -1);
|
||||||
assert (endian >= -1 && endian <= 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;
|
ptrdiff_t word_step;
|
||||||
/* The current (partial) limb. */
|
/* The current (partial) limb. */
|
||||||
mp_limb_t 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;
|
size_t bytes;
|
||||||
/* The index where the limb was read. */
|
/* The index where the limb was read. */
|
||||||
mp_size_t i;
|
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;
|
count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
r = gmp_xalloc (count * size);
|
r = gmp_alloc (count * size);
|
||||||
|
|
||||||
if (endian == 0)
|
if (endian == 0)
|
||||||
endian = gmp_detect_endian ();
|
endian = gmp_detect_endian ();
|
||||||
|
@ -1,21 +1,32 @@
|
|||||||
/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
|
/* 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.
|
This file is part of the GNU MP Library.
|
||||||
|
|
||||||
The GNU MP Library is free software; you can redistribute it and/or modify
|
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
|
it under the terms of either:
|
||||||
the Free Software Foundation; either version 3 of the License, or (at your
|
|
||||||
|
* 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.
|
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
|
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
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
License for more details.
|
for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received copies of the GNU General Public License and the
|
||||||
along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
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
|
/* About mini-gmp: This is a minimal implementation of a subset of the
|
||||||
GMP interface. It is intended for inclusion into applications which
|
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_slong_p (const mpz_t);
|
||||||
int mpz_fits_ulong_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);
|
long int mpz_get_si (const mpz_t);
|
||||||
unsigned long int mpz_get_ui (const mpz_t);
|
unsigned long int mpz_get_ui (const mpz_t);
|
||||||
double mpz_get_d (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 (_MSL_STDIO_H) /* Metrowerks */ \
|
||||||
|| defined (_STDIO_H_INCLUDED) /* QNX4 */ \
|
|| defined (_STDIO_H_INCLUDED) /* QNX4 */ \
|
||||||
|| defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \
|
|| 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);
|
size_t mpz_out_str (FILE *, int, const mpz_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
cd ..
|
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
|
cd jsoncpp
|
||||||
python amalgamate.py
|
./amalgamate.py
|
||||||
cp -R dist/json ../json
|
cp -R dist/json ../json
|
||||||
cp dist/jsoncpp.cpp ..
|
cp dist/jsoncpp.cpp ..
|
||||||
|
@ -94,10 +94,10 @@ license you like.
|
|||||||
// 3. /CMakeLists.txt
|
// 3. /CMakeLists.txt
|
||||||
// IMPORTANT: also update the SOVERSION!!
|
// 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_MAJOR 1
|
||||||
#define JSONCPP_VERSION_MINOR 9
|
#define JSONCPP_VERSION_MINOR 9
|
||||||
#define JSONCPP_VERSION_PATCH 3
|
#define JSONCPP_VERSION_PATCH 5
|
||||||
#define JSONCPP_VERSION_QUALIFIER
|
#define JSONCPP_VERSION_QUALIFIER
|
||||||
#define JSONCPP_VERSION_HEXA \
|
#define JSONCPP_VERSION_HEXA \
|
||||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||||
@ -162,11 +162,10 @@ public:
|
|||||||
* Release memory which was allocated for N items at pointer P.
|
* Release memory which was allocated for N items at pointer P.
|
||||||
*
|
*
|
||||||
* The memory block is filled with zeroes before being released.
|
* 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) {
|
void deallocate(pointer p, size_type n) {
|
||||||
std::memset(p, 0, n * sizeof(T));
|
// 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"
|
// free using "global operator delete"
|
||||||
::operator delete(p);
|
::operator delete(p);
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,10 @@ license you like.
|
|||||||
// 3. /CMakeLists.txt
|
// 3. /CMakeLists.txt
|
||||||
// IMPORTANT: also update the SOVERSION!!
|
// 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_MAJOR 1
|
||||||
#define JSONCPP_VERSION_MINOR 9
|
#define JSONCPP_VERSION_MINOR 9
|
||||||
#define JSONCPP_VERSION_PATCH 3
|
#define JSONCPP_VERSION_PATCH 5
|
||||||
#define JSONCPP_VERSION_QUALIFIER
|
#define JSONCPP_VERSION_QUALIFIER
|
||||||
#define JSONCPP_VERSION_HEXA \
|
#define JSONCPP_VERSION_HEXA \
|
||||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||||
@ -161,11 +161,10 @@ public:
|
|||||||
* Release memory which was allocated for N items at pointer P.
|
* Release memory which was allocated for N items at pointer P.
|
||||||
*
|
*
|
||||||
* The memory block is filled with zeroes before being released.
|
* 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) {
|
void deallocate(pointer p, size_type n) {
|
||||||
std::memset(p, 0, n * sizeof(T));
|
// 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"
|
// free using "global operator delete"
|
||||||
::operator delete(p);
|
::operator delete(p);
|
||||||
}
|
}
|
||||||
@ -575,7 +574,7 @@ public:
|
|||||||
// be used by...
|
// be used by...
|
||||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4251)
|
#pragma warning(disable : 4251 4275)
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
#pragma pack(push, 8)
|
||||||
@ -788,10 +787,10 @@ private:
|
|||||||
CZString(ArrayIndex index);
|
CZString(ArrayIndex index);
|
||||||
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
||||||
CZString(CZString const& other);
|
CZString(CZString const& other);
|
||||||
CZString(CZString&& other);
|
CZString(CZString&& other) noexcept;
|
||||||
~CZString();
|
~CZString();
|
||||||
CZString& operator=(const CZString& other);
|
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;
|
||||||
bool operator==(CZString const& other) const;
|
bool operator==(CZString const& other) const;
|
||||||
@ -869,13 +868,13 @@ public:
|
|||||||
Value(bool value);
|
Value(bool value);
|
||||||
Value(std::nullptr_t ptr) = delete;
|
Value(std::nullptr_t ptr) = delete;
|
||||||
Value(const Value& other);
|
Value(const Value& other);
|
||||||
Value(Value&& other);
|
Value(Value&& other) noexcept;
|
||||||
~Value();
|
~Value();
|
||||||
|
|
||||||
/// \note Overwrite existing comments. To preserve comments, use
|
/// \note Overwrite existing comments. To preserve comments, use
|
||||||
/// #swapPayload().
|
/// #swapPayload().
|
||||||
Value& operator=(const Value& other);
|
Value& operator=(const Value& other);
|
||||||
Value& operator=(Value&& other);
|
Value& operator=(Value&& other) noexcept;
|
||||||
|
|
||||||
/// Swap everything.
|
/// Swap everything.
|
||||||
void swap(Value& other);
|
void swap(Value& other);
|
||||||
@ -1160,9 +1159,9 @@ private:
|
|||||||
public:
|
public:
|
||||||
Comments() = default;
|
Comments() = default;
|
||||||
Comments(const Comments& that);
|
Comments(const Comments& that);
|
||||||
Comments(Comments&& that);
|
Comments(Comments&& that) noexcept;
|
||||||
Comments& operator=(const Comments& that);
|
Comments& operator=(const Comments& that);
|
||||||
Comments& operator=(Comments&& that);
|
Comments& operator=(Comments&& that) noexcept;
|
||||||
bool has(CommentPlacement slot) const;
|
bool has(CommentPlacement slot) const;
|
||||||
String get(CommentPlacement slot) const;
|
String get(CommentPlacement slot) const;
|
||||||
void set(CommentPlacement slot, String comment);
|
void set(CommentPlacement slot, String comment);
|
||||||
@ -1443,8 +1442,8 @@ public:
|
|||||||
* because the returned references/pointers can be used
|
* because the returned references/pointers can be used
|
||||||
* to change state of the base class.
|
* to change state of the base class.
|
||||||
*/
|
*/
|
||||||
reference operator*() { return deref(); }
|
reference operator*() const { return const_cast<reference>(deref()); }
|
||||||
pointer operator->() { return &deref(); }
|
pointer operator->() const { return const_cast<pointer>(&deref()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void swap(Value& a, Value& b) { a.swap(b); }
|
inline void swap(Value& a, Value& b) { a.swap(b); }
|
||||||
@ -1507,8 +1506,7 @@ namespace Json {
|
|||||||
* \deprecated Use CharReader and CharReaderBuilder.
|
* \deprecated Use CharReader and CharReaderBuilder.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class JSONCPP_DEPRECATED(
|
class JSON_API Reader {
|
||||||
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
|
|
||||||
public:
|
public:
|
||||||
using Char = char;
|
using Char = char;
|
||||||
using Location = const Char*;
|
using Location = const Char*;
|
||||||
@ -1525,13 +1523,13 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Constructs a Reader allowing all features for parsing.
|
/** \brief Constructs a Reader allowing all features for parsing.
|
||||||
|
* \deprecated Use CharReader and CharReaderBuilder.
|
||||||
*/
|
*/
|
||||||
JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
|
|
||||||
Reader();
|
Reader();
|
||||||
|
|
||||||
/** \brief Constructs a Reader allowing the specified feature set for parsing.
|
/** \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);
|
Reader(const Features& features);
|
||||||
|
|
||||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||||
@ -1798,6 +1796,9 @@ public:
|
|||||||
* - `"allowSpecialFloats": false or true`
|
* - `"allowSpecialFloats": false or true`
|
||||||
* - If true, special float values (NaNs and infinities) are allowed and
|
* - If true, special float values (NaNs and infinities) are allowed and
|
||||||
* their values are lossfree restorable.
|
* 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
|
* You can examine 'settings_` yourself to see the defaults. You can also
|
||||||
* write and read them just like any JSON Value.
|
* write and read them just like any JSON Value.
|
||||||
@ -2001,6 +2002,8 @@ public:
|
|||||||
* - Number of precision digits for formatting of real values.
|
* - Number of precision digits for formatting of real values.
|
||||||
* - "precisionType": "significant"(default) or "decimal"
|
* - "precisionType": "significant"(default) or "decimal"
|
||||||
* - Type of precision for formatting of real values.
|
* - 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
|
* You can examine 'settings_` yourself
|
||||||
* to see the defaults. You can also write and read them just like any
|
* to see the defaults. You can also write and read them just like any
|
||||||
@ -2036,7 +2039,7 @@ public:
|
|||||||
/** \brief Abstract class for writers.
|
/** \brief Abstract class for writers.
|
||||||
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
||||||
*/
|
*/
|
||||||
class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer {
|
class JSON_API Writer {
|
||||||
public:
|
public:
|
||||||
virtual ~Writer();
|
virtual ~Writer();
|
||||||
|
|
||||||
@ -2056,7 +2059,7 @@ public:
|
|||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||||
#endif
|
#endif
|
||||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
|
class JSON_API FastWriter
|
||||||
: public Writer {
|
: public Writer {
|
||||||
public:
|
public:
|
||||||
FastWriter();
|
FastWriter();
|
||||||
@ -2116,7 +2119,7 @@ private:
|
|||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||||
#endif
|
#endif
|
||||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
class JSON_API
|
||||||
StyledWriter : public Writer {
|
StyledWriter : public Writer {
|
||||||
public:
|
public:
|
||||||
StyledWriter();
|
StyledWriter();
|
||||||
@ -2185,7 +2188,7 @@ private:
|
|||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||||
#endif
|
#endif
|
||||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
class JSON_API
|
||||||
StyledStreamWriter {
|
StyledStreamWriter {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -202,15 +202,19 @@ template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
|
|||||||
* Return iterator that would be the new end of the range [begin,end), if we
|
* 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 '.'.
|
* 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) {
|
for (; begin != end; --end) {
|
||||||
if (*(end - 1) != '0') {
|
if (*(end - 1) != '0') {
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
// Don't delete the last zero before the decimal point.
|
// Don't delete the last zero before the decimal point.
|
||||||
if (begin != (end - 1) && *(end - 2) == '.') {
|
if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
|
||||||
|
if (precision) {
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
return end - 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return end;
|
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
|
// Since String is reference-counted, this at least does not
|
||||||
// create an extra copy.
|
// create an extra copy.
|
||||||
String doc;
|
String doc(std::istreambuf_iterator<char>(is), {});
|
||||||
std::getline(is, doc, static_cast<char> EOF);
|
|
||||||
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
|
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))
|
if (valid_keys.count(key))
|
||||||
continue;
|
continue;
|
||||||
if (invalid)
|
if (invalid)
|
||||||
(*invalid)[std::move(key)] = *si;
|
(*invalid)[key] = *si;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2670,7 +2673,7 @@ Value::CZString::CZString(const CZString& other) {
|
|||||||
storage_.length_ = other.storage_.length_;
|
storage_.length_ = other.storage_.length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::CZString::CZString(CZString&& other)
|
Value::CZString::CZString(CZString&& other) noexcept
|
||||||
: cstr_(other.cstr_), index_(other.index_) {
|
: cstr_(other.cstr_), index_(other.index_) {
|
||||||
other.cstr_ = nullptr;
|
other.cstr_ = nullptr;
|
||||||
}
|
}
|
||||||
@ -2696,7 +2699,7 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::CZString& Value::CZString::operator=(CZString&& other) {
|
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
|
||||||
cstr_ = other.cstr_;
|
cstr_ = other.cstr_;
|
||||||
index_ = other.index_;
|
index_ = other.index_;
|
||||||
other.cstr_ = nullptr;
|
other.cstr_ = nullptr;
|
||||||
@ -2844,7 +2847,7 @@ Value::Value(const Value& other) {
|
|||||||
dupMeta(other);
|
dupMeta(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(Value&& other) {
|
Value::Value(Value&& other) noexcept {
|
||||||
initBasic(nullValue);
|
initBasic(nullValue);
|
||||||
swap(other);
|
swap(other);
|
||||||
}
|
}
|
||||||
@ -2859,7 +2862,7 @@ Value& Value::operator=(const Value& other) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator=(Value&& other) {
|
Value& Value::operator=(Value&& other) noexcept {
|
||||||
other.swap(*this);
|
other.swap(*this);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -3323,7 +3326,8 @@ void Value::resize(ArrayIndex newSize) {
|
|||||||
if (newSize == 0)
|
if (newSize == 0)
|
||||||
clear();
|
clear();
|
||||||
else if (newSize > oldSize)
|
else if (newSize > oldSize)
|
||||||
this->operator[](newSize - 1);
|
for (ArrayIndex i = oldSize; i < newSize; ++i)
|
||||||
|
(*this)[i];
|
||||||
else {
|
else {
|
||||||
for (ArrayIndex index = newSize; index < oldSize; ++index) {
|
for (ArrayIndex index = newSize; index < oldSize; ++index) {
|
||||||
value_.map_->erase(index);
|
value_.map_->erase(index);
|
||||||
@ -3784,14 +3788,15 @@ bool Value::isObject() const { return type() == objectValue; }
|
|||||||
Value::Comments::Comments(const Comments& that)
|
Value::Comments::Comments(const Comments& that)
|
||||||
: ptr_{cloneUnique(that.ptr_)} {}
|
: 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) {
|
Value::Comments& Value::Comments::operator=(const Comments& that) {
|
||||||
ptr_ = cloneUnique(that.ptr_);
|
ptr_ = cloneUnique(that.ptr_);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Comments& Value::Comments::operator=(Comments&& that) {
|
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
|
||||||
ptr_ = std::move(that.ptr_);
|
ptr_ = std::move(that.ptr_);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -3807,14 +3812,12 @@ String Value::Comments::get(CommentPlacement slot) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Value::Comments::set(CommentPlacement slot, String comment) {
|
void Value::Comments::set(CommentPlacement slot, String comment) {
|
||||||
if (!ptr_) {
|
if (slot >= CommentPlacement::numberOfCommentPlacement)
|
||||||
|
return;
|
||||||
|
if (!ptr_)
|
||||||
ptr_ = std::unique_ptr<Array>(new Array());
|
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) {
|
void Value::setComment(String comment, CommentPlacement placement) {
|
||||||
if (!comment.empty() && (comment.back() == '\n')) {
|
if (!comment.empty() && (comment.back() == '\n')) {
|
||||||
@ -4127,7 +4130,7 @@ Value& Path::make(Value& root) const {
|
|||||||
|
|
||||||
#if !defined(isnan)
|
#if !defined(isnan)
|
||||||
// IEEE standard states that NaN values will not compare to themselves
|
// IEEE standard states that NaN values will not compare to themselves
|
||||||
#define isnan(x) (x != x)
|
#define isnan(x) ((x) != (x))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__APPLE__)
|
#if !defined(__APPLE__)
|
||||||
@ -4213,16 +4216,18 @@ String valueToString(double value, bool useSpecialFloats,
|
|||||||
|
|
||||||
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
|
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
|
// try to ensure we preserve the fact that this was given to us as a double on
|
||||||
// input
|
// input
|
||||||
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
|
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
|
||||||
buffer += ".0";
|
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;
|
return buffer;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -4329,7 +4334,7 @@ static void appendHex(String& result, unsigned ch) {
|
|||||||
result.append("\\u").append(toHex16Bit(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) {
|
bool emitUTF8 = false) {
|
||||||
if (value == nullptr)
|
if (value == nullptr)
|
||||||
return "";
|
return "";
|
||||||
@ -4407,7 +4412,7 @@ static String valueToQuotedStringN(const char* value, unsigned length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
String valueToQuotedString(const char* value) {
|
String valueToQuotedString(const char* value) {
|
||||||
return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
|
return valueToQuotedStringN(value, strlen(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class Writer
|
// Class Writer
|
||||||
@ -4456,7 +4461,7 @@ void FastWriter::writeValue(const Value& value) {
|
|||||||
char const* end;
|
char const* end;
|
||||||
bool ok = value.getString(&str, &end);
|
bool ok = value.getString(&str, &end);
|
||||||
if (ok)
|
if (ok)
|
||||||
document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
|
document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case booleanValue:
|
case booleanValue:
|
||||||
@ -4479,8 +4484,7 @@ void FastWriter::writeValue(const Value& value) {
|
|||||||
const String& name = *it;
|
const String& name = *it;
|
||||||
if (it != members.begin())
|
if (it != members.begin())
|
||||||
document_ += ',';
|
document_ += ',';
|
||||||
document_ += valueToQuotedStringN(name.data(),
|
document_ += valueToQuotedStringN(name.data(), name.length());
|
||||||
static_cast<unsigned>(name.length()));
|
|
||||||
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
|
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
|
||||||
writeValue(value[name]);
|
writeValue(value[name]);
|
||||||
}
|
}
|
||||||
@ -4525,7 +4529,7 @@ void StyledWriter::writeValue(const Value& value) {
|
|||||||
char const* end;
|
char const* end;
|
||||||
bool ok = value.getString(&str, &end);
|
bool ok = value.getString(&str, &end);
|
||||||
if (ok)
|
if (ok)
|
||||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||||
else
|
else
|
||||||
pushValue("");
|
pushValue("");
|
||||||
break;
|
break;
|
||||||
@ -4566,7 +4570,7 @@ void StyledWriter::writeValue(const Value& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StyledWriter::writeArrayValue(const Value& value) {
|
void StyledWriter::writeArrayValue(const Value& value) {
|
||||||
unsigned size = value.size();
|
size_t size = value.size();
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
pushValue("[]");
|
pushValue("[]");
|
||||||
else {
|
else {
|
||||||
@ -4575,7 +4579,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
|||||||
writeWithIndent("[");
|
writeWithIndent("[");
|
||||||
indent();
|
indent();
|
||||||
bool hasChildValue = !childValues_.empty();
|
bool hasChildValue = !childValues_.empty();
|
||||||
unsigned index = 0;
|
ArrayIndex index = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const Value& childValue = value[index];
|
const Value& childValue = value[index];
|
||||||
writeCommentBeforeValue(childValue);
|
writeCommentBeforeValue(childValue);
|
||||||
@ -4598,7 +4602,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
|||||||
{
|
{
|
||||||
assert(childValues_.size() == size);
|
assert(childValues_.size() == size);
|
||||||
document_ += "[ ";
|
document_ += "[ ";
|
||||||
for (unsigned index = 0; index < size; ++index) {
|
for (size_t index = 0; index < size; ++index) {
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
document_ += ", ";
|
document_ += ", ";
|
||||||
document_ += childValues_[index];
|
document_ += childValues_[index];
|
||||||
@ -4743,7 +4747,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
|
|||||||
char const* end;
|
char const* end;
|
||||||
bool ok = value.getString(&str, &end);
|
bool ok = value.getString(&str, &end);
|
||||||
if (ok)
|
if (ok)
|
||||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||||
else
|
else
|
||||||
pushValue("");
|
pushValue("");
|
||||||
break;
|
break;
|
||||||
@ -5017,8 +5021,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
|||||||
char const* end;
|
char const* end;
|
||||||
bool ok = value.getString(&str, &end);
|
bool ok = value.getString(&str, &end);
|
||||||
if (ok)
|
if (ok)
|
||||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
|
pushValue(
|
||||||
emitUTF8_));
|
valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_));
|
||||||
else
|
else
|
||||||
pushValue("");
|
pushValue("");
|
||||||
break;
|
break;
|
||||||
@ -5041,8 +5045,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
|||||||
String const& name = *it;
|
String const& name = *it;
|
||||||
Value const& childValue = value[name];
|
Value const& childValue = value[name];
|
||||||
writeCommentBeforeValue(childValue);
|
writeCommentBeforeValue(childValue);
|
||||||
writeWithIndent(valueToQuotedStringN(
|
writeWithIndent(
|
||||||
name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
|
valueToQuotedStringN(name.data(), name.length(), emitUTF8_));
|
||||||
*sout_ << colonSymbol_;
|
*sout_ << colonSymbol_;
|
||||||
writeValue(childValue);
|
writeValue(childValue);
|
||||||
if (++it == members.end()) {
|
if (++it == members.end()) {
|
||||||
@ -5276,7 +5280,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const {
|
|||||||
if (valid_keys.count(key))
|
if (valid_keys.count(key))
|
||||||
continue;
|
continue;
|
||||||
if (invalid)
|
if (invalid)
|
||||||
(*invalid)[std::move(key)] = *si;
|
(*invalid)[key] = *si;
|
||||||
else
|
else
|
||||||
return false;
|
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)
|
set(USE_CURL FALSE)
|
||||||
|
|
||||||
if(ENABLE_CURL)
|
if(ENABLE_CURL)
|
||||||
find_package(CURL)
|
find_package(CURL 7.28.0)
|
||||||
if (CURL_FOUND)
|
if (CURL_FOUND)
|
||||||
message(STATUS "cURL support enabled.")
|
message(STATUS "cURL support enabled.")
|
||||||
set(USE_CURL TRUE)
|
set(USE_CURL TRUE)
|
||||||
@ -326,6 +326,9 @@ if(HAVE_LINK_ATOMIC)
|
|||||||
set(PLATFORM_LIBS ${PLATFORM_LIBS} "-latomic")
|
set(PLATFORM_LIBS ${PLATFORM_LIBS} "-latomic")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY)
|
||||||
|
|
||||||
check_include_files(endian.h HAVE_ENDIAN_H)
|
check_include_files(endian.h HAVE_ENDIAN_H)
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
@ -363,9 +366,7 @@ set(common_SRCS
|
|||||||
${mapgen_SRCS}
|
${mapgen_SRCS}
|
||||||
${server_SRCS}
|
${server_SRCS}
|
||||||
${content_SRCS}
|
${content_SRCS}
|
||||||
ban.cpp
|
|
||||||
chat.cpp
|
chat.cpp
|
||||||
clientiface.cpp
|
|
||||||
collision.cpp
|
collision.cpp
|
||||||
content_mapnode.cpp
|
content_mapnode.cpp
|
||||||
content_nodemeta.cpp
|
content_nodemeta.cpp
|
||||||
@ -410,12 +411,10 @@ set(common_SRCS
|
|||||||
raycast.cpp
|
raycast.cpp
|
||||||
reflowscan.cpp
|
reflowscan.cpp
|
||||||
remoteplayer.cpp
|
remoteplayer.cpp
|
||||||
rollback.cpp
|
|
||||||
rollback_interface.cpp
|
rollback_interface.cpp
|
||||||
serialization.cpp
|
serialization.cpp
|
||||||
server.cpp
|
server.cpp
|
||||||
serverenvironment.cpp
|
serverenvironment.cpp
|
||||||
serverlist.cpp
|
|
||||||
settings.cpp
|
settings.cpp
|
||||||
staticobject.cpp
|
staticobject.cpp
|
||||||
terminal_chat_console.cpp
|
terminal_chat_console.cpp
|
||||||
@ -693,7 +692,6 @@ endif()
|
|||||||
# Set some optimizations and tweaks
|
# Set some optimizations and tweaks
|
||||||
|
|
||||||
include(CheckCSourceCompiles)
|
include(CheckCSourceCompiles)
|
||||||
include(CheckSymbolExists)
|
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${LUA_INCLUDE_DIR})
|
set(CMAKE_REQUIRED_INCLUDES ${LUA_INCLUDE_DIR})
|
||||||
if(USE_LUAJIT)
|
if(USE_LUAJIT)
|
||||||
|
@ -19,10 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "util/container.h"
|
||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
#include "util/basic_macros.h"
|
#include "util/basic_macros.h"
|
||||||
|
|
||||||
@ -52,24 +51,19 @@ public:
|
|||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
while (!m_active_objects.empty())
|
// on_destruct could add new objects so this has to be a loop
|
||||||
removeObject(m_active_objects.begin()->first);
|
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)
|
T *getActiveObject(u16 id)
|
||||||
{
|
{
|
||||||
auto it = m_active_objects.find(id);
|
return m_active_objects.get(id).get();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -88,11 +82,9 @@ protected:
|
|||||||
|
|
||||||
bool isFreeId(u16 id) const
|
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 that this is ordered to fix #10985
|
||||||
// Note: ActiveObjects can access the ActiveObjectMgr. Only erase objects using
|
ModifySafeMap<u16, std::unique_ptr<T>> m_active_objects;
|
||||||
// removeObject()!
|
|
||||||
std::map<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_lighting.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_serialize.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_serialize.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_mapblock.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_mapblock.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_mapmodify.cpp
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
|
||||||
set (BENCHMARK_CLIENT_SRCS
|
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():
|
ChatBackend::ChatBackend():
|
||||||
m_console_buffer(500),
|
m_console_buffer(1500),
|
||||||
m_recent_buffer(6),
|
m_recent_buffer(6),
|
||||||
m_prompt(L"]", 500)
|
m_prompt(L"]", 1500)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,17 +37,14 @@ ActiveObjectMgr::~ActiveObjectMgr()
|
|||||||
void ActiveObjectMgr::step(
|
void ActiveObjectMgr::step(
|
||||||
float dtime, const std::function<void(ClientActiveObject *)> &f)
|
float dtime, const std::function<void(ClientActiveObject *)> &f)
|
||||||
{
|
{
|
||||||
g_profiler->avg("ActiveObjectMgr: CAO count [#]", m_active_objects.size());
|
size_t count = 0;
|
||||||
|
for (auto &ao_it : m_active_objects.iter()) {
|
||||||
// Same as in server activeobjectmgr.
|
if (!ao_it.second)
|
||||||
std::vector<u16> ids = getAllIds();
|
continue;
|
||||||
|
count++;
|
||||||
for (u16 id : ids) {
|
f(ao_it.second.get());
|
||||||
auto it = m_active_objects.find(id);
|
|
||||||
if (it == m_active_objects.end())
|
|
||||||
continue; // obj was removed
|
|
||||||
f(it->second.get());
|
|
||||||
}
|
}
|
||||||
|
g_profiler->avg("ActiveObjectMgr: CAO count [#]", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActiveObjectMgr::registerObject(std::unique_ptr<ClientActiveObject> obj)
|
bool ActiveObjectMgr::registerObject(std::unique_ptr<ClientActiveObject> obj)
|
||||||
@ -71,7 +68,7 @@ bool ActiveObjectMgr::registerObject(std::unique_ptr<ClientActiveObject> obj)
|
|||||||
}
|
}
|
||||||
infostream << "Client::ActiveObjectMgr::registerObject(): "
|
infostream << "Client::ActiveObjectMgr::registerObject(): "
|
||||||
<< "added (id=" << obj->getId() << ")" << std::endl;
|
<< "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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,16 +76,14 @@ void ActiveObjectMgr::removeObject(u16 id)
|
|||||||
{
|
{
|
||||||
verbosestream << "Client::ActiveObjectMgr::removeObject(): "
|
verbosestream << "Client::ActiveObjectMgr::removeObject(): "
|
||||||
<< "id=" << id << std::endl;
|
<< "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(): "
|
infostream << "Client::ActiveObjectMgr::removeObject(): "
|
||||||
<< "id=" << id << " not found" << std::endl;
|
<< "id=" << id << " not found" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ClientActiveObject> obj = std::move(it->second);
|
|
||||||
m_active_objects.erase(it);
|
|
||||||
|
|
||||||
obj->removeFromScene(true);
|
obj->removeFromScene(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,8 +91,10 @@ void ActiveObjectMgr::getActiveObjects(const v3f &origin, f32 max_d,
|
|||||||
std::vector<DistanceSortedActiveObject> &dest)
|
std::vector<DistanceSortedActiveObject> &dest)
|
||||||
{
|
{
|
||||||
f32 max_d2 = max_d * max_d;
|
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();
|
ClientActiveObject *obj = ao_it.second.get();
|
||||||
|
if (!obj)
|
||||||
|
continue;
|
||||||
|
|
||||||
f32 d2 = (obj->getPosition() - origin).getLengthSQ();
|
f32 d2 = (obj->getPosition() - origin).getLengthSQ();
|
||||||
|
|
||||||
@ -114,8 +111,10 @@ std::vector<DistanceSortedActiveObject> ActiveObjectMgr::getActiveSelectableObje
|
|||||||
f32 max_d = shootline.getLength();
|
f32 max_d = shootline.getLength();
|
||||||
v3f dir = shootline.getVector().normalize();
|
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();
|
ClientActiveObject *obj = ao_it.second.get();
|
||||||
|
if (!obj)
|
||||||
|
continue;
|
||||||
|
|
||||||
aabb3f selection_box;
|
aabb3f selection_box;
|
||||||
if (!obj->getSelectionBox(&selection_box))
|
if (!obj->getSelectionBox(&selection_box))
|
||||||
|
@ -83,8 +83,10 @@ u32 PacketCounter::sum() const
|
|||||||
void PacketCounter::print(std::ostream &o) const
|
void PacketCounter::print(std::ostream &o) const
|
||||||
{
|
{
|
||||||
for (const auto &it : m_packets) {
|
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;
|
: toClientCommandTable[it.first].name;
|
||||||
|
if (!name)
|
||||||
|
name = "?";
|
||||||
o << "cmd " << it.first << " (" << name << ") count "
|
o << "cmd " << it.first << " (" << name << ") count "
|
||||||
<< it.second << std::endl;
|
<< it.second << std::endl;
|
||||||
}
|
}
|
||||||
@ -991,27 +993,25 @@ inline void Client::handleCommand(NetworkPacket* pkt)
|
|||||||
void Client::ProcessData(NetworkPacket *pkt)
|
void Client::ProcessData(NetworkPacket *pkt)
|
||||||
{
|
{
|
||||||
ToClientCommand command = (ToClientCommand) pkt->getCommand();
|
ToClientCommand command = (ToClientCommand) pkt->getCommand();
|
||||||
u32 sender_peer_id = pkt->getPeerId();
|
|
||||||
|
|
||||||
//infostream<<"Client: received command="<<command<<std::endl;
|
m_packetcounter.add(static_cast<u16>(command));
|
||||||
m_packetcounter.add((u16)command);
|
|
||||||
g_profiler->graphAdd("client_received_packets", 1);
|
g_profiler->graphAdd("client_received_packets", 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If this check is removed, be sure to change the queue
|
If this check is removed, be sure to change the queue
|
||||||
system to know the ids
|
system to know the ids
|
||||||
*/
|
*/
|
||||||
if(sender_peer_id != PEER_ID_SERVER) {
|
if (pkt->getPeerId() != PEER_ID_SERVER) {
|
||||||
infostream << "Client::ProcessData(): Discarding data not "
|
infostream << "Client::ProcessData(): Discarding data not "
|
||||||
"coming from server: peer_id=" << sender_peer_id << " command=" << pkt->getCommand()
|
"coming from server: peer_id=" << static_cast<int>(pkt->getPeerId())
|
||||||
<< std::endl;
|
<< " command=" << static_cast<unsigned>(command) << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command must be handled into ToClientCommandHandler
|
// Command must be handled into ToClientCommandHandler
|
||||||
if (command >= TOCLIENT_NUM_MSG_TYPES) {
|
if (command >= TOCLIENT_NUM_MSG_TYPES) {
|
||||||
infostream << "Client: Ignoring unknown command "
|
infostream << "Client: Ignoring unknown command "
|
||||||
<< command << std::endl;
|
<< static_cast<unsigned>(command) << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1027,24 +1027,19 @@ void Client::ProcessData(NetworkPacket *pkt)
|
|||||||
|
|
||||||
if (m_server_ser_ver == SER_FMT_VER_INVALID) {
|
if (m_server_ser_ver == SER_FMT_VER_INVALID) {
|
||||||
infostream << "Client: Server serialization"
|
infostream << "Client: Server serialization"
|
||||||
" format invalid or not initialized."
|
" format invalid. Skipping incoming command "
|
||||||
" Skipping incoming command=" << command << std::endl;
|
<< static_cast<unsigned>(command) << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Handle runtime commands
|
|
||||||
*/
|
|
||||||
|
|
||||||
handleCommand(pkt);
|
handleCommand(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Send(NetworkPacket* pkt)
|
void Client::Send(NetworkPacket* pkt)
|
||||||
{
|
{
|
||||||
m_con->Send(PEER_ID_SERVER,
|
auto &scf = serverCommandFactoryTable[pkt->getCommand()];
|
||||||
serverCommandFactoryTable[pkt->getCommand()].channel,
|
FATAL_ERROR_IF(!scf.name, "packet type missing in table");
|
||||||
pkt,
|
m_con->Send(PEER_ID_SERVER, scf.channel, pkt, scf.reliable);
|
||||||
serverCommandFactoryTable[pkt->getCommand()].reliable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will fill up 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 bytes
|
// 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
|
class CAOShaderConstantSetter : public IShaderConstantSetter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CAOShaderConstantSetter():
|
|
||||||
m_emissive_color_setting("emissiveColor")
|
|
||||||
{}
|
|
||||||
|
|
||||||
~CAOShaderConstantSetter() override = default;
|
~CAOShaderConstantSetter() override = default;
|
||||||
|
|
||||||
void onSetConstants(video::IMaterialRendererServices *services) override
|
void onSetConstants(video::IMaterialRendererServices *services) override
|
||||||
@ -74,7 +70,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
video::SColor m_emissive_color;
|
video::SColor m_emissive_color;
|
||||||
CachedPixelShaderSetting<float, 4> m_emissive_color_setting;
|
CachedPixelShaderSetting<float, 4>
|
||||||
|
m_emissive_color_setting{"emissiveColor"};
|
||||||
};
|
};
|
||||||
|
|
||||||
class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory
|
class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory
|
||||||
@ -492,7 +489,8 @@ ClientEnvEvent ClientEnvironment::getClientEnvEvent()
|
|||||||
|
|
||||||
void ClientEnvironment::getSelectedActiveObjects(
|
void ClientEnvironment::getSelectedActiveObjects(
|
||||||
const core::line3d<f32> &shootline_on_map,
|
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);
|
auto allObjects = m_ao_manager.getActiveSelectableObjects(shootline_on_map);
|
||||||
const v3f line_vector = shootline_on_map.getVector();
|
const v3f line_vector = shootline_on_map.getVector();
|
||||||
@ -519,9 +517,23 @@ void ClientEnvironment::getSelectedActiveObjects(
|
|||||||
current_raw_normal = current_normal;
|
current_raw_normal = current_normal;
|
||||||
}
|
}
|
||||||
if (collision) {
|
if (collision) {
|
||||||
|
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();
|
current_intersection += obj->getPosition();
|
||||||
objects.emplace_back(obj->getId(), current_intersection, current_normal, current_raw_normal,
|
objects.emplace_back(obj->getId(), current_intersection, current_normal, current_raw_normal,
|
||||||
(current_intersection - shootline_on_map.start).getLengthSQ());
|
(current_intersection - shootline_on_map.start).getLengthSQ(), pointable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,8 @@ public:
|
|||||||
|
|
||||||
virtual void getSelectedActiveObjects(
|
virtual void getSelectedActiveObjects(
|
||||||
const core::line3d<f32> &shootline_on_map,
|
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; }
|
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 "chat.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "profiler.h"
|
#include "profiler.h"
|
||||||
#include "serverlist.h"
|
|
||||||
#include "gui/guiEngine.h"
|
#include "gui/guiEngine.h"
|
||||||
#include "fontengine.h"
|
#include "fontengine.h"
|
||||||
#include "clientlauncher.h"
|
#include "clientlauncher.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "renderingengine.h"
|
#include "renderingengine.h"
|
||||||
#include "network/networkexceptions.h"
|
#include "network/networkexceptions.h"
|
||||||
|
#include <IGUISpriteBank.h>
|
||||||
|
#include <ICameraSceneNode.h>
|
||||||
|
|
||||||
#if USE_SOUND
|
#if USE_SOUND
|
||||||
#include "sound/sound_openal.h"
|
#include "sound/sound_openal.h"
|
||||||
@ -106,13 +107,6 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
|||||||
return false;
|
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) {
|
if (m_rendering_engine->get_video_driver() == NULL) {
|
||||||
errorstream << "Could not initialize video driver." << std::endl;
|
errorstream << "Could not initialize video driver." << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -213,7 +207,8 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
|||||||
m_rendering_engine->get_raw_device()->
|
m_rendering_engine->get_raw_device()->
|
||||||
setWindowCaption((utf8_to_wide(PROJECT_NAME_C) +
|
setWindowCaption((utf8_to_wide(PROJECT_NAME_C) +
|
||||||
L" " + utf8_to_wide(g_version_hash) +
|
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
|
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
|
// Break out of menu-game loop to shut down cleanly
|
||||||
if (!m_rendering_engine->run() || *kill) {
|
if (!m_rendering_engine->run() || *kill)
|
||||||
if (!g_settings_path.empty())
|
|
||||||
g_settings->updateConfigFile(g_settings_path.c_str());
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
m_rendering_engine->get_video_driver()->setTextureCreationFlag(
|
m_rendering_engine->get_video_driver()->setTextureCreationFlag(
|
||||||
video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
|
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?)");
|
error_message = gettext("Connection error (timed out?)");
|
||||||
errorstream << error_message << std::endl;
|
errorstream << error_message << std::endl;
|
||||||
}
|
}
|
||||||
|
catch (ShaderException &e) {
|
||||||
|
error_message = e.what();
|
||||||
|
errorstream << error_message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
catch (std::exception &e) {
|
catch (std::exception &e) {
|
||||||
@ -292,6 +288,16 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
|||||||
receiver->m_touchscreengui = NULL;
|
receiver->m_touchscreengui = NULL;
|
||||||
#endif
|
#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 no main menu, show error and exit
|
||||||
if (skip_main_menu) {
|
if (skip_main_menu) {
|
||||||
if (!error_message.empty()) {
|
if (!error_message.empty()) {
|
||||||
@ -380,7 +386,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
|
|||||||
if (cmd_args.exists("password-file")) {
|
if (cmd_args.exists("password-file")) {
|
||||||
std::ifstream passfile(cmd_args.get("password-file"));
|
std::ifstream passfile(cmd_args.get("password-file"));
|
||||||
if (passfile.good()) {
|
if (passfile.good()) {
|
||||||
getline(passfile, start_data.password);
|
std::getline(passfile, start_data.password);
|
||||||
} else {
|
} else {
|
||||||
error_message = gettext("Provided password file "
|
error_message = gettext("Provided password file "
|
||||||
"failed to open: ")
|
"failed to open: ")
|
||||||
@ -437,8 +443,6 @@ bool ClientLauncher::launch_game(std::string &error_message,
|
|||||||
|
|
||||||
int world_index = menudata.selected_world;
|
int world_index = menudata.selected_world;
|
||||||
if (world_index >= 0 && world_index < (int)worldspecs.size()) {
|
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];
|
start_data.world_spec = worldspecs[world_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,15 +514,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (porting::signal_handler_killstatus())
|
|
||||||
return true;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start_data.world_path = start_data.world_spec.path;
|
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;
|
infostream << "Waited for other menus" << std::endl;
|
||||||
|
|
||||||
#ifndef ANDROID
|
auto *cur_control = m_rendering_engine->get_raw_device()->getCursorControl();
|
||||||
|
if (cur_control) {
|
||||||
// Cursor can be non-visible when coming from the game
|
// Cursor can be non-visible when coming from the game
|
||||||
m_rendering_engine->get_raw_device()->getCursorControl()->setVisible(true);
|
cur_control->setVisible(true);
|
||||||
|
|
||||||
// Set absolute mouse mode
|
// Set absolute mouse mode
|
||||||
m_rendering_engine->get_raw_device()->getCursorControl()->setRelativeMode(false);
|
cur_control->setRelativeMode(false);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
/* show main menu */
|
/* show main menu */
|
||||||
GUIEngine mymenu(&input->joystick, guiroot, m_rendering_engine, &g_menumgr, menudata, *kill);
|
GUIEngine mymenu(&input->joystick, guiroot, m_rendering_engine, &g_menumgr, menudata, *kill);
|
||||||
|
|
||||||
/* leave scene manager in a clean state */
|
/* leave scene manager in a clean state */
|
||||||
m_rendering_engine->get_scene_manager()->clear();
|
m_rendering_engine->get_scene_manager()->clear();
|
||||||
}
|
|
||||||
|
|
||||||
void ClientLauncher::speed_tests()
|
/* Save the settings when leaving the mainmenu.
|
||||||
{
|
* This makes sure that setting changes made in the mainmenu are persisted
|
||||||
// volatile to avoid some potential compiler optimisations
|
* even in case of a later unclean exit from the game.
|
||||||
volatile static s16 temp16;
|
* This is especially useful on Android because closing the app from the
|
||||||
volatile static f32 tempf;
|
* "Recents screen" results in an unclean exit.
|
||||||
// Silence compiler warning
|
* Caveat: This means that the settings are saved twice when exiting Minetest.
|
||||||
(void)temp16;
|
*/
|
||||||
static v3f tempv3f1;
|
if (!g_settings_path.empty())
|
||||||
static v3f tempv3f2;
|
g_settings->updateConfigFile(g_settings_path.c_str());
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,6 @@ private:
|
|||||||
|
|
||||||
void main_menu(MainMenuData *menudata);
|
void main_menu(MainMenuData *menudata);
|
||||||
|
|
||||||
void speed_tests();
|
|
||||||
|
|
||||||
bool skip_main_menu = false;
|
bool skip_main_menu = false;
|
||||||
bool random_input = false;
|
bool random_input = false;
|
||||||
RenderingEngine *m_rendering_engine = nullptr;
|
RenderingEngine *m_rendering_engine = nullptr;
|
||||||
|
@ -329,7 +329,7 @@ void ClientMap::updateDrawList()
|
|||||||
MapBlockVect sectorblocks;
|
MapBlockVect sectorblocks;
|
||||||
|
|
||||||
for (auto §or_it : m_sectors) {
|
for (auto §or_it : m_sectors) {
|
||||||
MapSector *sector = sector_it.second;
|
const MapSector *sector = sector_it.second;
|
||||||
v2s16 sp = sector->getPos();
|
v2s16 sp = sector->getPos();
|
||||||
|
|
||||||
blocks_loaded += sector->size();
|
blocks_loaded += sector->size();
|
||||||
@ -339,18 +339,16 @@ void ClientMap::updateDrawList()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sectorblocks.clear();
|
|
||||||
sector->getBlocks(sectorblocks);
|
|
||||||
|
|
||||||
// Loop through blocks in sector
|
// Loop through blocks in sector
|
||||||
for (MapBlock *block : sectorblocks) {
|
for (const auto &entry : sector->getBlocks()) {
|
||||||
|
MapBlock *block = entry.second.get();
|
||||||
MapBlockMesh *mesh = block->mesh;
|
MapBlockMesh *mesh = block->mesh;
|
||||||
|
|
||||||
// Calculate the coordinates for range and frustum culling
|
// Calculate the coordinates for range and frustum culling
|
||||||
v3f mesh_sphere_center;
|
v3f mesh_sphere_center;
|
||||||
f32 mesh_sphere_radius;
|
f32 mesh_sphere_radius;
|
||||||
|
|
||||||
v3s16 block_pos_nodes = block->getPos() * MAP_BLOCKSIZE;
|
v3s16 block_pos_nodes = block->getPosRelative();
|
||||||
|
|
||||||
if (mesh) {
|
if (mesh) {
|
||||||
mesh_sphere_center = intToFloat(block_pos_nodes, BS)
|
mesh_sphere_center = intToFloat(block_pos_nodes, BS)
|
||||||
@ -649,7 +647,7 @@ void ClientMap::touchMapBlocks()
|
|||||||
u32 blocks_in_range_with_mesh = 0;
|
u32 blocks_in_range_with_mesh = 0;
|
||||||
|
|
||||||
for (const auto §or_it : m_sectors) {
|
for (const auto §or_it : m_sectors) {
|
||||||
MapSector *sector = sector_it.second;
|
const MapSector *sector = sector_it.second;
|
||||||
v2s16 sp = sector->getPos();
|
v2s16 sp = sector->getPos();
|
||||||
|
|
||||||
blocks_loaded += sector->size();
|
blocks_loaded += sector->size();
|
||||||
@ -659,21 +657,19 @@ void ClientMap::touchMapBlocks()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapBlockVect sectorblocks;
|
|
||||||
sector->getBlocks(sectorblocks);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Loop through blocks in sector
|
Loop through blocks in sector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (MapBlock *block : sectorblocks) {
|
for (const auto &entry : sector->getBlocks()) {
|
||||||
|
MapBlock *block = entry.second.get();
|
||||||
MapBlockMesh *mesh = block->mesh;
|
MapBlockMesh *mesh = block->mesh;
|
||||||
|
|
||||||
// Calculate the coordinates for range and frustum culling
|
// Calculate the coordinates for range and frustum culling
|
||||||
v3f mesh_sphere_center;
|
v3f mesh_sphere_center;
|
||||||
f32 mesh_sphere_radius;
|
f32 mesh_sphere_radius;
|
||||||
|
|
||||||
v3s16 block_pos_nodes = block->getPos() * MAP_BLOCKSIZE;
|
v3s16 block_pos_nodes = block->getPosRelative();
|
||||||
|
|
||||||
if (mesh) {
|
if (mesh) {
|
||||||
mesh_sphere_center = intToFloat(block_pos_nodes, BS)
|
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);
|
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) {
|
for (auto &i : m_drawlist_shadow) {
|
||||||
MapBlock *block = i.second;
|
MapBlock *block = i.second;
|
||||||
block->refDrop();
|
block->refDrop();
|
||||||
@ -1266,25 +1257,23 @@ void ClientMap::updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir,
|
|||||||
u32 blocks_in_range_with_mesh = 0;
|
u32 blocks_in_range_with_mesh = 0;
|
||||||
|
|
||||||
for (auto §or_it : m_sectors) {
|
for (auto §or_it : m_sectors) {
|
||||||
MapSector *sector = sector_it.second;
|
const MapSector *sector = sector_it.second;
|
||||||
if (!sector)
|
if (!sector)
|
||||||
continue;
|
continue;
|
||||||
blocks_loaded += sector->size();
|
blocks_loaded += sector->size();
|
||||||
|
|
||||||
MapBlockVect sectorblocks;
|
|
||||||
sector->getBlocks(sectorblocks);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Loop through blocks in sector
|
Loop through blocks in sector
|
||||||
*/
|
*/
|
||||||
for (MapBlock *block : sectorblocks) {
|
for (const auto &entry : sector->getBlocks()) {
|
||||||
|
MapBlock *block = entry.second.get();
|
||||||
MapBlockMesh *mesh = block->mesh;
|
MapBlockMesh *mesh = block->mesh;
|
||||||
if (!mesh) {
|
if (!mesh) {
|
||||||
// Ignore if mesh doesn't exist
|
// Ignore if mesh doesn't exist
|
||||||
continue;
|
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);
|
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()))
|
if (projection.getDistanceFrom(block_pos) > (radius + mesh->getBoundingRadius()))
|
||||||
continue;
|
continue;
|
||||||
|
@ -165,9 +165,11 @@ void Clouds::render()
|
|||||||
driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
||||||
fog_pixelfog, fog_rangefog);
|
fog_pixelfog, fog_rangefog);
|
||||||
|
|
||||||
// Set our own fog
|
// 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,
|
driver->setFog(fog_color, fog_type, cloud_full_radius * 0.5,
|
||||||
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
|
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
|
||||||
|
}
|
||||||
|
|
||||||
// Read noise
|
// Read noise
|
||||||
|
|
||||||
|
@ -411,8 +411,7 @@ GenericCAO::~GenericCAO()
|
|||||||
|
|
||||||
bool GenericCAO::getSelectionBox(aabb3f *toset) const
|
bool GenericCAO::getSelectionBox(aabb3f *toset) const
|
||||||
{
|
{
|
||||||
if (!m_prop.is_visible || !m_is_visible || m_is_local_player
|
if (!m_prop.is_visible || !m_is_visible || m_is_local_player) {
|
||||||
|| !m_prop.pointable) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*toset = m_selection_box;
|
*toset = m_selection_box;
|
||||||
@ -620,6 +619,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
|||||||
|
|
||||||
infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl;
|
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) {
|
if (m_enable_shaders) {
|
||||||
IShaderSource *shader_source = m_client->getShaderSource();
|
IShaderSource *shader_source = m_client->getShaderSource();
|
||||||
MaterialType material_type;
|
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);
|
u32 shader_id = shader_source->getShader("object_shader", material_type, NDT_NORMAL);
|
||||||
m_material_type = shader_source->getShaderInfo(shader_id).material;
|
m_material_type = shader_source->getShaderInfo(shader_id).material;
|
||||||
} else {
|
} else {
|
||||||
m_material_type = (m_prop.use_texture_alpha) ?
|
if (m_prop.use_texture_alpha) {
|
||||||
video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
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] {
|
auto grabMatrixNode = [this] {
|
||||||
@ -1341,7 +1346,7 @@ void GenericCAO::updateTextures(std::string mod)
|
|||||||
|
|
||||||
video::SMaterial &material = m_spritenode->getMaterial(0);
|
video::SMaterial &material = m_spritenode->getMaterial(0);
|
||||||
material.MaterialType = m_material_type;
|
material.MaterialType = m_material_type;
|
||||||
material.MaterialTypeParam = 0.5f;
|
material.MaterialTypeParam = m_material_type_param;
|
||||||
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
||||||
|
|
||||||
// This allows setting per-material colors. However, until a real lighting
|
// 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
|
// Set material flags and texture
|
||||||
video::SMaterial &material = m_animated_meshnode->getMaterial(i);
|
video::SMaterial &material = m_animated_meshnode->getMaterial(i);
|
||||||
material.MaterialType = m_material_type;
|
material.MaterialType = m_material_type;
|
||||||
material.MaterialTypeParam = 0.5f;
|
material.MaterialTypeParam = m_material_type_param;
|
||||||
material.TextureLayers[0].Texture = texture;
|
material.TextureLayers[0].Texture = texture;
|
||||||
material.Lighting = true;
|
material.Lighting = true;
|
||||||
material.BackfaceCulling = m_prop.backface_culling;
|
material.BackfaceCulling = m_prop.backface_culling;
|
||||||
@ -1421,7 +1426,7 @@ void GenericCAO::updateTextures(std::string mod)
|
|||||||
// Set material flags and texture
|
// Set material flags and texture
|
||||||
video::SMaterial &material = m_meshnode->getMaterial(i);
|
video::SMaterial &material = m_meshnode->getMaterial(i);
|
||||||
material.MaterialType = m_material_type;
|
material.MaterialType = m_material_type;
|
||||||
material.MaterialTypeParam = 0.5f;
|
material.MaterialTypeParam = m_material_type_param;
|
||||||
material.Lighting = false;
|
material.Lighting = false;
|
||||||
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
|
||||||
material.getTextureMatrix(0).makeIdentity();
|
material.getTextureMatrix(0).makeIdentity();
|
||||||
|
@ -130,6 +130,7 @@ private:
|
|||||||
bool m_is_visible = false;
|
bool m_is_visible = false;
|
||||||
// Material
|
// Material
|
||||||
video::E_MATERIAL_TYPE m_material_type;
|
video::E_MATERIAL_TYPE m_material_type;
|
||||||
|
f32 m_material_type_param;
|
||||||
// Settings
|
// Settings
|
||||||
bool m_enable_shaders = false;
|
bool m_enable_shaders = false;
|
||||||
|
|
||||||
@ -173,6 +174,8 @@ public:
|
|||||||
|
|
||||||
inline const ObjectProperties &getProperties() const { return m_prop; }
|
inline const ObjectProperties &getProperties() const { return m_prop; }
|
||||||
|
|
||||||
|
inline const std::string &getName() const { return m_name; }
|
||||||
|
|
||||||
scene::ISceneNode *getSceneNode() const override;
|
scene::ISceneNode *getSceneNode() const override;
|
||||||
|
|
||||||
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const override;
|
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const override;
|
||||||
@ -207,6 +210,11 @@ public:
|
|||||||
return m_is_local_player;
|
return m_is_local_player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isPlayer() const
|
||||||
|
{
|
||||||
|
return m_is_player;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool isVisible() const
|
inline bool isVisible() const
|
||||||
{
|
{
|
||||||
return m_is_visible;
|
return m_is_visible;
|
||||||
|
@ -1008,7 +1008,9 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
|||||||
switch (wall) {
|
switch (wall) {
|
||||||
case DWM_YP: tileindex = 1; break; // ceiling
|
case DWM_YP: tileindex = 1; break; // ceiling
|
||||||
case DWM_YN: tileindex = 0; break; // floor
|
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);
|
useTile(tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||||
|
|
||||||
@ -1044,6 +1046,17 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
|||||||
case DWM_ZN:
|
case DWM_ZN:
|
||||||
vertex.X += -size + BS/2;
|
vertex.X += -size + BS/2;
|
||||||
vertex.rotateXZBy(-90);
|
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);
|
drawQuad(vertices);
|
||||||
@ -1077,6 +1090,10 @@ void MapblockMeshGenerator::drawSignlikeNode()
|
|||||||
vertex.rotateXZBy( 90); break;
|
vertex.rotateXZBy( 90); break;
|
||||||
case DWM_ZN:
|
case DWM_ZN:
|
||||||
vertex.rotateXZBy(-90); break;
|
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);
|
drawQuad(vertices);
|
||||||
|
@ -74,6 +74,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "script/scripting_client.h"
|
#include "script/scripting_client.h"
|
||||||
#include "hud.h"
|
#include "hud.h"
|
||||||
#include "clientdynamicinfo.h"
|
#include "clientdynamicinfo.h"
|
||||||
|
#include <IAnimatedMeshSceneNode.h>
|
||||||
|
|
||||||
#if USE_SOUND
|
#if USE_SOUND
|
||||||
#include "client/sound/sound_openal.h"
|
#include "client/sound/sound_openal.h"
|
||||||
@ -373,43 +374,55 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
|
|||||||
bool *m_force_fog_off;
|
bool *m_force_fog_off;
|
||||||
f32 *m_fog_range;
|
f32 *m_fog_range;
|
||||||
bool m_fog_enabled;
|
bool m_fog_enabled;
|
||||||
CachedPixelShaderSetting<float, 4> m_sky_bg_color;
|
CachedPixelShaderSetting<float, 4> m_fog_color{"fogColor"};
|
||||||
CachedPixelShaderSetting<float> m_fog_distance;
|
CachedPixelShaderSetting<float> m_fog_distance{"fogDistance"};
|
||||||
CachedPixelShaderSetting<float> m_fog_shading_parameter;
|
CachedPixelShaderSetting<float>
|
||||||
CachedVertexShaderSetting<float> m_animation_timer_vertex;
|
m_fog_shading_parameter{"fogShadingParameter"};
|
||||||
CachedPixelShaderSetting<float> m_animation_timer_pixel;
|
CachedVertexShaderSetting<float> m_animation_timer_vertex{"animationTimer"};
|
||||||
CachedVertexShaderSetting<float> m_animation_timer_delta_vertex;
|
CachedPixelShaderSetting<float> m_animation_timer_pixel{"animationTimer"};
|
||||||
CachedPixelShaderSetting<float> m_animation_timer_delta_pixel;
|
CachedVertexShaderSetting<float>
|
||||||
CachedPixelShaderSetting<float, 3> m_day_light;
|
m_animation_timer_delta_vertex{"animationTimerDelta"};
|
||||||
CachedPixelShaderSetting<float, 4> m_star_color;
|
CachedPixelShaderSetting<float>
|
||||||
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
|
m_animation_timer_delta_pixel{"animationTimerDelta"};
|
||||||
CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
|
CachedPixelShaderSetting<float, 3> m_day_light{"dayLight"};
|
||||||
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
|
CachedPixelShaderSetting<float, 4> m_star_color{"starColor"};
|
||||||
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
|
CachedPixelShaderSetting<float, 3> m_eye_position_pixel{"eyePosition"};
|
||||||
CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
|
CachedVertexShaderSetting<float, 3> m_eye_position_vertex{"eyePosition"};
|
||||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture0;
|
CachedPixelShaderSetting<float, 3> m_minimap_yaw{"yawVec"};
|
||||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture1;
|
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel{"cameraOffset"};
|
||||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture2;
|
CachedPixelShaderSetting<float, 3> m_camera_offset_vertex{"cameraOffset"};
|
||||||
CachedPixelShaderSetting<SamplerLayer_t> m_texture3;
|
CachedPixelShaderSetting<SamplerLayer_t> m_texture0{"texture0"};
|
||||||
CachedVertexShaderSetting<float, 2> m_texel_size0_vertex;
|
CachedPixelShaderSetting<SamplerLayer_t> m_texture1{"texture1"};
|
||||||
CachedPixelShaderSetting<float, 2> m_texel_size0_pixel;
|
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;
|
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;
|
float m_user_exposure_compensation;
|
||||||
bool m_bloom_enabled;
|
bool m_bloom_enabled;
|
||||||
CachedPixelShaderSetting<float> m_bloom_intensity_pixel;
|
CachedPixelShaderSetting<float> m_bloom_intensity_pixel{"bloomIntensity"};
|
||||||
float m_bloom_intensity;
|
float m_bloom_intensity;
|
||||||
CachedPixelShaderSetting<float> m_bloom_strength_pixel;
|
CachedPixelShaderSetting<float> m_bloom_strength_pixel{"bloomStrength"};
|
||||||
float m_bloom_strength;
|
float m_bloom_strength;
|
||||||
CachedPixelShaderSetting<float> m_bloom_radius_pixel;
|
CachedPixelShaderSetting<float> m_bloom_radius_pixel{"bloomRadius"};
|
||||||
float m_bloom_radius;
|
float m_bloom_radius;
|
||||||
CachedPixelShaderSetting<float> m_saturation_pixel;
|
CachedPixelShaderSetting<float> m_saturation_pixel{"saturation"};
|
||||||
bool m_volumetric_light_enabled;
|
bool m_volumetric_light_enabled;
|
||||||
CachedPixelShaderSetting<float, 3> m_sun_position_pixel;
|
CachedPixelShaderSetting<float, 3>
|
||||||
CachedPixelShaderSetting<float> m_sun_brightness_pixel;
|
m_sun_position_pixel{"sunPositionScreen"};
|
||||||
CachedPixelShaderSetting<float, 3> m_moon_position_pixel;
|
CachedPixelShaderSetting<float> m_sun_brightness_pixel{"sunBrightness"};
|
||||||
CachedPixelShaderSetting<float> m_moon_brightness_pixel;
|
CachedPixelShaderSetting<float, 3>
|
||||||
CachedPixelShaderSetting<float> m_volumetric_light_strength_pixel;
|
m_moon_position_pixel{"moonPositionScreen"};
|
||||||
|
CachedPixelShaderSetting<float> m_moon_brightness_pixel{"moonBrightness"};
|
||||||
|
CachedPixelShaderSetting<float>
|
||||||
|
m_volumetric_light_strength_pixel{"volumetricLightStrength"};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void onSettingsChange(const std::string &name)
|
void onSettingsChange(const std::string &name)
|
||||||
@ -438,41 +451,7 @@ public:
|
|||||||
m_sky(sky),
|
m_sky(sky),
|
||||||
m_client(client),
|
m_client(client),
|
||||||
m_force_fog_off(force_fog_off),
|
m_force_fog_off(force_fog_off),
|
||||||
m_fog_range(fog_range),
|
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")
|
|
||||||
{
|
{
|
||||||
g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
|
g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
|
||||||
g_settings->registerChangedCallback("exposure_compensation", settingsCallback, this);
|
g_settings->registerChangedCallback("exposure_compensation", settingsCallback, this);
|
||||||
@ -496,20 +475,13 @@ public:
|
|||||||
|
|
||||||
void onSetConstants(video::IMaterialRendererServices *services) override
|
void onSetConstants(video::IMaterialRendererServices *services) override
|
||||||
{
|
{
|
||||||
// Background color
|
video::SColorf fogcolorf(m_sky->getFogColor());
|
||||||
video::SColor bgcolor = m_sky->getBgColor();
|
float fogcolorfa[4] = {
|
||||||
video::SColorf bgcolorf(bgcolor);
|
fogcolorf.r, fogcolorf.g, fogcolorf.b, fogcolorf.a,
|
||||||
float bgcolorfa[4] = {
|
|
||||||
bgcolorf.r,
|
|
||||||
bgcolorf.g,
|
|
||||||
bgcolorf.b,
|
|
||||||
bgcolorf.a,
|
|
||||||
};
|
};
|
||||||
m_sky_bg_color.set(bgcolorfa, services);
|
m_fog_color.set(fogcolorfa, services);
|
||||||
|
|
||||||
// Fog distance
|
|
||||||
float fog_distance = 10000 * BS;
|
float fog_distance = 10000 * BS;
|
||||||
|
|
||||||
if (m_fog_enabled && !*m_force_fog_off)
|
if (m_fog_enabled && !*m_force_fog_off)
|
||||||
fog_distance = *m_fog_range;
|
fog_distance = *m_fog_range;
|
||||||
|
|
||||||
@ -862,6 +834,7 @@ protected:
|
|||||||
* the camera position. This also gives the maximal distance
|
* the camera position. This also gives the maximal distance
|
||||||
* of the search.
|
* of the search.
|
||||||
* @param[in] liquids_pointable if false, liquids are ignored
|
* @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] look_for_object if false, objects are ignored
|
||||||
* @param[in] camera_offset offset of the camera
|
* @param[in] camera_offset offset of the camera
|
||||||
* @param[out] selected_object the selected object or
|
* @param[out] selected_object the selected object or
|
||||||
@ -869,6 +842,7 @@ protected:
|
|||||||
*/
|
*/
|
||||||
PointedThing updatePointedThing(
|
PointedThing updatePointedThing(
|
||||||
const core::line3d<f32> &shootline, bool liquids_pointable,
|
const core::line3d<f32> &shootline, bool liquids_pointable,
|
||||||
|
const std::optional<Pointabilities> &pointabilities,
|
||||||
bool look_for_object, const v3s16 &camera_offset);
|
bool look_for_object, const v3s16 &camera_offset);
|
||||||
void handlePointingAtNothing(const ItemStack &playerItem);
|
void handlePointingAtNothing(const ItemStack &playerItem);
|
||||||
void handlePointingAtNode(const PointedThing &pointed,
|
void handlePointingAtNode(const PointedThing &pointed,
|
||||||
@ -1002,7 +976,6 @@ private:
|
|||||||
bool *kill;
|
bool *kill;
|
||||||
std::string *error_message;
|
std::string *error_message;
|
||||||
bool *reconnect_requested;
|
bool *reconnect_requested;
|
||||||
scene::ISceneNode *skybox;
|
|
||||||
PausedNodesList paused_animated_nodes;
|
PausedNodesList paused_animated_nodes;
|
||||||
|
|
||||||
bool simple_singleplayer_mode;
|
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);
|
sky = new Sky(-1, m_rendering_engine, texture_src, shader_src);
|
||||||
scsf->setSky(sky);
|
scsf->setSky(sky);
|
||||||
skybox = NULL; // This is used/set later on in the main run loop
|
|
||||||
|
|
||||||
/* Pre-calculated values
|
/* Pre-calculated values
|
||||||
*/
|
*/
|
||||||
@ -1771,7 +1743,7 @@ bool Game::getServerContent(bool *aborted)
|
|||||||
// End condition
|
// End condition
|
||||||
if (client->mediaReceived() && client->itemdefReceived() &&
|
if (client->mediaReceived() && client->itemdefReceived() &&
|
||||||
client->nodedefReceived()) {
|
client->nodedefReceived()) {
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error conditions
|
// 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)
|
void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
|
||||||
{
|
{
|
||||||
#ifndef __ANDROID__
|
auto *cur_control = device->getCursorControl();
|
||||||
if (isMenuActive())
|
|
||||||
device->getCursorControl()->setRelativeMode(false);
|
/* With CIrrDeviceSDL on Linux and Windows, enabling relative mouse mode
|
||||||
else
|
somehow results in simulated mouse events being generated from touch events,
|
||||||
device->getCursorControl()->setRelativeMode(true);
|
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
|
#endif
|
||||||
|
|
||||||
if ((device->isWindowActive() && device->isWindowFocused()
|
if ((device->isWindowActive() && device->isWindowFocused()
|
||||||
&& !isMenuActive()) || input->isRandom()) {
|
&& !isMenuActive()) || input->isRandom()) {
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
if (cur_control && !input->isRandom()) {
|
||||||
if (!input->isRandom()) {
|
|
||||||
// Mac OSX gets upset if this is set every frame
|
// Mac OSX gets upset if this is set every frame
|
||||||
if (device->getCursorControl()->isVisible())
|
if (cur_control->isVisible())
|
||||||
device->getCursorControl()->setVisible(false);
|
cur_control->setVisible(false);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m_first_loop_after_window_activation) {
|
if (m_first_loop_after_window_activation) {
|
||||||
m_first_loop_after_window_activation = false;
|
m_first_loop_after_window_activation = false;
|
||||||
@ -2663,15 +2641,11 @@ void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
#ifndef ANDROID
|
|
||||||
// Mac OSX gets upset if this is set every frame
|
// Mac OSX gets upset if this is set every frame
|
||||||
if (!device->getCursorControl()->isVisible())
|
if (cur_control && !cur_control->isVisible())
|
||||||
device->getCursorControl()->setVisible(true);
|
cur_control->setVisible(true);
|
||||||
#endif
|
|
||||||
|
|
||||||
m_first_loop_after_window_activation = 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_TEXT2, text2, sdata);
|
||||||
|
|
||||||
CASE_SET(HUD_STAT_STYLE, style, data);
|
CASE_SET(HUD_STAT_STYLE, style, data);
|
||||||
|
|
||||||
|
case HudElementStat_END:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef CASE_SET
|
#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.
|
// Whether clouds are visible in front of a custom skybox.
|
||||||
sky->setCloudsEnabled(event->set_sky->clouds);
|
sky->setCloudsEnabled(event->set_sky->clouds);
|
||||||
|
|
||||||
if (skybox) {
|
|
||||||
skybox->remove();
|
|
||||||
skybox = NULL;
|
|
||||||
}
|
|
||||||
// Clear the old textures out in case we switch rendering type.
|
// Clear the old textures out in case we switch rendering type.
|
||||||
sky->clearSkyboxTextures();
|
sky->clearSkyboxTextures();
|
||||||
// Handle according to type
|
// Handle according to type
|
||||||
@ -3124,6 +3097,8 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam)
|
|||||||
else
|
else
|
||||||
sky->setFogStart(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
|
sky->setFogStart(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
|
||||||
|
|
||||||
|
sky->setFogColor(event->set_sky->fog_color);
|
||||||
|
|
||||||
delete event->set_sky;
|
delete event->set_sky;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3361,12 +3336,18 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
|
|||||||
|
|
||||||
PointedThing pointed = updatePointedThing(shootline,
|
PointedThing pointed = updatePointedThing(shootline,
|
||||||
selected_def.liquids_pointable,
|
selected_def.liquids_pointable,
|
||||||
|
selected_def.pointabilities,
|
||||||
!runData.btn_down_for_dig,
|
!runData.btn_down_for_dig,
|
||||||
camera_offset);
|
camera_offset);
|
||||||
|
|
||||||
if (pointed != runData.pointed_old)
|
if (pointed != runData.pointed_old)
|
||||||
infostream << "Pointing at " << pointed.dump() << std::endl;
|
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,
|
// 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
|
// but the halo rendering code is already inefficient so there's no point in optimizing it here
|
||||||
hud->updateSelectionMesh(camera_offset);
|
hud->updateSelectionMesh(camera_offset);
|
||||||
@ -3467,6 +3448,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
|
|||||||
PointedThing Game::updatePointedThing(
|
PointedThing Game::updatePointedThing(
|
||||||
const core::line3d<f32> &shootline,
|
const core::line3d<f32> &shootline,
|
||||||
bool liquids_pointable,
|
bool liquids_pointable,
|
||||||
|
const std::optional<Pointabilities> &pointabilities,
|
||||||
bool look_for_object,
|
bool look_for_object,
|
||||||
const v3s16 &camera_offset)
|
const v3s16 &camera_offset)
|
||||||
{
|
{
|
||||||
@ -3483,7 +3465,7 @@ PointedThing Game::updatePointedThing(
|
|||||||
runData.selected_object = NULL;
|
runData.selected_object = NULL;
|
||||||
hud->pointing_at_object = false;
|
hud->pointing_at_object = false;
|
||||||
|
|
||||||
RaycastState s(shootline, look_for_object, liquids_pointable);
|
RaycastState s(shootline, look_for_object, liquids_pointable, pointabilities);
|
||||||
PointedThing result;
|
PointedThing result;
|
||||||
env.continueRaycast(&s, &result);
|
env.continueRaycast(&s, &result);
|
||||||
if (result.type == POINTEDTHING_OBJECT) {
|
if (result.type == POINTEDTHING_OBJECT) {
|
||||||
@ -3725,7 +3707,36 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
|
|||||||
v3s16 dir = nodepos - neighborpos;
|
v3s16 dir = nodepos - neighborpos;
|
||||||
|
|
||||||
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
|
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)) {
|
} else if (abs(dir.X) > abs(dir.Z)) {
|
||||||
predicted_node.setParam2(dir.X < 0 ? 3 : 2);
|
predicted_node.setParam2(dir.X < 0 ? 3 : 2);
|
||||||
} else {
|
} 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());
|
draw_control->wanted_range = MYMIN(draw_control->wanted_range, sky->getFogDistance());
|
||||||
}
|
}
|
||||||
if (draw_control->range_all && sky->getFogDistance() < 0) {
|
if (draw_control->range_all && sky->getFogDistance() < 0) {
|
||||||
runData.fog_range = 100000 * BS;
|
runData.fog_range = FOG_RANGE_ALL;
|
||||||
} else {
|
} else {
|
||||||
runData.fog_range = draw_control->wanted_range * BS;
|
runData.fog_range = draw_control->wanted_range * BS;
|
||||||
}
|
}
|
||||||
@ -4196,7 +4207,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||||||
/*
|
/*
|
||||||
==================== Drawing begins ====================
|
==================== Drawing begins ====================
|
||||||
*/
|
*/
|
||||||
if (RenderingEngine::shouldRender())
|
if (device->isWindowVisible())
|
||||||
drawScene(graph, stats);
|
drawScene(graph, stats);
|
||||||
/*
|
/*
|
||||||
==================== End scene ====================
|
==================== End scene ====================
|
||||||
@ -4277,7 +4288,7 @@ void Game::updateShadows()
|
|||||||
|
|
||||||
void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
|
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();
|
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) {
|
if (this->m_cache_enable_fog) {
|
||||||
this->driver->setFog(
|
this->driver->setFog(
|
||||||
bg_color,
|
fog_color,
|
||||||
video::EFT_FOG_LINEAR,
|
video::EFT_FOG_LINEAR,
|
||||||
this->runData.fog_range * this->sky->getFogStart(),
|
this->runData.fog_range * this->sky->getFogStart(),
|
||||||
this->runData.fog_range * 1.0f,
|
this->runData.fog_range * 1.0f,
|
||||||
0.01f,
|
0.f, // unused
|
||||||
false, // pixel fog
|
false, // pixel fog
|
||||||
true // range fog
|
true // range fog
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this->driver->setFog(
|
this->driver->setFog(
|
||||||
bg_color,
|
fog_color,
|
||||||
video::EFT_FOG_LINEAR,
|
video::EFT_FOG_LINEAR,
|
||||||
100000 * BS,
|
FOG_RANGE_ALL,
|
||||||
110000 * BS,
|
FOG_RANGE_ALL + 100 * BS,
|
||||||
0.01f,
|
0.f, // unused
|
||||||
false, // pixel fog
|
false, // pixel fog
|
||||||
false // range fog
|
false // range fog
|
||||||
);
|
);
|
||||||
@ -4473,8 +4484,8 @@ void Game::showPauseMenu()
|
|||||||
static const std::string control_text = strgettext("Controls:\n"
|
static const std::string control_text = strgettext("Controls:\n"
|
||||||
"No menu open:\n"
|
"No menu open:\n"
|
||||||
"- slide finger: look around\n"
|
"- slide finger: look around\n"
|
||||||
"- tap: place/use\n"
|
"- tap: place/punch/use (default)\n"
|
||||||
"- long tap: dig/punch/use\n"
|
"- long tap: dig/use (default)\n"
|
||||||
"Menu/inventory open:\n"
|
"Menu/inventory open:\n"
|
||||||
"- double tap (outside):\n"
|
"- double tap (outside):\n"
|
||||||
" --> close\n"
|
" --> close\n"
|
||||||
|
@ -416,7 +416,9 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
|
|||||||
(e->number >> 0) & 0xFF);
|
(e->number >> 0) & 0xFF);
|
||||||
std::wstring text = unescape_translate(utf8_to_wide(e->name));
|
std::wstring text = unescape_translate(utf8_to_wide(e->name));
|
||||||
const std::string &unit = e->text;
|
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;
|
u32 item = e->item;
|
||||||
float precision = (item == 0) ? 10.0f : (item - 1.f);
|
float precision = (item == 0) ? 10.0f : (item - 1.f);
|
||||||
bool draw_precision = precision > 0;
|
bool draw_precision = precision > 0;
|
||||||
|
@ -54,7 +54,6 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client):
|
|||||||
{
|
{
|
||||||
m_cache_enable_shaders = g_settings->getBool("enable_shaders");
|
m_cache_enable_shaders = g_settings->getBool("enable_shaders");
|
||||||
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
|
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
|
||||||
m_meshgen_block_cache_size = g_settings->getS32("meshgen_block_cache_size");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshUpdateQueue::~MeshUpdateQueue()
|
MeshUpdateQueue::~MeshUpdateQueue()
|
||||||
|
@ -87,7 +87,6 @@ private:
|
|||||||
// TODO: Add callback to update these when g_settings changes
|
// TODO: Add callback to update these when g_settings changes
|
||||||
bool m_cache_enable_shaders;
|
bool m_cache_enable_shaders;
|
||||||
bool m_cache_smooth_lighting;
|
bool m_cache_smooth_lighting;
|
||||||
int m_meshgen_block_cache_size;
|
|
||||||
|
|
||||||
void fillDataFromMapBlocks(QueuedMeshUpdate *q);
|
void fillDataFromMapBlocks(QueuedMeshUpdate *q);
|
||||||
void cleanupCache();
|
void cleanupCache();
|
||||||
|
@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <IrrlichtDevice.h>
|
#include <irrlicht.h>
|
||||||
#include "fontengine.h"
|
#include "fontengine.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "clouds.h"
|
#include "clouds.h"
|
||||||
@ -292,15 +292,16 @@ std::vector<video::E_DRIVER_TYPE> RenderingEngine::getSupportedVideoDrivers()
|
|||||||
// Order by preference (best first)
|
// Order by preference (best first)
|
||||||
static const video::E_DRIVER_TYPE glDrivers[] = {
|
static const video::E_DRIVER_TYPE glDrivers[] = {
|
||||||
video::EDT_OPENGL,
|
video::EDT_OPENGL,
|
||||||
|
video::EDT_OPENGL3,
|
||||||
video::EDT_OGLES2,
|
video::EDT_OGLES2,
|
||||||
video::EDT_OGLES1,
|
video::EDT_OGLES1,
|
||||||
video::EDT_NULL,
|
video::EDT_NULL,
|
||||||
};
|
};
|
||||||
std::vector<video::E_DRIVER_TYPE> drivers;
|
std::vector<video::E_DRIVER_TYPE> drivers;
|
||||||
|
|
||||||
for (u32 i = 0; i < ARRLEN(glDrivers); i++) {
|
for (video::E_DRIVER_TYPE driver: glDrivers) {
|
||||||
if (IrrlichtDevice::isDriverSupported(glDrivers[i]))
|
if (IrrlichtDevice::isDriverSupported(driver))
|
||||||
drivers.push_back(glDrivers[i]);
|
drivers.push_back(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
return drivers;
|
return drivers;
|
||||||
@ -328,6 +329,7 @@ const VideoDriverInfo &RenderingEngine::getVideoDriverInfo(irr::video::E_DRIVER_
|
|||||||
static const std::unordered_map<int, VideoDriverInfo> driver_info_map = {
|
static const std::unordered_map<int, VideoDriverInfo> driver_info_map = {
|
||||||
{(int)video::EDT_NULL, {"null", "NULL Driver"}},
|
{(int)video::EDT_NULL, {"null", "NULL Driver"}},
|
||||||
{(int)video::EDT_OPENGL, {"opengl", "OpenGL"}},
|
{(int)video::EDT_OPENGL, {"opengl", "OpenGL"}},
|
||||||
|
{(int)video::EDT_OPENGL3, {"opengl3", "OpenGL 3+"}},
|
||||||
{(int)video::EDT_OGLES1, {"ogles1", "OpenGL ES1"}},
|
{(int)video::EDT_OGLES1, {"ogles1", "OpenGL ES1"}},
|
||||||
{(int)video::EDT_OGLES2, {"ogles2", "OpenGL ES2"}},
|
{(int)video::EDT_OGLES2, {"ogles2", "OpenGL ES2"}},
|
||||||
};
|
};
|
||||||
|
@ -43,6 +43,9 @@ class Minimap;
|
|||||||
|
|
||||||
class RenderingCore;
|
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
|
class RenderingEngine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -138,17 +141,6 @@ public:
|
|||||||
const irr::core::dimension2d<u32> initial_screen_size,
|
const irr::core::dimension2d<u32> initial_screen_size,
|
||||||
const bool initial_window_maximized);
|
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:
|
private:
|
||||||
v2u32 _getWindowSize() const;
|
v2u32 _getWindowSize() const;
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <IShaderConstantSetCallBack.h>
|
#include <IShaderConstantSetCallBack.h>
|
||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
#include "EShaderTypes.h"
|
#include "EShaderTypes.h"
|
||||||
|
#include "gettext.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "gamedef.h"
|
#include "gamedef.h"
|
||||||
#include "client/tile.h"
|
#include "client/tile.h"
|
||||||
@ -210,51 +211,36 @@ public:
|
|||||||
|
|
||||||
class MainShaderConstantSetter : public IShaderConstantSetter
|
class MainShaderConstantSetter : public IShaderConstantSetter
|
||||||
{
|
{
|
||||||
CachedVertexShaderSetting<f32, 16> m_world_view_proj;
|
CachedVertexShaderSetting<f32, 16> m_world_view_proj{"mWorldViewProj"};
|
||||||
CachedVertexShaderSetting<f32, 16> m_world;
|
CachedVertexShaderSetting<f32, 16> m_world{"mWorld"};
|
||||||
|
|
||||||
// Shadow-related
|
// Shadow-related
|
||||||
CachedPixelShaderSetting<f32, 16> m_shadow_view_proj;
|
CachedPixelShaderSetting<f32, 16> m_shadow_view_proj{"m_ShadowViewProj"};
|
||||||
CachedPixelShaderSetting<f32, 3> m_light_direction;
|
CachedPixelShaderSetting<f32, 3> m_light_direction{"v_LightDirection"};
|
||||||
CachedPixelShaderSetting<f32> m_texture_res;
|
CachedPixelShaderSetting<f32> m_texture_res{"f_textureresolution"};
|
||||||
CachedPixelShaderSetting<f32> m_shadow_strength;
|
CachedPixelShaderSetting<f32> m_shadow_strength{"f_shadow_strength"};
|
||||||
CachedPixelShaderSetting<f32> m_time_of_day;
|
CachedPixelShaderSetting<f32> m_time_of_day{"f_timeofday"};
|
||||||
CachedPixelShaderSetting<f32> m_shadowfar;
|
CachedPixelShaderSetting<f32> m_shadowfar{"f_shadowfar"};
|
||||||
CachedPixelShaderSetting<f32, 4> m_camera_pos;
|
CachedPixelShaderSetting<f32, 4> m_camera_pos{"CameraPos"};
|
||||||
CachedPixelShaderSetting<s32> m_shadow_texture;
|
CachedPixelShaderSetting<s32> m_shadow_texture{"ShadowMapSampler"};
|
||||||
CachedVertexShaderSetting<f32> m_perspective_bias0_vertex;
|
CachedVertexShaderSetting<f32>
|
||||||
CachedPixelShaderSetting<f32> m_perspective_bias0_pixel;
|
m_perspective_bias0_vertex{"xyPerspectiveBias0"};
|
||||||
CachedVertexShaderSetting<f32> m_perspective_bias1_vertex;
|
CachedPixelShaderSetting<f32>
|
||||||
CachedPixelShaderSetting<f32> m_perspective_bias1_pixel;
|
m_perspective_bias0_pixel{"xyPerspectiveBias0"};
|
||||||
CachedVertexShaderSetting<f32> m_perspective_zbias_vertex;
|
CachedVertexShaderSetting<f32>
|
||||||
CachedPixelShaderSetting<f32> m_perspective_zbias_pixel;
|
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
|
// Modelview matrix
|
||||||
CachedVertexShaderSetting<float, 16> m_world_view;
|
CachedVertexShaderSetting<float, 16> m_world_view{"mWorldView"};
|
||||||
// Texture matrix
|
// Texture matrix
|
||||||
CachedVertexShaderSetting<float, 16> m_texture;
|
CachedVertexShaderSetting<float, 16> m_texture{"mTexture"};
|
||||||
|
|
||||||
public:
|
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;
|
~MainShaderConstantSetter() = default;
|
||||||
|
|
||||||
virtual void onSetConstants(video::IMaterialRendererServices *services) override
|
virtual void onSetConstants(video::IMaterialRendererServices *services) override
|
||||||
@ -276,7 +262,7 @@ public:
|
|||||||
worldViewProj *= worldView;
|
worldViewProj *= worldView;
|
||||||
m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
|
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);
|
core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
|
||||||
m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
|
m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
|
||||||
m_texture.set(*reinterpret_cast<float(*)[16]>(texture.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();
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||||
if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
|
if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
|
||||||
errorstream << "Shaders are enabled but GLSL is not supported by the driver\n";
|
throw ShaderException(gettext("Shaders are enabled but GLSL is not "
|
||||||
return shaderinfo;
|
"supported by the driver."));
|
||||||
}
|
}
|
||||||
video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
|
video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
|
||||||
|
|
||||||
// Create shaders header
|
// 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;
|
std::stringstream shaders_header;
|
||||||
shaders_header
|
shaders_header
|
||||||
<< std::noboolalpha
|
<< std::noboolalpha
|
||||||
<< std::showpoint // for GLSL ES
|
<< std::showpoint // for GLSL ES
|
||||||
;
|
;
|
||||||
std::string vertex_header, fragment_header, geometry_header;
|
std::string vertex_header, fragment_header, geometry_header;
|
||||||
if (use_gles) {
|
if (fully_programmable) {
|
||||||
shaders_header << R"(
|
if (driver->getDriverType() == video::EDT_OPENGL3) {
|
||||||
#version 100
|
shaders_header << "#version 150\n";
|
||||||
)";
|
} else {
|
||||||
|
shaders_header << "#version 100\n";
|
||||||
|
}
|
||||||
vertex_header = R"(
|
vertex_header = R"(
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
|
|
||||||
@ -673,7 +661,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool use_discard = use_gles;
|
bool use_discard = fully_programmable;
|
||||||
// For renderers that should use discard instead of GL_ALPHA_TEST
|
// For renderers that should use discard instead of GL_ALPHA_TEST
|
||||||
const char *renderer = reinterpret_cast<const char*>(GL.GetString(GL.RENDERER));
|
const char *renderer = reinterpret_cast<const char*>(GL.GetString(GL.RENDERER));
|
||||||
if (strstr(renderer, "GC7000"))
|
if (strstr(renderer, "GC7000"))
|
||||||
@ -805,7 +793,9 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||||||
dumpShaderProgram(warningstream, "Vertex", vertex_shader);
|
dumpShaderProgram(warningstream, "Vertex", vertex_shader);
|
||||||
dumpShaderProgram(warningstream, "Fragment", fragment_shader);
|
dumpShaderProgram(warningstream, "Fragment", fragment_shader);
|
||||||
dumpShaderProgram(warningstream, "Geometry", geometry_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
|
// Apply the newly created material type
|
||||||
|
@ -39,16 +39,12 @@ private:
|
|||||||
class shadowScreenQuadCB : public video::IShaderConstantSetCallBack
|
class shadowScreenQuadCB : public video::IShaderConstantSetCallBack
|
||||||
{
|
{
|
||||||
public:
|
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,
|
virtual void OnSetConstants(video::IMaterialRendererServices *services,
|
||||||
s32 userData);
|
s32 userData);
|
||||||
private:
|
private:
|
||||||
CachedPixelShaderSetting<s32> m_sm_client_map_setting;
|
CachedPixelShaderSetting<s32> m_sm_client_map_setting{"ShadowMapClientMap"};
|
||||||
CachedPixelShaderSetting<s32> m_sm_client_map_trans_setting;
|
CachedPixelShaderSetting<s32>
|
||||||
CachedPixelShaderSetting<s32> m_sm_dynamic_sampler_setting;
|
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
|
class ShadowDepthShaderCB : public video::IShaderConstantSetCallBack
|
||||||
{
|
{
|
||||||
public:
|
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 OnSetMaterial(const video::SMaterial &material) override {}
|
||||||
|
|
||||||
void OnSetConstants(video::IMaterialRendererServices *services,
|
void OnSetConstants(video::IMaterialRendererServices *services,
|
||||||
@ -47,12 +36,13 @@ public:
|
|||||||
v3f CameraPos;
|
v3f CameraPos;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CachedVertexShaderSetting<f32, 16> m_light_mvp_setting;
|
CachedVertexShaderSetting<f32, 16> m_light_mvp_setting{"LightMVP"};
|
||||||
CachedVertexShaderSetting<f32> m_map_resolution_setting;
|
CachedVertexShaderSetting<f32> m_map_resolution_setting{"MapResolution"};
|
||||||
CachedVertexShaderSetting<f32> m_max_far_setting;
|
CachedVertexShaderSetting<f32> m_max_far_setting{"MaxFar"};
|
||||||
CachedPixelShaderSetting<s32> m_color_map_sampler_setting;
|
CachedPixelShaderSetting<s32>
|
||||||
CachedVertexShaderSetting<f32> m_perspective_bias0;
|
m_color_map_sampler_setting{"ColorMapSampler"};
|
||||||
CachedVertexShaderSetting<f32> m_perspective_bias1;
|
CachedVertexShaderSetting<f32> m_perspective_bias0{"xyPerspectiveBias0"};
|
||||||
CachedVertexShaderSetting<f32> m_perspective_zbias;
|
CachedVertexShaderSetting<f32> m_perspective_bias1{"xyPerspectiveBias1"};
|
||||||
CachedVertexShaderSetting<f32, 4> m_cam_pos_setting;
|
CachedVertexShaderSetting<f32> m_perspective_zbias{"zPerspectiveBias"};
|
||||||
|
CachedVertexShaderSetting<f32, 4> m_cam_pos_setting{"CameraPos"};
|
||||||
};
|
};
|
||||||
|
@ -54,12 +54,12 @@ public:
|
|||||||
|
|
||||||
float getBrightness() { return m_brightness; }
|
float getBrightness() { return m_brightness; }
|
||||||
|
|
||||||
const video::SColor &getBgColor() const
|
video::SColor getBgColor() const
|
||||||
{
|
{
|
||||||
return m_visible ? m_bgcolor : m_fallback_bg_color;
|
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;
|
return m_visible ? m_skycolor : m_fallback_bg_color;
|
||||||
}
|
}
|
||||||
@ -90,6 +90,7 @@ public:
|
|||||||
const video::SColorf &getCloudColor() const { return m_cloudcolor_f; }
|
const video::SColorf &getCloudColor() const { return m_cloudcolor_f; }
|
||||||
|
|
||||||
void setVisible(bool visible) { m_visible = visible; }
|
void setVisible(bool visible) { m_visible = visible; }
|
||||||
|
|
||||||
// Set only from set_sky API
|
// Set only from set_sky API
|
||||||
void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; }
|
void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; }
|
||||||
void setFallbackBgColor(video::SColor fallback_bg_color)
|
void setFallbackBgColor(video::SColor fallback_bg_color)
|
||||||
@ -114,14 +115,20 @@ public:
|
|||||||
void addTextureToSkybox(const std::string &texture, int material_id,
|
void addTextureToSkybox(const std::string &texture, int material_id,
|
||||||
ITextureSource *tsrc);
|
ITextureSource *tsrc);
|
||||||
const video::SColorf &getCurrentStarColor() const { return m_star_color; }
|
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; }
|
void setFogDistance(s16 fog_distance) { m_sky_params.fog_distance = fog_distance; }
|
||||||
s16 getFogDistance() const { return m_sky_params.fog_distance; }
|
s16 getFogDistance() const { return m_sky_params.fog_distance; }
|
||||||
|
|
||||||
void setFogStart(float fog_start) { m_sky_params.fog_start = fog_start; }
|
void setFogStart(float fog_start) { m_sky_params.fog_start = fog_start; }
|
||||||
float getFogStart() const { return m_sky_params.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; }
|
void setFogColor(video::SColor v) { m_sky_params.fog_color = v; }
|
||||||
float getVolumetricLightStrength() const { return m_sky_params.volumetric_light_strength; }
|
video::SColor getFogColor() const {
|
||||||
|
if (m_sky_params.fog_color.getAlpha() > 0)
|
||||||
|
return m_sky_params.fog_color;
|
||||||
|
return getBgColor();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
aabb3f m_box;
|
aabb3f m_box;
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ICameraSceneNode.h>
|
#include <ICameraSceneNode.h>
|
||||||
#include <IVideoDriver.h>
|
#include <IVideoDriver.h>
|
||||||
|
#include <IFileSystem.h>
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "util/container.h"
|
#include "util/container.h"
|
||||||
#include "util/thread.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
|
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.
|
Replaces the filename extension.
|
||||||
@ -185,11 +186,11 @@ struct TextureInfo
|
|||||||
TextureInfo(
|
TextureInfo(
|
||||||
const std::string &name_,
|
const std::string &name_,
|
||||||
video::ITexture *texture_,
|
video::ITexture *texture_,
|
||||||
std::set<std::string> &sourceImages_
|
std::set<std::string> &&sourceImages_
|
||||||
):
|
):
|
||||||
name(name_),
|
name(name_),
|
||||||
texture(texture_),
|
texture(texture_),
|
||||||
sourceImages(sourceImages_)
|
sourceImages(std::move(sourceImages_))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -486,8 +487,6 @@ TextureSource::~TextureSource()
|
|||||||
|
|
||||||
u32 TextureSource::getTextureId(const std::string &name)
|
u32 TextureSource::getTextureId(const std::string &name)
|
||||||
{
|
{
|
||||||
//infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
See if texture already exists
|
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.
|
// color alpha with the destination alpha.
|
||||||
// Otherwise, any pixels that are not fully transparent get the color 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,
|
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
|
// paint a texture using the given color
|
||||||
static void apply_multiplication(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
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
|
// Perform a Screen blend with the given color. The opposite effect of a
|
||||||
// Multiply blend.
|
// Multiply blend.
|
||||||
static void apply_screen(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
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
|
// Adjust the hue, saturation, and lightness of destination. Like
|
||||||
// "Hue-Saturation" in GIMP.
|
// "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)
|
u32 TextureSource::generateTexture(const std::string &name)
|
||||||
{
|
{
|
||||||
//infostream << "generateTexture(): name=\"" << name << "\"" << std::endl;
|
|
||||||
|
|
||||||
// Empty name means texture 0
|
// Empty name means texture 0
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
infostream<<"generateTexture(): name is empty"<<std::endl;
|
infostream<<"generateTexture(): name is empty"<<std::endl;
|
||||||
@ -620,8 +617,7 @@ u32 TextureSource::generateTexture(const std::string &name)
|
|||||||
See if texture already exists
|
See if texture already exists
|
||||||
*/
|
*/
|
||||||
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
std::map<std::string, u32>::iterator n;
|
auto n = m_name_to_id.find(name);
|
||||||
n = m_name_to_id.find(name);
|
|
||||||
if (n != m_name_to_id.end()) {
|
if (n != m_name_to_id.end()) {
|
||||||
return n->second;
|
return n->second;
|
||||||
}
|
}
|
||||||
@ -660,8 +656,8 @@ u32 TextureSource::generateTexture(const std::string &name)
|
|||||||
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
MutexAutoLock lock(m_textureinfo_cache_mutex);
|
||||||
|
|
||||||
u32 id = m_textureinfo_cache.size();
|
u32 id = m_textureinfo_cache.size();
|
||||||
TextureInfo ti(name, tex, source_image_names);
|
TextureInfo ti(name, tex, std::move(source_image_names));
|
||||||
m_textureinfo_cache.push_back(ti);
|
m_textureinfo_cache.emplace_back(std::move(ti));
|
||||||
m_name_to_id[name] = id;
|
m_name_to_id[name] = id;
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
@ -707,7 +703,7 @@ video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *
|
|||||||
const bool filter_needed =
|
const bool filter_needed =
|
||||||
m_setting_mipmap || m_setting_trilinear_filter ||
|
m_setting_mipmap || m_setting_trilinear_filter ||
|
||||||
m_setting_bilinear_filter || m_setting_anisotropic_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 + "^[applyfiltersformesh", id);
|
||||||
return getTexture(name, id);
|
return getTexture(name, id);
|
||||||
}
|
}
|
||||||
@ -779,19 +775,12 @@ void TextureSource::processQueue()
|
|||||||
GetRequest<std::string, u32, std::thread::id, u8>
|
GetRequest<std::string, u32, std::thread::id, u8>
|
||||||
request = m_get_texture_queue.pop();
|
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));
|
m_get_texture_queue.pushResult(request, generateTexture(request.key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureSource::insertSourceImage(const std::string &name, video::IImage *img)
|
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);
|
sanity_check(std::this_thread::get_id() == m_main_thread);
|
||||||
|
|
||||||
m_sourcecache.insert(name, img, true);
|
m_sourcecache.insert(name, img, true);
|
||||||
@ -838,8 +827,7 @@ void TextureSource::rebuildImagesAndTextures()
|
|||||||
|
|
||||||
void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
|
void TextureSource::rebuildTexture(video::IVideoDriver *driver, TextureInfo &ti)
|
||||||
{
|
{
|
||||||
if (ti.name.empty())
|
assert(!ti.name.empty());
|
||||||
return; // this shouldn't happen, just a precaution
|
|
||||||
|
|
||||||
// replaces the previous sourceImages
|
// replaces the previous sourceImages
|
||||||
// shouldn't really need to be done, but can't hurt
|
// 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;
|
video::ITexture *t_old = ti.texture;
|
||||||
// Replace texture
|
// Replace texture
|
||||||
ti.texture = t;
|
ti.texture = t;
|
||||||
ti.sourceImages = source_image_names;
|
ti.sourceImages = std::move(source_image_names);
|
||||||
|
|
||||||
if (t_old)
|
if (t_old)
|
||||||
m_texture_trash.push_back(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) {
|
if (baseimg == NULL) {
|
||||||
errorstream << "generateImage(): baseimg is NULL (attempted to"
|
errorstream << "generateImage(): baseimg is NULL (attempted to"
|
||||||
" create texture \"" << name << "\")" << std::endl;
|
" 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;
|
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);
|
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,
|
bool TextureSource::generateImagePart(std::string part_of_name,
|
||||||
video::IImage *& baseimg, std::set<std::string> &source_image_names)
|
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();
|
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
||||||
sanity_check(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
|
// Stuff starting with [ are special commands
|
||||||
if (part_of_name.empty() || part_of_name[0] != '[') {
|
if (part_of_name.empty() || part_of_name[0] != '[') {
|
||||||
source_image_names.insert(part_of_name);
|
source_image_names.insert(part_of_name);
|
||||||
video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
|
video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
|
||||||
if (image == NULL) {
|
if (!image) {
|
||||||
if (!part_of_name.empty()) {
|
// Do not create the dummy texture
|
||||||
|
if (part_of_name.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
// Do not create normalmap dummies
|
// Do not create normalmap dummies
|
||||||
if (part_of_name.find("_normal.png") != std::string::npos) {
|
if (str_ends_with(part_of_name, "_normal.png")) {
|
||||||
warningstream << "generateImage(): Could not load normal map \""
|
warningstream << "generateImagePart(): Could not load normal map \""
|
||||||
<< part_of_name << "\"" << std::endl;
|
<< part_of_name << "\"" << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorstream << "generateImage(): Could not load image \""
|
errorstream << "generateImagePart(): Could not load image \""
|
||||||
<< part_of_name << "\" while building texture; "
|
<< part_of_name << "\" while building texture; "
|
||||||
"Creating a dummy image" << std::endl;
|
"Creating a dummy image" << std::endl;
|
||||||
}
|
|
||||||
|
|
||||||
// Just create a dummy image
|
|
||||||
//core::dimension2d<u32> dim(2,2);
|
|
||||||
core::dimension2d<u32> dim(1,1);
|
core::dimension2d<u32> dim(1,1);
|
||||||
image = driver->createImage(video::ECF_A8R8G8B8, dim);
|
image = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
sanity_check(image != NULL);
|
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,
|
image->setPixel(0,0, video::SColor(255,myrand()%256,
|
||||||
myrand()%256,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 base image is NULL, load as base.
|
||||||
if (baseimg == NULL)
|
if (baseimg == NULL)
|
||||||
{
|
{
|
||||||
//infostream<<"Setting "<<part_of_name<<" as base"<<std::endl;
|
|
||||||
/*
|
/*
|
||||||
Copy it this way to get an alpha channel.
|
Copy it this way to get an alpha channel.
|
||||||
Otherwise images with alpha cannot be blitted on
|
Otherwise images with alpha cannot be blitted on
|
||||||
@ -1245,17 +1260,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
{
|
{
|
||||||
blitBaseImage(image, baseimg);
|
blitBaseImage(image, baseimg);
|
||||||
}
|
}
|
||||||
//cleanup
|
|
||||||
image->drop();
|
image->drop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// A special texture modification
|
// A special texture modification
|
||||||
|
|
||||||
/*infostream<<"generateImage(): generating special "
|
|
||||||
<<"modification \""<<part_of_name<<"\""
|
|
||||||
<<std::endl;*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
[crack:N:P
|
[crack:N:P
|
||||||
[cracko: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 (str_starts_with(part_of_name, "[crack"))
|
||||||
{
|
{
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream<<"generateImagePart(): baseimg == NULL "
|
|
||||||
<<"for part_of_name=\""<<part_of_name
|
|
||||||
<<"\", cancelling."<<std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crack image number and overlay option
|
// Crack image number and overlay option
|
||||||
// Format: crack[o][:<tiles>]:<frame_count>:<frame>
|
// Format: crack[o][:<tiles>]:<frame_count>:<frame>
|
||||||
@ -1317,6 +1323,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
sf.next(":");
|
sf.next(":");
|
||||||
u32 w0 = stoi(sf.next("x"));
|
u32 w0 = stoi(sf.next("x"));
|
||||||
u32 h0 = stoi(sf.next(":"));
|
u32 h0 = stoi(sf.next(":"));
|
||||||
|
CHECK_DIM(w0, h0);
|
||||||
core::dimension2d<u32> dim(w0,h0);
|
core::dimension2d<u32> dim(w0,h0);
|
||||||
if (baseimg == NULL) {
|
if (baseimg == NULL) {
|
||||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
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 x = stoi(sf.next(","));
|
||||||
u32 y = stoi(sf.next("="));
|
u32 y = stoi(sf.next("="));
|
||||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
||||||
|
|
||||||
|
if (x >= w0 || y >= h0)
|
||||||
|
COMPLAIN_INVALID("X or Y offset");
|
||||||
infostream<<"Adding \""<<filename
|
infostream<<"Adding \""<<filename
|
||||||
<<"\" to combined ("<<x<<","<<y<<")"
|
<<"\" to combined ("<<x<<","<<y<<")"
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
|
|
||||||
video::IImage *img = generateImage(filename, source_image_names);
|
video::IImage *img = generateImage(filename, source_image_names);
|
||||||
if (img) {
|
if (img) {
|
||||||
core::dimension2d<u32> dim = img->getDimension();
|
core::dimension2d<u32> dim = img->getDimension();
|
||||||
@ -1337,10 +1348,6 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
driver->createImage(video::ECF_A8R8G8B8, dim);
|
driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
img->copyTo(img2);
|
img->copyTo(img2);
|
||||||
img->drop();
|
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);
|
blit_with_alpha(img2, baseimg, v2s32(0,0), pos_base, dim);
|
||||||
img2->drop();
|
img2->drop();
|
||||||
} else {
|
} else {
|
||||||
@ -1357,8 +1364,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
*/
|
*/
|
||||||
else if (str_starts_with(part_of_name, "[fill"))
|
else if (str_starts_with(part_of_name, "[fill"))
|
||||||
{
|
{
|
||||||
s32 x = 0;
|
u32 x = 0;
|
||||||
s32 y = 0;
|
u32 y = 0;
|
||||||
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
@ -1377,6 +1384,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
}
|
}
|
||||||
core::dimension2d<u32> dim(width, height);
|
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);
|
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
img->fill(color);
|
img->fill(color);
|
||||||
|
|
||||||
@ -1392,12 +1406,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
*/
|
*/
|
||||||
else if (str_starts_with(part_of_name, "[brighten"))
|
else if (str_starts_with(part_of_name, "[brighten"))
|
||||||
{
|
{
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream<<"generateImagePart(): baseimg==NULL "
|
|
||||||
<<"for part_of_name=\""<<part_of_name
|
|
||||||
<<"\", cancelling."<<std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
brighten(baseimg);
|
brighten(baseimg);
|
||||||
}
|
}
|
||||||
@ -1410,13 +1419,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
*/
|
*/
|
||||||
else if (str_starts_with(part_of_name, "[noalpha"))
|
else if (str_starts_with(part_of_name, "[noalpha"))
|
||||||
{
|
{
|
||||||
if (baseimg == NULL){
|
CHECK_BASEIMG();
|
||||||
errorstream<<"generateImagePart(): baseimg==NULL "
|
|
||||||
<<"for part_of_name=\""<<part_of_name
|
|
||||||
<<"\", cancelling."<<std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
core::dimension2d<u32> dim = baseimg->getDimension();
|
core::dimension2d<u32> dim = baseimg->getDimension();
|
||||||
|
|
||||||
// Set alpha to full
|
// 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:"))
|
else if (str_starts_with(part_of_name, "[makealpha:"))
|
||||||
{
|
{
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream<<"generateImagePart(): baseimg == NULL "
|
|
||||||
<<"for part_of_name=\""<<part_of_name
|
|
||||||
<<"\", cancelling."<<std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Strfnd sf(part_of_name.substr(11));
|
Strfnd sf(part_of_name.substr(11));
|
||||||
u32 r1 = stoi(sf.next(","));
|
u32 r1 = stoi(sf.next(","));
|
||||||
@ -1448,12 +1446,6 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
|
|
||||||
core::dimension2d<u32> dim = baseimg->getDimension();
|
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 y=0; y<dim.Height; y++)
|
||||||
for (u32 x=0; x<dim.Width; x++)
|
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"))
|
else if (str_starts_with(part_of_name, "[transform"))
|
||||||
{
|
{
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream<<"generateImagePart(): baseimg == NULL "
|
|
||||||
<<"for part_of_name=\""<<part_of_name
|
|
||||||
<<"\", cancelling."<<std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 transform = parseImageTransform(part_of_name.substr(10));
|
u32 transform = parseImageTransform(part_of_name.substr(10));
|
||||||
core::dimension2d<u32> dim = imageTransformDimension(
|
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"))
|
else if (str_starts_with(part_of_name, "[inventorycube"))
|
||||||
{
|
{
|
||||||
if (baseimg != NULL){
|
if (baseimg) {
|
||||||
errorstream<<"generateImagePart(): baseimg != NULL "
|
errorstream<<"generateImagePart(): baseimg != NULL "
|
||||||
<<"for part_of_name=\""<<part_of_name
|
<<"for part_of_name=\""<<part_of_name
|
||||||
<<"\", cancelling."<<std::endl;
|
<<"\", cancelling."<<std::endl;
|
||||||
@ -1539,8 +1526,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
errorstream << "generateImagePart(): Failed to create textures"
|
errorstream << "generateImagePart(): Failed to create textures"
|
||||||
<< " for inventorycube \"" << part_of_name << "\""
|
<< " for inventorycube \"" << part_of_name << "\""
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
baseimg = generateImage(imagename_top, source_image_names);
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
baseimg = createInventoryCubeImage(img_top, img_left, img_right);
|
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);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
u32 percent = stoi(sf.next(":"));
|
u32 percent = stoi(sf.next(":"), 0, 100);
|
||||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
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);
|
video::IImage *img = generateImage(filename, source_image_names);
|
||||||
if (img)
|
if (img) {
|
||||||
{
|
|
||||||
core::dimension2d<u32> dim = img->getDimension();
|
core::dimension2d<u32> dim = img->getDimension();
|
||||||
|
if (!baseimg)
|
||||||
|
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
|
|
||||||
core::position2d<s32> pos_base(0, 0);
|
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);
|
core::position2d<s32> clippos(0, 0);
|
||||||
clippos.Y = dim.Height * (100-percent) / 100;
|
clippos.Y = dim.Height * (100-percent) / 100;
|
||||||
core::dimension2d<u32> clipdim = dim;
|
core::dimension2d<u32> clipdim = dim;
|
||||||
clipdim.Height = clipdim.Height * percent / 100 + 1;
|
clipdim.Height = clipdim.Height * percent / 100 + 1;
|
||||||
core::rect<s32> cliprect(clippos, clipdim);
|
core::rect<s32> cliprect(clippos, clipdim);
|
||||||
img2->copyToWithAlpha(baseimg, pos_base,
|
img->copyToWithAlpha(baseimg, pos_base,
|
||||||
core::rect<s32>(v2s32(0,0), dim),
|
core::rect<s32>(v2s32(0,0), dim),
|
||||||
video::SColor(255,255,255,255),
|
video::SColor(255,255,255,255),
|
||||||
&cliprect);
|
&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:"))
|
else if (str_starts_with(part_of_name, "[verticalframe:"))
|
||||||
{
|
{
|
||||||
|
CHECK_BASEIMG();
|
||||||
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
u32 frame_count = stoi(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;
|
<< "\", using frame_count = 1 instead." << std::endl;
|
||||||
frame_count = 1;
|
frame_count = 1;
|
||||||
}
|
}
|
||||||
|
if (frame_index >= frame_count)
|
||||||
if (baseimg == NULL){
|
frame_index = frame_count - 1;
|
||||||
errorstream<<"generateImagePart(): baseimg != NULL "
|
|
||||||
<<"for part_of_name=\""<<part_of_name
|
|
||||||
<<"\", cancelling."<<std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
v2u32 frame_size = baseimg->getDimension();
|
v2u32 frame_size = baseimg->getDimension();
|
||||||
frame_size.Y /= frame_count;
|
frame_size.Y /= frame_count;
|
||||||
|
|
||||||
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8,
|
video::IImage *img = driver->createImage(video::ECF_A8R8G8B8,
|
||||||
frame_size);
|
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
|
// Fill target image with transparency
|
||||||
img->fill(video::SColor(0,0,0,0));
|
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:"))
|
else if (str_starts_with(part_of_name, "[mask:"))
|
||||||
{
|
{
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImage(): baseimg == NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
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->getDimension());
|
||||||
img->drop();
|
img->drop();
|
||||||
} else {
|
} else {
|
||||||
errorstream << "generateImage(): Failed to load \""
|
errorstream << "generateImagePart(): Failed to load image \""
|
||||||
<< filename << "\".";
|
<< filename << "\" for [mask" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -1680,12 +1649,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
sf.next(":");
|
sf.next(":");
|
||||||
std::string color_str = sf.next(":");
|
std::string color_str = sf.next(":");
|
||||||
|
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg != NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
video::SColor color;
|
video::SColor color;
|
||||||
|
|
||||||
@ -1711,12 +1675,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
std::string color_str = sf.next(":");
|
std::string color_str = sf.next(":");
|
||||||
std::string ratio_str = sf.next(":");
|
std::string ratio_str = sf.next(":");
|
||||||
|
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg != NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
video::SColor color;
|
video::SColor color;
|
||||||
int ratio = -1;
|
int ratio = -1;
|
||||||
@ -1741,12 +1700,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
/* IMPORTANT: When changing this, getTextureForMesh() needs to be
|
/* IMPORTANT: When changing this, getTextureForMesh() needs to be
|
||||||
* updated too. */
|
* updated too. */
|
||||||
|
|
||||||
if (!baseimg) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg == NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the "clean transparent" filter, if needed
|
// Apply the "clean transparent" filter, if needed
|
||||||
if (m_setting_mipmap || m_setting_bilinear_filter ||
|
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
|
* equal to the target minimum. If e.g. this is a vertical frames
|
||||||
* animation, the short dimension will be the real size.
|
* 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 xscale = scaleto / dim.Width;
|
||||||
u32 yscale = scaleto / dim.Height;
|
u32 yscale = scaleto / dim.Height;
|
||||||
const s32 scale = std::max(xscale, yscale);
|
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"))
|
else if (str_starts_with(part_of_name, "[resize"))
|
||||||
{
|
{
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg == NULL "
|
|
||||||
<< "for part_of_name=\""<< part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
u32 width = stoi(sf.next("x"));
|
u32 width = stoi(sf.next("x"));
|
||||||
u32 height = stoi(sf.next(""));
|
u32 height = stoi(sf.next(""));
|
||||||
core::dimension2d<u32> dim(width, height);
|
CHECK_DIM(width, height);
|
||||||
|
|
||||||
video::IImage *image = RenderingEngine::get_video_driver()->
|
video::IImage *image = driver->
|
||||||
createImage(video::ECF_A8R8G8B8, dim);
|
createImage(video::ECF_A8R8G8B8, {width, height});
|
||||||
baseimg->copyToScaling(image);
|
baseimg->copyToScaling(image);
|
||||||
baseimg->drop();
|
baseimg->drop();
|
||||||
baseimg = image;
|
baseimg = image;
|
||||||
@ -1824,12 +1767,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
255 means totally opaque.
|
255 means totally opaque.
|
||||||
*/
|
*/
|
||||||
else if (str_starts_with(part_of_name, "[opacity:")) {
|
else if (str_starts_with(part_of_name, "[opacity:")) {
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg == NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
@ -1854,12 +1792,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
will be inverted.
|
will be inverted.
|
||||||
*/
|
*/
|
||||||
else if (str_starts_with(part_of_name, "[invert:")) {
|
else if (str_starts_with(part_of_name, "[invert:")) {
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg == NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
@ -1891,13 +1824,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
from the base image it assumes to be a
|
from the base image it assumes to be a
|
||||||
tilesheet with dimensions W,H (in tiles).
|
tilesheet with dimensions W,H (in tiles).
|
||||||
*/
|
*/
|
||||||
else if (part_of_name.substr(0,7) == "[sheet:") {
|
else if (str_starts_with(part_of_name, "[sheet:")) {
|
||||||
if (baseimg == NULL) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg != NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
@ -1906,26 +1834,21 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
u32 x0 = stoi(sf.next(","));
|
u32 x0 = stoi(sf.next(","));
|
||||||
u32 y0 = stoi(sf.next(":"));
|
u32 y0 = stoi(sf.next(":"));
|
||||||
|
|
||||||
if (w0 == 0 || h0 == 0) {
|
CHECK_DIM(w0, h0);
|
||||||
errorstream << "generateImagePart(): invalid width or height "
|
if (x0 >= w0 || y0 >= h0)
|
||||||
<< "for part_of_name=\"" << part_of_name
|
COMPLAIN_INVALID("tile position (X,Y)");
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
core::dimension2d<u32> img_dim = baseimg->getDimension();
|
core::dimension2d<u32> img_dim = baseimg->getDimension();
|
||||||
core::dimension2d<u32> tile_dim(v2u32(img_dim) / v2u32(w0, h0));
|
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::IImage *img = driver->createImage(
|
||||||
video::ECF_A8R8G8B8, tile_dim);
|
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));
|
img->fill(video::SColor(0,0,0,0));
|
||||||
|
|
||||||
v2u32 vdim(tile_dim);
|
v2u32 vdim(tile_dim);
|
||||||
core::rect<s32> rect(v2s32(x0 * vdim.X, y0 * vdim.Y), tile_dim);
|
core::rect<s32> rect(v2s32(x0 * vdim.X, y0 * vdim.Y), tile_dim);
|
||||||
baseimg->copyToWithAlpha(img, v2s32(0), rect,
|
baseimg->copyToWithAlpha(img, v2s32(0), rect,
|
||||||
@ -1942,15 +1865,12 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
to produce a valid string.
|
to produce a valid string.
|
||||||
*/
|
*/
|
||||||
else if (str_starts_with(part_of_name, "[png:")) {
|
else if (str_starts_with(part_of_name, "[png:")) {
|
||||||
Strfnd sf(part_of_name);
|
|
||||||
sf.next(":");
|
|
||||||
std::string png;
|
std::string png;
|
||||||
{
|
{
|
||||||
std::string blob = sf.next("");
|
std::string blob = part_of_name.substr(5);
|
||||||
if (!base64_is_valid(blob)) {
|
if (!base64_is_valid(blob)) {
|
||||||
errorstream << "generateImagePart(): "
|
errorstream << "generateImagePart(): "
|
||||||
<< "malformed base64 in '[png'"
|
<< "malformed base64 in [png" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
png = base64_decode(blob);
|
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:") ||
|
else if (str_starts_with(part_of_name, "[hsl:") ||
|
||||||
str_starts_with(part_of_name, "[colorizehsl:")) {
|
str_starts_with(part_of_name, "[colorizehsl:")) {
|
||||||
|
|
||||||
if (baseimg == nullptr) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg == NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool colorize = str_starts_with(part_of_name, "[colorizehsl:");
|
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:") ||
|
else if (str_starts_with(part_of_name, "[overlay:") ||
|
||||||
str_starts_with(part_of_name, "[hardlight:")) {
|
str_starts_with(part_of_name, "[hardlight:")) {
|
||||||
|
|
||||||
if (baseimg == nullptr) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImage(): baseimg == NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
|
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->getDimension(), hardlight);
|
||||||
img->drop();
|
img->drop();
|
||||||
} else {
|
} else {
|
||||||
errorstream << "generateImage(): Failed to load \""
|
errorstream << "generateImage(): Failed to load image \""
|
||||||
<< filename << "\".";
|
<< 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:")) {
|
else if (str_starts_with(part_of_name, "[contrast:")) {
|
||||||
|
|
||||||
if (baseimg == nullptr) {
|
CHECK_BASEIMG();
|
||||||
errorstream << "generateImagePart(): baseimg == NULL "
|
|
||||||
<< "for part_of_name=\"" << part_of_name
|
|
||||||
<< "\", cancelling." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Strfnd sf(part_of_name);
|
Strfnd sf(part_of_name);
|
||||||
sf.next(":");
|
sf.next(":");
|
||||||
@ -2096,6 +2002,12 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef CHECK_BASEIMG
|
||||||
|
|
||||||
|
#undef COMPLAIN_INVALID
|
||||||
|
|
||||||
|
#undef CHECK_DIM
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the color of a single pixel drawn on top of another pixel.
|
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=64 drawn atop a pixel with alpha=128 should yield a
|
||||||
pixel with alpha=160, while getInterpolated would yield alpha=96.
|
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)
|
if (dst_c.getAlpha() == 0)
|
||||||
return src_c;
|
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
|
Apply color to destination, using a weighted interpolation blend
|
||||||
*/
|
*/
|
||||||
static void apply_colorize(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
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();
|
u32 alpha = color.getAlpha();
|
||||||
video::SColor dst_c;
|
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
|
Apply color to destination, using a Multiply blend mode
|
||||||
*/
|
*/
|
||||||
static void apply_multiplication(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
static void apply_multiplication(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||||
const video::SColor &color)
|
const video::SColor color)
|
||||||
{
|
{
|
||||||
video::SColor dst_c;
|
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
|
Apply color to destination, using a Screen blend mode
|
||||||
*/
|
*/
|
||||||
static void apply_screen(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
static void apply_screen(video::IImage *dst, v2u32 dst_pos, v2u32 size,
|
||||||
const video::SColor &color)
|
const video::SColor color)
|
||||||
{
|
{
|
||||||
video::SColor dst_c;
|
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> size, u8 tiles, video::IVideoDriver *driver)
|
||||||
{
|
{
|
||||||
core::dimension2d<u32> strip_size = crack->getDimension();
|
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> frame_size(strip_size.Width, strip_size.Width);
|
||||||
core::dimension2d<u32> tile_size(size / tiles);
|
core::dimension2d<u32> tile_size(size / tiles);
|
||||||
s32 frame_count = strip_size.Height / strip_size.Width;
|
s32 frame_count = strip_size.Height / strip_size.Width;
|
||||||
@ -2695,7 +2611,7 @@ namespace {
|
|||||||
return v / 12.92f;
|
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());
|
v3f col(col_srgb.getRed(), col_srgb.getGreen(), col_srgb.getBlue());
|
||||||
col /= 255.0f;
|
col /= 255.0f;
|
||||||
@ -2705,7 +2621,7 @@ namespace {
|
|||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
|
|
||||||
video::SColor linear_to_srgb(const v3f &col_linear)
|
video::SColor linear_to_srgb(const v3f col_linear)
|
||||||
{
|
{
|
||||||
v3f col;
|
v3f col;
|
||||||
col.X = linear_to_srgb_component(col_linear.X);
|
col.X = linear_to_srgb_component(col_linear.X);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#cmakedefine01 USE_SYSTEM_JSONCPP
|
#cmakedefine01 USE_SYSTEM_JSONCPP
|
||||||
#cmakedefine01 USE_REDIS
|
#cmakedefine01 USE_REDIS
|
||||||
#cmakedefine01 HAVE_ENDIAN_H
|
#cmakedefine01 HAVE_ENDIAN_H
|
||||||
|
#cmakedefine01 HAVE_STRLCPY
|
||||||
#cmakedefine01 CURSES_HAVE_CURSES_H
|
#cmakedefine01 CURSES_HAVE_CURSES_H
|
||||||
#cmakedefine01 CURSES_HAVE_NCURSES_H
|
#cmakedefine01 CURSES_HAVE_NCURSES_H
|
||||||
#cmakedefine01 CURSES_HAVE_NCURSES_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 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
|
Server
|
||||||
*/
|
*/
|
||||||
|
@ -46,7 +46,6 @@ void set_default_settings()
|
|||||||
settings->setDefault("enable_mesh_cache", "false");
|
settings->setDefault("enable_mesh_cache", "false");
|
||||||
settings->setDefault("mesh_generation_interval", "0");
|
settings->setDefault("mesh_generation_interval", "0");
|
||||||
settings->setDefault("mesh_generation_threads", "0");
|
settings->setDefault("mesh_generation_threads", "0");
|
||||||
settings->setDefault("meshgen_block_cache_size", "20");
|
|
||||||
settings->setDefault("enable_vbo", "true");
|
settings->setDefault("enable_vbo", "true");
|
||||||
settings->setDefault("free_move", "false");
|
settings->setDefault("free_move", "false");
|
||||||
settings->setDefault("pitch_move", "false");
|
settings->setDefault("pitch_move", "false");
|
||||||
|