mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Merge branch 'luanti-org:master' into new-header
This commit is contained in:
commit
35a7619219
584 changed files with 81256 additions and 31655 deletions
54
.github/workflows/linux.yml
vendored
54
.github/workflows/linux.yml
vendored
|
@ -34,28 +34,32 @@ env:
|
|||
|
||||
jobs:
|
||||
# Older gcc version (should be close to our minimum supported version)
|
||||
gcc_7:
|
||||
runs-on: ubuntu-20.04
|
||||
gcc_9:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install deps
|
||||
run: |
|
||||
source ./util/ci/common.sh
|
||||
install_linux_deps g++-7
|
||||
install_linux_deps g++-9
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
./util/ci/build.sh
|
||||
env:
|
||||
CC: gcc-7
|
||||
CXX: g++-7
|
||||
# Test fallback SHA implementations
|
||||
CMAKE_FLAGS: '-DENABLE_OPENSSL=0'
|
||||
CC: gcc-9
|
||||
CXX: g++-9
|
||||
CMAKE_FLAGS: '-DCMAKE_C_FLAGS="-fsanitize=address" -DCMAKE_CXX_FLAGS="-fsanitize=address"'
|
||||
|
||||
- name: Test
|
||||
- name: Unittest
|
||||
run: |
|
||||
./bin/luanti --run-unittests
|
||||
|
||||
# Do this here because we have ASan and error paths are sensitive to dangling pointers
|
||||
- name: Test error cases
|
||||
run: |
|
||||
./util/test_error_cases.sh
|
||||
|
||||
# Current gcc version
|
||||
gcc_14:
|
||||
runs-on: ubuntu-24.04
|
||||
|
@ -81,32 +85,28 @@ jobs:
|
|||
../bin/luanti --run-unittests
|
||||
|
||||
# Older clang version (should be close to our minimum supported version)
|
||||
clang_7:
|
||||
runs-on: ubuntu-20.04
|
||||
clang_11:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install deps
|
||||
run: |
|
||||
source ./util/ci/common.sh
|
||||
install_linux_deps clang-7 llvm-7
|
||||
install_linux_deps clang-11
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
./util/ci/build.sh
|
||||
env:
|
||||
CC: clang-7
|
||||
CXX: clang++-7
|
||||
CMAKE_FLAGS: '-DCMAKE_C_FLAGS="-fsanitize=address" -DCMAKE_CXX_FLAGS="-fsanitize=address"'
|
||||
CC: clang-11
|
||||
CXX: clang++-11
|
||||
# Test fallback SHA implementations
|
||||
CMAKE_FLAGS: '-DENABLE_OPENSSL=0'
|
||||
|
||||
- name: Unittest
|
||||
- name: Test
|
||||
run: |
|
||||
./bin/luanti --run-unittests
|
||||
|
||||
# Do this here because we have ASan and error paths are sensitive to dangling pointers
|
||||
- name: Test error cases
|
||||
run: |
|
||||
./util/test_error_cases.sh
|
||||
|
||||
# Current clang version
|
||||
clang_18:
|
||||
runs-on: ubuntu-24.04
|
||||
|
@ -132,16 +132,16 @@ jobs:
|
|||
run: |
|
||||
./util/test_multiplayer.sh
|
||||
|
||||
# Build with prometheus-cpp (server-only)
|
||||
clang_11_prometheus:
|
||||
name: "clang_11 (PROMETHEUS=1)"
|
||||
runs-on: ubuntu-22.04
|
||||
# Build with prometheus-cpp (server-only), also runs on ARM64
|
||||
clang_prometheus_arm:
|
||||
name: "clang (with Prometheus, ARM64)"
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install deps
|
||||
run: |
|
||||
source ./util/ci/common.sh
|
||||
install_linux_deps clang-11
|
||||
install_linux_deps --headless clang libluajit-5.1-dev
|
||||
|
||||
- name: Build prometheus-cpp
|
||||
run: ./util/ci/build_prometheus_cpp.sh
|
||||
|
@ -150,8 +150,8 @@ jobs:
|
|||
run: |
|
||||
./util/ci/build.sh
|
||||
env:
|
||||
CC: clang-11
|
||||
CXX: clang++-11
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
CMAKE_FLAGS: "-DENABLE_PROMETHEUS=1 -DBUILD_CLIENT=0 -DENABLE_CURSES=0"
|
||||
|
||||
- name: Test
|
||||
|
|
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
|
@ -45,7 +45,7 @@ jobs:
|
|||
mkdir build
|
||||
cd build
|
||||
cmake .. \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.14 \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=13 \
|
||||
-DCMAKE_FIND_FRAMEWORK=LAST \
|
||||
-DCMAKE_INSTALL_PREFIX=../build/macos/ \
|
||||
-DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE \
|
||||
|
|
2
.github/workflows/whitespace_checks.yml
vendored
2
.github/workflows/whitespace_checks.yml
vendored
|
@ -92,7 +92,7 @@ jobs:
|
|||
- name: Check indent spaces
|
||||
run: |
|
||||
if git ls-files |\
|
||||
grep -E '^src/.*\.cpp$|^src/.*\.[ch]$|\.lua' |\
|
||||
grep -E '^src/.*\.cpp$|^src/.*\.[ch]$|\.lua$' |\
|
||||
xargs grep -n -P '^\t*[ ]';\
|
||||
then\
|
||||
echo -e "\033[0;31mFound incorrect indent whitespaces";\
|
||||
|
|
12
.github/workflows/windows.yml
vendored
12
.github/workflows/windows.yml
vendored
|
@ -71,9 +71,7 @@ jobs:
|
|||
name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }}
|
||||
runs-on: windows-2019
|
||||
env:
|
||||
VCPKG_VERSION: 01f602195983451bc83e72f4214af2cbc495aa94
|
||||
# 2024.05.24
|
||||
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp sdl2
|
||||
VCPKG_DEFAULT_TRIPLET: ${{matrix.config.vcpkg_triplet}}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
@ -97,19 +95,17 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Restore from cache and run vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
uses: lukka/run-vcpkg@v11
|
||||
with:
|
||||
vcpkgArguments: ${{env.vcpkg_packages}}
|
||||
vcpkgDirectory: '${{ github.workspace }}\vcpkg'
|
||||
appendedCacheKey: ${{ matrix.config.vcpkg_triplet }}
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_VERSION }}
|
||||
vcpkgTriplet: ${{ matrix.config.vcpkg_triplet }}
|
||||
|
||||
- name: CMake
|
||||
# Note: See #15976 for why CMAKE_POLICY_VERSION_MINIMUM=3.5 is set.
|
||||
run: |
|
||||
cmake ${{matrix.config.generator}} `
|
||||
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}\vcpkg\scripts\buildsystems\vcpkg.cmake" `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 `
|
||||
-DENABLE_POSTGRESQL=OFF `
|
||||
-DENABLE_LUAJIT=TRUE `
|
||||
-DREQUIRE_LUAJIT=TRUE `
|
||||
|
|
16
.luacheckrc
16
.luacheckrc
|
@ -19,10 +19,10 @@ read_globals = {
|
|||
"VoxelManip",
|
||||
"profiler",
|
||||
"Settings",
|
||||
"PerlinNoise", "PerlinNoiseMap",
|
||||
"ValueNoise", "ValueNoiseMap",
|
||||
|
||||
string = {fields = {"split", "trim"}},
|
||||
table = {fields = {"copy", "getn", "indexof", "keyof", "insert_all"}},
|
||||
table = {fields = {"copy", "copy_with_metatables", "getn", "indexof", "keyof", "insert_all"}},
|
||||
math = {fields = {"hypot", "round"}},
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,13 @@ globals = {
|
|||
"_",
|
||||
}
|
||||
|
||||
stds.menu_common = {
|
||||
globals = {
|
||||
"mt_color_grey", "mt_color_blue", "mt_color_lightblue", "mt_color_green",
|
||||
"mt_color_dark_green", "mt_color_orange", "mt_color_red",
|
||||
},
|
||||
}
|
||||
|
||||
files["builtin/client/register.lua"] = {
|
||||
globals = {
|
||||
debug = {fields={"getinfo"}},
|
||||
|
@ -73,11 +80,16 @@ files["builtin/common/filterlist.lua"] = {
|
|||
}
|
||||
|
||||
files["builtin/mainmenu"] = {
|
||||
std = "+menu_common",
|
||||
globals = {
|
||||
"gamedata",
|
||||
},
|
||||
}
|
||||
|
||||
files["builtin/common/settings"] = {
|
||||
std = "+menu_common",
|
||||
}
|
||||
|
||||
files["builtin/common/tests"] = {
|
||||
read_globals = {
|
||||
"describe",
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
cmake_minimum_required(VERSION 3.12)
|
||||
if(POLICY CMP0177)
|
||||
cmake_policy(SET CMP0177 NEW)
|
||||
endif()
|
||||
|
||||
# This can be read from ${PROJECT_NAME} after project() is called
|
||||
project(luanti)
|
||||
|
@ -11,7 +14,7 @@ set(CLANG_MINIMUM_VERSION "7.0.1")
|
|||
|
||||
# You should not need to edit these manually, use util/bump_version.sh
|
||||
set(VERSION_MAJOR 5)
|
||||
set(VERSION_MINOR 12)
|
||||
set(VERSION_MINOR 13)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||
|
||||
|
@ -262,8 +265,8 @@ install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
|
|||
|
||||
if(UNIX AND NOT APPLE)
|
||||
install(FILES "doc/luanti.6" "doc/luantiserver.6" DESTINATION "${MANDIR}/man6")
|
||||
install(FILES "misc/net.minetest.minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
|
||||
install(FILES "misc/net.minetest.minetest.metainfo.xml" DESTINATION "${METAINFODIR}")
|
||||
install(FILES "misc/org.luanti.luanti.desktop" DESTINATION "${XDG_APPS_DIR}")
|
||||
install(FILES "misc/org.luanti.luanti.metainfo.xml" DESTINATION "${METAINFODIR}")
|
||||
install(FILES "misc/luanti.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
|
||||
install(FILES "misc/luanti-xorg-icon-128.png"
|
||||
DESTINATION "${ICONDIR}/hicolor/128x128/apps"
|
||||
|
|
|
@ -104,6 +104,14 @@ grorp:
|
|||
using the font "undefined medium" (https://undefined-medium.com/),
|
||||
which is licensed under the SIL Open Font License, Version 1.1
|
||||
modified by DS
|
||||
textures/base/pack/dig_btn.png
|
||||
textures/base/pack/place_btn.png
|
||||
derived by editing the text in aux1_btn.svg
|
||||
|
||||
Material Design, Google (Apache license v2.0):
|
||||
textures/base/pack/contentdb_thumb_up.png
|
||||
textures/base/pack/contentdb_thumb_down.png
|
||||
textures/base/pack/contentdb_neutral.png
|
||||
|
||||
License of Luanti source code
|
||||
-------------------------------
|
||||
|
|
17
README.md
17
README.md
|
@ -1,13 +1,15 @@
|
|||
Luanti (formerly Minetest)
|
||||
==========================
|
||||
|
||||

|
||||
[](https://hosted.weblate.org/engage/minetest/?utm_source=widget)
|
||||
[](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
|
||||
<div align="center">
|
||||
<img src="textures/base/pack/logo.png" width="32%">
|
||||
<h1>Luanti (formerly Minetest)</h1>
|
||||
<img src="https://github.com/luanti-org/luanti/workflows/build/badge.svg" alt="Build Status">
|
||||
<a href="https://hosted.weblate.org/engage/minetest/?utm_source=widget"><img src="https://hosted.weblate.org/widgets/minetest/-/svg-badge.svg" alt="Translation status"></a>
|
||||
<a href="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html"><img src="https://img.shields.io/badge/license-LGPLv2.1%2B-blue.svg" alt="License"></a>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
Luanti is a free open-source voxel game engine with easy modding and game creation.
|
||||
|
||||
Copyright (C) 2010-2024 Perttu Ahola <celeron55@gmail.com>
|
||||
Copyright (C) 2010-2025 Perttu Ahola <celeron55@gmail.com>
|
||||
and contributors (see source file comments and the version control log)
|
||||
|
||||
Table of Contents
|
||||
|
@ -55,6 +57,7 @@ Some can be changed in the key config dialog in the settings tab.
|
|||
| T | Chat |
|
||||
| / | Command |
|
||||
| Esc | Pause menu/abort/exit (pauses only singleplayer game) |
|
||||
| Shift + Esc | Exit directly to main menu from anywhere, bypassing pause menu |
|
||||
| + | Increase view range |
|
||||
| - | Decrease view range |
|
||||
| K | Enable/disable fly mode (needs fly privilege) |
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
diff --git a/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||
index fd5a056e3..83e3cf657 100644
|
||||
--- a/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||
+++ b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||
@@ -1345,7 +1345,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
|
@ -9,7 +8,7 @@ index fd5a056e3..83e3cf657 100644
|
|||
- if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
|
||||
+ if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
|
||||
+ /*
|
||||
+ * CUSTOM ADDITION FOR MINETEST
|
||||
+ * CUSTOM ADDITION FOR LUANTI
|
||||
+ * should be upstreamed
|
||||
+ */
|
||||
+ (source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {
|
||||
|
|
|
@ -22,14 +22,19 @@ package net.minetest.minetest;
|
|||
|
||||
import org.libsdl.app.SDLActivity;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
|
@ -91,6 +96,9 @@ public class GameActivity extends SDLActivity {
|
|||
saveSettings();
|
||||
}
|
||||
|
||||
private NotificationManager mNotifyManager;
|
||||
private boolean gameNotificationShown = false;
|
||||
|
||||
public void showTextInputDialog(String hint, String current, int editType) {
|
||||
runOnUiThread(() -> showTextInputDialogUI(hint, current, editType));
|
||||
}
|
||||
|
@ -263,4 +271,67 @@ public class GameActivity extends SDLActivity {
|
|||
public boolean hasPhysicalKeyboard() {
|
||||
return getContext().getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS;
|
||||
}
|
||||
|
||||
// TODO: share code with UnzipService.createNotification
|
||||
private void updateGameNotification() {
|
||||
if (mNotifyManager == null) {
|
||||
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
}
|
||||
|
||||
if (!gameNotificationShown) {
|
||||
mNotifyManager.cancel(MainActivity.NOTIFICATION_ID_GAME);
|
||||
return;
|
||||
}
|
||||
|
||||
Notification.Builder builder;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
builder = new Notification.Builder(this, MainActivity.NOTIFICATION_CHANNEL_ID);
|
||||
} else {
|
||||
builder = new Notification.Builder(this);
|
||||
}
|
||||
|
||||
Intent notificationIntent = new Intent(this, GameActivity.class);
|
||||
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
int pendingIntentFlag = 0;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
pendingIntentFlag = PendingIntent.FLAG_MUTABLE;
|
||||
}
|
||||
PendingIntent intent = PendingIntent.getActivity(this, 0,
|
||||
notificationIntent, pendingIntentFlag);
|
||||
|
||||
builder.setContentTitle(getString(R.string.game_notification_title))
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setContentIntent(intent)
|
||||
.setOngoing(true);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// This avoids a stuck notification if the app is killed while
|
||||
// in-game: (1) if the user closes the app from the "Recents" screen
|
||||
// or (2) if the system kills the app while it is in background.
|
||||
// onStop is called too early to remove the notification and
|
||||
// onDestroy is often not called at all, so there's this hack instead.
|
||||
builder.setTimeoutAfter(16000);
|
||||
|
||||
// Replace the notification just before it expires as long as the app is
|
||||
// running (and we're still in-game).
|
||||
final Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (gameNotificationShown) {
|
||||
updateGameNotification();
|
||||
}
|
||||
}
|
||||
}, 15000);
|
||||
}
|
||||
|
||||
mNotifyManager.notify(MainActivity.NOTIFICATION_ID_GAME, builder.build());
|
||||
}
|
||||
|
||||
|
||||
public void setPlayingNowNotification(boolean show) {
|
||||
gameNotificationShown = show;
|
||||
updateGameNotification();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ import static net.minetest.minetest.UnzipService.*;
|
|||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
public static final String NOTIFICATION_CHANNEL_ID = "Minetest channel";
|
||||
public static final int NOTIFICATION_ID_UNZIP = 1;
|
||||
public static final int NOTIFICATION_ID_GAME = 2;
|
||||
|
||||
private final static int versionCode = BuildConfig.VERSION_CODE;
|
||||
private static final String SETTINGS = "MinetestSettings";
|
||||
|
|
|
@ -51,7 +51,6 @@ public class UnzipService extends IntentService {
|
|||
public static final int SUCCESS = -1;
|
||||
public static final int FAILURE = -2;
|
||||
public static final int INDETERMINATE = -3;
|
||||
private final int id = 1;
|
||||
private NotificationManager mNotifyManager;
|
||||
private boolean isSuccess = true;
|
||||
private String failureMessage;
|
||||
|
@ -100,11 +99,14 @@ public class UnzipService extends IntentService {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: share code with GameActivity.updateGameNotification
|
||||
@NonNull
|
||||
private Notification.Builder createNotification() {
|
||||
Notification.Builder builder;
|
||||
if (mNotifyManager == null)
|
||||
if (mNotifyManager == null) {
|
||||
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
}
|
||||
|
||||
Notification.Builder builder;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
builder = new Notification.Builder(this, MainActivity.NOTIFICATION_CHANNEL_ID);
|
||||
} else {
|
||||
|
@ -128,7 +130,7 @@ public class UnzipService extends IntentService {
|
|||
.setOngoing(true)
|
||||
.setProgress(0, 0, true);
|
||||
|
||||
mNotifyManager.notify(id, builder.build());
|
||||
mNotifyManager.notify(MainActivity.NOTIFICATION_ID_UNZIP, builder.build());
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
@ -200,14 +202,14 @@ public class UnzipService extends IntentService {
|
|||
} else {
|
||||
notificationBuilder.setProgress(100, progress, false);
|
||||
}
|
||||
mNotifyManager.notify(id, notificationBuilder.build());
|
||||
mNotifyManager.notify(MainActivity.NOTIFICATION_ID_UNZIP, notificationBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mNotifyManager.cancel(id);
|
||||
mNotifyManager.cancel(MainActivity.NOTIFICATION_ID_UNZIP);
|
||||
publishProgress(null, R.string.loading, isSuccess ? SUCCESS : FAILURE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,8 @@ import java.util.Locale;
|
|||
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
|
||||
private static final String TAG = "SDL";
|
||||
private static final int SDL_MAJOR_VERSION = 2;
|
||||
private static final int SDL_MINOR_VERSION = 30;
|
||||
private static final int SDL_MICRO_VERSION = 8;
|
||||
private static final int SDL_MINOR_VERSION = 32;
|
||||
private static final int SDL_MICRO_VERSION = 0;
|
||||
/*
|
||||
// Display InputType.SOURCE/CLASS of events and devices
|
||||
//
|
||||
|
@ -790,6 +790,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
SDLActivity.mFullscreenModeActive = false;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) {
|
||||
window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "error handling message, getContext() returned no Activity");
|
||||
|
@ -1347,7 +1350,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||
|
||||
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
|
||||
/*
|
||||
* CUSTOM ADDITION FOR MINETEST
|
||||
* CUSTOM ADDITION FOR LUANTI
|
||||
* should be upstreamed
|
||||
*/
|
||||
(source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {
|
||||
|
|
11
android/app/src/main/res/values-br/strings.xml
Normal file
11
android/app/src/main/res/values-br/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="unzip_notification_title">O kargañ Luanti</string>
|
||||
<string name="label">Luanti</string>
|
||||
<string name="loading">O kargañ…</string>
|
||||
<string name="notification_channel_description">Evezhiadennoù gant Luanti</string>
|
||||
<string name="unzip_notification_description">Nebeutoc\'h eget ur vunutenn…</string>
|
||||
<string name="ime_dialog_done">Graet</string>
|
||||
<string name="no_web_browser">Merdeer web ebet bet kavet</string>
|
||||
<string name="notification_channel_name">Evezhiadennoù hollek</string>
|
||||
</resources>
|
|
@ -1,11 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="label">Luanti</string>
|
||||
<string name="loading">Lädt…</string>
|
||||
<string name="loading">Laden …</string>
|
||||
<string name="unzip_notification_title">Luanti lädt</string>
|
||||
<string name="unzip_notification_description">Weniger als 1 Minute…</string>
|
||||
<string name="unzip_notification_description">Weniger als 1 Minute …</string>
|
||||
<string name="ime_dialog_done">Fertig</string>
|
||||
<string name="no_web_browser">Kein Web-Browser gefunden</string>
|
||||
<string name="no_web_browser">Keinen Web-Browser gefunden</string>
|
||||
<string name="notification_channel_name">Allgemeine Benachrichtigung</string>
|
||||
<string name="notification_channel_description">Benachrichtigungen von Luanti</string>
|
||||
<string name="game_notification_title">Luanti läuft</string>
|
||||
</resources>
|
|
@ -8,4 +8,5 @@
|
|||
<string name="unzip_notification_description">Moins d\'une minute…</string>
|
||||
<string name="ime_dialog_done">Terminé</string>
|
||||
<string name="no_web_browser">Aucun navigateur web trouvé</string>
|
||||
<string name="game_notification_title">Luanti est en cours d\'exécution</string>
|
||||
</resources>
|
||||
|
|
|
@ -8,4 +8,5 @@
|
|||
<string name="unzip_notification_description">Kurang dari 1 menit…</string>
|
||||
<string name="notification_channel_description">Pemberitahuan dari Luanti</string>
|
||||
<string name="unzip_notification_title">Memuat Luanti…</string>
|
||||
<string name="game_notification_title">Luanti sedang berjalan</string>
|
||||
</resources>
|
11
android/app/src/main/res/values-ro/strings.xml
Normal file
11
android/app/src/main/res/values-ro/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="label">Luanti</string>
|
||||
<string name="loading">Se încarcă…</string>
|
||||
<string name="notification_channel_name">Notificare generală</string>
|
||||
<string name="notification_channel_description">Notificări de la Luanti</string>
|
||||
<string name="unzip_notification_title">Luanti pornește</string>
|
||||
<string name="unzip_notification_description">Sub 1 minut…</string>
|
||||
<string name="ime_dialog_done">Gata</string>
|
||||
<string name="no_web_browser">Niciun navigator web găsit</string>
|
||||
</resources>
|
|
@ -1,11 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="unzip_notification_title">Загрузка Luanti</string>
|
||||
<string name="unzip_notification_description">Меньше чам за 1 минуту…</string>
|
||||
<string name="unzip_notification_description">Менее 1 минуты…</string>
|
||||
<string name="ime_dialog_done">Готово</string>
|
||||
<string name="label">Luаnti</string>
|
||||
<string name="notification_channel_description">Уведомления от Luanti</string>
|
||||
<string name="notification_channel_name">Основные уведомления</string>
|
||||
<string name="loading">Загрузка…</string>
|
||||
<string name="no_web_browser">Не найдено веб-браузера</string>
|
||||
<string name="game_notification_title">Luanti запущено</string>
|
||||
</resources>
|
11
android/app/src/main/res/values-sl/strings.xml
Normal file
11
android/app/src/main/res/values-sl/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="no_web_browser">Ni bil najden spletni brskalnik</string>
|
||||
<string name="notification_channel_name">Glavno obvestilo</string>
|
||||
<string name="loading">Nalaganje …</string>
|
||||
<string name="unzip_notification_description">Manj kot 1 minuta …</string>
|
||||
<string name="label">Luanti</string>
|
||||
<string name="notification_channel_description">Obvestilo od Luantia</string>
|
||||
<string name="ime_dialog_done">Končano!l</string>
|
||||
<string name="unzip_notification_title">Nalaganje Luantia</string>
|
||||
</resources>
|
|
@ -4,8 +4,9 @@
|
|||
<string name="loading">Laddar…</string>
|
||||
<string name="unzip_notification_description">Mindre än 1 minut…</string>
|
||||
<string name="ime_dialog_done">Färdig</string>
|
||||
<string name="no_web_browser">Ingen webbläsare kunde hittas</string>
|
||||
<string name="notification_channel_name">Generell notis</string>
|
||||
<string name="notification_channel_description">Notiser från Luanti</string>
|
||||
<string name="no_web_browser">Ingen webbläsare hittades</string>
|
||||
<string name="notification_channel_name">Allmän notifikation</string>
|
||||
<string name="notification_channel_description">Notifikationer från Luanti</string>
|
||||
<string name="unzip_notification_title">Laddar Luanti</string>
|
||||
<string name="game_notification_title">Luanti är igång</string>
|
||||
</resources>
|
|
@ -6,6 +6,7 @@
|
|||
<string name="notification_channel_description">Notifications from Luanti</string>
|
||||
<string name="unzip_notification_title">Loading Luanti</string>
|
||||
<string name="unzip_notification_description">Less than 1 minute…</string>
|
||||
<string name="game_notification_title">Luanti is running</string>
|
||||
<string name="ime_dialog_done">Done</string>
|
||||
<string name="no_web_browser">No web browser found</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
project.ext.set("versionMajor", 5) // Version Major
|
||||
project.ext.set("versionMinor", 12) // Version Minor
|
||||
project.ext.set("versionMinor", 13) // Version Minor
|
||||
project.ext.set("versionPatch", 0) // Version Patch
|
||||
// ^ keep in sync with cmake
|
||||
|
||||
|
|
148
android/icons/dig_btn.svg
Normal file
148
android/icons/dig_btn.svg
Normal file
|
@ -0,0 +1,148 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
inkscape:export-ydpi="24.000002"
|
||||
inkscape:export-xdpi="24.000002"
|
||||
inkscape:export-filename="../../textures/base/pack/dig_btn.png"
|
||||
sodipodi:docname="dig_btn.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 135.46666 135.46667"
|
||||
height="512"
|
||||
width="512"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:snap-object-midpoints="false"
|
||||
inkscape:snap-to-guides="true"
|
||||
inkscape:snap-bbox="true"
|
||||
showguides="true"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:snap-grids="false"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="32"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1011"
|
||||
inkscape:window-width="1920"
|
||||
units="px"
|
||||
showgrid="true"
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:cy="266.84627"
|
||||
inkscape:cx="201.24514"
|
||||
inkscape:zoom="1.4633894"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#404040"
|
||||
id="base"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1">
|
||||
<inkscape:grid
|
||||
empopacity="0.25098039"
|
||||
empcolor="#40ff40"
|
||||
opacity="0.1254902"
|
||||
color="#40ff40"
|
||||
empspacing="4"
|
||||
spacingy="0.26458333"
|
||||
spacingx="0.26458333"
|
||||
id="grid16"
|
||||
type="xygrid"
|
||||
originx="0"
|
||||
originy="0"
|
||||
units="px"
|
||||
visible="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
style="display:inline"
|
||||
inkscape:label="Layer 2"
|
||||
id="layer2"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7055"
|
||||
d=""
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7035"
|
||||
d=""
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7005"
|
||||
d=""
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5127"
|
||||
d=""
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<text
|
||||
transform="scale(1.0078883,0.99217343)"
|
||||
id="text4716"
|
||||
y="85.59491"
|
||||
x="67.78315"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48.4785px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
style="fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
y="85.59491"
|
||||
x="67.78315"
|
||||
id="tspan4714"
|
||||
sodipodi:role="line">LMB</tspan></text>
|
||||
<flowRoot
|
||||
transform="scale(0.26458333)"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||
id="flowRoot4718"
|
||||
xml:space="preserve"><flowRegion
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||
id="flowRegion4720"><rect
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||
y="124.10143"
|
||||
x="264.65997"
|
||||
height="136.37059"
|
||||
width="157.5838"
|
||||
id="rect4722" /></flowRegion><flowPara
|
||||
id="flowPara4724" /></flowRoot>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
148
android/icons/place_btn.svg
Normal file
148
android/icons/place_btn.svg
Normal file
|
@ -0,0 +1,148 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
inkscape:export-ydpi="24.000002"
|
||||
inkscape:export-xdpi="24.000002"
|
||||
inkscape:export-filename="../../textures/base/pack/place_btn.png"
|
||||
sodipodi:docname="place_btn.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 135.46666 135.46667"
|
||||
height="512"
|
||||
width="512"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-others="true"
|
||||
inkscape:snap-object-midpoints="false"
|
||||
inkscape:snap-to-guides="true"
|
||||
inkscape:snap-bbox="true"
|
||||
showguides="true"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:snap-grids="false"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="32"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1011"
|
||||
inkscape:window-width="1920"
|
||||
units="px"
|
||||
showgrid="true"
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:cy="266.84627"
|
||||
inkscape:cx="201.24514"
|
||||
inkscape:zoom="1.4633894"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#404040"
|
||||
id="base"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1">
|
||||
<inkscape:grid
|
||||
empopacity="0.25098039"
|
||||
empcolor="#40ff40"
|
||||
opacity="0.1254902"
|
||||
color="#40ff40"
|
||||
empspacing="4"
|
||||
spacingy="0.26458333"
|
||||
spacingx="0.26458333"
|
||||
id="grid16"
|
||||
type="xygrid"
|
||||
originx="0"
|
||||
originy="0"
|
||||
units="px"
|
||||
visible="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
style="display:inline"
|
||||
inkscape:label="Layer 2"
|
||||
id="layer2"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7055"
|
||||
d=""
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7035"
|
||||
d=""
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7005"
|
||||
d=""
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5127"
|
||||
d=""
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<text
|
||||
transform="scale(1.0078883,0.99217343)"
|
||||
id="text4716"
|
||||
y="85.59491"
|
||||
x="67.78315"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48.4785px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
style="fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
y="85.59491"
|
||||
x="67.78315"
|
||||
id="tspan4714"
|
||||
sodipodi:role="line">RMB</tspan></text>
|
||||
<flowRoot
|
||||
transform="scale(0.26458333)"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||
id="flowRoot4718"
|
||||
xml:space="preserve"><flowRegion
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||
id="flowRegion4720"><rect
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||
y="124.10143"
|
||||
x="264.65997"
|
||||
height="136.37059"
|
||||
width="157.5838"
|
||||
id="rect4722" /></flowRegion><flowPara
|
||||
id="flowPara4724" /></flowRoot>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
|
@ -32,8 +32,8 @@ do
|
|||
all.registered_craftitems = {}
|
||||
all.registered_tools = {}
|
||||
for k, v in pairs(all.registered_items) do
|
||||
-- Disable further modification
|
||||
setmetatable(v, {__newindex = {}})
|
||||
-- Ignore new keys
|
||||
setmetatable(v, {__newindex = function() end})
|
||||
-- Reassemble the other tables
|
||||
if v.type == "node" then
|
||||
getmetatable(v).__index = all.nodedef_default
|
||||
|
@ -59,6 +59,9 @@ end
|
|||
local alias_metatable = {
|
||||
__index = function(t, name)
|
||||
return rawget(t, core.registered_aliases[name])
|
||||
end,
|
||||
__newindex = function()
|
||||
error("table is read-only")
|
||||
end
|
||||
}
|
||||
setmetatable(core.registered_items, alias_metatable)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
core.log("info", "Initializing asynchronous environment")
|
||||
|
||||
|
||||
function core.job_processor(func, serialized_param)
|
||||
local param = core.deserialize(serialized_param)
|
||||
|
||||
|
@ -7,3 +8,15 @@ function core.job_processor(func, serialized_param)
|
|||
|
||||
return retval or core.serialize(nil)
|
||||
end
|
||||
|
||||
|
||||
function core.get_http_accept_languages()
|
||||
local languages
|
||||
local current_language = core.get_language()
|
||||
if current_language ~= "" then
|
||||
languages = { current_language, "en;q=0.8" }
|
||||
else
|
||||
languages = { "en" }
|
||||
end
|
||||
return "Accept-Language: " .. table.concat(languages, ", ")
|
||||
end
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2013 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- TODO improve doc --
|
||||
|
|
15
builtin/common/menu.lua
Normal file
15
builtin/common/menu.lua
Normal file
|
@ -0,0 +1,15 @@
|
|||
-- Luanti
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
-- These colors are used by the main menu and the settings menu
|
||||
mt_color_grey = "#AAAAAA"
|
||||
mt_color_blue = "#6389FF"
|
||||
mt_color_lightblue = "#99CCFF"
|
||||
mt_color_green = "#72FF63"
|
||||
mt_color_dark_green = "#25C191"
|
||||
mt_color_orange = "#FF8800"
|
||||
mt_color_red = "#FF3300"
|
||||
|
||||
function core.are_keycodes_equal(k1, k2)
|
||||
return core.normalize_keycode(k1) == core.normalize_keycode(k2)
|
||||
end
|
|
@ -7,18 +7,21 @@ local math = math
|
|||
local function basic_dump(o)
|
||||
local tp = type(o)
|
||||
if tp == "number" then
|
||||
return tostring(o)
|
||||
local s = tostring(o)
|
||||
if tonumber(s) == o then
|
||||
return s
|
||||
end
|
||||
-- Prefer an exact representation over a compact representation.
|
||||
-- e.g. basic_dump(0.3) == "0.3",
|
||||
-- but basic_dump(0.1 + 0.2) == "0.30000000000000004"
|
||||
-- so the user can see that 0.1 + 0.2 ~= 0.3
|
||||
return string.format("%.17g", o)
|
||||
elseif tp == "string" then
|
||||
return string.format("%q", o)
|
||||
elseif tp == "boolean" then
|
||||
return tostring(o)
|
||||
elseif tp == "nil" then
|
||||
return "nil"
|
||||
-- Uncomment for full function dumping support.
|
||||
-- Not currently enabled because bytecode isn't very human-readable and
|
||||
-- dump's output is intended for humans.
|
||||
--elseif tp == "function" then
|
||||
-- return string.format("loadstring(%q)", string.dump(o))
|
||||
elseif tp == "userdata" then
|
||||
return tostring(o)
|
||||
else
|
||||
|
@ -105,65 +108,141 @@ function dump2(o, name, dumped)
|
|||
return string.format("%s = {}\n%s", name, table.concat(t))
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- This dumps values in a one-statement format.
|
||||
|
||||
-- This dumps values in a human-readable expression format.
|
||||
-- If possible, the resulting string should evaluate to an equivalent value if loaded and executed.
|
||||
-- For example, {test = {"Testing..."}} becomes:
|
||||
-- [[{
|
||||
-- test = {
|
||||
-- "Testing..."
|
||||
-- }
|
||||
-- }]]
|
||||
-- This supports tables as keys, but not circular references.
|
||||
-- It performs poorly with multiple references as it writes out the full
|
||||
-- table each time.
|
||||
-- The indent field specifies a indentation string, it defaults to a tab.
|
||||
-- Use the empty string to disable indentation.
|
||||
-- The dumped and level arguments are internal-only.
|
||||
|
||||
function dump(o, indent, nested, level)
|
||||
local t = type(o)
|
||||
if not level and t == "userdata" then
|
||||
-- when userdata (e.g. player) is passed directly, print its metatable:
|
||||
return "userdata metatable: " .. dump(getmetatable(o))
|
||||
end
|
||||
if t ~= "table" then
|
||||
return basic_dump(o)
|
||||
end
|
||||
|
||||
-- Contains table -> true/nil of currently nested tables
|
||||
nested = nested or {}
|
||||
if nested[o] then
|
||||
return "<circular reference>"
|
||||
end
|
||||
nested[o] = true
|
||||
function dump(value, indent)
|
||||
indent = indent or "\t"
|
||||
level = level or 1
|
||||
local newline = indent == "" and "" or "\n"
|
||||
|
||||
local ret = {}
|
||||
local dumped_indexes = {}
|
||||
for i, v in ipairs(o) do
|
||||
ret[#ret + 1] = dump(v, indent, nested, level + 1)
|
||||
dumped_indexes[i] = true
|
||||
end
|
||||
for k, v in pairs(o) do
|
||||
if not dumped_indexes[k] then
|
||||
if type(k) ~= "string" or not is_valid_identifier(k) then
|
||||
k = "["..dump(k, indent, nested, level + 1).."]"
|
||||
end
|
||||
v = dump(v, indent, nested, level + 1)
|
||||
ret[#ret + 1] = k.." = "..v
|
||||
local rope = {}
|
||||
local write
|
||||
do
|
||||
-- Keeping the length of the table as a local variable is *much*
|
||||
-- faster than invoking the length operator.
|
||||
-- See https://gitspartv.github.io/LuaJIT-Benchmarks/#test12.
|
||||
local i = 0
|
||||
function write(str)
|
||||
i = i + 1
|
||||
rope[i] = str
|
||||
end
|
||||
end
|
||||
nested[o] = nil
|
||||
if indent ~= "" then
|
||||
local indent_str = "\n"..string.rep(indent, level)
|
||||
local end_indent_str = "\n"..string.rep(indent, level - 1)
|
||||
return string.format("{%s%s%s}",
|
||||
indent_str,
|
||||
table.concat(ret, ","..indent_str),
|
||||
end_indent_str)
|
||||
|
||||
local n_refs = {}
|
||||
local function count_refs(val)
|
||||
if type(val) ~= "table" then
|
||||
return
|
||||
end
|
||||
return "{"..table.concat(ret, ", ").."}"
|
||||
local tbl = val
|
||||
if n_refs[tbl] then
|
||||
n_refs[tbl] = n_refs[tbl] + 1
|
||||
return
|
||||
end
|
||||
n_refs[tbl] = 1
|
||||
for k, v in pairs(tbl) do
|
||||
count_refs(k)
|
||||
count_refs(v)
|
||||
end
|
||||
end
|
||||
count_refs(value)
|
||||
|
||||
local refs = {}
|
||||
local cur_ref = 1
|
||||
local function write_value(val, level)
|
||||
if type(val) ~= "table" then
|
||||
write(basic_dump(val))
|
||||
return
|
||||
end
|
||||
|
||||
local tbl = val
|
||||
if refs[tbl] then
|
||||
write(refs[tbl])
|
||||
return
|
||||
end
|
||||
|
||||
if n_refs[val] > 1 then
|
||||
refs[val] = ("getref(%d)"):format(cur_ref)
|
||||
write(("setref(%d)"):format(cur_ref))
|
||||
cur_ref = cur_ref + 1
|
||||
end
|
||||
write("{")
|
||||
if next(tbl) == nil then
|
||||
write("}")
|
||||
return
|
||||
end
|
||||
write(newline)
|
||||
|
||||
local function write_entry(k, v)
|
||||
write(indent:rep(level))
|
||||
write("[")
|
||||
write_value(k, level + 1)
|
||||
write("] = ")
|
||||
write_value(v, level + 1)
|
||||
write(",")
|
||||
write(newline)
|
||||
end
|
||||
|
||||
local keys = {string = {}, number = {}}
|
||||
for k in pairs(tbl) do
|
||||
local t = type(k)
|
||||
if keys[t] then
|
||||
table.insert(keys[t], k)
|
||||
end
|
||||
end
|
||||
|
||||
-- Write string-keyed entries
|
||||
table.sort(keys.string)
|
||||
for _, k in ipairs(keys.string) do
|
||||
local v = val[k]
|
||||
if is_valid_identifier(k) then
|
||||
write(indent:rep(level))
|
||||
write(k)
|
||||
write(" = ")
|
||||
write_value(v, level + 1)
|
||||
write(",")
|
||||
write(newline)
|
||||
else
|
||||
write_entry(k, v)
|
||||
end
|
||||
end
|
||||
|
||||
-- Write number-keyed entries
|
||||
local len = 0
|
||||
for i in ipairs(tbl) do
|
||||
len = i
|
||||
end
|
||||
if #keys.number == len then -- table is a list
|
||||
for _, v in ipairs(tbl) do
|
||||
write(indent:rep(level))
|
||||
write_value(v, level + 1)
|
||||
write(",")
|
||||
write(newline)
|
||||
end
|
||||
else -- table harbors arbitrary number keys
|
||||
table.sort(keys.number)
|
||||
for _, k in ipairs(keys.number) do
|
||||
write_entry(k, tbl[k])
|
||||
end
|
||||
end
|
||||
|
||||
-- Write all remaining entries
|
||||
for k, v in pairs(val) do
|
||||
if not keys[type(k)] then
|
||||
write_entry(k, v)
|
||||
end
|
||||
end
|
||||
|
||||
write(indent:rep(level - 1))
|
||||
write("}")
|
||||
end
|
||||
write_value(value, 1)
|
||||
return table.concat(rope)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -457,18 +536,37 @@ do
|
|||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function table.copy(t, seen)
|
||||
local n = {}
|
||||
seen = seen or {}
|
||||
seen[t] = n
|
||||
for k, v in pairs(t) do
|
||||
n[(type(k) == "table" and (seen[k] or table.copy(k, seen))) or k] =
|
||||
(type(v) == "table" and (seen[v] or table.copy(v, seen))) or v
|
||||
|
||||
local function table_copy(value, preserve_metatables)
|
||||
local seen = {}
|
||||
local function copy(val)
|
||||
if type(val) ~= "table" then
|
||||
return val
|
||||
end
|
||||
return n
|
||||
local t = val
|
||||
if seen[t] then
|
||||
return seen[t]
|
||||
end
|
||||
local res = {}
|
||||
seen[t] = res
|
||||
for k, v in pairs(t) do
|
||||
res[copy(k)] = copy(v)
|
||||
end
|
||||
if preserve_metatables then
|
||||
setmetatable(res, getmetatable(t))
|
||||
end
|
||||
return res
|
||||
end
|
||||
return copy(value)
|
||||
end
|
||||
|
||||
function table.copy(value)
|
||||
return table_copy(value, false)
|
||||
end
|
||||
|
||||
function table.copy_with_metatables(value)
|
||||
return table_copy(value, true)
|
||||
end
|
||||
|
||||
function table.insert_all(t, other)
|
||||
if table.move then -- LuaJIT
|
||||
|
@ -536,6 +634,10 @@ if core.gettext then -- for client and mainmenu
|
|||
function fgettext(text, ...)
|
||||
return core.formspec_escape(fgettext_ne(text, ...))
|
||||
end
|
||||
|
||||
function hgettext(text, ...)
|
||||
return core.hypertext_escape(fgettext_ne(text, ...))
|
||||
end
|
||||
end
|
||||
|
||||
local ESCAPE_CHAR = string.char(0x1b)
|
||||
|
|
|
@ -190,11 +190,41 @@ local function serialize(value, write)
|
|||
dump(value)
|
||||
end
|
||||
|
||||
-- Whether `value` recursively contains a function
|
||||
local function contains_function(value)
|
||||
local seen = {}
|
||||
local function check(val)
|
||||
if type(val) == "function" then
|
||||
return true
|
||||
end
|
||||
if type(val) == "table" then
|
||||
if seen[val] then
|
||||
return false
|
||||
end
|
||||
seen[val] = true
|
||||
for k, v in pairs(val) do
|
||||
if check(k) or check(v) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
return check(value)
|
||||
end
|
||||
|
||||
function core.serialize(value)
|
||||
if contains_function(value) then
|
||||
core.log("deprecated", "Support for dumping functions in `core.serialize` is deprecated.")
|
||||
end
|
||||
local rope = {}
|
||||
-- Keeping the length of the table as a local variable is *much*
|
||||
-- faster than invoking the length operator.
|
||||
-- See https://gitspartv.github.io/LuaJIT-Benchmarks/#test12.
|
||||
local i = 0
|
||||
serialize(value, function(text)
|
||||
-- Faster than table.insert(rope, text) on PUC Lua 5.1
|
||||
rope[#rope + 1] = text
|
||||
i = i + 1
|
||||
rope[i] = text
|
||||
end)
|
||||
return table_concat(rope)
|
||||
end
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2022 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local make = {}
|
||||
|
||||
|
@ -37,6 +24,7 @@ local make = {}
|
|||
-- * `fs` is a string for the formspec.
|
||||
-- Components should be relative to `0,0`, and not exceed `avail_w` or the returned `used_height`.
|
||||
-- * `used_height` is the space used by components in `fs`.
|
||||
-- * `spacing`: (Optional) the vertical margin to be added before the component (default 0.25)
|
||||
-- * `on_submit = function(self, fields, parent)`:
|
||||
-- * `fields`: submitted formspec fields
|
||||
-- * `parent`: the fstk element for the settings UI, use to show dialogs
|
||||
|
@ -442,13 +430,66 @@ local function make_noise_params(setting)
|
|||
}
|
||||
end
|
||||
|
||||
function make.key(setting)
|
||||
local btn_bind = "bind_" .. setting.name
|
||||
local btn_clear = "unbind_" .. setting.name
|
||||
local function add_conflict_warnings(fs, height)
|
||||
local value = core.settings:get(setting.name)
|
||||
if value == "" then
|
||||
return height
|
||||
end
|
||||
for _, o in ipairs(core.full_settingtypes) do
|
||||
if o.type == "key" and o.name ~= setting.name and core.are_keycodes_equal(core.settings:get(o.name), value) then
|
||||
table.insert(fs, ("label[0,%f;%s]"):format(height + 0.3,
|
||||
core.colorize(mt_color_orange, fgettext([[Conflicts with "$1"]], fgettext(o.readable_name)))))
|
||||
height = height + 0.6
|
||||
end
|
||||
end
|
||||
return height
|
||||
end
|
||||
return {
|
||||
info_text = setting.comment,
|
||||
setting = setting,
|
||||
spacing = 0.1,
|
||||
|
||||
get_formspec = function(self, avail_w)
|
||||
self.resettable = core.settings:has(setting.name)
|
||||
local btn_bind_width = math.max(2.5, avail_w/2)
|
||||
local value = core.settings:get(setting.name)
|
||||
local fs = {
|
||||
("label[0,0.4;%s]"):format(get_label(setting)),
|
||||
("button_key[%f,0;%f,0.8;%s;%s]"):format(
|
||||
btn_bind_width, btn_bind_width-0.8,
|
||||
btn_bind, core.formspec_escape(value)),
|
||||
("image_button[%f,0;0.8,0.8;%s;%s;]"):format(avail_w - 0.8,
|
||||
core.formspec_escape(defaulttexturedir .. "clear.png"),
|
||||
btn_clear),
|
||||
("tooltip[%s;%s]"):format(btn_clear, fgettext("Remove keybinding")),
|
||||
}
|
||||
local height = 0.8
|
||||
height = add_conflict_warnings(fs, height)
|
||||
return table.concat(fs), height
|
||||
end,
|
||||
|
||||
on_submit = function(self, fields)
|
||||
if fields[btn_bind] then
|
||||
core.settings:set(setting.name, fields[btn_bind])
|
||||
return true
|
||||
elseif fields[btn_clear] then
|
||||
core.settings:set(setting.name, "")
|
||||
return true
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
if INIT == "pause_menu" then
|
||||
-- Making the noise parameter dialog work in the pause menu settings would
|
||||
-- require porting "FSTK" (at least the dialog API) from the mainmenu formspec
|
||||
-- API to the in-game formspec API.
|
||||
-- There's no reason you'd want to adjust mapgen noise parameter settings
|
||||
-- in-game (they only apply to new worlds), so there's no reason to implement
|
||||
-- this.
|
||||
-- in-game (they only apply to new worlds, hidden as [world_creation]),
|
||||
-- so there's no reason to implement this.
|
||||
local empty = function()
|
||||
return { get_formspec = function() return "", 0 end }
|
||||
end
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2015 PilzAdam
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2015 PilzAdam
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local checkboxes = {}
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2022 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local path = core.get_builtin_path() .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM
|
||||
|
@ -22,7 +9,6 @@ local component_funcs = dofile(path .. "components.lua")
|
|||
local shadows_component = dofile(path .. "shadows_component.lua")
|
||||
|
||||
local loaded = false
|
||||
local full_settings
|
||||
local info_icon_path = core.formspec_escape(defaulttexturedir .. "settings_info.png")
|
||||
local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png")
|
||||
local all_pages = {}
|
||||
|
@ -32,7 +18,7 @@ local filtered_page_by_id = page_by_id
|
|||
|
||||
|
||||
local function get_setting_info(name)
|
||||
for _, entry in ipairs(full_settings) do
|
||||
for _, entry in ipairs(core.full_settingtypes) do
|
||||
if entry.type ~= "category" and entry.name == name then
|
||||
return entry
|
||||
end
|
||||
|
@ -70,7 +56,7 @@ local function load_settingtypes()
|
|||
end
|
||||
end
|
||||
|
||||
for _, entry in ipairs(full_settings) do
|
||||
for _, entry in ipairs(core.full_settingtypes) do
|
||||
if entry.type == "category" then
|
||||
if entry.level == 0 then
|
||||
section = entry.name
|
||||
|
@ -104,29 +90,14 @@ local function load()
|
|||
end
|
||||
loaded = true
|
||||
|
||||
full_settings = settingtypes.parse_config_file(false, true)
|
||||
|
||||
local change_keys = {
|
||||
query_text = "Controls",
|
||||
requires = {
|
||||
keyboard_mouse = true,
|
||||
},
|
||||
get_formspec = function(self, avail_w)
|
||||
local btn_w = math.min(avail_w, 3)
|
||||
return ("button[0,0;%f,0.8;btn_change_keys;%s]"):format(btn_w, fgettext("Controls")), 0.8
|
||||
end,
|
||||
on_submit = function(self, fields)
|
||||
if fields.btn_change_keys then
|
||||
core.show_keys_menu()
|
||||
end
|
||||
end,
|
||||
}
|
||||
core.full_settingtypes = settingtypes.parse_config_file(false, true)
|
||||
|
||||
local touchscreen_layout = {
|
||||
query_text = "Touchscreen layout",
|
||||
requires = {
|
||||
touchscreen = true,
|
||||
},
|
||||
context = "client",
|
||||
get_formspec = function(self, avail_w)
|
||||
local btn_w = math.min(avail_w, 6)
|
||||
return ("button[0,0;%f,0.8;btn_touch_layout;%s]"):format(btn_w, fgettext("Touchscreen layout")), 0.8
|
||||
|
@ -159,13 +130,11 @@ local function load()
|
|||
{ heading = fgettext_ne("Movement") },
|
||||
"arm_inertia",
|
||||
"view_bobbing_amount",
|
||||
"fall_bobbing_amount",
|
||||
},
|
||||
})
|
||||
|
||||
load_settingtypes()
|
||||
|
||||
table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys)
|
||||
-- insert after "touch_controls"
|
||||
table.insert(page_by_id.controls_touchscreen.content, 2, touchscreen_layout)
|
||||
do
|
||||
|
@ -174,18 +143,24 @@ local function load()
|
|||
table.insert(content, idx, shadows_component)
|
||||
|
||||
idx = table.indexof(content, "enable_auto_exposure") + 1
|
||||
local setting_info = get_setting_info("enable_auto_exposure")
|
||||
local note = component_funcs.note(fgettext_ne("(The game will need to enable automatic exposure as well)"))
|
||||
note.requires = get_setting_info("enable_auto_exposure").requires
|
||||
note.requires = setting_info.requires
|
||||
note.context = setting_info.context
|
||||
table.insert(content, idx, note)
|
||||
|
||||
idx = table.indexof(content, "enable_bloom") + 1
|
||||
setting_info = get_setting_info("enable_bloom")
|
||||
note = component_funcs.note(fgettext_ne("(The game will need to enable bloom as well)"))
|
||||
note.requires = get_setting_info("enable_bloom").requires
|
||||
note.requires = setting_info.requires
|
||||
note.context = setting_info.context
|
||||
table.insert(content, idx, note)
|
||||
|
||||
idx = table.indexof(content, "enable_volumetric_lighting") + 1
|
||||
setting_info = get_setting_info("enable_volumetric_lighting")
|
||||
note = component_funcs.note(fgettext_ne("(The game will need to enable volumetric lighting as well)"))
|
||||
note.requires = get_setting_info("enable_volumetric_lighting").requires
|
||||
note.requires = setting_info.requires
|
||||
note.context = setting_info.context
|
||||
table.insert(content, idx, note)
|
||||
end
|
||||
|
||||
|
@ -260,6 +235,17 @@ local function load()
|
|||
["true"] = fgettext_ne("Enabled"),
|
||||
["false"] = fgettext_ne("Disabled"),
|
||||
}
|
||||
|
||||
get_setting_info("touch_interaction_style").option_labels = {
|
||||
["tap"] = fgettext_ne("Tap"),
|
||||
["tap_crosshair"] = fgettext_ne("Tap with crosshair"),
|
||||
["buttons_crosshair"] = fgettext("Buttons with crosshair"),
|
||||
}
|
||||
|
||||
get_setting_info("touch_punch_gesture").option_labels = {
|
||||
["short_tap"] = fgettext_ne("Short tap"),
|
||||
["long_tap"] = fgettext_ne("Long tap"),
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -352,7 +338,18 @@ local function update_filtered_pages(query)
|
|||
end
|
||||
|
||||
|
||||
local function check_requirements(name, requires)
|
||||
local shown_contexts = {
|
||||
common = true,
|
||||
client = true,
|
||||
server = INIT ~= "pause_menu" or core.is_internal_server(),
|
||||
world_creation = INIT ~= "pause_menu",
|
||||
}
|
||||
|
||||
local function check_requirements(name, requires, context)
|
||||
if context and not shown_contexts[context] then
|
||||
return false
|
||||
end
|
||||
|
||||
if requires == nil then
|
||||
return true
|
||||
end
|
||||
|
@ -360,6 +357,7 @@ local function check_requirements(name, requires)
|
|||
local video_driver = core.get_active_driver()
|
||||
local touch_support = core.irrlicht_device_supports_touch()
|
||||
local touch_controls = core.settings:get("touch_controls")
|
||||
local touch_interaction_style = core.settings:get("touch_interaction_style")
|
||||
local special = {
|
||||
android = PLATFORM == "Android",
|
||||
desktop = PLATFORM ~= "Android",
|
||||
|
@ -370,6 +368,7 @@ local function check_requirements(name, requires)
|
|||
keyboard_mouse = not touch_support or (touch_controls == "auto" or not core.is_yes(touch_controls)),
|
||||
opengl = (video_driver == "opengl" or video_driver == "opengl3"),
|
||||
gles = video_driver:sub(1, 5) == "ogles",
|
||||
touch_interaction_style_tap = touch_interaction_style ~= "buttons_crosshair",
|
||||
}
|
||||
|
||||
for req_key, req_value in pairs(requires) do
|
||||
|
@ -411,11 +410,11 @@ function page_has_contents(page, actual_content)
|
|||
elseif type(item) == "string" then
|
||||
local setting = get_setting_info(item)
|
||||
assert(setting, "Unknown setting: " .. item)
|
||||
if check_requirements(setting.name, setting.requires) then
|
||||
if check_requirements(setting.name, setting.requires, setting.context) then
|
||||
return true
|
||||
end
|
||||
elseif item.get_formspec then
|
||||
if check_requirements(item.id, item.requires) then
|
||||
if check_requirements(item.id, item.requires, item.context) then
|
||||
return true
|
||||
end
|
||||
else
|
||||
|
@ -437,20 +436,22 @@ local function build_page_components(page)
|
|||
elseif item.heading then
|
||||
last_heading = item
|
||||
else
|
||||
local name, requires
|
||||
local name, requires, context
|
||||
if type(item) == "string" then
|
||||
local setting = get_setting_info(item)
|
||||
assert(setting, "Unknown setting: " .. item)
|
||||
name = setting.name
|
||||
requires = setting.requires
|
||||
context = setting.context
|
||||
elseif item.get_formspec then
|
||||
name = item.id
|
||||
requires = item.requires
|
||||
context = item.context
|
||||
else
|
||||
error("Unknown content in page: " .. dump(item))
|
||||
end
|
||||
|
||||
if check_requirements(name, requires) then
|
||||
if check_requirements(name, requires, context) then
|
||||
if last_heading then
|
||||
content[#content + 1] = last_heading
|
||||
last_heading = nil
|
||||
|
@ -517,7 +518,7 @@ local function get_formspec(dialogdata)
|
|||
|
||||
("button[0,%f;%f,0.8;back;%s]"):format(
|
||||
tabsize.height + 0.2, back_w,
|
||||
INIT == "pause_menu" and fgettext("Exit") or fgettext("Back")),
|
||||
fgettext("Back")),
|
||||
|
||||
("box[%f,%f;%f,0.8;#0000008C]"):format(
|
||||
back_w + 0.2, tabsize.height + 0.2, checkbox_w),
|
||||
|
@ -632,7 +633,13 @@ local function get_formspec(dialogdata)
|
|||
fs[#fs + 1] = "container_end[]"
|
||||
|
||||
if used_h > 0 then
|
||||
y = y + used_h + 0.25
|
||||
local spacing = 0.25
|
||||
local next_comp = dialogdata.components[i + 1]
|
||||
if next_comp and next_comp.spacing then
|
||||
spacing = next_comp.spacing
|
||||
end
|
||||
|
||||
y = y + used_h + spacing
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -771,11 +778,11 @@ end
|
|||
|
||||
|
||||
if INIT == "mainmenu" then
|
||||
function create_settings_dlg()
|
||||
function create_settings_dlg(page_id)
|
||||
load()
|
||||
local dlg = dialog_create("dlg_settings", get_formspec, buttonhandler, eventhandler)
|
||||
|
||||
dlg.data.page_id = update_filtered_pages("")
|
||||
dlg.data.page_id = page_id or update_filtered_pages("")
|
||||
|
||||
return dlg
|
||||
end
|
||||
|
|
|
@ -61,7 +61,7 @@ local function create_minetest_conf_example(settings)
|
|||
end
|
||||
end
|
||||
if entry.type == "key" then
|
||||
local line = "See https://github.com/luanti-org/luanti/blob/master/irr/include/Keycodes.h"
|
||||
local line = "See https://docs.luanti.org/for-players/controls/"
|
||||
insert(result, "# " .. line .. "\n")
|
||||
end
|
||||
insert(result, "# type: " .. entry.type)
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2022 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local path = core.get_builtin_path() .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2015 PilzAdam
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2015 PilzAdam
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
settingtypes = {}
|
||||
|
||||
|
@ -40,12 +27,24 @@ local CHAR_CLASSES = {
|
|||
FLAGS = "[%w_%-%.,]",
|
||||
}
|
||||
|
||||
local valid_contexts = {common = true, client = true, server = true, world_creation = true}
|
||||
|
||||
local function check_context_annotation(context, force_context)
|
||||
if force_context then
|
||||
return "Context annotations are not allowed, context is always " .. force_context
|
||||
end
|
||||
if not valid_contexts[context] then
|
||||
return "Unknown context"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function flags_to_table(flags)
|
||||
return flags:gsub("%s+", ""):split(",", true) -- Remove all spaces and split
|
||||
end
|
||||
|
||||
-- returns error message, or nil
|
||||
local function parse_setting_line(settings, line, read_all, base_level, allow_secure)
|
||||
local function parse_setting_line(settings, line, read_all, base_level, allow_secure, force_context)
|
||||
|
||||
-- strip carriage returns (CR, /r)
|
||||
line = line:gsub("\r", "")
|
||||
|
@ -69,9 +68,32 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
|
||||
-- category
|
||||
local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
|
||||
local category_context
|
||||
if not category then
|
||||
stars, category, category_context = line:match("^%[([%*]*)([^%]]+)%] %[([^%]]+)%]$")
|
||||
end
|
||||
if category then
|
||||
local category_level = stars:len() + base_level
|
||||
|
||||
if settings.current_context_level and
|
||||
category_level <= settings.current_context_level then
|
||||
-- The start of this category marks the end of the context annotation's scope.
|
||||
settings.current_context_level = nil
|
||||
settings.current_context = nil
|
||||
end
|
||||
|
||||
if category_context then
|
||||
local err = check_context_annotation(category_context, force_context)
|
||||
if err then
|
||||
return err
|
||||
end
|
||||
if settings.current_context_level then
|
||||
return "Category context annotations cannot be nested"
|
||||
end
|
||||
settings.current_context_level = category_level
|
||||
settings.current_context = category_context
|
||||
end
|
||||
|
||||
if settings.current_hide_level then
|
||||
if settings.current_hide_level < category_level then
|
||||
-- Skip this category, it's inside a hidden category.
|
||||
|
@ -102,7 +124,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
end
|
||||
|
||||
-- settings
|
||||
local first_part, name, readable_name, setting_type = line:match("^"
|
||||
local function make_pattern(include_context)
|
||||
return "^"
|
||||
-- this first capture group matches the whole first part,
|
||||
-- so we can later strip it from the rest of the line
|
||||
.. "("
|
||||
|
@ -110,9 +133,19 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
.. CHAR_CLASSES.SPACE .. "*"
|
||||
.. "%(([^%)]*)%)" -- readable name
|
||||
.. CHAR_CLASSES.SPACE .. "*"
|
||||
.. (include_context and (
|
||||
"%[([^%]]+)%]" -- context annotation
|
||||
.. CHAR_CLASSES.SPACE .. "*"
|
||||
) or "")
|
||||
.. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type
|
||||
.. CHAR_CLASSES.SPACE .. "*"
|
||||
.. ")")
|
||||
.. ")"
|
||||
end
|
||||
local first_part, name, readable_name, setting_type = line:match(make_pattern(false))
|
||||
local setting_context
|
||||
if not first_part then
|
||||
first_part, name, readable_name, setting_context, setting_type = line:match(make_pattern(true))
|
||||
end
|
||||
|
||||
if not first_part then
|
||||
return "Invalid line"
|
||||
|
@ -122,6 +155,26 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
return "Tried to add \"secure.\" setting"
|
||||
end
|
||||
|
||||
if setting_context then
|
||||
local err = check_context_annotation(setting_context, force_context)
|
||||
if err then
|
||||
return err
|
||||
end
|
||||
end
|
||||
|
||||
local context
|
||||
if force_context then
|
||||
context = force_context
|
||||
else
|
||||
if setting_context then
|
||||
context = setting_context
|
||||
elseif settings.current_context_level then
|
||||
context = settings.current_context
|
||||
else
|
||||
return "Missing context annotation"
|
||||
end
|
||||
end
|
||||
|
||||
local requires = {}
|
||||
local last_line = #current_comment > 0 and current_comment[#current_comment]:trim()
|
||||
if last_line and last_line:lower():sub(1, 9) == "requires:" then
|
||||
|
@ -170,6 +223,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
min = min,
|
||||
max = max,
|
||||
requires = requires,
|
||||
context = context,
|
||||
comment = comment,
|
||||
})
|
||||
return
|
||||
|
@ -182,9 +236,9 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
if not default then
|
||||
return "Invalid string setting"
|
||||
end
|
||||
if setting_type == "key" and not read_all then
|
||||
-- ignore key type if read_all is false
|
||||
return
|
||||
|
||||
if setting_type == "key" then
|
||||
requires.keyboard_mouse = true
|
||||
end
|
||||
|
||||
table.insert(settings, {
|
||||
|
@ -193,6 +247,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
type = setting_type,
|
||||
default = default,
|
||||
requires = requires,
|
||||
context = context,
|
||||
comment = comment,
|
||||
})
|
||||
return
|
||||
|
@ -245,6 +300,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
},
|
||||
values = values,
|
||||
requires = requires,
|
||||
context = context,
|
||||
comment = comment,
|
||||
noise_params = true,
|
||||
flags = flags_to_table("defaults,eased,absvalue")
|
||||
|
@ -263,6 +319,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
type = "bool",
|
||||
default = remaining_line,
|
||||
requires = requires,
|
||||
context = context,
|
||||
comment = comment,
|
||||
})
|
||||
return
|
||||
|
@ -290,6 +347,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
min = min,
|
||||
max = max,
|
||||
requires = requires,
|
||||
context = context,
|
||||
comment = comment,
|
||||
})
|
||||
return
|
||||
|
@ -313,6 +371,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
default = default,
|
||||
values = values:split(",", true),
|
||||
requires = requires,
|
||||
context = context,
|
||||
comment = comment,
|
||||
})
|
||||
return
|
||||
|
@ -331,6 +390,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
type = setting_type,
|
||||
default = default,
|
||||
requires = requires,
|
||||
context = context,
|
||||
comment = comment,
|
||||
})
|
||||
return
|
||||
|
@ -361,6 +421,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
default = default,
|
||||
possible = flags_to_table(possible),
|
||||
requires = requires,
|
||||
context = context,
|
||||
comment = comment,
|
||||
})
|
||||
return
|
||||
|
@ -369,14 +430,14 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
|||
return "Invalid setting type \"" .. setting_type .. "\""
|
||||
end
|
||||
|
||||
local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure)
|
||||
local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure, force_context)
|
||||
-- store this helper variable in the table so it's easier to pass to parse_setting_line()
|
||||
result.current_comment = {}
|
||||
result.current_hide_level = nil
|
||||
|
||||
local line = file:read("*line")
|
||||
while line do
|
||||
local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure)
|
||||
local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure, force_context)
|
||||
if error_msg then
|
||||
core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"")
|
||||
end
|
||||
|
@ -411,7 +472,6 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
|||
-- TODO: Support game/mod settings in the pause menu too
|
||||
-- Note that this will need to work different from how it's done in the
|
||||
-- mainmenu:
|
||||
-- * Only if in singleplayer / on local server, not on remote servers
|
||||
-- * Only show settings for the active game and mods
|
||||
-- (add API function to get them, can return nil if on a remote server)
|
||||
-- (names are probably not enough, will need paths for uniqueness)
|
||||
|
@ -441,7 +501,7 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
|||
type = "category",
|
||||
})
|
||||
|
||||
parse_single_file(file, path, read_all, settings, 2, false)
|
||||
parse_single_file(file, path, read_all, settings, 2, false, "server")
|
||||
|
||||
file:close()
|
||||
end
|
||||
|
@ -474,7 +534,7 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
|||
type = "category",
|
||||
})
|
||||
|
||||
parse_single_file(file, path, read_all, settings, 2, false)
|
||||
parse_single_file(file, path, read_all, settings, 2, false, "server")
|
||||
|
||||
file:close()
|
||||
end
|
||||
|
@ -505,7 +565,7 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
|||
type = "category",
|
||||
})
|
||||
|
||||
parse_single_file(file, path, read_all, settings, 2, false)
|
||||
parse_single_file(file, path, read_all, settings, 2, false, "client")
|
||||
|
||||
file:close()
|
||||
end
|
||||
|
|
|
@ -1,20 +1,7 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2021-2 x2048
|
||||
--Copyright (C) 2022-3 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2021-2 x2048
|
||||
-- Copyright (C) 2022-3 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local shadow_levels_labels = {
|
||||
|
@ -84,6 +71,7 @@ return {
|
|||
requires = {
|
||||
opengl = true,
|
||||
},
|
||||
context = "client",
|
||||
get_formspec = function(self, avail_w)
|
||||
local labels = table.copy(shadow_levels_labels)
|
||||
local idx = detect_mapping_idx()
|
||||
|
|
|
@ -19,6 +19,7 @@ function meta:__newindex(name, value)
|
|||
return
|
||||
end
|
||||
local info = getinfo(2, "Sl")
|
||||
if info ~= nil then
|
||||
local desc = ("%s:%d"):format(info.short_src, info.currentline)
|
||||
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
|
||||
if not warned[warn_key] and info.what ~= "main" and info.what ~= "C" then
|
||||
|
@ -26,6 +27,7 @@ function meta:__newindex(name, value)
|
|||
:format(name, desc))
|
||||
warned[warn_key] = true
|
||||
end
|
||||
end
|
||||
declared[name] = true
|
||||
end
|
||||
|
||||
|
@ -35,6 +37,9 @@ function meta:__index(name)
|
|||
return
|
||||
end
|
||||
local info = getinfo(2, "Sl")
|
||||
if info == nil then
|
||||
return
|
||||
end
|
||||
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
|
||||
if not warned[warn_key] and info.what ~= "C" then
|
||||
core.log("warning", ("Undeclared global variable %q accessed at %s:%s")
|
||||
|
|
|
@ -178,6 +178,35 @@ describe("table", function()
|
|||
assert.equal(2, table.keyof({[2] = "foo", [3] = "bar"}, "foo"))
|
||||
assert.equal(3, table.keyof({[1] = "foo", [3] = "bar"}, "bar"))
|
||||
end)
|
||||
|
||||
describe("copy()", function()
|
||||
it("strips metatables", function()
|
||||
local v = vector.new(1, 2, 3)
|
||||
local w = table.copy(v)
|
||||
assert.are_not.equal(v, w)
|
||||
assert.same(v, w)
|
||||
assert.equal(nil, getmetatable(w))
|
||||
end)
|
||||
it("preserves referential structure", function()
|
||||
local t = {{}, {}}
|
||||
t[1][1] = t[2]
|
||||
t[2][1] = t[1]
|
||||
local copy = table.copy(t)
|
||||
assert.same(t, copy)
|
||||
assert.equal(copy[1][1], copy[2])
|
||||
assert.equal(copy[2][1], copy[1])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("copy_with_metatables()", function()
|
||||
it("preserves metatables", function()
|
||||
local v = vector.new(1, 2, 3)
|
||||
local w = table.copy_with_metatables(v)
|
||||
assert.equal(getmetatable(v), getmetatable(w))
|
||||
assert(vector.check(w))
|
||||
assert.equal(v, w) -- vector overrides ==
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("formspec_escape", function()
|
||||
|
@ -201,3 +230,124 @@ describe("math", function()
|
|||
assert.equal(0, math.round(-0.49999999999999994))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("dump", function()
|
||||
local function test_expression(expr)
|
||||
local chunk = assert(loadstring("return " .. expr))
|
||||
local refs = {}
|
||||
setfenv(chunk, {
|
||||
setref = function(id)
|
||||
refs[id] = {}
|
||||
return function(fields)
|
||||
for k, v in pairs(fields) do
|
||||
refs[id][k] = v
|
||||
end
|
||||
return refs[id]
|
||||
end
|
||||
end,
|
||||
getref = function(id)
|
||||
return assert(refs[id])
|
||||
end,
|
||||
})
|
||||
assert.equal(expr, dump(chunk()))
|
||||
end
|
||||
|
||||
it("nil", function()
|
||||
test_expression("nil")
|
||||
end)
|
||||
|
||||
it("booleans", function()
|
||||
test_expression("false")
|
||||
test_expression("true")
|
||||
end)
|
||||
|
||||
describe("numbers", function()
|
||||
it("formats integers nicely", function()
|
||||
test_expression("42")
|
||||
end)
|
||||
it("avoids misleading rounding", function()
|
||||
test_expression("0.3")
|
||||
assert.equal("0.30000000000000004", dump(0.1 + 0.2))
|
||||
end)
|
||||
end)
|
||||
|
||||
it("strings", function()
|
||||
test_expression('"hello world"')
|
||||
test_expression([["hello \"world\""]])
|
||||
end)
|
||||
|
||||
describe("tables", function()
|
||||
it("empty", function()
|
||||
test_expression("{}")
|
||||
end)
|
||||
|
||||
it("lists", function()
|
||||
test_expression([[
|
||||
{
|
||||
false,
|
||||
true,
|
||||
"foo",
|
||||
1,
|
||||
2,
|
||||
}]])
|
||||
end)
|
||||
|
||||
it("number keys", function()
|
||||
test_expression([[
|
||||
{
|
||||
[0.5] = false,
|
||||
[1.5] = true,
|
||||
[2.5] = "foo",
|
||||
}]])
|
||||
end)
|
||||
|
||||
it("dicts", function()
|
||||
test_expression([[{
|
||||
a = 1,
|
||||
b = 2,
|
||||
c = 3,
|
||||
}]])
|
||||
end)
|
||||
|
||||
it("mixed", function()
|
||||
test_expression([[{
|
||||
a = 1,
|
||||
b = 2,
|
||||
c = 3,
|
||||
["d e"] = true,
|
||||
"foo",
|
||||
"bar",
|
||||
}]])
|
||||
end)
|
||||
|
||||
it("nested", function()
|
||||
test_expression([[{
|
||||
a = {
|
||||
1,
|
||||
{},
|
||||
},
|
||||
b = "foo",
|
||||
c = {
|
||||
[0.5] = 0.1,
|
||||
[1.5] = 0.2,
|
||||
},
|
||||
}]])
|
||||
end)
|
||||
|
||||
it("circular references", function()
|
||||
test_expression([[setref(1){
|
||||
child = {
|
||||
parent = getref(1),
|
||||
},
|
||||
other_child = {
|
||||
parent = getref(1),
|
||||
},
|
||||
}]])
|
||||
end)
|
||||
|
||||
it("supports variable indent", function()
|
||||
assert.equal('{1,2,3,{foo = "bar",},}', dump({1, 2, 3, {foo = "bar"}}, ""))
|
||||
assert.equal('{\n "x",\n "y",\n}', dump({"x", "y"}, " "))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
|
@ -93,7 +93,16 @@ describe("serialize", function()
|
|||
assert_preserves(test_in)
|
||||
end)
|
||||
|
||||
it("strips functions in safe mode", function()
|
||||
describe("safe mode", function()
|
||||
setup(function()
|
||||
assert(not core.log)
|
||||
-- logging a deprecation warning will be attempted
|
||||
function core.log() end
|
||||
end)
|
||||
teardown(function()
|
||||
core.log = nil
|
||||
end)
|
||||
it("functions are stripped", function()
|
||||
local test_in = {
|
||||
func = function(a, b)
|
||||
error("test")
|
||||
|
@ -109,6 +118,25 @@ describe("serialize", function()
|
|||
assert.is_nil(test_out.func)
|
||||
assert.equals(test_out.foo, "bar")
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("deprecation warnings", function()
|
||||
before_each(function()
|
||||
assert(not core.log)
|
||||
core.log = spy.new(function(level)
|
||||
assert(level == "deprecated")
|
||||
end)
|
||||
end)
|
||||
after_each(function()
|
||||
core.log = nil
|
||||
end)
|
||||
it("dumping functions", function()
|
||||
local t = {f = function() end, g = function() end}
|
||||
t.t = t
|
||||
core.serialize(t)
|
||||
assert.spy(core.log).was.called(1) -- should have been called exactly *once*
|
||||
end)
|
||||
end)
|
||||
|
||||
it("vectors work", function()
|
||||
local v = vector.new(1, 2, 3)
|
||||
|
|
|
@ -33,7 +33,7 @@ function core.get_node(pos)
|
|||
return core.vmanip:get_node_at(pos)
|
||||
end
|
||||
|
||||
function core.get_perlin(seed, octaves, persist, spread)
|
||||
function core.get_value_noise(seed, octaves, persist, spread)
|
||||
local params
|
||||
if type(seed) == "table" then
|
||||
params = table.copy(seed)
|
||||
|
@ -47,12 +47,18 @@ function core.get_perlin(seed, octaves, persist, spread)
|
|||
}
|
||||
end
|
||||
params.seed = core.get_seed(params.seed) -- add mapgen seed
|
||||
return PerlinNoise(params)
|
||||
return ValueNoise(params)
|
||||
end
|
||||
|
||||
|
||||
function core.get_perlin_map(params, size)
|
||||
function core.get_value_noise_map(params, size)
|
||||
local params2 = table.copy(params)
|
||||
params2.seed = core.get_seed(params.seed) -- add mapgen seed
|
||||
return PerlinNoiseMap(params2, size)
|
||||
return ValueNoiseMap(params2, size)
|
||||
end
|
||||
|
||||
-- deprecated as of 5.12, as it was not Perlin noise
|
||||
-- but with no warnings (yet) for compatibility
|
||||
core.get_perlin = core.get_value_noise
|
||||
core.get_perlin_map = core.get_value_noise_map
|
||||
PerlinNoise = ValueNoise
|
||||
PerlinNoiseMap = ValueNoiseMap
|
||||
|
|
|
@ -9,8 +9,8 @@ do
|
|||
all.registered_craftitems = {}
|
||||
all.registered_tools = {}
|
||||
for k, v in pairs(all.registered_items) do
|
||||
-- Disable further modification
|
||||
setmetatable(v, {__newindex = {}})
|
||||
-- Ignore new keys
|
||||
setmetatable(v, {__newindex = function() end})
|
||||
-- Reassemble the other tables
|
||||
if v.type == "node" then
|
||||
getmetatable(v).__index = all.nodedef_default
|
||||
|
@ -36,6 +36,9 @@ end
|
|||
local alias_metatable = {
|
||||
__index = function(t, name)
|
||||
return rawget(t, core.registered_aliases[name])
|
||||
end,
|
||||
__newindex = function()
|
||||
error("table is read-only")
|
||||
end
|
||||
}
|
||||
setmetatable(core.registered_items, alias_metatable)
|
||||
|
|
|
@ -1,20 +1,7 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--Copyright (C) 2023 Gregor Parzefall
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- Copyright (C) 2023 Gregor Parzefall
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local BASE_SPACING = 0.1
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--this program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local function dialog_event_handler(self,event)
|
||||
if self.user_eventhandler == nil or
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
ui = {}
|
||||
ui.childlist = {}
|
||||
|
@ -179,6 +166,10 @@ end
|
|||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
core.button_handler = function(fields)
|
||||
if fields["try_quit"] and not fields["key_enter"] then
|
||||
core.event_handler("MenuQuit")
|
||||
return
|
||||
end
|
||||
if fields["btn_reconnect_yes"] then
|
||||
gamedata.reconnect_requested = false
|
||||
gamedata.errormessage = nil
|
||||
|
|
|
@ -60,6 +60,8 @@ core.register_on_chat_message(function(name, message)
|
|||
|
||||
param = param or ""
|
||||
|
||||
core.log("verbose", string.format("Handling chat command %q with params %q", cmd, param))
|
||||
|
||||
-- Run core.registered_on_chatcommands callbacks.
|
||||
if core.run_callbacks(core.registered_on_chatcommands, 5, name, cmd, param) then
|
||||
return true
|
||||
|
@ -1275,7 +1277,7 @@ core.register_chatcommand("msg", {
|
|||
core.log("action", "DM from " .. name .. " to " .. sendto
|
||||
.. ": " .. message)
|
||||
core.chat_send_player(sendto, S("DM from @1: @2", name, message))
|
||||
return true, S("Message sent.")
|
||||
return true, S("DM sent to @1: @2", sendto, message)
|
||||
end,
|
||||
})
|
||||
|
||||
|
|
|
@ -61,3 +61,10 @@ function core.register_on_auth_fail(func)
|
|||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- deprecated as of 5.12, as it was not Perlin noise
|
||||
-- but with no warnings (yet) for compatibility
|
||||
core.get_perlin = core.get_value_noise
|
||||
core.get_perlin_map = core.get_value_noise_map
|
||||
PerlinNoise = ValueNoise
|
||||
PerlinNoiseMap = ValueNoiseMap
|
||||
|
|
|
@ -46,6 +46,7 @@ core.features = {
|
|||
biome_weights = true,
|
||||
particle_blend_clip = true,
|
||||
remove_item_match_meta = true,
|
||||
httpfetch_additional_methods = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
|
|
@ -360,13 +360,12 @@ end
|
|||
function core.item_drop(itemstack, dropper, pos)
|
||||
local dropper_is_player = dropper and dropper:is_player()
|
||||
local p = table.copy(pos)
|
||||
local cnt = itemstack:get_count()
|
||||
if dropper_is_player then
|
||||
p.y = p.y + 1.2
|
||||
end
|
||||
local item = itemstack:take_item(cnt)
|
||||
local obj = core.add_item(p, item)
|
||||
local obj = core.add_item(p, ItemStack(itemstack))
|
||||
if obj then
|
||||
itemstack:clear()
|
||||
if dropper_is_player then
|
||||
local dir = dropper:get_look_dir()
|
||||
dir.x = dir.x * 2.9
|
||||
|
@ -375,7 +374,7 @@ function core.item_drop(itemstack, dropper, pos)
|
|||
obj:set_velocity(dir)
|
||||
obj:get_luaentity().dropped_by = dropper:get_player_name()
|
||||
end
|
||||
return itemstack
|
||||
return itemstack, obj
|
||||
end
|
||||
-- If we reach this, adding the object to the
|
||||
-- environment failed
|
||||
|
@ -514,7 +513,8 @@ function core.node_dig(pos, node, digger)
|
|||
.. node.name .. " at " .. core.pos_to_string(pos))
|
||||
|
||||
local wielded = digger and digger:get_wielded_item()
|
||||
local drops = core.get_node_drops(node, wielded and wielded:get_name())
|
||||
local drops = core.get_node_drops(node, wielded and wielded:get_name(),
|
||||
wielded and ItemStack(wielded), digger, vector.copy(pos))
|
||||
|
||||
if wielded then
|
||||
local wdef = wielded:get_definition()
|
||||
|
|
|
@ -129,6 +129,7 @@ core.protocol_versions = {
|
|||
["5.9.1"] = 45,
|
||||
["5.10.0"] = 46,
|
||||
["5.11.0"] = 47,
|
||||
["5.12.0"] = 48,
|
||||
}
|
||||
|
||||
setmetatable(core.protocol_versions, {__newindex = function()
|
||||
|
|
|
@ -61,7 +61,7 @@ local function check_modname_prefix(name)
|
|||
return name:sub(2)
|
||||
else
|
||||
-- Enforce that the name starts with the correct mod name.
|
||||
local expected_prefix = core.get_current_modname() .. ":"
|
||||
local expected_prefix = (core.get_current_modname() or "") .. ":"
|
||||
if name:sub(1, #expected_prefix) ~= expected_prefix then
|
||||
error("Name " .. name .. " does not follow naming conventions: " ..
|
||||
"\"" .. expected_prefix .. "\" or \":\" prefix required")
|
||||
|
@ -95,6 +95,7 @@ function core.register_abm(spec)
|
|||
check_node_list(spec.nodenames, "nodenames")
|
||||
check_node_list(spec.neighbors, "neighbors")
|
||||
assert(type(spec.action) == "function", "Required field 'action' of type function")
|
||||
|
||||
core.registered_abms[#core.registered_abms + 1] = spec
|
||||
spec.mod_origin = core.get_current_modname() or "??"
|
||||
end
|
||||
|
@ -128,127 +129,51 @@ function core.register_entity(name, prototype)
|
|||
prototype.mod_origin = core.get_current_modname() or "??"
|
||||
end
|
||||
|
||||
function core.register_item(name, itemdef)
|
||||
-- Check name
|
||||
if name == nil then
|
||||
error("Unable to register item: Name is nil")
|
||||
end
|
||||
name = check_modname_prefix(tostring(name))
|
||||
if forbidden_item_names[name] then
|
||||
error("Unable to register item: Name is forbidden: " .. name)
|
||||
end
|
||||
itemdef.name = name
|
||||
|
||||
-- Apply defaults and add to registered_* table
|
||||
if itemdef.type == "node" then
|
||||
local function preprocess_node(nodedef)
|
||||
-- Use the nodebox as selection box if it's not set manually
|
||||
if itemdef.drawtype == "nodebox" and not itemdef.selection_box then
|
||||
itemdef.selection_box = itemdef.node_box
|
||||
elseif itemdef.drawtype == "fencelike" and not itemdef.selection_box then
|
||||
itemdef.selection_box = {
|
||||
if nodedef.drawtype == "nodebox" and not nodedef.selection_box then
|
||||
nodedef.selection_box = nodedef.node_box
|
||||
elseif nodedef.drawtype == "fencelike" and not nodedef.selection_box then
|
||||
nodedef.selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
|
||||
}
|
||||
end
|
||||
if itemdef.light_source and itemdef.light_source > core.LIGHT_MAX then
|
||||
itemdef.light_source = core.LIGHT_MAX
|
||||
|
||||
if nodedef.light_source and nodedef.light_source > core.LIGHT_MAX then
|
||||
nodedef.light_source = core.LIGHT_MAX
|
||||
core.log("warning", "Node 'light_source' value exceeds maximum," ..
|
||||
" limiting to maximum: " ..name)
|
||||
end
|
||||
setmetatable(itemdef, {__index = core.nodedef_default})
|
||||
core.registered_nodes[itemdef.name] = itemdef
|
||||
elseif itemdef.type == "craft" then
|
||||
setmetatable(itemdef, {__index = core.craftitemdef_default})
|
||||
core.registered_craftitems[itemdef.name] = itemdef
|
||||
elseif itemdef.type == "tool" then
|
||||
setmetatable(itemdef, {__index = core.tooldef_default})
|
||||
core.registered_tools[itemdef.name] = itemdef
|
||||
elseif itemdef.type == "none" then
|
||||
setmetatable(itemdef, {__index = core.noneitemdef_default})
|
||||
else
|
||||
error("Unable to register item: Type is invalid: " .. dump(itemdef))
|
||||
" limiting it: " .. nodedef.name)
|
||||
end
|
||||
|
||||
-- Flowing liquid uses param2
|
||||
if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
|
||||
itemdef.paramtype2 = "flowingliquid"
|
||||
if nodedef.liquidtype == "flowing" then
|
||||
nodedef.paramtype2 = "flowingliquid"
|
||||
end
|
||||
end
|
||||
|
||||
local function preprocess_craft(itemdef)
|
||||
-- BEGIN Legacy stuff
|
||||
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
|
||||
core.register_craft({
|
||||
type="cooking",
|
||||
output=itemdef.cookresult_itemstring,
|
||||
recipe=itemdef.name,
|
||||
cooktime=itemdef.furnace_cooktime
|
||||
})
|
||||
end
|
||||
if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
|
||||
core.register_craft({
|
||||
type="fuel",
|
||||
recipe=itemdef.name,
|
||||
burntime=itemdef.furnace_burntime
|
||||
})
|
||||
if itemdef.inventory_image == nil and itemdef.image ~= nil then
|
||||
core.log("deprecated", "The `image` field in craftitem definitions " ..
|
||||
"is deprecated. Use `inventory_image` instead. " ..
|
||||
"Craftitem name: " .. itemdef.name, 3)
|
||||
itemdef.inventory_image = itemdef.image
|
||||
end
|
||||
-- END Legacy stuff
|
||||
|
||||
itemdef.mod_origin = core.get_current_modname() or "??"
|
||||
|
||||
-- Disable all further modifications
|
||||
getmetatable(itemdef).__newindex = {}
|
||||
|
||||
--core.log("Registering item: " .. itemdef.name)
|
||||
core.registered_items[itemdef.name] = itemdef
|
||||
core.registered_aliases[itemdef.name] = nil
|
||||
register_item_raw(itemdef)
|
||||
end
|
||||
|
||||
function core.unregister_item(name)
|
||||
if not core.registered_items[name] then
|
||||
core.log("warning", "Not unregistering item " ..name..
|
||||
" because it doesn't exist.")
|
||||
return
|
||||
end
|
||||
-- Erase from registered_* table
|
||||
local type = core.registered_items[name].type
|
||||
if type == "node" then
|
||||
core.registered_nodes[name] = nil
|
||||
elseif type == "craft" then
|
||||
core.registered_craftitems[name] = nil
|
||||
elseif type == "tool" then
|
||||
core.registered_tools[name] = nil
|
||||
end
|
||||
core.registered_items[name] = nil
|
||||
|
||||
|
||||
unregister_item_raw(name)
|
||||
end
|
||||
|
||||
function core.register_node(name, nodedef)
|
||||
nodedef.type = "node"
|
||||
core.register_item(name, nodedef)
|
||||
end
|
||||
|
||||
function core.register_craftitem(name, craftitemdef)
|
||||
craftitemdef.type = "craft"
|
||||
|
||||
-- BEGIN Legacy stuff
|
||||
if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
|
||||
craftitemdef.inventory_image = craftitemdef.image
|
||||
end
|
||||
-- END Legacy stuff
|
||||
|
||||
core.register_item(name, craftitemdef)
|
||||
end
|
||||
|
||||
function core.register_tool(name, tooldef)
|
||||
tooldef.type = "tool"
|
||||
local function preprocess_tool(tooldef)
|
||||
tooldef.stack_max = 1
|
||||
|
||||
-- BEGIN Legacy stuff
|
||||
if tooldef.inventory_image == nil and tooldef.image ~= nil then
|
||||
core.log("deprecated", "The `image` field in tool definitions " ..
|
||||
"is deprecated. Use `inventory_image` instead. " ..
|
||||
"Tool name: " .. tooldef.name, 3)
|
||||
tooldef.inventory_image = tooldef.image
|
||||
end
|
||||
|
||||
if tooldef.tool_capabilities == nil and
|
||||
(tooldef.full_punch_interval ~= nil or
|
||||
tooldef.basetime ~= nil or
|
||||
|
@ -261,6 +186,9 @@ function core.register_tool(name, tooldef)
|
|||
tooldef.dd_crackiness ~= nil or
|
||||
tooldef.dd_crumbliness ~= nil or
|
||||
tooldef.dd_cuttability ~= nil) then
|
||||
core.log("deprecated", "Specifying tool capabilities directly in the tool " ..
|
||||
"definition is deprecated. Use the `tool_capabilities` field instead. " ..
|
||||
"Tool name: " .. tooldef.name, 3)
|
||||
tooldef.tool_capabilities = {
|
||||
full_punch_interval = tooldef.full_punch_interval,
|
||||
basetime = tooldef.basetime,
|
||||
|
@ -277,7 +205,7 @@ function core.register_tool(name, tooldef)
|
|||
end
|
||||
-- END Legacy stuff
|
||||
|
||||
-- This isn't just legacy, but more of a convenience feature
|
||||
-- Automatically set punch_attack_uses as a convenience feature
|
||||
local toolcaps = tooldef.tool_capabilities
|
||||
if toolcaps and toolcaps.punch_attack_uses == nil then
|
||||
for _, cap in pairs(toolcaps.groupcaps or {}) do
|
||||
|
@ -288,8 +216,126 @@ function core.register_tool(name, tooldef)
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
core.register_item(name, tooldef)
|
||||
local default_tables = {
|
||||
node = core.nodedef_default,
|
||||
craft = core.craftitemdef_default,
|
||||
tool = core.tooldef_default,
|
||||
none = core.noneitemdef_default,
|
||||
}
|
||||
|
||||
local preprocess_fns = {
|
||||
node = preprocess_node,
|
||||
craft = preprocess_craft,
|
||||
tool = preprocess_tool,
|
||||
}
|
||||
|
||||
function core.register_item(name, itemdef)
|
||||
-- Check name
|
||||
if name == nil then
|
||||
error("Unable to register item: Name is nil")
|
||||
end
|
||||
name = check_modname_prefix(tostring(name))
|
||||
if forbidden_item_names[name] then
|
||||
error("Unable to register item: Name is forbidden: " .. name)
|
||||
end
|
||||
|
||||
itemdef.name = name
|
||||
|
||||
-- Compatibility stuff depending on type
|
||||
local fn = preprocess_fns[itemdef.type]
|
||||
if fn then
|
||||
fn(itemdef)
|
||||
end
|
||||
|
||||
-- Apply defaults
|
||||
local defaults = default_tables[itemdef.type]
|
||||
if defaults == nil then
|
||||
error("Unable to register item: Type is invalid: " .. dump(itemdef))
|
||||
end
|
||||
local old_mt = getmetatable(itemdef)
|
||||
-- TODO most of these checks should become an error after a while (maybe in 2026?)
|
||||
if old_mt ~= nil and next(old_mt) ~= nil then
|
||||
-- Note that even registering multiple identical items with the same table
|
||||
-- is not allowed, due to the 'name' property.
|
||||
if old_mt.__index == defaults then
|
||||
core.log("warning", "Item definition table was reused between registrations. "..
|
||||
"This is unsupported and broken: " .. name)
|
||||
else
|
||||
core.log("warning", "Item definition has a metatable, this is "..
|
||||
"unsupported and it will be overwritten: " .. name)
|
||||
end
|
||||
end
|
||||
setmetatable(itemdef, {__index = defaults})
|
||||
|
||||
-- BEGIN Legacy stuff
|
||||
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
|
||||
core.log("deprecated", "The `cookresult_itemstring` item definition " ..
|
||||
"field is deprecated. Use `core.register_craft` instead. " ..
|
||||
"Item name: " .. itemdef.name, 2)
|
||||
core.register_craft({
|
||||
type="cooking",
|
||||
output=itemdef.cookresult_itemstring,
|
||||
recipe=itemdef.name,
|
||||
cooktime=itemdef.furnace_cooktime
|
||||
})
|
||||
end
|
||||
if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
|
||||
core.log("deprecated", "The `furnace_burntime` item definition " ..
|
||||
"field is deprecated. Use `core.register_craft` instead. " ..
|
||||
"Item name: " .. itemdef.name, 2)
|
||||
core.register_craft({
|
||||
type="fuel",
|
||||
recipe=itemdef.name,
|
||||
burntime=itemdef.furnace_burntime
|
||||
})
|
||||
end
|
||||
-- END Legacy stuff
|
||||
|
||||
itemdef.mod_origin = core.get_current_modname() or "??"
|
||||
|
||||
-- Ignore new keys as a failsafe to prevent mistakes
|
||||
getmetatable(itemdef).__newindex = function() end
|
||||
|
||||
-- Add to registered_* tables
|
||||
if itemdef.type == "node" then
|
||||
core.registered_nodes[itemdef.name] = itemdef
|
||||
elseif itemdef.type == "craft" then
|
||||
core.registered_craftitems[itemdef.name] = itemdef
|
||||
elseif itemdef.type == "tool" then
|
||||
core.registered_tools[itemdef.name] = itemdef
|
||||
end
|
||||
core.registered_items[itemdef.name] = itemdef
|
||||
core.registered_aliases[itemdef.name] = nil
|
||||
|
||||
register_item_raw(itemdef)
|
||||
end
|
||||
|
||||
local function make_register_item_wrapper(the_type)
|
||||
return function(name, itemdef)
|
||||
itemdef.type = the_type
|
||||
return core.register_item(name, itemdef)
|
||||
end
|
||||
end
|
||||
|
||||
core.register_node = make_register_item_wrapper("node")
|
||||
core.register_craftitem = make_register_item_wrapper("craft")
|
||||
core.register_tool = make_register_item_wrapper("tool")
|
||||
|
||||
function core.unregister_item(name)
|
||||
if not core.registered_items[name] then
|
||||
core.log("warning", "Not unregistering item " ..name..
|
||||
" because it doesn't exist.")
|
||||
return
|
||||
end
|
||||
-- Erase from registered_* table
|
||||
core.registered_nodes[name] = nil
|
||||
core.registered_craftitems[name] = nil
|
||||
core.registered_tools[name] = nil
|
||||
core.registered_items[name] = nil
|
||||
|
||||
unregister_item_raw(name)
|
||||
end
|
||||
|
||||
function core.register_alias(name, convert_to)
|
||||
|
@ -300,7 +346,6 @@ function core.register_alias(name, convert_to)
|
|||
core.log("warning", "Not registering alias, item with same name" ..
|
||||
" is already defined: " .. name .. " -> " .. convert_to)
|
||||
else
|
||||
--core.log("Registering alias: " .. name .. " -> " .. convert_to)
|
||||
core.registered_aliases[name] = convert_to
|
||||
register_alias_raw(name, convert_to)
|
||||
end
|
||||
|
@ -315,7 +360,6 @@ function core.register_alias_force(name, convert_to)
|
|||
core.log("info", "Removed item " ..name..
|
||||
" while attempting to force add an alias")
|
||||
end
|
||||
--core.log("Registering alias: " .. name .. " -> " .. convert_to)
|
||||
core.registered_aliases[name] = convert_to
|
||||
register_alias_raw(name, convert_to)
|
||||
end
|
||||
|
@ -406,6 +450,7 @@ core.register_item(":", {
|
|||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
local itemdefs_finalized = false
|
||||
|
||||
function core.override_item(name, redefinition, del_fields)
|
||||
if redefinition.name ~= nil then
|
||||
|
@ -418,10 +463,16 @@ function core.override_item(name, redefinition, del_fields)
|
|||
if not item then
|
||||
error("Attempt to override non-existent item "..name, 2)
|
||||
end
|
||||
if itemdefs_finalized then
|
||||
-- TODO: it's not clear if this needs to be allowed at all?
|
||||
core.log("warning", "Overriding item " .. name .. " after server startup. " ..
|
||||
"This is unsupported and can cause problems related to data inconsistency.")
|
||||
end
|
||||
for k, v in pairs(redefinition) do
|
||||
rawset(item, k, v)
|
||||
end
|
||||
for _, field in ipairs(del_fields or {}) do
|
||||
assert(field ~= "name" and field ~= "type")
|
||||
rawset(item, field, nil)
|
||||
end
|
||||
register_item_raw(item)
|
||||
|
@ -568,13 +619,57 @@ core.registered_on_rightclickplayers, core.register_on_rightclickplayer = make_r
|
|||
core.registered_on_liquid_transformed, core.register_on_liquid_transformed = make_registration()
|
||||
core.registered_on_mapblocks_changed, core.register_on_mapblocks_changed = make_registration()
|
||||
|
||||
-- A bunch of registrations are read by the C++ side once on env init, so we cannot
|
||||
-- allow them to change afterwards (see s_env.cpp).
|
||||
-- Nodes and items do not have this problem but there are obvious consistency
|
||||
-- problems if this would be allowed.
|
||||
|
||||
local function freeze_table(t)
|
||||
-- Freezing a Lua table is not actually possible without some very intrusive
|
||||
-- metatable hackery, but we can trivially prevent new additions.
|
||||
local mt = table.copy(getmetatable(t) or {})
|
||||
mt.__newindex = function()
|
||||
error("modification forbidden")
|
||||
end
|
||||
setmetatable(t, mt)
|
||||
end
|
||||
|
||||
local function generic_reg_error(what)
|
||||
return function(something)
|
||||
local described = what
|
||||
if type(something) == "table" and type(something.name) == "string" then
|
||||
described = what .. " " .. something.name
|
||||
elseif type(something) == "string" then
|
||||
described = what .. " " .. something
|
||||
end
|
||||
error("Tried to register " .. described .. " after load time!")
|
||||
end
|
||||
end
|
||||
|
||||
core.register_on_mods_loaded(function()
|
||||
core.after(0, function()
|
||||
setmetatable(core.registered_on_mapblocks_changed, {
|
||||
__newindex = function()
|
||||
error("on_mapblocks_changed callbacks must be registered at load time")
|
||||
end,
|
||||
})
|
||||
itemdefs_finalized = true
|
||||
|
||||
-- prevent direct modification
|
||||
freeze_table(core.registered_abms)
|
||||
freeze_table(core.registered_lbms)
|
||||
freeze_table(core.registered_items)
|
||||
freeze_table(core.registered_nodes)
|
||||
freeze_table(core.registered_craftitems)
|
||||
freeze_table(core.registered_tools)
|
||||
freeze_table(core.registered_aliases)
|
||||
freeze_table(core.registered_on_mapblocks_changed)
|
||||
|
||||
-- neutralize registration functions
|
||||
core.register_abm = generic_reg_error("ABM")
|
||||
core.register_lbm = generic_reg_error("LBM")
|
||||
core.register_item = generic_reg_error("item")
|
||||
core.unregister_item = function(name)
|
||||
error("Refusing to unregister item " .. name .. " after load time")
|
||||
end
|
||||
core.register_alias = generic_reg_error("alias")
|
||||
core.register_alias_force = generic_reg_error("alias")
|
||||
core.register_on_mapblocks_changed = generic_reg_error("on_mapblocks_changed callback")
|
||||
end)
|
||||
end)
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
-- Global menu data
|
||||
menudata = {}
|
||||
|
@ -34,7 +21,6 @@ function check_cache_age(key, max_age)
|
|||
end
|
||||
|
||||
function core.on_before_close()
|
||||
-- called before the menu is closed, either exit or to join a game
|
||||
cache_settings:write()
|
||||
end
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2018-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2018-24 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
if not core.get_http_api then
|
||||
return
|
||||
|
@ -41,6 +28,7 @@ contentdb = {
|
|||
REASON_DEPENDENCY = "dependency",
|
||||
}
|
||||
|
||||
-- API documentation: https://content.luanti.org/help/api/
|
||||
|
||||
local function get_download_url(package, reason)
|
||||
local base_url = core.settings:get("contentdb_url")
|
||||
|
@ -182,14 +170,16 @@ function contentdb.get_package_by_id(id)
|
|||
end
|
||||
|
||||
|
||||
function contentdb.calculate_package_id(type, author, name)
|
||||
local id = author:lower() .. "/"
|
||||
local function strip_game_suffix(type, name)
|
||||
if (type == nil or type == "game") and #name > 5 and name:sub(#name - 4) == "_game" then
|
||||
id = id .. name:sub(1, #name - 5)
|
||||
return name:sub(1, #name - 5)
|
||||
else
|
||||
id = id .. name
|
||||
return name
|
||||
end
|
||||
return id
|
||||
end
|
||||
|
||||
function contentdb.calculate_package_id(type, author, name)
|
||||
return author:lower() .. "/" .. strip_game_suffix(type, name)
|
||||
end
|
||||
|
||||
|
||||
|
@ -398,7 +388,6 @@ local function fetch_pkgs()
|
|||
local url = base_url ..
|
||||
"/api/packages/?type=mod&type=game&type=txp&protocol_version=" ..
|
||||
core.get_max_supp_proto() .. "&engine_version=" .. core.urlencode(version.string)
|
||||
|
||||
for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do
|
||||
item = item:trim()
|
||||
if item ~= "" then
|
||||
|
@ -406,19 +395,11 @@ local function fetch_pkgs()
|
|||
end
|
||||
end
|
||||
|
||||
local languages
|
||||
local current_language = core.get_language()
|
||||
if current_language ~= "" then
|
||||
languages = { current_language, "en;q=0.8" }
|
||||
else
|
||||
languages = { "en" }
|
||||
end
|
||||
|
||||
local http = core.get_http_api()
|
||||
local response = http.fetch_sync({
|
||||
url = url,
|
||||
extra_headers = {
|
||||
"Accept-Language: " .. table.concat(languages, ", ")
|
||||
core.get_http_accept_languages()
|
||||
},
|
||||
})
|
||||
if not response.succeeded then
|
||||
|
@ -448,7 +429,7 @@ function contentdb.set_packages_from_api(packages)
|
|||
-- We currently don't support name changing
|
||||
local suffix = "/" .. package.name
|
||||
if alias:sub(-#suffix) == suffix then
|
||||
contentdb.aliases[alias:lower()] = package.id
|
||||
contentdb.aliases[strip_game_suffix(packages.type, alias:lower())] = package.id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -596,27 +577,19 @@ function contentdb.filter_packages(query, by_type)
|
|||
end
|
||||
|
||||
|
||||
function contentdb.get_full_package_info(package, callback)
|
||||
local function get_package_info(key, path)
|
||||
return function(package, callback)
|
||||
assert(package)
|
||||
if package.full_info then
|
||||
callback(package.full_info)
|
||||
if package[key] then
|
||||
callback(package[key])
|
||||
return
|
||||
end
|
||||
|
||||
local function fetch(params)
|
||||
local version = core.get_version()
|
||||
local base_url = core.settings:get("contentdb_url")
|
||||
|
||||
local languages
|
||||
local current_language = core.get_language()
|
||||
if current_language ~= "" then
|
||||
languages = { current_language, "en;q=0.8" }
|
||||
else
|
||||
languages = { "en" }
|
||||
end
|
||||
|
||||
local url = base_url ..
|
||||
"/api/packages/" .. params.package.url_part .. "/for-client/?" ..
|
||||
"/api/packages/" .. params.package.url_part .. params.path .. "?" ..
|
||||
"protocol_version=" .. core.urlencode(core.get_max_supp_proto()) ..
|
||||
"&engine_version=" .. core.urlencode(version.string) ..
|
||||
"&formspec_version=" .. core.urlencode(core.get_formspec_version()) ..
|
||||
|
@ -625,7 +598,7 @@ function contentdb.get_full_package_info(package, callback)
|
|||
local response = http.fetch_sync({
|
||||
url = url,
|
||||
extra_headers = {
|
||||
"Accept-Language: " .. table.concat(languages, ", ")
|
||||
core.get_http_accept_languages()
|
||||
},
|
||||
})
|
||||
if not response.succeeded then
|
||||
|
@ -636,17 +609,22 @@ function contentdb.get_full_package_info(package, callback)
|
|||
end
|
||||
|
||||
local function my_callback(value)
|
||||
package.full_info = value
|
||||
package[key] = value
|
||||
callback(value)
|
||||
end
|
||||
|
||||
if not core.handle_async(fetch, { package = package }, my_callback) then
|
||||
if not core.handle_async(fetch, { package = package, path = path }, my_callback) then
|
||||
core.log("error", "ERROR: async event failed")
|
||||
callback(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
contentdb.get_full_package_info = get_package_info("full_info", "/for-client/")
|
||||
contentdb.get_package_reviews = get_package_info("reviews", "/for-client/reviews/")
|
||||
|
||||
|
||||
function contentdb.get_formspec_padding()
|
||||
-- Padding is increased on Android to account for notches
|
||||
-- TODO: use Android API to determine size of cut outs
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2018-20 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2018-20 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
if not core.get_http_api then
|
||||
function create_contentdb_dlg()
|
||||
|
@ -323,9 +310,17 @@ local function get_formspec(dlgdata)
|
|||
})
|
||||
local img_w = cell_h * 3 / 2
|
||||
|
||||
-- Use as much of the available space as possible (so no padding on the
|
||||
-- right/bottom), but don't quite allow the text to touch the border.
|
||||
local text_w = cell_w - img_w - 0.25 - 0.025
|
||||
local text_h = cell_h - 0.25 - 0.025
|
||||
|
||||
local start_idx = (cur_page - 1) * num_per_page + 1
|
||||
for i=start_idx, math.min(#contentdb.packages, start_idx+num_per_page-1) do
|
||||
local package = contentdb.packages[i]
|
||||
local text = core.colorize(mt_color_green, package.title) ..
|
||||
core.colorize("#BFBFBF", " by " .. package.author) .. "\n" ..
|
||||
package.short_description
|
||||
|
||||
table.insert_all(formspec, {
|
||||
"container[",
|
||||
|
@ -340,13 +335,14 @@ local function get_formspec(dlgdata)
|
|||
"image[0,0;", img_w, ",", cell_h, ";",
|
||||
core.formspec_escape(get_screenshot(package, package.thumbnail, 2)), "]",
|
||||
|
||||
"label[", img_w + 0.25 + 0.05, ",0.5;",
|
||||
core.formspec_escape(
|
||||
core.colorize(mt_color_green, package.title) ..
|
||||
core.colorize("#BFBFBF", " by " .. package.author)), "]",
|
||||
"label[", img_w + 0.25, ",0.25;", text_w, ",", text_h, ";",
|
||||
core.formspec_escape(text), "]",
|
||||
|
||||
"textarea[", img_w + 0.25, ",0.75;", cell_w - img_w - 0.25, ",", cell_h - 0.75, ";;;",
|
||||
core.formspec_escape(package.short_description), "]",
|
||||
-- Add a tooltip in case the label overflows and the short description is cut off.
|
||||
"tooltip[", img_w + 0.25, ",0.25;", text_w, ",", text_h, ";",
|
||||
-- Text in tooltips doesn't wrap automatically, so we do it manually to
|
||||
-- avoid everything being one long line.
|
||||
core.formspec_escape(core.wrap_text(package.short_description, 80)), "]",
|
||||
|
||||
"style[view_", i, ";border=false]",
|
||||
"style[view_", i, ":hovered;bgimg=", core.formspec_escape(defaulttexturedir .. "button_hover_semitrans.png"), "]",
|
||||
|
@ -362,7 +358,7 @@ local function get_formspec(dlgdata)
|
|||
end
|
||||
|
||||
table.insert_all(formspec, {
|
||||
"container[", cell_w - 0.625,",", 0.25, "]",
|
||||
"container[", cell_w - 0.625,",", 0.125, "]",
|
||||
})
|
||||
|
||||
if package.downloading then
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2018-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2018-24 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local function is_still_visible(dlg)
|
||||
local this = ui.find_by_name("install_dialog")
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2018-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2018-24 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
function get_formspec(data)
|
||||
local package = data.package
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2018-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2018-24 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local function get_info_formspec(size, padding, text)
|
||||
|
@ -32,6 +19,7 @@ end
|
|||
|
||||
|
||||
local function get_formspec(data)
|
||||
local package = data.package
|
||||
local window_padding = contentdb.get_formspec_padding()
|
||||
local size = contentdb.get_formspec_size()
|
||||
size.x = math.min(size.x, 20)
|
||||
|
@ -42,7 +30,7 @@ local function get_formspec(data)
|
|||
if not data.loading and not data.loading_error then
|
||||
data.loading = true
|
||||
|
||||
contentdb.get_full_package_info(data.package, function(info)
|
||||
contentdb.get_full_package_info(package, function(info)
|
||||
data.loading = false
|
||||
|
||||
if info == nil then
|
||||
|
@ -61,7 +49,7 @@ local function get_formspec(data)
|
|||
-- check to see if that happened
|
||||
if not data.info then
|
||||
if data.loading_error then
|
||||
return get_info_formspec(size, window_padding, fgettext("No packages could be retrieved"))
|
||||
return get_info_formspec(size, window_padding, fgettext("Error loading package information"))
|
||||
end
|
||||
return get_info_formspec(size, window_padding, fgettext("Loading..."))
|
||||
end
|
||||
|
@ -103,15 +91,15 @@ local function get_formspec(data)
|
|||
|
||||
local left_button_rect = "0,0;2.875,1"
|
||||
local right_button_rect = "3.125,0;2.875,1"
|
||||
if data.package.downloading then
|
||||
if package.downloading then
|
||||
formspec[#formspec + 1] = "animated_image[5,0;1,1;downloading;"
|
||||
formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
|
||||
formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
|
||||
elseif data.package.queued then
|
||||
elseif package.queued then
|
||||
formspec[#formspec + 1] = "style[queued;border=false]"
|
||||
formspec[#formspec + 1] = "image_button[5,0;1,1;" .. core.formspec_escape(defaulttexturedir)
|
||||
formspec[#formspec + 1] = "cdb_queued.png;queued;]"
|
||||
elseif not data.package.path then
|
||||
elseif not package.path then
|
||||
formspec[#formspec + 1] = "style[install;bgcolor=green]"
|
||||
formspec[#formspec + 1] = "button["
|
||||
formspec[#formspec + 1] = right_button_rect
|
||||
|
@ -119,7 +107,7 @@ local function get_formspec(data)
|
|||
formspec[#formspec + 1] = fgettext("Install [$1]", info.download_size)
|
||||
formspec[#formspec + 1] = "]"
|
||||
else
|
||||
if data.package.installed_release < data.package.release then
|
||||
if package.installed_release < package.release then
|
||||
-- The install_ action also handles updating
|
||||
formspec[#formspec + 1] = "style[install;bgcolor=#28ccdf]"
|
||||
formspec[#formspec + 1] = "button["
|
||||
|
@ -137,10 +125,12 @@ local function get_formspec(data)
|
|||
formspec[#formspec + 1] = "]"
|
||||
end
|
||||
|
||||
local review_count = info.reviews.positive + info.reviews.neutral + info.reviews.negative
|
||||
local current_tab = data.current_tab or 1
|
||||
local tab_titles = {
|
||||
fgettext("Description"),
|
||||
fgettext("Information"),
|
||||
fgettext("Reviews") .. core.formspec_escape(" [" .. review_count .. "]"),
|
||||
}
|
||||
|
||||
local tab_body_height = bottom_buttons_y - 2.8
|
||||
|
@ -162,8 +152,8 @@ local function get_formspec(data)
|
|||
local winfo = core.get_window_info()
|
||||
local fs_to_px = winfo.size.x / winfo.max_formspec_size.x
|
||||
for i, ss in ipairs(info.screenshots) do
|
||||
local path = get_screenshot(data.package, ss.url, 2)
|
||||
hypertext = hypertext .. "<action name=\"ss_" .. i .. "\"><img name=\"" ..
|
||||
local path = get_screenshot(package, ss.url, 2)
|
||||
hypertext = hypertext .. "<action name=\"ss_".. i .. "\"><img name=\"" ..
|
||||
core.hypertext_escape(path) .. "\" width=" .. (3 * fs_to_px) ..
|
||||
" height=" .. (2 * fs_to_px) .. "></action>"
|
||||
if i ~= #info.screenshots then
|
||||
|
@ -194,22 +184,54 @@ local function get_formspec(data)
|
|||
|
||||
hypertext = hypertext .. "\n\n" .. info.long_description.body
|
||||
|
||||
-- Fix the path to blank.png. This is needed for bullet indentation.
|
||||
hypertext = hypertext:gsub("<img name=\"?blank.png\"? ",
|
||||
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "blank.png\" ")
|
||||
|
||||
table.insert_all(formspec, {
|
||||
"hypertext[0,0;", W, ",", tab_body_height - 0.375,
|
||||
";desc;", core.formspec_escape(hypertext), "]",
|
||||
|
||||
})
|
||||
|
||||
elseif current_tab == 2 then
|
||||
local hypertext = info.info_hypertext.head .. info.info_hypertext.body
|
||||
|
||||
table.insert_all(formspec, {
|
||||
"hypertext[0,0;", W, ",", tab_body_height - 0.375,
|
||||
";info;", core.formspec_escape(hypertext), "]",
|
||||
})
|
||||
elseif current_tab == 3 then
|
||||
if not package.reviews and not data.reviews_error and not data.reviews_loading then
|
||||
data.reviews_loading = true
|
||||
|
||||
contentdb.get_package_reviews(package, function(reviews)
|
||||
if not reviews then
|
||||
data.reviews_error = true
|
||||
end
|
||||
ui.update()
|
||||
end)
|
||||
end
|
||||
|
||||
if package.reviews then
|
||||
local hypertext = package.reviews.head .. package.reviews.body
|
||||
-- Provide correct path to blank.png image. This is needed for bullet indentation.
|
||||
hypertext = hypertext:gsub("<img name=\"?blank.png\"? ",
|
||||
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "blank.png\" ")
|
||||
-- Placeholders in reviews hypertext for icons
|
||||
hypertext = hypertext:gsub("<thumbsup>",
|
||||
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "contentdb_thumb_up.png\" width=24>")
|
||||
hypertext = hypertext:gsub("<thumbsdown>",
|
||||
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "contentdb_thumb_down.png\" width=24>")
|
||||
hypertext = hypertext:gsub("<neutral>",
|
||||
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "contentdb_neutral.png\" width=24>")
|
||||
table.insert_all(formspec, {
|
||||
"hypertext[0,0;", W, ",", tab_body_height - 0.375,
|
||||
";reviews;", core.formspec_escape(hypertext), "]",
|
||||
})
|
||||
elseif data.reviews_error then
|
||||
table.insert_all(formspec, {"label[2,2;", fgettext("Error loading reviews"), "]"} )
|
||||
else
|
||||
table.insert_all(formspec, {"label[2,2;", fgettext("Loading..."), "]"} )
|
||||
end
|
||||
else
|
||||
error("Unknown tab " .. current_tab)
|
||||
end
|
||||
|
@ -269,9 +291,10 @@ local function handle_submit(this, fields)
|
|||
end
|
||||
|
||||
if fields.open_contentdb then
|
||||
local url = ("%s/packages/%s/?protocol_version=%d"):format(
|
||||
core.settings:get("contentdb_url"), package.url_part,
|
||||
core.get_max_supp_proto())
|
||||
local version = core.get_version()
|
||||
local url = core.settings:get("contentdb_url") .. "/packages/" .. package.url_part ..
|
||||
"/?protocol_version=" .. core.urlencode(core.get_max_supp_proto()) ..
|
||||
"&engine_version=" .. core.urlencode(version.string)
|
||||
core.open_url(url)
|
||||
return true
|
||||
end
|
||||
|
@ -295,7 +318,8 @@ local function handle_submit(this, fields)
|
|||
end
|
||||
|
||||
if handle_hypertext_event(this, fields.desc, info.long_description) or
|
||||
handle_hypertext_event(this, fields.info, info.info_hypertext) then
|
||||
handle_hypertext_event(this, fields.info, info.info_hypertext) or
|
||||
(package.reviews and handle_hypertext_event(this, fields.reviews, package.reviews)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2023 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2023 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local path = core.get_mainmenu_path() .. DIR_DELIM .. "content"
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2013 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function get_last_folder(text,count)
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2023-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2023-24 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
-- Screenshot
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2022 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local mods_dir = "/tmp/.minetest/mods"
|
||||
local games_dir = "/tmp/.minetest/games"
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2023 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2023 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
update_detector = {}
|
||||
|
|
|
@ -47,22 +47,20 @@
|
|||
],
|
||||
"#": "For updating active/previous contributors, see the script in ./util/gather_git_credits.py",
|
||||
"contributors": [
|
||||
"JosiahWI",
|
||||
"Erich Schubert",
|
||||
"wrrrzr",
|
||||
"1F616EMO",
|
||||
"red-001 <red-001@outlook.ie>",
|
||||
"veprogames",
|
||||
"paradust7",
|
||||
"AFCMS",
|
||||
"siliconsniffer",
|
||||
"Wuzzy",
|
||||
"Zemtzov7",
|
||||
"JosiahWI",
|
||||
"veprogames",
|
||||
"Miguel P.L",
|
||||
"AFCMS"
|
||||
],
|
||||
"previous_contributors": [
|
||||
"Ælla Chiana Moskopp (erle) <erle@dieweltistgarnichtso.net> [Logo]",
|
||||
"numzero",
|
||||
"red-001 <red-001@outlook.ie>",
|
||||
"Giuseppe Bilotta",
|
||||
"HybridDog",
|
||||
"ClobberXD",
|
||||
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
|
||||
"MirceaKitsune <mirceakitsune@gmail.com>",
|
||||
|
@ -75,6 +73,7 @@
|
|||
"stujones11",
|
||||
"Rogier <rogier777@gmail.com>",
|
||||
"Gregory Currie (gregorycu)",
|
||||
"paradust7",
|
||||
"JacobF",
|
||||
"Jeija <jeija@mesecons.net>"
|
||||
]
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2013 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local function table_to_flags(ftable)
|
||||
-- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves"
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local function delete_world_formspec(dialogdata)
|
||||
|
|
108
builtin/mainmenu/dlg_rebind_keys.lua
Normal file
108
builtin/mainmenu/dlg_rebind_keys.lua
Normal file
|
@ -0,0 +1,108 @@
|
|||
-- Luanti
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
-- Modified based on dlg_reinstall_mtg.lua
|
||||
-- Note that this is only needed for migrating from <5.11 to 5.12.
|
||||
|
||||
local doc_url = "https://docs.luanti.org/for-players/controls/"
|
||||
local SETTING_NAME = "no_keycode_migration_warning"
|
||||
|
||||
local function get_formspec(dialogdata)
|
||||
local markup = table.concat({
|
||||
"<big>" .. hgettext("Keybindings changed") .. "</big>",
|
||||
hgettext("The input handling system was reworked in Luanti 5.12.0."),
|
||||
hgettext("As a result, your keybindings may have been changed."),
|
||||
hgettext("Check out the key settings or refer to the documentation:"),
|
||||
("<action name='doc_url'><style color='cyan' hovercolor='orangered'>%s</style></action>"):format(doc_url),
|
||||
}, "\n")
|
||||
|
||||
return table.concat({
|
||||
"formspec_version[6]",
|
||||
"size[12,7]",
|
||||
"hypertext[0.5,0.5;11,4.7;text;", core.formspec_escape(markup), "]",
|
||||
"container[0.5,5.7]",
|
||||
"button[0,0;4,0.8;dismiss;", fgettext("Close"), "]",
|
||||
"button[4.5,0;6.5,0.8;reconfigure;", fgettext("Open settings"), "]",
|
||||
"container_end[]",
|
||||
})
|
||||
end
|
||||
|
||||
local function close_dialog(this)
|
||||
cache_settings:set_bool(SETTING_NAME, true)
|
||||
this:delete()
|
||||
end
|
||||
|
||||
local function buttonhandler(this, fields)
|
||||
if fields.reconfigure then
|
||||
close_dialog(this)
|
||||
|
||||
local maintab = ui.find_by_name("maintab")
|
||||
|
||||
local dlg = create_settings_dlg("controls_keyboard_and_mouse")
|
||||
dlg:set_parent(maintab)
|
||||
maintab:hide()
|
||||
dlg:show()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.dismiss then
|
||||
close_dialog(this)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.text == "action:doc_url" then
|
||||
core.open_url(doc_url)
|
||||
end
|
||||
end
|
||||
|
||||
local function eventhandler(event)
|
||||
if event == "DialogShow" then
|
||||
mm_game_theme.set_engine()
|
||||
return true
|
||||
elseif event == "MenuQuit" then
|
||||
-- Don't allow closing the dialog with ESC, but still allow exiting
|
||||
-- Luanti
|
||||
core.close()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function create_rebind_keys_dlg()
|
||||
local dlg = dialog_create("dlg_rebind_keys", get_formspec,
|
||||
buttonhandler, eventhandler)
|
||||
return dlg
|
||||
end
|
||||
|
||||
function migrate_keybindings()
|
||||
-- Show migration dialog if the user upgraded from an earlier version
|
||||
-- and this has not yet been shown before, *or* if keys settings had to be changed
|
||||
if core.is_first_run then
|
||||
cache_settings:set_bool(SETTING_NAME, true)
|
||||
end
|
||||
local has_migration = not cache_settings:get_bool(SETTING_NAME)
|
||||
|
||||
-- normalize all existing key settings, this converts them from KEY_KEY_C to SYSTEM_SCANCODE_6
|
||||
local settings = core.settings:to_table()
|
||||
for name, value in pairs(settings) do
|
||||
if name:match("^keymap_") then
|
||||
local normalized = core.normalize_keycode(value)
|
||||
if value ~= normalized then
|
||||
has_migration = true
|
||||
core.settings:set(name, normalized)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not has_migration then
|
||||
return
|
||||
end
|
||||
|
||||
local maintab = ui.find_by_name("maintab")
|
||||
|
||||
local dlg = create_rebind_keys_dlg()
|
||||
dlg:set_parent(maintab)
|
||||
maintab:hide()
|
||||
dlg:show()
|
||||
ui.update()
|
||||
end
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2022 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2023 Gregor Parzefall
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2023 Gregor Parzefall
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
---- IMPORTANT ----
|
||||
-- This whole file can be removed after a while.
|
||||
|
@ -67,10 +54,10 @@ end
|
|||
|
||||
local function get_formspec(dialogdata)
|
||||
local markup = table.concat({
|
||||
"<big>", fgettext("Minetest Game is no longer installed by default"), "</big>\n",
|
||||
fgettext("For a long time, Luanti shipped with a default game called \"Minetest Game\". " ..
|
||||
"<big>", hgettext("Minetest Game is no longer installed by default"), "</big>\n",
|
||||
hgettext("For a long time, Luanti shipped with a default game called \"Minetest Game\". " ..
|
||||
"Since version 5.8.0, Luanti ships without a default game."), "\n",
|
||||
fgettext("If you want to continue playing in your Minetest Game worlds, you need to reinstall Minetest Game."),
|
||||
hgettext("If you want to continue playing in your Minetest Game worlds, you need to reinstall Minetest Game."),
|
||||
})
|
||||
|
||||
return table.concat({
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2013 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
mm_game_theme = {}
|
||||
|
|
|
@ -1,27 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
mt_color_grey = "#AAAAAA"
|
||||
mt_color_blue = "#6389FF"
|
||||
mt_color_lightblue = "#99CCFF"
|
||||
mt_color_green = "#72FF63"
|
||||
mt_color_dark_green = "#25C191"
|
||||
mt_color_orange = "#FF8800"
|
||||
mt_color_red = "#FF3300"
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
MAIN_TAB_W = 15.5
|
||||
MAIN_TAB_H = 7.1
|
||||
|
@ -35,6 +14,7 @@ local basepath = core.get_builtin_path()
|
|||
defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
|
||||
DIR_DELIM .. "pack" .. DIR_DELIM
|
||||
|
||||
dofile(basepath .. "common" .. DIR_DELIM .. "menu.lua")
|
||||
dofile(basepath .. "common" .. DIR_DELIM .. "filterlist.lua")
|
||||
dofile(basepath .. "fstk" .. DIR_DELIM .. "buttonbar.lua")
|
||||
dofile(basepath .. "fstk" .. DIR_DELIM .. "dialog.lua")
|
||||
|
@ -55,6 +35,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
|
|||
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_rebind_keys.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_server_list_mods.lua")
|
||||
|
||||
|
@ -132,6 +113,7 @@ local function init_globals()
|
|||
ui.update()
|
||||
|
||||
check_reinstall_mtg()
|
||||
migrate_keybindings()
|
||||
check_new_version()
|
||||
end
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2020 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2020 rubenwardy
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
serverlistmgr = {
|
||||
-- continent code we detected for ourselves
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2013 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local function prepare_credits(dest, source)
|
||||
|
|
|
@ -1,20 +1,7 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local function get_content_icons(packages_with_updates)
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local current_game, singleplayer_refresh_gamebar
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2014 sapier
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local function get_sorted_servers()
|
||||
local servers = {
|
||||
|
|
|
@ -8,5 +8,6 @@ defaulttexturedir = ""
|
|||
local builtin_shared = {}
|
||||
|
||||
assert(loadfile(commonpath .. "register.lua"))(builtin_shared)
|
||||
assert(loadfile(commonpath .. "menu.lua"))(builtin_shared)
|
||||
assert(loadfile(pausepath .. "register.lua"))(builtin_shared)
|
||||
dofile(commonpath .. "settings" .. DIR_DELIM .. "init.lua")
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2016 T4im
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2016 T4im
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local S = core.get_translator("__builtin")
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2016 T4im
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2016 T4im
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local format, pairs, type = string.format, pairs, type
|
||||
local core, get_current_modname = core, core.get_current_modname
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2016 T4im
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2016 T4im
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
local S = core.get_translator("__builtin")
|
||||
-- Note: In this file, only messages are translated
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2016 T4im
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
--it under the terms of the GNU Lesser General Public License as published by
|
||||
--the Free Software Foundation; either version 2.1 of the License, or
|
||||
--(at your option) any later version.
|
||||
--
|
||||
--This program is distributed in the hope that it will be useful,
|
||||
--but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
--GNU Lesser General Public License for more details.
|
||||
--
|
||||
--You should have received a copy of the GNU Lesser General Public License along
|
||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- Luanti
|
||||
-- Copyright (C) 2016 T4im
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
local setmetatable = setmetatable
|
||||
local pairs, format = pairs, string.format
|
||||
local min, max, huge = math.min, math.max, math.huge
|
||||
|
|
|
@ -2,9 +2,27 @@
|
|||
#
|
||||
# General format:
|
||||
# name (Readable name) type type_args
|
||||
# name (Readable name) [context] type type_args
|
||||
#
|
||||
# Note that the parts are separated by exactly one space
|
||||
#
|
||||
# `context` (optional) is used to document where the setting is read. It can be:
|
||||
# - common: Read by both client and server.
|
||||
# - client: Read by the client.
|
||||
# (Includes settings read by the mainmenu.)
|
||||
# - server: Read by the server.
|
||||
# - world_creation: Read at world creation, thus only applied to new worlds.
|
||||
# (Worlds are commonly created in the mainmenu (part of the client), but
|
||||
# world creation is conceptually a server-side thing...)
|
||||
# If not specified, the value is inherited from the context value of the containing
|
||||
# category instead.
|
||||
# For the builtin/settingtypes.txt file, every setting needs to have a context defined,
|
||||
# either via a category containing it or via the setting itself. In game/mod-provided
|
||||
# settingtypes.txt files, context annotations are invalid.
|
||||
# Note: For context annotations, it's irrelevant whether changes to a setting
|
||||
# after startup/game-join will be read. A separate mechanism for declaring that
|
||||
# is needed.
|
||||
#
|
||||
# `type` can be:
|
||||
# - int
|
||||
# - string
|
||||
|
@ -13,7 +31,7 @@
|
|||
# - enum
|
||||
# - path
|
||||
# - filepath
|
||||
# - key (will be ignored in GUI, since a special key change dialog exists)
|
||||
# - key
|
||||
# - flags
|
||||
# - noise_params_2d
|
||||
# - noise_params_3d
|
||||
|
@ -73,10 +91,14 @@
|
|||
# * touchscreen / keyboard_mouse
|
||||
# * opengl / gles
|
||||
# * You can negate any requirement by prepending with !
|
||||
# * The "keyboard_mouse" requirement is automatically added to settings with the
|
||||
# "key" type.
|
||||
#
|
||||
# Sections are marked by a single line in the format: [Section Name]
|
||||
# Sub-section are marked by adding * in front of the section name: [*Sub-section]
|
||||
# Sub-sub-sections have two * etc.
|
||||
# A context (see above) can be specified optionally: [Section Name] [context]
|
||||
# Context annotations on categories cannot be nested.
|
||||
# There shouldn't be too many settings per category.
|
||||
#
|
||||
# The top-level categories "Advanced", "Client and Server" and "Mapgen" are
|
||||
|
@ -84,7 +106,7 @@
|
|||
# They contain settings not intended for the "average user".
|
||||
|
||||
|
||||
[Controls]
|
||||
[Controls] [client]
|
||||
|
||||
[*General]
|
||||
|
||||
|
@ -111,6 +133,13 @@ doubletap_jump (Double tap jump for fly) bool false
|
|||
# enabled.
|
||||
always_fly_fast (Always fly fast) bool true
|
||||
|
||||
# If enabled, the "Sneak" key will toggle when pressed.
|
||||
# This functionality is ignored when fly is enabled.
|
||||
toggle_sneak_key (Toggle Sneak key) bool false
|
||||
|
||||
# If enabled, the "Aux1" key will toggle when pressed.
|
||||
toggle_aux1_key (Toggle Aux1 key) bool false
|
||||
|
||||
# The time in seconds it takes between repeated node placements when holding
|
||||
# the place button.
|
||||
#
|
||||
|
@ -151,6 +180,228 @@ enable_hotbar_mouse_wheel (Hotbar: Enable mouse wheel for selection) bool true
|
|||
# Requires: keyboard_mouse
|
||||
invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false
|
||||
|
||||
[**Keybindings]
|
||||
|
||||
# Key for moving the player forward.
|
||||
keymap_forward (Move forward) key SYSTEM_SCANCODE_26
|
||||
|
||||
# Key for moving the player backward.
|
||||
# Will also disable autoforward, when active.
|
||||
keymap_backward (Move backward) key SYSTEM_SCANCODE_22
|
||||
|
||||
# Key for moving the player left.
|
||||
keymap_left (Move left) key SYSTEM_SCANCODE_4
|
||||
|
||||
# Key for moving the player right.
|
||||
keymap_right (Move right) key SYSTEM_SCANCODE_7
|
||||
|
||||
# Key for jumping.
|
||||
keymap_jump (Jump) key SYSTEM_SCANCODE_44
|
||||
|
||||
# Key for sneaking.
|
||||
# Also used for climbing down and descending in water if aux1_descends is disabled.
|
||||
keymap_sneak (Sneak) key SYSTEM_SCANCODE_225
|
||||
|
||||
# Key for digging, punching or using something.
|
||||
# (Note: The actual meaning might vary on a per-game basis.)
|
||||
keymap_dig (Dig/punch/use) key KEY_LBUTTON
|
||||
|
||||
# Key for placing an item/block or for using something.
|
||||
# (Note: The actual meaning might vary on a per-game basis.)
|
||||
keymap_place (Place/use) key KEY_RBUTTON
|
||||
|
||||
# Key for opening the inventory.
|
||||
keymap_inventory (Open inventory) key SYSTEM_SCANCODE_12
|
||||
|
||||
# Key for moving fast in fast mode.
|
||||
keymap_aux1 (Aux1) key SYSTEM_SCANCODE_8
|
||||
|
||||
# Key for opening the chat window.
|
||||
keymap_chat (Open chat) key SYSTEM_SCANCODE_23
|
||||
|
||||
# Key for opening the chat window to type commands.
|
||||
keymap_cmd (Command) key SYSTEM_SCANCODE_56
|
||||
|
||||
# Key for opening the chat window to type local commands.
|
||||
keymap_cmd_local (Local command) key SYSTEM_SCANCODE_55
|
||||
|
||||
# Key for toggling unlimited view range.
|
||||
keymap_rangeselect (Range select) key
|
||||
|
||||
# Key for toggling flying.
|
||||
keymap_freemove (Toggle fly) key SYSTEM_SCANCODE_14
|
||||
|
||||
# Key for toggling pitch move mode.
|
||||
keymap_pitchmove (Toggle pitchmove) key
|
||||
|
||||
# Key for toggling fast mode.
|
||||
keymap_fastmove (Toggle fast) key SYSTEM_SCANCODE_13
|
||||
|
||||
# Key for toggling noclip mode.
|
||||
keymap_noclip (Toggle noclip) key SYSTEM_SCANCODE_11
|
||||
|
||||
# Key for selecting the next item in the hotbar.
|
||||
keymap_hotbar_next (Hotbar: select next item) key SYSTEM_SCANCODE_17
|
||||
|
||||
# Key for selecting the previous item in the hotbar.
|
||||
keymap_hotbar_previous (Hotbar: select previous item) key SYSTEM_SCANCODE_5
|
||||
|
||||
# Key for muting the game.
|
||||
keymap_mute (Mute) key SYSTEM_SCANCODE_16
|
||||
|
||||
# Key for increasing the volume.
|
||||
keymap_increase_volume (Increase volume) key
|
||||
|
||||
# Key for decreasing the volume.
|
||||
keymap_decrease_volume (Decrease volume) key
|
||||
|
||||
# Key for toggling autoforward.
|
||||
keymap_autoforward (Toggle automatic forward) key
|
||||
|
||||
# Key for toggling cinematic mode.
|
||||
keymap_cinematic (Toggle cinematic mode) key
|
||||
|
||||
# Key for toggling display of minimap.
|
||||
keymap_minimap (Toggle minimap) key SYSTEM_SCANCODE_25
|
||||
|
||||
# Key for taking screenshots.
|
||||
keymap_screenshot (Screenshot) key SYSTEM_SCANCODE_69
|
||||
|
||||
# Key for toggling fullscreen mode.
|
||||
keymap_fullscreen (Toggle fullscreen) key SYSTEM_SCANCODE_68
|
||||
|
||||
# Key for dropping the currently selected item.
|
||||
keymap_drop (Drop item) key SYSTEM_SCANCODE_20
|
||||
|
||||
# Key to use view zoom when possible.
|
||||
keymap_zoom (Zoom) key SYSTEM_SCANCODE_29
|
||||
|
||||
# Key for toggling the display of the HUD.
|
||||
keymap_toggle_hud (Toggle HUD) key SYSTEM_SCANCODE_58
|
||||
|
||||
# Key for toggling the display of chat.
|
||||
keymap_toggle_chat (Toggle chat log) key SYSTEM_SCANCODE_59
|
||||
|
||||
# Key for toggling the display of the large chat console.
|
||||
keymap_console (Large chat console) key SYSTEM_SCANCODE_67
|
||||
|
||||
# Key for toggling the display of fog.
|
||||
keymap_toggle_fog (Toggle fog) key SYSTEM_SCANCODE_60
|
||||
|
||||
# Key for toggling the display of debug info.
|
||||
keymap_toggle_debug (Toggle debug info) key SYSTEM_SCANCODE_62
|
||||
|
||||
# Key for toggling the display of the profiler. Used for development.
|
||||
keymap_toggle_profiler (Toggle profiler) key SYSTEM_SCANCODE_63
|
||||
|
||||
# Key for toggling the display of mapblock boundaries.
|
||||
keymap_toggle_block_bounds (Toggle block bounds) key
|
||||
|
||||
# Key for switching between first- and third-person camera.
|
||||
keymap_camera_mode (Toggle camera mode) key SYSTEM_SCANCODE_6
|
||||
|
||||
# Key for increasing the viewing range.
|
||||
keymap_increase_viewing_range_min (Increase view range) key SYSTEM_SCANCODE_46
|
||||
|
||||
# Key for decreasing the viewing range.
|
||||
keymap_decrease_viewing_range_min (Decrease view range) key SYSTEM_SCANCODE_45
|
||||
|
||||
# Key for selecting the first hotbar slot.
|
||||
keymap_slot1 (Hotbar slot 1) key SYSTEM_SCANCODE_30
|
||||
|
||||
# Key for selecting the second hotbar slot.
|
||||
keymap_slot2 (Hotbar slot 2) key SYSTEM_SCANCODE_31
|
||||
|
||||
# Key for selecting the third hotbar slot.
|
||||
keymap_slot3 (Hotbar slot 3) key SYSTEM_SCANCODE_32
|
||||
|
||||
# Key for selecting the fourth hotbar slot.
|
||||
keymap_slot4 (Hotbar slot 4) key SYSTEM_SCANCODE_33
|
||||
|
||||
# Key for selecting the fifth hotbar slot.
|
||||
keymap_slot5 (Hotbar slot 5) key SYSTEM_SCANCODE_34
|
||||
|
||||
# Key for selecting the sixth hotbar slot.
|
||||
keymap_slot6 (Hotbar slot 6) key SYSTEM_SCANCODE_35
|
||||
|
||||
# Key for selecting the seventh hotbar slot.
|
||||
keymap_slot7 (Hotbar slot 7) key SYSTEM_SCANCODE_36
|
||||
|
||||
# Key for selecting the eighth hotbar slot.
|
||||
keymap_slot8 (Hotbar slot 8) key SYSTEM_SCANCODE_37
|
||||
|
||||
# Key for selecting the ninth hotbar slot.
|
||||
keymap_slot9 (Hotbar slot 9) key SYSTEM_SCANCODE_38
|
||||
|
||||
# Key for selecting the tenth hotbar slot.
|
||||
keymap_slot10 (Hotbar slot 10) key SYSTEM_SCANCODE_39
|
||||
|
||||
# Key for selecting the 11th hotbar slot.
|
||||
keymap_slot11 (Hotbar slot 11) key
|
||||
|
||||
# Key for selecting the 12th hotbar slot.
|
||||
keymap_slot12 (Hotbar slot 12) key
|
||||
|
||||
# Key for selecting the 13th hotbar slot.
|
||||
keymap_slot13 (Hotbar slot 13) key
|
||||
|
||||
# Key for selecting the 14th hotbar slot.
|
||||
keymap_slot14 (Hotbar slot 14) key
|
||||
|
||||
# Key for selecting the 15th hotbar slot.
|
||||
keymap_slot15 (Hotbar slot 15) key
|
||||
|
||||
# Key for selecting the 16th hotbar slot.
|
||||
keymap_slot16 (Hotbar slot 16) key
|
||||
|
||||
# Key for selecting the 17th hotbar slot.
|
||||
keymap_slot17 (Hotbar slot 17) key
|
||||
|
||||
# Key for selecting the 18th hotbar slot.
|
||||
keymap_slot18 (Hotbar slot 18) key
|
||||
|
||||
# Key for selecting the 19th hotbar slot.
|
||||
keymap_slot19 (Hotbar slot 19) key
|
||||
|
||||
# Key for selecting the 20th hotbar slot.
|
||||
keymap_slot20 (Hotbar slot 20) key
|
||||
|
||||
# Key for selecting the 21st hotbar slot.
|
||||
keymap_slot21 (Hotbar slot 21) key
|
||||
|
||||
# Key for selecting the 22nd hotbar slot.
|
||||
keymap_slot22 (Hotbar slot 22) key
|
||||
|
||||
# Key for selecting the 23rd hotbar slot.
|
||||
keymap_slot23 (Hotbar slot 23) key
|
||||
|
||||
# Key for selecting the 24th hotbar slot.
|
||||
keymap_slot24 (Hotbar slot 24) key
|
||||
|
||||
# Key for selecting the 25th hotbar slot.
|
||||
keymap_slot25 (Hotbar slot 25) key
|
||||
|
||||
# Key for selecting the 26th hotbar slot.
|
||||
keymap_slot26 (Hotbar slot 26) key
|
||||
|
||||
# Key for selecting the 27th hotbar slot.
|
||||
keymap_slot27 (Hotbar slot 27) key
|
||||
|
||||
# Key for selecting the 28th hotbar slot.
|
||||
keymap_slot28 (Hotbar slot 28) key
|
||||
|
||||
# Key for selecting the 29th hotbar slot.
|
||||
keymap_slot29 (Hotbar slot 29) key
|
||||
|
||||
# Key for selecting the 30th hotbar slot.
|
||||
keymap_slot30 (Hotbar slot 30) key
|
||||
|
||||
# Key for selecting the 31st hotbar slot.
|
||||
keymap_slot31 (Hotbar slot 31) key
|
||||
|
||||
# Key for selecting the 32nd hotbar slot.
|
||||
keymap_slot32 (Hotbar slot 32) key
|
||||
|
||||
[*Touchscreen]
|
||||
|
||||
# Enables the touchscreen controls, allowing you to play the game with a touchscreen.
|
||||
|
@ -160,6 +411,36 @@ invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false
|
|||
# Requires: touch_support
|
||||
touch_controls (Touchscreen controls) enum auto auto,true,false
|
||||
|
||||
# The kind of digging/placing controls used.
|
||||
#
|
||||
# * Tap
|
||||
# Long/short tap anywhere on the screen to interact.
|
||||
# Interaction happens at finger position.
|
||||
#
|
||||
# * Tap with crosshair
|
||||
# Long/short tap anywhere on the screen to interact.
|
||||
# Interaction happens at crosshair position.
|
||||
#
|
||||
# * Buttons with crosshair
|
||||
# Use dedicated dig/place buttons to interact.
|
||||
# Interaction happens at crosshair position.
|
||||
#
|
||||
# Requires: touchscreen
|
||||
touch_interaction_style (Interaction style) enum tap tap,tap_crosshair,buttons_crosshair
|
||||
|
||||
# The gesture for punching players/entities.
|
||||
# This can be overridden by games and mods.
|
||||
#
|
||||
# * Short tap
|
||||
# Easy to use and well-known from other games that shall not be named.
|
||||
#
|
||||
# * Long tap
|
||||
# Known from the classic Luanti mobile controls.
|
||||
# Combat is more or less impossible.
|
||||
#
|
||||
# Requires: touchscreen, touch_interaction_style_tap
|
||||
touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap
|
||||
|
||||
# Touchscreen sensitivity multiplier.
|
||||
#
|
||||
# Requires: touchscreen
|
||||
|
@ -175,12 +456,6 @@ touchscreen_threshold (Movement threshold) int 20 0 100
|
|||
# Requires: touchscreen
|
||||
touch_long_tap_delay (Threshold for long taps) int 400 100 1000
|
||||
|
||||
# Use crosshair to select object instead of whole screen.
|
||||
# If enabled, a crosshair will be shown and will be used for selecting object.
|
||||
#
|
||||
# Requires: touchscreen
|
||||
touch_use_crosshair (Use crosshair for touch screen) bool false
|
||||
|
||||
# Fixes the position of virtual joystick.
|
||||
# If disabled, virtual joystick will center to first-touch's position.
|
||||
#
|
||||
|
@ -193,21 +468,7 @@ fixed_virtual_joystick (Fixed virtual joystick) bool false
|
|||
# Requires: touchscreen
|
||||
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
|
||||
|
||||
# The gesture for punching players/entities.
|
||||
# This can be overridden by games and mods.
|
||||
#
|
||||
# * short_tap
|
||||
# Easy to use and well-known from other games that shall not be named.
|
||||
#
|
||||
# * long_tap
|
||||
# Known from the classic Luanti mobile controls.
|
||||
# Combat is more or less impossible.
|
||||
#
|
||||
# Requires: touchscreen
|
||||
touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap
|
||||
|
||||
|
||||
[Graphics and Audio]
|
||||
[Graphics and Audio] [client]
|
||||
|
||||
[*Graphics]
|
||||
|
||||
|
@ -295,10 +556,6 @@ arm_inertia (Arm inertia) bool true
|
|||
# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
|
||||
view_bobbing_amount (View bobbing factor) float 1.0 0.0 7.9
|
||||
|
||||
# Multiplier for fall bobbing.
|
||||
# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
|
||||
fall_bobbing_amount (Fall bobbing factor) float 0.03 0.0 100.0
|
||||
|
||||
[**Camera]
|
||||
|
||||
# Field of view in degrees.
|
||||
|
@ -615,11 +872,6 @@ enable_volumetric_lighting (Volumetric lighting) bool false
|
|||
# Requires: enable_dynamic_shadows
|
||||
enable_translucent_foliage (Translucent foliage) bool false
|
||||
|
||||
# Apply specular shading to nodes.
|
||||
#
|
||||
# Requires: enable_dynamic_shadows
|
||||
enable_node_specular (Node specular) bool false
|
||||
|
||||
# When enabled, liquid reflections are simulated.
|
||||
#
|
||||
# Requires: enable_waving_water, enable_dynamic_shadows
|
||||
|
@ -749,13 +1001,13 @@ contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3 1
|
|||
|
||||
[Client and Server]
|
||||
|
||||
[*Client]
|
||||
[*Client] [client]
|
||||
|
||||
# Save the map received by the client on disk.
|
||||
enable_local_map_saving (Saving map received from server) bool false
|
||||
|
||||
# URL to the server list displayed in the Multiplayer Tab.
|
||||
serverlist_url (Serverlist URL) string https://servers.luanti.org
|
||||
serverlist_url (Serverlist URL) [common] string https://servers.luanti.org
|
||||
|
||||
# If enabled, server account registration is separate from login in the UI.
|
||||
# If disabled, connecting to a server will automatically register a new account.
|
||||
|
@ -765,7 +1017,7 @@ enable_split_login_register (Enable split login/register) bool true
|
|||
# If this is empty the engine will never check for updates.
|
||||
update_information_url (Update information URL) string https://www.luanti.org/release_info.json
|
||||
|
||||
[*Server]
|
||||
[*Server] [server]
|
||||
|
||||
# Name of the player.
|
||||
# When running a server, a client connecting with this name is admin.
|
||||
|
@ -793,7 +1045,7 @@ server_announce (Announce server) bool false
|
|||
server_announce_send_players (Send player names to the server list) bool true
|
||||
|
||||
# Announce to this serverlist.
|
||||
serverlist_url (Serverlist URL) string https://servers.luanti.org
|
||||
serverlist_url (Serverlist URL) [common] string https://servers.luanti.org
|
||||
|
||||
# Message of the day displayed to players connecting.
|
||||
motd (Message of the day) string
|
||||
|
@ -839,7 +1091,7 @@ remote_media (Remote media) string
|
|||
# Requires: enable_ipv6
|
||||
ipv6_server (IPv6 server) bool true
|
||||
|
||||
[*Server Security]
|
||||
[*Server Security] [server]
|
||||
|
||||
# New users need to input this password.
|
||||
default_password (Default password) string
|
||||
|
@ -899,7 +1151,7 @@ chat_message_limit_per_10sec (Chat message count limit) float 8.0 1.0
|
|||
# Kick players who sent more than X messages per 10 seconds.
|
||||
chat_message_limit_trigger_kick (Chat message kick threshold) int 50 1 65535
|
||||
|
||||
[*Server Gameplay]
|
||||
[*Server Gameplay] [server]
|
||||
|
||||
# Controls length of day/night cycle.
|
||||
# Examples:
|
||||
|
@ -907,7 +1159,7 @@ chat_message_limit_trigger_kick (Chat message kick threshold) int 50 1 65535
|
|||
time_speed (Time speed) int 72 0
|
||||
|
||||
# Time of day when a new world is started, in millihours (0-23999).
|
||||
world_start_time (World start time) int 6125 0 23999
|
||||
world_start_time (World start time) [world_creation] int 6125 0 23999
|
||||
|
||||
# Time in seconds for item entity (dropped items) to live.
|
||||
# Setting it to -1 disables the feature.
|
||||
|
@ -962,7 +1214,7 @@ movement_liquid_sink (Liquid sinking) float 10.0
|
|||
movement_gravity (Gravity) float 9.81
|
||||
|
||||
|
||||
[Mapgen]
|
||||
[Mapgen] [world_creation]
|
||||
|
||||
# A chosen map seed for a new map, leave empty for random.
|
||||
# Will be overridden when creating a new world in the main menu.
|
||||
|
@ -978,7 +1230,7 @@ mg_name (Mapgen name) enum v7 v7,valleys,carpathian,v5,flat,fractal,singlenode,v
|
|||
water_level (Water level) int 1 -31000 31000
|
||||
|
||||
# From how far blocks are generated for clients, stated in mapblocks (16 nodes).
|
||||
max_block_generate_distance (Max block generate distance) int 10 1 32767
|
||||
max_block_generate_distance (Max block generate distance) [server] int 10 1 32767
|
||||
|
||||
# Limit of map generation, in nodes, in all 6 directions from (0, 0, 0).
|
||||
# Only mapchunks completely within the mapgen limit are generated.
|
||||
|
@ -1691,12 +1943,12 @@ mgvalleys_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 500),
|
|||
|
||||
# Enable Lua modding support on client.
|
||||
# This support is experimental and API can change.
|
||||
enable_client_modding (Client modding) bool false
|
||||
enable_client_modding (Client modding) [client] bool false
|
||||
|
||||
# Replaces the default main menu with a custom one.
|
||||
main_menu_script (Main menu script) string
|
||||
main_menu_script (Main menu script) [client] string
|
||||
|
||||
[**Mod Security]
|
||||
[**Mod Security] [server]
|
||||
|
||||
# Prevent mods from doing insecure things like running shell commands.
|
||||
secure.enable_security (Enable mod security) bool true
|
||||
|
@ -1720,33 +1972,33 @@ secure.http_mods (HTTP mods) string
|
|||
# - info
|
||||
# - verbose
|
||||
# - trace
|
||||
debug_log_level (Debug log level) enum action ,none,error,warning,action,info,verbose,trace
|
||||
debug_log_level (Debug log level) [common] enum action ,none,error,warning,action,info,verbose,trace
|
||||
|
||||
# If the file size of debug.txt exceeds the number of megabytes specified in
|
||||
# this setting when it is opened, the file is moved to debug.txt.1,
|
||||
# deleting an older debug.txt.1 if it exists.
|
||||
# debug.txt is only moved if this setting is positive.
|
||||
debug_log_size_max (Debug log file size threshold) int 50 1
|
||||
debug_log_size_max (Debug log file size threshold) [common] int 50 1
|
||||
|
||||
# Minimal level of logging to be written to chat.
|
||||
chat_log_level (Chat log level) enum error ,none,error,warning,action,info,verbose,trace
|
||||
chat_log_level (Chat log level) [client] enum error ,none,error,warning,action,info,verbose,trace
|
||||
|
||||
# Handling for deprecated Lua API calls:
|
||||
# - none: Do not log deprecated calls
|
||||
# - log: mimic and log backtrace of deprecated call (default).
|
||||
# - error: abort on usage of deprecated call (suggested for mod developers).
|
||||
deprecated_lua_api_handling (Deprecated Lua API handling) enum log none,log,error
|
||||
deprecated_lua_api_handling (Deprecated Lua API handling) [common] enum log none,log,error
|
||||
|
||||
# Enable random user input (only used for testing).
|
||||
random_input (Random input) bool false
|
||||
random_input (Random input) [client] bool false
|
||||
|
||||
# Enable random mod loading (mainly used for testing).
|
||||
random_mod_load_order (Random mod load order) bool false
|
||||
random_mod_load_order (Random mod load order) [server] bool false
|
||||
|
||||
# Enable mod channels support.
|
||||
enable_mod_channels (Mod channels) bool false
|
||||
enable_mod_channels (Mod channels) [server] bool false
|
||||
|
||||
[**Mod Profiler]
|
||||
[**Mod Profiler] [server]
|
||||
|
||||
# Load the game profiler to collect game profiling data.
|
||||
# Provides a /profiler command to access the compiled profile.
|
||||
|
@ -1786,16 +2038,15 @@ instrument.builtin (Builtin) bool false
|
|||
# * Instrument the sampler being used to update the statistics.
|
||||
instrument.profiler (Profiler) bool false
|
||||
|
||||
[**Engine Profiler]
|
||||
[**Engine Profiler] [common]
|
||||
|
||||
# Print the engine's profiling data in regular intervals (in seconds).
|
||||
# 0 = disable. Useful for developers.
|
||||
profiler_print_interval (Engine profiling data print interval) int 0 0
|
||||
|
||||
|
||||
[*Advanced]
|
||||
|
||||
[**Graphics]
|
||||
[**Graphics] [client]
|
||||
|
||||
# Enables debug and error-checking in the OpenGL driver.
|
||||
opengl_debug (OpenGL debug) bool false
|
||||
|
@ -1850,7 +2101,7 @@ world_aligned_mode (World-aligned textures mode) enum enable disable,enable,forc
|
|||
# World-aligned textures may be scaled to span several nodes. However,
|
||||
# the server may not send the scale you want, especially if you use
|
||||
# a specially-designed texture pack; with this option, the client tries
|
||||
# to determine the scale automatically basing on the texture size.
|
||||
# to determine the scale automatically based on the texture size.
|
||||
# See also texture_min_size.
|
||||
# Warning: This option is EXPERIMENTAL!
|
||||
autoscale_mode (Autoscaling mode) enum disable disable,enable,force
|
||||
|
@ -1862,7 +2113,7 @@ autoscale_mode (Autoscaling mode) enum disable disable,enable,force
|
|||
# This setting is ONLY applied if any of the mentioned filters are enabled.
|
||||
# This is also used as the base node texture size for world-aligned
|
||||
# texture autoscaling.
|
||||
texture_min_size (Base texture size) int 64 1 32768
|
||||
texture_min_size (Base texture size) int 192 192 16384
|
||||
|
||||
# Side length of a cube of map blocks that the client will consider together
|
||||
# when generating meshes.
|
||||
|
@ -1899,12 +2150,12 @@ shadow_update_frames (Map shadows update frames) int 16 1 32
|
|||
# Requires: enable_post_processing, enable_bloom
|
||||
enable_bloom_debug (Enable Bloom Debug) bool false
|
||||
|
||||
[**Sound]
|
||||
[**Sound] [client]
|
||||
# Comma-separated list of AL and ALC extensions that should not be used.
|
||||
# Useful for testing. See al_extensions.[h,cpp] for details.
|
||||
sound_extensions_blacklist (Sound Extensions Blacklist) string
|
||||
|
||||
[**Font]
|
||||
[**Font] [client]
|
||||
|
||||
font_bold (Font bold by default) bool false
|
||||
|
||||
|
@ -1954,7 +2205,7 @@ mono_font_path_bold_italic (Bold and italic monospace font path) filepath fonts/
|
|||
# This font will be used for certain languages or if the default font is unavailable.
|
||||
fallback_font_path (Fallback font path) filepath fonts/DroidSansFallbackFull.ttf
|
||||
|
||||
[**Lighting]
|
||||
[**Lighting] [client]
|
||||
|
||||
# Gradient of light curve at minimum light level.
|
||||
# Controls the contrast of the lowest light levels.
|
||||
|
@ -1982,45 +2233,48 @@ lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
|
|||
|
||||
# Enable IPv6 support (for both client and server).
|
||||
# Required for IPv6 connections to work at all.
|
||||
enable_ipv6 (IPv6) bool true
|
||||
enable_ipv6 (IPv6) [common] bool true
|
||||
|
||||
# Prometheus listener address.
|
||||
# If Luanti is compiled with ENABLE_PROMETHEUS option enabled,
|
||||
# enable metrics listener for Prometheus on that address.
|
||||
# Metrics can be fetched on http://127.0.0.1:30000/metrics
|
||||
prometheus_listener_address (Prometheus listener address) string 127.0.0.1:30000
|
||||
# If Luanti is compiled with Prometheus support, this setting
|
||||
# enables the metrics listener for Prometheus on that address.
|
||||
# By default you can fetch metrics from http://127.0.0.1:30000/metrics.
|
||||
# An empty value disables the metrics listener.
|
||||
prometheus_listener_address (Prometheus listener address) [server] string 127.0.0.1:30000
|
||||
|
||||
# Maximum size of the outgoing chat queue.
|
||||
# Maximum size of the client's outgoing chat queue.
|
||||
# 0 to disable queueing and -1 to make the queue size unlimited.
|
||||
max_out_chat_queue_size (Maximum size of the outgoing chat queue) int 20 -1 32767
|
||||
max_out_chat_queue_size (Maximum size of the client's outgoing chat queue) [client] int 20 -1 32767
|
||||
|
||||
# Timeout for client to remove unused map data from memory, in seconds.
|
||||
client_unload_unused_data_timeout (Mapblock unload timeout) float 600.0 0.0
|
||||
client_unload_unused_data_timeout (Mapblock unload timeout) [client] float 600.0 0.0
|
||||
|
||||
# Maximum number of mapblocks for client to be kept in memory.
|
||||
# Set to -1 for unlimited amount.
|
||||
client_mapblock_limit (Mapblock limit) int 7500 -1 2147483647
|
||||
# Note that there is an internal dynamic minimum number of blocks that
|
||||
# won't be deleted, depending on the current view range.
|
||||
# Set to -1 for no limit.
|
||||
client_mapblock_limit (Mapblock limit) [client] int 7500 -1 2147483647
|
||||
|
||||
# Maximum number of blocks that are simultaneously sent per client.
|
||||
# The maximum total count is calculated dynamically:
|
||||
# max_total = ceil((#clients + max_users) * per_client / 4)
|
||||
max_simultaneous_block_sends_per_client (Maximum simultaneous block sends per client) int 40 1 4294967295
|
||||
max_simultaneous_block_sends_per_client (Maximum simultaneous block sends per client) [server] int 40 1 4294967295
|
||||
|
||||
# To reduce lag, block transfers are slowed down when a player is building something.
|
||||
# This determines how long they are slowed down after placing or removing a node.
|
||||
full_block_send_enable_min_time_from_building (Delay in sending blocks after building) float 2.0 0.0
|
||||
full_block_send_enable_min_time_from_building (Delay in sending blocks after building) [server] float 2.0 0.0
|
||||
|
||||
# Maximum number of packets sent per send step in the low-level networking code.
|
||||
# You generally don't need to change this, however busy servers may benefit from a higher number.
|
||||
max_packets_per_iteration (Max. packets per iteration) int 1024 1 65535
|
||||
max_packets_per_iteration (Max. packets per iteration) [common] int 1024 1 65535
|
||||
|
||||
# Compression level to use when sending mapblocks to the client.
|
||||
# -1 - use default compression level
|
||||
# 0 - least compression, fastest
|
||||
# 9 - best compression, slowest
|
||||
map_compression_level_net (Map Compression Level for Network Transfer) int -1 -1 9
|
||||
map_compression_level_net (Map Compression Level for Network Transfer) [server] int -1 -1 9
|
||||
|
||||
[**Server]
|
||||
[**Server] [server]
|
||||
|
||||
# Format of player chat messages. The following strings are valid placeholders:
|
||||
# @name, @message, @timestamp (optional)
|
||||
|
@ -2040,7 +2294,7 @@ kick_msg_crash (Crash message) string This server has experienced an internal er
|
|||
# Set this to true if your server is set up to restart automatically.
|
||||
ask_reconnect_on_crash (Ask to reconnect after crash) bool false
|
||||
|
||||
[**Server/Env Performance]
|
||||
[**Server/Env Performance] [server]
|
||||
|
||||
# Length of a server tick (the interval at which everything is generally updated),
|
||||
# stated in seconds.
|
||||
|
@ -2091,14 +2345,14 @@ max_objects_per_block (Maximum objects per block) int 256 256 65535
|
|||
active_block_mgmt_interval (Active block management interval) float 2.0 0.0
|
||||
|
||||
# Length of time between Active Block Modifier (ABM) execution cycles, stated in seconds.
|
||||
abm_interval (ABM interval) float 1.0 0.0
|
||||
abm_interval (ABM interval) float 1.0 0.1 30.0
|
||||
|
||||
# The time budget allowed for ABMs to execute on each step
|
||||
# (as a fraction of the ABM Interval)
|
||||
abm_time_budget (ABM time budget) float 0.2 0.1 0.9
|
||||
|
||||
# Length of time between NodeTimer execution cycles, stated in seconds.
|
||||
nodetimer_interval (NodeTimer interval) float 0.2 0.0
|
||||
nodetimer_interval (NodeTimer interval) float 0.2 0.1 1.0
|
||||
|
||||
# Max liquids processed per step.
|
||||
liquid_loop_max (Liquid loop max) int 100000 1 4294967295
|
||||
|
@ -2133,7 +2387,7 @@ server_side_occlusion_culling (Server-side occlusion culling) bool true
|
|||
# Stated in MapBlocks (16 nodes).
|
||||
block_cull_optimize_distance (Block cull optimize distance) int 25 2 2047
|
||||
|
||||
[**Mapgen]
|
||||
[**Mapgen] [server]
|
||||
|
||||
# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).
|
||||
# WARNING: There is no benefit, and there are several dangers, in
|
||||
|
@ -2141,7 +2395,7 @@ block_cull_optimize_distance (Block cull optimize distance) int 25 2 2047
|
|||
# Reducing this value increases cave and dungeon density.
|
||||
# Altering this value is for special usage, leaving it unchanged is
|
||||
# recommended.
|
||||
chunksize (Chunk size) int 5 1 10
|
||||
chunksize (Chunk size) [world_creation] int 5 1 10
|
||||
|
||||
# Dump the mapgen debug information.
|
||||
enable_mapgen_debug_info (Mapgen debug) bool false
|
||||
|
@ -2169,7 +2423,7 @@ emergequeue_limit_generate (Per-player limit of queued blocks to generate) int 1
|
|||
# 'on_generated'. For many users the optimum setting may be '1'.
|
||||
num_emerge_threads (Number of emerge threads) int 1 0 32767
|
||||
|
||||
[**cURL]
|
||||
[**cURL] [common]
|
||||
|
||||
# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
|
||||
curl_timeout (cURL interactive timeout) int 20000 1000 2147483647
|
||||
|
@ -2184,51 +2438,68 @@ curl_parallel_limit (cURL parallel limit) int 8 1 2147483647
|
|||
# Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.
|
||||
curl_file_download_timeout (cURL file download timeout) int 300000 5000 2147483647
|
||||
|
||||
[**Client Debugging] [client]
|
||||
|
||||
# Key for toggling the camera update. Only usable with 'debug' privilege.
|
||||
keymap_toggle_update_camera (Toggle camera update) key
|
||||
|
||||
# Key for switching to the previous entry in Quicktune.
|
||||
keymap_quicktune_prev (Quicktune: select previous entry) key
|
||||
|
||||
# Key for switching to the next entry in Quicktune.
|
||||
keymap_quicktune_next (Quicktune: select next entry) key
|
||||
|
||||
# Key for decrementing the selected value in Quicktune.
|
||||
keymap_quicktune_dec (Quicktune: decrement value) key
|
||||
|
||||
# Key for incrementing the selected value in Quicktune.
|
||||
keymap_quicktune_inc (Quicktune: increment value) key
|
||||
|
||||
[**Miscellaneous]
|
||||
|
||||
# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output.
|
||||
clickable_chat_weblinks (Chat weblinks) bool true
|
||||
clickable_chat_weblinks (Chat weblinks) [client] bool true
|
||||
|
||||
# If enabled, invalid world data won't cause the server to shut down.
|
||||
# Only enable this if you know what you are doing.
|
||||
ignore_world_load_errors (Ignore world errors) bool false
|
||||
ignore_world_load_errors (Ignore world errors) [server] bool false
|
||||
|
||||
# Adjust the detected display density, used for scaling UI elements.
|
||||
display_density_factor (Display Density Scaling Factor) float 1 0.5 5.0
|
||||
display_density_factor (Display Density Scaling Factor) [client] float 1 0.5 5.0
|
||||
|
||||
# Windows systems only: Start Luanti with the command line window in the background.
|
||||
# Contains the same information as the file debug.txt (default name).
|
||||
enable_console (Enable console window) bool false
|
||||
enable_console (Enable console window) [common] bool false
|
||||
|
||||
# Number of extra blocks that can be loaded by /clearobjects at once.
|
||||
# This is a trade-off between SQLite transaction overhead and
|
||||
# memory consumption (4096=100MB, as a rule of thumb).
|
||||
max_clearobjects_extra_loaded_blocks (Max. clearobjects extra blocks) int 4096 0 4294967295
|
||||
max_clearobjects_extra_loaded_blocks (Max. clearobjects extra blocks) [server] int 4096 0 4294967295
|
||||
|
||||
# World directory (everything in the world is stored here).
|
||||
# Not needed if starting from the main menu.
|
||||
map-dir (Map directory) path
|
||||
map-dir (Map directory) [server] path
|
||||
|
||||
# See https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||
sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2
|
||||
sqlite_synchronous (Synchronous SQLite) [server] enum 2 0,1,2
|
||||
|
||||
# Compression level to use when saving mapblocks to disk.
|
||||
# -1 - use default compression level
|
||||
# 0 - least compression, fastest
|
||||
# 9 - best compression, slowest
|
||||
map_compression_level_disk (Map Compression Level for Disk Storage) int -1 -1 9
|
||||
map_compression_level_disk (Map Compression Level for Disk Storage) [server] int -1 -1 9
|
||||
|
||||
# Enable usage of remote media server (if provided by server).
|
||||
# Remote servers offer a significantly faster way to download media (e.g. textures)
|
||||
# when connecting to the server.
|
||||
enable_remote_media_server (Connect to external media server) bool true
|
||||
enable_remote_media_server (Connect to external media server) [client] bool true
|
||||
|
||||
# File in client/serverlist/ that contains your favorite servers displayed in the
|
||||
# Multiplayer Tab.
|
||||
serverlist_file (Serverlist file) string favoriteservers.json
|
||||
serverlist_file (Serverlist file) [client] string favoriteservers.json
|
||||
|
||||
|
||||
[*Gamepads]
|
||||
[*Gamepads] [client]
|
||||
|
||||
# Enable joysticks. Requires a restart to take effect
|
||||
enable_joysticks (Enable joysticks) bool false
|
||||
|
@ -2251,7 +2522,7 @@ joystick_deadzone (Joystick dead zone) int 2048 0 65535
|
|||
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170.0 0.001
|
||||
|
||||
|
||||
[*Hide: Temporary Settings]
|
||||
[*Hide: Temporary Settings] [common]
|
||||
|
||||
# Path to texture directory. All textures are first searched from here.
|
||||
texture_path (Texture path) path
|
||||
|
@ -2310,226 +2581,3 @@ show_technical_names (Show technical names) bool false
|
|||
|
||||
# Controlled by a checkbox in the settings menu.
|
||||
show_advanced (Show advanced settings) bool false
|
||||
|
||||
# Key for moving the player forward.
|
||||
keymap_forward (Forward key) key KEY_KEY_W
|
||||
|
||||
# Key for moving the player backward.
|
||||
# Will also disable autoforward, when active.
|
||||
keymap_backward (Backward key) key KEY_KEY_S
|
||||
|
||||
# Key for moving the player left.
|
||||
keymap_left (Left key) key KEY_KEY_A
|
||||
|
||||
# Key for moving the player right.
|
||||
keymap_right (Right key) key KEY_KEY_D
|
||||
|
||||
# Key for jumping.
|
||||
keymap_jump (Jump key) key KEY_SPACE
|
||||
|
||||
# Key for sneaking.
|
||||
# Also used for climbing down and descending in water if aux1_descends is disabled.
|
||||
keymap_sneak (Sneak key) key KEY_LSHIFT
|
||||
|
||||
# Key for digging, punching or using something.
|
||||
# (Note: The actual meaning might vary on a per-game basis.)
|
||||
keymap_dig (Dig/punch/use key) key KEY_LBUTTON
|
||||
|
||||
# Key for placing an item/block or for using something.
|
||||
# (Note: The actual meaning might vary on a per-game basis.)
|
||||
keymap_place (Place/use key) key KEY_RBUTTON
|
||||
|
||||
# Key for opening the inventory.
|
||||
keymap_inventory (Inventory key) key KEY_KEY_I
|
||||
|
||||
# Key for moving fast in fast mode.
|
||||
keymap_aux1 (Aux1 key) key KEY_KEY_E
|
||||
|
||||
# Key for opening the chat window.
|
||||
keymap_chat (Chat key) key KEY_KEY_T
|
||||
|
||||
# Key for opening the chat window to type commands.
|
||||
keymap_cmd (Command key) key /
|
||||
|
||||
# Key for opening the chat window to type local commands.
|
||||
keymap_cmd_local (Command key) key .
|
||||
|
||||
# Key for toggling unlimited view range.
|
||||
keymap_rangeselect (Range select key) key
|
||||
|
||||
# Key for toggling flying.
|
||||
keymap_freemove (Fly key) key KEY_KEY_K
|
||||
|
||||
# Key for toggling pitch move mode.
|
||||
keymap_pitchmove (Pitch move key) key
|
||||
|
||||
# Key for toggling fast mode.
|
||||
keymap_fastmove (Fast key) key KEY_KEY_J
|
||||
|
||||
# Key for toggling noclip mode.
|
||||
keymap_noclip (Noclip key) key KEY_KEY_H
|
||||
|
||||
# Key for selecting the next item in the hotbar.
|
||||
keymap_hotbar_next (Hotbar next key) key KEY_KEY_N
|
||||
|
||||
# Key for selecting the previous item in the hotbar.
|
||||
keymap_hotbar_previous (Hotbar previous key) key KEY_KEY_B
|
||||
|
||||
# Key for muting the game.
|
||||
keymap_mute (Mute key) key KEY_KEY_M
|
||||
|
||||
# Key for increasing the volume.
|
||||
keymap_increase_volume (Inc. volume key) key
|
||||
|
||||
# Key for decreasing the volume.
|
||||
keymap_decrease_volume (Dec. volume key) key
|
||||
|
||||
# Key for toggling autoforward.
|
||||
keymap_autoforward (Automatic forward key) key
|
||||
|
||||
# Key for toggling cinematic mode.
|
||||
keymap_cinematic (Cinematic mode key) key
|
||||
|
||||
# Key for toggling display of minimap.
|
||||
keymap_minimap (Minimap key) key KEY_KEY_V
|
||||
|
||||
# Key for taking screenshots.
|
||||
keymap_screenshot (Screenshot) key KEY_F12
|
||||
|
||||
# Key for toggling fullscreen mode.
|
||||
keymap_fullscreen (Fullscreen key) key KEY_F11
|
||||
|
||||
# Key for dropping the currently selected item.
|
||||
keymap_drop (Drop item key) key KEY_KEY_Q
|
||||
|
||||
# Key to use view zoom when possible.
|
||||
keymap_zoom (View zoom key) key KEY_KEY_Z
|
||||
|
||||
# Key for selecting the first hotbar slot.
|
||||
keymap_slot1 (Hotbar slot 1 key) key KEY_KEY_1
|
||||
|
||||
# Key for selecting the second hotbar slot.
|
||||
keymap_slot2 (Hotbar slot 2 key) key KEY_KEY_2
|
||||
|
||||
# Key for selecting the third hotbar slot.
|
||||
keymap_slot3 (Hotbar slot 3 key) key KEY_KEY_3
|
||||
|
||||
# Key for selecting the fourth hotbar slot.
|
||||
keymap_slot4 (Hotbar slot 4 key) key KEY_KEY_4
|
||||
|
||||
# Key for selecting the fifth hotbar slot.
|
||||
keymap_slot5 (Hotbar slot 5 key) key KEY_KEY_5
|
||||
|
||||
# Key for selecting the sixth hotbar slot.
|
||||
keymap_slot6 (Hotbar slot 6 key) key KEY_KEY_6
|
||||
|
||||
# Key for selecting the seventh hotbar slot.
|
||||
keymap_slot7 (Hotbar slot 7 key) key KEY_KEY_7
|
||||
|
||||
# Key for selecting the eighth hotbar slot.
|
||||
keymap_slot8 (Hotbar slot 8 key) key KEY_KEY_8
|
||||
|
||||
# Key for selecting the ninth hotbar slot.
|
||||
keymap_slot9 (Hotbar slot 9 key) key KEY_KEY_9
|
||||
|
||||
# Key for selecting the tenth hotbar slot.
|
||||
keymap_slot10 (Hotbar slot 10 key) key KEY_KEY_0
|
||||
|
||||
# Key for selecting the 11th hotbar slot.
|
||||
keymap_slot11 (Hotbar slot 11 key) key
|
||||
|
||||
# Key for selecting the 12th hotbar slot.
|
||||
keymap_slot12 (Hotbar slot 12 key) key
|
||||
|
||||
# Key for selecting the 13th hotbar slot.
|
||||
keymap_slot13 (Hotbar slot 13 key) key
|
||||
|
||||
# Key for selecting the 14th hotbar slot.
|
||||
keymap_slot14 (Hotbar slot 14 key) key
|
||||
|
||||
# Key for selecting the 15th hotbar slot.
|
||||
keymap_slot15 (Hotbar slot 15 key) key
|
||||
|
||||
# Key for selecting the 16th hotbar slot.
|
||||
keymap_slot16 (Hotbar slot 16 key) key
|
||||
|
||||
# Key for selecting the 17th hotbar slot.
|
||||
keymap_slot17 (Hotbar slot 17 key) key
|
||||
|
||||
# Key for selecting the 18th hotbar slot.
|
||||
keymap_slot18 (Hotbar slot 18 key) key
|
||||
|
||||
# Key for selecting the 19th hotbar slot.
|
||||
keymap_slot19 (Hotbar slot 19 key) key
|
||||
|
||||
# Key for selecting the 20th hotbar slot.
|
||||
keymap_slot20 (Hotbar slot 20 key) key
|
||||
|
||||
# Key for selecting the 21st hotbar slot.
|
||||
keymap_slot21 (Hotbar slot 21 key) key
|
||||
|
||||
# Key for selecting the 22nd hotbar slot.
|
||||
keymap_slot22 (Hotbar slot 22 key) key
|
||||
|
||||
# Key for selecting the 23rd hotbar slot.
|
||||
keymap_slot23 (Hotbar slot 23 key) key
|
||||
|
||||
# Key for selecting the 24th hotbar slot.
|
||||
keymap_slot24 (Hotbar slot 24 key) key
|
||||
|
||||
# Key for selecting the 25th hotbar slot.
|
||||
keymap_slot25 (Hotbar slot 25 key) key
|
||||
|
||||
# Key for selecting the 26th hotbar slot.
|
||||
keymap_slot26 (Hotbar slot 26 key) key
|
||||
|
||||
# Key for selecting the 27th hotbar slot.
|
||||
keymap_slot27 (Hotbar slot 27 key) key
|
||||
|
||||
# Key for selecting the 28th hotbar slot.
|
||||
keymap_slot28 (Hotbar slot 28 key) key
|
||||
|
||||
# Key for selecting the 29th hotbar slot.
|
||||
keymap_slot29 (Hotbar slot 29 key) key
|
||||
|
||||
# Key for selecting the 30th hotbar slot.
|
||||
keymap_slot30 (Hotbar slot 30 key) key
|
||||
|
||||
# Key for selecting the 31st hotbar slot.
|
||||
keymap_slot31 (Hotbar slot 31 key) key
|
||||
|
||||
# Key for selecting the 32nd hotbar slot.
|
||||
keymap_slot32 (Hotbar slot 32 key) key
|
||||
|
||||
# Key for toggling the display of the HUD.
|
||||
keymap_toggle_hud (HUD toggle key) key KEY_F1
|
||||
|
||||
# Key for toggling the display of chat.
|
||||
keymap_toggle_chat (Chat toggle key) key KEY_F2
|
||||
|
||||
# Key for toggling the display of the large chat console.
|
||||
keymap_console (Large chat console key) key KEY_F10
|
||||
|
||||
# Key for toggling the display of fog.
|
||||
keymap_toggle_fog (Fog toggle key) key KEY_F3
|
||||
|
||||
# Key for toggling the camera update. Only usable with 'debug' privilege.
|
||||
keymap_toggle_update_camera (Camera update toggle key) key
|
||||
|
||||
# Key for toggling the display of debug info.
|
||||
keymap_toggle_debug (Debug info toggle key) key KEY_F5
|
||||
|
||||
# Key for toggling the display of the profiler. Used for development.
|
||||
keymap_toggle_profiler (Profiler toggle key) key KEY_F6
|
||||
|
||||
# Key for toggling the display of mapblock boundaries.
|
||||
keymap_toggle_block_bounds (Block bounds toggle key) key
|
||||
|
||||
# Key for switching between first- and third-person camera.
|
||||
keymap_camera_mode (Toggle camera mode key) key KEY_KEY_C
|
||||
|
||||
# Key for increasing the viewing range.
|
||||
keymap_increase_viewing_range_min (View range increase key) key +
|
||||
|
||||
# Key for decreasing the viewing range.
|
||||
keymap_decrease_viewing_range_min (View range decrease key) key -
|
||||
|
|
|
@ -44,8 +44,6 @@ centroid varying float nightRatio;
|
|||
varying float perspective_factor;
|
||||
#endif
|
||||
|
||||
varying float area_enable_parallax;
|
||||
|
||||
varying highp vec3 eyeVec;
|
||||
// Color of the light emitted by the light sources.
|
||||
const vec3 artificialLight = vec3(1.04, 1.04, 1.04);
|
||||
|
|
|
@ -23,3 +23,6 @@ This list is largely advisory and items may be reevaluated once the time comes.
|
|||
* stop reading initial properties from bare entity def
|
||||
* change particle default blend mode to `clip`
|
||||
* remove built-in knockback and related functions entirely
|
||||
* remove `safe` parameter from `core.serialize`, always enforce `safe = true`.
|
||||
possibly error when `loadstring` calls are encountered in `core.deserialize`.
|
||||
* introduce strict type checking for all instances of `v3s16` / `v3f` read from Lua
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
Luanti Lua Client Modding API Reference 5.12.0
|
||||
Luanti Lua Client Modding API Reference 5.13.0
|
||||
==============================================
|
||||
|
||||
**WARNING**: if you're looking for the `minetest` namespace (e.g. `minetest.something`),
|
||||
it's now called `core` due to the renaming of Luanti (formerly Minetest).
|
||||
`minetest` will keep existing as an alias, so that old code won't break.
|
||||
|
||||
Note that `core` has already existed since version 0.4.10, so you can use it
|
||||
safely without breaking backwards compatibility.
|
||||
|
||||
* More information at <http://www.luanti.org/>
|
||||
* Developer Wiki: <https://dev.luanti.org/>
|
||||
* Additional documentation: <https://docs.luanti.org/>
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
|
|
@ -23,6 +23,7 @@ General options and their default values:
|
|||
PRECOMPILE_HEADERS=FALSE - Precompile some headers (experimental; requires CMake 3.16 or later)
|
||||
PRECOMPILED_HEADERS_PATH= - Path to a file listing all headers to precompile (default points to src/precompiled_headers.txt)
|
||||
USE_SDL2=TRUE - Build with SDL2; Enables IrrlichtMt device SDL2
|
||||
USE_SDL2_STATIC=TRUE - Links with SDL2::SDL2-static instead of SDL2::SDL2
|
||||
ENABLE_CURL=ON - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http
|
||||
ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
|
||||
ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations
|
||||
|
|
|
@ -90,6 +90,10 @@ Run it:
|
|||
|
||||
./bin/luanti
|
||||
|
||||
Run unit tests:
|
||||
|
||||
./bin/luanti --run-unittests
|
||||
|
||||
- Use `cmake . -LH` to see all CMake options and their current state.
|
||||
- If you want to install it system-wide (or are making a distribution package),
|
||||
you will want to use `-DRUN_IN_PLACE=FALSE`.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
The long-term roadmaps, aims, and guiding philosophies are set out using the
|
||||
following documents:
|
||||
|
||||
* [What is Minetest?](http://c55.me/blog/?p=1491)
|
||||
* [What is Minetest? (archived)](https://web.archive.org/web/20160328054721/http://c55.me/blog/?p=1491)
|
||||
* [celeron55's roadmap](https://forum.luanti.org/viewtopic.php?t=9177)
|
||||
* [celeron55's comment in "A clear mission statement for Minetest is missing"](https://github.com/luanti-org/luanti/issues/3476#issuecomment-167399287)
|
||||
* [Core developer to-do/wish lists](https://forum.luanti.org/viewforum.php?f=7)
|
||||
|
|
488
doc/lua_api.md
488
doc/lua_api.md
|
@ -5,8 +5,11 @@ Luanti Lua Modding API Reference
|
|||
it's now called `core` due to the renaming of Luanti (formerly Minetest).
|
||||
`minetest` will keep existing as an alias, so that old code won't break.
|
||||
|
||||
Note that `core` has already existed since version 0.4.10, so you can use it
|
||||
safely without breaking backwards compatibility.
|
||||
|
||||
* More information at <http://www.luanti.org/>
|
||||
* Developer Wiki: <https://dev.luanti.org/>
|
||||
* Additional documentation: <https://docs.luanti.org/>
|
||||
* (Unofficial) Minetest Modding Book by rubenwardy: <https://rubenwardy.com/minetest_modding_book/>
|
||||
* Modding tools: <https://github.com/luanti-org/modtools>
|
||||
|
||||
|
@ -518,6 +521,15 @@ stripping out the file extension:
|
|||
|
||||
Supported texture formats are PNG (`.png`), JPEG (`.jpg`) and Targa (`.tga`).
|
||||
|
||||
Luanti generally uses nearest-neighbor upscaling for textures to preserve the crisp
|
||||
look of pixel art (low-res textures).
|
||||
Users can optionally enable bilinear and/or trilinear filtering. However, to avoid
|
||||
everything becoming blurry, textures smaller than 192px will either not be filtered,
|
||||
or will be upscaled to that minimum resolution first without filtering.
|
||||
|
||||
This is subject to change to move more control to the Lua API, but you can rely on
|
||||
low-res textures not suddenly becoming filtered.
|
||||
|
||||
Texture modifiers
|
||||
-----------------
|
||||
|
||||
|
@ -1596,7 +1608,8 @@ There are a bunch of different looking node types.
|
|||
Node boxes
|
||||
----------
|
||||
|
||||
Node selection boxes are defined using "node boxes".
|
||||
Node selection boxes and collision boxes, and the appearance of the `nodebox`
|
||||
drawtype, are defined using "node boxes".
|
||||
|
||||
A nodebox is defined as any of:
|
||||
|
||||
|
@ -1681,7 +1694,9 @@ roughly 1x1x1 meters in size.
|
|||
|
||||
A 'mapblock' (often abbreviated to 'block') is 16x16x16 nodes and is the
|
||||
fundamental region of a world that is stored in the world database, sent to
|
||||
clients and handled by many parts of the engine.
|
||||
clients and handled by many parts of the engine. This size is available as the
|
||||
constant `core.MAP_BLOCKSIZE` (=16).
|
||||
|
||||
'mapblock' is preferred terminology to 'block' to help avoid confusion with
|
||||
'node', however 'block' often appears in the API.
|
||||
|
||||
|
@ -1690,6 +1705,38 @@ A 'mapchunk' (sometimes abbreviated to 'chunk') is usually 5x5x5 mapblocks
|
|||
the map generator.
|
||||
The size in mapblocks has been chosen to optimize map generation.
|
||||
|
||||
### Mapblock status
|
||||
|
||||
A mapblock being "loaded" means that is in memory. These are the mapblocks that
|
||||
API functions like `core.get_node` or `core.set_node` can operate on. To reach
|
||||
this state, the mapblock must first go through the process of being "emerged".
|
||||
This means that it is loaded from disk, and/or, if it isn't yet generated,
|
||||
generated by the map generator.
|
||||
|
||||
Mapblocks are loaded in a broad area around each player. They become "unloaded"
|
||||
again if no player is close enough. The engine commonly represents the contents
|
||||
of unloaded mapblocks as `"ignore"` nodes.
|
||||
|
||||
A mapblock being "active" means that it is not only in memory, but also affected
|
||||
by world simulation:
|
||||
|
||||
* Entities are active
|
||||
* They are in memory as `ServerActiveObject`, exposed to Lua as `ObjectRef`
|
||||
* They exist in Lua as luaentity tables
|
||||
* ABMs are executed
|
||||
* Node timers are executed
|
||||
|
||||
Also, when a mapblock is "activated", LBMs are executed. Mapblocks are active
|
||||
in a smaller area around each player, and are "deactivated" again if no player
|
||||
is close enough.
|
||||
|
||||
Related API functions:
|
||||
|
||||
* `core.compare_block_status`
|
||||
* `core.forceload_block`
|
||||
* `core.load_area`
|
||||
* `core.emerge_area`
|
||||
|
||||
Coordinates
|
||||
-----------
|
||||
|
||||
|
@ -1713,7 +1760,7 @@ node position (0,0,0) to node position (15,15,15).
|
|||
To calculate the blockpos of the mapblock that contains the node at 'nodepos',
|
||||
for each axis:
|
||||
|
||||
* blockpos = math.floor(nodepos / 16)
|
||||
* blockpos = math.floor(nodepos / core.MAP_BLOCKSIZE)
|
||||
|
||||
#### Converting blockpos to min/max node positions
|
||||
|
||||
|
@ -1721,9 +1768,9 @@ To calculate the min/max node positions contained in the mapblock at 'blockpos',
|
|||
for each axis:
|
||||
|
||||
* Minimum:
|
||||
nodepos = blockpos * 16
|
||||
nodepos = blockpos * core.MAP_BLOCKSIZE
|
||||
* Maximum:
|
||||
nodepos = blockpos * 16 + 15
|
||||
nodepos = (blockpos + 1) * core.MAP_BLOCKSIZE - 1
|
||||
|
||||
|
||||
|
||||
|
@ -2024,6 +2071,21 @@ that acts as tool in a gameplay sense as a craftitem, and vice-versa.
|
|||
Craftitems can be used for items that neither need to be a node
|
||||
nor a tool.
|
||||
|
||||
Special Items
|
||||
-------------
|
||||
The following items are predefined and have special properties.
|
||||
|
||||
* `"unknown"`: An item that represents every item which has not been registered
|
||||
* `"air"`: The node which appears everywhere where no other node is
|
||||
* `"ignore"`: Mapblocks that are not loaded are represented using this node.
|
||||
* Also used for nodes that have not yet been set by the map generator.
|
||||
* This is also what appears outside of the map boundary.
|
||||
* `""`: The player's hand, which is in use whenever the player wields no item.
|
||||
* Its range and tool capabilities are also used as a fallback for the wielded item.
|
||||
* It can be overridden to change those properties:
|
||||
* globally using `core.override_item`
|
||||
* per-player using the special `"hand"` inventory list
|
||||
|
||||
Amount and wear
|
||||
---------------
|
||||
|
||||
|
@ -2783,6 +2845,9 @@ Version History
|
|||
* Add field_enter_after_edit[] (experimental)
|
||||
* Formspec version 8 (5.10.0)
|
||||
* scroll_container[]: content padding parameter
|
||||
* Formspec version 9 (5.12.0)
|
||||
* Add allow_close[]
|
||||
* label[]: Add "area label" variant
|
||||
|
||||
Elements
|
||||
--------
|
||||
|
@ -2853,6 +2918,13 @@ Elements
|
|||
* For information on converting forms to the new coordinate system, see `Migrating
|
||||
to Real Coordinates`.
|
||||
|
||||
### `allow_close[<bool>]`
|
||||
|
||||
* When set to false, the formspec will not close when the user tries to close
|
||||
it with the Escape key or similar. Default true.
|
||||
* The formspec can still be closed with `*_exit[]` elements and
|
||||
`core.close_formspec()`, regardless of this setting.
|
||||
|
||||
### `container[<X>,<Y>]`
|
||||
|
||||
* Start of a container block, moves all physical elements in the container by
|
||||
|
@ -3088,9 +3160,11 @@ Elements
|
|||
### `textarea[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
|
||||
|
||||
* Same as fields above, but with multi-line input
|
||||
* Text is wrapped to fit within the given bounds.
|
||||
* If the text overflows, a vertical scrollbar is added.
|
||||
* If the name is empty, the textarea is read-only and
|
||||
the background is not shown, which corresponds to a multi-line label.
|
||||
See also `label[<X>,<Y>;<W>,<H>;<label>]` for an alternative.
|
||||
|
||||
### `label[<X>,<Y>;<label>]`
|
||||
|
||||
|
@ -3105,6 +3179,16 @@ Elements
|
|||
half a coordinate. With the old system, newlines are spaced 2/5 of
|
||||
an inventory slot.
|
||||
|
||||
### `label[<X>,<Y>;<W>,<H>;<label>]`
|
||||
|
||||
* The "area label" formspec element displays the text set in `label`
|
||||
at the specified position and size.
|
||||
* Text is wrapped to fit within the given bounds.
|
||||
* If the text overflows, it is currently simply truncated, but this behavior is
|
||||
subject to change. There is no scrollbar.
|
||||
* See also `textarea` for an alternative.
|
||||
* Only available with the new coordinate system.
|
||||
|
||||
### `hypertext[<X>,<Y>;<W>,<H>;<name>;<text>]`
|
||||
* Displays a static formatted text with hyperlinks.
|
||||
* **Note**: This element is currently unstable and subject to change.
|
||||
|
@ -3766,7 +3850,8 @@ Player Inventory lists
|
|||
* `craftresult`: list containing the crafted output
|
||||
* `hand`: list containing an override for the empty hand
|
||||
* Is not created automatically, use `InvRef:set_size`
|
||||
* Is only used to enhance the empty hand's tool capabilities
|
||||
* Players use the first item in this list as their hand
|
||||
* It behaves as if the default hand `""` has been overridden for this specific player
|
||||
|
||||
Custom lists can be added and deleted with `InvRef:set_size(name, size)` like
|
||||
any other inventory.
|
||||
|
@ -4080,9 +4165,11 @@ Helper functions
|
|||
* `obj`: arbitrary variable
|
||||
* `name`: string, default: `"_"`
|
||||
* `dumped`: table, default: `{}`
|
||||
* `dump(obj, dumped)`: returns a string which makes `obj` human-readable
|
||||
* `obj`: arbitrary variable
|
||||
* `dumped`: table, default: `{}`
|
||||
* `dump(value, indent)`: returns a string which makes `value` human-readable
|
||||
* `value`: arbitrary value
|
||||
* Circular references are supported. Every table is dumped only once.
|
||||
* `indent`: string to use for indentation, default: `"\t"`
|
||||
* `""` disables indentation & line breaks (compact output)
|
||||
* `math.hypot(x, y)`
|
||||
* Get the hypotenuse of a triangle with legs x and y.
|
||||
Useful for distance calculation.
|
||||
|
@ -4142,6 +4229,11 @@ Helper functions
|
|||
* returns time with microsecond precision. May not return wall time.
|
||||
* `table.copy(table)`: returns a table
|
||||
* returns a deep copy of `table`
|
||||
* strips metatables, but this may change in the future
|
||||
* `table.copy_with_metatables(table)`
|
||||
* since 5.12
|
||||
* `table` can also be non-table value, which will be returned as-is
|
||||
* preserves metatables as they are
|
||||
* `table.indexof(list, val)`: returns the smallest numerical index containing
|
||||
the value `val` in the table `list`. Non-numerical indices are ignored.
|
||||
If `val` could not be found, `-1` is returned. `list` must not have
|
||||
|
@ -4464,22 +4556,25 @@ textdomain match the mod name, but this isn't required.
|
|||
|
||||
|
||||
|
||||
Perlin noise
|
||||
============
|
||||
Fractal value noise
|
||||
===================
|
||||
|
||||
Value noise creates a continuously-varying value depending on the input values.
|
||||
It is similar to Perlin noise, but may exhibit more geometric artifacts,
|
||||
as it interpolates between values and not between gradients as in Perlin noise.
|
||||
|
||||
Perlin noise creates a continuously-varying value depending on the input values.
|
||||
Usually in Luanti the input values are either 2D or 3D coordinates in nodes.
|
||||
The result is used during map generation to create the terrain shape, vary heat
|
||||
and humidity to distribute biomes, vary the density of decorations or vary the
|
||||
structure of ores.
|
||||
|
||||
Structure of perlin noise
|
||||
-------------------------
|
||||
Structure of fractal value noise
|
||||
--------------------------------
|
||||
|
||||
An 'octave' is a simple noise generator that outputs a value between -1 and 1.
|
||||
The smooth wavy noise it generates has a single characteristic scale, almost
|
||||
like a 'wavelength', so on its own does not create fine detail.
|
||||
Due to this perlin noise combines several octaves to create variation on
|
||||
Due to this fractal value noise combines several octaves to create variation on
|
||||
multiple scales. Each additional octave has a smaller 'wavelength' than the
|
||||
previous.
|
||||
|
||||
|
@ -4487,13 +4582,15 @@ This combination results in noise varying very roughly between -2.0 and 2.0 and
|
|||
with an average value of 0.0, so `scale` and `offset` are then used to multiply
|
||||
and offset the noise variation.
|
||||
|
||||
The final perlin noise variation is created as follows:
|
||||
The final fractal value noise variation is created as follows:
|
||||
|
||||
```
|
||||
noise = offset + scale * (octave1 +
|
||||
octave2 * persistence +
|
||||
octave3 * persistence ^ 2 +
|
||||
octave4 * persistence ^ 3 +
|
||||
...)
|
||||
```
|
||||
|
||||
Noise Parameters
|
||||
----------------
|
||||
|
@ -4605,17 +4702,19 @@ with restraint.
|
|||
#### `absvalue`
|
||||
|
||||
The absolute value of each octave's noise variation is used when combining the
|
||||
octaves. The final perlin noise variation is created as follows:
|
||||
octaves. The final value noise variation is created as follows:
|
||||
|
||||
```
|
||||
noise = offset + scale * (abs(octave1) +
|
||||
abs(octave2) * persistence +
|
||||
abs(octave3) * persistence ^ 2 +
|
||||
abs(octave4) * persistence ^ 3 +
|
||||
...)
|
||||
```
|
||||
|
||||
### Format example
|
||||
|
||||
For 2D or 3D perlin noise or perlin noise maps:
|
||||
For 2D or 3D value noise or value noise maps:
|
||||
|
||||
```lua
|
||||
np_terrain = {
|
||||
|
@ -4650,13 +4749,13 @@ All default ores are of the uniformly-distributed scatter type.
|
|||
|
||||
Randomly chooses a location and generates a cluster of ore.
|
||||
|
||||
If `noise_params` is specified, the ore will be placed if the 3D perlin noise
|
||||
If `noise_params` is specified, the ore will be placed if the 3D value noise
|
||||
at that point is greater than the `noise_threshold`, giving the ability to
|
||||
create a non-equal distribution of ore.
|
||||
|
||||
### `sheet`
|
||||
|
||||
Creates a sheet of ore in a blob shape according to the 2D perlin noise
|
||||
Creates a sheet of ore in a blob shape according to the 2D value noise
|
||||
described by `noise_params` and `noise_threshold`. This is essentially an
|
||||
improved version of the so-called "stratus" ore seen in some unofficial mods.
|
||||
|
||||
|
@ -4689,14 +4788,14 @@ noise parameters `np_puff_top` and `np_puff_bottom`, respectively.
|
|||
|
||||
### `blob`
|
||||
|
||||
Creates a deformed sphere of ore according to 3d perlin noise described by
|
||||
Creates a deformed sphere of ore according to 3d value noise described by
|
||||
`noise_params`. The maximum size of the blob is `clust_size`, and
|
||||
`clust_scarcity` has the same meaning as with the `scatter` type.
|
||||
|
||||
### `vein`
|
||||
|
||||
Creates veins of ore varying in density by according to the intersection of two
|
||||
instances of 3d perlin noise with different seeds, both described by
|
||||
instances of 3d value noise with different seeds, both described by
|
||||
`noise_params`.
|
||||
|
||||
`random_factor` varies the influence random chance has on placement of an ore
|
||||
|
@ -4731,8 +4830,8 @@ computationally expensive than any other ore.
|
|||
Creates a single undulating ore stratum that is continuous across mapchunk
|
||||
borders and horizontally spans the world.
|
||||
|
||||
The 2D perlin noise described by `noise_params` defines the Y coordinate of
|
||||
the stratum midpoint. The 2D perlin noise described by `np_stratum_thickness`
|
||||
The 2D value noise described by `noise_params` defines the Y coordinate of
|
||||
the stratum midpoint. The 2D value noise described by `np_stratum_thickness`
|
||||
defines the stratum's vertical thickness (in units of nodes). Due to being
|
||||
continuous across mapchunk borders the stratum's vertical thickness is
|
||||
unlimited.
|
||||
|
@ -4980,7 +5079,7 @@ and the array index for a position p contained completely in p1..p2 is:
|
|||
`(p.Z - p1.Z) * Ny * Nx + (p.Y - p1.Y) * Nx + (p.X - p1.X) + 1`
|
||||
|
||||
Note that this is the same "flat 3D array" format as
|
||||
`PerlinNoiseMap:get3dMap_flat()`.
|
||||
`ValueNoiseMap:get3dMap_flat()`.
|
||||
VoxelArea objects (see section [`VoxelArea`]) can be used to simplify calculation
|
||||
of the index for a single point in a flat VoxelManip array.
|
||||
|
||||
|
@ -5171,7 +5270,7 @@ The coordinates are *inclusive*, like most other things in Luanti.
|
|||
* The position (x, y, z) is not checked for being inside the area volume,
|
||||
being outside can cause an incorrect index result.
|
||||
* Useful for things like `VoxelManip`, raw Schematic specifiers,
|
||||
`PerlinNoiseMap:get2d`/`3dMap`, and so on.
|
||||
`ValueNoiseMap:get2d`/`3dMap`, and so on.
|
||||
* `indexp(p)`: same functionality as `index(x, y, z)` but takes a vector.
|
||||
* As with `index(x, y, z)`, the components of `p` must be integers, and `p`
|
||||
is not checked for being inside the area volume.
|
||||
|
@ -5505,7 +5604,6 @@ provided by the Luanti engine and can be used by mods:
|
|||
* `fly`: can use "fly mode" to move freely above the ground without falling.
|
||||
* `noclip`: can use "noclip mode" to fly through solid nodes (e.g. walls).
|
||||
* `teleport`: can use `/teleport` command to move to any point in the world.
|
||||
* `creative`: can access creative inventory.
|
||||
* `bring`: can teleport other players to oneself.
|
||||
* `give`: can use `/give` and `/giveme` commands to give any item
|
||||
in the game to oneself or others.
|
||||
|
@ -5691,6 +5789,8 @@ Utilities
|
|||
particle_blend_clip = true,
|
||||
-- The `match_meta` optional parameter is available for `InvRef:remove_item()` (5.12.0)
|
||||
remove_item_match_meta = true,
|
||||
-- The HTTP API supports the HEAD and PATCH methods (5.12.0)
|
||||
httpfetch_additional_methods = true,
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -5888,16 +5988,23 @@ Call these functions only at load time!
|
|||
|
||||
### Environment
|
||||
|
||||
* `core.register_node(name, node definition)`
|
||||
* `core.register_craftitem(name, item definition)`
|
||||
* `core.register_tool(name, item definition)`
|
||||
* `core.register_node(name, nodedef)`
|
||||
* register a node with its definition
|
||||
* Note: you must pass a clean table that hasn't already been used for
|
||||
another registration to this function, as it will be modified.
|
||||
* `core.register_craftitem(name, itemdef)`
|
||||
* register an item with its definition
|
||||
* Note: (as above)
|
||||
* `core.register_tool(name, tooldef)`
|
||||
* register a tool item with its definition
|
||||
* Note: (as above)
|
||||
* `core.override_item(name, redefinition, del_fields)`
|
||||
* `redefinition` is a table of fields `[name] = new_value`,
|
||||
overwriting fields of or adding fields to the existing definition.
|
||||
* `del_fields` is a list of field names to be set
|
||||
to `nil` ("deleted from") the original definition.
|
||||
* Overrides fields of an item registered with register_node/tool/craftitem.
|
||||
* Note: Item must already be defined, (opt)depend on the mod defining it.
|
||||
* Note: Item must already be defined.
|
||||
* Example: `core.override_item("default:mese",
|
||||
{light_source=core.LIGHT_MAX}, {"sounds"})`:
|
||||
Overwrites the `light_source` field,
|
||||
|
@ -5905,7 +6012,7 @@ Call these functions only at load time!
|
|||
* `core.unregister_item(name)`
|
||||
* Unregisters the item from the engine, and deletes the entry with key
|
||||
`name` from `core.registered_items` and from the associated item table
|
||||
according to its nature: `core.registered_nodes`, etc.
|
||||
according to its nature (e.g. `core.registered_nodes`)
|
||||
* `core.register_entity(name, entity definition)`
|
||||
* `core.register_abm(abm definition)`
|
||||
* `core.register_lbm(lbm definition)`
|
||||
|
@ -6140,8 +6247,10 @@ Call these functions only at load time!
|
|||
* `table`: See `core.explode_table_event`
|
||||
* `scrollbar`: See `core.explode_scrollbar_event`
|
||||
* Special case: `["quit"]="true"` is sent when the user actively
|
||||
closed the form by mouse click, keypress or through a button_exit[]
|
||||
closed the form by mouse click, keypress or through a `button_exit[]`
|
||||
element.
|
||||
* Special case: `["try_quit"]="true"` is sent when the user tries to
|
||||
close the formspec, but the formspec used `allow_close[false]`.
|
||||
* Special case: `["key_enter"]="true"` is sent when the user pressed
|
||||
the Enter key and the focus was either nowhere (causing the formspec
|
||||
to be closed) or on a button. If the focus was on a text field,
|
||||
|
@ -6449,18 +6558,21 @@ Environment access
|
|||
first value: Table with all node positions
|
||||
second value: Table with the count of each node with the node name
|
||||
as index
|
||||
* Area volume is limited to 4,096,000 nodes
|
||||
* Area volume is limited to 150,000,000 nodes
|
||||
* `core.find_nodes_in_area_under_air(pos1, pos2, nodenames)`: returns a
|
||||
list of positions.
|
||||
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
|
||||
* Return value: Table with all node positions with a node air above
|
||||
* Area volume is limited to 4,096,000 nodes
|
||||
* `core.get_perlin(noiseparams)`
|
||||
* Return world-specific perlin noise.
|
||||
* Area volume is limited to 150,000,000 nodes
|
||||
* `core.get_value_noise(noiseparams)`
|
||||
* Return world-specific value noise.
|
||||
* The actual seed used is the noiseparams seed plus the world seed.
|
||||
* `core.get_value_noise(seeddiff, octaves, persistence, spread)`
|
||||
* Deprecated: use `core.get_value_noise(noiseparams)` instead.
|
||||
* `core.get_perlin(noiseparams)`
|
||||
* Deprecated: renamed to `core.get_value_noise` in version 5.12.0.
|
||||
* `core.get_perlin(seeddiff, octaves, persistence, spread)`
|
||||
* Deprecated: use `core.get_perlin(noiseparams)` instead.
|
||||
* Return world-specific perlin noise.
|
||||
* Deprecated: renamed to `core.get_value_noise` in version 5.12.0.
|
||||
* `core.get_voxel_manip([pos1, pos2])`
|
||||
* Return voxel manipulator object.
|
||||
* Loads the manipulator from the map if positions are passed.
|
||||
|
@ -6829,11 +6941,16 @@ Item handling
|
|||
given `param2` value.
|
||||
* Returns `nil` if the given `paramtype2` does not contain color
|
||||
information.
|
||||
* `core.get_node_drops(node, toolname)`
|
||||
* Returns list of itemstrings that are dropped by `node` when dug
|
||||
with the item `toolname` (not limited to tools).
|
||||
* `core.get_node_drops(node, toolname[, tool, digger, pos])`
|
||||
* Returns list of itemstrings that are dropped by `node` when dug with the
|
||||
item `toolname` (not limited to tools). The default implementation doesn't
|
||||
use `tool`, `digger`, and `pos`, but these are provided by `core.node_dig`
|
||||
since 5.12.0 for games/mods implementing customized drops.
|
||||
* `node`: node as table or node name
|
||||
* `toolname`: name of the item used to dig (can be `nil`)
|
||||
* `tool`: `ItemStack` used to dig (can be `nil`)
|
||||
* `digger`: the ObjectRef that digs the node (can be `nil`)
|
||||
* `pos`: the pos of the dug node (can be `nil`)
|
||||
* `core.get_craft_result(input)`: returns `output, decremented_input`
|
||||
* `input.method` = `"normal"` or `"cooking"` or `"fuel"`
|
||||
* `input.width` = for example `3`
|
||||
|
@ -6937,8 +7054,13 @@ Defaults for the `on_place` and `on_drop` item definition functions
|
|||
* Parameters are the same as in `on_pickup`.
|
||||
* Returns the leftover itemstack.
|
||||
* `core.item_drop(itemstack, dropper, pos)`
|
||||
* Drop the item
|
||||
* returns the leftover itemstack
|
||||
* Converts `itemstack` to an in-world Lua entity.
|
||||
* `itemstack` (`ItemStack`) is modified (cleared) on success.
|
||||
* In versions < 5.12.0, `itemstack` was cleared in all cases.
|
||||
* `dropper` (`ObjectRef`) is optional.
|
||||
* Returned values on success:
|
||||
1. leftover itemstack
|
||||
2. `ObjectRef` of the spawned object (provided since 5.12.0)
|
||||
* `core.item_eat(hp_change[, replace_with_item])`
|
||||
* Returns `function(itemstack, user, pointed_thing)` as a
|
||||
function wrapper for `core.do_item_eat`.
|
||||
|
@ -7030,8 +7152,8 @@ Classes:
|
|||
|
||||
* `AreaStore`
|
||||
* `ItemStack`
|
||||
* `PerlinNoise`
|
||||
* `PerlinNoiseMap`
|
||||
* `ValueNoise`
|
||||
* `ValueNoiseMap`
|
||||
* `PseudoRandom`
|
||||
* `PcgRandom`
|
||||
* `SecureRandom`
|
||||
|
@ -7043,8 +7165,8 @@ Classes:
|
|||
Class instances that can be transferred between environments:
|
||||
|
||||
* `ItemStack`
|
||||
* `PerlinNoise`
|
||||
* `PerlinNoiseMap`
|
||||
* `ValueNoise`
|
||||
* `ValueNoiseMap`
|
||||
* `VoxelManip`
|
||||
|
||||
Functions:
|
||||
|
@ -7110,8 +7232,8 @@ Classes:
|
|||
|
||||
* `AreaStore`
|
||||
* `ItemStack`
|
||||
* `PerlinNoise`
|
||||
* `PerlinNoiseMap`
|
||||
* `ValueNoise`
|
||||
* `ValueNoiseMap`
|
||||
* `PseudoRandom`
|
||||
* `PcgRandom`
|
||||
* `SecureRandom`
|
||||
|
@ -7456,7 +7578,8 @@ Misc.
|
|||
* This function can be overridden by mods to change the leave message.
|
||||
* `core.hash_node_position(pos)`: returns a 48-bit integer
|
||||
* `pos`: table {x=number, y=number, z=number},
|
||||
* Gives a unique hash number for a node position (16+16+16=48bit)
|
||||
* Gives a unique numeric encoding for a node position (16+16+16=48bit)
|
||||
* Despite the name, this is not a hash function (so it doesn't mix or produce collisions).
|
||||
* `core.get_position_from_hash(hash)`: returns a position
|
||||
* Inverse transform of `core.hash_node_position`
|
||||
* `core.get_item_group(name, group)`: returns a rating
|
||||
|
@ -7494,16 +7617,22 @@ Misc.
|
|||
* Example: `write_json({10, {a = false}})`,
|
||||
returns `'[10, {"a": false}]'`
|
||||
* `core.serialize(table)`: returns a string
|
||||
* Convert a table containing tables, strings, numbers, booleans and `nil`s
|
||||
into string form readable by `core.deserialize`
|
||||
* Convert a value into string form readable by `core.deserialize`.
|
||||
* Supports tables, strings, numbers, booleans and `nil`.
|
||||
* Support for dumping function bytecode is **deprecated**.
|
||||
* Note: To obtain a human-readable representation of a value, use `dump` instead.
|
||||
* Example: `serialize({foo="bar"})`, returns `'return { ["foo"] = "bar" }'`
|
||||
* `core.deserialize(string[, safe])`: returns a table
|
||||
* Convert a string returned by `core.serialize` into a table
|
||||
* `string` is loaded in an empty sandbox environment.
|
||||
* Will load functions if safe is false or omitted. Although these functions
|
||||
cannot directly access the global environment, they could bypass this
|
||||
restriction with maliciously crafted Lua bytecode if mod security is
|
||||
disabled.
|
||||
* Will load functions if `safe` is `false` or omitted.
|
||||
Although these functions cannot directly access the global environment,
|
||||
they could bypass this restriction with maliciously crafted Lua bytecode
|
||||
if mod security is disabled.
|
||||
* Will silently strip functions embedded via calls to `loadstring`
|
||||
(typically bytecode dumped by `core.serialize`) if `safe` is `true`.
|
||||
You should not rely on this if possible.
|
||||
* Example: `core.deserialize("return loadstring('')", true)` will be `nil`.
|
||||
* This function should not be used on untrusted data, regardless of the
|
||||
value of `safe`. It is fine to serialize then deserialize user-provided
|
||||
data, but directly providing user input to deserialize is always unsafe.
|
||||
|
@ -7616,6 +7745,8 @@ Misc.
|
|||
|
||||
* `core.forceload_block(pos[, transient[, limit]])`
|
||||
* forceloads the position `pos`.
|
||||
* this means that the mapblock containing `pos` will always be kept in the
|
||||
`"active"` state, regardless of nearby players or server settings.
|
||||
* returns `true` if area could be forceloaded
|
||||
* If `transient` is `false` or absent, the forceload will be persistent
|
||||
(saved between server runs). If `true`, the forceload will be transient
|
||||
|
@ -8044,8 +8175,8 @@ of the `${k}` syntax in formspecs is not deprecated.
|
|||
The value will be converted into a string when stored.
|
||||
* `get_int(key)`: Returns `0` if key not present.
|
||||
* `set_float(key, value)`
|
||||
* The range for the value is system-dependent (usually 32 bits).
|
||||
The value will be converted into a string when stored.
|
||||
* Store a number (a 64-bit float) exactly.
|
||||
* The value will be converted into a string when stored.
|
||||
* `get_float(key)`: Returns `0` if key not present.
|
||||
* `get_keys()`: returns a list of all keys in the metadata.
|
||||
* `to_table()`:
|
||||
|
@ -8934,70 +9065,6 @@ offering very strong randomness.
|
|||
* `get_state()`: return generator state encoded in string
|
||||
* `set_state(state_string)`: restore generator state from encoded string
|
||||
|
||||
`PerlinNoise`
|
||||
-------------
|
||||
|
||||
A perlin noise generator.
|
||||
It can be created via `PerlinNoise()` or `core.get_perlin()`.
|
||||
For `core.get_perlin()`, the actual seed used is the noiseparams seed
|
||||
plus the world seed, to create world-specific noise.
|
||||
|
||||
`PerlinNoise(noiseparams)`
|
||||
`PerlinNoise(seed, octaves, persistence, spread)` (Deprecated).
|
||||
|
||||
`core.get_perlin(noiseparams)`
|
||||
`core.get_perlin(seeddiff, octaves, persistence, spread)` (Deprecated).
|
||||
|
||||
### Methods
|
||||
|
||||
* `get_2d(pos)`: returns 2D noise value at `pos={x=,y=}`
|
||||
* `get_3d(pos)`: returns 3D noise value at `pos={x=,y=,z=}`
|
||||
|
||||
`PerlinNoiseMap`
|
||||
----------------
|
||||
|
||||
A fast, bulk perlin noise generator.
|
||||
|
||||
It can be created via `PerlinNoiseMap(noiseparams, size)` or
|
||||
`core.get_perlin_map(noiseparams, size)`.
|
||||
For `core.get_perlin_map()`, the actual seed used is the noiseparams seed
|
||||
plus the world seed, to create world-specific noise.
|
||||
|
||||
Format of `size` is `{x=dimx, y=dimy, z=dimz}`. The `z` component is omitted
|
||||
for 2D noise, and it must be larger than 1 for 3D noise (otherwise
|
||||
`nil` is returned).
|
||||
|
||||
For each of the functions with an optional `buffer` parameter: If `buffer` is
|
||||
not nil, this table will be used to store the result instead of creating a new
|
||||
table.
|
||||
|
||||
### Methods
|
||||
|
||||
* `get_2d_map(pos)`: returns a `<size.x>` times `<size.y>` 2D array of 2D noise
|
||||
with values starting at `pos={x=,y=}`
|
||||
* `get_3d_map(pos)`: returns a `<size.x>` times `<size.y>` times `<size.z>`
|
||||
3D array of 3D noise with values starting at `pos={x=,y=,z=}`.
|
||||
* `get_2d_map_flat(pos, buffer)`: returns a flat `<size.x * size.y>` element
|
||||
array of 2D noise with values starting at `pos={x=,y=}`
|
||||
* `get_3d_map_flat(pos, buffer)`: Same as `get2dMap_flat`, but 3D noise
|
||||
* `calc_2d_map(pos)`: Calculates the 2d noise map starting at `pos`. The result
|
||||
is stored internally.
|
||||
* `calc_3d_map(pos)`: Calculates the 3d noise map starting at `pos`. The result
|
||||
is stored internally.
|
||||
* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array,
|
||||
returns a slice of the most recently computed noise results. The result slice
|
||||
begins at coordinates `slice_offset` and takes a chunk of `slice_size`.
|
||||
E.g. to grab a 2-slice high horizontal 2d plane of noise starting at buffer
|
||||
offset y = 20:
|
||||
`noisevals = noise:get_map_slice({y=20}, {y=2})`
|
||||
It is important to note that `slice_offset` offset coordinates begin at 1,
|
||||
and are relative to the starting position of the most recently calculated
|
||||
noise.
|
||||
To grab a single vertical column of noise starting at map coordinates
|
||||
x = 1023, y=1000, z = 1000:
|
||||
`noise:calc_3d_map({x=1000, y=1000, z=1000})`
|
||||
`noisevals = noise:get_map_slice({x=24, z=1}, {x=1, z=1})`
|
||||
|
||||
`PlayerMetaRef`
|
||||
---------------
|
||||
|
||||
|
@ -9049,14 +9116,17 @@ end
|
|||
The map is loaded as the ray advances. If the map is modified after the
|
||||
`Raycast` is created, the changes may or may not have an effect on the object.
|
||||
|
||||
It can be created via `Raycast(pos1, pos2, objects, liquids)` or
|
||||
`core.raycast(pos1, pos2, objects, liquids)` where:
|
||||
It can be created via `Raycast(pos1, pos2, objects, liquids, pointabilities)`
|
||||
or `core.raycast(pos1, pos2, objects, liquids, pointabilities)` where:
|
||||
|
||||
* `pos1`: start of the ray
|
||||
* `pos2`: end of the ray
|
||||
* `objects`: if false, only nodes will be returned. Default is true.
|
||||
* `objects`: if false, only nodes will be returned. Default is `true`.
|
||||
* `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be
|
||||
returned. Default is false.
|
||||
returned. Default is `false`.
|
||||
* `pointabilities`: Allows overriding the `pointable` property of
|
||||
nodes and objects. Uses the same format as the `pointabilities` property
|
||||
of item definitions. Default is `nil`.
|
||||
|
||||
### Limitations
|
||||
|
||||
|
@ -9162,7 +9232,7 @@ The settings have the format `key = value`. Example:
|
|||
`StorageRef`
|
||||
------------
|
||||
|
||||
Mod metadata: per mod metadata, saved automatically.
|
||||
Mod metadata: per mod and world metadata, saved automatically.
|
||||
Can be obtained via `core.get_mod_storage()` during load time.
|
||||
|
||||
WARNING: This storage backend is incapable of saving raw binary data due
|
||||
|
@ -9172,6 +9242,81 @@ to restrictions of JSON.
|
|||
|
||||
* All methods in MetaDataRef
|
||||
|
||||
`ValueNoise`
|
||||
-------------
|
||||
|
||||
A value noise generator.
|
||||
It can be created via `ValueNoise()` or `core.get_value_noise()`.
|
||||
For `core.get_value_noise()`, the actual seed used is the noiseparams seed
|
||||
plus the world seed, to create world-specific noise.
|
||||
|
||||
* `ValueNoise(noiseparams)`
|
||||
* `ValueNoise(seed, octaves, persistence, spread)` (deprecated)
|
||||
* `core.get_value_noise(noiseparams)`
|
||||
* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (deprecated)
|
||||
|
||||
These were previously called `PerlinNoise()` and `core.get_perlin()`, but the
|
||||
implemented noise was not Perlin noise. They were renamed in 5.12.0. The old
|
||||
names still exist as aliases.
|
||||
|
||||
### Methods
|
||||
|
||||
* `get_2d(pos)`: returns 2D noise value at `pos={x=,y=}`
|
||||
* `get_3d(pos)`: returns 3D noise value at `pos={x=,y=,z=}`
|
||||
|
||||
`ValueNoiseMap`
|
||||
----------------
|
||||
|
||||
A fast, bulk noise generator.
|
||||
|
||||
It can be created via `ValueNoiseMap(noiseparams, size)` or
|
||||
`core.get_value_noise_map(noiseparams, size)`.
|
||||
For `core.get_value_noise_map()`, the actual seed used is the noiseparams seed
|
||||
plus the world seed, to create world-specific noise.
|
||||
|
||||
These were previously called `PerlinNoiseMap()` and `core.get_perlin_map()`,
|
||||
but the implemented noise was not Perlin noise. They were renamed in 5.12.0.
|
||||
The old names still exist as aliases.
|
||||
|
||||
Format of `size` is `{x=dimx, y=dimy, z=dimz}`. The `z` component is omitted
|
||||
for 2D noise, and it must be larger than 1 for 3D noise (otherwise
|
||||
`nil` is returned).
|
||||
|
||||
For each of the functions with an optional `buffer` parameter: If `buffer` is
|
||||
not nil, this table will be used to store the result instead of creating a new
|
||||
table.
|
||||
|
||||
### Methods
|
||||
|
||||
* `get_2d_map(pos)`: returns a `<size.x>` times `<size.y>` 2D array of 2D noise
|
||||
with values starting at `pos={x=,y=}`
|
||||
* `get_3d_map(pos)`: returns a `<size.x>` times `<size.y>` times `<size.z>`
|
||||
3D array of 3D noise with values starting at `pos={x=,y=,z=}`.
|
||||
* `get_2d_map_flat(pos, buffer)`: returns a flat `<size.x * size.y>` element
|
||||
array of 2D noise with values starting at `pos={x=,y=}`
|
||||
* `get_3d_map_flat(pos, buffer)`: Same as `get2dMap_flat`, but 3D noise
|
||||
* `calc_2d_map(pos)`: Calculates the 2d noise map starting at `pos`. The result
|
||||
is stored internally.
|
||||
* `calc_3d_map(pos)`: Calculates the 3d noise map starting at `pos`. The result
|
||||
is stored internally.
|
||||
* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array,
|
||||
returns a slice of the most recently computed noise results. The result slice
|
||||
begins at coordinates `slice_offset` and takes a chunk of `slice_size`.
|
||||
E.g., to grab a 2-slice high horizontal 2d plane of noise starting at buffer
|
||||
offset `y = 20`:
|
||||
```lua
|
||||
noisevals = noise:get_map_slice({y=20}, {y=2})
|
||||
```
|
||||
It is important to note that `slice_offset` offset coordinates begin at 1,
|
||||
and are relative to the starting position of the most recently calculated
|
||||
noise.
|
||||
To grab a single vertical column of noise starting at map coordinates
|
||||
`x = 1023, y=1000, z = 1000`:
|
||||
```lua
|
||||
noise:calc_3d_map({x=1000, y=1000, z=1000})
|
||||
noisevals = noise:get_map_slice({x=24, z=1}, {x=1, z=1})
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -9263,7 +9408,8 @@ Player properties need to be saved manually.
|
|||
-- to scale the entity along both horizontal axes.
|
||||
|
||||
mesh = "model.obj",
|
||||
-- File name of mesh when using "mesh" visual
|
||||
-- File name of mesh when using "mesh" visual.
|
||||
-- For legacy reasons, this uses a 10x scale for meshes: 10 units = 1 node.
|
||||
|
||||
textures = {},
|
||||
-- Number of required textures depends on visual:
|
||||
|
@ -9410,6 +9556,10 @@ ABM (ActiveBlockModifier) definition
|
|||
|
||||
Used by `core.register_abm`.
|
||||
|
||||
An active block modifier (ABM) is used to define a function that is continously
|
||||
and randomly called for specific nodes (defined by `nodenames` and other conditions)
|
||||
in active mapblocks.
|
||||
|
||||
```lua
|
||||
{
|
||||
label = "Lava cooling",
|
||||
|
@ -9466,12 +9616,29 @@ Used by `core.register_lbm`.
|
|||
|
||||
A loading block modifier (LBM) is used to define a function that is called for
|
||||
specific nodes (defined by `nodenames`) when a mapblock which contains such nodes
|
||||
gets activated (not loaded!).
|
||||
gets **activated** (**not loaded!**).
|
||||
|
||||
Note: LBMs operate on a "snapshot" of node positions taken once before they are triggered.
|
||||
*Note*: LBMs operate on a "snapshot" of node positions taken once before they are triggered.
|
||||
That means if an LBM callback adds a node, it won't be taken into account.
|
||||
However the engine guarantees that when the callback is called that all given position(s)
|
||||
contain a matching node.
|
||||
However the engine guarantees that at the point in time when the callback is called
|
||||
that all given positions contain a matching node.
|
||||
|
||||
For `run_at_every_load = false` to work, both mapblocks and LBMs have timestamps
|
||||
associated with them:
|
||||
|
||||
* Each mapblock has a "last active" timestamp. It is also updated when the
|
||||
mapblock is generated.
|
||||
* For each LBM, an introduction timestamp is stored in the world data, identified
|
||||
by the LBM's `name` field. If an LBM disappears, the corresponding timestamp
|
||||
is cleared.
|
||||
|
||||
When a mapblock is activated, only LBMs whose introduction timestamp is newer
|
||||
than the mapblock's timestamp are run.
|
||||
|
||||
*Note*: For maps generated in 5.11.0 or older, many newly generated mapblocks
|
||||
did not get a timestamp set. This means LBMs introduced between generation time
|
||||
and time of first activation will never run.
|
||||
Currently the only workaround is to use `run_at_every_load = true`.
|
||||
|
||||
```lua
|
||||
{
|
||||
|
@ -9488,14 +9655,17 @@ contain a matching node.
|
|||
-- will work as well.
|
||||
|
||||
run_at_every_load = false,
|
||||
-- Whether to run the LBM's action every time a block gets activated,
|
||||
-- and not only the first time the block gets activated after the LBM
|
||||
-- was introduced.
|
||||
-- If `false`: The LBM only runs on mapblocks the first time they are
|
||||
-- activated after the LBM was introduced.
|
||||
-- It never runs on mapblocks generated after the LBM's introduction.
|
||||
-- See above for details.
|
||||
--
|
||||
-- If `true`: The LBM runs every time a mapblock is activated.
|
||||
|
||||
action = function(pos, node, dtime_s) end,
|
||||
-- Function triggered for each qualifying node.
|
||||
-- `dtime_s` is the in-game time (in seconds) elapsed since the block
|
||||
-- was last active.
|
||||
-- `dtime_s` is the in-game time (in seconds) elapsed since the mapblock
|
||||
-- was last active (available since 5.7.0).
|
||||
|
||||
bulk_action = function(pos_list, dtime_s) end,
|
||||
-- Function triggered with a list of all applicable node positions at once.
|
||||
|
@ -10011,6 +10181,13 @@ Used by `core.register_node`.
|
|||
|
||||
mesh = "",
|
||||
-- File name of mesh when using "mesh" drawtype
|
||||
-- The center of the node is the model origin.
|
||||
-- For legacy reasons, this uses a different scale depending on the mesh:
|
||||
-- 1. For glTF models: 10 units = 1 node (consistent with the scale for entities).
|
||||
-- 2. For obj models: 1 unit = 1 node.
|
||||
-- 3. For b3d and x models: 1 unit = 1 node if static, otherwise 10 units = 1 node.
|
||||
-- Using static glTF or obj models is recommended.
|
||||
-- You can use the `visual_scale` multiplier to achieve the expected scale.
|
||||
|
||||
selection_box = {
|
||||
-- see [Node boxes] for possibilities
|
||||
|
@ -10317,6 +10494,16 @@ table format. The accepted parameters are listed below.
|
|||
|
||||
Recipe input items can either be specified by item name (item count = 1)
|
||||
or by group (see "Groups in crafting recipes" for details).
|
||||
Only the item name (and groups) matter for matching a recipe, i.e. meta and count
|
||||
are ignored.
|
||||
|
||||
If multiple recipes match the input of a craft grid, one of them is chosen by the
|
||||
following priority rules:
|
||||
|
||||
* Shaped recipes are preferred over shapeless recipes, which in turn are preferred
|
||||
over tool repair.
|
||||
* Otherwise, recipes without groups are preferred over recipes with groups.
|
||||
* Otherwise, earlier registered recipes are preferred.
|
||||
|
||||
The following sections describe the types and syntaxes of recipes.
|
||||
|
||||
|
@ -10336,6 +10523,10 @@ For example, for a 3x3 recipe, the `recipes` table must have
|
|||
In order to craft the recipe, the players' crafting grid must
|
||||
have equal or larger dimensions (both width and height).
|
||||
|
||||
Empty slots outside of the recipe's extents are ignored, e.g. a 3x3
|
||||
recipe where only the bottom right 2x2 slots are filled is the same
|
||||
as the corresponding 2x2 recipe without the empty slots.
|
||||
|
||||
Parameters:
|
||||
|
||||
* `type = "shaped"`: (optional) specifies recipe type as shaped
|
||||
|
@ -10651,7 +10842,7 @@ See [Ores] section above for essential information.
|
|||
octaves = 3,
|
||||
persistence = 0.7
|
||||
},
|
||||
-- NoiseParams structure describing one of the perlin noises used for
|
||||
-- NoiseParams structure describing one of the noises used for
|
||||
-- ore distribution.
|
||||
-- Needed by "sheet", "puff", "blob" and "vein" ores.
|
||||
-- Omit from "scatter" ore for a uniform ore distribution.
|
||||
|
@ -10838,7 +11029,7 @@ See [Decoration types]. Used by `core.register_decoration`.
|
|||
lacunarity = 2.0,
|
||||
flags = "absvalue"
|
||||
},
|
||||
-- NoiseParams structure describing the perlin noise used for decoration
|
||||
-- NoiseParams structure describing the noise used for decoration
|
||||
-- distribution.
|
||||
-- A noise value is calculated for each square division and determines
|
||||
-- 'decorations per surface node' within each division.
|
||||
|
@ -11656,22 +11847,22 @@ Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
|
|||
|
||||
```lua
|
||||
{
|
||||
url = "http://example.org",
|
||||
url = "https://example.org",
|
||||
|
||||
timeout = 10,
|
||||
-- Timeout for request to be completed in seconds. Default depends on engine settings.
|
||||
|
||||
method = "GET", "POST", "PUT" or "DELETE"
|
||||
method = "GET", "HEAD", "POST", "PUT", "PATCH" or "DELETE"
|
||||
-- The http method to use. Defaults to "GET".
|
||||
|
||||
data = "Raw request data string" OR {field1 = "data1", field2 = "data2"},
|
||||
-- Data for the POST, PUT or DELETE request.
|
||||
data = "Raw request data string" or {field1 = "data1", field2 = "data2"},
|
||||
-- Data for the POST, PUT, PATCH or DELETE request.
|
||||
-- Accepts both a string and a table. If a table is specified, encodes
|
||||
-- table as x-www-form-urlencoded key-value pairs.
|
||||
|
||||
user_agent = "ExampleUserAgent",
|
||||
-- Optional, if specified replaces the default Luanti user agent with
|
||||
-- given string
|
||||
-- given string.
|
||||
|
||||
extra_headers = { "Accept-Language: en-us", "Accept-Charset: utf-8" },
|
||||
-- Optional, if specified adds additional headers to the HTTP request.
|
||||
|
@ -11681,7 +11872,7 @@ Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
|
|||
multipart = boolean
|
||||
-- Optional, if true performs a multipart HTTP request.
|
||||
-- Default is false.
|
||||
-- Post only, data must be array
|
||||
-- Not allowed for GET or HEAD method and `data` must be a table.
|
||||
|
||||
post_data = "Raw POST request data string" OR {field1 = "data1", field2 = "data2"},
|
||||
-- Deprecated, use `data` instead. Forces `method = "POST"`.
|
||||
|
@ -11709,7 +11900,8 @@ Passed to `HTTPApiTable.fetch` callback. Returned by
|
|||
code = 200,
|
||||
-- HTTP status code
|
||||
|
||||
data = "response"
|
||||
data = "",
|
||||
-- Response body
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Luanti Lua Mainmenu API Reference 5.12.0
|
||||
Luanti Lua Mainmenu API Reference 5.13.0
|
||||
========================================
|
||||
|
||||
Introduction
|
||||
|
@ -25,6 +25,8 @@ Callbacks
|
|||
* `core.event_handler(event)`
|
||||
* `event`: `"MenuQuit"`, `"KeyEnter"`, `"ExitButton"`, `"EditBoxEnter"` or
|
||||
`"FullscreenChange"`
|
||||
* `core.on_before_close()`: called before the menu is closed, either to exit or
|
||||
to join a game
|
||||
|
||||
|
||||
Gamedata
|
||||
|
@ -217,7 +219,6 @@ GUI
|
|||
doing tiling (background only)
|
||||
* `core.set_clouds(<true/false>)`
|
||||
* `core.set_topleft_text(text)`
|
||||
* `core.show_keys_menu()`
|
||||
* `core.show_touchscreen_layout()`
|
||||
* `core.show_path_select_dialog(formname, caption, is_file_select)`
|
||||
* shows a path select dialog
|
||||
|
@ -331,7 +332,7 @@ Package - content which is downloadable from the content db, may or may not be i
|
|||
```lua
|
||||
{
|
||||
name = "technical_id",
|
||||
type = "mod" or "modpack" or "game" or "txp",
|
||||
type = "mod" or "modpack" or "game" or "txp" or "unknown",
|
||||
title = "Human readable title",
|
||||
description = "description",
|
||||
author = "author",
|
||||
|
|
|
@ -22,6 +22,11 @@ This is a directory containing the entire contents of a single texture pack.
|
|||
It can be chosen more or less freely and will also become the name of the
|
||||
texture pack. The name must not be “base”.
|
||||
|
||||
### The "server" texture pack
|
||||
If a texture pack named `server` exists, the textures in it will replace textures
|
||||
sent to clients.
|
||||
It's independent of the client's texture pack, which will take precedence as usual.
|
||||
|
||||
### `texture_pack.conf`
|
||||
A key-value config file with the following keys:
|
||||
|
||||
|
@ -139,21 +144,34 @@ are placeholders intended to be overwritten by the game.
|
|||
|
||||
### Android textures
|
||||
|
||||
* `drop_btn.png`
|
||||
* `fast_btn.png`
|
||||
* `fly_btn.png`
|
||||
* `jump_btn.png`
|
||||
* `noclip_btn.png`
|
||||
* `dig_btn.png`
|
||||
* `place_btn.png`
|
||||
|
||||
* `jump_btn.png`
|
||||
* `down.png`
|
||||
* `zoom.png`
|
||||
* `aux1_btn.png`
|
||||
* `overflow_btn.png`
|
||||
|
||||
* `camera_btn.png`
|
||||
* `chat_btn.png`
|
||||
* `inventory_btn.png`
|
||||
* `rangeview_btn.png`
|
||||
|
||||
* `debug_btn.png`
|
||||
* `overflow_btn.png`
|
||||
* `drop_btn.png`
|
||||
* `exit_btn.png`
|
||||
|
||||
* `fly_btn.png`
|
||||
* `fast_btn.png`
|
||||
* `noclip_btn.png`
|
||||
* `debug_btn.png`
|
||||
* `camera_btn.png`
|
||||
* `rangeview_btn.png`
|
||||
* `minimap_btn.png`
|
||||
* `chat_hide_btn.png`
|
||||
* `chat_show_btn.png`
|
||||
|
||||
* `joystick_off.png`
|
||||
* `joystick_bg.png`
|
||||
* `joystick_center.png`
|
||||
|
||||
Texture Overrides
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -298,41 +298,44 @@ Before 5.12.0 it looked like this:
|
|||
CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY, `data` BLOB);
|
||||
```
|
||||
|
||||
## Position Hashing
|
||||
## Position Encoding
|
||||
|
||||
Applies to the pre-5.12.0 schema:
|
||||
|
||||
`pos` (a node position hash) is created from the three coordinates of a
|
||||
`MapBlock` using this algorithm, defined here in Python:
|
||||
`pos` (a node position encoding) is created from the three coordinates of a
|
||||
`MapBlock` using the following simple equation:
|
||||
|
||||
```python
|
||||
def getBlockAsInteger(p):
|
||||
return int64(p[2]*16777216 + p[1]*4096 + p[0])
|
||||
```C
|
||||
pos = (z << 24) + (y << 12) + x;
|
||||
```
|
||||
or, equivalently, `pos = (z * 0x1000000) + (y * 0x1000) + x`.
|
||||
|
||||
def int64(u):
|
||||
while u >= 2**63:
|
||||
u -= 2**64
|
||||
while u <= -2**63:
|
||||
u += 2**64
|
||||
return u
|
||||
A position can be decoded using:
|
||||
|
||||
```C
|
||||
pos = pos + 0x800800800;
|
||||
x = (pos & 0xFFF) - 0x800;
|
||||
y = ((pos >> 12) & 0xFFF) - 0x800;
|
||||
z = ((pos >> 24) & 0xFFF) - 0x800;
|
||||
```
|
||||
|
||||
It can be converted the other way by using this code:
|
||||
Positions are sequential along the x axis (as easily seen from the position equation above).
|
||||
It is possible to retrieve all blocks from an interval using the following SQL statement:
|
||||
|
||||
```python
|
||||
def getIntegerAsBlock(i):
|
||||
x = unsignedToSigned(i % 4096, 2048)
|
||||
i = int((i - x) / 4096)
|
||||
y = unsignedToSigned(i % 4096, 2048)
|
||||
i = int((i - y) / 4096)
|
||||
z = unsignedToSigned(i % 4096, 2048)
|
||||
return x,y,z
|
||||
|
||||
def unsignedToSigned(i, max_positive):
|
||||
if i < max_positive:
|
||||
return i
|
||||
else:
|
||||
return i - 2*max_positive
|
||||
```sql
|
||||
SELECT
|
||||
`pos`,
|
||||
`data`,
|
||||
( (`pos` + 0x800800800) & 0xFFF) - 0x800 as x,
|
||||
(((`pos` + 0x800800800) >> 12) & 0xFFF) - 0x800 as y,
|
||||
(((`pos` + 0x800800800) >> 24) & 0xFFF) - 0x800 as z
|
||||
FROM `blocks` WHERE
|
||||
( (`pos` + 0x800800800) & 0xFFF) - 0x800 >= ? AND -- minx
|
||||
( (`pos` + 0x800800800) & 0xFFF) - 0x800 <= ? AND -- maxx
|
||||
(((`pos` + 0x800800800) >> 12) & 0xFFF) - 0x800 >= ? AND -- miny
|
||||
(((`pos` + 0x800800800) >> 12) & 0xFFF) - 0x800 <= ? AND -- maxy
|
||||
`pos` >= (? << 24) - 0x800800 AND -- minz
|
||||
`pos` <= (? << 24) + 0x7FF7FF; -- maxz
|
||||
```
|
||||
|
||||
## Blob
|
||||
|
|
|
@ -22,11 +22,15 @@ core.register_node("basenodes:desert_stone", {
|
|||
|
||||
core.register_node("basenodes:dirt_with_grass", {
|
||||
description = "Dirt with Grass",
|
||||
tiles ={"default_grass.png",
|
||||
-- Using overlays here has no real merit here but we do it anyway so
|
||||
-- overlay-related bugs become more apparent in devtest.
|
||||
tiles = {"default_dirt.png"},
|
||||
overlay_tiles = {
|
||||
"default_grass.png",
|
||||
-- a little dot on the bottom to distinguish it from dirt
|
||||
"default_dirt.png^basenodes_dirt_with_grass_bottom.png",
|
||||
{name = "default_dirt.png^default_grass_side.png",
|
||||
tileable_vertical = false}},
|
||||
"basenodes_dirt_with_grass_bottom.png",
|
||||
{name = "default_grass_side.png", tileable_vertical = false},
|
||||
},
|
||||
groups = {crumbly=3, soil=1},
|
||||
})
|
||||
|
||||
|
|
280
games/devtest/mods/testeditor/init.lua
Normal file
280
games/devtest/mods/testeditor/init.lua
Normal file
|
@ -0,0 +1,280 @@
|
|||
local S = core.get_translator("testeditor")
|
||||
local F = core.formspec_escape
|
||||
|
||||
local function val_to_lua_str(v)
|
||||
if type(v) == "string" then
|
||||
return "\"" .. v .. "\""
|
||||
elseif type(v) == "table" then
|
||||
return tostring(dump(v)):gsub("\n", "")
|
||||
else
|
||||
return tostring(v)
|
||||
end
|
||||
end
|
||||
|
||||
local editor_formspecs = {}
|
||||
|
||||
--- Updates the fields `.index_to_key` and `.list` based on `.data`
|
||||
local function update_formspec_list(formspec)
|
||||
assert(formspec)
|
||||
|
||||
-- Get sorted keys of the formspec fields in `formspec.data`
|
||||
local datalist = {}
|
||||
for k,_ in pairs(formspec.data) do
|
||||
table.insert(datalist, k)
|
||||
end
|
||||
table.sort(datalist)
|
||||
|
||||
-- Build list of table values
|
||||
local props = {}
|
||||
for i, k in ipairs(datalist) do
|
||||
local v = formspec.data[k]
|
||||
props[#props + 1] = F(("%s = %s"):format(k, val_to_lua_str(v)))
|
||||
end
|
||||
|
||||
formspec.index_to_key = datalist
|
||||
formspec.list = table.concat(props, ",")
|
||||
end
|
||||
|
||||
local function show_editor_formspec(playername)
|
||||
local formspec = editor_formspecs[playername]
|
||||
local sel = formspec.selindex or ""
|
||||
local key = formspec.index_to_key[sel]
|
||||
local value = ""
|
||||
if formspec.data[key] ~= nil then
|
||||
value = val_to_lua_str(formspec.data[key])
|
||||
end
|
||||
local title = formspec.title
|
||||
if not formspec.actual then
|
||||
title = S("@1 - NOT APPLIED CHANGES", title)
|
||||
end
|
||||
core.show_formspec(playername, "testeditor:editor",
|
||||
"size[11,9]"..
|
||||
"label[0,0;"..F(title).."]"..
|
||||
"textlist[0,0.5;11,6.5;editor_data;"..formspec.list..";"..sel..";false]"..
|
||||
"field[0.2,7.75;7,1;key;"..F(S("Key"))..";"..F(formspec.key).."]"..
|
||||
"field_close_on_enter[key;false]"..
|
||||
"field[0.2,8.75;8,1;value;"..F(S("Value"))..";"..F(value).."]"..
|
||||
"button[8,7.5;3,1;submit_key;"..F(S("Add/Change key")).."]"..
|
||||
"field_close_on_enter[value;false]"..
|
||||
"button[8,8.5;3,1;submit_value;"..F(S("Submit and apply")).."]"
|
||||
)
|
||||
end
|
||||
|
||||
local function editor_formspec_create(playername, wrapper)
|
||||
local data = wrapper.read_cb(playername)
|
||||
editor_formspecs[playername] = {
|
||||
title = wrapper.title,
|
||||
read_cb = wrapper.read_cb,
|
||||
write_cb = wrapper.write_cb,
|
||||
data = data,
|
||||
key = "",
|
||||
actual = true,
|
||||
}
|
||||
update_formspec_list(editor_formspecs[playername])
|
||||
show_editor_formspec(playername)
|
||||
end
|
||||
|
||||
-- Use loadstring to parse param as a Lua value
|
||||
local function use_loadstring(param, player)
|
||||
-- For security reasons, require 'server' priv, just in case
|
||||
-- someone is actually crazy enough to run this on a public server.
|
||||
local privs = core.get_player_privs(player:get_player_name())
|
||||
if not privs.server then
|
||||
return false, "You need 'server' privilege to change object properties!"
|
||||
end
|
||||
if not param then
|
||||
return false, "Failed: parameter is nil"
|
||||
end
|
||||
--[[ DANGER ZONE ]]
|
||||
-- Interpret string as Lua value
|
||||
local func, errormsg = loadstring("return (" .. param .. ")")
|
||||
if not func then
|
||||
return false, "loadstring failed: " .. errormsg
|
||||
end
|
||||
|
||||
-- Apply sandbox here using setfenv
|
||||
setfenv(func, {})
|
||||
|
||||
-- Run it
|
||||
local good, errOrResult = pcall(func)
|
||||
if not good then
|
||||
-- A Lua error was thrown
|
||||
return false, "pcall failed: " .. errOrResult
|
||||
end
|
||||
|
||||
-- errOrResult will be the value
|
||||
return true, errOrResult
|
||||
end
|
||||
|
||||
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if not (player and player:is_player()) then
|
||||
return
|
||||
end
|
||||
if formname ~= "testeditor:editor" then
|
||||
return
|
||||
end
|
||||
|
||||
local name = player:get_player_name()
|
||||
local formspec = editor_formspecs[name]
|
||||
if not formspec then
|
||||
return
|
||||
end
|
||||
|
||||
if fields.editor_data then
|
||||
local expl = core.explode_textlist_event(fields.editor_data)
|
||||
if expl.type == "DCL" or expl.type == "CHG" then
|
||||
formspec.selindex = expl.index
|
||||
formspec.key = formspec.index_to_key[expl.index]
|
||||
show_editor_formspec(name)
|
||||
return
|
||||
end
|
||||
end
|
||||
if fields.key_enter_field == "key" or fields.submit_key then
|
||||
local success, str = use_loadstring(fields.value, player)
|
||||
if success then
|
||||
local key = fields.key
|
||||
formspec.data[key] = str
|
||||
update_formspec_list(formspec)
|
||||
formspec.actual = false
|
||||
else
|
||||
core.chat_send_player(name, str)
|
||||
return
|
||||
end
|
||||
show_editor_formspec(name)
|
||||
if fields.submit_value then
|
||||
formspec.write_cb(name, formspec.data)
|
||||
end
|
||||
return
|
||||
end
|
||||
if fields.key_enter_field == "value" or fields.submit_value then
|
||||
local success, str = use_loadstring(fields.value, player)
|
||||
if success then
|
||||
local key = formspec.index_to_key[formspec.selindex]
|
||||
formspec.data[key] = str
|
||||
update_formspec_list(formspec)
|
||||
formspec.actual = false
|
||||
else
|
||||
core.chat_send_player(name, str)
|
||||
return
|
||||
end
|
||||
show_editor_formspec(name)
|
||||
if fields.submit_value then
|
||||
formspec.write_cb(name, formspec.data)
|
||||
formspec.data = formspec.read_cb(name)
|
||||
update_formspec_list(formspec)
|
||||
formspec.actual = true
|
||||
end
|
||||
return
|
||||
end
|
||||
end)
|
||||
|
||||
local function create_read_cb(func)
|
||||
return
|
||||
function(name)
|
||||
local player = core.get_player_by_name(name)
|
||||
if player then
|
||||
return player[func](player)
|
||||
end
|
||||
return {}
|
||||
end
|
||||
end
|
||||
local function create_write_cb(func)
|
||||
return
|
||||
function(name, data)
|
||||
local player = core.get_player_by_name(name)
|
||||
if player then
|
||||
return player[func](player, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local wrappers = {
|
||||
armor = {
|
||||
title = S("Properties editor of armor groups (get_armor_groups/set_armor_groups)"),
|
||||
read_cb = create_read_cb("get_armor_groups"),
|
||||
write_cb = create_write_cb("set_armor_groups")
|
||||
},
|
||||
nametag = {
|
||||
title = S("Properties editor of nametag (get_nametag/set_nametag)"),
|
||||
read_cb = create_read_cb("get_nametag_attributes"),
|
||||
write_cb = create_write_cb("set_nametag_attributes")
|
||||
},
|
||||
physics = {
|
||||
title = S("Properties editor of physics_override (get_physics_override/set_physics_override)"),
|
||||
read_cb = create_read_cb("get_physics_override"),
|
||||
write_cb = create_write_cb("set_physics_override")
|
||||
},
|
||||
hud_flags = {
|
||||
title = S("Properties editor of hud_flags (hud_get_flags/hud_set_flags)"),
|
||||
read_cb = create_read_cb("hud_get_flags"),
|
||||
write_cb = create_write_cb("hud_set_flags")
|
||||
},
|
||||
sky = {
|
||||
title = S("Properties editor of sky (get_sky/set_sky)"),
|
||||
read_cb =
|
||||
function(name)
|
||||
local player = core.get_player_by_name(name)
|
||||
if player then
|
||||
return player:get_sky(true)
|
||||
end
|
||||
return {}
|
||||
end,
|
||||
write_cb = create_write_cb("set_sky")
|
||||
},
|
||||
sun = {
|
||||
title = S("Properties editor of sun (get_sun/set_sun)"),
|
||||
read_cb = create_read_cb("get_sun"),
|
||||
write_cb = create_write_cb("set_sun")
|
||||
},
|
||||
moon = {
|
||||
title = S("Properties editor of moon (get_moon/set_moon)"),
|
||||
read_cb = create_read_cb("get_moon"),
|
||||
write_cb = create_write_cb("set_moon")
|
||||
},
|
||||
stars = {
|
||||
title = S("Properties editor of stars (get_stars/set_stars)"),
|
||||
read_cb = create_read_cb("get_stars"),
|
||||
write_cb = create_write_cb("set_stars")
|
||||
},
|
||||
clouds = {
|
||||
title = S("Properties editor of clouds (get_clouds/set_clouds)"),
|
||||
read_cb = create_read_cb("get_clouds"),
|
||||
write_cb = create_write_cb("set_clouds")
|
||||
},
|
||||
lighting = {
|
||||
title = S("Properties editor of lighting (get_lighting/set_lighting)"),
|
||||
read_cb = create_read_cb("get_lighting"),
|
||||
write_cb = create_write_cb("set_lighting")
|
||||
},
|
||||
flags = {
|
||||
title = S("Properties editor of flags (get_flags/set_flags)"),
|
||||
read_cb = create_read_cb("get_flags"),
|
||||
write_cb = create_write_cb("set_flags")
|
||||
}
|
||||
}
|
||||
|
||||
local editor_params
|
||||
do
|
||||
local params = {}
|
||||
for key, _ in pairs(wrappers) do
|
||||
params[#params + 1] = key
|
||||
end
|
||||
editor_params = table.concat(params, "|")
|
||||
end
|
||||
|
||||
core.register_chatcommand("player_editor", {
|
||||
params = "<"..editor_params..">",
|
||||
description = "Open editor for some player data",
|
||||
func = function(name, param)
|
||||
local player = core.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "No player."
|
||||
end
|
||||
if wrappers[param] then
|
||||
editor_formspec_create(name, wrappers[param])
|
||||
else
|
||||
return false, S("Use with @1.", editor_params)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
})
|
2
games/devtest/mods/testeditor/mod.conf
Normal file
2
games/devtest/mods/testeditor/mod.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
name = testeditor
|
||||
description = Commands for create formspec for edit some things like sky etc.
|
|
@ -339,10 +339,11 @@ local pages = {
|
|||
[[
|
||||
formspec_version[3]
|
||||
size[12,13]
|
||||
allow_close[false]
|
||||
image_button[0,0;1,1;logo.png;rc_image_button_1x1;1x1]
|
||||
image_button[1,0;2,2;logo.png;rc_image_button_2x2;2x2]
|
||||
image_button_exit[1,0;2,2;logo.png;rc_image_button_2x2;2x2 exit]
|
||||
button[0,2;1,1;rc_button_1x1;1x1]
|
||||
button[1,2;2,2;rc_button_2x2;2x2]
|
||||
button_exit[1,2;2,2;rc_button_2x2;2x2 exit]
|
||||
item_image[0,4;1,1;air]
|
||||
item_image[1,4;2,2;air]
|
||||
item_image_button[0,6;1,1;testformspec:node;rc_item_image_button_1x1;1x1]
|
||||
|
@ -575,6 +576,10 @@ core.register_on_player_receive_fields(function(player, formname, fields)
|
|||
if fields.submit_window then
|
||||
show_test_formspec(player:get_player_name())
|
||||
end
|
||||
|
||||
if fields.try_quit then
|
||||
core.chat_send_player(player:get_player_name(), "Quit attempt received")
|
||||
end
|
||||
end)
|
||||
|
||||
core.register_chatcommand("test_formspec", {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue