1
0
Fork 0

Add MultiCraft changes in src

minenux-minetest5
Deve 2023-08-27 01:30:22 +02:00
parent fda3932c16
commit b6dbd3fc7a
198 changed files with 14763 additions and 2326 deletions

View File

@ -8,22 +8,26 @@ else()
endif()
# This can be read from ${PROJECT_NAME} after project() is called
project(minetest)
set(PROJECT_NAME_CAPITALIZED "Minetest")
project(multicraft)
set(PROJECT_NAME_CAPITALIZED "MultiCraft")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(GCC_MINIMUM_VERSION "5.1")
set(CLANG_MINIMUM_VERSION "3.5")
# Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing
set(VERSION_MAJOR 5)
set(VERSION_MINOR 5)
set(VERSION_PATCH 0)
set(VERSION_MAJOR 2)
set(VERSION_MINOR 0)
set(VERSION_PATCH 4)
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
# Change to false for releases
set(DEVELOPMENT_BUILD FALSE)
set(ENABLE_UPDATE_CHECKER (NOT ${DEVELOPMENT_BUILD}) CACHE BOOL
"Whether to enable update checks by default")
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
if(VERSION_EXTRA)
set(VERSION_STRING "${VERSION_STRING}-${VERSION_EXTRA}")
@ -50,7 +54,7 @@ set(RUN_IN_PLACE ${DEFAULT_RUN_IN_PLACE} CACHE BOOL
set(BUILD_CLIENT TRUE CACHE BOOL "Build client")
set(BUILD_SERVER FALSE CACHE BOOL "Build server")
set(BUILD_UNITTESTS TRUE CACHE BOOL "Build unittests")
set(BUILD_UNITTESTS FALSE CACHE BOOL "Build unittests")
set(WARN_ALL TRUE CACHE BOOL "Enable -Wall for Release build")
@ -186,16 +190,15 @@ install(FILES "doc/client_lua_api.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/menu_lua_api.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/texture_packs.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/world_format.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
install(FILES "multicraft.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
if(UNIX AND NOT APPLE)
install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6")
install(FILES "misc/net.minetest.minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
install(FILES "misc/net.minetest.minetest.appdata.xml" DESTINATION "${APPDATADIR}")
install(FILES "misc/minetest.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
install(FILES "misc/minetest-xorg-icon-128.png"
install(FILES "misc/multicraft-xorg-icon-128.png"
DESTINATION "${ICONDIR}/hicolor/128x128/apps"
RENAME "minetest.png")
RENAME "multicraft.png")
endif()
if(APPLE)
@ -207,6 +210,9 @@ endif()
find_package(GMP REQUIRED)
find_package(Json REQUIRED)
find_package(Lua REQUIRED)
add_subdirectory(lib/luautf8)
add_subdirectory(lib/luachacha)
if(NOT USE_LUAJIT)
set(LUA_BIT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/bitop)
set(LUA_BIT_LIBRARY bitop)
@ -284,7 +290,7 @@ if(WIN32)
set(CPACK_CREATE_DESKTOP_LINKS ${PROJECT_NAME})
set(CPACK_PACKAGING_INSTALL_PREFIX "/${PROJECT_NAME_CAPITALIZED}")
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/minetest-icon.ico")
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/multicraft-icon.ico")
# Supported languages can be found at
# http://wixtoolset.org/documentation/manual/v3/wixui/wixui_localization.html
#set(CPACK_WIX_CULTURES "ar-SA,bg-BG,ca-ES,hr-HR,cs-CZ,da-DK,nl-NL,en-US,et-EE,fi-FI,fr-FR,de-DE")

View File

@ -0,0 +1,2 @@
add_library(luachacha STATIC chacha.c lchacha.c)
target_include_directories(luachacha PUBLIC ${LUA_INCLUDE_DIR})

210
lib/luachacha/chacha.c Normal file
View File

@ -0,0 +1,210 @@
/*
chacha-merged.c version 20080118
D. J. Bernstein
Public domain.
*/
#include "ecrypt-sync.h"
#include <stddef.h>
#define ROTATE(v,c) (ROTL32(v,c))
#define XOR(v,w) ((v) ^ (w))
#define PLUS(v,w) (U32V((v) + (w)))
#define PLUSONE(v) (PLUS((v),1))
#define QUARTERROUND(a,b,c,d) \
a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
void ECRYPT_init(void)
{
return;
}
static const char sigma[16] = "expand 32-byte k";
static const char tau[16] = "expand 16-byte k";
void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
{
const char *constants;
x->input[4] = U8TO32_LITTLE(k + 0);
x->input[5] = U8TO32_LITTLE(k + 4);
x->input[6] = U8TO32_LITTLE(k + 8);
x->input[7] = U8TO32_LITTLE(k + 12);
if (kbits == 256) { /* recommended */
k += 16;
constants = sigma;
} else { /* kbits == 128 */
constants = tau;
}
x->input[8] = U8TO32_LITTLE(k + 0);
x->input[9] = U8TO32_LITTLE(k + 4);
x->input[10] = U8TO32_LITTLE(k + 8);
x->input[11] = U8TO32_LITTLE(k + 12);
x->input[0] = U8TO32_LITTLE(constants + 0);
x->input[1] = U8TO32_LITTLE(constants + 4);
x->input[2] = U8TO32_LITTLE(constants + 8);
x->input[3] = U8TO32_LITTLE(constants + 12);
}
void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv,const u8* counter)
{
x->input[12] = (counter == NULL) ? 0 : U8TO32_LITTLE(counter + 0);
x->input[13] = (counter == NULL) ? 0 : U8TO32_LITTLE(counter + 4);
x->input[14] = U8TO32_LITTLE(iv + 0);
x->input[15] = U8TO32_LITTLE(iv + 4);
}
void ECRYPT_IETF_ivsetup(ECRYPT_ctx *x,const u8 *iv,const u8* counter)
{
x->input[12] = (counter == NULL) ? 0 : U8TO32_LITTLE(counter);
x->input[13] = U8TO32_LITTLE(iv + 0);
x->input[14] = U8TO32_LITTLE(iv + 4);
x->input[15] = U8TO32_LITTLE(iv + 8);
}
void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes,int rounds)
{
u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
u8 *ctarget;
u8 tmp[64];
int i;
if (!bytes) return;
j0 = x->input[0];
j1 = x->input[1];
j2 = x->input[2];
j3 = x->input[3];
j4 = x->input[4];
j5 = x->input[5];
j6 = x->input[6];
j7 = x->input[7];
j8 = x->input[8];
j9 = x->input[9];
j10 = x->input[10];
j11 = x->input[11];
j12 = x->input[12];
j13 = x->input[13];
j14 = x->input[14];
j15 = x->input[15];
for (;;) {
if (bytes < 64) {
for (i = 0;i < bytes;++i) tmp[i] = m[i];
m = tmp;
ctarget = c;
c = tmp;
}
x0 = j0;
x1 = j1;
x2 = j2;
x3 = j3;
x4 = j4;
x5 = j5;
x6 = j6;
x7 = j7;
x8 = j8;
x9 = j9;
x10 = j10;
x11 = j11;
x12 = j12;
x13 = j13;
x14 = j14;
x15 = j15;
for (i = rounds;i > 0;i -= 2) {
QUARTERROUND( x0, x4, x8,x12)
QUARTERROUND( x1, x5, x9,x13)
QUARTERROUND( x2, x6,x10,x14)
QUARTERROUND( x3, x7,x11,x15)
QUARTERROUND( x0, x5,x10,x15)
QUARTERROUND( x1, x6,x11,x12)
QUARTERROUND( x2, x7, x8,x13)
QUARTERROUND( x3, x4, x9,x14)
}
x0 = PLUS(x0,j0);
x1 = PLUS(x1,j1);
x2 = PLUS(x2,j2);
x3 = PLUS(x3,j3);
x4 = PLUS(x4,j4);
x5 = PLUS(x5,j5);
x6 = PLUS(x6,j6);
x7 = PLUS(x7,j7);
x8 = PLUS(x8,j8);
x9 = PLUS(x9,j9);
x10 = PLUS(x10,j10);
x11 = PLUS(x11,j11);
x12 = PLUS(x12,j12);
x13 = PLUS(x13,j13);
x14 = PLUS(x14,j14);
x15 = PLUS(x15,j15);
x0 = XOR(x0,U8TO32_LITTLE(m + 0));
x1 = XOR(x1,U8TO32_LITTLE(m + 4));
x2 = XOR(x2,U8TO32_LITTLE(m + 8));
x3 = XOR(x3,U8TO32_LITTLE(m + 12));
x4 = XOR(x4,U8TO32_LITTLE(m + 16));
x5 = XOR(x5,U8TO32_LITTLE(m + 20));
x6 = XOR(x6,U8TO32_LITTLE(m + 24));
x7 = XOR(x7,U8TO32_LITTLE(m + 28));
x8 = XOR(x8,U8TO32_LITTLE(m + 32));
x9 = XOR(x9,U8TO32_LITTLE(m + 36));
x10 = XOR(x10,U8TO32_LITTLE(m + 40));
x11 = XOR(x11,U8TO32_LITTLE(m + 44));
x12 = XOR(x12,U8TO32_LITTLE(m + 48));
x13 = XOR(x13,U8TO32_LITTLE(m + 52));
x14 = XOR(x14,U8TO32_LITTLE(m + 56));
x15 = XOR(x15,U8TO32_LITTLE(m + 60));
j12 = PLUSONE(j12);
if (!j12) {
j13 = PLUSONE(j13);
/* stopping at 2^70 bytes per nonce is user's responsibility */
}
U32TO8_LITTLE(c + 0,x0);
U32TO8_LITTLE(c + 4,x1);
U32TO8_LITTLE(c + 8,x2);
U32TO8_LITTLE(c + 12,x3);
U32TO8_LITTLE(c + 16,x4);
U32TO8_LITTLE(c + 20,x5);
U32TO8_LITTLE(c + 24,x6);
U32TO8_LITTLE(c + 28,x7);
U32TO8_LITTLE(c + 32,x8);
U32TO8_LITTLE(c + 36,x9);
U32TO8_LITTLE(c + 40,x10);
U32TO8_LITTLE(c + 44,x11);
U32TO8_LITTLE(c + 48,x12);
U32TO8_LITTLE(c + 52,x13);
U32TO8_LITTLE(c + 56,x14);
U32TO8_LITTLE(c + 60,x15);
if (bytes <= 64) {
if (bytes < 64) {
for (i = 0;i < bytes;++i) ctarget[i] = c[i];
}
x->input[12] = j12;
x->input[13] = j13;
return;
}
bytes -= 64;
c += 64;
m += 64;
}
}
void ECRYPT_decrypt_bytes(ECRYPT_ctx *x,const u8 *c,u8 *m,u32 bytes)
{
ECRYPT_encrypt_bytes(x,c,m,bytes,8);
}
void ECRYPT_keystream_bytes(ECRYPT_ctx *x,u8 *stream,u32 bytes)
{
u32 i;
for (i = 0;i < bytes;++i) stream[i] = 0;
ECRYPT_encrypt_bytes(x,stream,stream,bytes,8);
}

View File

@ -0,0 +1,272 @@
/* ecrypt-config.h */
/* *** Normally, it should not be necessary to edit this file. *** */
#ifndef ECRYPT_CONFIG
#define ECRYPT_CONFIG
/* ------------------------------------------------------------------------- */
/* Guess the endianness of the target architecture. */
/*
* The LITTLE endian machines:
*/
#if defined(__ultrix) /* Older MIPS */
#define ECRYPT_LITTLE_ENDIAN
#elif defined(__alpha) /* Alpha */
#define ECRYPT_LITTLE_ENDIAN
#elif defined(i386) /* x86 (gcc) */
#define ECRYPT_LITTLE_ENDIAN
#elif defined(__i386) /* x86 (gcc) */
#define ECRYPT_LITTLE_ENDIAN
#elif defined(_M_IX86) /* x86 (MSC, Borland) */
#define ECRYPT_LITTLE_ENDIAN
#elif defined(_MSC_VER) /* x86 (surely MSC) */
#define ECRYPT_LITTLE_ENDIAN
#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */
#define ECRYPT_LITTLE_ENDIAN
/*
* The BIG endian machines:
*/
#elif defined(sun) /* Newer Sparc's */
#define ECRYPT_BIG_ENDIAN
#elif defined(__ppc__) /* PowerPC */
#define ECRYPT_BIG_ENDIAN
/*
* Finally machines with UNKNOWN endianness:
*/
#elif defined (_AIX) /* RS6000 */
#define ECRYPT_UNKNOWN
#elif defined(__hpux) /* HP-PA */
#define ECRYPT_UNKNOWN
#elif defined(__aux) /* 68K */
#define ECRYPT_UNKNOWN
#elif defined(__dgux) /* 88K (but P6 in latest boxes) */
#define ECRYPT_UNKNOWN
#elif defined(__sgi) /* Newer MIPS */
#define ECRYPT_UNKNOWN
#else /* Any other processor */
#define ECRYPT_UNKNOWN
#endif
/* ------------------------------------------------------------------------- */
/*
* Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit
* integers.
*
* Note: to enable 64-bit types on 32-bit compilers, it might be
* necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc
* -std=c99).
*/
#include <limits.h>
/* --- check char --- */
#if (UCHAR_MAX / 0xFU > 0xFU)
#ifndef I8T
#define I8T char
#define U8C(v) (v##U)
#if (UCHAR_MAX == 0xFFU)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (UCHAR_MAX / 0xFFU > 0xFFU)
#ifndef I16T
#define I16T char
#define U16C(v) (v##U)
#endif
#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU)
#ifndef I32T
#define I32T char
#define U32C(v) (v##U)
#endif
#if (UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
#ifndef I64T
#define I64T char
#define U64C(v) (v##U)
#define ECRYPT_NATIVE64
#endif
#endif
#endif
#endif
#endif
/* --- check short --- */
#if (USHRT_MAX / 0xFU > 0xFU)
#ifndef I8T
#define I8T short
#define U8C(v) (v##U)
#if (USHRT_MAX == 0xFFU)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (USHRT_MAX / 0xFFU > 0xFFU)
#ifndef I16T
#define I16T short
#define U16C(v) (v##U)
#endif
#if (USHRT_MAX / 0xFFFFU > 0xFFFFU)
#ifndef I32T
#define I32T short
#define U32C(v) (v##U)
#endif
#if (USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
#ifndef I64T
#define I64T short
#define U64C(v) (v##U)
#define ECRYPT_NATIVE64
#endif
#endif
#endif
#endif
#endif
/* --- check int --- */
#if (UINT_MAX / 0xFU > 0xFU)
#ifndef I8T
#define I8T int
#define U8C(v) (v##U)
#if (ULONG_MAX == 0xFFU)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (UINT_MAX / 0xFFU > 0xFFU)
#ifndef I16T
#define I16T int
#define U16C(v) (v##U)
#endif
#if (UINT_MAX / 0xFFFFU > 0xFFFFU)
#ifndef I32T
#define I32T int
#define U32C(v) (v##U)
#endif
#if (UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
#ifndef I64T
#define I64T int
#define U64C(v) (v##U)
#define ECRYPT_NATIVE64
#endif
#endif
#endif
#endif
#endif
/* --- check long --- */
#if (ULONG_MAX / 0xFUL > 0xFUL)
#ifndef I8T
#define I8T long
#define U8C(v) (v##UL)
#if (ULONG_MAX == 0xFFUL)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (ULONG_MAX / 0xFFUL > 0xFFUL)
#ifndef I16T
#define I16T long
#define U16C(v) (v##UL)
#endif
#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL)
#ifndef I32T
#define I32T long
#define U32C(v) (v##UL)
#endif
#if (ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL)
#ifndef I64T
#define I64T long
#define U64C(v) (v##UL)
#define ECRYPT_NATIVE64
#endif
#endif
#endif
#endif
#endif
/* --- check long long --- */
#ifdef ULLONG_MAX
#if (ULLONG_MAX / 0xFULL > 0xFULL)
#ifndef I8T
#define I8T long long
#define U8C(v) (v##ULL)
#if (ULLONG_MAX == 0xFFULL)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (ULLONG_MAX / 0xFFULL > 0xFFULL)
#ifndef I16T
#define I16T long long
#define U16C(v) (v##ULL)
#endif
#if (ULLONG_MAX / 0xFFFFULL > 0xFFFFULL)
#ifndef I32T
#define I32T long long
#define U32C(v) (v##ULL)
#endif
#if (ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL)
#ifndef I64T
#define I64T long long
#define U64C(v) (v##ULL)
#endif
#endif
#endif
#endif
#endif
#endif
/* --- check __int64 --- */
#ifdef _UI64_MAX
#ifndef I64T
#if (_UI64_MAX / 0xFFFFFFFFui64 > 0xFFFFFFFFui64)
#define I64T __int64
#define U64C(v) (v##ui64)
#endif
#endif
#endif
/* ------------------------------------------------------------------------- */
#endif

View File

@ -0,0 +1,46 @@
/* ecrypt-machine.h */
/*
* This file is included by 'ecrypt-portable.h'. It allows to override
* the default macros for specific platforms. Please carefully check
* the machine code generated by your compiler (with optimisations
* turned on) before deciding to edit this file.
*/
/* ------------------------------------------------------------------------- */
#if (defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT))
#define ECRYPT_MACHINE_ROT
#if (defined(WIN32) && defined(_MSC_VER))
#undef ROTL32
#undef ROTR32
#undef ROTL64
#undef ROTR64
#include <stdlib.h>
#define ROTL32(v, n) _lrotl(v, n)
#define ROTR32(v, n) _lrotr(v, n)
#define ROTL64(v, n) _rotl64(v, n)
#define ROTR64(v, n) _rotr64(v, n)
#endif
#endif
/* ------------------------------------------------------------------------- */
#if (defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP))
#define ECRYPT_MACHINE_SWAP
/*
* If you want to overwrite the default swap macros, put it here. And so on.
*/
#endif
/* ------------------------------------------------------------------------- */

View File

@ -0,0 +1,303 @@
/* ecrypt-portable.h */
/*
* WARNING: the conversions defined below are implemented as macros,
* and should be used carefully. They should NOT be used with
* parameters which perform some action. E.g., the following two lines
* are not equivalent:
*
* 1) ++x; y = ROTL32(x, n);
* 2) y = ROTL32(++x, n);
*/
/*
* *** Please do not edit this file. ***
*
* The default macros can be overridden for specific architectures by
* editing 'ecrypt-machine.h'.
*/
#ifndef ECRYPT_PORTABLE
#define ECRYPT_PORTABLE
#include "ecrypt-config.h"
/* ------------------------------------------------------------------------- */
/*
* The following types are defined (if available):
*
* u8: unsigned integer type, at least 8 bits
* u16: unsigned integer type, at least 16 bits
* u32: unsigned integer type, at least 32 bits
* u64: unsigned integer type, at least 64 bits
*
* s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64
*
* The selection of minimum-width integer types is taken care of by
* 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit
* compilers, it might be necessary to switch from ISO C90 mode to ISO
* C99 mode (e.g., gcc -std=c99).
*/
#ifdef I8T
typedef signed I8T s8;
typedef unsigned I8T u8;
#endif
#ifdef I16T
typedef signed I16T s16;
typedef unsigned I16T u16;
#endif
#ifdef I32T
typedef signed I32T s32;
typedef unsigned I32T u32;
#endif
#ifdef I64T
typedef signed I64T s64;
typedef unsigned I64T u64;
#endif
/*
* The following macros are used to obtain exact-width results.
*/
#define U8V(v) ((u8)(v) & U8C(0xFF))
#define U16V(v) ((u16)(v) & U16C(0xFFFF))
#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
#define U64V(v) ((u64)(v) & U64C(0xFFFFFFFFFFFFFFFF))
/* ------------------------------------------------------------------------- */
/*
* The following macros return words with their bits rotated over n
* positions to the left/right.
*/
#define ECRYPT_DEFAULT_ROT
#define ROTL8(v, n) \
(U8V((v) << (n)) | ((v) >> (8 - (n))))
#define ROTL16(v, n) \
(U16V((v) << (n)) | ((v) >> (16 - (n))))
#define ROTL32(v, n) \
(U32V((v) << (n)) | ((v) >> (32 - (n))))
#define ROTL64(v, n) \
(U64V((v) << (n)) | ((v) >> (64 - (n))))
#define ROTR8(v, n) ROTL8(v, 8 - (n))
#define ROTR16(v, n) ROTL16(v, 16 - (n))
#define ROTR32(v, n) ROTL32(v, 32 - (n))
#define ROTR64(v, n) ROTL64(v, 64 - (n))
#include "ecrypt-machine.h"
/* ------------------------------------------------------------------------- */
/*
* The following macros return a word with bytes in reverse order.
*/
#define ECRYPT_DEFAULT_SWAP
#define SWAP16(v) \
ROTL16(v, 8)
#define SWAP32(v) \
((ROTL32(v, 8) & U32C(0x00FF00FF)) | \
(ROTL32(v, 24) & U32C(0xFF00FF00)))
#ifdef ECRYPT_NATIVE64
#define SWAP64(v) \
((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | \
(ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \
(ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | \
(ROTL64(v, 56) & U64C(0xFF000000FF000000)))
#else
#define SWAP64(v) \
(((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32)))
#endif
#include "ecrypt-machine.h"
#define ECRYPT_DEFAULT_WTOW
#ifdef ECRYPT_LITTLE_ENDIAN
#define U16TO16_LITTLE(v) (v)
#define U32TO32_LITTLE(v) (v)
#define U64TO64_LITTLE(v) (v)
#define U16TO16_BIG(v) SWAP16(v)
#define U32TO32_BIG(v) SWAP32(v)
#define U64TO64_BIG(v) SWAP64(v)
#endif
#ifdef ECRYPT_BIG_ENDIAN
#define U16TO16_LITTLE(v) SWAP16(v)
#define U32TO32_LITTLE(v) SWAP32(v)
#define U64TO64_LITTLE(v) SWAP64(v)
#define U16TO16_BIG(v) (v)
#define U32TO32_BIG(v) (v)
#define U64TO64_BIG(v) (v)
#endif
#include "ecrypt-machine.h"
/*
* The following macros load words from an array of bytes with
* different types of endianness, and vice versa.
*/
#define ECRYPT_DEFAULT_BTOW
#if (!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE))
#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0])
#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0])
#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0])
#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0])
#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0])
#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0])
#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v))
#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v))
#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v))
#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v))
#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v))
#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v))
#else
#define U8TO16_LITTLE(p) \
(((u16)((p)[0]) ) | \
((u16)((p)[1]) << 8))
#define U8TO32_LITTLE(p) \
(((u32)((p)[0]) ) | \
((u32)((p)[1]) << 8) | \
((u32)((p)[2]) << 16) | \
((u32)((p)[3]) << 24))
#ifdef ECRYPT_NATIVE64
#define U8TO64_LITTLE(p) \
(((u64)((p)[0]) ) | \
((u64)((p)[1]) << 8) | \
((u64)((p)[2]) << 16) | \
((u64)((p)[3]) << 24) | \
((u64)((p)[4]) << 32) | \
((u64)((p)[5]) << 40) | \
((u64)((p)[6]) << 48) | \
((u64)((p)[7]) << 56))
#else
#define U8TO64_LITTLE(p) \
((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32))
#endif
#define U8TO16_BIG(p) \
(((u16)((p)[0]) << 8) | \
((u16)((p)[1]) ))
#define U8TO32_BIG(p) \
(((u32)((p)[0]) << 24) | \
((u32)((p)[1]) << 16) | \
((u32)((p)[2]) << 8) | \
((u32)((p)[3]) ))
#ifdef ECRYPT_NATIVE64
#define U8TO64_BIG(p) \
(((u64)((p)[0]) << 56) | \
((u64)((p)[1]) << 48) | \
((u64)((p)[2]) << 40) | \
((u64)((p)[3]) << 32) | \
((u64)((p)[4]) << 24) | \
((u64)((p)[5]) << 16) | \
((u64)((p)[6]) << 8) | \
((u64)((p)[7]) ))
#else
#define U8TO64_BIG(p) \
(((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4))
#endif
#define U16TO8_LITTLE(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
} while (0)
#define U32TO8_LITTLE(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
(p)[2] = U8V((v) >> 16); \
(p)[3] = U8V((v) >> 24); \
} while (0)
#ifdef ECRYPT_NATIVE64
#define U64TO8_LITTLE(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
(p)[2] = U8V((v) >> 16); \
(p)[3] = U8V((v) >> 24); \
(p)[4] = U8V((v) >> 32); \
(p)[5] = U8V((v) >> 40); \
(p)[6] = U8V((v) >> 48); \
(p)[7] = U8V((v) >> 56); \
} while (0)
#else
#define U64TO8_LITTLE(p, v) \
do { \
U32TO8_LITTLE((p), U32V((v) )); \
U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \
} while (0)
#endif
#define U16TO8_BIG(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
} while (0)
#define U32TO8_BIG(p, v) \
do { \
(p)[0] = U8V((v) >> 24); \
(p)[1] = U8V((v) >> 16); \
(p)[2] = U8V((v) >> 8); \
(p)[3] = U8V((v) ); \
} while (0)
#ifdef ECRYPT_NATIVE64
#define U64TO8_BIG(p, v) \
do { \
(p)[0] = U8V((v) >> 56); \
(p)[1] = U8V((v) >> 48); \
(p)[2] = U8V((v) >> 40); \
(p)[3] = U8V((v) >> 32); \
(p)[4] = U8V((v) >> 24); \
(p)[5] = U8V((v) >> 16); \
(p)[6] = U8V((v) >> 8); \
(p)[7] = U8V((v) ); \
} while (0)
#else
#define U64TO8_BIG(p, v) \
do { \
U32TO8_BIG((p), U32V((v) >> 32)); \
U32TO8_BIG((p) + 4, U32V((v) )); \
} while (0)
#endif
#endif
#include "ecrypt-machine.h"
/* ------------------------------------------------------------------------- */
#endif

290
lib/luachacha/ecrypt-sync.h Normal file
View File

@ -0,0 +1,290 @@
/* ecrypt-sync.h */
/*
* Header file for synchronous stream ciphers without authentication
* mechanism.
*
* *** Please only edit parts marked with "[edit]". ***
*/
#ifndef ECRYPT_SYNC
#define ECRYPT_SYNC
#include "ecrypt-portable.h"
/* ------------------------------------------------------------------------- */
/* Cipher parameters */
/*
* The name of your cipher.
*/
#define ECRYPT_NAME "ChaCha8"
#define ECRYPT_PROFILE "_____"
/*
* Specify which key and IV sizes are supported by your cipher. A user
* should be able to enumerate the supported sizes by running the
* following code:
*
* for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i)
* {
* keysize = ECRYPT_KEYSIZE(i);
*
* ...
* }
*
* All sizes are in bits.
*/
#define ECRYPT_MAXKEYSIZE 256 /* [edit] */
#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */
#define ECRYPT_MAXIVSIZE 64 /* [edit] */
#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */
/* ------------------------------------------------------------------------- */
/* Data structures */
/*
* ECRYPT_ctx is the structure containing the representation of the
* internal state of your cipher.
*/
typedef struct
{
u32 input[16]; /* could be compressed */
/*
* [edit]
*
* Put here all state variable needed during the encryption process.
*/
} ECRYPT_ctx;
/* ------------------------------------------------------------------------- */
/* Mandatory functions */
/*
* Key and message independent initialization. This function will be
* called once when the program starts (e.g., to build expanded S-box
* tables).
*/
void ECRYPT_init();
/*
* Key setup. It is the user's responsibility to select the values of
* keysize and ivsize from the set of supported values specified
* above.
*/
void ECRYPT_keysetup(
ECRYPT_ctx* ctx,
const u8* key,
u32 keysize, /* Key size in bits. */
u32 ivsize); /* IV size in bits. */
/*
* IV setup. After having called ECRYPT_keysetup(), the user is
* allowed to call ECRYPT_ivsetup() different times in order to
* encrypt/decrypt different messages with the same key but different
* IV's.
*/
void ECRYPT_ivsetup(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* counter);
/*
* IV setup for the IETF version of ChaCha (RFC 7539)
*/
void ECRYPT_IETF_ivsetup(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* counter);
/*
* Encryption/decryption of arbitrary length messages.
*
* For efficiency reasons, the API provides two types of
* encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function
* (declared here) encrypts byte strings of arbitrary length, while
* the ECRYPT_encrypt_blocks() function (defined later) only accepts
* lengths which are multiples of ECRYPT_BLOCKLENGTH.
*
* The user is allowed to make multiple calls to
* ECRYPT_encrypt_blocks() to incrementally encrypt a long message,
* but he is NOT allowed to make additional encryption calls once he
* has called ECRYPT_encrypt_bytes() (unless he starts a new message
* of course). For example, this sequence of calls is acceptable:
*
* ECRYPT_keysetup();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_bytes();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_blocks();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_bytes();
*
* The following sequence is not:
*
* ECRYPT_keysetup();
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_bytes();
* ECRYPT_encrypt_blocks();
*/
void ECRYPT_encrypt_bytes(
ECRYPT_ctx* ctx,
const u8* plaintext,
u8* ciphertext,
u32 msglen, /* Message length in bytes. */
int rounds
);
void ECRYPT_decrypt_bytes(
ECRYPT_ctx* ctx,
const u8* ciphertext,
u8* plaintext,
u32 msglen); /* Message length in bytes. */
/* ------------------------------------------------------------------------- */
/* Optional features */
/*
* For testing purposes it can sometimes be useful to have a function
* which immediately generates keystream without having to provide it
* with a zero plaintext. If your cipher cannot provide this function
* (e.g., because it is not strictly a synchronous cipher), please
* reset the ECRYPT_GENERATES_KEYSTREAM flag.
*/
#define ECRYPT_GENERATES_KEYSTREAM
#ifdef ECRYPT_GENERATES_KEYSTREAM
void ECRYPT_keystream_bytes(
ECRYPT_ctx* ctx,
u8* keystream,
u32 length); /* Length of keystream in bytes. */
#endif
/* ------------------------------------------------------------------------- */
/* Optional optimizations */
/*
* By default, the functions in this section are implemented using
* calls to functions declared above. However, you might want to
* implement them differently for performance reasons.
*/
/*
* All-in-one encryption/decryption of (short) packets.
*
* The default definitions of these functions can be found in
* "ecrypt-sync.c". If you want to implement them differently, please
* undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag.
*/
#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */
void ECRYPT_encrypt_packet(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* plaintext,
u8* ciphertext,
u32 msglen);
void ECRYPT_decrypt_packet(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* ciphertext,
u8* plaintext,
u32 msglen);
/*
* Encryption/decryption of blocks.
*
* By default, these functions are defined as macros. If you want to
* provide a different implementation, please undef the
* ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions
* declared below.
*/
#define ECRYPT_BLOCKLENGTH 64 /* [edit] */
#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */
#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS
#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \
ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \
(blocks) * ECRYPT_BLOCKLENGTH)
#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \
ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \
(blocks) * ECRYPT_BLOCKLENGTH)
#ifdef ECRYPT_GENERATES_KEYSTREAM
#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \
ECRYPT_keystream_bytes(ctx, keystream, \
(blocks) * ECRYPT_BLOCKLENGTH)
#endif
#else
void ECRYPT_encrypt_blocks(
ECRYPT_ctx* ctx,
const u8* plaintext,
u8* ciphertext,
u32 blocks); /* Message length in blocks. */
void ECRYPT_decrypt_blocks(
ECRYPT_ctx* ctx,
const u8* ciphertext,
u8* plaintext,
u32 blocks); /* Message length in blocks. */
#ifdef ECRYPT_GENERATES_KEYSTREAM
void ECRYPT_keystream_blocks(
ECRYPT_ctx* ctx,
const u8* keystream,
u32 blocks); /* Keystream length in blocks. */
#endif
#endif
/*
* If your cipher can be implemented in different ways, you can use
* the ECRYPT_VARIANT parameter to allow the user to choose between
* them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please
* only use this possibility if you really think it could make a
* significant difference and keep the number of variants
* (ECRYPT_MAXVARIANT) as small as possible (definitely not more than
* 10). Note also that all variants should have exactly the same
* external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.).
*/
#define ECRYPT_MAXVARIANT 1 /* [edit] */
#ifndef ECRYPT_VARIANT
#define ECRYPT_VARIANT 1
#endif
#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT)
#error this variant does not exist
#endif
/* ------------------------------------------------------------------------- */
#endif

79
lib/luachacha/lchacha.c Normal file
View File

@ -0,0 +1,79 @@
#include <stdlib.h>
#include <stdbool.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include "ecrypt-sync.h"
#if LUA_VERSION_NUM == 501
#define l_setfuncs(L, funcs) luaL_register(L, NULL, funcs)
#else
#define l_setfuncs(L, funcs) luaL_setfuncs(L, funcs, 0)
#endif
static int chacha_generic_crypt(lua_State *L, bool is_ietf)
{
ECRYPT_ctx ctx;
const char *key, *iv, *plaintext, *counter;
char *ciphertext;
size_t keysize, ivsize, msglen, countersize;
int rounds = luaL_checkinteger(L, 1);
/* IETF only normalizes ChaCha 20. */
if (rounds != 20 && (is_ietf || (rounds % 2 != 0)))
return luaL_error(L, "invalid number of rounds: %d", rounds);
luaL_checktype(L, 2, LUA_TSTRING);
luaL_checktype(L, 3, LUA_TSTRING);
luaL_checktype(L, 4, LUA_TSTRING);
key = lua_tolstring(L, 2, &keysize);
iv = lua_tolstring(L, 3, &ivsize);
plaintext = lua_tolstring(L, 4, &msglen);
counter = luaL_optlstring(L, 5, NULL, &countersize);
if (ivsize != (is_ietf ? 12 : 8))
return luaL_error(L, "invalid IV size: %dB", (int)ivsize);
if (keysize != 32 && (is_ietf || keysize != 16))
return luaL_error(L, "invalid key size: %dB", (int)keysize);
if (counter && countersize != (is_ietf ? 4 : 8))
return luaL_error(L, "invalid counter size: %dB", (int)countersize);
if (msglen == 0) { lua_pushlstring(L, "", 0); return 1; }
ciphertext = malloc(msglen);
if (!ciphertext) return luaL_error(L, "OOM");
/* keysize and ivsize are in bits */
ECRYPT_keysetup(&ctx, (u8*)key, 8 * keysize, 8 * ivsize);
if (is_ietf) ECRYPT_IETF_ivsetup(&ctx, (u8*)iv, (u8*)counter);
else ECRYPT_ivsetup(&ctx, (u8*)iv, (u8*)counter);
ECRYPT_encrypt_bytes(&ctx, (u8*)plaintext, (u8*)ciphertext, msglen, rounds);
lua_pushlstring(L, ciphertext, msglen);
free(ciphertext);
return 1;
}
static int chacha_ref_crypt(lua_State *L)
{ return chacha_generic_crypt(L, false); }
static int chacha_ietf_crypt(lua_State *L)
{ return chacha_generic_crypt(L, true); }
int luaopen_chacha(lua_State *L)
{
struct luaL_Reg l[] = {
{ "ref_crypt", chacha_ref_crypt },
{ "ietf_crypt", chacha_ietf_crypt },
{ NULL, NULL }
};
lua_newtable(L);
l_setfuncs(L, l);
return 1;
}

View File

@ -0,0 +1,2 @@
add_library(luautf8 STATIC lutf8lib.c)
target_include_directories(luautf8 PUBLIC ${LUA_INCLUDE_DIR})

1300
lib/luautf8/lutf8lib.c Normal file

File diff suppressed because it is too large Load Diff

3753
lib/luautf8/unidata.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
project(minetest)
project(multicraft)
INCLUDE(CheckIncludeFiles)
INCLUDE(CheckLibraryExists)
@ -32,12 +32,17 @@ if(NOT (BUILD_CLIENT OR BUILD_SERVER))
endif()
option(USE_SDL "Use SDL2 for window management" FALSE)
option(USE_STATIC_BUILD "Link additional libraries needed for static build" FALSE)
if(USE_SDL)
find_package(SDL2)
if(NOT USE_STATIC_BUILD)
find_package(SDL2)
else()
set(SDL2_FOUND TRUE)
endif()
if (SDL2_FOUND)
message(STATUS "SDL2 found.")
include_directories(${SDL2_INCLUDEDIR})
include_directories(${SDL2_INCLUDE_DIR})
else()
message(FATAL_ERROR "SDL2 not found.")
endif()
@ -193,6 +198,8 @@ if(ENABLE_LEVELDB)
endif()
endif(ENABLE_LEVELDB)
option(ENABLE_SQLITE "Enable SQLite backend" TRUE)
set(USE_SQLITE TRUE)
OPTION(ENABLE_REDIS "Enable Redis backend" TRUE)
set(USE_REDIS FALSE)
@ -556,6 +563,8 @@ if(BUILD_CLIENT)
${FREETYPE_LIBRARY}
${PLATFORM_LIBS}
${SDL2_LIBRARIES}
luautf8
luachacha
)
if(NOT USE_LUAJIT)
set_target_properties(${PROJECT_NAME} PROPERTIES
@ -565,6 +574,21 @@ if(BUILD_CLIENT)
)
endif()
if(USE_SDL)
target_link_libraries(
${PROJECT_NAME}
${SDL2_LIBRARIES}
)
if(USE_STATIC_BUILD AND WIN32)
target_link_libraries(
${PROJECT_NAME}
winmm
imm32
setupapi
opengl32
)
endif()
endif()
if(ENABLE_GLES)
target_link_libraries(
${PROJECT_NAME}
@ -582,12 +606,23 @@ if(BUILD_CLIENT)
${PROJECT_NAME}
${GETTEXT_LIBRARY}
)
if(USE_STATIC_BUILD)
target_link_libraries(
${PROJECT_NAME}
${GETTEXT_ICONV_LIBRARY}
)
endif()
endif()
if(USE_CURL)
target_link_libraries(
${PROJECT_NAME}
${CURL_LIBRARY}
)
if(USE_STATIC_BUILD)
if(WIN32)
target_link_libraries(${PROJECT_NAME} bcrypt crypt32 ws2_32)
endif()
endif()
endif()
if(FREETYPE_PKGCONFIG_FOUND)
set_target_properties(${PROJECT_NAME}
@ -634,6 +669,8 @@ if(BUILD_SERVER)
${LUA_BIT_LIBRARY}
${GMP_LIBRARY}
${PLATFORM_LIBS}
luautf8
luachacha
)
set_target_properties(${PROJECT_NAME}server PROPERTIES
COMPILE_DEFINITIONS "SERVER")
@ -901,7 +938,7 @@ if(BUILD_CLIENT)
if(USE_GETTEXT)
foreach(LOCALE ${GETTEXT_USED_LOCALES})
set_mo_paths(MO_BUILD_PATH MO_DEST_PATH ${LOCALE})
set(MO_BUILD_PATH "${MO_BUILD_PATH}/${PROJECT_NAME}.mo")
set(MO_BUILD_PATH "${MO_BUILD_PATH}/minetest.mo")
install(FILES ${MO_BUILD_PATH} DESTINATION ${MO_DEST_PATH})
endforeach()
endif()
@ -918,9 +955,9 @@ if (USE_GETTEXT)
set(MO_FILES)
foreach(LOCALE ${GETTEXT_USED_LOCALES})
set(PO_FILE_PATH "${GETTEXT_PO_PATH}/${LOCALE}/${PROJECT_NAME}.po")
set(PO_FILE_PATH "${GETTEXT_PO_PATH}/${LOCALE}/minetest.po")
set_mo_paths(MO_BUILD_PATH MO_DEST_PATH ${LOCALE})
set(MO_FILE_PATH "${MO_BUILD_PATH}/${PROJECT_NAME}.mo")
set(MO_FILE_PATH "${MO_BUILD_PATH}/minetest.mo")
add_custom_command(OUTPUT ${MO_BUILD_PATH}
COMMAND ${CMAKE_COMMAND} -E make_directory ${MO_BUILD_PATH}

View File

@ -44,15 +44,18 @@ enum ActiveObjectType {
struct ActiveObjectMessage
{
ActiveObjectMessage(u16 id_, bool reliable_=true, const std::string &data_ = "") :
ActiveObjectMessage(u16 id_, bool reliable_ = true,
const std::string &data_ = "", const std::string legacy_ = "") :
id(id_),
reliable(reliable_),
datastring(data_)
datastring(data_),
legacystring(legacy_)
{}
u16 id;
bool reliable;
std::string datastring;
std::string legacystring;
};
enum ActiveObjectCommand {

View File

@ -19,8 +19,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
#include "IrrCompileConfig.h"
#include "util/string.h"
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
#include "threading/sdl_thread.h"
#else
#include "threading/thread.h"
#endif
#include "exceptions.h"
#include <map>
#include <string>

View File

@ -35,6 +35,7 @@ ChatBuffer::ChatBuffer(u32 scrollback):
if (m_scrollback == 0)
m_scrollback = 1;
m_empty_formatted_line.first = true;
m_empty_formatted_line.line_index = 0;
m_cache_clickable_chat_weblinks = false;
// Curses mode cannot access g_settings here
@ -52,8 +53,9 @@ void ChatBuffer::addLine(const std::wstring &name, const std::wstring &text)
{
m_lines_modified = true;
ChatLine line(name, text);
ChatLine line(name, text, m_current_line_index);
m_unformatted.push_back(line);
m_current_line_index++;
if (m_rows > 0) {
// m_formatted is valid and must be kept valid
@ -73,6 +75,7 @@ void ChatBuffer::clear()
{
m_unformatted.clear();
m_formatted.clear();
m_current_line_index = 0;
m_scroll = 0;
m_lines_modified = true;
}
@ -127,6 +130,8 @@ void ChatBuffer::deleteOldest(u32 count)
m_scroll = getBottomScrollPos();
else
scrollAbsolute(m_scroll - del_formatted);
m_del_formatted += del_formatted;
}
void ChatBuffer::deleteByAge(f32 maxAge)
@ -272,6 +277,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
//EnrichedString line_text(line.text);
next_line.first = true;
next_line.line_index = line.line_index;
// Set/use forced newline after the last frag in each line
bool mark_newline = false;
@ -461,6 +467,7 @@ void ChatPrompt::input(wchar_t ch)
clampView();
m_nick_completion_start = 0;
m_nick_completion_end = 0;
m_line_modified = true;
}
void ChatPrompt::input(const std::wstring &str)
@ -470,6 +477,7 @@ void ChatPrompt::input(const std::wstring &str)
clampView();
m_nick_completion_start = 0;
m_nick_completion_end = 0;
m_line_modified = true;
}
void ChatPrompt::addToHistory(const std::wstring &line)
@ -494,6 +502,7 @@ void ChatPrompt::clear()
m_cursor = 0;
m_nick_completion_start = 0;
m_nick_completion_end = 0;
m_line_modified = true;
}
std::wstring ChatPrompt::replace(const std::wstring &line)
@ -504,6 +513,7 @@ std::wstring ChatPrompt::replace(const std::wstring &line)
clampView();
m_nick_completion_start = 0;
m_nick_completion_end = 0;
m_line_modified = true;
return old_line;
}
@ -605,6 +615,7 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
clampView();
m_nick_completion_start = prefix_start;
m_nick_completion_end = prefix_end;
m_line_modified = true;
}
void ChatPrompt::reformat(u32 cols)
@ -686,6 +697,7 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
m_line.erase(m_cursor, abs(new_cursor - old_cursor));
}
m_cursor_len = 0;
m_line_modified = true;
break;
case CURSOROP_SELECT:
if (scope == CURSOROP_SCOPE_LINE) {
@ -705,6 +717,25 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
m_nick_completion_end = 0;
}
void ChatPrompt::setCursorPos(int cursor_pos)
{
s32 length = m_line.size();
m_cursor = MYMAX(MYMIN(cursor_pos, length), 0);
m_cursor_len = 0;
clampView();
m_nick_completion_start = 0;
m_nick_completion_end = 0;
}
void ChatPrompt::setViewPosition(int view)
{
m_view = view;
clampView();
}
void ChatPrompt::clampView()
{
s32 length = m_line.size();

View File

@ -37,16 +37,22 @@ struct ChatLine
EnrichedString name;
// message text
EnrichedString text;
// Line index in ChatLine buffer
int line_index;
ChatLine(const std::wstring &a_name, const std::wstring &a_text):
ChatLine(const std::wstring &a_name, const std::wstring &a_text,
int a_line_index):
name(a_name),
text(a_text)
text(a_text),
line_index(a_line_index)
{
}
ChatLine(const EnrichedString &a_name, const EnrichedString &a_text):
ChatLine(const EnrichedString &a_name, const EnrichedString &a_text,
int a_line_index):
name(a_name),
text(a_text)
text(a_text),
line_index(a_line_index)
{
}
};
@ -69,6 +75,8 @@ struct ChatFormattedLine
std::vector<ChatFormattedFragment> fragments;
// true if first line of one formatted ChatLine
bool first;
// Line index in ChatLine buffer
int line_index;
};
class ChatBuffer
@ -118,6 +126,12 @@ public:
bool getLinesModified() const { return m_lines_modified; }
void resetLinesModified() { m_lines_modified = false; }
s32 getScrollPos() { return m_scroll; }
u32 getColsCount() { return m_cols; }
u32 getDelFormatted() const { return m_del_formatted; }
void resetDelFormatted() { m_del_formatted = 0; }
// Format a chat line for the given number of columns.
// Appends the formatted lines to the destination array and
// returns the number of formatted lines.
@ -126,7 +140,6 @@ public:
void resize(u32 scrollback);
protected:
s32 getTopScrollPos() const;
s32 getBottomScrollPos() const;
@ -147,15 +160,20 @@ private:
// Empty formatted line, for error returns
ChatFormattedLine m_empty_formatted_line;
// Enable clickable chat weblinks
bool m_cache_clickable_chat_weblinks;
// Color of clickable chat weblinks
irr::video::SColor m_cache_chat_weblink_color;
// Whether the lines were modified since last markLinesUnchanged()
// Is always set to true when m_unformatted is modified, because that's what
// determines the output of getLineCount() and getLine()
bool m_lines_modified = true;
// How many formatted lines have been deleted
u32 m_del_formatted = 0;
int m_current_line_index = 0;
// Enable clickable chat weblinks
bool m_cache_clickable_chat_weblinks;
// Color of clickable chat weblinks
irr::video::SColor m_cache_chat_weblink_color;
};
class ChatPrompt
@ -197,6 +215,8 @@ public:
std::wstring getVisiblePortion() const;
// Get cursor position (relative to visible portion). -1 if invalid
s32 getVisibleCursorPosition() const;
// Get view position (absolute value)
s32 getViewPosition() const { return m_view; }
// Get length of cursor selection
s32 getCursorLength() const { return m_cursor_len; }
@ -232,6 +252,14 @@ public:
// deletes the word to the left of the cursor.
void cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope scope);
void setCursorPos(int cursor_pos);
void setViewPosition(int view);
// Functions for keeping track of whether the line was modified by any
// preceding operations
bool getLineModified() const { return m_line_modified; }
void resetLineModified() { m_line_modified = false; }
protected:
// set m_view to ensure that 0 <= m_view <= m_cursor < m_view + m_cols
// if line can be fully shown, set m_view to zero
@ -263,6 +291,9 @@ private:
s32 m_nick_completion_start = 0;
// Last nick completion start (index into m_line)
s32 m_nick_completion_end = 0;
// True if line was modified
bool m_line_modified = true;
};
class ChatBackend

View File

@ -595,12 +595,11 @@ void Camera::updateViewingRange()
m_cameranode->setNearValue(0.1f * BS);
#endif
m_draw_control.wanted_range = std::fmin(adjustDist(viewing_range, getFovMax()), 4000);
if (m_draw_control.range_all) {
m_cameranode->setFarValue(100000.0);
return;
}
m_cameranode->setFarValue((viewing_range < 2000) ? 2000 * BS : viewing_range * BS);
if (m_draw_control.extended_range)
viewing_range *= 3;
viewing_range = std::fmin(adjustDist(viewing_range, getFovMax()), 4000);
m_draw_control.wanted_range = viewing_range;
m_cameranode->setFarValue(m_draw_control.range_all ? 100000.0 : std::max(2000.0f, viewing_range) * BS);
}
void Camera::setDigging(s32 button)
@ -609,15 +608,20 @@ void Camera::setDigging(s32 button)
m_digging_button = button;
}
void Camera::wield(const ItemStack &item)
void Camera::wield(const ItemStack &item, const bool no_change_anim)
{
if (item.name != m_wield_item_next.name ||
item.metadata != m_wield_item_next.metadata) {
m_wield_item_next = item;
if (m_wield_change_timer > 0)
if (no_change_anim) {
// Change items immediately
m_wieldnode->setItem(item, m_client);
m_wield_change_timer = 0.125f;
} else if (m_wield_change_timer > 0) {
m_wield_change_timer = -m_wield_change_timer;
else if (m_wield_change_timer == 0)
} else if (m_wield_change_timer == 0) {
m_wield_change_timer = -0.001;
}
}
}

View File

@ -150,7 +150,7 @@ public:
void setDigging(s32 button);
// Replace the wielded item mesh
void wield(const ItemStack &item);
void wield(const ItemStack &item, const bool no_change_anim);
// Draw the wielded tool.
// This has to happen *after* the main scene is drawn.

View File

@ -51,7 +51,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientmedia.h"
#include "version.h"
#include "database/database-files.h"
#if USE_SQLITE
#include "database/database-sqlite3.h"
#endif
#include "serialization.h"
#include "guiscalingfilter.h"
#include "script/scripting_client.h"
@ -139,6 +141,9 @@ Client::Client(
}
m_cache_save_interval = g_settings->getU16("server_map_save_interval");
m_round_screen = g_settings->getU16("round_screen");
m_hud_scaling = g_settings->getFloat("hud_scaling");
m_inv_item_anim_enabled = g_settings->getBool("inventory_items_animations");
}
void Client::migrateModStorage()
@ -272,7 +277,7 @@ const std::string &Client::getBuiltinLuaPath()
const std::string &Client::getClientModsLuaPath()
{
static const std::string clientmods_dir = porting::path_share + DIR_DELIM + "clientmods";
static const std::string clientmods_dir = porting::path_user + DIR_DELIM + "clientmods";
return clientmods_dir;
}
@ -294,11 +299,13 @@ void Client::Stop()
m_script->on_shutdown();
//request all client managed threads to stop
m_mesh_update_thread.stop();
#if USE_SQLITE
// Save local server map
if (m_localdb) {
infostream << "Local map saving ended." << std::endl;
m_localdb->endSave();
}
#endif
if (m_mods_loaded)
delete m_script;
@ -687,12 +694,14 @@ void Client::step(float dtime)
m_mod_storage_database->beginSave();
}
#if USE_SQLITE
// Write server map
if (m_localdb && m_localdb_save_interval.step(dtime,
m_cache_save_interval)) {
m_localdb->endSave();
m_localdb->beginSave();
}
#endif
}
bool Client::loadMedia(const std::string &data, const std::string &filename,
@ -852,9 +861,11 @@ void Client::initLocalMapSaving(const Address &address,
#undef set_world_path
fs::CreateAllDirs(world_path);
#if USE_SQLITE
m_localdb = new MapDatabaseSQLite3(world_path);
m_localdb->beginSave();
actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl;
#endif
}
void Client::ReceiveAll()
@ -1055,14 +1066,14 @@ AuthMechanism Client::choseAuthMech(const u32 mechs)
void Client::sendInit(const std::string &playerName)
{
NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()));
NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()) + 1);
// we don't support network compression yet
u16 supp_comp_modes = NETPROTO_COMPRESSION_NONE;
pkt << (u8) SER_FMT_VER_HIGHEST_READ << (u16) supp_comp_modes;
pkt << (u16) CLIENT_PROTOCOL_VERSION_MIN << (u16) CLIENT_PROTOCOL_VERSION_MAX;
pkt << playerName;
pkt << playerName << (u8) 1;
Send(&pkt);
}
@ -1239,6 +1250,14 @@ bool Client::canSendChatMessage() const
void Client::sendChatMessage(const std::wstring &message)
{
// Exempt SSCSM com messages from limits
if (message.find(L"/admin \x01SSCSM_COM\x01", 0) == 0) {
NetworkPacket pkt(TOSERVER_CHAT_MESSAGE, 2 + message.size() * sizeof(u16));
pkt << message;
Send(&pkt);
return;
}
const s16 max_queue_size = g_settings->getS16("max_out_chat_queue_size");
if (canSendChatMessage()) {
u32 now = time(NULL);
@ -1270,12 +1289,18 @@ void Client::clearOutChatQueue()
}
void Client::sendChangePassword(const std::string &oldpassword,
const std::string &newpassword)
const std::string &newpassword, const bool close_form)
{
LocalPlayer *player = m_env.getLocalPlayer();
if (player == NULL)
return;
if (close_form) {
auto formspec = m_game_ui->getFormspecGUI();
if (formspec)
formspec->quitMenu();
}
// get into sudo mode and then send new password to server
m_password = oldpassword;
m_new_password = newpassword;
@ -1298,13 +1323,20 @@ void Client::sendRespawn()
void Client::sendReady()
{
const char *platform_name = porting::getPlatformName();
const std::string sysinfo = porting::get_sysinfo();
const size_t version_len = strlen(g_version_hash) + 1 + strlen(platform_name) + 1 + sysinfo.size();
NetworkPacket pkt(TOSERVER_CLIENT_READY,
1 + 1 + 1 + 1 + 2 + sizeof(char) * strlen(g_version_hash) + 2);
1 + 1 + 1 + 1 + 2 + sizeof(char) * version_len + 2);
pkt << (u8) VERSION_MAJOR << (u8) VERSION_MINOR << (u8) VERSION_PATCH
<< (u8) 0 << (u16) strlen(g_version_hash);
<< (u8) 0 << (u16) version_len;
pkt.putRawString(g_version_hash, (u16) strlen(g_version_hash));
pkt << (u8) 0;
pkt.putRawString(platform_name, (u16) strlen(platform_name));
pkt << (u8) 0;
pkt.putRawString(sysinfo.c_str(), sysinfo.size());
pkt << (u16)FORMSPEC_API_VERSION;
Send(&pkt);
}
@ -1719,7 +1751,7 @@ void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progres
std::wostringstream strm;
strm << targs->text_base << L" " << targs->last_percent << L"%...";
m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
72 + (u16) ((18. / 100.) * (double) targs->last_percent), true);
72 + (u16) ((18. / 100.) * (double) targs->last_percent));
}
}

View File

@ -242,7 +242,7 @@ public:
void sendChatMessage(const std::wstring &message);
void clearOutChatQueue();
void sendChangePassword(const std::string &oldpassword,
const std::string &newpassword);
const std::string &newpassword, const bool close_form = false);
void sendDamage(u16 damage);
void sendRespawn();
void sendReady();
@ -439,6 +439,10 @@ public:
{
return m_env.getLocalPlayer()->formspec_prepend;
}
const u16 getRoundScreen() { return m_round_screen; }
const f32 getHudScaling() { return m_hud_scaling; }
const bool getInvItemAnimEnabled() { return m_inv_item_anim_enabled; }
private:
void loadMods();
@ -605,4 +609,8 @@ private:
u32 m_csm_restriction_noderange = 8;
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
u16 m_round_screen;
f32 m_hud_scaling;
bool m_inv_item_anim_enabled;
};

View File

@ -80,7 +80,7 @@ ClientLauncher::~ClientLauncher()
delete m_rendering_engine;
#if USE_SOUND
g_sound_manager_singleton.reset();
deleteSoundManagerSingleton(g_sound_manager_singleton);
#endif
}
@ -97,8 +97,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
init_args(start_data, cmd_args);
#if USE_SOUND
if (g_settings->getBool("enable_sound"))
g_sound_manager_singleton = createSoundManagerSingleton();
if (g_settings->getBool("enable_sound")) {
// Check if it's already created just in case
if (!g_sound_manager_singleton)
g_sound_manager_singleton = createSoundManagerSingleton();
}
#endif
if (!init_engine()) {
@ -120,6 +123,8 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
m_rendering_engine->setupTopLevelWindow(PROJECT_NAME_C);
RenderingEngine::get_raw_device()->getLogger()->setLogLevel(irr::ELL_INFORMATION);
/*
This changes the minimum allowed number of vertices in a VBO.
Default is 500.
@ -144,30 +149,21 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255, 0, 0, 0));
skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255, 70, 120, 50));
skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255, 255, 255, 255));
#ifdef HAVE_TOUCHSCREENGUI
float density = RenderingEngine::getDisplayDensity();
skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(17.0f * density));
skin->setSize(gui::EGDS_SCROLLBAR_SIZE, (s32)(14.0f * density));
skin->setSize(gui::EGDS_WINDOW_BUTTON_WIDTH, (s32)(15.0f * density));
if (density > 1.5f) {
std::string sprite_path = porting::path_user + "/textures/base/pack/";
if (density > 3.5f)
sprite_path.append("checkbox_64.png");
else if (density > 2.0f)
sprite_path.append("checkbox_32.png");
else
sprite_path.append("checkbox_16.png");
// Texture dimensions should be a power of 2
gui::IGUISpriteBank *sprites = skin->getSpriteBank();
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
video::ITexture *sprite_texture = driver->getTexture(sprite_path.c_str());
if (sprite_texture) {
s32 sprite_id = sprites->addTextureAsSprite(sprite_texture);
if (sprite_id != -1)
skin->setIcon(gui::EGDI_CHECK_BOX_CHECKED, sprite_id);
}
}
#endif
float density = RenderingEngine::getDisplayDensity() * g_settings->getFloat("gui_scaling");
skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(18.0f * density));
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 9
// Load check icon for the checkbox
// TODO other icons
std::string sprite_path = porting::path_share + DIR_DELIM + "textures"
+ DIR_DELIM + "base" + DIR_DELIM + "pack" + DIR_DELIM + "checkbox.png";
if (auto *sprite_texture = RenderingEngine::get_video_driver()->getTexture(sprite_path.c_str())) {
auto *sprites = skin->getSpriteBank();
s32 sprite_id = sprites->addTextureAsSprite(sprite_texture);
if (sprite_id != -1)
skin->setIcon(gui::EGDI_CHECK_BOX_CHECKED, sprite_id);
}
#endif
g_fontengine = new FontEngine(guienv);
FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed.");
@ -293,6 +289,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
receiver->m_touchscreengui = NULL;
#endif
#if defined(__ANDROID__) || defined(__IOS__)
if (!g_gamecallback->shutdown_requested)
porting::notifyExitGame();
#endif
// If no main menu, show error and exit
if (skip_main_menu) {
if (!error_message.empty()) {
@ -472,7 +473,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
// If using simple singleplayer mode, override
if (start_data.isSinglePlayer()) {
start_data.name = "singleplayer";
start_data.name = "Player";
start_data.password = "";
start_data.socket_port = myrand_range(49152, 65535);
} else {
@ -548,9 +549,7 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
infostream << "Waited for other menus" << std::endl;
// Cursor can be non-visible when coming from the game
#ifndef ANDROID
m_rendering_engine->get_raw_device()->getCursorControl()->setVisible(true);
#endif
input->setCursorVisible(true);
/* show main menu */
GUIEngine mymenu(&input->joystick, guiroot, m_rendering_engine, &g_menumgr, menudata, *kill);

View File

@ -29,6 +29,7 @@ struct MapDrawControl
{
// Overrides limits by drawing everything
bool range_all = false;
bool extended_range = false;
// Wanted drawing range
float wanted_range = 0.0f;
// show a wire frame for debugging

View File

@ -40,6 +40,21 @@ static void cloud_3d_setting_changed(const std::string &settingname, void *data)
((Clouds *)data)->readSettings();
}
static const std::vector<u16> quad_indices = []() {
int quad_count = 0x10000 / 4; // max number of quads that can be drawn with 16-bit indices
std::vector<u16> indices;
indices.reserve(quad_count * 6);
for (int k = 0; k < quad_count; k++) {
indices.push_back(4 * k + 0);
indices.push_back(4 * k + 1);
indices.push_back(4 * k + 2);
indices.push_back(4 * k + 2);
indices.push_back(4 * k + 3);
indices.push_back(4 * k + 0);
}
return indices;
}();
Clouds::Clouds(scene::ISceneManager* mgr,
s32 id,
u32 seed
@ -101,8 +116,6 @@ void Clouds::render()
ScopeProfiler sp(g_profiler, "Clouds::render()", SPT_AVG);
int num_faces_to_draw = m_enable_3d ? 6 : 1;
m_material.setFlag(video::EMF_BACK_FACE_CULLING, m_enable_3d);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
@ -170,9 +183,14 @@ void Clouds::render()
// Read noise
std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2);
std::vector<video::S3DVertex> vertices;
vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i);
const int grid_length = 2 * m_cloud_radius_i;
std::vector<bool> grid(grid_length * grid_length);
auto grid_index = [&] (int x, int z) -> int {
return (z + m_cloud_radius_i) * grid_length + (x + m_cloud_radius_i);
};
auto grid_point = [&] (int x, int z) -> bool {
return grid[grid_index(x, z)];
};
for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) {
u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i;
@ -187,147 +205,78 @@ void Clouds::render()
}
}
#define GETINDEX(x, z, radius) (((z)+(radius))*(radius)*2 + (x)+(radius))
#define INAREA(x, z, radius) \
((x) >= -(radius) && (x) < (radius) && (z) >= -(radius) && (z) < (radius))
const float rel_y = m_camera_pos.Y - m_params.height * BS;
const bool draw_top = !m_enable_3d || rel_y >= m_params.thickness * BS;
const bool draw_bottom = rel_y < 0.0f;
for (s16 zi0= -m_cloud_radius_i; zi0 < m_cloud_radius_i; zi0++)
for (s16 xi0= -m_cloud_radius_i; xi0 < m_cloud_radius_i; xi0++)
const v3f origin = v3f(world_center_of_drawing_in_noise_f.X, m_params.height * BS, world_center_of_drawing_in_noise_f.Y) - intToFloat(m_camera_offset, BS);
const f32 rx = cloud_size;
// if clouds are flat, the top layer should be at the given height
const f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
const f32 rz = cloud_size;
// std::vector is great but it is slow
// reserve+push/insert is slow because extending needs to check vector size
// resize+direct access is slow because resize initializes the whole vector
// so... malloc! it can't overflow as there can't be too many faces to draw
const int max_quads_per_cell = m_enable_3d ? 4 : 1;
const int max_quad_id = m_enable_3d ? 6 : 1;
video::S3DVertex *buf = (video::S3DVertex *)malloc(grid.size() * max_quads_per_cell * 4 * sizeof(video::S3DVertex));
video::S3DVertex *pv = buf;
const v3f faces[6][4] = {
{{0, ry, 0}, {0, ry, rz}, {rx, ry, rz}, {rx, ry, 0}}, // top
{{0, ry, 0}, {rx, ry, 0}, {rx, 0, 0}, {0, 0, 0}}, // back
{{rx, ry, 0}, {rx, ry, rz}, {rx, 0, rz}, {rx, 0, 0}}, // right
{{rx, ry, rz}, {0, ry, rz}, {0, 0, rz}, {rx, 0, rz}}, // front
{{0, ry, rz}, {0, ry, 0}, {0, 0, 0}, {0, 0, rz}}, // left
{{rx, 0, rz}, {0, 0, rz}, {0, 0, 0}, {rx, 0, 0}}, // bottom
};
const v3f normals[6] = {{0, 1, 0}, {0, 0, -1}, {1, 0, 0}, {0, 0, 1}, {-1, 0, 0}, {0, -1, 0}};
const video::SColor colors[6] = {c_top, c_side_1, c_side_2, c_side_1, c_side_2, c_bottom};
const v2f tex_coords[4] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
// Draw from back to front for proper transparency
for (s16 zi0= 1-(int)m_cloud_radius_i; zi0 < m_cloud_radius_i-1; zi0++)
for (s16 xi0= 1-(int)m_cloud_radius_i; xi0 < m_cloud_radius_i-1; xi0++)
{
s16 zi = zi0;
s16 xi = xi0;
// Draw from back to front for proper transparency
if(zi >= 0)
zi = m_cloud_radius_i - zi - 1;
if(xi >= 0)
xi = m_cloud_radius_i - xi - 1;
if (zi >= 0)
zi = m_cloud_radius_i - zi - 2;
if (xi >= 0)
xi = m_cloud_radius_i - xi - 2;
u32 i = GETINDEX(xi, zi, m_cloud_radius_i);
if (!grid[i])
if (!grid_point(xi, zi))
continue;
v2f p0 = v2f(xi,zi)*cloud_size + world_center_of_drawing_in_noise_f;
video::S3DVertex v[4] = {
video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 1),
video::S3DVertex(0,0,0, 0,0,0, c_top, 1, 1),
video::S3DVertex(0,0,0, 0,0,0, c_top, 1, 0),
video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 0)
bool do_draw[6] = {
draw_top,
zi > 0 && !grid_point(xi, zi - 1),
xi < 0 && !grid_point(xi + 1, zi),
zi < 0 && !grid_point(xi, zi + 1),
xi > 0 && !grid_point(xi - 1, zi),
draw_bottom,
};
const f32 rx = cloud_size / 2.0f;
// if clouds are flat, the top layer should be at the given height
const f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
const f32 rz = cloud_size / 2;
for(int i=0; i<num_faces_to_draw; i++)
{
switch(i)
{
case 0: // top
for (video::S3DVertex &vertex : v) {
vertex.Normal.set(0,1,0);
}
v[0].Pos.set(-rx, ry,-rz);
v[1].Pos.set(-rx, ry, rz);
v[2].Pos.set( rx, ry, rz);
v[3].Pos.set( rx, ry,-rz);
break;
case 1: // back
if (INAREA(xi, zi - 1, m_cloud_radius_i)) {
u32 j = GETINDEX(xi, zi - 1, m_cloud_radius_i);
if(grid[j])
continue;
}
for (video::S3DVertex &vertex : v) {
vertex.Color = c_side_1;
vertex.Normal.set(0,0,-1);
}
v[0].Pos.set(-rx, ry,-rz);
v[1].Pos.set( rx, ry,-rz);
v[2].Pos.set( rx, 0,-rz);
v[3].Pos.set(-rx, 0,-rz);
break;
case 2: //right
if (INAREA(xi + 1, zi, m_cloud_radius_i)) {
u32 j = GETINDEX(xi+1, zi, m_cloud_radius_i);
if(grid[j])
continue;
}
for (video::S3DVertex &vertex : v) {
vertex.Color = c_side_2;
vertex.Normal.set(1,0,0);
}
v[0].Pos.set( rx, ry,-rz);
v[1].Pos.set( rx, ry, rz);
v[2].Pos.set( rx, 0, rz);
v[3].Pos.set( rx, 0,-rz);
break;
case 3: // front
if (INAREA(xi, zi + 1, m_cloud_radius_i)) {
u32 j = GETINDEX(xi, zi + 1, m_cloud_radius_i);
if(grid[j])
continue;
}
for (video::S3DVertex &vertex : v) {
vertex.Color = c_side_1;
vertex.Normal.set(0,0,-1);
}
v[0].Pos.set( rx, ry, rz);
v[1].Pos.set(-rx, ry, rz);
v[2].Pos.set(-rx, 0, rz);
v[3].Pos.set( rx, 0, rz);
break;
case 4: // left
if (INAREA(xi-1, zi, m_cloud_radius_i)) {
u32 j = GETINDEX(xi-1, zi, m_cloud_radius_i);
if(grid[j])
continue;
}
for (video::S3DVertex &vertex : v) {
vertex.Color = c_side_2;
vertex.Normal.set(-1,0,0);
}
v[0].Pos.set(-rx, ry, rz);
v[1].Pos.set(-rx, ry,-rz);
v[2].Pos.set(-rx, 0,-rz);
v[3].Pos.set(-rx, 0, rz);
break;
case 5: // bottom
for (video::S3DVertex &vertex : v) {
vertex.Color = c_bottom;
vertex.Normal.set(0,-1,0);
}
v[0].Pos.set( rx, 0, rz);
v[1].Pos.set(-rx, 0, rz);
v[2].Pos.set(-rx, 0,-rz);
v[3].Pos.set( rx, 0,-rz);
break;
}
v3f pos(p0.X, m_params.height * BS, p0.Y);
pos -= intToFloat(m_camera_offset, BS);
for (video::S3DVertex &vertex : v) {
vertex.Pos += pos;
vertices.push_back(vertex);
v3f const pos = origin + v3f(xi, 0.0f, zi) * cloud_size;
for (int i = 0; i < max_quad_id; i++) {
if (!do_draw[i])
continue;
for (int k = 0; k < 4; k++) {
pv->Pos = pos + faces[i][k];
pv->Normal = normals[i];
pv->Color = colors[i];
pv->TCoords = tex_coords[k];
pv++;
}
}
}
int quad_count = vertices.size() / 4;
std::vector<u16> indices;
indices.reserve(quad_count * 6);
for (int k = 0; k < quad_count; k++) {
indices.push_back(4 * k + 0);
indices.push_back(4 * k + 1);
indices.push_back(4 * k + 2);
indices.push_back(4 * k + 2);
indices.push_back(4 * k + 3);
indices.push_back(4 * k + 0);
}
driver->drawVertexPrimitiveList(vertices.data(), vertices.size(), indices.data(), 2 * quad_count,
int vertex_count = pv - buf;
int quad_count = vertex_count / 4;
driver->drawVertexPrimitiveList(buf, vertex_count, quad_indices.data(), 2 * quad_count,
video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
free(buf);
// Restore fog settings
driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,

View File

@ -964,10 +964,9 @@ void GenericCAO::updateMarker()
void GenericCAO::updateNametag()
{
if (m_is_local_player) // No nametag for local player
return;
if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0) {
if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0 ||
(m_is_local_player &&
m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST)) {
// Delete nametag
if (m_nametag) {
m_client->getCamera()->removeNametag(m_nametag);
@ -1318,7 +1317,7 @@ void GenericCAO::updateTextures(std::string mod)
bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
m_previous_texture_modifier = m_current_texture_modifier;
// m_previous_texture_modifier = m_current_texture_modifier; // otherwise modifiers will overlap due to function design bug
m_current_texture_modifier = mod;
m_glow = m_prop.glow;
@ -1692,7 +1691,7 @@ void GenericCAO::processMessage(const std::string &data)
player->setZoomFOV(m_prop.zoom_fov);
}
if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
if (m_is_player && m_prop.nametag.empty())
m_prop.nametag = m_name;
if (m_is_local_player)
m_prop.show_on_minimap = false;
@ -1852,14 +1851,14 @@ void GenericCAO::processMessage(const std::string &data)
{
// TODO: Execute defined fast response
// As there is no definition, make a smoke puff
ClientSimpleObject *simple = createSmokePuff(
/*ClientSimpleObject *simple = createSmokePuff(
m_smgr, m_env, m_position,
v2f(m_prop.visual_size.X, m_prop.visual_size.Y) * BS);
m_env->addSimpleObject(simple);
m_env->addSimpleObject(simple);*/
} else if (m_reset_textures_timer < 0 && !m_prop.damage_texture_modifier.empty()) {
m_reset_textures_timer = 0.05;
m_reset_textures_timer = 0.1;
if(damage >= 2)
m_reset_textures_timer += 0.05 * damage;
m_reset_textures_timer += 0.25 * damage;
// Cap damage overlay to 1 second
m_reset_textures_timer = std::min(m_reset_textures_timer, 1.0f);
updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
@ -1912,24 +1911,32 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
time_from_last_punch,
punchitem->wear);
if(result.did_punch && result.damage != 0)
if (!itemgroup_get(m_armor_groups, "silent")) {
SimpleSoundSpec spec;
spec.name = "player_punch";
spec.gain = 1.0f;
m_client->sound()->playSoundAt(spec, false, getPosition());
}
s16 damage = result.damage;
if(result.did_punch && damage != 0)
{
if(result.damage < m_hp)
if(damage < m_hp)
{
m_hp -= result.damage;
m_hp -= damage;
} else {
m_hp = 0;
// TODO: Execute defined fast response
// As there is no definition, make a smoke puff
ClientSimpleObject *simple = createSmokePuff(
/*ClientSimpleObject *simple = createSmokePuff(
m_smgr, m_env, m_position,
v2f(m_prop.visual_size.X, m_prop.visual_size.Y) * BS);
m_env->addSimpleObject(simple);
m_env->addSimpleObject(simple);*/
}
if (m_reset_textures_timer < 0 && !m_prop.damage_texture_modifier.empty()) {
m_reset_textures_timer = 0.05;
m_reset_textures_timer = 0.1;
if (result.damage >= 2)
m_reset_textures_timer += 0.05 * result.damage;
m_reset_textures_timer += 0.25 * result.damage;
// Cap damage overlay to 1 second
m_reset_textures_timer = std::min(m_reset_textures_timer, 1.0f);
updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
@ -1989,6 +1996,9 @@ void GenericCAO::updateMeshCulling()
node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING,
false);
}
// Show/hide the nametag
updateNametag();
}
// Prototype

View File

@ -150,8 +150,10 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
// should be (2+2)*6=24 values in the list. The order of
// the faces in the list is up-down-right-left-back-front
// (compatible with ContentFeatures).
// mask - a bit mask that suppresses drawing of tiles.
// tile i will not be drawn if mask & (1 << i) is 1
void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
TileSpec *tiles, int tilecount, const LightInfo *lights, const f32 *txc)
TileSpec *tiles, int tilecount, const LightInfo *lights, const f32 *txc, u8 mask)
{
assert(tilecount >= 1 && tilecount <= 6); // pre-condition
@ -274,6 +276,8 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
// Add to mesh collector
for (int k = 0; k < 6; ++k) {
if (mask & (1 << k))
continue;
int tileindex = MYMIN(k, tilecount - 1);
collector->append(tiles[tileindex], vertices + 4 * k, 4, quad_indices, 6);
}
@ -363,7 +367,7 @@ void MapblockMeshGenerator::generateCuboidTextureCoords(const aabb3f &box, f32 *
}
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
TileSpec *tiles, int tile_count)
TileSpec *tiles, int tile_count, u8 mask)
{
bool scale = std::fabs(f->visual_scale - 1.0f) > 1e-3f;
f32 texture_coord_buf[24];
@ -400,12 +404,49 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
d.Z = (j & 1) ? dz2 : dz1;
lights[j] = blendLight(d);
}
drawCuboid(box, tiles, tile_count, lights, txc);
drawCuboid(box, tiles, tile_count, lights, txc, mask);
} else {
drawCuboid(box, tiles, tile_count, nullptr, txc);
drawCuboid(box, tiles, tile_count, nullptr, txc, mask);
}
}
u8 MapblockMeshGenerator::getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const
{
const f32 NODE_BOUNDARY = 0.5 * BS;
// For an oversized nodebox, return immediately
if (box.MaxEdge.X > NODE_BOUNDARY ||
box.MinEdge.X < -NODE_BOUNDARY ||
box.MaxEdge.Y > NODE_BOUNDARY ||
box.MinEdge.Y < -NODE_BOUNDARY ||
box.MaxEdge.Z > NODE_BOUNDARY ||
box.MinEdge.Z < -NODE_BOUNDARY)
return 0;
// We can skip faces at node boundary if the matching neighbor is solid
u8 solid_mask =
(box.MaxEdge.Y == NODE_BOUNDARY ? 1 : 0) |
(box.MinEdge.Y == -NODE_BOUNDARY ? 2 : 0) |
(box.MaxEdge.X == NODE_BOUNDARY ? 4 : 0) |
(box.MinEdge.X == -NODE_BOUNDARY ? 8 : 0) |
(box.MaxEdge.Z == NODE_BOUNDARY ? 16 : 0) |
(box.MinEdge.Z == -NODE_BOUNDARY ? 32 : 0);
u8 sametype_mask = 0;
if (f->alpha == AlphaMode::ALPHAMODE_OPAQUE) {
// In opaque nodeboxes, faces on opposite sides can cancel
// each other out if there is a matching neighbor of the same type
sametype_mask =
((solid_mask & 3) == 3 ? 3 : 0) |
((solid_mask & 12) == 12 ? 12 : 0) |
((solid_mask & 48) == 48 ? 48 : 0);
}
// Combine masks with actual neighbors to get the faces to be skipped
return (solid_mask & solid_neighbors) | (sametype_mask & sametype_neighbors);
}
void MapblockMeshGenerator::prepareLiquidNodeDrawing()
{
getSpecialTile(0, &tile_liquid_top);
@ -908,7 +949,7 @@ void MapblockMeshGenerator::drawSignlikeNode()
{
u8 wall = n.getWallMounted(nodedef);
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
static const float offset = BS / 16;
static const float offset = BS / 48;
float size = BS / 2 * f->visual_scale;
// Wall at X+ of node
v3f vertices[4] = {
@ -1363,13 +1404,38 @@ void MapblockMeshGenerator::drawNodeboxNode()
getTile(nodebox_tile_dirs[face], &tiles[face]);
}
bool param2_is_rotation =
f->param_type_2 == CPT2_COLORED_FACEDIR ||
f->param_type_2 == CPT2_COLORED_WALLMOUNTED ||
f->param_type_2 == CPT2_FACEDIR ||
f->param_type_2 == CPT2_WALLMOUNTED;
bool param2_is_level =
f->param_type_2 == CPT2_LEVELED;
// locate possible neighboring nodes to connect to
u8 neighbors_set = 0;
if (f->node_box.type == NODEBOX_CONNECTED) {
for (int dir = 0; dir != 6; dir++) {
u8 flag = 1 << dir;
v3s16 p2 = blockpos_nodes + p + nodebox_connection_dirs[dir];
MapNode n2 = data->m_vmanip.getNodeNoEx(p2);
u8 solid_neighbors = 0;
u8 sametype_neighbors = 0;
for (int dir = 0; dir != 6; dir++) {
u8 flag = 1 << dir;
v3s16 p2 = blockpos_nodes + p + nodebox_tile_dirs[dir];
MapNode n2 = data->m_vmanip.getNodeNoEx(p2);
// mark neighbors that are the same node type
// and have the same rotation or higher level stored as param2
if (n2.param0 == n.param0 &&
(!param2_is_rotation || n.param2 == n2.param2) &&
(!param2_is_level || n.param2 <= n2.param2))
sametype_neighbors |= flag;
// mark neighbors that are simple solid blocks
if (nodedef->get(n2).drawtype == NDT_NORMAL)
solid_neighbors |= flag;
if (f->node_box.type == NODEBOX_CONNECTED) {
p2 = blockpos_nodes + p + nodebox_connection_dirs[dir];
n2 = data->m_vmanip.getNodeNoEx(p2);
if (nodedef->nodeboxConnects(n, n2, flag))
neighbors_set |= flag;
}
@ -1377,8 +1443,10 @@ void MapblockMeshGenerator::drawNodeboxNode()
std::vector<aabb3f> boxes;
n.getNodeBoxes(nodedef, &boxes, neighbors_set);
for (auto &box : boxes)
drawAutoLightedCuboid(box, nullptr, tiles, 6);
for (auto &box : boxes) {
u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors);
drawAutoLightedCuboid(box, nullptr, tiles, 6, mask);
}
}
void MapblockMeshGenerator::drawMeshNode()

View File

@ -100,10 +100,11 @@ public:
// cuboid drawing!
void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount,
const LightInfo *lights , const f32 *txc);
const LightInfo *lights , const f32 *txc, u8 mask = 0);
void generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
void drawAutoLightedCuboid(aabb3f box, const f32 *txc = NULL,
TileSpec *tiles = NULL, int tile_count = 0);
TileSpec *tiles = NULL, int tile_count = 0, u8 mask = 0);
u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const;
// liquid-specific
bool top_is_same_liquid;

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@ GameUI::GameUI()
m_statustext_initial_color = video::SColor(255, 0, 0, 0);
}
void GameUI::init()
void GameUI::init(Client *client)
{
// First line of debug text
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
@ -76,11 +76,15 @@ void GameUI::init()
// If in debug mode, object debug infos shown here, too.
// Located on the left on the screen, below chat.
u32 chat_font_height = m_guitext_chat->getActiveFont()->getDimension(L"Ay").Height;
float scale = 1.0f;
#if defined(__ANDROID__) || defined(__APPLE__)
scale = RenderingEngine::getDisplayDensity() * client->getHudScaling() * 0.5f;
#endif
m_guitext_info = gui::StaticText::add(guienv, L"",
// Size is limited; text will be truncated after 6 lines.
core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 6) +
v2s32(100, chat_font_height *
(g_settings->getU16("recent_chat_messages") + 3)),
v2s32(100 + client->getRoundScreen(),
chat_font_height * (g_settings->getU16("recent_chat_messages") + 3) * scale),
false, true, guiroot);
// Status text (displays info when showing and hiding GUI stuff, etc.)
@ -101,6 +105,10 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
const GUIChatConsole *chat_console, float dtime)
{
v2u32 screensize = RenderingEngine::getWindowSize();
LocalPlayer *player = client->getEnv().getLocalPlayer();
v3f player_position = player->getPosition();
std::ostringstream os(std::ios_base::binary);
// Minimal debug text must only contain info that can't give a gameplay advantage
if (m_flags.show_minimal_debug) {
@ -108,7 +116,6 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
m_drawtime_avg *= 0.95f;
m_drawtime_avg += 0.05f * (stats.drawtime / 1000);
std::ostringstream os(std::ios_base::binary);
os << std::fixed
<< PROJECT_NAME_C " " << g_version_hash
<< " | FPS: " << fps
@ -122,26 +129,29 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
<< (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
<< std::setprecision(2)
<< " | RTT: " << (client->getRTT() * 1000.0f) << "ms";
setStaticText(m_guitext, utf8_to_wide(os.str()).c_str());
} else if (m_flags.show_minimap) {
os << std::setprecision(1) << std::fixed
<< "X: " << (player_position.X / BS)
<< ", Y: " << (player_position.Y / BS)
<< ", Z: " << (player_position.Z / BS);
}
m_guitext->setText(utf8_to_wide(os.str()).c_str());
m_guitext->setRelativePosition(core::rect<s32>(5, 5, screensize.X,
5 + g_fontengine->getTextHeight()));
}
m_guitext->setRelativePosition(core::rect<s32>(
5 + client->getRoundScreen(), 5,
screensize.X, 5 + g_fontengine->getTextHeight()));
// Finally set the guitext visible depending on the flag
m_guitext->setVisible(m_flags.show_minimal_debug);
m_guitext->setVisible(m_flags.show_hud && (m_flags.show_minimal_debug || m_flags.show_minimap));
// Basic debug text also shows info that might give a gameplay advantage
if (m_flags.show_basic_debug) {
LocalPlayer *player = client->getEnv().getLocalPlayer();
v3f player_position = player->getPosition();
std::ostringstream os(std::ios_base::binary);
os << std::setprecision(1) << std::fixed
<< "pos: (" << (player_position.X / BS)
<< ", " << (player_position.Y / BS)
<< ", " << (player_position.Z / BS)
<< ") | yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
<< "X: " << (player_position.X / BS)
<< ", Y: " << (player_position.Y / BS)
<< ", Z: " << (player_position.Z / BS)
<< " | yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
<< yawToDirectionString(cam.camera_yaw)
<< " | pitch: " << (-wrapDegrees_180(cam.camera_pitch)) << "°"
<< " | seed: " << ((u64)client->getMapSeed());
@ -165,7 +175,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
));
}
m_guitext2->setVisible(m_flags.show_basic_debug);
m_guitext2->setVisible(m_flags.show_basic_debug && m_flags.show_hud);
setStaticText(m_guitext_info, m_infotext.c_str());
m_guitext_info->setVisible(m_flags.show_hud && g_menumgr.menuCount() == 0);
@ -187,7 +197,10 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
if (!m_statustext.empty()) {
s32 status_width = m_guitext_status->getTextWidth();
s32 status_height = m_guitext_status->getTextHeight();
s32 status_y = screensize.Y - 150;
s32 status_y = screensize.Y -
150 * RenderingEngine::getDisplayDensity() * client->getHudScaling();
s32 status_x = (screensize.X - status_width) / 2;
m_guitext_status->setRelativePosition(core::rect<s32>(status_x ,
@ -202,6 +215,30 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
m_guitext_status->enableOverrideColor(true);
}
// Update chat text
if (m_chat_text_needs_update) {
m_chat_text_needs_update = false;
if ((!m_flags.show_hud || (!m_flags.show_minimal_debug && !m_flags.show_minimap)) &&
client->getRoundScreen() > 0) {
// Cache the space count
if (!m_space_count) {
// Use spaces to shift the text
const u32 spwidth = g_fontengine->getFont()->getDimension(L" ").Width;
// Divide and round up
m_space_count = (client->getRoundScreen() + spwidth - 1) / spwidth;
}
EnrichedString padded_chat_text;
for (int i = 0; i < m_space_count; i++)
padded_chat_text.addCharNoColor(L' ');
padded_chat_text += m_chat_text;
setStaticText(m_guitext_chat, padded_chat_text);
} else {
setStaticText(m_guitext_chat, m_chat_text);
}
}
// Hide chat when console is visible
m_guitext_chat->setVisible(isChatVisible() && !chat_console->isVisible());
}
@ -214,6 +251,7 @@ void GameUI::initFlags()
void GameUI::showMinimap(bool show)
{
m_chat_text_needs_update = m_chat_text_needs_update || show != m_flags.show_minimap;
m_flags.show_minimap = show;
}
@ -226,8 +264,8 @@ void GameUI::showTranslatedStatusText(const char *str)
void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
{
setStaticText(m_guitext_chat, chat_text);
m_chat_text = chat_text;
m_chat_text_needs_update = true;
m_recent_chat_count = recent_chat_count;
}
@ -236,10 +274,12 @@ void GameUI::updateChatSize()
// Update gui element size and position
s32 chat_y = 5;
if (m_flags.show_minimal_debug)
chat_y += g_fontengine->getLineHeight();
if (m_flags.show_basic_debug)
chat_y += g_fontengine->getLineHeight();
if (m_flags.show_hud) {
if (m_flags.show_minimal_debug)
chat_y += g_fontengine->getLineHeight() * 2;
else if (m_flags.show_minimap)
chat_y += g_fontengine->getLineHeight();
}
const v2u32 &window_size = RenderingEngine::getWindowSize();
@ -297,6 +337,7 @@ void GameUI::toggleHud()
showTranslatedStatusText("HUD shown");
else
showTranslatedStatusText("HUD hidden");
m_chat_text_needs_update = true;
}
void GameUI::toggleProfiler()

View File

@ -63,7 +63,7 @@ public:
bool show_profiler_graph = false;
};
void init();
void init(Client *client);
void update(const RunStats &stats, Client *client, MapDrawControl *draw_control,
const CameraOrientation &cam, const PointedThing &pointed_old,
const GUIChatConsole *chat_console, float dtime);
@ -124,6 +124,9 @@ private:
video::SColor m_statustext_initial_color;
gui::IGUIStaticText *m_guitext_chat = nullptr; // Chat text
EnrichedString m_chat_text;
bool m_chat_text_needs_update = false;
int m_space_count = 0;
u32 m_recent_chat_count = 0;
core::rect<s32> m_current_chat_size{0, 0, 0, 0};

View File

@ -170,52 +170,61 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
}
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
const core::rect<s32> &rect, const core::rect<s32> &middle,
const core::rect<s32> *cliprect, const video::SColor *const colors)
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
const core::rect<s32> &middlerect, const core::rect<s32> *cliprect,
const video::SColor *const colors)
{
auto originalSize = texture->getOriginalSize();
core::vector2di lowerRightOffset = core::vector2di(originalSize.Width, originalSize.Height) - middle.LowerRightCorner;
// `-x` is interpreted as `w - x`
core::rect<s32> middle = middlerect;
if (middlerect.LowerRightCorner.X < 0)
middle.LowerRightCorner.X += srcrect.getWidth();
if (middlerect.LowerRightCorner.Y < 0)
middle.LowerRightCorner.Y += srcrect.getHeight();
core::vector2di lower_right_offset = core::vector2di(srcrect.getWidth(),
srcrect.getHeight()) - middle.LowerRightCorner;
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
core::rect<s32> src({0, 0}, originalSize);
core::rect<s32> dest = rect;
core::rect<s32> src = srcrect;
core::rect<s32> dest = destrect;
switch (x) {
case 0:
dest.LowerRightCorner.X = rect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
src.LowerRightCorner.X = middle.UpperLeftCorner.X;
dest.LowerRightCorner.X = destrect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
src.LowerRightCorner.X = srcrect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
break;
case 1:
dest.UpperLeftCorner.X += middle.UpperLeftCorner.X;
dest.LowerRightCorner.X -= lowerRightOffset.X;
src.UpperLeftCorner.X = middle.UpperLeftCorner.X;
src.LowerRightCorner.X = middle.LowerRightCorner.X;
dest.LowerRightCorner.X -= lower_right_offset.X;
src.UpperLeftCorner.X += middle.UpperLeftCorner.X;
src.LowerRightCorner.X -= lower_right_offset.X;
break;
case 2:
dest.UpperLeftCorner.X = rect.LowerRightCorner.X - lowerRightOffset.X;
src.UpperLeftCorner.X = middle.LowerRightCorner.X;
dest.UpperLeftCorner.X = destrect.LowerRightCorner.X - lower_right_offset.X;
src.UpperLeftCorner.X = srcrect.LowerRightCorner.X - lower_right_offset.X;
break;
}
switch (y) {
case 0:
dest.LowerRightCorner.Y = rect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
src.LowerRightCorner.Y = middle.UpperLeftCorner.Y;
dest.LowerRightCorner.Y = destrect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
src.LowerRightCorner.Y = srcrect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
break;
case 1:
dest.UpperLeftCorner.Y += middle.UpperLeftCorner.Y;
dest.LowerRightCorner.Y -= lowerRightOffset.Y;
src.UpperLeftCorner.Y = middle.UpperLeftCorner.Y;
src.LowerRightCorner.Y = middle.LowerRightCorner.Y;
dest.LowerRightCorner.Y -= lower_right_offset.Y;
src.UpperLeftCorner.Y += middle.UpperLeftCorner.Y;
src.LowerRightCorner.Y -= lower_right_offset.Y;
break;
case 2:
dest.UpperLeftCorner.Y = rect.LowerRightCorner.Y - lowerRightOffset.Y;
src.UpperLeftCorner.Y = middle.LowerRightCorner.Y;
dest.UpperLeftCorner.Y = destrect.LowerRightCorner.Y - lower_right_offset.Y;
src.UpperLeftCorner.Y = srcrect.LowerRightCorner.Y - lower_right_offset.Y;
break;
}

View File

@ -46,13 +46,13 @@ video::ITexture *guiScalingImageButton(video::IVideoDriver *driver, video::IText
*/
void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
const core::rect<s32> *cliprect = 0, const video::SColor *const colors = 0,
bool usealpha = false);
const core::rect<s32> *cliprect = nullptr,
const video::SColor *const colors = nullptr, bool usealpha = false);
/*
* 9-slice / segment drawing
*/
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
const core::rect<s32> &rect, const core::rect<s32> &middle,
const core::rect<s32> *cliprect = nullptr,
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
const core::rect<s32> &middlerect, const core::rect<s32> *cliprect = nullptr,
const video::SColor *const colors = nullptr);

View File

@ -44,8 +44,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gui/touchscreengui.h"
#endif
#define OBJECT_CROSSHAIR_LINE_SIZE 8
#define CROSSHAIR_LINE_SIZE 10
#define OBJECT_CROSSHAIR_LINE_SIZE 16
#define CROSSHAIR_LINE_SIZE 16
Hud::Hud(Client *client, LocalPlayer *player,
Inventory *inventory)
@ -61,6 +61,7 @@ Hud::Hud(Client *client, LocalPlayer *player,
RenderingEngine::getDisplayDensity() + 0.5f);
m_hotbar_imagesize *= m_hud_scaling;
m_padding = m_hotbar_imagesize / 12;
m_hud_move_upwards = g_settings->getU16("hud_move_upwards");
for (auto &hbar_color : hbar_colors)
hbar_color = video::SColor(255, 255, 255, 255);
@ -109,7 +110,7 @@ Hud::Hud(Client *client, LocalPlayer *player,
if (m_mode == HIGHLIGHT_BOX) {
m_selection_material.Thickness =
rangelim(g_settings->getS16("selectionbox_width"), 1, 5);
rangelim(g_settings->getS16("selectionbox_width"), 1, 6);
} else if (m_mode == HIGHLIGHT_HALO) {
m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png"));
m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true);
@ -360,10 +361,12 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
floor(e->pos.Y * (float) m_screensize.Y + 0.5));
switch (e->type) {
case HUD_ELEM_TEXT: {
unsigned int font_size = g_fontengine->getDefaultFontSize();
float font_size = g_fontengine->getDefaultFontSize();
if (e->size.X > 0)
font_size *= e->size.X;
else if (e->size.Y > 0)
font_size = MYMAX(font_size * (float) e->size.Y / 100, 1.0f);
#ifdef __ANDROID__
// The text size on Android is not proportional with the actual scaling
@ -448,14 +451,19 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
const video::SColor color(255, 255, 255, 255);
const video::SColor colors[] = {color, color, color, color};
core::dimension2di imgsize(texture->getOriginalSize());
v2s32 dstsize(imgsize.Width * e->scale.X * m_scale_factor,
imgsize.Height * e->scale.Y * m_scale_factor);
v2s32 dstsize(imgsize.Width * e->scale.X,
imgsize.Height * e->scale.Y);
if (e->scale.X < 0)
dstsize.X = m_screensize.X * (e->scale.X * -0.01);
if (e->scale.Y < 0)
dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
dstsize.X *= m_scale_factor;
dstsize.Y *= m_scale_factor;
v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
(e->align.Y - 1.0) * dstsize.Y / 2);
if ((dstsize.Y + pos.Y + offset.Y + e->offset.Y * m_scale_factor) > m_displaycenter.Y)
offset.Y -= m_hud_move_upwards;
core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
rect += pos + offset + v2s32(e->offset.X * m_scale_factor,
e->offset.Y * m_scale_factor);
@ -619,26 +627,29 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
}
core::dimension2di srcd(stat_texture->getOriginalSize());
core::dimension2di srcd_bg = stat_texture_bg ? core::dimension2di(stat_texture_bg->getOriginalSize()) : srcd;
core::dimension2di dstd;
if (size == v2s32()) {
dstd = srcd;
dstd.Height *= m_scale_factor;
dstd.Width *= m_scale_factor;
offset.X *= m_scale_factor;
offset.Y *= m_scale_factor;
} else {
dstd.Height = size.Y * m_scale_factor;
dstd.Width = size.X * m_scale_factor;
offset.X *= m_scale_factor;
offset.Y *= m_scale_factor;
}
offset.X *= m_scale_factor;
offset.Y *= m_scale_factor;
v2s32 p = pos;
if (corner & HUD_CORNER_LOWER)
p -= dstd.Height;
p += offset;
if ((pos.Y + offset.Y) > m_displaycenter.Y)
p.Y -= m_hud_move_upwards;
v2s32 steppos;
switch (drawdir) {
case HUD_DIR_RIGHT_LEFT:
@ -680,7 +691,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
// Need to draw halves: Calculate rectangles
srchalfrect = calculate_clipping_rect(srcd, steppos);
dsthalfrect = calculate_clipping_rect(dstd, steppos);
srchalfrect2 = calculate_clipping_rect(srcd, steppos * -1);
srchalfrect2 = calculate_clipping_rect(srcd_bg, steppos * -1);
dsthalfrect2 = calculate_clipping_rect(dstd, steppos * -1);
}
@ -719,7 +730,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
else
start_offset = count / 2;
for (s32 i = start_offset; i < maxcount / 2; i++) {
core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
core::rect<s32> srcrect(0, 0, srcd_bg.Width, srcd_bg.Height);
core::rect<s32> dstrect(0, 0, dstd.Width, dstd.Height);
dstrect += p;
@ -731,7 +742,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
if (maxcount % 2 == 1) {
draw2DImageFilterScaled(driver, stat_texture_bg,
dsthalfrect + p, srchalfrect,
dsthalfrect + p, calculate_clipping_rect(srcd_bg, steppos),
NULL, colors, true);
}
}
@ -750,7 +761,8 @@ void Hud::drawHotbar(u16 playeritem) {
s32 hotbar_itemcount = player->hud_hotbar_itemcount;
s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 2.4);
pos.Y -= m_hud_move_upwards;
const v2u32 &window_size = RenderingEngine::getWindowSize();
if ((float) width / (float) window_size.X <=
@ -777,43 +789,49 @@ void Hud::drawHotbar(u16 playeritem) {
void Hud::drawCrosshair()
{
if (pointing_at_object) {
int obj_crosshair_size = (int) (OBJECT_CROSSHAIR_LINE_SIZE * m_scale_factor);
if (use_object_crosshair_image) {
video::ITexture *object_crosshair = tsrc->getTexture("object_crosshair.png");
v2u32 size = object_crosshair->getOriginalSize();
v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
m_displaycenter.Y - (size.Y / 2));
driver->draw2DImage(object_crosshair, lsize,
core::rect<s32>(0, 0, size.X, size.Y),
nullptr, crosshair_argb, true);
core::rect<s32> rect(m_displaycenter.X - obj_crosshair_size,
m_displaycenter.Y - obj_crosshair_size,
m_displaycenter.X + obj_crosshair_size,
m_displaycenter.Y + obj_crosshair_size);
video::SColor crosshair_color[] = {crosshair_argb, crosshair_argb,
crosshair_argb, crosshair_argb};
draw2DImageFilterScaled(driver, object_crosshair, rect,
core::rect<s32>({0, 0}, object_crosshair->getOriginalSize()),
nullptr, crosshair_color, true);
} else {
driver->draw2DLine(
m_displaycenter - v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
OBJECT_CROSSHAIR_LINE_SIZE),
m_displaycenter + v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
OBJECT_CROSSHAIR_LINE_SIZE), crosshair_argb);
m_displaycenter - v2s32(obj_crosshair_size, obj_crosshair_size),
m_displaycenter + v2s32(obj_crosshair_size, obj_crosshair_size),
crosshair_argb);
driver->draw2DLine(
m_displaycenter + v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
-OBJECT_CROSSHAIR_LINE_SIZE),
m_displaycenter + v2s32(-OBJECT_CROSSHAIR_LINE_SIZE,
OBJECT_CROSSHAIR_LINE_SIZE), crosshair_argb);
m_displaycenter + v2s32(obj_crosshair_size, -obj_crosshair_size),
m_displaycenter + v2s32(-obj_crosshair_size, obj_crosshair_size),
crosshair_argb);
}
return;
}
int crosshair_size = (int) (CROSSHAIR_LINE_SIZE * m_scale_factor);
if (use_crosshair_image) {
video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
v2u32 size = crosshair->getOriginalSize();
v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
m_displaycenter.Y - (size.Y / 2));
driver->draw2DImage(crosshair, lsize,
core::rect<s32>(0, 0, size.X, size.Y),
nullptr, crosshair_argb, true);
core::rect<s32> rect(m_displaycenter.X - crosshair_size,
m_displaycenter.Y - crosshair_size,
m_displaycenter.X + crosshair_size,
m_displaycenter.Y + crosshair_size);
video::SColor crosshair_color[] = {crosshair_argb, crosshair_argb,
crosshair_argb, crosshair_argb};
draw2DImageFilterScaled(driver, crosshair, rect,
core::rect<s32>({0, 0}, crosshair->getOriginalSize()),
nullptr, crosshair_color, true);
} else {
driver->draw2DLine(m_displaycenter - v2s32(CROSSHAIR_LINE_SIZE, 0),
m_displaycenter + v2s32(CROSSHAIR_LINE_SIZE, 0), crosshair_argb);
driver->draw2DLine(m_displaycenter - v2s32(0, CROSSHAIR_LINE_SIZE),
m_displaycenter + v2s32(0, CROSSHAIR_LINE_SIZE), crosshair_argb);
driver->draw2DLine(m_displaycenter - v2s32(crosshair_size, 0),
m_displaycenter + v2s32(crosshair_size, 0), crosshair_argb);
driver->draw2DLine(m_displaycenter - v2s32(0, crosshair_size),
m_displaycenter + v2s32(0, crosshair_size), crosshair_argb);
}
}

View File

@ -120,6 +120,7 @@ private:
v2s32 m_displaycenter;
s32 m_hotbar_imagesize; // Takes hud_scaling into account, updated by resizeHotbar()
s32 m_padding; // Takes hud_scaling into account, updated by resizeHotbar()
s32 m_hud_move_upwards;
video::SColor hbar_colors[4];
std::vector<aabb3f> m_selection_boxes;

View File

@ -20,8 +20,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include "inputhandler.h"
#include "gui/guiChatConsole.h"
#include "gui/mainmenumanager.h"
#include "hud.h"
#include "settings.h"
#ifdef __IOS__
#include "porting_ios.h"
extern "C" void external_pause_game();
#endif
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
#include <SDL.h>
#endif
void KeyCache::populate_nonchanging()
{
@ -98,13 +109,57 @@ void KeyCache::populate()
bool MyEventReceiver::OnEvent(const SEvent &event)
{
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
if (event.EventType == irr::EET_SDL_CONTROLLER_BUTTON_EVENT ||
event.EventType == irr::EET_SDL_CONTROLLER_AXIS_EVENT) {
if (g_settings->getBool("enable_joysticks")) {
sdl_game_controller->translateEvent(event);
input->setCursorVisible(sdl_game_controller->isCursorVisible());
}
} else if ((event.EventType == irr::EET_MOUSE_INPUT_EVENT &&
event.MouseInput.Event == irr::EMIE_MOUSE_MOVED) ||
event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
if (!sdl_game_controller->isFakeEvent() &&
sdl_game_controller->isActive()) {
sdl_game_controller->setActive(false);
input->setCursorVisible(sdl_game_controller->isCursorVisible());
}
}
#endif
#ifdef HAVE_TOUCHSCREENGUI
if (event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
TouchScreenGUI::setActive(true);
if (m_touchscreengui && !isMenuActive())
m_touchscreengui->show();
} else if ((event.EventType == irr::EET_MOUSE_INPUT_EVENT &&
event.MouseInput.Event == irr::EMIE_MOUSE_MOVED) ||
sdl_game_controller->isActive()) {
TouchScreenGUI::setActive(false);
if (m_touchscreengui && !isMenuActive())
m_touchscreengui->hide();
}
#endif
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
if (event.EventType == irr::EET_SDL_CONTROLLER_BUTTON_EVENT)
return true;
#endif
GUIChatConsole* chat_console = GUIChatConsole::getChatConsole();
if (chat_console && chat_console->isOpen()) {
bool result = chat_console->preprocessEvent(event);
if (result)
return true;
}
/*
React to nothing here if a menu is active
*/
if (isMenuActive()) {
#ifdef HAVE_TOUCHSCREENGUI
if (m_touchscreengui) {
m_touchscreengui->Toggle(false);
m_touchscreengui->hide();
}
#endif
return g_menumgr.preprocessEvent(event);
@ -137,6 +192,15 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
return true;
#endif
#ifdef __IOS__
} else if (event.EventType == irr::EET_APPLICATION_EVENT) {
int AppEvent = event.ApplicationEvent.EventType;
ioswrap_events(AppEvent);
if (AppEvent == irr::EAET_WILL_PAUSE)
external_pause_game();
return true;
#endif
} else if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
// joystick may be nullptr if game is launched with '--random-input' parameter
return joystick && joystick->handleEvent(event.JoystickEvent);
@ -191,8 +255,10 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
LL_NONE, // ELL_NONE
};
assert(event.LogEvent.Level < ARRLEN(irr_loglev_conv));
#ifndef NDEBUG
g_logger.log(irr_loglev_conv[event.LogEvent.Level],
std::string("Irrlicht: ") + event.LogEvent.Text);
#endif
return true;
}
/* always return false in order to continue processing events */

View File

@ -197,6 +197,11 @@ public:
JoystickController *joystick = nullptr;
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
SDLGameController* sdl_game_controller = nullptr;
InputHandler* input = nullptr;
#endif
#ifdef HAVE_TOUCHSCREENGUI
TouchScreenGUI *m_touchscreengui;
#endif
@ -264,8 +269,13 @@ public:
virtual void clear() {}
virtual void setCursorVisible(bool visible) {};
JoystickController joystick;
KeyCache keycache;
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
SDLGameController sdl_game_controller;
#endif
};
/*
Separated input handler
@ -277,6 +287,10 @@ public:
RealInputHandler(MyEventReceiver *receiver) : m_receiver(receiver)
{
m_receiver->joystick = &joystick;
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
m_receiver->sdl_game_controller = &sdl_game_controller;
m_receiver->input = this;
#endif
}
virtual ~RealInputHandler()
@ -389,6 +403,22 @@ public:
return m_receiver->getMouseWheel();
}
virtual void setCursorVisible(bool visible)
{
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
sdl_game_controller.setCursorVisible(visible);
if (sdl_game_controller.isActive())
visible = false;
#endif
IrrlichtDevice *device = RenderingEngine::get_raw_device();
if (device->getCursorControl()) {
if (visible != device->getCursorControl()->isVisible())
device->getCursorControl()->setVisible(visible);
}
}
void clear()
{
joystick.clear();

View File

@ -20,9 +20,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "joystick_controller.h"
#include "irrlichttypes_extrabloated.h"
#include "keys.h"
#include "keycode.h"
#include "gui/mainmenumanager.h"
#include "settings.h"
#include "gettime.h"
#include "porting.h"
#include "renderingengine.h"
#include "util/string.h"
bool JoystickButtonCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
@ -326,3 +329,352 @@ float JoystickController::getMovementSpeed()
speed = 1.0f;
return speed;
}
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
bool SDLGameController::m_active = false;
bool SDLGameController::m_cursor_visible = false;
void SDLGameController::handleMouseMovement(int x, int y)
{
IrrlichtDevice* device = RenderingEngine::get_raw_device();
bool changed = false;
u32 current_time = device->getTimer()->getRealTime();
v2s32 mouse_pos = device->getCursorControl()->getPosition();
int deadzone = g_settings->getU16("joystick_deadzone");
if (x > deadzone || x < -deadzone) {
s32 dt = current_time - m_mouse_time;
mouse_pos.X += (x * dt / 30000);
if (mouse_pos.X < 0)
mouse_pos.X = 0;
if (mouse_pos.X > device->getVideoDriver()->getScreenSize().Width)
mouse_pos.X = device->getVideoDriver()->getScreenSize().Width;
changed = true;
}
if (y > deadzone || y < -deadzone) {
s32 dt = current_time - m_mouse_time;
mouse_pos.Y += (y * dt / 30000);
if (mouse_pos.Y < 0)
mouse_pos.Y = 0;
if (mouse_pos.Y > device->getVideoDriver()->getScreenSize().Height)
mouse_pos.Y = device->getVideoDriver()->getScreenSize().Height;
changed = true;
}
if (changed) {
SEvent translated_event;
translated_event.EventType = irr::EET_MOUSE_INPUT_EVENT;
translated_event.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
translated_event.MouseInput.X = mouse_pos.X;
translated_event.MouseInput.Y = mouse_pos.Y;
translated_event.MouseInput.Control = false;
translated_event.MouseInput.Shift = false;
translated_event.MouseInput.ButtonStates = m_button_states;
sendEvent(translated_event);
device->getCursorControl()->setPosition(mouse_pos.X, mouse_pos.Y);
}
m_mouse_time = current_time;
}
void SDLGameController::handleTriggerLeft(s16 value)
{
IrrlichtDevice* device = RenderingEngine::get_raw_device();
int deadzone = g_settings->getU16("joystick_deadzone");
SEvent translated_event;
translated_event.EventType = irr::EET_KEY_INPUT_EVENT;
translated_event.KeyInput.Char = 0;
translated_event.KeyInput.Key = getKeySetting("keymap_hotbar_previous").getKeyCode();
translated_event.KeyInput.Shift = false;
translated_event.KeyInput.Control = false;
if (value <= deadzone && m_trigger_left_value > deadzone) {
translated_event.KeyInput.PressedDown = false;
sendEvent(translated_event);
} else if (value > deadzone && m_trigger_left_value <= deadzone) {
translated_event.KeyInput.PressedDown = true;
sendEvent(translated_event);
}
m_trigger_left_value = value;
}
void SDLGameController::handleTriggerRight(s16 value)
{
IrrlichtDevice* device = RenderingEngine::get_raw_device();
int deadzone = g_settings->getU16("joystick_deadzone");
SEvent translated_event;
translated_event.EventType = irr::EET_KEY_INPUT_EVENT;
translated_event.KeyInput.Char = 0;
translated_event.KeyInput.Key = getKeySetting("keymap_hotbar_next").getKeyCode();
translated_event.KeyInput.Shift = false;
translated_event.KeyInput.Control = false;
if (value <= deadzone && m_trigger_right_value > deadzone) {
translated_event.KeyInput.PressedDown = false;
sendEvent(translated_event);
} else if (value > deadzone && m_trigger_right_value <= deadzone) {
translated_event.KeyInput.PressedDown = true;
sendEvent(translated_event);
}
m_trigger_right_value = value;
}
void SDLGameController::handleMouseClickLeft(bool pressed)
{
IrrlichtDevice* device = RenderingEngine::get_raw_device();
v2s32 mouse_pos = device->getCursorControl()->getPosition();
if (pressed)
m_button_states |= irr::EMBSM_LEFT;
else
m_button_states &= ~irr::EMBSM_LEFT;
SEvent translated_event;
translated_event.EventType = irr::EET_MOUSE_INPUT_EVENT;
translated_event.MouseInput.Event = pressed ? irr::EMIE_LMOUSE_PRESSED_DOWN : irr::EMIE_LMOUSE_LEFT_UP;
translated_event.MouseInput.X = mouse_pos.X;
translated_event.MouseInput.Y = mouse_pos.Y;
translated_event.MouseInput.Control = false;
translated_event.MouseInput.Shift = false;
translated_event.MouseInput.ButtonStates = m_button_states;
sendEvent(translated_event);
}
void SDLGameController::handleMouseClickRight(bool pressed)
{
IrrlichtDevice* device = RenderingEngine::get_raw_device();
v2s32 mouse_pos = device->getCursorControl()->getPosition();
if (pressed)
m_button_states |= irr::EMBSM_RIGHT;
else
m_button_states &= ~irr::EMBSM_RIGHT;
SEvent translated_event;
translated_event.EventType = irr::EET_MOUSE_INPUT_EVENT;
translated_event.MouseInput.Event = pressed ? irr::EMIE_RMOUSE_PRESSED_DOWN : irr::EMIE_RMOUSE_LEFT_UP;
translated_event.MouseInput.X = mouse_pos.X;
translated_event.MouseInput.Y = mouse_pos.Y;
translated_event.MouseInput.Control = false;
translated_event.MouseInput.Shift = false;
translated_event.MouseInput.ButtonStates = m_button_states;
sendEvent(translated_event);
}
void SDLGameController::handleButton(const SEvent &event)
{
irr::EKEY_CODE key = KEY_UNKNOWN;
switch (event.SDLControllerButtonEvent.Button) {
case SDL_CONTROLLER_BUTTON_A:
key = getKeySetting("keymap_jump").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_B:
key = getKeySetting("keymap_sneak").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_X:
key = getKeySetting("keymap_special1").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_Y:
key = getKeySetting("keymap_minimap").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_BACK:
key = getKeySetting("keymap_chat").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_GUIDE:
break;
case SDL_CONTROLLER_BUTTON_START:
key = KEY_ESCAPE;
break;
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
key = getKeySetting("keymap_camera_mode").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
key = KEY_LBUTTON;
break;
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
key = KEY_LBUTTON;
break;
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
key = KEY_RBUTTON;
break;
case SDL_CONTROLLER_BUTTON_DPAD_UP:
key = getKeySetting("keymap_rangeselect").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
key = getKeySetting("keymap_drop").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
key = KEY_ESCAPE;
break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
key = getKeySetting("keymap_inventory").getKeyCode();
break;
case SDL_CONTROLLER_BUTTON_MISC1:
case SDL_CONTROLLER_BUTTON_PADDLE1:
case SDL_CONTROLLER_BUTTON_PADDLE2:
case SDL_CONTROLLER_BUTTON_PADDLE3:
case SDL_CONTROLLER_BUTTON_PADDLE4:
case SDL_CONTROLLER_BUTTON_TOUCHPAD:
break;
}
if (key != KEY_UNKNOWN) {
SEvent translated_event;
translated_event.EventType = irr::EET_KEY_INPUT_EVENT;
translated_event.KeyInput.Char = 0;
translated_event.KeyInput.Key = key;
translated_event.KeyInput.PressedDown = event.SDLControllerButtonEvent.Pressed;
translated_event.KeyInput.Shift = false;
translated_event.KeyInput.Control = false;
sendEvent(translated_event);
}
}
void SDLGameController::handleButtonInMenu(const SEvent &event)
{
irr::EKEY_CODE key = KEY_UNKNOWN;
// Just used game mapping for escape key for now
switch (event.SDLControllerButtonEvent.Button) {
case SDL_CONTROLLER_BUTTON_A:
case SDL_CONTROLLER_BUTTON_B:
case SDL_CONTROLLER_BUTTON_X:
case SDL_CONTROLLER_BUTTON_Y:
case SDL_CONTROLLER_BUTTON_BACK:
case SDL_CONTROLLER_BUTTON_GUIDE:
break;
case SDL_CONTROLLER_BUTTON_START:
key = KEY_ESCAPE;
break;
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
case SDL_CONTROLLER_BUTTON_DPAD_UP:
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
key = KEY_ESCAPE;
break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
case SDL_CONTROLLER_BUTTON_MISC1:
case SDL_CONTROLLER_BUTTON_PADDLE1:
case SDL_CONTROLLER_BUTTON_PADDLE2:
case SDL_CONTROLLER_BUTTON_PADDLE3:
case SDL_CONTROLLER_BUTTON_PADDLE4:
case SDL_CONTROLLER_BUTTON_TOUCHPAD:
break;
}
if (key != KEY_UNKNOWN) {
SEvent translated_event;
translated_event.EventType = irr::EET_KEY_INPUT_EVENT;
translated_event.KeyInput.Char = 0;
translated_event.KeyInput.Key = key;
translated_event.KeyInput.PressedDown = event.SDLControllerButtonEvent.Pressed;
translated_event.KeyInput.Shift = false;
translated_event.KeyInput.Control = false;
sendEvent(translated_event);
}
}
void SDLGameController::handlePlayerMovement(int x, int y)
{
int deadzone = g_settings->getU16("joystick_deadzone");
m_move_sideward = x;
if (m_move_sideward < deadzone && m_move_sideward > -deadzone)
m_move_sideward = 0;
else
m_active = true;
m_move_forward = y;
if (m_move_forward < deadzone && m_move_forward > -deadzone)
m_move_forward = 0;
else
m_active = true;
}
void SDLGameController::handleCameraOrientation(int x, int y)
{
int deadzone = g_settings->getU16("joystick_deadzone");
m_camera_yaw = x;
if (m_camera_yaw < deadzone && m_camera_yaw > -deadzone)
m_camera_yaw = 0;
else
m_active = true;
m_camera_pitch = y;
if (m_camera_pitch < deadzone && m_camera_pitch > -deadzone)
m_camera_pitch = 0;
else
m_active = true;
}
void SDLGameController::sendEvent(const SEvent &event)
{
m_active = true;
m_is_fake_event = true;
IrrlichtDevice* device = RenderingEngine::get_raw_device();
device->postEventFromUser(event);
m_is_fake_event = false;
}
void SDLGameController::translateEvent(const SEvent &event)
{
if (event.EventType == irr::EET_SDL_CONTROLLER_BUTTON_EVENT) {
if (isMenuActive()) {
if (event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSTICK ||
event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
handleMouseClickLeft(event.SDLControllerButtonEvent.Pressed);
} else if (event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
handleMouseClickRight(event.SDLControllerButtonEvent.Pressed);
} else {
handleButtonInMenu(event);
}
} else {
if (event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_RIGHTSTICK ||
event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
handleMouseClickLeft(event.SDLControllerButtonEvent.Pressed);
} else if (event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
handleMouseClickRight(event.SDLControllerButtonEvent.Pressed);
} else {
handleButton(event);
}
}
} else if (event.EventType == irr::EET_SDL_CONTROLLER_AXIS_EVENT) {
const s16* value = event.SDLControllerAxisEvent.Value;
if (isMenuActive()) {
handleMouseMovement(value[SDL_CONTROLLER_AXIS_LEFTX], value[SDL_CONTROLLER_AXIS_LEFTY]);
} else {
handleTriggerLeft(value[SDL_CONTROLLER_AXIS_TRIGGERLEFT]);
handleTriggerRight(value[SDL_CONTROLLER_AXIS_TRIGGERRIGHT]);
handlePlayerMovement(value[SDL_CONTROLLER_AXIS_LEFTX], value[SDL_CONTROLLER_AXIS_LEFTY]);
handleCameraOrientation(value[SDL_CONTROLLER_AXIS_RIGHTX], value[SDL_CONTROLLER_AXIS_RIGHTY]);
}
}
}
#endif

View File

@ -170,3 +170,47 @@ private:
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_keys_pressed;
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_released;
};
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
class SDLGameController
{
private:
void handleMouseMovement(int x, int y);
void handleTriggerLeft(s16 value);
void handleTriggerRight(s16 value);
void handleMouseClickLeft(bool pressed);
void handleMouseClickRight(bool pressed);
void handleButton(const SEvent &event);
void handleButtonInMenu(const SEvent &event);
void handlePlayerMovement(int x, int y);
void handleCameraOrientation(int x, int y);
void sendEvent(const SEvent &event);
int m_button_states = 0;
u32 m_mouse_time = 0;
s16 m_trigger_left_value = 0;
s16 m_trigger_right_value = 0;
s16 m_move_sideward = 0;
s16 m_move_forward = 0;
s16 m_camera_yaw = 0;
s16 m_camera_pitch = 0;
static bool m_active;
static bool m_cursor_visible;
bool m_is_fake_event = false;
public:
void translateEvent(const SEvent &event);
s16 getMoveSideward() { return m_move_sideward; }
s16 getMoveForward() { return m_move_forward; }
s16 getCameraYaw() { return m_camera_yaw; }
s16 getCameraPitch() { return m_camera_pitch; }
void setActive(bool value) { m_active = value; }
static bool isActive() { return m_active; }
void setCursorVisible(bool visible) { m_cursor_visible = visible; }
static bool isCursorVisible() { return m_cursor_visible; }
bool isFakeEvent() { return m_is_fake_event; }
};
#endif

View File

@ -44,6 +44,8 @@ public:
const char *sym() const;
const char *name() const;
irr::EKEY_CODE getKeyCode() { return Key; }
protected:
static bool valid_kcode(irr::EKEY_CODE k)
{

View File

@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "client.h"
#include "content_cao.h"
#include "client/joystick_controller.h"
#include "gui/touchscreengui.h"
/*
LocalPlayer
@ -172,11 +174,13 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
if (!collision_info || collision_info->empty())
m_standing_node = floatToInt(m_position, BS);
#if 0
// Temporary option for old move code
if (!physics_override_new_move) {
old_move(dtime, env, pos_max_d, collision_info);
return;
}
#endif
Map *map = &env->getMap();
const NodeDefManager *nodemgr = m_client->ndef();
@ -292,6 +296,11 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
float player_stepheight = (m_cao == nullptr) ? 0.0f :
(touching_ground ? m_cao->getStepHeight() : (0.2f * BS));
#ifdef HAVE_TOUCHSCREENGUI
if (TouchScreenGUI::isActive() && touching_ground)
player_stepheight += (0.6f * BS);
#endif
v3f accel_f;
const v3f initial_position = position;
const v3f initial_speed = m_speed;
@ -423,7 +432,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
// Set camera impact value to be used for view bobbing
camera_impact = getSpeed().Y * -1;
camera_impact = -initial_speed.Y;
}
{
@ -627,6 +636,18 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
speedH *= control.movement_speed; /* Apply analog input */
if (!free_move && !in_liquid && !in_liquid_stable && !getParent() && (physics_override_speed != 0)) {
if (!m_sneak_offset && control.sneak) {
eye_offset_first.Y -= 3.0f;
eye_offset_third.Y -= 3.0f;
m_sneak_offset = true;
} else if (m_sneak_offset && !control.sneak) {
eye_offset_first.Y += 3.0f;
eye_offset_third.Y += 3.0f;
m_sneak_offset = false;
}
}
// Acceleration increase
f32 incH = 0.0f; // Horizontal (X, Z)
f32 incV = 0.0f; // Vertical (Y)
@ -646,11 +667,18 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
}
float slip_factor = 1.0f;
if (!free_move && !in_liquid && !in_liquid_stable)
float speed_factor = 1.0f;
if (!free_move && !in_liquid && !in_liquid_stable) {
slip_factor = getSlipFactor(env, speedH);
speed_factor = getSpeedFactor(env);
}
// Don't sink when swimming in pitch mode
if (pitch_move && in_liquid) {
// Apply speed factor
speedH *= speed_factor;
speedV *= speed_factor;
// Don't sink when swimming
if (in_liquid) {
v3f controlSpeed = speedH + speedV;
if (controlSpeed.getLength() > 0.01f)
swimming_pitch = true;
@ -751,6 +779,7 @@ void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
m_speed += d;
}
#if 0
// Temporary option for old move code
void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info)
@ -888,6 +917,11 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
// TODO: This shouldn't be hardcoded but decided by the server
float player_stepheight = touching_ground ? (BS * 0.6f) : (BS * 0.2f);
#ifdef HAVE_TOUCHSCREENGUI
if (TouchScreenGUI::isActive())
player_stepheight += (0.6 * BS);
#endif
v3f accel_f;
const v3f initial_position = position;
const v3f initial_speed = m_speed;
@ -953,7 +987,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
std::fabs(player_p2df.Y - node_p2df.Y));
if (distance_f > min_distance_f ||
max_axis_distance_f > 0.5f * BS + sneak_max + 0.1f * BS)
max_axis_distance_f > 0.5f * BS + sneak_max + 0.05f * BS)
continue;
// The node to be sneaked on has to be walkable
@ -1065,6 +1099,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
// Autojump
handleAutojump(dtime, env, result, initial_position, initial_speed, pos_max_d);
}
#endif
float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
{
@ -1085,12 +1120,53 @@ float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
return 1.0f;
}
float LocalPlayer::getSpeedFactor(Environment *env)
{
int speed_below = 0, speed_above = 0;
v3s16 pos = getStandingNodePos();
const NodeDefManager *nodemgr = env->getGameDef()->ndef();
Map *map = &env->getMap();
const ContentFeatures &f = nodemgr->get(map->getNode(pos));
if (f.walkable)
speed_below = itemgroup_get(f.groups, "speed");
const ContentFeatures &f2 = nodemgr->get(map->getNode(
pos + v3s16(0, 1, 0)));
speed_above = itemgroup_get(f2.groups, "speed");
if (speed_above == 0) {
const ContentFeatures &f3 = nodemgr->get(map->getNode(
pos + v3s16(0, 2, 0)));
speed_above = itemgroup_get(f3.groups, "speed");
}
int speed = speed_below + speed_above;
if (speed != 0)
return core::clamp(1.0f + f32(speed) / 100.f, 0.01f, 10.f);
return 1.0f;
}
void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
const collisionMoveResult &result, const v3f &initial_position,
const v3f &initial_speed, f32 pos_max_d)
{
#ifdef HAVE_TOUCHSCREENGUI
// Touchscreen uses player_stepheight for autojump
if (TouchScreenGUI::isActive())
return;
#endif
PlayerSettings &player_settings = getPlayerSettings();
if (!player_settings.autojump)
bool autojump_enabled = player_settings.autojump;
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
// Force autojump on gamepad
autojump_enabled |= SDLGameController::isActive();
#endif
if (!autojump_enabled)
return;
if (m_autojump)

View File

@ -163,6 +163,7 @@ private:
const f32 max_increase_V, const bool use_pitch);
bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max);
float getSlipFactor(Environment *env, const v3f &speedH);
float getSpeedFactor(Environment *env);
void handleAutojump(f32 dtime, Environment *env,
const collisionMoveResult &result,
const v3f &position_before_move, const v3f &speed_before_move,
@ -179,6 +180,7 @@ private:
// Whether a "sneak ladder" structure is detected at the players pos
// see detectSneakLadder() in the .cpp for more info (always false if disabled)
bool m_sneak_ladder_detected = false;
bool m_sneak_offset = false;
// ***** Variables for temporary option of the old move code *****
// Stores the max player uplift by m_sneak_node

View File

@ -1162,9 +1162,6 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
material.MaterialType = m_shdrsrc->getShaderInfo(
p.layer.shader_id).material;
p.layer.applyMaterialOptionsWithShaders(material);
if (p.layer.normal_texture)
material.setTexture(1, p.layer.normal_texture);
material.setTexture(2, p.layer.flags_texture);
} else {
p.layer.applyMaterialOptions(material);
}
@ -1267,12 +1264,6 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
const FrameSpec &animation_frame = (*tile.frames)[frame];
buf->getMaterial().setTexture(0, animation_frame.texture);
if (m_enable_shaders) {
if (animation_frame.normal_texture)
buf->getMaterial().setTexture(1,
animation_frame.normal_texture);
buf->getMaterial().setTexture(2, animation_frame.flags_texture);
}
}
// Day-night transition

View File

@ -193,12 +193,18 @@ Minimap::Minimap(Client *client)
// Initialize minimap modes
addMode(MINIMAP_TYPE_OFF);
#if !defined(__ANDROID__) && !defined(__IOS__)
addMode(MINIMAP_TYPE_SURFACE, 256);
addMode(MINIMAP_TYPE_SURFACE, 128);
#endif
addMode(MINIMAP_TYPE_SURFACE, 64);
#if !defined(__ANDROID__) && !defined(__IOS__)
addMode(MINIMAP_TYPE_RADAR, 512);
addMode(MINIMAP_TYPE_RADAR, 256);
addMode(MINIMAP_TYPE_RADAR, 128);
#else
addMode(MINIMAP_TYPE_RADAR, 64);
#endif
// Initialize minimap data
data = new MinimapData;
@ -356,6 +362,9 @@ void Minimap::addMode(MinimapModeDef mode)
porting::mt_snprintf(label_buf, sizeof(label_buf),
mode.label.c_str(), zoom);
mode.label = label_buf;
#if defined(__ANDROID__) || defined(__IOS__)
mode.label = mode.label.substr(0, mode.label.find(", "));
#endif
}
m_modes.push_back(mode);
@ -458,7 +467,7 @@ void Minimap::blitMinimapPixelsToImageSurface(
map_image->setPixel(x, data->mode.map_size - z - 1, tilecolor);
u32 h = mmpixel->height;
const u32 h = 255; // full bright
heightmap_image->setPixel(x,data->mode.map_size - z - 1,
video::SColor(255, h, h, h));
}
@ -518,8 +527,13 @@ video::ITexture *Minimap::getMinimapTexture()
if (minimap_mask) {
for (s16 y = 0; y < MINIMAP_MAX_SY; y++)
for (s16 x = 0; x < MINIMAP_MAX_SX; x++) {
const video::SColor &mask_col = minimap_mask->getPixel(x, y);
video::SColor mask_col = minimap_mask->getPixel(x, y);
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 9
// Irrlicht 1.9 has some problem with alpha
if (mask_col.getRed() != 255)
#else
if (!mask_col.getAlpha())
#endif
minimap_image->setPixel(x, y, video::SColor(0,0,0,0));
}
}
@ -579,10 +593,11 @@ void Minimap::drawMinimap()
// Non hud managed minimap drawing (legacy minimap)
v2u32 screensize = RenderingEngine::getWindowSize();
const u32 size = 0.25 * screensize.Y;
const u32 padding = 10 * RenderingEngine::getDisplayDensity();
drawMinimap(core::rect<s32>(
screensize.X - size - 10, 10,
screensize.X - 10, size + 10));
screensize.X - size - padding, padding,
screensize.X - padding, size + padding));
}
void Minimap::drawMinimap(core::rect<s32> rect) {
@ -611,7 +626,7 @@ void Minimap::drawMinimap(core::rect<s32> rect) {
material.setFlag(video::EMF_TRILINEAR_FILTER, true);
material.Lighting = false;
material.TextureLayer[0].Texture = minimap_texture;
material.TextureLayer[1].Texture = data->heightmap_texture;
material.TextureLayer[1].Texture = data->mode.type == MINIMAP_TYPE_RADAR ? 0 : data->heightmap_texture;
if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) {
u16 sid = m_shdrsrc->getShader("minimap_shader", TILE_MATERIAL_ALPHA);

View File

@ -76,6 +76,7 @@ Particle::Particle(
m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
m_material.setFlag(video::EMF_FOG_ENABLE, true);
m_material.setFlag(video::EMF_ZWRITE_ENABLE, false);
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
m_material.setTexture(0, texture);
m_texpos = texpos;

View File

@ -32,7 +32,7 @@ void RenderingCoreAnaglyph::setupMaterial(int color_mask)
video::SOverrideMaterial &mat = driver->getOverrideMaterial();
mat.reset();
mat.Material.ColorMask = color_mask;
mat.EnableFlags = video::EMF_COLOR_MASK;
mat.EnableFlags |= video::EMF_COLOR_MASK;
mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID |
scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT |
scene::ESNRP_SHADOW;

View File

@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include <IrrlichtDevice.h>
#include "filesys.h"
#include "fontengine.h"
#include "client.h"
#include "clouds.h"
@ -37,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "../gui/guiSkin.h"
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__) && \
!defined(SERVER) && !defined(__HAIKU__)
!defined(SERVER) && !defined(__HAIKU__) && !defined(__IOS__)
#define XORG_USED
#endif
#ifdef XORG_USED
@ -56,8 +57,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <winuser.h>
#endif
#if ENABLE_GLES
#include "filesys.h"
#ifdef __ANDROID__
#include "defaultsettings.h"
#endif
RenderingEngine *RenderingEngine::s_singleton = nullptr;
@ -91,8 +92,13 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
// Resolution selection
bool fullscreen = g_settings->getBool("fullscreen");
#if defined(__ANDROID__) || defined(__IOS__)
u16 screen_w = 0;
u16 screen_h = 0;
#else
u16 screen_w = g_settings->getU16("screen_w");
u16 screen_h = g_settings->getU16("screen_h");
#endif
// bpp, fsaa, vsync
bool vsync = g_settings->getBool("vsync");
@ -132,9 +138,6 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
params.Vsync = vsync;
params.EventReceiver = receiver;
params.HighPrecisionFPU = true;
#ifdef __ANDROID__
params.PrivateData = porting::app_global;
#endif
#if ENABLE_GLES
// there is no standardized path for these on desktop
std::string rel_path = std::string("client") + DIR_DELIM
@ -151,6 +154,13 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
gui::EGST_WINDOWS_METALLIC, driver);
m_device->getGUIEnvironment()->setSkin(skin);
skin->drop();
#ifdef __ANDROID__
// Apply settings according to screen size
// We can get real screen size only after device initialization finished
if (m_device)
set_default_settings();
#endif
}
RenderingEngine::~RenderingEngine()
@ -464,6 +474,14 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
gui::IGUIEnvironment *guienv, ITextureSource *tsrc, float dtime,
int percent, bool clouds)
{
#ifdef __IOS__
if (m_device->isWindowMinimized())
return;
#else
if (!m_device->isWindowFocused())
return;
#endif
v2u32 screensize = getWindowSize();
v2s32 textsize(g_fontengine->getTextWidth(text), g_fontengine->getLineHeight());
@ -481,31 +499,50 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
get_video_driver()->beginScene(
true, true, video::SColor(255, 140, 186, 250));
g_menucloudsmgr->drawAll();
} else
} else {
get_video_driver()->beginScene(true, true, video::SColor(255, 0, 0, 0));
video::ITexture *background_image = tsrc->getTexture("bg.png");
v2u32 screensize = driver->getScreenSize();
get_video_driver()->draw2DImage(background_image,
irr::core::rect<s32>(0, 0, screensize.X * 4, screensize.Y * 4),
irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
}
// draw progress bar
if ((percent >= 0) && (percent <= 100)) {
video::ITexture *progress_img = tsrc->getTexture("progress_bar.png");
std::string texture_path = porting::path_share + DIR_DELIM + "textures"
+ DIR_DELIM + "base" + DIR_DELIM + "pack" + DIR_DELIM;
video::ITexture *progress_img =
driver->getTexture((texture_path + "progress_bar.png").c_str());
video::ITexture *progress_img_bg =
tsrc->getTexture("progress_bar_bg.png");
driver->getTexture((texture_path + "progress_bar_bg.png").c_str());
video::ITexture *progress_img_fg =
driver->getTexture((texture_path + "progress_bar_fg.png").c_str());
if (progress_img && progress_img_bg) {
#ifndef __ANDROID__
if (progress_img && progress_img_bg && progress_img_fg) {
const core::dimension2d<u32> &img_size =
progress_img_bg->getSize();
u32 imgW = rangelim(img_size.Width, 200, 600);
u32 imgH = rangelim(img_size.Height, 24, 72);
#if !defined(__ANDROID__) && !defined(__IOS__)
float density = RenderingEngine::getDisplayDensity();
float gui_scaling = g_settings->getFloat("gui_scaling");
float scale = density * gui_scaling;
u32 imgW = rangelim(img_size.Width, 256, 1024) * scale;
u32 imgH = rangelim(img_size.Height, 32, 128) * scale;
#else
const core::dimension2d<u32> img_size(256, 48);
float imgRatio = (float)img_size.Height / img_size.Width;
u32 imgW = screensize.X / 2.2f;
u32 imgH = floor(imgW * imgRatio);
float imgRatio = (float) img_size.Height / img_size.Width;
u32 imgW = screensize.X / 2;
if (!hasNPotSupport()) {
imgW = npot2(imgW);
if (imgW > (screensize.X * 0.7) && imgW >= 1024)
imgW /= 2;
}
u32 imgH = imgW * imgRatio;
#endif
v2s32 img_pos((screensize.X - imgW) / 2,
(screensize.Y - imgH) / 2);
draw2DImageFilterScaled(get_video_driver(), progress_img_bg,
draw2DImageFilterScaled(driver, progress_img_bg,
core::rect<s32>(img_pos.X, img_pos.Y,
img_pos.X + imgW,
img_pos.Y + imgH),
@ -513,7 +550,19 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
img_size.Height),
0, 0, true);
draw2DImageFilterScaled(get_video_driver(), progress_img,
const video::SColor color(255, 255 - percent * 2, percent * 2, 25);
const video::SColor colors[] = {color, color, color, color};
draw2DImageFilterScaled(driver, progress_img_fg,
core::rect<s32>(img_pos.X, img_pos.Y,
img_pos.X + (percent * imgW) / 100,
img_pos.Y + imgH),
core::rect<s32>(0, 0,
(percent * img_size.Width) / 100,
img_size.Height),
0, colors, true);
draw2DImageFilterScaled(driver, progress_img,
core::rect<s32>(img_pos.X, img_pos.Y,
img_pos.X + (percent * imgW) / 100,
img_pos.Y + imgH),
@ -525,7 +574,7 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
}
guienv->drawAll();
get_video_driver()->endScene();
driver->endScene();
guitext->remove();
}
@ -533,7 +582,7 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
Draws the menu scene including (optional) cloud background.
*/
void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv,
float dtime, bool clouds)
ITextureSource *tsrc, float dtime, bool clouds)
{
bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
if (cloud_menu_background) {
@ -542,8 +591,15 @@ void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv,
get_video_driver()->beginScene(
true, true, video::SColor(255, 140, 186, 250));
g_menucloudsmgr->drawAll();
} else
} else {
get_video_driver()->beginScene(true, true, video::SColor(255, 0, 0, 0));
video::ITexture *background_image = tsrc->getTexture("bg.png");
v2u32 screensize = driver->getScreenSize();
get_video_driver()->draw2DImage(background_image,
irr::core::rect<s32>(0, 0, screensize.X * 4, screensize.Y * 4),
irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
}
guienv->drawAll();
get_video_driver()->endScene();
@ -598,7 +654,7 @@ const VideoDriverInfo &RenderingEngine::getVideoDriverInfo(irr::video::E_DRIVER_
return driver_info_map.at((int)type);
}
#ifndef __ANDROID__
#if !defined(__ANDROID__) && !defined(__IOS__)
#if defined(XORG_USED)
static float calcDisplayDensity(irr::video::IVideoDriver *driver)
@ -695,14 +751,30 @@ v2u32 RenderingEngine::getDisplaySize()
return deskres;
}
#else // __ANDROID__
#else // __ANDROID__/__IOS__
float RenderingEngine::getDisplayDensity()
{
return porting::getDisplayDensity();
static const float density = porting::getDisplayDensity();
return density;
}
v2u32 RenderingEngine::getDisplaySize()
{
return porting::getDisplaySize();
const RenderingEngine *engine = RenderingEngine::get_instance();
if (engine == nullptr)
return v2u32(0, 0);
return engine->getWindowSize();
}
#endif // __ANDROID__/__IOS__
bool RenderingEngine::isHighDpi()
{
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
return g_settings->getFloat("screen_dpi") / 72.0f >= 2;
#elif defined(__IOS__)
float density = RenderingEngine::getDisplayDensity();
return g_settings->getBool("device_is_tablet") ? (density >= 2) : (density >= 3);
#else
return RenderingEngine::getDisplayDensity() >= 3;
#endif
}
#endif // __ANDROID__

View File

@ -56,6 +56,7 @@ public:
static const VideoDriverInfo &getVideoDriverInfo(irr::video::E_DRIVER_TYPE type);
static float getDisplayDensity();
static v2u32 getDisplaySize();
static bool isHighDpi();
bool setupTopLevelWindow(const std::string &name);
void setupTopLevelXorgWindow(const std::string &name);
@ -106,9 +107,11 @@ public:
void draw_load_screen(const std::wstring &text,
gui::IGUIEnvironment *guienv, ITextureSource *tsrc,
float dtime = 0, int percent = 0, bool clouds = true);
float dtime = 0, int percent = 0, bool clouds = false);
void draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime, bool clouds);
void draw_menu_scene(
gui::IGUIEnvironment *guienv, ITextureSource *tsrc,
float dtime, bool clouds = false);
void draw_scene(video::SColor skycolor, bool show_hud,
bool show_minimap, bool draw_wield_tool, bool draw_crosshair);

View File

@ -40,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/tile.h"
#include "config.h"
#if ENABLE_GLES
#if ENABLE_GLES && !defined(__APPLE__)
#ifdef _IRR_COMPILE_WITH_OGLES1_
#include <GLES/gl.h>
#else
@ -49,7 +49,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#else
#ifndef __APPLE__
#include <GL/gl.h>
#else
#elif !defined(__IOS__)
#define GL_SILENCE_DEPRECATION
#include <OpenGL/gl.h>
#endif
@ -240,8 +240,6 @@ class MainShaderConstantSetter : public IShaderConstantSetter
CachedVertexShaderSetting<float, 16> m_world_view;
// Texture matrix
CachedVertexShaderSetting<float, 16> m_texture;
// Normal matrix
CachedVertexShaderSetting<float, 9> m_normal;
#endif
public:
@ -251,7 +249,6 @@ public:
#if ENABLE_GLES
, m_world_view("mWorldView")
, m_texture("mTexture")
, m_normal("mNormal")
#endif
, m_shadow_view_proj("m_ShadowViewProj")
, m_light_direction("v_LightDirection")
@ -286,16 +283,6 @@ public:
core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
core::matrix4 normal;
worldView.getTransposed(normal);
sanity_check(normal.makeInverse());
float m[9] = {
normal[0], normal[1], normal[2],
normal[4], normal[5], normal[6],
normal[8], normal[9], normal[10],
};
m_normal.set(m, services);
#endif
// Set uniforms for Shadow shader
@ -633,7 +620,6 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
uniform highp mat4 mWorldView;
uniform highp mat4 mWorldViewProj;
uniform mediump mat4 mTexture;
uniform mediump mat3 mNormal;
attribute highp vec4 inVertexPosition;
attribute lowp vec4 inVertexColor;
@ -656,7 +642,6 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
#define mWorldView gl_ModelViewMatrix
#define mWorldViewProj gl_ModelViewProjectionMatrix
#define mTexture (gl_TextureMatrix[0])
#define mNormal gl_NormalMatrix
#define inVertexPosition gl_Vertex
#define inVertexColor gl_Color
@ -668,7 +653,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
}
bool use_discard = use_gles;
#ifdef __unix__
#if defined(__unix__) && !defined(__APPLE__)
// For renderers that should use discard instead of GL_ALPHA_TEST
const char* gl_renderer = (const char*)glGetString(GL_RENDERER);
if (strstr(gl_renderer, "GC7000"))

View File

@ -237,7 +237,7 @@ void Sky::render()
}
// Draw far cloudy fog thing blended with skycolor
if (m_visible) {
/*if (m_visible) {
driver->setMaterial(m_materials[1]);
for (u32 j = 0; j < 4; j++) {
vertices[0] = video::S3DVertex(-1, -0.02, -1, 0, 0, 1, m_bgcolor, t, t);
@ -260,7 +260,7 @@ void Sky::render()
}
driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
}
}*/
// Draw stars before sun and moon to be behind them
if (m_star_params.visible)
@ -813,7 +813,7 @@ void Sky::updateStars()
video::SColor fallback_color = m_star_params.starcolor; // used on GLES 2 “without shaders”
PcgRandom rgen(m_seed);
float d = (0.006 / 2) * m_star_params.scale;
float d = (0.003 / 2) * m_star_params.scale;
for (u16 i = 0; i < m_star_params.count; i++) {
v3f r = v3f(
rgen.range(-10000, 10000),

View File

@ -50,7 +50,7 @@ with this program; ifnot, write to the Free Software Foundation, Inc.,
#define BUFFER_SIZE 30000
std::shared_ptr<SoundManagerSingleton> g_sound_manager_singleton;
SoundManagerSingleton* g_sound_manager_singleton = nullptr;
typedef std::unique_ptr<ALCdevice, void (*)(ALCdevice *p)> unique_ptr_alcdevice;
typedef std::unique_ptr<ALCcontext, void(*)(ALCcontext *p)> unique_ptr_alccontext;
@ -707,15 +707,22 @@ public:
}
};
std::shared_ptr<SoundManagerSingleton> createSoundManagerSingleton()
SoundManagerSingleton* createSoundManagerSingleton()
{
auto smg = std::make_shared<SoundManagerSingleton>();
auto smg = new SoundManagerSingleton();
if (!smg->init()) {
smg.reset();
delete smg;
smg = nullptr;
}
return smg;
}
void deleteSoundManagerSingleton(SoundManagerSingleton* smg)
{
delete smg;
smg = nullptr;
}
ISoundManager *createOpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher)
{
return new OpenALSoundManager(smg, fetcher);

View File

@ -24,8 +24,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sound.h"
class SoundManagerSingleton;
extern std::shared_ptr<SoundManagerSingleton> g_sound_manager_singleton;
extern SoundManagerSingleton* g_sound_manager_singleton;
std::shared_ptr<SoundManagerSingleton> createSoundManagerSingleton();
SoundManagerSingleton* createSoundManagerSingleton();
void deleteSoundManagerSingleton(SoundManagerSingleton* smg);
ISoundManager *createOpenALSoundManager(
SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher);

View File

@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
A cache from texture name to texture path
*/
MutexedMap<std::string, std::string> g_texturename_to_path_cache;
bool g_disable_texture_packs = false;
/*
Replaces the filename extension.
@ -1023,14 +1024,9 @@ video::IImage *Align2Npot2(video::IImage *image,
unsigned int height = npot2(dim.Height);
unsigned int width = npot2(dim.Width);
if (dim.Height == height && dim.Width == width)
if (dim.Width == width)
return image;
if (dim.Height > height)
height *= 2;
if (dim.Width > width)
width *= 2;
video::IImage *targetimage =
driver->createImage(video::ECF_A8R8G8B8,
core::dimension2d<u32>(width, height));
@ -1040,7 +1036,15 @@ video::IImage *Align2Npot2(video::IImage *image,
image->drop();
return targetimage;
}
#else
bool hasNPotSupport()
{
#ifdef __IOS__
return true; // Irrlicht cares about it on iOS
#endif
static const std::string &driverstring = g_settings->get("video_driver");
return (driverstring != "ogles1"); // gles3 has NPot Support and used instead of gles2
}
#endif
static std::string unescape_string(const std::string &str, const char esc = '\\')
@ -1215,8 +1219,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
It is an image with a number of cracking stages
horizontally tiled.
*/
#ifndef HAVE_TOUCHSCREENGUI
video::IImage *img_crack = m_sourcecache.getOrLoad(
"crack_anylength.png");
#else
video::IImage *img_crack = m_sourcecache.getOrLoad(
"crack_anylength_touch.png");
#endif
if (img_crack) {
draw_crack(img_crack, baseimg,
@ -2332,5 +2341,13 @@ video::ITexture *TextureSource::getShaderFlagsTexture(bool normalmap_present)
std::vector<std::string> getTextureDirs()
{
if (g_disable_texture_packs)
return {};
return fs::GetRecursiveDirs(g_settings->get("texture_path"));
}
void setDisableTexturePacks(const bool disable_texture_packs)
{
g_disable_texture_packs = disable_texture_packs;
}

View File

@ -175,8 +175,6 @@ struct FrameSpec
u32 texture_id = 0;
video::ITexture *texture = nullptr;
video::ITexture *normal_texture = nullptr;
video::ITexture *flags_texture = nullptr;
};
#define MAX_TILE_LAYERS 2
@ -262,11 +260,8 @@ struct TileLayer
// Ordered for size, please do not reorder
video::ITexture *texture = nullptr;
video::ITexture *normal_texture = nullptr;
video::ITexture *flags_texture = nullptr;
u32 shader_id = 0;
u32 texture_id = 0;
u16 animation_frame_length_ms = 0;
@ -326,3 +321,5 @@ struct TileSpec
};
std::vector<std::string> getTextureDirs();
void setDisableTexturePacks(const bool disable_texture_packs);

View File

@ -41,6 +41,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MIN_EXTRUSION_MESH_RESOLUTION 16
#define MAX_EXTRUSION_MESH_RESOLUTION 512
/*!
* Applies overlays, textures and materials to the given mesh and
* extracts tile colors for colorization.
* \param colors returns the colors of the mesh buffers in the mesh.
*/
static void postProcessCubeMesh(scene::SMesh *mesh, const ContentFeatures &f,
IShaderSource *shader_source, std::string const &shader_name,
std::vector<ItemPartColor> *colors);
static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y)
{
const f32 r = 0.5;
@ -237,18 +247,6 @@ WieldMeshSceneNode::~WieldMeshSceneNode()
g_extrusion_mesh_cache = nullptr;
}
void WieldMeshSceneNode::setCube(const ContentFeatures &f,
v3f wield_scale)
{
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
scene::SMesh *copy = cloneMesh(cubemesh);
cubemesh->drop();
postProcessNodeMesh(copy, f, false, true, &m_material_type, &m_colors, true);
changeToMesh(copy);
copy->drop();
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
}
void WieldMeshSceneNode::setExtruded(const std::string &imagename,
const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc,
u8 num_frames)
@ -310,7 +308,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
}
static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
std::vector<ItemPartColor> *colors, const ContentFeatures &f)
std::vector<ItemPartColor> *colors, const ContentFeatures &f, std::string const shader_name = {})
{
MeshMakeData mesh_make_data(client, false);
MeshCollector collector;
@ -333,6 +331,7 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
}
gen.renderSingle(n.getContent(), n.getParam2());
IShaderSource *shader_source = shader_name.empty() ? nullptr : client->getShaderSource();
colors->clear();
scene::SMesh *mesh = new scene::SMesh();
for (auto &prebuffers : collector.prebuffers)
@ -340,14 +339,20 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
const FrameSpec &frame = (*p.layer.frames)[0];
p.layer.texture = frame.texture;
p.layer.normal_texture = frame.normal_texture;
}
for (video::S3DVertex &v : p.vertices) {
v.Color.setAlpha(255);
}
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
buf->Material.setTexture(0, p.layer.texture);
p.layer.applyMaterialOptions(buf->Material);
if (!shader_name.empty()) {
auto shader_id = shader_source->getShader(shader_name, (MaterialType)p.layer.material_type, f.drawtype);
buf->Material.MaterialType = shader_source->getShaderInfo(shader_id).material;
p.layer.applyMaterialOptionsWithShaders(buf->Material);
} else {
p.layer.applyMaterialOptions(buf->Material);
}
buf->Material.MaterialTypeParam = 0.0f;
mesh->addMeshBuffer(buf);
buf->append(&p.vertices[0], p.vertices.size(),
&p.indices[0], p.indices.size());
@ -430,15 +435,22 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
}
case NDT_NORMAL:
case NDT_ALLFACES:
case NDT_LIQUID:
setCube(f, def.wield_scale);
break;
case NDT_LIQUID: {
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
scene::SMesh *copy = cloneMesh(cubemesh);
cubemesh->drop();
postProcessCubeMesh(copy, f, shdrsrc, "object_shader", &m_colors);
changeToMesh(copy);
copy->drop();
m_meshnode->setScale(def.wield_scale * WIELD_SCALE_FACTOR);
break;
}
default: {
// Render non-trivial drawtypes like the actual node
MapNode n(id);
n.setParam2(def.place_param2);
mesh = createSpecialNodeMesh(client, n, &m_colors, f);
mesh = createSpecialNodeMesh(client, id, &m_colors, f, "object_shader");
changeToMesh(mesh);
mesh->drop();
m_meshnode->setScale(
@ -451,8 +463,6 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
u32 material_count = m_meshnode->getMaterialCount();
for (u32 i = 0; i < material_count; ++i) {
video::SMaterial &material = m_meshnode->getMaterial(i);
material.MaterialType = m_material_type;
material.MaterialTypeParam = 0.5f;
material.setFlag(video::EMF_BACK_FACE_CULLING, cull_backface);
material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
@ -546,6 +556,7 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
m_shadow->addNodeToShadowList(m_meshnode);
}
// Only used for inventory images
void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
{
ITextureSource *tsrc = client->getTextureSource();
@ -593,8 +604,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
} else
scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
// add overlays
postProcessNodeMesh(mesh, f, false, false, nullptr,
&result->buffer_colors, true);
postProcessCubeMesh(mesh, f, nullptr, {}, &result->buffer_colors);
if (f.drawtype == NDT_ALLFACES)
scaleMesh(mesh, v3f(f.visual_scale));
break;
@ -692,9 +702,9 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
return mesh;
}
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
bool use_shaders, bool set_material, const video::E_MATERIAL_TYPE *mattype,
std::vector<ItemPartColor> *colors, bool apply_scale)
static void postProcessCubeMesh(scene::SMesh *mesh, const ContentFeatures &f,
IShaderSource *shader_source, std::string const &shader_name,
std::vector<ItemPartColor> *colors)
{
u32 mc = mesh->getMeshBufferCount();
// Allocate colors for existing buffers
@ -721,28 +731,21 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
(*colors)[i] = ItemPartColor(layer->has_color, layer->color);
}
video::SMaterial &material = buf->getMaterial();
if (set_material)
if (shader_source && !shader_name.empty()) {
auto shader_id = shader_source->getShader(shader_name, (MaterialType)layer->material_type, NDT_ALLFACES);
material.MaterialType = shader_source->getShaderInfo(shader_id).material;
layer->applyMaterialOptionsWithShaders(material);
} else {
layer->applyMaterialOptions(material);
if (mattype) {
material.MaterialType = *mattype;
}
material.MaterialTypeParam = 0.0f;
if (layer->animation_frame_count > 1) {
const FrameSpec &animation_frame = (*layer->frames)[0];
material.setTexture(0, animation_frame.texture);
} else {
material.setTexture(0, layer->texture);
}
if (use_shaders) {
if (layer->normal_texture) {
if (layer->animation_frame_count > 1) {
const FrameSpec &animation_frame = (*layer->frames)[0];
material.setTexture(1, animation_frame.normal_texture);
} else
material.setTexture(1, layer->normal_texture);
}
material.setTexture(2, layer->flags_texture);
}
if (apply_scale && tile->world_aligned) {
if (tile->world_aligned) {
u32 n = buf->getVertexCount();
for (u32 k = 0; k != n; ++k)
buf->getTCoords(k) /= layer->scale;

View File

@ -133,14 +133,3 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename,
const std::string &overlay_name);
/*!
* Applies overlays, textures and optionally materials to the given mesh and
* extracts tile colors for colorization.
* \param mattype overrides the buffer's material type, but can also
* be NULL to leave the original material.
* \param colors returns the colors of the mesh buffers in the mesh.
*/
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, bool use_shaders,
bool set_material, const video::E_MATERIAL_TYPE *mattype,
std::vector<ItemPartColor> *colors, bool apply_scale = false);

View File

@ -472,20 +472,14 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
{
case CSE_AuthAccept:
m_state = CS_AwaitingInit2;
if (chosen_mech == AUTH_MECHANISM_SRP ||
chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
srp_verifier_delete((SRPVerifier *) auth_data);
chosen_mech = AUTH_MECHANISM_NONE;
resetChosenMech();
break;
case CSE_Disconnect:
m_state = CS_Disconnecting;
break;
case CSE_SetDenied:
m_state = CS_Denied;
if (chosen_mech == AUTH_MECHANISM_SRP ||
chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
srp_verifier_delete((SRPVerifier *) auth_data);
chosen_mech = AUTH_MECHANISM_NONE;
resetChosenMech();
break;
default:
myerror << "HelloSent: Invalid client state transition! " << event;
@ -561,9 +555,7 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
break;
case CSE_SudoSuccess:
m_state = CS_SudoMode;
if (chosen_mech == AUTH_MECHANISM_SRP)
srp_verifier_delete((SRPVerifier *) auth_data);
chosen_mech = AUTH_MECHANISM_NONE;
resetChosenMech();
break;
/* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
default:
@ -596,6 +588,15 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
}
}
void RemoteClient::resetChosenMech()
{
if (auth_data) {
srp_verifier_delete((SRPVerifier *) auth_data);
auth_data = nullptr;
}
chosen_mech = AUTH_MECHANISM_NONE;
}
u64 RemoteClient::uptime() const
{
return porting::getTimeS() - m_connection_time;
@ -714,6 +715,59 @@ void ClientInterface::sendToAll(NetworkPacket *pkt)
}
}
void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt,
u16 min_proto_ver)
{
RecursiveMutexAutoLock clientslock(m_clients_mutex);
for (auto &client_it : m_clients) {
RemoteClient *client = client_it.second;
NetworkPacket *pkt_to_send = nullptr;
if (client->net_proto_version >= min_proto_ver) {
pkt_to_send = pkt;
} else if (client->net_proto_version != 0) {
pkt_to_send = legacypkt;
} else {
// This will happen if a client is connecting when sendToAllCompat
// is called, this can safely be ignored.
continue;
}
m_con->Send(client->peer_id,
clientCommandFactoryTable[pkt_to_send->getCommand()].channel,
pkt_to_send,
clientCommandFactoryTable[pkt_to_send->getCommand()].reliable);
}
}
void ClientInterface::oldSendToAll(NetworkPacket *pkt)
{
RecursiveMutexAutoLock clientslock(m_clients_mutex);
for (auto &client_it : m_clients) {
RemoteClient *client = client_it.second;
if (client->net_proto_version != 0 && client->net_proto_version < 37) {
m_con->Send(client->peer_id,
clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
clientCommandFactoryTable[pkt->getCommand()].reliable);
}
}
}
void ClientInterface::newSendToAll(NetworkPacket *pkt)
{
RecursiveMutexAutoLock clientslock(m_clients_mutex);
for (auto &client_it : m_clients) {
RemoteClient *client = client_it.second;
if (client->net_proto_version > 36) {
m_con->Send(client->peer_id,
clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
clientCommandFactoryTable[pkt->getCommand()].reliable);
}
}
}
RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
{
RecursiveMutexAutoLock clientslock(m_clients_mutex);

View File

@ -242,6 +242,8 @@ public:
u32 allowed_auth_mechs = 0;
u32 allowed_sudo_mechs = 0;
void resetChosenMech();
bool isSudoMechAllowed(AuthMechanism mech)
{ return allowed_sudo_mechs & mech; }
bool isMechAllowed(AuthMechanism mech)
@ -332,7 +334,15 @@ public:
m_version_major = major;
m_version_minor = minor;
m_version_patch = patch;
m_full_version = full;
m_full_version = full.c_str();
const size_t pos = full.find('\x00');
if (pos != std::string::npos) {
m_platform = full.substr(pos + 1).c_str();
const size_t pos2 = full.find('\x00', pos + 1);
if (pos2 != std::string::npos)
m_sysinfo = full.substr(pos2 + 1);
}
}
/* read version information */
@ -340,6 +350,9 @@ public:
u8 getMinor() const { return m_version_minor; }
u8 getPatch() const { return m_version_patch; }
const std::string &getFullVer() const { return m_full_version; }
const std::string &getPlatform() const { return m_platform; }
const std::string &getSysInfo() const { return m_sysinfo; }
void setLangCode(const std::string &code) { m_lang_code = code; }
const std::string &getLangCode() const { return m_lang_code; }
@ -426,6 +439,8 @@ private:
u8 m_version_patch = 0;
std::string m_full_version = "unknown";
std::string m_platform = "unknown";
std::string m_sysinfo = "unknown";
u16 m_deployed_compression = 0;
@ -465,6 +480,9 @@ public:
/* send to all clients */
void sendToAll(NetworkPacket *pkt);
void sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt, u16 min_proto_ver);
void oldSendToAll(NetworkPacket *pkt);
void newSendToAll(NetworkPacket *pkt);
/* delete a client */
void DeleteClient(session_t peer_id);

View File

@ -15,11 +15,14 @@
#define BUILD_TYPE "@CMAKE_BUILD_TYPE@"
#define ICON_DIR "@ICONDIR@"
#cmakedefine01 RUN_IN_PLACE
#cmakedefine01 DEVELOPMENT_BUILD
#cmakedefine01 ENABLE_UPDATE_CHECKER
#cmakedefine01 USE_GETTEXT
#cmakedefine01 USE_CURL
#cmakedefine01 USE_SOUND
#cmakedefine01 USE_CURSES
#cmakedefine01 USE_LEVELDB
#cmakedefine01 USE_SQLITE
#cmakedefine01 USE_LUAJIT
#cmakedefine01 USE_POSTGRESQL
#cmakedefine01 USE_PROMETHEUS

View File

@ -11,10 +11,11 @@
#if defined USE_CMAKE_CONFIG_H
#include "cmake_config.h"
#elif defined (__ANDROID__)
#define PROJECT_NAME "minetest"
#define PROJECT_NAME_C "Minetest"
#elif defined(__ANDROID__) || defined(__APPLE__)
#define PROJECT_NAME "multicraft"
#define PROJECT_NAME_C "MultiCraft"
#define STATIC_SHAREDIR ""
#define ENABLE_UPDATE_CHECKER 1
#define VERSION_STRING STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_PATCH) STR(VERSION_EXTRA)
#ifdef NDEBUG
#define BUILD_TYPE "Release"

View File

@ -110,4 +110,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
GUI related things
*/
#define TTF_DEFAULT_FONT_SIZE (16)
#if defined(__ANDROID__) || defined(__IOS__)
#define TTF_DEFAULT_FONT_SIZE (13)
#else
#define TTF_DEFAULT_FONT_SIZE (18)
#endif

69
src/content/packages.cpp Normal file
View File

@ -0,0 +1,69 @@
/*
Minetest
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 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content/packages.h"
#include "log.h"
#include "filesys.h"
#include "porting.h"
#include "settings.h"
#include "content/mods.h"
#include "content/subgames.h"
std::string Package::getDownloadURL(const std::string &baseURL) const
{
return baseURL + "/packages/" + author + "/" + name + "/releases/" +
std::to_string(release) + "/download/";
}
#if USE_CURL
std::vector<Package> getPackagesFromURL(const std::string &url)
{
std::vector<std::string> extra_headers;
extra_headers.emplace_back("Accept: application/json");
Json::Value json = fetchJsonValue(url, &extra_headers);
if (!json.isArray()) {
errorstream << "Invalid JSON download " << std::endl;
return std::vector<Package>();
}
std::vector<Package> packages;
// Note: `unsigned int` is required to index JSON
for (unsigned int i = 0; i < json.size(); ++i) {
Package package;
package.author = json[i]["author"].asString();
package.name = json[i]["name"].asString();
package.title = json[i]["title"].asString();
package.type = json[i]["type"].asString();
package.shortDesc = json[i]["shortDesc"].asString();
package.release = json[i]["release"].asInt();
if (json[i].isMember("thumbnail"))
package.thumbnail = json[i]["thumbnail"].asString();
if (package.valid())
packages.push_back(package);
else
errorstream << "Invalid package at " << i << std::endl;
}
return packages;
}
#endif

52
src/content/packages.h Normal file
View File

@ -0,0 +1,52 @@
/*
Minetest
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 3.0 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.
*/
#pragma once
#include "config.h"
#include "convert_json.h"
#include "irrlichttypes.h"
struct Package
{
std::string author;
std::string name; // Technical name
std::string title;
std::string type; // One of "mod", "game", or "txp"
std::string shortDesc;
u32 release;
std::string thumbnail;
bool valid() const
{
return !(author.empty() || name.empty() || title.empty() ||
type.empty() || release <= 0);
}
std::string getDownloadURL(const std::string &baseURL) const;
};
#if USE_CURL
std::vector<Package> getPackagesFromURL(const std::string &url);
#else
inline std::vector<Package> getPackagesFromURL(const std::string &url)
{
return std::vector<Package>();
}
#endif

View File

@ -37,9 +37,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
namespace
{
bool getGameMinetestConfig(const std::string &game_path, Settings &conf)
bool getGameMinetestConfig(
const std::string &game_path, Settings &conf, const std::string &file)
{
std::string conf_path = game_path + DIR_DELIM + "minetest.conf";
std::string conf_path = game_path + DIR_DELIM + file;
return conf.readConfigFile(conf_path.c_str());
}
@ -136,13 +137,17 @@ SubgameSpec findSubgame(const std::string &id)
if (conf.exists("release"))
game_release = conf.getS32("release");
bool moddable = true;
if (conf.exists("moddable"))
moddable = conf.getBool("moddable");
std::string menuicon_path;
#ifndef SERVER
menuicon_path = getImagePath(
game_path + DIR_DELIM + "menu" + DIR_DELIM + "icon.png");
#endif
return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name,
menuicon_path, game_author, game_release);
menuicon_path, game_author, game_release, moddable);
}
SubgameSpec findWorldSubgame(const std::string &world_path)
@ -341,7 +346,8 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
game_settings = Settings::createLayer(SL_GAME);
}
getGameMinetestConfig(gamespec.path, *game_settings);
getGameMinetestConfig(gamespec.path, *game_settings, "minetest.conf");
getGameMinetestConfig(gamespec.path, *game_settings, "multicraft.conf");
game_settings->removeSecureSettings();
infostream << "Initializing world at " << final_path << std::endl;
@ -355,10 +361,17 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
conf.set("world_name", name);
conf.set("gameid", gamespec.id);
#if !defined(__ANDROID__) && !defined(__APPLE__)
conf.set("backend", "sqlite3");
conf.set("player_backend", "sqlite3");
conf.set("auth_backend", "sqlite3");
conf.set("mod_storage_backend", "sqlite3");
#else
conf.set("backend", "leveldb");
conf.set("player_backend", "leveldb");
conf.set("auth_backend", "leveldb");
conf.set("mod_storage_backend", "leveldb");
#endif
conf.setBool("creative_mode", g_settings->getBool("creative_mode"));
conf.setBool("enable_damage", g_settings->getBool("enable_damage"));

View File

@ -35,6 +35,7 @@ struct SubgameSpec
std::string gamemods_path;
std::set<std::string> addon_mods_paths;
std::string menuicon_path;
bool moddable;
SubgameSpec(const std::string &id = "", const std::string &path = "",
const std::string &gamemods_path = "",
@ -42,11 +43,12 @@ struct SubgameSpec
std::set<std::string>(),
const std::string &name = "",
const std::string &menuicon_path = "",
const std::string &author = "", int release = 0) :
const std::string &author = "", int release = 0,
const bool moddable = true) :
id(id),
name(name), author(author), release(release), path(path),
gamemods_path(gamemods_path), addon_mods_paths(addon_mods_paths),
menuicon_path(menuicon_path)
menuicon_path(menuicon_path), moddable(moddable)
{
}

View File

@ -56,7 +56,14 @@ void sanity_check_fn(const char *assertion, const char *file,
errorstream << file << ":" << line << ": " << function
<< ": An engine assumption '" << assertion << "' failed." << std::endl;
#if defined(__ANDROID__) || defined(__IOS__)
std::string capture = "An engine assumption failed: \"" + std::string(assertion) +
"\" in file: " + std::string(file) + ":" + std::to_string(line) +
" (" + std::string(function) + ")";
porting::finishGame(capture);
#else
abort();
#endif
}
void fatal_error_fn(const char *msg, const char *file,
@ -71,7 +78,14 @@ void fatal_error_fn(const char *msg, const char *file,
errorstream << file << ":" << line << ": " << function
<< ": A fatal error occurred: " << msg << std::endl;
#if defined(__ANDROID__) || defined(__IOS__)
std::string capture = "A fatal error occurred: \"" + std::string(msg) +
"\" in file: " + std::string(file) + ":" + std::to_string(line) +
" (" + std::string(function) + ")";
porting::finishGame(capture);
#else
abort();
#endif
}
#ifdef _MSC_VER

View File

@ -23,24 +23,37 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include "config.h"
#include "constants.h"
#include "porting.h"
#include "mapgen/mapgen.h" // Mapgen::setDefaultSettings
#include "util/string.h"
#ifdef __ANDROID__
#include "client/renderingengine.h"
#endif
#ifdef __APPLE__
#ifdef __IOS__
#import "SDVersion.h"
#else
#import <AppKit/AppKit.h>
#endif
#endif
void set_default_settings()
{
Settings *settings = Settings::createLayer(SL_DEFAULTS);
Settings *settings = Settings::getLayer(SL_DEFAULTS);
if (settings == nullptr)
settings = Settings::createLayer(SL_DEFAULTS);
// Client and server
settings->setDefault("language", "");
settings->setDefault("name", "");
settings->setDefault("bind_address", "");
settings->setDefault("serverlist_url", "servers.minetest.net");
settings->setDefault("serverlist_url", "servers.multicraft.world");
// Client
settings->setDefault("address", "");
settings->setDefault("enable_sound", "true");
settings->setDefault("sound_volume", "0.8");
settings->setDefault("sound_volume", "1.0");
settings->setDefault("mute_sound", "false");
settings->setDefault("enable_mesh_cache", "false");
settings->setDefault("mesh_generation_interval", "0");
@ -61,9 +74,9 @@ void set_default_settings()
settings->setDefault("curl_file_download_timeout", "300000");
settings->setDefault("curl_verify_cert", "true");
settings->setDefault("enable_remote_media_server", "true");
settings->setDefault("enable_client_modding", "false");
settings->setDefault("enable_client_modding", "true");
settings->setDefault("max_out_chat_queue_size", "20");
settings->setDefault("pause_on_lost_focus", "false");
settings->setDefault("pause_on_lost_focus", "true");
settings->setDefault("enable_register_confirmation", "true");
settings->setDefault("clickable_chat_weblinks", "false");
settings->setDefault("chat_weblink_color", "#8888FF");
@ -176,7 +189,7 @@ void set_default_settings()
settings->setDefault("near_plane", "0.1");
#endif
settings->setDefault("screen_w", "1024");
settings->setDefault("screen_h", "600");
settings->setDefault("screen_h", "768");
settings->setDefault("autosave_screensize", "true");
settings->setDefault("fullscreen", "false");
settings->setDefault("vsync", "false");
@ -207,12 +220,13 @@ void set_default_settings()
settings->setDefault("cinematic_camera_smoothing", "0.7");
settings->setDefault("enable_clouds", "true");
settings->setDefault("view_bobbing_amount", "1.0");
settings->setDefault("fall_bobbing_amount", "0.03");
settings->setDefault("fall_bobbing_amount", "1.0");
settings->setDefault("enable_3d_clouds", "true");
settings->setDefault("cloud_radius", "12");
settings->setDefault("menu_clouds", "true");
settings->setDefault("opaque_water", "false");
settings->setDefault("console_height", "0.6");
settings->setDefault("console_message_height", "0.25");
settings->setDefault("console_color", "(0,0,0)");
settings->setDefault("console_alpha", "200");
settings->setDefault("formspec_fullscreen_bg_color", "(0,0,0)");
@ -220,21 +234,24 @@ void set_default_settings()
settings->setDefault("formspec_default_bg_color", "(0,0,0)");
settings->setDefault("formspec_default_bg_opacity", "140");
settings->setDefault("selectionbox_color", "(0,0,0)");
settings->setDefault("selectionbox_width", "2");
settings->setDefault("selectionbox_width", "4");
settings->setDefault("node_highlighting", "box");
settings->setDefault("crosshair_color", "(255,255,255)");
settings->setDefault("crosshair_alpha", "255");
settings->setDefault("recent_chat_messages", "6");
settings->setDefault("recent_chat_messages", "10");
settings->setDefault("hud_scaling", "1.0");
settings->setDefault("gui_scaling", "1.0");
settings->setDefault("gui_scaling_filter", "false");
settings->setDefault("gui_scaling_filter_txr2img", "true");
settings->setDefault("desynchronize_mapblock_texture_animation", "true");
settings->setDefault("hud_hotbar_max_width", "1.0");
settings->setDefault("hud_move_upwards", "0");
settings->setDefault("round_screen", "0");
settings->setDefault("enable_local_map_saving", "false");
settings->setDefault("show_entity_selectionbox", "false");
settings->setDefault("transparency_sorting", "true");
settings->setDefault("texture_clean_transparent", "false");
settings->setDefault("texture_min_size", "64");
settings->setDefault("texture_min_size", "0");
settings->setDefault("ambient_occlusion_gamma", "1.8");
#if ENABLE_GLES
settings->setDefault("enable_shaders", "false");
@ -243,11 +260,11 @@ void set_default_settings()
#endif
settings->setDefault("enable_particles", "true");
settings->setDefault("arm_inertia", "true");
settings->setDefault("show_nametag_backgrounds", "true");
settings->setDefault("show_nametag_backgrounds", "false");
settings->setDefault("enable_minimap", "true");
settings->setDefault("minimap_shape_round", "true");
settings->setDefault("minimap_double_scan_height", "true");
settings->setDefault("minimap_double_scan_height", "false");
// Effects
settings->setDefault("directional_colored_fog", "true");
@ -286,39 +303,53 @@ void set_default_settings()
settings->setDefault("aux1_descends", "false");
settings->setDefault("doubletap_jump", "false");
settings->setDefault("always_fly_fast", "true");
#ifdef HAVE_TOUCHSCREENGUI
settings->setDefault("autojump", "true");
#else
settings->setDefault("autojump", "false");
#endif
settings->setDefault("continuous_forward", "false");
settings->setDefault("enable_joysticks", "false");
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
settings->setDefault("enable_joysticks", "true");
#else
settings->setDefault("enable_joysticks", "false");
#endif
settings->setDefault("joystick_id", "0");
settings->setDefault("joystick_type", "");
settings->setDefault("repeat_joystick_button_time", "0.17");
settings->setDefault("joystick_frustum_sensitivity", "170");
settings->setDefault("joystick_deadzone", "2048");
settings->setDefault("joystick_deadzone", "4096");
// Main menu
settings->setDefault("main_menu_path", "");
settings->setDefault("serverlist_file", "favoriteservers.json");
// General font settings
std::string MultiCraftFont = porting::getDataPath("fonts" DIR_DELIM "MultiCraftFont.ttf");
#if !defined(__ANDROID__) && !defined(__APPLE__)
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "Arimo-Regular.ttf"));
settings->setDefault("font_path_italic", porting::getDataPath("fonts" DIR_DELIM "Arimo-Italic.ttf"));
settings->setDefault("font_path_bold", porting::getDataPath("fonts" DIR_DELIM "Arimo-Bold.ttf"));
settings->setDefault("font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Arimo-BoldItalic.ttf"));
#else
settings->setDefault("font_path", MultiCraftFont);
settings->setDefault("font_path_italic", MultiCraftFont);
settings->setDefault("font_path_bold", MultiCraftFont);
settings->setDefault("font_path_bold_italic", MultiCraftFont);
#endif
settings->setDefault("font_bold", "false");
settings->setDefault("font_italic", "false");
settings->setDefault("font_shadow", "1");
settings->setDefault("font_shadow_alpha", "127");
settings->setDefault("font_size_divisible_by", "1");
settings->setDefault("mono_font_path", porting::getDataPath("fonts" DIR_DELIM "Cousine-Regular.ttf"));
settings->setDefault("mono_font_path_italic", porting::getDataPath("fonts" DIR_DELIM "Cousine-Italic.ttf"));
settings->setDefault("mono_font_path_bold", porting::getDataPath("fonts" DIR_DELIM "Cousine-Bold.ttf"));
settings->setDefault("mono_font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Cousine-BoldItalic.ttf"));
settings->setDefault("mono_font_path", MultiCraftFont);
settings->setDefault("mono_font_path_italic", MultiCraftFont);
settings->setDefault("mono_font_path_bold", MultiCraftFont);
settings->setDefault("mono_font_path_bold_italic", MultiCraftFont);
settings->setDefault("mono_font_size_divisible_by", "1");
#if !defined(__ANDROID__) && !defined(__APPLE__)
settings->setDefault("fallback_font_path", porting::getDataPath("fonts" DIR_DELIM "DroidSansFallbackFull.ttf"));
#else
settings->setDefault("fallback_font_path", MultiCraftFont);
#endif
std::string font_size_str = std::to_string(TTF_DEFAULT_FONT_SIZE);
settings->setDefault("font_size", font_size_str);
@ -326,7 +357,7 @@ void set_default_settings()
settings->setDefault("chat_font_size", "0"); // Default "font_size"
// ContentDB
settings->setDefault("contentdb_url", "https://content.minetest.net");
settings->setDefault("contentdb_url", "https://content.multicraft.world");
settings->setDefault("contentdb_max_concurrent_downloads", "3");
#ifdef __ANDROID__
@ -335,10 +366,20 @@ void set_default_settings()
settings->setDefault("contentdb_flag_blacklist", "nonfree, desktop_default");
#endif
settings->setDefault("update_information_url", "https://updates.multicraft.world/app.json");
#if ENABLE_UPDATE_CHECKER
settings->setDefault("update_last_checked", "");
#else
settings->setDefault("update_last_checked", "disabled");
#endif
// Server
settings->setDefault("compat_player_model", "character.b3d,3d_armor_character.b3d,skinsdb_3d_armor_character_5.b3d");
settings->setDefault("compat_send_original_model", "true");
settings->setDefault("disable_texture_packs", "false");
settings->setDefault("disable_escape_sequences", "false");
settings->setDefault("strip_color_codes", "false");
settings->setDefault("strip_color_codes", "true");
settings->setDefault("announce_mt", "true");
#if USE_PROMETHEUS
settings->setDefault("prometheus_listener_address", "127.0.0.1:30000");
#endif
@ -347,13 +388,14 @@ void set_default_settings()
settings->setDefault("enable_ipv6", "true");
settings->setDefault("ipv6_server", "false");
settings->setDefault("max_packets_per_iteration","1024");
settings->setDefault("port", "30000");
settings->setDefault("port", "40000");
settings->setDefault("enable_protocol_compat", "true");
settings->setDefault("strict_protocol_version_checking", "false");
settings->setDefault("player_transfer_distance", "0");
settings->setDefault("max_simultaneous_block_sends_per_client", "40");
settings->setDefault("time_send_interval", "5");
settings->setDefault("default_game", "minetest");
settings->setDefault("default_game", "default");
settings->setDefault("motd", "");
settings->setDefault("max_users", "15");
settings->setDefault("creative_mode", "false");
@ -361,7 +403,7 @@ void set_default_settings()
settings->setDefault("default_password", "");
settings->setDefault("default_privs", "interact, shout");
settings->setDefault("enable_pvp", "true");
settings->setDefault("enable_mod_channels", "false");
settings->setDefault("enable_mod_channels", "true");
settings->setDefault("disallow_empty_password", "false");
settings->setDefault("disable_anticheat", "false");
settings->setDefault("enable_rollback_recording", "false");
@ -371,7 +413,7 @@ void set_default_settings()
settings->setDefault("kick_msg_crash", "This server has experienced an internal error. You will now be disconnected.");
settings->setDefault("ask_reconnect_on_crash", "false");
settings->setDefault("chat_message_format", "<@name> @message");
settings->setDefault("chat_message_format", "@name: @message");
settings->setDefault("profiler_print_interval", "0");
settings->setDefault("active_object_send_range_blocks", "8");
settings->setDefault("active_block_range", "4");
@ -380,7 +422,7 @@ void set_default_settings()
settings->setDefault("max_block_send_distance", "12");
settings->setDefault("block_send_optimize_distance", "4");
settings->setDefault("server_side_occlusion_culling", "true");
settings->setDefault("csm_restriction_flags", "62");
settings->setDefault("csm_restriction_flags", "60");
settings->setDefault("csm_restriction_noderange", "0");
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
settings->setDefault("time_speed", "72");
@ -389,7 +431,7 @@ void set_default_settings()
settings->setDefault("max_objects_per_block", "64");
settings->setDefault("server_map_save_interval", "5.3");
settings->setDefault("chat_message_max_size", "500");
settings->setDefault("chat_message_limit_per_10sec", "8.0");
settings->setDefault("chat_message_limit_per_10sec", "5.0");
settings->setDefault("chat_message_limit_trigger_kick", "50");
settings->setDefault("sqlite_synchronous", "2");
settings->setDefault("map_compression_level_disk", "-1");
@ -402,13 +444,14 @@ void set_default_settings()
settings->setDefault("nodetimer_interval", "0.2");
settings->setDefault("ignore_world_load_errors", "false");
settings->setDefault("remote_media", "");
settings->setDefault("debug_log_level", "action");
settings->setDefault("debug_log_level", "warning");
settings->setDefault("debug_log_size_max", "50");
settings->setDefault("chat_log_level", "error");
settings->setDefault("emergequeue_limit_total", "1024");
settings->setDefault("emergequeue_limit_diskonly", "128");
settings->setDefault("emergequeue_limit_generate", "128");
settings->setDefault("num_emerge_threads", "1");
settings->setDefault("log_mod_memory_usage_on_load", "false");
settings->setDefault("secure.enable_security", "true");
settings->setDefault("secure.trusted_mods", "");
settings->setDefault("secure.http_mods", "");
@ -416,7 +459,7 @@ void set_default_settings()
// Physics
settings->setDefault("movement_acceleration_default", "3");
settings->setDefault("movement_acceleration_air", "2");
settings->setDefault("movement_acceleration_fast", "10");
settings->setDefault("movement_acceleration_fast", "20");
settings->setDefault("movement_speed_walk", "4");
settings->setDefault("movement_speed_crouch", "1.35");
settings->setDefault("movement_speed_fast", "20");
@ -424,7 +467,7 @@ void set_default_settings()
settings->setDefault("movement_speed_jump", "6.5");
settings->setDefault("movement_liquid_fluidity", "1");
settings->setDefault("movement_liquid_fluidity_smooth", "0.5");
settings->setDefault("movement_liquid_sink", "10");
settings->setDefault("movement_liquid_sink", "20");
settings->setDefault("movement_gravity", "9.81");
// Liquids
@ -433,7 +476,7 @@ void set_default_settings()
settings->setDefault("liquid_update", "1.0");
// Mapgen
settings->setDefault("mg_name", "v7");
settings->setDefault("mg_name", "v7p");
settings->setDefault("water_level", "1");
settings->setDefault("mapgen_limit", "31007");
settings->setDefault("chunksize", "5");
@ -453,60 +496,249 @@ void set_default_settings()
settings->setDefault("screen_dpi", "72");
settings->setDefault("display_density_factor", "1");
settings->setDefault("device_is_tablet", "false");
// Altered settings for macOS
#if defined(__MACH__) && defined(__APPLE__)
settings->setDefault("keymap_sneak", "KEY_SHIFT");
settings->setDefault("fps_max", "0");
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
settings->setDefault("screen_w", "0");
settings->setDefault("screen_h", "0");
settings->setDefault("keymap_camera_mode", "KEY_KEY_C");
settings->setDefault("vsync", "true");
int ScaleFactor = (int) [NSScreen mainScreen].backingScaleFactor;
settings->setDefault("screen_dpi", std::to_string(ScaleFactor * 72));
if (ScaleFactor >= 2) {
settings->setDefault("hud_scaling", "1.5");
} else {
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE - 2));
settings->setDefault("hud_scaling", "1.25");
settings->setDefault("gui_scaling", "1.5");
}
// Shaders work but may reduce performance on iGPU
settings->setDefault("enable_shaders", "false");
#endif
#ifdef HAVE_TOUCHSCREENGUI
settings->setDefault("touchtarget", "true");
settings->setDefault("touchscreen_threshold","20");
settings->setDefault("fixed_virtual_joystick", "false");
settings->setDefault("touchscreen_threshold", "20");
settings->setDefault("touch_sensitivity", "0.2");
settings->setDefault("fixed_virtual_joystick", "true");
settings->setDefault("virtual_joystick_triggers_aux1", "false");
settings->setDefault("fast_move", "true");
#endif
// Altered settings for Android
#ifdef __ANDROID__
settings->setDefault("screen_w", "0");
settings->setDefault("screen_h", "0");
// Mobile Platform
#if defined(__ANDROID__) || defined(__IOS__)
settings->setDefault("fullscreen", "true");
settings->setDefault("smooth_lighting", "false");
settings->setDefault("performance_tradeoffs", "true");
settings->setDefault("max_simultaneous_block_sends_per_client", "10");
settings->setDefault("emergequeue_limit_diskonly", "16");
settings->setDefault("emergequeue_limit_generate", "16");
settings->setDefault("max_block_generate_distance", "5");
settings->setDefault("enable_3d_clouds", "false");
settings->setDefault("fps_max", "30");
settings->setDefault("fps_max_unfocused", "10");
settings->setDefault("max_objects_per_block", "20");
settings->setDefault("sqlite_synchronous", "1");
settings->setDefault("map_compression_level_disk", "-1");
settings->setDefault("map_compression_level_net", "-1");
settings->setDefault("server_map_save_interval", "15");
settings->setDefault("client_mapblock_limit", "1000");
settings->setDefault("active_block_range", "2");
settings->setDefault("viewing_range", "50");
settings->setDefault("leaves_style", "simple");
settings->setDefault("curl_verify_cert","false");
settings->setDefault("emergequeue_limit_diskonly", "16");
settings->setDefault("emergequeue_limit_generate", "16");
settings->setDefault("curl_verify_cert", "false");
settings->setDefault("max_objects_per_block", "16");
settings->setDefault("doubletap_jump", "true");
settings->setDefault("gui_scaling_filter_txr2img", "false");
settings->setDefault("autosave_screensize", "false");
settings->setDefault("recent_chat_messages", "6");
// Apply settings according to screen size
float x_inches = (float) porting::getDisplaySize().X /
(160.f * porting::getDisplayDensity());
// Set the optimal settings depending on the memory size [Android] | model [iOS]
#ifdef __ANDROID__
float memoryMax = porting::getTotalSystemMemory();
if (x_inches < 3.7f) {
settings->setDefault("hud_scaling", "0.6");
settings->setDefault("font_size", "14");
settings->setDefault("mono_font_size", "14");
} else if (x_inches < 4.5f) {
settings->setDefault("hud_scaling", "0.7");
settings->setDefault("font_size", "14");
settings->setDefault("mono_font_size", "14");
} else if (x_inches < 6.0f) {
settings->setDefault("hud_scaling", "0.85");
settings->setDefault("font_size", "14");
settings->setDefault("mono_font_size", "14");
if (memoryMax < 2) {
// minimal settings for less than 2GB RAM
#elif __IOS__
if (false) {
// obsolete
#endif
settings->setDefault("client_unload_unused_data_timeout", "60");
settings->setDefault("client_mapblock_limit", "50");
settings->setDefault("fps_max", "30");
settings->setDefault("fps_max_unfocused", "10");
settings->setDefault("viewing_range", "30");
settings->setDefault("smooth_lighting", "false");
settings->setDefault("enable_3d_clouds", "false");
settings->setDefault("active_object_send_range_blocks", "1");
settings->setDefault("active_block_range", "1");
settings->setDefault("dedicated_server_step", "0.2");
settings->setDefault("abm_interval", "3.0");
settings->setDefault("chunksize", "3");
settings->setDefault("max_block_generate_distance", "1");
settings->setDefault("arm_inertia", "false");
#ifdef __ANDROID__
} else if (memoryMax >= 2 && memoryMax < 4) {
// low settings for 2-4GB RAM
#elif __IOS__
} else if (!IOS_VERSION_AVAILABLE("13.0")) {
// low settings
#endif
settings->setDefault("client_unload_unused_data_timeout", "120");
settings->setDefault("client_mapblock_limit", "200");
settings->setDefault("fps_max", "35");
settings->setDefault("fps_max_unfocused", "10");
settings->setDefault("viewing_range", "40");
settings->setDefault("smooth_lighting", "false");
settings->setDefault("active_object_send_range_blocks", "1");
settings->setDefault("active_block_range", "2");
settings->setDefault("dedicated_server_step", "0.2");
settings->setDefault("abm_interval", "2.0");
settings->setDefault("chunksize", "3");
settings->setDefault("max_block_generate_distance", "2");
settings->setDefault("arm_inertia", "false");
#ifdef __ANDROID__
} else if (memoryMax >= 4 && memoryMax < 6) {
// medium settings for 4.1-6GB RAM
#elif __IOS__
} else if (([SDVersion deviceVersion] == iPhone6S) || ([SDVersion deviceVersion] == iPhone6SPlus) || ([SDVersion deviceVersion] == iPhoneSE) ||
([SDVersion deviceVersion] == iPhone7) || ([SDVersion deviceVersion] == iPhone7Plus) ||
([SDVersion deviceVersion] == iPadMini4) || ([SDVersion deviceVersion] == iPadAir2) || ([SDVersion deviceVersion] == iPad5))
{
// medium settings
#endif
settings->setDefault("client_unload_unused_data_timeout", "180");
settings->setDefault("client_mapblock_limit", "300");
settings->setDefault("fps_max", "35");
settings->setDefault("viewing_range", "60");
settings->setDefault("active_object_send_range_blocks", "2");
settings->setDefault("active_block_range", "2");
settings->setDefault("max_block_generate_distance", "3");
} else {
// high settings
settings->setDefault("client_mapblock_limit", "500");
settings->setDefault("viewing_range", "125");
settings->setDefault("active_object_send_range_blocks", "4");
settings->setDefault("max_block_generate_distance", "5");
// enable visual shader effects
settings->setDefault("enable_waving_water", "true");
settings->setDefault("enable_waving_leaves", "true");
settings->setDefault("enable_waving_plants", "true");
}
// Tablets >= 6.0 use non-Android defaults for these settings
// Android Settings
#ifdef __ANDROID__
// Switch to olges2 with shaders on powerful Android devices
if (memoryMax >= 6) {
settings->setDefault("video_driver", "ogles2");
settings->setDefault("enable_shaders", "true");
} else {
settings->setDefault("video_driver", "ogles1");
settings->setDefault("enable_shaders", "false");
}
v2u32 window_size = RenderingEngine::getDisplaySize();
if (window_size.X > 0) {
float x_inches = window_size.X / (160.f * RenderingEngine::getDisplayDensity());
if (x_inches <= 3.7) {
// small 4" phones
g_settings->setDefault("hud_scaling", "0.55");
g_settings->setDefault("touch_sensitivity", "0.3");
} else if (x_inches > 3.7 && x_inches <= 4.5) {
// medium phones
g_settings->setDefault("hud_scaling", "0.6");
g_settings->setDefault("selectionbox_width", "6");
} else if (x_inches > 4.5 && x_inches <= 5.5) {
// large 6" phones
g_settings->setDefault("hud_scaling", "0.7");
g_settings->setDefault("selectionbox_width", "6");
} else if (x_inches > 5.5 && x_inches <= 6.5) {
// 7" tablets
g_settings->setDefault("hud_scaling", "0.9");
g_settings->setDefault("selectionbox_width", "6");
} else if (x_inches >= 7.0) {
settings->setDefault("device_is_tablet", "true");
settings->setDefault("recent_chat_messages", "8");
settings->setDefault("console_message_height", "0.4");
}
if (x_inches <= 4.5) {
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE - 1));
} else if (x_inches >= 7.0) {
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE + 1));
}
// Settings for the Rounded or Cutout Screen
int RoundScreen = porting::getRoundScreen();
if (RoundScreen > 0)
settings->setDefault("round_screen", std::to_string(RoundScreen));
}
#endif // Android
// iOS Settings
#ifdef __IOS__
// Switch to olges2 with shaders in new iOS versions
if (IOS_VERSION_AVAILABLE("13.0")) {
settings->setDefault("video_driver", "ogles2");
settings->setDefault("enable_shaders", "true");
} else {
settings->setDefault("video_driver", "ogles1");
settings->setDefault("enable_shaders", "false");
}
settings->setDefault("debug_log_level", "none");
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
settings->setDefault("device_is_tablet", "true");
settings->setDefault("recent_chat_messages", "8");
settings->setDefault("console_message_height", "0.4");
}
// Set the size of the elements depending on the screen size
if SDVersion4Inch {
// 4" iPhone and iPod Touch
settings->setDefault("hud_scaling", "0.55");
settings->setDefault("touch_sensitivity", "0.33");
} else if SDVersion4and7Inch {
// 4.7" iPhone
settings->setDefault("hud_scaling", "0.6");
settings->setDefault("touch_sensitivity", "0.27");
} else if SDVersion5and5Inch {
// 5.5" iPhone Plus
settings->setDefault("hud_scaling", "0.65");
settings->setDefault("touch_sensitivity", "0.3");
} else if (SDVersion5and8Inch || SDVersion6and1Inch) {
// 5.8" and 6.1" iPhones
settings->setDefault("hud_scaling", "0.8");
settings->setDefault("touch_sensitivity", "0.35");
settings->setDefault("selectionbox_width", "6");
} else if SDVersion6and5Inch {
// 6.5" iPhone
settings->setDefault("hud_scaling", "0.85");
settings->setDefault("touch_sensitivity", "0.35");
settings->setDefault("selectionbox_width", "6");
} else if SDVersion7and9Inch {
// iPad mini
settings->setDefault("hud_scaling", "0.9");
settings->setDefault("touch_sensitivity", "0.25");
settings->setDefault("selectionbox_width", "6");
} else if SDVersion8and3Inch {
settings->setDefault("touch_sensitivity", "0.25");
settings->setDefault("selectionbox_width", "6");
} else {
// iPad
settings->setDefault("touch_sensitivity", "0.3");
settings->setDefault("selectionbox_width", "6");
}
if SDVersion4Inch {
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE - 2));
} else if (SDVersion4and7Inch || SDVersion5and5Inch) {
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE - 1));
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && !SDVersion7and9Inch) {
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE + 1));
}
// Settings for the Rounded Screen and Home Bar
if SDVersionRoundScreen {
int upwards = 25, round = 40;
if SDVersioniPhone12Series {
upwards = 20, round = 90;
} else if SDVersion8and3Inch {
upwards = 15, round = 20;
}
settings->setDefault("hud_move_upwards", std::to_string(upwards));
settings->setDefault("round_screen", std::to_string(round));
}
#endif // iOS
#endif
}

View File

@ -316,12 +316,13 @@ bool IsDirDelimiter(char c)
bool RecursiveDelete(const std::string &path)
{
infostream<<"Removing \""<<path<<"\""<<std::endl;
#if 0
/*
Execute the 'rm' command directly, by fork() and execve()
*/
infostream<<"Removing \""<<path<<"\""<<std::endl;
pid_t child_pid = fork();
if(child_pid == 0)
@ -356,6 +357,28 @@ bool RecursiveDelete(const std::string &path)
}while(tpid != child_pid);
return (child_status == 0);
}
#else
/*
Executing fork() and execve() is unsafe and unavailable on some platforms
*/
bool success = true;
std::vector<std::string> paths;
paths.push_back(path);
fs::GetRecursiveSubPaths(path, paths, true, {});
// Go backwards to successfully delete the output of GetRecursiveSubPaths
for (int i = paths.size() - 1; i >= 0; i--) {
const std::string &p = paths[i];
bool did = DeleteSingleFileOrEmptyDirectory(p);
if (!did) {
errorstream << "Failed to delete " << p << std::endl;
success = false;
}
}
return success;
#endif
}
bool DeleteSingleFileOrEmptyDirectory(const std::string &path)
@ -387,7 +410,7 @@ std::string TempPath()
configuration hardcodes mkstemp("/tmp/lua_XXXXXX").
*/
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__APPLE__)
return porting::path_cache;
#else
return DIR_DELIM "tmp";
@ -796,7 +819,8 @@ bool safeWriteToFile(const std::string &path, const std::string &content)
}
#ifndef SERVER
bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string &destination)
bool extractZipFile(io::IFileSystem *fs, const char *filename,
const std::string &destination, const char *password, std::string *errorMessage)
{
// Be careful here not to touch the global file hierarchy in Irrlicht
// since this function needs to be thread-safe!
@ -814,6 +838,13 @@ bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string
}
irr_ptr<io::IFileArchive> opened_zip(zip_loader->createArchive(filename, false, false));
if (opened_zip.get() == nullptr) {
if (errorMessage != nullptr)
*errorMessage = "failed to open zip file";
return false;
}
opened_zip->Password = core::stringc(password);
const io::IFileList* files_in_zip = opened_zip->getFileList();
for (u32 i = 0; i < files_in_zip->getFileCount(); i++) {
@ -829,6 +860,14 @@ bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string
irr_ptr<io::IReadFile> toread(opened_zip->createAndOpenFile(i));
if (toread.get() == nullptr) {
// Wrong password
fs->removeFileArchive(fs->getFileArchiveCount()-1);
if (errorMessage != nullptr)
*errorMessage = "invalid password";
return false;
}
std::ofstream os(fullpath.c_str(), std::ios::binary);
if (!os.good())
return false;

View File

@ -138,7 +138,9 @@ const char *GetFilenameFromPath(const char *path);
bool safeWriteToFile(const std::string &path, const std::string &content);
#ifndef SERVER
bool extractZipFile(irr::io::IFileSystem *fs, const char *filename, const std::string &destination);
bool extractZipFile(irr::io::IFileSystem *fs, const char *filename,
const std::string &destination, const char *password = "",
std::string *errorMessage = nullptr);
#endif
bool ReadFile(const std::string &path, std::string &out);

View File

@ -24,6 +24,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gettext.h"
#include "util/string.h"
#include "log.h"
#include "porting.h"
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
#include <SDL.h>
#endif
#if USE_GETTEXT && defined(_MSC_VER)
#include <windows.h>
@ -131,6 +136,10 @@ void init_gettext(const char *path, const std::string &configured_language,
setenv("LANG", configured_language.c_str(), 1);
#endif
#if defined(__ANDROID__) || defined(__APPLE__)
setenv("LANG", configured_language.c_str(), 1);
#endif
// Reload locale with changed environment
setlocale(LC_ALL, "");
#elif defined(_MSC_VER)
@ -207,6 +216,20 @@ void init_gettext(const char *path, const std::string &configured_language,
}
else {
/* set current system default locale */
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
SDL_Locale* locale = SDL_GetPreferredLocales();
if (locale) {
if (locale[0].language) {
char lang[3] = {0};
strncpy(lang, locale[0].language, 2);
SDL_setenv("LANG", lang, 1);
SDL_setenv("LANGUAGE", lang, 1);
}
SDL_free(locale);
}
#endif
setlocale(LC_ALL, "");
}
@ -221,7 +244,7 @@ void init_gettext(const char *path, const std::string &configured_language,
#endif
#endif
std::string name = lowercase(PROJECT_NAME);
std::string name = "minetest";;
infostream << "Gettext: domainname=\"" << name
<< "\" path=\"" << path << "\"" << std::endl;

View File

@ -19,7 +19,6 @@ set(gui_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/guiInventoryList.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiItemImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiKeyChangeMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiPathSelectMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiScene.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp

View File

@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/tile.h" // ITextureSource
#include "client/fontengine.h"
#include "client/renderingengine.h"
#include "debug.h"
#include "irrlichttypes_extrabloated.h"
#include "util/string.h"
@ -45,6 +46,7 @@ public:
BGIMG_PRESSED, // Note: Deprecated property
FGIMG,
FGIMG_HOVERED, // Note: Deprecated property
FGIMG_MIDDLE,
FGIMG_PRESSED, // Note: Deprecated property
ALPHA,
CONTENT_OFFSET,
@ -57,6 +59,12 @@ public:
SOUND,
SPACING,
SIZE,
SCROLLBAR_BGIMG,
SCROLLBAR_THUMB_IMG,
SCROLLBAR_UP_IMG,
SCROLLBAR_DOWN_IMG,
SCROLLBAR_THUMB_TOP_IMG,
SCROLLBAR_THUMB_BOTTOM_IMG,
NUM_PROPERTIES,
NONE
};
@ -69,6 +77,32 @@ public:
STATE_INVALID = 1 << 3,
};
// Used in guiConfirmRegistration.cpp, guiKeyChangeMenu.cpp and guiVolumeChange.h
static std::array<StyleSpec, NUM_STATES> getButtonStyle(const std::string texture_path = "", std::string color = "") {
std::array<StyleSpec, NUM_STATES> ret;
color = color != "" ? "_" + color : "";
const bool high_dpi = RenderingEngine::isHighDpi();
const std::string x2 = high_dpi ? ".x2" : "";
StyleSpec btn_spec;
btn_spec.set(BGIMG, texture_path + "gui/gui_button" + color + x2 + ".png");
btn_spec.set(BGIMG_MIDDLE, high_dpi ? "48" : "32");
btn_spec.set(BORDER, "false");
btn_spec.set(PADDING, high_dpi ? "-30" : "-20");
ret[STATE_DEFAULT] = btn_spec;
StyleSpec hovered_spec;
hovered_spec.set(BGIMG, texture_path + "gui/gui_button" + color + "_hovered" + x2 + ".png");
ret[STATE_HOVERED] = hovered_spec;
StyleSpec pressed_spec;
pressed_spec.set(BGIMG, texture_path + "gui/gui_button" + color + "_pressed" + x2 + ".png");
ret[STATE_PRESSED] = pressed_spec;
return ret;
}
private:
std::array<bool, NUM_PROPERTIES> property_set{};
std::array<std::string, NUM_PROPERTIES> properties;
@ -101,6 +135,8 @@ public:
return FGIMG;
} else if (name == "fgimg_hovered") {
return FGIMG_HOVERED;
} else if (name == "fgimg_middle") {
return FGIMG_MIDDLE;
} else if (name == "fgimg_pressed") {
return FGIMG_PRESSED;
} else if (name == "alpha") {
@ -125,6 +161,18 @@ public:
return SPACING;
} else if (name == "size") {
return SIZE;
} else if (name == "scrollbar_bgimg") {
return SCROLLBAR_BGIMG;
} else if (name == "scrollbar_thumb_img") {
return SCROLLBAR_THUMB_IMG;
} else if (name == "scrollbar_up_img") {
return SCROLLBAR_UP_IMG;
} else if (name == "scrollbar_down_img") {
return SCROLLBAR_DOWN_IMG;
} else if (name == "scrollbar_thumb_top_img") {
return SCROLLBAR_THUMB_TOP_IMG;
} else if (name == "scrollbar_thumb_bottom_img") {
return SCROLLBAR_THUMB_BOTTOM_IMG;
} else {
return NONE;
}
@ -176,9 +224,14 @@ public:
{
StyleSpec temp = styles[StyleSpec::STATE_DEFAULT];
temp.state_map = state;
#ifdef HAVE_TOUCHSCREENGUI
// always render pressed as hovered on touchscreen
if (state & STATE_PRESSED)
state = State(state | STATE_HOVERED);
#endif
for (int i = StyleSpec::STATE_DEFAULT + 1; i <= state; i++) {
if ((state & i) != 0) {
temp = temp | styles[i];
temp |= styles[i];
}
}

View File

@ -9,40 +9,37 @@
#include <vector>
GUIAnimatedImage::GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
s32 id, const core::rect<s32> &rectangle, const std::string &texture_name,
s32 frame_count, s32 frame_duration, ISimpleTextureSource *tsrc) :
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle), m_tsrc(tsrc)
s32 id, const core::rect<s32> &rectangle) :
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle)
{
m_texture = m_tsrc->getTexture(texture_name);
m_frame_count = std::max(frame_count, 1);
m_frame_duration = std::max(frame_duration, 0);
if (m_texture != nullptr) {
core::dimension2d<u32> size = m_texture->getOriginalSize();
if (size.Height < (u64)m_frame_count)
m_frame_count = size.Height;
} else {
// No need to step an animation if we have nothing to draw
m_frame_count = 1;
}
}
void GUIAnimatedImage::draw()
{
// Render the current frame
if (m_texture != nullptr) {
video::IVideoDriver *driver = Environment->getVideoDriver();
if (m_texture == nullptr)
return;
video::IVideoDriver *driver = Environment->getVideoDriver();
core::dimension2d<u32> size = m_texture->getOriginalSize();
if ((u32)m_frame_count > size.Height)
m_frame_count = size.Height;
if (m_frame_idx >= m_frame_count)
m_frame_idx = m_frame_count - 1;
size.Height /= m_frame_count;
core::rect<s32> rect(core::position2d<s32>(0, size.Height * m_frame_idx), size);
core::rect<s32> *cliprect = NoClip ? nullptr : &AbsoluteClippingRect;
if (m_middle.getArea() == 0) {
const video::SColor color(255, 255, 255, 255);
const video::SColor colors[] = {color, color, color, color};
core::dimension2d<u32> size = m_texture->getOriginalSize();
size.Height /= m_frame_count;
draw2DImageFilterScaled(driver, m_texture, AbsoluteRect,
core::rect<s32>(core::position2d<s32>(0, size.Height * m_frame_idx), size),
NoClip ? nullptr : &AbsoluteClippingRect, colors, true);
draw2DImageFilterScaled(driver, m_texture, AbsoluteRect, rect, cliprect,
colors, true);
} else {
draw2DImage9Slice(driver, m_texture, AbsoluteRect, rect, m_middle, cliprect);
}
// Step the animation
@ -55,7 +52,7 @@ void GUIAnimatedImage::draw()
m_global_time = new_global_time;
// Advance by the number of elapsed frames, looping if necessary
m_frame_idx += u32(m_frame_time / m_frame_duration);
m_frame_idx += (u32)(m_frame_time / m_frame_duration);
m_frame_idx %= m_frame_count;
// If 1 or more frames have elapsed, reset the frame time counter with
@ -63,11 +60,3 @@ void GUIAnimatedImage::draw()
m_frame_time %= m_frame_duration;
}
}
void GUIAnimatedImage::setFrameIndex(s32 frame)
{
s32 idx = std::max(frame, 0);
if (idx > 0 && idx < m_frame_count)
m_frame_idx = idx;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "irrlichttypes_extrabloated.h"
#include <algorithm>
#include <string>
class ISimpleTextureSource;
@ -8,21 +9,33 @@ class ISimpleTextureSource;
class GUIAnimatedImage : public gui::IGUIElement {
public:
GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
s32 id, const core::rect<s32> &rectangle, const std::string &texture_name,
s32 frame_count, s32 frame_duration, ISimpleTextureSource *tsrc);
s32 id, const core::rect<s32> &rectangle);
virtual void draw() override;
void setFrameIndex(s32 frame);
void setTexture(video::ITexture *texture) { m_texture = texture; };
video::ITexture *getTexture() const { return m_texture; };
void setMiddleRect(const core::rect<s32> &middle) { m_middle = middle; };
core::rect<s32> getMiddleRect() const { return m_middle; };
void setFrameDuration(u64 duration) { m_frame_duration = duration; };
u64 getFrameDuration() const { return m_frame_duration; };
void setFrameCount(s32 count) { m_frame_count = std::max(count, 1); };
s32 getFrameCount() const { return m_frame_count; };
void setFrameIndex(s32 frame) { m_frame_idx = std::max(frame, 0); };
s32 getFrameIndex() const { return m_frame_idx; };
private:
ISimpleTextureSource *m_tsrc;
video::ITexture *m_texture = nullptr;
u64 m_global_time = 0;
s32 m_frame_idx = 0;
s32 m_frame_count = 1;
u64 m_frame_duration = 1;
u64 m_frame_duration = 0;
u64 m_frame_time = 0;
core::rect<s32> m_middle;
};

View File

@ -48,21 +48,15 @@ void GUIBackgroundImage::draw()
video::IVideoDriver *driver = Environment->getVideoDriver();
core::rect<s32> srcrect(core::position2d<s32>(0, 0),
core::dimension2di(texture->getOriginalSize()));
if (m_middle.getArea() == 0) {
const video::SColor color(255, 255, 255, 255);
const video::SColor colors[] = {color, color, color, color};
draw2DImageFilterScaled(driver, texture, rect,
core::rect<s32>(core::position2d<s32>(0, 0),
core::dimension2di(texture->getOriginalSize())),
nullptr, colors, true);
draw2DImageFilterScaled(driver, texture, rect, srcrect, nullptr, colors, true);
} else {
core::rect<s32> middle = m_middle;
// `-x` is interpreted as `w - x`
if (middle.LowerRightCorner.X < 0)
middle.LowerRightCorner.X += texture->getOriginalSize().Width;
if (middle.LowerRightCorner.Y < 0)
middle.LowerRightCorner.Y += texture->getOriginalSize().Height;
draw2DImage9Slice(driver, texture, rect, middle);
draw2DImage9Slice(driver, texture, rect, srcrect, m_middle);
}
IGUIElement::draw();

View File

@ -320,15 +320,9 @@ void GUIButton::draw()
sourceRect, &AbsoluteClippingRect,
image_colors, UseAlphaChannel);
} else {
core::rect<s32> middle = BgMiddle;
// `-x` is interpreted as `w - x`
if (middle.LowerRightCorner.X < 0)
middle.LowerRightCorner.X += texture->getOriginalSize().Width;
if (middle.LowerRightCorner.Y < 0)
middle.LowerRightCorner.Y += texture->getOriginalSize().Height;
draw2DImage9Slice(driver, texture,
ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
middle, &AbsoluteClippingRect, image_colors);
sourceRect, BgMiddle, &AbsoluteClippingRect, image_colors);
}
// END PATCH
}
@ -509,7 +503,12 @@ video::SColor GUIButton::getOverrideColor() const
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
video::SColor GUIButton::getActiveColor() const
{
return video::SColor(0,0,0,0); // unused?
if (OverrideColorEnabled)
return OverrideColor;
IGUISkin* skin = Environment->getSkin();
if (skin)
return skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT);
return OverrideColor;
}
#endif

View File

@ -32,15 +32,15 @@ using namespace gui;
GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment,
gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
ISimpleTextureSource *tsrc, bool noclip)
: GUIButton (environment, parent, id, rectangle, tsrc, noclip)
: GUIButton(environment, parent, id, rectangle, tsrc, noclip)
{
m_image = Environment->addImage(
core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), this);
m_image->setScaleImage(isScalingImage());
GUIButton::setScaleImage(true);
m_image = new GUIAnimatedImage(environment, this, id, rectangle);
sendToBack(m_image);
}
void GUIButtonImage::setForegroundImage(video::ITexture *image)
void GUIButtonImage::setForegroundImage(video::ITexture *image,
const core::rect<s32> &middle)
{
if (image == m_foreground_image)
return;
@ -52,11 +52,12 @@ void GUIButtonImage::setForegroundImage(video::ITexture *image)
m_foreground_image->drop();
m_foreground_image = image;
m_image->setImage(image);
m_image->setTexture(image);
m_image->setMiddleRect(middle);
}
//! Set element properties from a StyleSpec
void GUIButtonImage::setFromStyle(const StyleSpec& style)
void GUIButtonImage::setFromStyle(const StyleSpec &style)
{
GUIButton::setFromStyle(style);
@ -67,19 +68,13 @@ void GUIButtonImage::setFromStyle(const StyleSpec& style)
getTextureSource());
setForegroundImage(guiScalingImageButton(driver, texture,
AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));
setScaleImage(true);
AbsoluteRect.getWidth(), AbsoluteRect.getHeight()),
style.getRect(StyleSpec::FGIMG_MIDDLE, m_image->getMiddleRect()));
} else {
setForegroundImage(nullptr);
setForegroundImage();
}
}
void GUIButtonImage::setScaleImage(bool scaleImage)
{
GUIButton::setScaleImage(scaleImage);
m_image->setScaleImage(scaleImage);
}
GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment,
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
IGUIElement *parent, s32 id, const wchar_t *text,

View File

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiButton.h"
#include "IGUIButton.h"
#include "guiAnimatedImage.h"
using namespace irr;
@ -32,12 +33,11 @@ public:
s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
bool noclip = false);
void setForegroundImage(video::ITexture *image = nullptr);
void setForegroundImage(video::ITexture *image = nullptr,
const core::rect<s32> &middle = core::rect<s32>());
//! Set element properties from a StyleSpec
virtual void setFromStyle(const StyleSpec& style) override;
virtual void setScaleImage(bool scaleImage=true) override;
virtual void setFromStyle(const StyleSpec &style) override;
//! Do not drop returned handle
static GUIButtonImage *addButton(gui::IGUIEnvironment *environment,
@ -47,5 +47,5 @@ public:
private:
video::ITexture *m_foreground_image = nullptr;
gui::IGUIImage *m_image;
GUIAnimatedImage *m_image;
};

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,99 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "modalMenu.h"
#include "chat.h"
#include "config.h"
#include "guiScrollBar.h"
struct ChatSelection
{
enum SelectionType {
SELECTION_NONE,
SELECTION_HISTORY,
SELECTION_PROMPT
};
ChatSelection() : selection_type(SELECTION_NONE), scroll(0), row(0),
line_index(0), line(0), fragment(0), character(0), x_max(false) {};
void reset() {
selection_type = SELECTION_NONE;
scroll = 0;
row = 0;
line_index = 0;
line = 0;
fragment = 0;
character = 0;
x_max = false;
}
bool operator== (const ChatSelection &other) const {
if (selection_type == SELECTION_HISTORY &&
other.selection_type == SELECTION_HISTORY) {
return (row + scroll == other.row + other.scroll &&
line_index == other.line_index &&
line == other.line &&
fragment == other.fragment &&
character == other.character &&
x_max == other.x_max);
} else {
return (scroll + character == other.scroll + other.character &&
x_max == other.x_max);
}
}
bool operator< (const ChatSelection &other) const {
if (selection_type == SELECTION_HISTORY &&
other.selection_type == SELECTION_HISTORY) {
if (row + scroll != other.row + other.scroll)
return (row + scroll < other.row + other.scroll);
if (line_index != other.line_index)
return (line_index < other.line_index);
if (line != other.line)
return (line < other.line);
if (fragment != other.fragment)
return (fragment < other.fragment);
if (character != other.character)
return (character < other.character);
if (x_max != other.x_max)
return (x_max < other.x_max);
return false;
} else {
if (scroll + character != other.scroll + other.character)
return (scroll + character < other.scroll + other.character);
if (x_max != other.x_max)
return (x_max < other.x_max);
return false;
}
}
bool operator> (const ChatSelection &other) {
return other < *this;
}
bool operator<= (const ChatSelection &other) {
return !(*this > other);
}
bool operator>= (const ChatSelection &other) {
return !(*this < other);
}
bool operator!= (const ChatSelection &other) const {
return !this->operator==(other);
}
SelectionType selection_type;
int scroll;
int row;
int line_index;
unsigned int line;
unsigned int fragment;
unsigned int character;
bool x_max;
};
class Client;
@ -50,8 +143,6 @@ public:
// Close the console, equivalent to openConsole(0).
// This doesn't close immediately but initiates an animation.
void closeConsole();
// Close the console immediately, without animation.
void closeConsoleAtOnce();
// Set whether to close the console after the user presses enter.
void setCloseOnEnter(bool close) { m_close_on_enter = close; }
@ -74,6 +165,21 @@ public:
virtual bool acceptsIME() { return true; }
bool hasFocus();
bool convertToMouseEvent(
SEvent &mouse_event, SEvent touch_event) const noexcept;
bool preprocessEvent(SEvent event);
bool getAndroidChatOpen() { return m_android_chat_open; }
void setAndroidChatOpen(bool value) { m_android_chat_open = value; }
void onLinesModified();
void onPromptModified();
static GUIChatConsole* getChatConsole() { return m_chat_console; }
private:
void reformatConsole();
void recalculateConsolePosition();
@ -87,7 +193,19 @@ private:
// If clicked fragment has a web url, send it to the system default web browser
void middleClick(s32 col, s32 row);
ChatSelection getCursorPos(s32 x, s32 y);
ChatSelection getPromptCursorPos(s32 x, s32 y);
ChatSelection getCurrentPromptCursorPos();
irr::core::stringc getSelectedText();
irr::core::stringc getPromptSelectedText();
void movePromptCursor(s32 x, s32 y);
void deletePromptSelection();
void createVScrollBar();
void updateVScrollBar(bool force_update = false, bool move_bottom = false);
private:
static GUIChatConsole* m_chat_console;
ChatBackend* m_chat_backend;
Client* m_client;
IMenuManager* m_menumgr;
@ -134,4 +252,17 @@ private:
bool m_cache_clickable_chat_weblinks;
// Track if a ctrl key is currently held down
bool m_is_ctrl_down;
ChatSelection m_mark_begin;
ChatSelection m_mark_end;
bool m_history_marking = false;
bool m_prompt_marking = false;
bool m_long_press = false;
ChatSelection m_cursor_press_pos;
u32 m_scrollbar_width = 0;
GUIScrollBar *m_vscrollbar = nullptr;
s32 m_bottom_scroll_pos = 0;
bool m_android_chat_open = false;
};

View File

@ -20,7 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiConfirmRegistration.h"
#include "client/client.h"
#include "filesys.h"
#include "guiBackgroundImage.h"
#include "guiButton.h"
#include "guiEditBoxWithScrollbar.h"
#include <IGUICheckBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
@ -32,6 +35,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/renderingengine.h"
#endif
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
#include <SDL.h>
#endif
#include "gettext.h"
// Continuing from guiPasswordChange.cpp
@ -40,6 +47,8 @@ const int ID_confirm = 263;
const int ID_intotext = 264;
const int ID_cancel = 265;
const int ID_message = 266;
const int ID_background = 267;
const int ID_confirmPasswordBg = 268;
GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client,
@ -52,11 +61,21 @@ GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
#ifdef HAVE_TOUCHSCREENGUI
m_touchscreen_visible = false;
#endif
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
if (porting::hasRealKeyboard())
SDL_StartTextInput();
#endif
}
GUIConfirmRegistration::~GUIConfirmRegistration()
{
removeChildren();
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
if (porting::hasRealKeyboard() && SDL_IsTextInputActive())
SDL_StopTextInput();
#endif
}
void GUIConfirmRegistration::removeChildren()
@ -77,11 +96,13 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
/*
Calculate new sizes and positions
*/
#ifdef HAVE_TOUCHSCREENGUI
const float s = m_gui_scale * RenderingEngine::getDisplayDensity() / 2;
float s = MYMIN(screensize.X / 600.f, screensize.Y / 360.f);
#if HAVE_TOUCHSCREENGUI
s *= g_settings->getBool("device_is_tablet") ? 0.7f : 0.8f;
#else
const float s = m_gui_scale;
s *= 0.5f;
#endif
DesiredRect = core::rect<s32>(
screensize.X / 2 - 600 * s / 2,
screensize.Y / 2 - 360 * s / 2,
@ -98,11 +119,21 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
/*
Add stuff
*/
s32 ypos = 30 * s;
// Background image
{
const std::string texture = "bg_common.png";
const core::rect<s32> rect(0, 0, 0, 0);
const core::rect<s32> middle(40, 40, -40, -40);
new GUIBackgroundImage(Environment, this, ID_background, rect,
texture, middle, m_tsrc, true);
}
s32 ypos = 20 * s;
{
core::rect<s32> rect2(0, 0, 540 * s, 180 * s);
rect2 += topleft_client + v2s32(30 * s, ypos);
static const std::string info_text_template = strgettext(
const std::string info_text_template = strgettext(
"You are about to join this server with the name \"%s\" for the "
"first time.\n"
"If you proceed, a new account using your credentials will be "
@ -122,40 +153,54 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER);
}
ypos += 200 * s;
{
core::rect<s32> rect2(0, 0, 540 * s, 30 * s);
rect2 += topleft_client + v2s32(30 * s, ypos);
gui::IGUIEditBox *e = Environment->addEditBox(m_pass_confirm.c_str(),
rect2, true, this, ID_confirmPassword);
e->setPasswordBox(true);
Environment->setFocus(e);
}
ypos += 50 * s;
{
core::rect<s32> rect2(0, 0, 230 * s, 35 * s);
rect2 = rect2 + v2s32(size.X / 2 - 220 * s, ypos);
text = wgettext("Register and Join");
GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_confirm, text);
delete[] text;
}
{
core::rect<s32> rect2(0, 0, 120 * s, 35 * s);
rect2 = rect2 + v2s32(size.X / 2 + 70 * s, ypos);
text = wgettext("Cancel");
GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text);
delete[] text;
}
ypos += 140 * s;
{
core::rect<s32> rect2(0, 0, 500 * s, 40 * s);
rect2 += topleft_client + v2s32(30 * s, ypos + 40 * s);
rect2 += topleft_client + v2s32(30 * s, ypos + 45 * s);
text = wgettext("Passwords do not match!");
IGUIElement *e = Environment->addStaticText(
text, rect2, false, true, this, ID_message);
e->setVisible(false);
delete[] text;
}
ypos += 75 * s;
{
core::rect<s32> rect2(0, 0, 540 * s, 40 * s);
rect2 += topleft_client + v2s32(30 * s, ypos);
core::rect<s32> bg_middle(10, 10, -10, -10);
new GUIBackgroundImage(Environment, this, ID_confirmPasswordBg,
rect2, "field_bg.png", bg_middle, m_tsrc, false);
rect2.UpperLeftCorner.X += 5 * s;
rect2.LowerRightCorner.X -= 5 * s;
gui::IGUIEditBox *e = Environment->addEditBox(m_pass_confirm.c_str(),
rect2, true, this, ID_confirmPassword);
e->setDrawBorder(false);
e->setDrawBackground(false);
e->setPasswordBox(true);
Environment->setFocus(e);
}
ypos += 60 * s;
{
core::rect<s32> rect2(0, 0, 300 * s, 40 * s);
rect2 = rect2 + v2s32(size.X / 2 - 250 * s, ypos);
text = wgettext("Register and Join");
GUIButton *e = GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_confirm, text);
e->setStyles(StyleSpec::getButtonStyle("", "green"));
delete[] text;
}
{
core::rect<s32> rect2(0, 0, 140 * s, 40 * s);
rect2 = rect2 + v2s32(size.X / 2 + 110 * s, ypos);
text = wgettext("Cancel");
GUIButton *e = GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text);
e->setStyles(StyleSpec::getButtonStyle());
delete[] text;
}
}
void GUIConfirmRegistration::drawMenu()
@ -163,13 +208,9 @@ void GUIConfirmRegistration::drawMenu()
gui::IGUISkin *skin = Environment->getSkin();
if (!skin)
return;
video::IVideoDriver *driver = Environment->getVideoDriver();
video::SColor bgcolor(140, 0, 0, 0);
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
gui::IGUIElement::draw();
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
getAndroidUIInput();
#endif
}
@ -257,10 +298,10 @@ bool GUIConfirmRegistration::OnEvent(const SEvent &event)
return false;
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool GUIConfirmRegistration::getAndroidUIInput()
{
if (!hasAndroidUIInput() || m_jni_field_name != "password")
if (m_jni_field_name.empty() || m_jni_field_name != "password")
return false;
// still waiting

View File

@ -51,13 +51,16 @@ public:
bool processInput();
bool OnEvent(const SEvent &event);
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool getAndroidUIInput();
#endif
private:
std::wstring getLabelByID(s32 id) { return L""; }
std::string getNameByID(s32 id) { return "password"; }
std::string getNameByID(s32 id)
{
return id == 262 ? "password" : ""; // 262 is ID_confirmPassword
}
Client *m_client = nullptr;
const std::string &m_playername;
@ -65,4 +68,5 @@ private:
bool *m_aborted = nullptr;
std::wstring m_pass_confirm = L"";
ISimpleTextureSource *m_tsrc;
video::SColor m_fullscreen_bgcolor;
};

View File

@ -25,8 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "IGUIFont.h"
#include "porting.h"
#include "touchscreengui.h"
#include "util/string.h"
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
#include <SDL.h>
#endif
GUIEditBox::~GUIEditBox()
{
if (m_override_font)
@ -178,6 +183,8 @@ void GUIEditBox::setTextMarkers(s32 begin, s32 end)
if (begin != m_mark_begin || end != m_mark_end) {
m_mark_begin = begin;
m_mark_end = end;
m_real_mark_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
m_real_mark_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
}
}
@ -203,13 +210,29 @@ bool GUIEditBox::OnEvent(const SEvent &event)
switch (event.EventType) {
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) {
if (event.GUIEvent.Caller == this) {
m_mouse_marking = false;
setTextMarkers(0, 0);
}
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) {
#ifdef HAVE_TOUCHSCREENGUI
if (!TouchScreenGUI::isActive())
#endif
if (event.GUIEvent.Caller == this) {
m_mouse_marking = false;
setTextMarkers(0, 0);
}
}
break;
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
case EET_SDL_TEXT_EVENT:
if (event.SDLTextEvent.Type == irr::ESDLET_TEXTINPUT) {
core::stringw text =
utf8_to_stringw(event.SDLTextEvent.Text);
for (size_t i = 0; i < text.size(); i++)
inputChar(text[i]);
return true;
}
break;
#endif
case EET_KEY_INPUT_EVENT:
if (processKey(event))
return true;
@ -240,11 +263,21 @@ bool GUIEditBox::processKey(const SEvent &event)
s32 new_mark_begin = m_mark_begin;
s32 new_mark_end = m_mark_end;
// On Windows right alt simulates additional control press/release events.
// It causes unexpected bahavior, for example right alt + A would clear text
// in the edit box. At least for SDL we can easily check if alt key is
// pressed
bool altPressed = false;
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
SDL_Keymod keymod = SDL_GetModState();
altPressed = keymod & KMOD_ALT;
#endif
// control shortcut handling
if (event.KeyInput.Control) {
if (event.KeyInput.Control && !altPressed) {
// german backlash '\' entered with control + '?'
if (event.KeyInput.Char == '\\') {
if (m_writable && event.KeyInput.Char == '\\') {
inputChar(event.KeyInput.Char);
return true;
}
@ -259,10 +292,14 @@ bool GUIEditBox::processKey(const SEvent &event)
onKeyControlC(event);
break;
case KEY_KEY_X:
text_changed = onKeyControlX(event, new_mark_begin, new_mark_end);
if (m_writable)
text_changed = onKeyControlX(
event, new_mark_begin, new_mark_end);
break;
case KEY_KEY_V:
text_changed = onKeyControlV(event, new_mark_begin, new_mark_end);
if (m_writable)
text_changed = onKeyControlV(
event, new_mark_begin, new_mark_end);
break;
case KEY_HOME:
// move/highlight to start of text
@ -288,6 +325,26 @@ bool GUIEditBox::processKey(const SEvent &event)
new_mark_end = 0;
}
break;
#if defined(__ANDROID__) || defined(__IOS__)
case EET_TOUCH_INPUT_EVENT:
if (event.TouchInput.Event == irr::ETIE_PRESSED_LONG) {
if (!m_mouse_marking) {
m_long_press = true;
bool success = onKeyControlC(event);
#ifdef __ANDROID__
if (success)
SDL_AndroidShowToast(
"Copied to clipboard", 2,
-1, 0, 0);
#elif __IOS__
if (success)
porting::showToast("Copied to clipboard");
#endif
}
return true;
}
break;
#endif
default:
return false;
}
@ -336,13 +393,16 @@ bool GUIEditBox::processKey(const SEvent &event)
m_blink_start_time = porting::getTimeMs();
} break;
case KEY_RETURN:
if (m_multiline) {
inputChar(L'\n');
} else {
calculateScrollPos();
sendGuiEvent(EGET_EDITBOX_ENTER);
if (m_writable) {
if (m_multiline) {
inputChar(L'\n');
} else {
calculateScrollPos();
sendGuiEvent(EGET_EDITBOX_ENTER);
}
return true;
}
return true;
break;
case KEY_LEFT:
if (event.KeyInput.Shift) {
if (m_cursor_pos > 0) {
@ -388,11 +448,15 @@ bool GUIEditBox::processKey(const SEvent &event)
}
break;
case KEY_BACK:
text_changed = onKeyBack(event, new_mark_begin, new_mark_end);
if (m_writable)
text_changed = onKeyBack(
event, new_mark_begin, new_mark_end);
break;
case KEY_DELETE:
text_changed = onKeyDelete(event, new_mark_begin, new_mark_end);
if (m_writable)
text_changed = onKeyDelete(
event, new_mark_begin, new_mark_end);
break;
case KEY_ESCAPE:
@ -426,8 +490,10 @@ bool GUIEditBox::processKey(const SEvent &event)
return false;
default:
inputChar(event.KeyInput.Char);
return true;
if (m_writable) {
inputChar(event.KeyInput.Char);
return true;
}
}
}
@ -450,8 +516,7 @@ bool GUIEditBox::onKeyUp(const SEvent &event, s32 &mark_begin, s32 &mark_end)
// clang-format off
if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) {
s32 lineNo = getLineFromPos(m_cursor_pos);
s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos :
(m_mark_begin > m_mark_end ? m_mark_begin : m_mark_end);
s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos : m_real_mark_begin;
if (lineNo > 0) {
s32 cp = m_cursor_pos - m_broken_text_positions[lineNo];
if ((s32)m_broken_text[lineNo - 1].size() < cp) {
@ -482,8 +547,7 @@ bool GUIEditBox::onKeyDown(const SEvent &event, s32 &mark_begin, s32 &mark_end)
// clang-format off
if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) {
s32 lineNo = getLineFromPos(m_cursor_pos);
s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos :
(m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end);
s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos : m_real_mark_begin;
if (lineNo < (s32)m_broken_text.size() - 1) {
s32 cp = m_cursor_pos - m_broken_text_positions[lineNo];
if ((s32)m_broken_text[lineNo + 1].size() < cp) {
@ -509,17 +573,16 @@ bool GUIEditBox::onKeyDown(const SEvent &event, s32 &mark_begin, s32 &mark_end)
return false;
}
void GUIEditBox::onKeyControlC(const SEvent &event)
bool GUIEditBox::onKeyControlC(const SEvent &event)
{
// copy to clipboard
if (m_passwordbox || !m_operator || m_mark_begin == m_mark_end)
return;
return false;
const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
std::string s = stringw_to_utf8(Text.subString(realmbgn, realmend - realmbgn));
m_operator->copyToClipboard(s.c_str());
std::string s = stringw_to_utf8(Text.subString(
m_real_mark_begin, m_real_mark_end - m_real_mark_begin));
m_operator->copyToClipboard(s.c_str());
return true;
}
bool GUIEditBox::onKeyControlX(const SEvent &event, s32 &mark_begin, s32 &mark_end)
@ -533,18 +596,15 @@ bool GUIEditBox::onKeyControlX(const SEvent &event, s32 &mark_begin, s32 &mark_e
if (m_passwordbox || !m_operator || m_mark_begin == m_mark_end)
return false;
const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
// Now remove from box if enabled
if (isEnabled()) {
// delete
core::stringw s;
s = Text.subString(0, realmbgn);
s.append(Text.subString(realmend, Text.size() - realmend));
s = Text.subString(0, m_real_mark_begin);
s.append(Text.subString(m_real_mark_end, Text.size() - m_real_mark_end));
Text = s;
m_cursor_pos = realmbgn;
m_cursor_pos = m_real_mark_begin;
mark_begin = 0;
mark_end = 0;
return true;
@ -562,9 +622,6 @@ bool GUIEditBox::onKeyControlV(const SEvent &event, s32 &mark_begin, s32 &mark_e
if (!m_operator)
return false;
const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
// add new character
if (const c8 *p = m_operator->getTextFromClipboard()) {
core::stringw inserted_text = utf8_to_stringw(p);
@ -582,13 +639,14 @@ bool GUIEditBox::onKeyControlV(const SEvent &event, s32 &mark_begin, s32 &mark_e
} else {
// replace text
core::stringw s = Text.subString(0, realmbgn);
core::stringw s = Text.subString(0, m_real_mark_begin);
s.append(inserted_text);
s.append(Text.subString(realmend, Text.size() - realmend));
s.append(Text.subString(
m_real_mark_end, Text.size() - m_real_mark_end));
if (!m_max || s.size() <= m_max) {
Text = s;
m_cursor_pos = realmbgn + inserted_text.size();
m_cursor_pos = m_real_mark_begin + inserted_text.size();
}
}
}
@ -607,16 +665,11 @@ bool GUIEditBox::onKeyBack(const SEvent &event, s32 &mark_begin, s32 &mark_end)
if (m_mark_begin != m_mark_end) {
// delete marked text
const s32 realmbgn =
m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
const s32 realmend =
m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
s = Text.subString(0, realmbgn);
s.append(Text.subString(realmend, Text.size() - realmend));
s = Text.subString(0, m_real_mark_begin);
s.append(Text.subString(m_real_mark_end, Text.size() - m_real_mark_end));
Text = s;
m_cursor_pos = realmbgn;
m_cursor_pos = m_real_mark_begin;
} else {
// delete text behind cursor
if (m_cursor_pos > 0)
@ -645,16 +698,11 @@ bool GUIEditBox::onKeyDelete(const SEvent &event, s32 &mark_begin, s32 &mark_end
if (m_mark_begin != m_mark_end) {
// delete marked text
const s32 realmbgn =
m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
const s32 realmend =
m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
s = Text.subString(0, realmbgn);
s.append(Text.subString(realmend, Text.size() - realmend));
s = Text.subString(0, m_real_mark_begin);
s.append(Text.subString(m_real_mark_end, Text.size() - m_real_mark_end));
Text = s;
m_cursor_pos = realmbgn;
m_cursor_pos = m_real_mark_begin;
} else {
// delete text before cursor
s = Text.subString(0, m_cursor_pos);
@ -690,14 +738,11 @@ void GUIEditBox::inputString(const core::stringw &str)
core::stringw s;
if (m_mark_begin != m_mark_end) {
// replace marked text
s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
s = Text.subString(0, real_begin);
s = Text.subString(0, m_real_mark_begin);
s.append(str);
s.append(Text.subString(real_end, Text.size() - real_end));
s.append(Text.subString(m_real_mark_end, Text.size() - m_real_mark_end));
Text = s;
m_cursor_pos = real_begin + len;
m_cursor_pos = m_real_mark_begin + 1;
} else {
// append string
s = Text.subString(0, m_cursor_pos);
@ -720,56 +765,106 @@ void GUIEditBox::inputString(const core::stringw &str)
bool GUIEditBox::processMouse(const SEvent &event)
{
switch (event.MouseInput.Event) {
case irr::EMIE_LMOUSE_LEFT_UP:
case irr::EMIE_LMOUSE_LEFT_UP: {
s32 cursor_pos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
#ifdef HAVE_TOUCHSCREENGUI
// Remove text markers for short tap in one place
if (TouchScreenGUI::isActive() && !m_long_press &&
m_cursor_press_pos == cursor_pos &&
Environment->hasFocus(this)) {
setTextMarkers(cursor_pos, cursor_pos);
}
#endif
m_cursor_press_pos = -1;
m_long_press = false;
if (Environment->hasFocus(this)) {
m_cursor_pos = getCursorPos(
event.MouseInput.X, event.MouseInput.Y);
if (m_mouse_marking) {
setTextMarkers(m_mark_begin, m_cursor_pos);
}
m_cursor_pos = cursor_pos;
m_mouse_marking = false;
calculateScrollPos();
return true;
}
break;
} break;
case irr::EMIE_MOUSE_MOVED: {
s32 cursor_pos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
#ifdef HAVE_TOUCHSCREENGUI
// Start text marking when cursor was moved, so that user doesn't want
// to copy text.
if (TouchScreenGUI::isActive() && !m_long_press && !m_mouse_marking &&
m_cursor_press_pos != -1 &&
cursor_pos != m_cursor_press_pos &&
Environment->hasFocus(this)) {
m_mouse_marking = true;
int mark_length = m_real_mark_end - m_real_mark_begin;
if (mark_length > 2 &&
std::abs(m_cursor_press_pos - m_mark_begin) < 3)
setTextMarkers(m_mark_end, m_cursor_press_pos);
else if (mark_length > 2 &&
std::abs(m_cursor_press_pos - m_mark_end) < 3)
setTextMarkers(m_mark_begin, m_cursor_press_pos);
else
setTextMarkers(m_cursor_press_pos, m_cursor_press_pos);
}
#endif
if (m_mouse_marking) {
m_cursor_pos = getCursorPos(
event.MouseInput.X, event.MouseInput.Y);
m_cursor_pos = cursor_pos;
setTextMarkers(m_mark_begin, m_cursor_pos);
calculateScrollPos();
return true;
}
} break;
case EMIE_LMOUSE_PRESSED_DOWN:
case EMIE_LMOUSE_PRESSED_DOWN: {
m_long_press = false;
if (!Environment->hasFocus(this)) {
m_blink_start_time = porting::getTimeMs();
m_mouse_marking = true;
m_cursor_pos = getCursorPos(
event.MouseInput.X, event.MouseInput.Y);
setTextMarkers(m_cursor_pos, m_cursor_pos);
m_cursor_press_pos = m_cursor_pos;
#ifdef HAVE_TOUCHSCREENGUI
if (!TouchScreenGUI::isActive() ||
m_cursor_pos < m_real_mark_begin ||
m_cursor_pos > m_real_mark_end) {
#endif
m_mouse_marking = true;
setTextMarkers(m_cursor_pos, m_cursor_pos);
#ifdef HAVE_TOUCHSCREENGUI
}
#endif
calculateScrollPos();
return true;
} else {
if (!AbsoluteClippingRect.isPointInside(core::position2d<s32>(
event.MouseInput.X, event.MouseInput.Y))) {
m_cursor_press_pos = -1;
return false;
} else {
// move cursor
m_cursor_pos = getCursorPos(
event.MouseInput.X, event.MouseInput.Y);
m_cursor_press_pos = m_cursor_pos;
s32 newMarkBegin = m_mark_begin;
if (!m_mouse_marking)
newMarkBegin = m_cursor_pos;
#ifdef HAVE_TOUCHSCREENGUI
if (!TouchScreenGUI::isActive() ||
m_cursor_pos < m_real_mark_begin ||
m_cursor_pos > m_real_mark_end) {
#endif
s32 newMarkBegin = m_mark_begin;
if (!m_mouse_marking)
newMarkBegin = m_cursor_pos;
m_mouse_marking = true;
setTextMarkers(newMarkBegin, m_cursor_pos);
m_mouse_marking = true;
setTextMarkers(newMarkBegin, m_cursor_pos);
#ifdef HAVE_TOUCHSCREENGUI
}
#endif
calculateScrollPos();
return true;
}
}
} break;
case EMIE_MOUSE_WHEEL:
if (m_vscrollbar && m_vscrollbar->isVisible()) {
s32 pos = m_vscrollbar->getPos();

View File

@ -132,6 +132,13 @@ public:
virtual bool acceptsIME() { return isEnabled() && m_writable; };
//! Sets the scrollbar texture
void setScrollbarStyle(const StyleSpec &style, ISimpleTextureSource *tsrc)
{
if (m_vscrollbar != nullptr)
m_vscrollbar->setStyle(style, tsrc);
}
protected:
virtual void breakText() = 0;
@ -179,6 +186,7 @@ protected:
u32 m_blink_start_time = 0;
s32 m_cursor_pos = 0;
s32 m_cursor_press_pos = 0;
s32 m_hscroll_pos = 0;
s32 m_vscroll_pos = 0; // scroll position in characters
u32 m_max = 0;
@ -190,9 +198,12 @@ protected:
bool m_writable;
bool m_mouse_marking = false;
bool m_long_press = false;
s32 m_mark_begin = 0;
s32 m_mark_end = 0;
s32 m_real_mark_begin = 0;
s32 m_real_mark_end = 0;
gui::IGUIFont *m_last_break_font = nullptr;
IOSOperator *m_operator = nullptr;
@ -207,7 +218,7 @@ private:
bool onKeyUp(const SEvent &event, s32 &mark_begin, s32 &mark_end);
bool onKeyDown(const SEvent &event, s32 &mark_begin, s32 &mark_end);
void onKeyControlC(const SEvent &event);
bool onKeyControlC(const SEvent &event);
bool onKeyControlX(const SEvent &event, s32 &mark_begin, s32 &mark_end);
bool onKeyControlV(const SEvent &event, s32 &mark_begin, s32 &mark_end);
bool onKeyBack(const SEvent &event, s32 &mark_begin, s32 &mark_end);

View File

@ -83,6 +83,7 @@ void GUIEditBoxWithScrollBar::draw()
return;
const bool focus = Environment->hasFocus(this);
const bool scollbar_focus = Environment->hasFocus(m_vscrollbar);
IGUISkin* skin = Environment->getSkin();
if (!skin)
@ -94,6 +95,10 @@ void GUIEditBoxWithScrollBar::draw()
default_bg_color = m_writable ? skin->getColor(EGDC_WINDOW) : video::SColor(0);
bg_color = m_bg_color_used ? m_bg_color : default_bg_color;
if (IsEnabled && m_writable) {
bg_color = focus ? skin->getColor(EGDC_FOCUSED_EDITABLE) : skin->getColor(EGDC_EDITABLE);
}
if (!m_border && m_background) {
skin->draw2DRectangle(this, bg_color, AbsoluteRect, &AbsoluteClippingRect);
}
@ -134,10 +139,8 @@ void GUIEditBoxWithScrollBar::draw()
// get mark position
const bool ml = (!m_passwordbox && (m_word_wrap || m_multiline));
const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
const s32 hline_start = ml ? getLineFromPos(realmbgn) : 0;
const s32 hline_count = ml ? getLineFromPos(realmend) - hline_start + 1 : 1;
const s32 hline_start = ml ? getLineFromPos(m_real_mark_begin) : 0;
const s32 hline_count = ml ? getLineFromPos(m_real_mark_end) - hline_start + 1 : 1;
const s32 line_count = ml ? m_broken_text.size() : 1;
// Save the override color information.
@ -187,26 +190,26 @@ void GUIEditBoxWithScrollBar::draw()
false, true, &local_clip_rect);
// draw mark and marked text
if (focus && m_mark_begin != m_mark_end && i >= hline_start && i < hline_start + hline_count) {
if ((focus || scollbar_focus) && m_mark_begin != m_mark_end && i >= hline_start && i < hline_start + hline_count) {
s32 mbegin = 0, mend = 0;
s32 lineStartPos = 0, lineEndPos = txt_line->size();
if (i == hline_start) {
// highlight start is on this line
s = txt_line->subString(0, realmbgn - start_pos);
s = txt_line->subString(0, m_real_mark_begin - start_pos);
mbegin = font->getDimension(s.c_str()).Width;
// deal with kerning
mbegin += font->getKerningWidth(
&((*txt_line)[realmbgn - start_pos]),
realmbgn - start_pos > 0 ? &((*txt_line)[realmbgn - start_pos - 1]) : 0);
&((*txt_line)[m_real_mark_begin - start_pos]),
m_real_mark_begin - start_pos > 0 ? &((*txt_line)[m_real_mark_begin - start_pos - 1]) : 0);
lineStartPos = realmbgn - start_pos;
lineStartPos = m_real_mark_begin - start_pos;
}
if (i == hline_start + hline_count - 1) {
// highlight end is on this line
s2 = txt_line->subString(0, realmend - start_pos);
s2 = txt_line->subString(0, m_real_mark_end - start_pos);
mend = font->getDimension(s2.c_str()).Width;
lineEndPos = (s32)s2.size();
} else {

View File

@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/fontengine.h"
#include "client/guiscalingfilter.h"
#include "irrlicht_changes/static_text.h"
#include "translation.h"
#if ENABLE_GLES
#include "client/tile.h"
@ -47,7 +48,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/******************************************************************************/
void TextDestGuiEngine::gotText(const StringMap &fields)
{
m_engine->getScriptIface()->handleMainMenuButtons(fields);
try {
m_engine->getScriptIface()->handleMainMenuButtons(fields);
} catch (LuaError &e) {
m_engine->handleMainMenuLuaError(e.what());
}
}
/******************************************************************************/
@ -76,6 +81,9 @@ video::ITexture *MenuTextureSource::getTexture(const std::string &name, u32 *id)
return NULL;
#if ENABLE_GLES
if (hasNPotSupport())
return m_driver->getTexture(name.c_str());
video::ITexture *retval = m_driver->findTexture(name.c_str());
if (retval)
return retval;
@ -84,10 +92,12 @@ video::ITexture *MenuTextureSource::getTexture(const std::string &name, u32 *id)
if (!image)
return NULL;
image = Align2Npot2(image, m_driver);
retval = m_driver->addTexture(name.c_str(), image);
// Verified by the profiler - it reduces memory usage!
video::IImage *newimage = Align2Npot2(image, m_driver);
retval = m_driver->addTexture(name.c_str(), newimage);
image = NULL;
m_to_delete.insert(name);
image->drop();
newimage->drop();
return retval;
#else
return m_driver->getTexture(name.c_str());
@ -151,8 +161,8 @@ GUIEngine::GUIEngine(JoystickController *joystick,
//create soundmanager
MenuMusicFetcher soundfetcher;
#if USE_SOUND
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get())
m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(), &soundfetcher);
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton)
m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton, &soundfetcher);
#endif
if (!m_sound_manager)
m_sound_manager = &dummySoundManager;
@ -191,6 +201,12 @@ GUIEngine::GUIEngine(JoystickController *joystick,
infostream << "GUIEngine: Initializing Lua" << std::endl;
// Translate the error message before clearing g_client_translations
if (!m_data->script_data.errormessage.empty())
m_data->script_data.errormessage = wide_to_utf8(translate_string(
utf8_to_wide(m_data->script_data.errormessage)));
g_client_translations->clear();
m_script = new MainMenuScripting(this);
try {
@ -204,8 +220,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
run();
} catch (LuaError &e) {
errorstream << "Main menu error: " << e.what() << std::endl;
m_data->script_data.errormessage = e.what();
handleMainMenuLuaError(e.what());
}
m_menu->quitMenu();
@ -213,6 +228,18 @@ GUIEngine::GUIEngine(JoystickController *joystick,
m_menu = NULL;
}
void GUIEngine::handleMainMenuLuaError(const char* errmsg) {
errorstream << "Main menu error: " << errmsg << std::endl;
m_data->script_data.errormessage = errmsg;
#ifdef __ANDROID__
porting::handleError("Main menu error", errmsg);
#endif
// Make the menu quit. Since an error message has been set this won't
// actually start the game.
m_startgame = true;
}
/******************************************************************************/
bool GUIEngine::loadMainMenuScript()
{
@ -231,6 +258,9 @@ bool GUIEngine::loadMainMenuScript()
} catch (const ModError &e) {
errorstream << "GUIEngine: execution of menu script failed: "
<< e.what() << std::endl;
#ifdef __ANDROID__
porting::handleError("Main menu load error", e.what());
#endif
}
return false;
@ -269,6 +299,16 @@ void GUIEngine::run()
}
while (m_rendering_engine->run() && (!m_startgame) && (!m_kill)) {
IrrlichtDevice *device = m_rendering_engine->get_raw_device();
#ifdef __IOS__
if (device->isWindowMinimized())
#else
if (!device->isWindowFocused())
#endif
{
sleep_ms(50);
continue;
}
const irr::core::dimension2d<u32> &current_screen_size =
m_rendering_engine->get_video_driver()->getScreenSize();
@ -306,7 +346,6 @@ void GUIEngine::run()
driver->endScene();
IrrlichtDevice *device = m_rendering_engine->get_raw_device();
u32 frametime_min = 1000 / (device->isWindowFocused()
? g_settings->getFloat("fps_max")
: g_settings->getFloat("fps_max_unfocused"));
@ -317,7 +356,7 @@ void GUIEngine::run()
m_script->step();
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
m_menu->getAndroidUIInput();
#endif
}
@ -499,19 +538,28 @@ void GUIEngine::drawHeader(video::IVideoDriver *driver)
v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult,
((f32)texture->getOriginalSize().Height) * mult);
#if !defined(__ANDROID__) && !defined(__IOS__)
// Don't draw the header if there isn't enough room
s32 free_space = (((s32)screensize.Height)-320)/2;
if (free_space > splashsize.Y) {
core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
((free_space/2)-splashsize.Y/2)+10);
if (free_space <= splashsize.Y)
return;
core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
((free_space/2)-splashsize.Y/2));
#else
core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
splashrect += v2s32((screensize.Width/2)-(splashsize.X/2), 0);
if (g_settings->getBool("device_is_tablet"))
splashrect += v2s32(0, splashsize.Y/4);
#endif
draw2DImageFilterScaled(driver, texture, splashrect,
core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(texture->getOriginalSize())),
NULL, NULL, true);
}
}
/******************************************************************************/
@ -614,7 +662,7 @@ void GUIEngine::updateTopLeftTextSize()
{
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
g_fontengine->getTextHeight());
rect += v2s32(4, 0);
rect += v2s32(5 + g_settings->getU16("round_screen"), 0);
m_irr_toplefttext->remove();
m_irr_toplefttext = gui::StaticText::add(m_rendering_engine->get_gui_env(),

View File

@ -159,6 +159,8 @@ public:
/** default destructor */
virtual ~GUIEngine();
void handleMainMenuLuaError(const char* errmsg);
/**
* return MainMenuScripting interface
*/

View File

@ -67,6 +67,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiScrollContainer.h"
#include "guiHyperText.h"
#include "guiScene.h"
#include "touchscreengui.h"
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
#include <SDL.h>
#endif
#define MY_CHECKPOS(a,b) \
if (v_pos.size() != 2) { \
@ -217,6 +222,10 @@ void GUIFormSpecMenu::setInitialFocus()
if (it->getType() == gui::EGUIET_EDIT_BOX
&& it->getText()[0] == 0) {
Environment->setFocus(it);
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
if (porting::hasRealKeyboard())
SDL_StartTextInput();
#endif
return;
}
}
@ -225,6 +234,10 @@ void GUIFormSpecMenu::setInitialFocus()
for (gui::IGUIElement *it : children) {
if (it->getType() == gui::EGUIET_EDIT_BOX) {
Environment->setFocus(it);
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
if (porting::hasRealKeyboard())
SDL_StartTextInput();
#endif
return;
}
}
@ -534,10 +547,15 @@ void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
pos.X + (geom.X - 1) * slot_spacing.X + slot_size.X,
pos.Y + (geom.Y - 1) * slot_spacing.Y + slot_size.Y);
video::ITexture *bgimg = style.getTexture(StyleSpec::BGIMG, m_tsrc, nullptr);
video::ITexture *bgimg_hovered = style.getTexture(StyleSpec::BGIMG_HOVERED, m_tsrc, nullptr);
video::ITexture *bgimg_pressed = style.getTexture(StyleSpec::BGIMG_PRESSED, m_tsrc, nullptr);
core::rect<s32> bgimg_middle = style.getRect(StyleSpec::BGIMG_MIDDLE, core::rect<s32>());
GUIInventoryList *e = new GUIInventoryList(Environment, data->current_parent,
spec.fid, rect, m_invmgr, loc, listname, geom, start_i,
v2s32(slot_size.X, slot_size.Y), slot_spacing, this,
data->inventorylist_options, m_font);
v2s32(slot_size.X, slot_size.Y), slot_spacing, bgimg, bgimg_hovered,
bgimg_pressed, bgimg_middle, this, data->inventorylist_options, m_font);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
@ -665,6 +683,10 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen
std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[3];
std::string value = parts[4];
std::vector<std::string> textures;
if (parts.size() == 6)
textures = split(parts[5], ',');
MY_CHECKPOS("scrollbar",0);
MY_CHECKGEOM("scrollbar",1);
@ -720,6 +742,18 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen
e->setPageSize(scrollbar_size * (max - min + 1) / data->scrollbar_options.thumb_size);
std::vector<video::ITexture *> itextures;
if (textures.empty()) {
// Fall back to the scrollbar textures specified in style[]
e->setStyle(style, m_tsrc);
} else {
for (u32 i = 0; i < textures.size(); ++i)
itextures.push_back(m_tsrc->getTexture(textures[i]));
e->setTextures(itextures);
}
if (spec.fname == m_focused_element) {
Environment->setFocus(e);
}
@ -784,101 +818,99 @@ void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
{
std::vector<std::string> parts;
if (!precheckElement("image", element, 2, 3, parts))
if (!precheckElement("image", element, 2, 4, parts))
return;
size_t offset = parts.size() >= 3;
std::vector<std::string> v_pos = split(parts[0],',');
MY_CHECKPOS("image", 0);
std::vector<std::string> v_geom;
if (parts.size() >= 3) {
std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],',');
std::string name = unescape_string(parts[2]);
MY_CHECKPOS("image", 0);
v_geom = split(parts[1],',');
MY_CHECKGEOM("image", 1);
}
v2s32 pos;
v2s32 geom;
std::string name = unescape_string(parts[1 + offset]);
video::ITexture *texture = m_tsrc->getTexture(name);
if (data->real_coordinates) {
pos = getRealCoordinateBasePos(v_pos);
geom = getRealCoordinateGeometry(v_geom);
v2s32 pos;
v2s32 geom;
if (parts.size() < 3) {
if (texture != nullptr) {
core::dimension2du dim = texture->getOriginalSize();
geom.X = dim.Width;
geom.Y = dim.Height;
} else {
pos = getElementBasePos(&v_pos);
geom = v2s32(0);
}
}
if (data->real_coordinates) {
pos = getRealCoordinateBasePos(v_pos);
if (parts.size() >= 3)
geom = getRealCoordinateGeometry(v_geom);
} else {
pos = getElementBasePos(&v_pos);
if (parts.size() >= 3) {
geom.X = stof(v_geom[0]) * (float)imgsize.X;
geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
}
if (!data->explicit_size)
warningstream<<"invalid use of image without a size[] element"<<std::endl;
video::ITexture *texture = m_tsrc->getTexture(name);
if (!texture) {
errorstream << "GUIFormSpecMenu::parseImage() Unable to load texture:"
<< std::endl << "\t" << name << std::endl;
return;
}
FieldSpec spec(
name,
L"",
L"",
258 + m_fields.size(),
1
);
core::rect<s32> rect(pos, pos + geom);
gui::IGUIImage *e = Environment->addImage(rect, data->current_parent,
spec.fid, 0, true);
e->setImage(texture);
e->setScaleImage(true);
auto style = getDefaultStyleForElement("image", spec.fname);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
m_fields.push_back(spec);
// images should let events through
e->grab();
m_clickthrough_elements.push_back(e);
return;
}
// Else: 2 arguments in "parts"
std::vector<std::string> v_pos = split(parts[0],',');
std::string name = unescape_string(parts[1]);
MY_CHECKPOS("image", 0);
v2s32 pos = getElementBasePos(&v_pos);
if (!data->explicit_size)
warningstream<<"invalid use of image without a size[] element"<<std::endl;
video::ITexture *texture = m_tsrc->getTexture(name);
if (!texture) {
errorstream << "GUIFormSpecMenu::parseImage() Unable to load texture:"
<< std::endl << "\t" << name << std::endl;
return;
}
warningstream << "Invalid use of image without a size[] element" << std::endl;
FieldSpec spec(
name,
L"",
L"",
258 + m_fields.size()
258 + m_fields.size(),
1
);
gui::IGUIImage *e = Environment->addImage(texture, pos, true,
data->current_parent, spec.fid, 0);
core::rect<s32> rect = core::rect<s32>(pos, pos + geom);
core::rect<s32> middle;
if (parts.size() >= 4)
parseMiddleRect(parts[3], &middle);
// Temporary fix for issue #12581 in 5.6.0.
// Use legacy image when not rendering 9-slice image because GUIAnimatedImage
// uses NNAA filter which causes visual artifacts when image uses alpha blending.
gui::IGUIElement *e;
if (middle.getArea() > 0) {
GUIAnimatedImage *image = new GUIAnimatedImage(Environment, data->current_parent,
spec.fid, rect);
image->setTexture(texture);
image->setMiddleRect(middle);
e = image;
}
else {
gui::IGUIImage *image = Environment->addImage(rect, data->current_parent, spec.fid, nullptr, true);
image->setImage(texture);
image->setScaleImage(true);
image->grab(); // compensate for drop in addImage
e = image;
}
auto style = getDefaultStyleForElement("image", spec.fname);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
m_fields.push_back(spec);
// images should let events through
e->grab();
// Animated images should let events through
m_clickthrough_elements.push_back(e);
m_fields.push_back(spec);
}
void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &element)
{
std::vector<std::string> parts;
if (!precheckElement("animated_image", element, 6, 7, parts))
if (!precheckElement("animated_image", element, 6, 8, parts))
return;
std::vector<std::string> v_pos = split(parts[0], ',');
@ -904,7 +936,8 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
}
if (!data->explicit_size)
warningstream << "Invalid use of animated_image without a size[] element" << std::endl;
warningstream << "Invalid use of animated_image without a size[] element"
<< std::endl;
FieldSpec spec(
name,
@ -917,9 +950,17 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
core::rect<s32> rect = core::rect<s32>(pos, pos + geom);
GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent, spec.fid,
rect, texture_name, frame_count, frame_duration, m_tsrc);
core::rect<s32> middle;
if (parts.size() >= 8)
parseMiddleRect(parts[7], &middle);
GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent,
spec.fid, rect);
e->setTexture(m_tsrc->getTexture(texture_name));
e->setMiddleRect(middle);
e->setFrameDuration(frame_duration);
e->setFrameCount(frame_count);
if (parts.size() >= 7)
e->setFrameIndex(stoi(parts[6]) - 1);
@ -1044,6 +1085,35 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
m_fields.push_back(spec);
}
bool GUIFormSpecMenu::parseMiddleRect(const std::string &value, core::rect<s32> *parsed_rect)
{
core::rect<s32> rect;
std::vector<std::string> v_rect = split(value, ',');
if (v_rect.size() == 1) {
s32 x = stoi(v_rect[0]);
rect.UpperLeftCorner = core::vector2di(x, x);
rect.LowerRightCorner = core::vector2di(-x, -x);
} else if (v_rect.size() == 2) {
s32 x = stoi(v_rect[0]);
s32 y = stoi(v_rect[1]);
rect.UpperLeftCorner = core::vector2di(x, y);
rect.LowerRightCorner = core::vector2di(-x, -y);
// `-x` is interpreted as `w - x`
} else if (v_rect.size() == 4) {
rect.UpperLeftCorner = core::vector2di(stoi(v_rect[0]), stoi(v_rect[1]));
rect.LowerRightCorner = core::vector2di(stoi(v_rect[2]), stoi(v_rect[3]));
} else {
warningstream << "Invalid rectangle string format: \"" << value
<< "\"" << std::endl;
return false;
}
*parsed_rect = rect;
return true;
}
void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &element)
{
std::vector<std::string> parts;
@ -1085,25 +1155,8 @@ void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &eleme
}
core::rect<s32> middle;
if (parts.size() >= 5) {
std::vector<std::string> v_middle = split(parts[4], ',');
if (v_middle.size() == 1) {
s32 x = stoi(v_middle[0]);
middle.UpperLeftCorner = core::vector2di(x, x);
middle.LowerRightCorner = core::vector2di(-x, -x);
} else if (v_middle.size() == 2) {
s32 x = stoi(v_middle[0]);
s32 y = stoi(v_middle[1]);
middle.UpperLeftCorner = core::vector2di(x, y);
middle.LowerRightCorner = core::vector2di(-x, -y);
// `-x` is interpreted as `w - x`
} else if (v_middle.size() == 4) {
middle.UpperLeftCorner = core::vector2di(stoi(v_middle[0]), stoi(v_middle[1]));
middle.LowerRightCorner = core::vector2di(stoi(v_middle[2]), stoi(v_middle[3]));
} else {
warningstream << "Invalid rectangle given to middle param of background[] element" << std::endl;
}
}
if (parts.size() >= 5)
parseMiddleRect(parts[4], &middle);
if (!data->explicit_size && !clip)
warningstream << "invalid use of unclipped background without a size[] element" << std::endl;
@ -1233,8 +1286,7 @@ void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element)
e->setSelected(stoi(str_initial_selection));
auto style = getDefaultStyleForElement("table", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->setOverrideFont(style.getFont());
e->setStyle(style);
m_tables.emplace_back(spec, e);
m_fields.push_back(spec);
@ -1307,8 +1359,7 @@ void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element
e->setSelected(stoi(str_initial_selection));
auto style = getDefaultStyleForElement("textlist", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->setOverrideFont(style.getFont());
e->setStyle(style);
m_tables.emplace_back(spec, e);
m_fields.push_back(spec);
@ -1414,6 +1465,10 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[2];
std::string label = parts[3];
std::string default_val;
if (parts.size() > 4)
default_val = parts[4];
MY_CHECKPOS("pwdfield",0);
MY_CHECKGEOM("pwdfield",1);
@ -1437,19 +1492,23 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
if (m_form_src && !default_val.empty())
default_val = m_form_src->resolveText(default_val);
std::wstring wlabel = translate_string(utf8_to_wide(unescape_string(label)));
std::wstring wpassword = utf8_to_wide(unescape_string(default_val));
FieldSpec spec(
name,
wlabel,
L"",
wpassword,
258 + m_fields.size(),
0,
ECI_IBEAM
);
spec.send = true;
gui::IGUIEditBox *e = Environment->addEditBox(0, rect, true,
gui::IGUIEditBox *e = Environment->addEditBox(wpassword.c_str(), rect, true,
data->current_parent, spec.fid);
if (spec.fname == m_focused_element) {
@ -1470,6 +1529,9 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->setDrawBorder(style.getBool(StyleSpec::BORDER, true));
e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF)));
if (style.get(StyleSpec::BGCOLOR, "") == "transparent") {
e->setDrawBackground(false);
}
e->setOverrideFont(style.getFont());
irr::SEvent evt;
@ -1506,10 +1568,12 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec,
spec.flabel.swap(spec.fdefault);
}
GUIEditBox *box = nullptr;
gui::IGUIEditBox *e = nullptr;
if (is_multiline) {
e = new GUIEditBoxWithScrollBar(spec.fdefault.c_str(), true, Environment,
data->current_parent, spec.fid, rect, is_editable, true);
box = new GUIEditBoxWithScrollBar(spec.fdefault.c_str(), true, Environment,
data->current_parent, spec.fid, rect, is_editable, !is_editable);
e = box;
} else if (is_editable) {
e = Environment->addEditBox(spec.fdefault.c_str(), rect, true,
data->current_parent, spec.fid);
@ -1543,6 +1607,8 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec,
e->setDrawBorder(border);
e->setDrawBackground(border);
e->setOverrideFont(style.getFont());
if (box != nullptr)
box->setScrollbarStyle(style, m_tsrc);
e->drop();
}
@ -1566,6 +1632,8 @@ void GUIFormSpecMenu::parseSimpleField(parserData *data,
std::string label = parts[1];
std::string default_val = parts[2];
bool is_dynamic = (name.length() > 0 && name[0] == 'D');
core::rect<s32> rect;
if (data->explicit_size)
@ -1596,6 +1664,8 @@ void GUIFormSpecMenu::parseSimpleField(parserData *data,
ECI_IBEAM
);
spec.is_dynamic = is_dynamic;
createTextField(data, spec, rect, false);
m_fields.push_back(spec);
@ -1612,6 +1682,8 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
std::string label = parts[3];
std::string default_val = parts[4];
bool is_dynamic = (name.length() > 0 && name[0] == 'D');
MY_CHECKPOS(type,0);
MY_CHECKGEOM(type,1);
@ -1660,6 +1732,8 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
ECI_IBEAM
);
spec.is_dynamic = is_dynamic;
createTextField(data, spec, rect, type == "textarea");
// Note: Before 5.2.0 "parts.size() >= 6" resulted in a
@ -1733,7 +1807,7 @@ void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &elemen
spec.sound = style.get(StyleSpec::Property::SOUND, "");
GUIHyperText *e = new GUIHyperText(spec.flabel.c_str(), Environment,
data->current_parent, spec.fid, rect, m_client, m_tsrc);
data->current_parent, spec.fid, rect, m_client, m_tsrc, style);
e->drop();
m_fields.push_back(spec);
@ -3247,10 +3321,34 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
double fitx_imgsize;
double fity_imgsize;
#if defined(__ANDROID__) || defined(__IOS__)
v2f padded_screensize(
mydata.screensize.X,
mydata.screensize.Y
);
// Try and find a tabheader[] element in the formspec
for (unsigned int j = i; j < elements.size(); j++) {
// This could use split() but since we don't parse parameters
// here it's probably faster to use find().
const size_t pos = elements[j].find('[');
if (pos == std::string::npos)
continue;
// If we find a tabheader then decrease padded_screensize.Y and
// stop searching through the formspec.
const std::string element_type = trim(elements[j].substr(0, pos));
if (element_type == "tabheader") {
padded_screensize.Y *= 0.9f;
break;
}
}
#else
v2f padded_screensize(
mydata.screensize.X * (1.0f - mydata.padding.X * 2.0f),
mydata.screensize.Y * (1.0f - mydata.padding.Y * 2.0f)
);
#endif
if (mydata.real_coordinates) {
fitx_imgsize = padded_screensize.X / mydata.invsize.X;
@ -3271,6 +3369,10 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
// In Android, the preferred imgsize should be larger to accommodate the
// smaller screensize.
double prefer_imgsize = min_screen_dim / 10 * gui_scaling;
// Try to fit 13 coordinates on large tablets.
if (g_settings->getBool("device_is_tablet"))
prefer_imgsize = min_screen_dim / 13 * gui_scaling;
#else
// Desktop computers have more space, so try to fit 15 coordinates.
double prefer_imgsize = min_screen_dim / 15 * gui_scaling;
@ -3476,10 +3578,10 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro
}
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool GUIFormSpecMenu::getAndroidUIInput()
{
if (!hasAndroidUIInput())
if (m_jni_field_name.empty())
return false;
// still waiting
@ -3500,6 +3602,17 @@ bool GUIFormSpecMenu::getAndroidUIInput()
std::string text = porting::getInputDialogValue();
((gui::IGUIEditBox *)element)->setText(utf8_to_wide(text).c_str());
// Create event
gui::IGUIElement *focus = Environment->getFocus();
if (focus) {
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = focus;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = gui::EGET_EDITBOX_CHANGED;
element->OnEvent(e);
}
}
return false;
}
@ -3631,9 +3744,12 @@ void GUIFormSpecMenu::drawMenu()
}
/* TODO find way to show tooltips on touchscreen */
#ifndef HAVE_TOUCHSCREENGUI
m_pointer = RenderingEngine::get_raw_device()->getCursorControl()->getPosition();
#ifdef HAVE_TOUCHSCREENGUI
if (!TouchScreenGUI::isActive())
#endif
{
m_pointer = RenderingEngine::get_raw_device()->getCursorControl()->getPosition();
}
/*
Draw fields/buttons tooltips and update the mouse cursor
@ -3641,11 +3757,9 @@ void GUIFormSpecMenu::drawMenu()
gui::IGUIElement *hovered =
Environment->getRootGUIElement()->getElementFromPoint(m_pointer);
#ifndef HAVE_TOUCHSCREENGUI
gui::ICursorControl *cursor_control = RenderingEngine::get_raw_device()->
getCursorControl();
gui::ECURSOR_ICON current_cursor_icon = cursor_control->getActiveIcon();
#endif
bool hovered_element_found = false;
if (hovered != NULL) {
@ -3681,11 +3795,9 @@ void GUIFormSpecMenu::drawMenu()
m_tooltips[field.fname].bgcolor);
}
#ifndef HAVE_TOUCHSCREENGUI
if (field.ftype != f_HyperText && // Handled directly in guiHyperText
current_cursor_icon != field.fcursor_icon)
cursor_control->setActiveIcon(field.fcursor_icon);
#endif
hovered_element_found = true;
@ -3696,10 +3808,8 @@ void GUIFormSpecMenu::drawMenu()
if (!hovered_element_found) {
// no element is hovered
#ifndef HAVE_TOUCHSCREENGUI
if (current_cursor_icon != ECI_NORMAL)
cursor_control->setActiveIcon(ECI_NORMAL);
#endif
}
m_tooltip_element->draw();
@ -3731,14 +3841,12 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text,
int tooltip_offset_x = m_btn_height;
int tooltip_offset_y = m_btn_height;
#ifdef HAVE_TOUCHSCREENGUI
tooltip_offset_x *= 3;
tooltip_offset_y = 0;
if (m_pointer.X > (s32)screenSize.X / 2)
tooltip_offset_x = -(tooltip_offset_x + tooltip_width);
// Hide tooltip after ETIE_LEFT_UP
if (m_pointer.X == 0)
return;
if (TouchScreenGUI::isActive()) {
tooltip_offset_x *= 3;
tooltip_offset_y = 0;
if (m_pointer.X > (s32)screenSize.X / 2)
tooltip_offset_x = -(tooltip_offset_x + tooltip_width);
}
#endif
// Calculate and set the tooltip position
@ -4081,6 +4189,15 @@ enum ButtonEventType : u8
BET_OTHER
};
void GUIFormSpecMenu::clearSelection()
{
m_selected_swap.clear();
delete m_selected_item;
m_selected_item = nullptr;
m_selected_amount = 0;
m_selected_dragging = false;
}
bool GUIFormSpecMenu::OnEvent(const SEvent& event)
{
if (event.EventType==EET_KEY_INPUT_EVENT) {
@ -4268,7 +4385,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
count = MYMIN(s_count, 10);
else if (button == BET_WHEEL_DOWN)
count = 1;
else // left
else // left
count = s_count;
if (!event.MouseInput.Shift) {
@ -4290,8 +4407,14 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
move_amount = 1;
else if (button == BET_MIDDLE)
move_amount = MYMIN(m_selected_amount, 10);
else if (button == BET_LEFT)
else if (button == BET_LEFT) {
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui && g_touchscreengui->isActive() && s.listname == "craft")
move_amount = 1;
else
#endif
move_amount = m_selected_amount;
}
// else wheeldown
if (identical) {
@ -4515,6 +4638,9 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
if (event.EventType == EET_GUI_EVENT) {
if (event.GUIEvent.EventType == gui::EGET_TAB_CHANGED
&& isVisible()) {
// reset selection
clearSelection();
// find the element that was clicked
for (GUIFormSpecMenu::FieldSpec &s : m_fields) {
if ((s.ftype == f_TabHeader) &&
@ -4541,8 +4667,10 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
(event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED) ||
(event.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED) ||
(event.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED)) {
s32 caller_id = event.GUIEvent.Caller->getID();
// reset selection
clearSelection();
s32 caller_id = event.GUIEvent.Caller->getID();
if (caller_id == 257) {
if (m_allowclose) {
acceptInput(quit_mode_accept);
@ -4651,14 +4779,19 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
}
}
if (event.GUIEvent.EventType == gui::EGET_TABLE_CHANGED) {
if (event.GUIEvent.EventType == gui::EGET_TABLE_CHANGED ||
event.GUIEvent.EventType == gui::EGET_EDITBOX_CHANGED) {
// reset selection
clearSelection();
int current_id = event.GUIEvent.Caller->getID();
if (current_id > 257) {
// find the element that was clicked
// find the element that was clicked or changed
for (GUIFormSpecMenu::FieldSpec &s : m_fields) {
// if it's a table, set the send field
// so lua knows which table was changed
if ((s.ftype == f_Table) && (s.fid == current_id)) {
if ((s.ftype == f_Table && s.fid == current_id) ||
(s.ftype == f_Unknown && s.is_dynamic && s.fid == current_id)) {
s.send = true;
acceptInput();
s.send=false;

View File

@ -113,6 +113,7 @@ class GUIFormSpecMenu : public GUIModalMenu
ftype(f_Unknown),
is_exit(false),
priority(priority),
is_dynamic(false),
fcursor_icon(cursor_icon)
{
}
@ -126,6 +127,7 @@ class GUIFormSpecMenu : public GUIModalMenu
bool is_exit;
// Draw priority for formspec version < 3
int priority;
bool is_dynamic;
core::rect<s32> rect;
gui::ECURSOR_ICON fcursor_icon;
std::string sound;
@ -257,6 +259,7 @@ public:
void acceptInput(FormspecQuitMode quitmode=quit_mode_no);
bool preprocessEvent(const SEvent& event);
void clearSelection();
bool OnEvent(const SEvent& event);
bool doPause;
bool pausesGame() { return doPause; }
@ -264,7 +267,7 @@ public:
GUITable* getTable(const std::string &tablename);
std::vector<std::string>* getDropDownValues(const std::string &name);
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool getAndroidUIInput();
#endif
@ -456,6 +459,8 @@ private:
void parseSetFocus(const std::string &element);
void parseModel(parserData *data, const std::string &element);
bool parseMiddleRect(const std::string &value, core::rect<s32> *parsed_rect);
void tryClose();
void showTooltip(const std::wstring &text, const irr::video::SColor &color,

View File

@ -990,7 +990,7 @@ void TextDrawer::draw(const core::rect<s32> &clip_rect,
//! constructor
GUIHyperText::GUIHyperText(const wchar_t *text, IGUIEnvironment *environment,
IGUIElement *parent, s32 id, const core::rect<s32> &rectangle,
Client *client, ISimpleTextureSource *tsrc) :
Client *client, ISimpleTextureSource *tsrc, const StyleSpec &style) :
IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
m_client(client), m_vscrollbar(nullptr),
m_drawer(text, client, environment, tsrc), m_text_scrollpos(0, 0)
@ -1012,6 +1012,7 @@ GUIHyperText::GUIHyperText(const wchar_t *text, IGUIEnvironment *environment,
m_vscrollbar = new GUIScrollBar(Environment, this, -1, rect, false, true);
m_vscrollbar->setVisible(false);
m_vscrollbar->setStyle(style, tsrc);
}
//! destructor

View File

@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
#include "StyleSpec.h"
#include <vector>
#include <list>
#include <unordered_map>
@ -202,7 +203,7 @@ public:
GUIHyperText(const wchar_t *text, gui::IGUIEnvironment *environment,
gui::IGUIElement *parent, s32 id,
const core::rect<s32> &rectangle, Client *client,
ISimpleTextureSource *tsrc);
ISimpleTextureSource *tsrc, const StyleSpec &style);
//! destructor
virtual ~GUIHyperText();

View File

@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiInventoryList.h"
#include "guiFormSpecMenu.h"
#include "client/guiscalingfilter.h"
#include "client/hud.h"
#include "client/client.h"
@ -33,6 +34,10 @@ GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env,
const s32 start_item_i,
const v2s32 &slot_size,
const v2f32 &slot_spacing,
video::ITexture* slotbg_n_texture,
video::ITexture* slotbg_h_texture,
video::ITexture* slotbg_p_texture,
const core::rect<s32> &slotbg_middle,
GUIFormSpecMenu *fs_menu,
const Options &options,
gui::IGUIFont *font) :
@ -44,10 +49,15 @@ GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env,
m_start_item_i(start_item_i),
m_slot_size(slot_size),
m_slot_spacing(slot_spacing),
m_slotbg_n_texture(slotbg_n_texture),
m_slotbg_h_texture(slotbg_h_texture),
m_slotbg_p_texture(slotbg_p_texture),
m_slotbg_middle(slotbg_middle),
m_fs_menu(fs_menu),
m_options(options),
m_font(font),
m_hovered_i(-1),
m_pressed(false),
m_already_warned(false)
{
}
@ -109,34 +119,56 @@ void GUIInventoryList::draw()
(hovering ? IT_ROT_HOVERED : IT_ROT_NONE);
// layer 0
if (hovering) {
driver->draw2DRectangle(m_options.slotbg_h, rect, &AbsoluteClippingRect);
} else {
driver->draw2DRectangle(m_options.slotbg_n, rect, &AbsoluteClippingRect);
}
if (m_slotbg_n_texture) {
video::ITexture *texture = m_slotbg_n_texture;
if (hovering) {
if (m_pressed && m_slotbg_p_texture)
texture = m_slotbg_p_texture;
else if (m_slotbg_h_texture)
texture = m_slotbg_h_texture;
}
// Draw inv slot borders
if (m_options.slotborder) {
s32 x1 = rect.UpperLeftCorner.X;
s32 y1 = rect.UpperLeftCorner.Y;
s32 x2 = rect.LowerRightCorner.X;
s32 y2 = rect.LowerRightCorner.Y;
s32 border = 1;
core::rect<s32> clipping_rect = Parent ? Parent->getAbsoluteClippingRect()
: core::rect<s32>();
core::rect<s32> *clipping_rect_ptr = Parent ? &clipping_rect : nullptr;
driver->draw2DRectangle(m_options.slotbordercolor,
core::rect<s32>(v2s32(x1 - border, y1 - border),
v2s32(x2 + border, y1)), clipping_rect_ptr);
driver->draw2DRectangle(m_options.slotbordercolor,
core::rect<s32>(v2s32(x1 - border, y2),
v2s32(x2 + border, y2 + border)), clipping_rect_ptr);
driver->draw2DRectangle(m_options.slotbordercolor,
core::rect<s32>(v2s32(x1 - border, y1),
v2s32(x1, y2)), clipping_rect_ptr);
driver->draw2DRectangle(m_options.slotbordercolor,
core::rect<s32>(v2s32(x2, y1),
v2s32(x2 + border, y2)), clipping_rect_ptr);
core::rect<s32> srcrect(core::position2d<s32>(0, 0),
core::dimension2di(texture->getOriginalSize()));
if (m_slotbg_middle.getArea() == 0) {
const video::SColor color(255, 255, 255, 255);
const video::SColor colors[] = {color, color, color, color};
draw2DImageFilterScaled(driver, texture, rect, srcrect,
&AbsoluteClippingRect, colors, true);
} else {
draw2DImage9Slice(driver, texture, rect, srcrect, m_slotbg_middle,
&AbsoluteClippingRect);
}
} else {
if (hovering) {
driver->draw2DRectangle(m_options.slotbg_h, rect, &AbsoluteClippingRect);
} else {
driver->draw2DRectangle(m_options.slotbg_n, rect, &AbsoluteClippingRect);
}
// Draw inv slot borders
if (m_options.slotborder) {
s32 x1 = rect.UpperLeftCorner.X;
s32 y1 = rect.UpperLeftCorner.Y;
s32 x2 = rect.LowerRightCorner.X;
s32 y2 = rect.LowerRightCorner.Y;
s32 border = 1;
core::rect<s32> clipping_rect = Parent ? Parent->getAbsoluteClippingRect()
: core::rect<s32>();
core::rect<s32> *clipping_rect_ptr = Parent ? &clipping_rect : nullptr;
driver->draw2DRectangle(m_options.slotbordercolor,
core::rect<s32>(v2s32(x1 - border, y1 - border),
v2s32(x2 + border, y1)), clipping_rect_ptr);
driver->draw2DRectangle(m_options.slotbordercolor,
core::rect<s32>(v2s32(x1 - border, y2),
v2s32(x2 + border, y2 + border)), clipping_rect_ptr);
driver->draw2DRectangle(m_options.slotbordercolor,
core::rect<s32>(v2s32(x1 - border, y1),
v2s32(x1, y2)), clipping_rect_ptr);
driver->draw2DRectangle(m_options.slotbordercolor,
core::rect<s32>(v2s32(x2, y1),
v2s32(x2 + border, y2)), clipping_rect_ptr);
}
}
// layer 1
@ -173,8 +205,15 @@ bool GUIInventoryList::OnEvent(const SEvent &event)
m_hovered_i = getItemIndexAtPos(v2s32(event.MouseInput.X, event.MouseInput.Y));
if (m_hovered_i != -1)
if (m_hovered_i != -1) {
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
m_pressed = true;
else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
m_pressed = false;
return IGUIElement::OnEvent(event);
}
m_pressed = false;
// no item slot at pos of mouse event => allow clicking through
// find the element that would be hovered if this inventorylist was invisible

View File

@ -69,6 +69,10 @@ public:
const s32 start_item_i,
const v2s32 &slot_size,
const v2f32 &slot_spacing,
video::ITexture* slotbg_n_texture,
video::ITexture* slotbg_h_texture,
video::ITexture* slotbg_p_texture,
const core::rect<s32> &slotbg_middle,
GUIFormSpecMenu *fs_menu,
const Options &options,
gui::IGUIFont *font);
@ -117,6 +121,12 @@ private:
// specifies how large the space between slots is (space between is spacing-size)
const v2f32 m_slot_spacing;
// Slot textures
video::ITexture* m_slotbg_n_texture;
video::ITexture* m_slotbg_h_texture;
video::ITexture* m_slotbg_p_texture;
core::rect<s32> m_slotbg_middle;
// the GUIFormSpecMenu can have an item selected and co.
GUIFormSpecMenu *m_fs_menu;
@ -128,6 +138,9 @@ private:
// the index of the hovered item; -1 if no item is hovered
s32 m_hovered_i;
// Whether the hovered item is being pressed
bool m_pressed;
// we do not want to write a warning on every draw
bool m_already_warned;
};

View File

@ -21,6 +21,7 @@
#include "guiKeyChangeMenu.h"
#include "debug.h"
#include "guiBackgroundImage.h"
#include "guiButton.h"
#include "serialization.h"
#include <string>
@ -29,10 +30,14 @@
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "filesys.h"
#include "porting.h"
#include "settings.h"
#include "StyleSpec.h"
#include <algorithm>
#include "mainmenumanager.h" // for g_gamecallback
#include "client/renderingengine.h"
#define KMaxButtonPerColumns 12
@ -41,6 +46,7 @@ extern MainGameCallback *g_gamecallback;
enum
{
GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
GUI_ID_BACKGROUND_IMG,
// buttons
GUI_ID_KEY_FORWARD_BUTTON,
GUI_ID_KEY_BACKWARD_BUTTON,
@ -84,11 +90,21 @@ enum
GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
ISimpleTextureSource *tsrc) :
ISimpleTextureSource *tsrc, bool main_menu) :
GUIModalMenu(env, parent, id, menumgr),
m_tsrc(tsrc)
m_tsrc(tsrc),
m_main_menu(main_menu)
{
init_keys();
if (m_main_menu) return;
v3f formspec_bgcolor = g_settings->getV3F("formspec_fullscreen_bg_color");
m_fullscreen_bgcolor = video::SColor(
(u8) MYMIN(MYMAX(g_settings->getS32("formspec_fullscreen_bg_opacity"), 0), 255),
MYMIN(MYMAX(myround(formspec_bgcolor.X), 0), 255),
MYMIN(MYMAX(myround(formspec_bgcolor.Y), 0), 255),
MYMIN(MYMAX(myround(formspec_bgcolor.Z), 0), 255)
);
}
GUIKeyChangeMenu::~GUIKeyChangeMenu()
@ -120,7 +136,20 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
removeChildren();
const float s = m_gui_scale;
float s = MYMIN(screensize.X / 835.f, screensize.Y / 430.f);
#if HAVE_TOUCHSCREENGUI
s *= g_settings->getBool("device_is_tablet") ? 0.8f : 0.9f;
#else
s *= 0.75f;
#endif
// Make sure the GUI will fit on the screen
// The change keys GUI is 835x430 pixels (with a scaling of 1)
if (835 * s > screensize.X)
s = screensize.X / 835.f;
if (430 * s > screensize.Y)
s = screensize.Y / 430.f;
DesiredRect = core::rect<s32>(
screensize.X / 2 - 835 * s / 2,
screensize.Y / 2 - 430 * s / 2,
@ -132,11 +161,29 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
v2s32 size = DesiredRect.getSize();
v2s32 topleft(0, 0);
std::string texture_path = "";
if (m_main_menu)
texture_path = porting::path_share + DIR_DELIM "textures" DIR_DELIM
"base" DIR_DELIM "pack" DIR_DELIM;
// Background image
{
core::rect<s32> rect(0, 0, 600 * s, 40 * s);
rect += topleft + v2s32(25 * s, 3 * s);
const std::string texture = texture_path + "bg_common.png";
const core::rect<s32> rect(0, 0, 0, 0);
const core::rect<s32> middle(40, 40, -40, -40);
new GUIBackgroundImage(Environment, this, GUI_ID_BACKGROUND_IMG, rect,
texture, middle, m_tsrc, true);
}
{
core::rect<s32> rect(0, 0, 795 * s, 50 * s);
rect += topleft + v2s32(25 * s, 10 * s);
//gui::IGUIStaticText *t =
const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
#if !defined(__ANDROID__) && !defined(__IOS__)
const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from multicraft.conf)");
#else
const wchar_t *text = wgettext("Change Keys");
#endif
Environment->addStaticText(text,
rect, false, true, this, -1);
delete[] text;
@ -174,7 +221,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
s32 option_x = offset.X;
s32 option_y = offset.Y + 5 * s;
u32 option_w = 180 * s;
u32 option_w = 300 * s;
{
core::rect<s32> rect(0, 0, option_w, 30 * s);
rect += topleft + v2s32(option_x, option_y);
@ -189,7 +236,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
s32 option_x = offset.X;
s32 option_y = offset.Y + 5 * s;
u32 option_w = 280 * s;
u32 option_w = 300 * s;
{
core::rect<s32> rect(0, 0, option_w, 30 * s);
rect += topleft + v2s32(option_x, option_y);
@ -204,7 +251,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
s32 option_x = offset.X;
s32 option_y = offset.Y + 5 * s;
u32 option_w = 280;
u32 option_w = 300 * s;
{
core::rect<s32> rect(0, 0, option_w, 30 * s);
rect += topleft + v2s32(option_x, option_y);
@ -216,18 +263,23 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
offset += v2s32(0, 25);
}
const std::array<StyleSpec, StyleSpec::NUM_STATES> styles =
StyleSpec::getButtonStyle(texture_path);
{
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
const wchar_t *text = wgettext("Save");
GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
core::rect<s32> rect(0, 0, 150 * s, 35 * s);
rect += topleft + v2s32(size.X / 2 - 165 * s, size.Y - 50 * s);
const wchar_t *text = wgettext("Save");
GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
e->setStyles(styles);
delete[] text;
}
{
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
core::rect<s32> rect(0, 0, 150 * s, 35 * s);
rect += topleft + v2s32(size.X / 2 + 15 * s, size.Y - 50 * s);
const wchar_t *text = wgettext("Cancel");
GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
e->setStyles(styles);
delete[] text;
}
}
@ -237,10 +289,13 @@ void GUIKeyChangeMenu::drawMenu()
gui::IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
video::IVideoDriver* driver = Environment->getVideoDriver();
video::SColor bgcolor(140, 0, 0, 0);
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
if (!m_main_menu) {
video::IVideoDriver* driver = Environment->getVideoDriver();
v2u32 screenSize = driver->getScreenSize();
core::rect<s32> allbg(0, 0, screenSize.X, screenSize.Y);
driver->draw2DRectangle(m_fullscreen_bgcolor, allbg, &allbg);
}
gui::IGUIElement::draw();
}
@ -277,6 +332,9 @@ bool GUIKeyChangeMenu::acceptInput()
g_gamecallback->signalKeyConfigChange();
if (!g_settings_path.empty())
g_settings->updateConfigFile(g_settings_path.c_str());
return true;
}
@ -296,7 +354,7 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
if (event.EventType == EET_KEY_INPUT_EVENT && active_key
&& event.KeyInput.PressedDown) {
bool prefer_character = shift_down;
bool prefer_character = shift_down && event.KeyInput.Char != 0;
KeyPress kp(event.KeyInput, prefer_character);
if (event.KeyInput.Key == irr::KEY_DELETE)
@ -355,6 +413,13 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
&& event.KeyInput.Key == irr::KEY_ESCAPE) {
quitMenu();
return true;
} else if (event.EventType == EET_KEY_INPUT_EVENT &&
!event.KeyInput.PressedDown) {
if (shift_down && !event.KeyInput.Shift) {
shift_down = false;
active_key = nullptr;
return true;
}
} else if (event.EventType == EET_GUI_EVENT) {
if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
&& isVisible())

View File

@ -43,7 +43,8 @@ class GUIKeyChangeMenu : public GUIModalMenu
{
public:
GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
IMenuManager *menumgr, ISimpleTextureSource *tsrc);
IMenuManager *menumgr, ISimpleTextureSource *tsrc,
bool main_menu = false);
~GUIKeyChangeMenu();
void removeChildren();
@ -77,4 +78,7 @@ private:
gui::IGUIStaticText *key_used_text = nullptr;
std::vector<key_setting *> key_settings;
ISimpleTextureSource *m_tsrc;
bool m_main_menu = false;
video::SColor m_fullscreen_bgcolor;
};

View File

@ -12,16 +12,18 @@ the arrow buttons where there is insufficient space.
#include "guiScrollBar.h"
#include <IGUIButton.h>
#include <IGUISkin.h>
#include <IGUIImage.h>
GUIScrollBar::GUIScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
core::rect<s32> rectangle, bool horizontal, bool auto_scale) :
IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
up_button(nullptr), down_button(nullptr), is_dragging(false),
is_horizontal(horizontal), is_auto_scaling(auto_scale),
dragged_by_slider(false), tray_clicked(false), scroll_pos(0),
draw_center(0), thumb_size(0), min_pos(0), max_pos(100), small_step(10),
large_step(50), drag_offset(0), page_size(100), border_size(0)
up_button(nullptr), down_button(nullptr), bg_image(nullptr),
slider_image(nullptr), slider_top_image(nullptr),
slider_bottom_image(nullptr), is_dragging(false), is_horizontal(horizontal),
is_auto_scaling(auto_scale), dragged_by_slider(false),
tray_clicked(false), scroll_pos(0), draw_center(0), thumb_size(0),
min_pos(0), max_pos(100), small_step(10), large_step(50),
drag_offset(0), page_size(100), border_size(0)
{
refreshControls();
setNotClipped(false);
@ -193,6 +195,14 @@ bool GUIScrollBar::OnEvent(const SEvent &event)
return IGUIElement::OnEvent(event);
}
gui::IGUIImage* GUIScrollBar::addImage(const core::rect<s32> &rect, video::ITexture *texture)
{
gui::IGUIImage *e = Environment->addImage(rect, this);
e->setImage(texture);
e->setScaleImage(true);
return e;
}
void GUIScrollBar::draw()
{
if (!IsVisible)
@ -208,10 +218,26 @@ void GUIScrollBar::draw()
refreshControls();
slider_rect = AbsoluteRect;
skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR), slider_rect,
&AbsoluteClippingRect);
if (core::isnotzero(range())) {
if (m_textures.size() >= 1) {
s32 w = RelativeRect.getWidth();
s32 h = RelativeRect.getHeight();
core::rect<s32> rect{0, w, w, h - w};
if (is_horizontal)
rect = {h, 0, w - h, h};
if (!bg_image)
bg_image = addImage(rect, m_textures[0]);
else
bg_image->setRelativePosition(rect);
} else {
skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR),
slider_rect, &AbsoluteClippingRect);
}
// Always show scrollbar thumb
//if (core::isnotzero(range())) {
if (is_horizontal) {
slider_rect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X +
draw_center - thumb_size / 2;
@ -223,8 +249,42 @@ void GUIScrollBar::draw()
slider_rect.LowerRightCorner.Y =
slider_rect.UpperLeftCorner.Y + thumb_size;
}
skin->draw3DButtonPaneStandard(this, slider_rect, &AbsoluteClippingRect);
}
if (m_textures.size() >= 2) {
s32 w = slider_rect.getWidth();
s32 h = slider_rect.getHeight();
core::rect<s32> rect{0, draw_center - (h / 2), w, draw_center + h - (h / 2)};
if (is_horizontal)
rect = {draw_center - (w / 2), 0, draw_center + w - (w / 2), h};
if (!slider_image)
slider_image = addImage(rect, m_textures[1]);
else
slider_image->setRelativePosition(rect);
// Add top and bottom images if required
// TODO: Horizontal scrollbars
if (m_textures.size() >= 6 && !is_horizontal) {
core::rect<s32> top_rect = rect;
top_rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + w / 2;
if (!slider_top_image)
slider_top_image = addImage(top_rect, m_textures[4]);
else
slider_top_image->setRelativePosition(top_rect);
core::rect<s32> bottom_rect = rect;
bottom_rect.UpperLeftCorner.Y = rect.LowerRightCorner.Y - w / 2;
if (!slider_bottom_image)
slider_bottom_image = addImage(bottom_rect, m_textures[5]);
else
slider_bottom_image->setRelativePosition(bottom_rect);
}
} else {
skin->draw3DButtonPaneStandard(this, slider_rect, &AbsoluteClippingRect);
}
//}
IGUIElement::draw();
}
@ -327,6 +387,34 @@ s32 GUIScrollBar::getPos() const
return scroll_pos;
}
void GUIScrollBar::setTextures(const std::vector<video::ITexture *> &textures)
{
m_textures = textures;
refreshControls();
};
void GUIScrollBar::setStyle(const StyleSpec &style, ISimpleTextureSource *tsrc)
{
if (style.isNotDefault(StyleSpec::SCROLLBAR_BGIMG) &&
style.isNotDefault(StyleSpec::SCROLLBAR_THUMB_IMG) &&
style.isNotDefault(StyleSpec::SCROLLBAR_UP_IMG) &&
style.isNotDefault(StyleSpec::SCROLLBAR_DOWN_IMG)) {
arrow_visibility = ArrowVisibility::SHOW;
std::vector<video::ITexture *> textures = {
style.getTexture(StyleSpec::SCROLLBAR_BGIMG, tsrc),
style.getTexture(StyleSpec::SCROLLBAR_THUMB_IMG, tsrc),
style.getTexture(StyleSpec::SCROLLBAR_UP_IMG, tsrc),
style.getTexture(StyleSpec::SCROLLBAR_DOWN_IMG, tsrc)
};
if (style.isNotDefault(StyleSpec::SCROLLBAR_THUMB_TOP_IMG) &&
style.isNotDefault(StyleSpec::SCROLLBAR_THUMB_BOTTOM_IMG)) {
textures.push_back(style.getTexture(StyleSpec::SCROLLBAR_THUMB_TOP_IMG, tsrc));
textures.push_back(style.getTexture(StyleSpec::SCROLLBAR_THUMB_BOTTOM_IMG, tsrc));
}
setTextures(textures);
}
}
void GUIScrollBar::refreshControls()
{
IGUISkin *skin = Environment->getSkin();
@ -342,13 +430,21 @@ void GUIScrollBar::refreshControls()
if (is_horizontal) {
s32 h = RelativeRect.getHeight();
border_size = RelativeRect.getWidth() < h * 4 ? 0 : h;
if (!up_button) {
up_button = Environment->addButton(
core::rect<s32>(0, 0, h, h), this);
up_button->setSubElement(true);
up_button->setTabStop(false);
}
if (sprites) {
if (m_textures.size() >= 3) {
up_button->setImage(m_textures[2]);
up_button->setScaleImage(true);
up_button->setDrawBorder(false);
up_button->setUseAlphaChannel(true);
up_button->setSpriteBank(nullptr);
} else if (sprites) {
up_button->setSpriteBank(sprites);
up_button->setSprite(EGBS_BUTTON_UP,
s32(skin->getIcon(EGDI_CURSOR_LEFT)),
@ -360,6 +456,7 @@ void GUIScrollBar::refreshControls()
up_button->setRelativePosition(core::rect<s32>(0, 0, h, h));
up_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT,
EGUIA_LOWERRIGHT);
if (!down_button) {
down_button = Environment->addButton(
core::rect<s32>(RelativeRect.getWidth() - h, 0,
@ -368,7 +465,14 @@ void GUIScrollBar::refreshControls()
down_button->setSubElement(true);
down_button->setTabStop(false);
}
if (sprites) {
if (m_textures.size() >= 4) {
down_button->setImage(m_textures[3]);
down_button->setScaleImage(true);
down_button->setDrawBorder(false);
down_button->setUseAlphaChannel(true);
down_button->setSpriteBank(nullptr);
} else if (sprites) {
down_button->setSpriteBank(sprites);
down_button->setSprite(EGBS_BUTTON_UP,
s32(skin->getIcon(EGDI_CURSOR_RIGHT)),
@ -377,6 +481,7 @@ void GUIScrollBar::refreshControls()
s32(skin->getIcon(EGDI_CURSOR_RIGHT)),
current_icon_color);
}
down_button->setRelativePosition(
core::rect<s32>(RelativeRect.getWidth() - h, 0,
RelativeRect.getWidth(), h));
@ -384,14 +489,23 @@ void GUIScrollBar::refreshControls()
EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
} else {
s32 w = RelativeRect.getWidth();
border_size = RelativeRect.getHeight() < w * 4 ? 0 : w;
s32 h = RelativeRect.getHeight();
border_size = h < w * 4 ? 0 : w;
if (!up_button) {
up_button = Environment->addButton(
core::rect<s32>(0, 0, w, w), this);
up_button->setSubElement(true);
up_button->setTabStop(false);
}
if (sprites) {
if (m_textures.size() >= 3) {
up_button->setImage(m_textures[2]);
up_button->setScaleImage(true);
up_button->setDrawBorder(false);
up_button->setUseAlphaChannel(true);
up_button->setSpriteBank(nullptr);
} else if (sprites) {
up_button->setSpriteBank(sprites);
up_button->setSprite(EGBS_BUTTON_UP,
s32(skin->getIcon(EGDI_CURSOR_UP)),
@ -403,15 +517,21 @@ void GUIScrollBar::refreshControls()
up_button->setRelativePosition(core::rect<s32>(0, 0, w, w));
up_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT,
EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
if (!down_button) {
down_button = Environment->addButton(
core::rect<s32>(0, RelativeRect.getHeight() - w,
w, RelativeRect.getHeight()),
this);
core::rect<s32>(0, 0, w, w), this);
down_button->setSubElement(true);
down_button->setTabStop(false);
}
if (sprites) {
if (m_textures.size() >= 4) {
down_button->setImage(m_textures[3]);
down_button->setScaleImage(true);
down_button->setDrawBorder(false);
down_button->setUseAlphaChannel(true);
down_button->setSpriteBank(nullptr);
} else if (sprites) {
down_button->setSpriteBank(sprites);
down_button->setSprite(EGBS_BUTTON_UP,
s32(skin->getIcon(EGDI_CURSOR_DOWN)),

View File

@ -12,7 +12,10 @@ the arrow buttons where there is insufficient space.
#pragma once
#include "guiAnimatedImage.h"
#include "irrlichttypes_extrabloated.h"
#include "StyleSpec.h"
#include <vector>
using namespace irr;
using namespace gui;
@ -39,6 +42,7 @@ public:
s32 getLargeStep() const { return large_step; }
s32 getSmallStep() const { return small_step; }
s32 getPos() const;
s32 getPageSize() const { return page_size; }
void setMax(const s32 &max);
void setMin(const s32 &min);
@ -47,14 +51,21 @@ public:
void setPos(const s32 &pos);
void setPageSize(const s32 &size);
void setArrowsVisible(ArrowVisibility visible);
void setTextures(const std::vector<video::ITexture *> &textures);
void setStyle(const StyleSpec &style, ISimpleTextureSource *tsrc);
private:
void refreshControls();
s32 getPosFromMousePos(const core::position2di &p) const;
f32 range() const { return f32(max_pos - min_pos); }
gui::IGUIImage *addImage(const core::rect<s32> &rect, video::ITexture *texture);
IGUIButton *up_button;
IGUIButton *down_button;
gui::IGUIImage *bg_image;
gui::IGUIImage *slider_image;
gui::IGUIImage *slider_top_image;
gui::IGUIImage *slider_bottom_image;
ArrowVisibility arrow_visibility = DEFAULT;
bool is_dragging;
bool is_horizontal;
@ -72,6 +83,9 @@ private:
s32 page_size;
s32 border_size;
std::vector<video::ITexture *> m_textures;
core::rect<s32> m_texture_middle;
core::rect<s32> slider_rect;
video::SColor current_icon_color;
};

View File

@ -29,7 +29,7 @@ GUISkin::GUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver)
{
Colors[EGDC_3D_DARK_SHADOW] = video::SColor(101,50,50,50);
Colors[EGDC_3D_SHADOW] = video::SColor(101,130,130,130);
Colors[EGDC_3D_FACE] = video::SColor(220,100,100,100);
Colors[EGDC_3D_FACE] = video::SColor(101,210,210,210);
Colors[EGDC_3D_HIGH_LIGHT] = video::SColor(101,255,255,255);
Colors[EGDC_3D_LIGHT] = video::SColor(101,210,210,210);
Colors[EGDC_ACTIVE_BORDER] = video::SColor(101,16,14,115);
@ -1003,6 +1003,16 @@ void GUISkin::drawColoredIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon,
colors = Colors;
bool gray = element && !element->isEnabled();
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 9
if (icon == EGDI_CHECK_BOX_CHECKED) {
// Scale checkbox check specifically
int radius = getSize(EGDS_CHECK_BOX_WIDTH) * .38;
core::recti rect{position.X - radius, position.Y - radius, position.X + radius, position.Y + radius};
SpriteBank->draw2DSprite(Icons[icon], rect, 0,
&colors[gray ? EGDC_GRAY_WINDOW_SYMBOL : EGDC_WINDOW_SYMBOL], currenttime - starttime, loop);
return;
}
#endif
SpriteBank->draw2DSprite(Icons[icon], position, clip,
colors[gray? EGDC_GRAY_WINDOW_SYMBOL : EGDC_WINDOW_SYMBOL], starttime, currenttime, loop, true);
}

View File

@ -77,14 +77,12 @@ GUITable::GUITable(gui::IGUIEnvironment *env,
setTabStop(true);
setTabOrder(-1);
updateAbsolutePosition();
#ifdef HAVE_TOUCHSCREENGUI
float density = 1; // dp scaling is applied by the skin
#else
float density = RenderingEngine::getDisplayDensity();
#endif
float gui_scaling = g_settings->getFloat("gui_scaling");
scale = density * gui_scaling;
core::rect<s32> relative_rect = m_scrollbar->getRelativePosition();
s32 width = (relative_rect.getWidth() / (2.0 / 3.0)) * density *
g_settings->getFloat("gui_scaling");
s32 width = (relative_rect.getWidth() / (2.0 / 3.0)) *
gui_scaling;
m_scrollbar->setRelativePosition(core::rect<s32>(
relative_rect.LowerRightCorner.X-width,relative_rect.UpperLeftCorner.Y,
relative_rect.LowerRightCorner.X,relative_rect.LowerRightCorner.Y
@ -387,7 +385,7 @@ void GUITable::setTable(const TableOptions &options,
image = m_images[row->content_index];
// Get content width and update xmax
row->content_width = image ? image->getOriginalSize().Width : 0;
row->content_width = image ? image->getOriginalSize().Width * scale : 0;
row->content_width = MYMAX(row->content_width, width);
s32 row_xmax = row->x + padding + row->content_width;
xmax = MYMAX(xmax, row_xmax);
@ -759,17 +757,21 @@ void GUITable::drawCell(const Cell *cell, video::SColor color,
core::rect<s32> source_rect(
core::position2d<s32>(0, 0),
image->getOriginalSize());
s32 imgh = source_rect.LowerRightCorner.Y;
s32 imgh = source_rect.LowerRightCorner.Y * scale;
s32 rowh = row_rect.getHeight();
if (imgh < rowh)
dest_pos.Y += (rowh - imgh) / 2;
else
source_rect.LowerRightCorner.Y = rowh;
video::SColor color(255, 255, 255, 255);
video::SColor colors[] = {color, color, color, color};
driver->draw2DImage(image, dest_pos, source_rect,
&client_clip, color, true);
core::rect<s32> image_pos(dest_pos.X, dest_pos.Y,
dest_pos.X + (image->getOriginalSize().Width * scale),
dest_pos.Y + (image->getOriginalSize().Height * scale));
draw2DImageFilterScaled(driver, image, image_pos, source_rect,
&client_clip, colors, true);
}
}
}

View File

@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "guiScrollBar.h"
#include "StyleSpec.h"
class ISimpleTextureSource;
@ -147,6 +148,14 @@ public:
/* Irrlicht event handler */
virtual bool OnEvent(const SEvent &event);
/* Set scrollbar texture */
void setStyle(const StyleSpec &style)
{
setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
setOverrideFont(style.getFont());
m_scrollbar->setStyle(style, m_tsrc);
}
protected:
enum ColumnType {
COLUMN_TYPE_TEXT,
@ -207,6 +216,8 @@ protected:
gui::IGUIFont *m_font = nullptr;
GUIScrollBar *m_scrollbar = nullptr;
float scale;
// Allocated strings and images
std::vector<core::stringw> m_strings;
std::vector<video::ITexture*> m_images;

View File

@ -19,18 +19,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "guiVolumeChange.h"
#include "debug.h"
#include "guiBackgroundImage.h"
#include "guiButton.h"
#include "guiScrollBar.h"
#include "serialization.h"
#include <string>
#include <IGUICheckBox.h>
#include <IGUIButton.h>
#include <IGUIScrollBar.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "settings.h"
#include "StyleSpec.h"
#include "gettext.h"
#include "client/renderingengine.h"
const int ID_backgroundImage = 262;
const int ID_soundText = 263;
const int ID_soundExitButton = 264;
const int ID_soundSlider = 265;
@ -43,6 +47,13 @@ GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env,
GUIModalMenu(env, parent, id, menumgr),
m_tsrc(tsrc)
{
v3f formspec_bgcolor = g_settings->getV3F("formspec_fullscreen_bg_color");
m_fullscreen_bgcolor = video::SColor(
(u8) MYMIN(MYMAX(g_settings->getS32("formspec_fullscreen_bg_opacity"), 0), 255),
MYMIN(MYMAX(myround(formspec_bgcolor.X), 0), 255),
MYMIN(MYMAX(myround(formspec_bgcolor.Y), 0), 255),
MYMIN(MYMAX(myround(formspec_bgcolor.Z), 0), 255)
);
}
GUIVolumeChange::~GUIVolumeChange()
@ -52,6 +63,9 @@ GUIVolumeChange::~GUIVolumeChange()
void GUIVolumeChange::removeChildren()
{
if (gui::IGUIElement *e = getElementFromId(ID_backgroundImage))
e->remove();
if (gui::IGUIElement *e = getElementFromId(ID_soundText))
e->remove();
@ -74,12 +88,18 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
/*
Calculate new sizes and positions
*/
const float s = m_gui_scale;
float s = MYMIN(screensize.X / 380.f, screensize.Y / 180.f);
#if HAVE_TOUCHSCREENGUI
s *= g_settings->getBool("device_is_tablet") ? 0.4f : 0.5f;
#else
s *= 0.35f;
#endif
DesiredRect = core::rect<s32>(
screensize.X / 2 - 380 * s / 2,
screensize.Y / 2 - 200 * s / 2,
screensize.Y / 2 - 180 * s / 2,
screensize.X / 2 + 380 * s / 2,
screensize.Y / 2 + 200 * s / 2
screensize.Y / 2 + 180 * s / 2 // 200
);
recalculateAbsolutePosition(false);
@ -90,8 +110,15 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
Add stuff
*/
{
core::rect<s32> rect(0, 0, 160 * s, 20 * s);
rect = rect + v2s32(size.X / 2 - 80 * s, size.Y / 2 - 70 * s);
const std::string texture = "bg_common.png";
const core::rect<s32> rect(0, 0, 0, 0);
const core::rect<s32> middle(40, 40, -40, -40);
new GUIBackgroundImage(Environment, this, ID_backgroundImage, rect,
texture, middle, m_tsrc, true);
}
{
core::rect<s32> rect(0, 0, 320 * s, 25 * s);
rect = rect + v2s32(30 * s, size.Y / 2 - 35 * s); // 55
wchar_t text[100];
const wchar_t *str = wgettext("Sound Volume: %d%%");
@ -103,28 +130,38 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
true, this, ID_soundText);
}
{
core::rect<s32> rect(0, 0, 80 * s, 30 * s);
rect = rect + v2s32(size.X / 2 - 80 * s / 2, size.Y / 2 + 55 * s);
core::rect<s32> rect(0, 0, 80 * s, 35 * s);
rect = rect + v2s32(size.X / 2 - 40 * s, size.Y / 2 + 35 * s); // 45
const wchar_t *text = wgettext("Exit");
GUIButton::addButton(Environment, rect, m_tsrc, this, ID_soundExitButton, text);
GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc, this,
ID_soundExitButton, text);
delete[] text;
e->setStyles(StyleSpec::getButtonStyle());
}
{
core::rect<s32> rect(0, 0, 300 * s, 20 * s);
rect = rect + v2s32(size.X / 2 - 150 * s, size.Y / 2);
gui::IGUIScrollBar *e = Environment->addScrollBar(true,
rect, this, ID_soundSlider);
core::rect<s32> rect(0, 0, 320 * s, 30 * s);
rect = rect + v2s32(size.X / 2 - 160 * s, size.Y / 2 - 12 * s); // 30
GUIScrollBar *e = new GUIScrollBar(Environment, this,
ID_soundSlider, rect, true, false);
e->setMax(100);
e->setPos(volume);
e->setArrowsVisible(GUIScrollBar::ArrowVisibility::SHOW);
e->setTextures({
m_tsrc->getTexture("gui/scrollbar_horiz_bg.png"),
m_tsrc->getTexture("gui/scrollbar_slider.png"),
m_tsrc->getTexture("gui/scrollbar_minus.png"),
m_tsrc->getTexture("gui/scrollbar_plus.png"),
});
}
{
core::rect<s32> rect(0, 0, 160 * s, 20 * s);
rect = rect + v2s32(size.X / 2 - 80 * s, size.Y / 2 - 35 * s);
/*{
core::rect<s32> rect(0, 0, 150 * s, 25 * s);
rect = rect + v2s32(30 * s, size.Y / 2 + 5 * s);
const wchar_t *text = wgettext("Muted");
Environment->addCheckBox(g_settings->getBool("mute_sound"), rect, this,
ID_soundMuteButton, text);
delete[] text;
}
}*/
}
void GUIVolumeChange::drawMenu()
@ -133,25 +170,35 @@ void GUIVolumeChange::drawMenu()
if (!skin)
return;
video::IVideoDriver* driver = Environment->getVideoDriver();
video::SColor bgcolor(140, 0, 0, 0);
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
v2u32 screenSize = driver->getScreenSize();
core::rect<s32> allbg(0, 0, screenSize.X, screenSize.Y);
driver->draw2DRectangle(m_fullscreen_bgcolor, allbg, &allbg);
gui::IGUIElement::draw();
}
void GUIVolumeChange::saveSettingsAndQuit()
{
if (!g_settings_path.empty())
g_settings->updateConfigFile(g_settings_path.c_str());
quitMenu();
}
bool GUIVolumeChange::OnEvent(const SEvent& event)
{
if (event.EventType == EET_KEY_INPUT_EVENT) {
if (event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown) {
quitMenu();
saveSettingsAndQuit();
return true;
}
if (event.KeyInput.Key == KEY_RETURN && event.KeyInput.PressedDown) {
quitMenu();
saveSettingsAndQuit();
return true;
}
} else if (event.EventType == EET_GUI_EVENT) {
if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED) {
/*if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED) {
gui::IGUIElement *e = getElementFromId(ID_soundMuteButton);
if (e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) {
g_settings->setBool("mute_sound", ((gui::IGUICheckBox*)e)->isChecked());
@ -159,11 +206,11 @@ bool GUIVolumeChange::OnEvent(const SEvent& event)
Environment->setFocus(this);
return true;
}
}*/
if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED) {
if (event.GUIEvent.Caller->getID() == ID_soundExitButton) {
quitMenu();
saveSettingsAndQuit();
return true;
}
Environment->setFocus(this);
@ -180,9 +227,13 @@ bool GUIVolumeChange::OnEvent(const SEvent& event)
}
if (event.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED) {
if (event.GUIEvent.Caller->getID() == ID_soundSlider) {
s32 pos = ((gui::IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
s32 pos = ((GUIScrollBar*)event.GUIEvent.Caller)->getPos();
g_settings->setFloat("sound_volume", (float) pos / 100);
// unmute sound when changing the volume
if (g_settings->getBool("mute_sound"))
g_settings->setBool("mute_sound", false);
gui::IGUIElement *e = getElementFromId(ID_soundText);
wchar_t text[100];
const wchar_t *str = wgettext("Sound Volume: %d%%");

View File

@ -50,5 +50,8 @@ protected:
std::string getNameByID(s32 id) { return ""; }
private:
void saveSettingsAndQuit();
ISimpleTextureSource *m_tsrc;
video::SColor m_fullscreen_bgcolor;
};

Some files were not shown because too many files have changed in this diff Show More