Backport MultiCraft Engine changes

master
MoNTE48 2020-09-04 20:07:19 +02:00
parent 6227f9c72c
commit 2aa0400bd2
92 changed files with 1522 additions and 452 deletions

View File

@ -27,26 +27,26 @@ on:
jobs:
# This is our minor gcc compiler
gcc_6:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Install deps
run: |
sudo apt-get install g++-6 gcc-6 -qyy
source ./util/ci/common.sh
install_linux_deps
- name: Build
run: |
./util/ci/build.sh
env:
CC: gcc-6
CXX: g++-6
- name: Test
run: |
./bin/multicraft --run-unittests
# gcc_6:
# runs-on: ubuntu-18.04
# steps:
# - uses: actions/checkout@v2
# - name: Install deps
# run: |
# sudo apt-get install g++-6 gcc-6 -qyy
# source ./util/ci/common.sh
# install_linux_deps
#
# - name: Build
# run: |
# ./util/ci/build.sh
# env:
# CC: gcc-6
# CXX: g++-6
#
# - name: Test
# run: |
# ./bin/multicraft --run-unittests
# This is the current gcc compiler (available in bionic)
gcc_8:
@ -71,26 +71,26 @@ jobs:
./bin/multicraft --run-unittests
# This is our minor clang compiler
clang_3_9:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Install deps
run: |
sudo apt-get install clang-3.9 -qyy
source ./util/ci/common.sh
install_linux_deps
- name: Build
run: |
./util/ci/build.sh
env:
CC: clang-3.9
CXX: clang++-3.9
- name: Test
run: |
./bin/multicraft --run-unittests
# clang_3_9:
# runs-on: ubuntu-18.04
# steps:
# - uses: actions/checkout@v2
# - name: Install deps
# run: |
# sudo apt-get install clang-3.9 -qyy
# source ./util/ci/common.sh
# install_linux_deps
#
# - name: Build
# run: |
# ./util/ci/build.sh
# env:
# CC: clang-3.9
# CXX: clang++-3.9
#
# - name: Test
# run: |
# ./bin/multicraft --run-unittests
# This is the current clang version
clang_9:
@ -121,56 +121,56 @@ jobs:
valgrind --leak-check=full --leak-check-heuristics=all --undef-value-errors=no --error-exitcode=9 ./bin/multicraft --run-unittests
# Build with prometheus-cpp (server-only)
clang_9_prometheus:
name: "clang_9 (PROMETHEUS=1)"
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Install deps
run: |
sudo apt-get install clang-9 -qyy
source ./util/ci/common.sh
install_linux_deps
- name: Build prometheus-cpp
run: |
./util/ci/build_prometheus_cpp.sh
- name: Build
run: |
./util/ci/build.sh
env:
CC: clang-9
CXX: clang++-9
CMAKE_FLAGS: "-DENABLE_PROMETHEUS=1 -DBUILD_CLIENT=0"
- name: Test
run: |
./bin/multicraftserver --run-unittests
# clang_9_prometheus:
# name: "clang_9 (PROMETHEUS=1)"
# runs-on: ubuntu-18.04
# steps:
# - uses: actions/checkout@v2
# - name: Install deps
# run: |
# sudo apt-get install clang-9 -qyy
# source ./util/ci/common.sh
# install_linux_deps
#
# - name: Build prometheus-cpp
# run: |
# ./util/ci/build_prometheus_cpp.sh
#
# - name: Build
# run: |
# ./util/ci/build.sh
# env:
# CC: clang-9
# CXX: clang++-9
# CMAKE_FLAGS: "-DENABLE_PROMETHEUS=1 -DBUILD_CLIENT=0"
#
# - name: Test
# run: |
# ./bin/multicraftserver --run-unittests
# Build without freetype (client-only)
clang_9_no_freetype:
name: "clang_9 (FREETYPE=0)"
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Install deps
run: |
sudo apt-get install clang-9 -qyy
source ./util/ci/common.sh
install_linux_deps
- name: Build
run: |
./util/ci/build.sh
env:
CC: clang-9
CXX: clang++-9
CMAKE_FLAGS: "-DENABLE_FREETYPE=0 -DBUILD_SERVER=0"
- name: Test
run: |
./bin/multicraft --run-unittests
# clang_9_no_freetype:
# name: "clang_9 (FREETYPE=0)"
# runs-on: ubuntu-18.04
# steps:
# - uses: actions/checkout@v2
# - name: Install deps
# run: |
# sudo apt-get install clang-9 -qyy
# source ./util/ci/common.sh
# install_linux_deps
#
# - name: Build
# run: |
# ./util/ci/build.sh
# env:
# CC: clang-9
# CXX: clang++-9
# CMAKE_FLAGS: "-DENABLE_FREETYPE=0 -DBUILD_SERVER=0"
#
# - name: Test
# run: |
# ./bin/multicraft --run-unittests
docker:
name: "Docker image"
@ -219,10 +219,10 @@ jobs:
msvc:
name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }}
runs-on: windows-2019
runs-on: windows-2019
env:
VCPKG_VERSION: c7ab9d3110813979a873b2dbac630a9ab79850dc
# 2020.04
VCPKG_VERSION: 0bf3923f9fab4001c00f0f429682a0853b5749e0
# 2020.11
vcpkg_packages: irrlicht zlib curl[winssl] openal-soft libvorbis libogg sqlite3 freetype luajit
strategy:
fail-fast: false
@ -248,7 +248,7 @@ jobs:
uses: actions/checkout@v2
- name: Restore from cache and run vcpkg
uses: lukka/run-vcpkg@v2
uses: lukka/run-vcpkg@v5
with:
vcpkgArguments: ${{env.vcpkg_packages}}
vcpkgDirectory: '${{ github.workspace }}\vcpkg'

2
.gitignore vendored
View File

@ -55,6 +55,8 @@ build/.cmake/
/clientmods/*
!/clientmods/preview/
/client/mod_storage/
/builtin/mainmenu/hosting/
/textures/base/pack/hosting/
## Configuration/log files
multicraft.conf

View File

@ -49,7 +49,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")

View File

@ -13,6 +13,7 @@ WARN_IF_UNDOCUMENTED = NO
BUILTIN_STL_SUPPORT = YES
PREDEFINED = "USE_SPATIAL=1" \
"USE_LEVELDB=1" \
"USE_SQLITE=1" \
"USE_REDIS=1" \
"USE_SOUND=1" \
"USE_CURL=1" \

View File

@ -198,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)

View File

@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "wieldmesh.h"
#include "noise.h" // easeCurve
#include "sound.h"
#include "event.h"
#include "mtevent.h"
#include "nodedef.h"
#include "util/numeric.h"
#include "constants.h"
@ -695,6 +695,8 @@ void Camera::drawNametags()
i = m_nametags.begin();
i != m_nametags.end(); ++i) {
Nametag *nametag = *i;
if (!nametag->parent_node->isVisible())
continue;
if (nametag->nametag_color.getAlpha() == 0) {
// Enforce hiding nametag,
// because if freetype is enabled, a grey

View File

@ -50,7 +50,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientmap.h"
#include "clientmedia.h"
#include "version.h"
#if USE_SQLITE
#include "database/database-sqlite3.h"
#endif
#include "serialization.h"
#include "guiscalingfilter.h"
#include "script/scripting_client.h"
@ -130,6 +132,8 @@ Client::Client(
m_minimap = new Minimap(this);
}
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");
}
void Client::loadMods()
@ -284,11 +288,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;
@ -663,12 +669,14 @@ void Client::step(float dtime)
infostream << "Saved " << n << " modified mod storages." << std::endl;
}
#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,
@ -831,9 +839,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()
@ -1219,6 +1229,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);

View File

@ -437,6 +437,9 @@ public:
{
return m_env.getLocalPlayer()->formspec_prepend;
}
const u16 getRoundScreen() { return m_round_screen; }
const f32 getHudScaling() { return m_hud_scaling; }
private:
void loadMods();
bool checkBuiltinIntegrity();
@ -602,4 +605,7 @@ private:
u32 m_csm_restriction_noderange = 8;
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
u16 m_round_screen;
f32 m_hud_scaling;
};

View File

@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientmap.h"
#include "scripting_client.h"
#include "mapblock_mesh.h"
#include "event.h"
#include "mtevent.h"
#include "collision.h"
#include "nodedef.h"
#include "profiler.h"

View File

@ -38,7 +38,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#if USE_SOUND
#include "sound_openal.h"
#endif
#ifdef __ANDROID__
#ifdef __IOS__
namespace irr {
class CIrrDeviceiOS : public IrrlichtDevice {
public:
void *getViewController();
};
}
#endif
#if defined(__ANDROID__) || defined(__IOS__)
#include "porting.h"
#endif
@ -106,6 +114,8 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
RenderingEngine::get_instance()->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.
@ -130,7 +140,7 @@ bool ClientLauncher::run(GameParams &game_params, 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 __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
float density = porting::getDisplayDensity();
skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(17.0f * density));
skin->setSize(gui::EGDS_SCROLLBAR_SIZE, (s32)(14.0f * density));
@ -279,6 +289,10 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
receiver->m_touchscreengui = NULL;
#endif
#if defined(__ANDROID__) || defined(__IOS__)
porting::notifyExitGame();
#endif
} //try
catch (con::PeerNotFoundException &e) {
error_message = gettext("Connection error (timed out?)");
@ -469,11 +483,11 @@ bool ClientLauncher::launch_game(std::string &error_message,
// If using simple singleplayer mode, override
if (simple_singleplayer_mode) {
assert(!skip_main_menu);
current_playername = "singleplayer";
current_playername = "Player";
current_password = "";
current_address = "";
current_port = myrand_range(49152, 65535);
} else {
} else if (menudata.servername != "\x01TEMP\x01") {
g_settings->set("name", playername);
if (!address.empty()) {
ServerListSpec server;
@ -552,7 +566,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
#if !defined(__ANDROID__) && !defined(__IOS__)
RenderingEngine::get_raw_device()->getCursorControl()->setVisible(true);
#endif

View File

@ -129,7 +129,7 @@ void ClientMap::updateDrawList()
// Use a higher fov to accomodate faster camera movements.
// Blocks are cropped better when they are drawn.
// Or maybe they aren't? Well whatever.
camera_fov *= 1.2;
camera_fov *= 1.1;
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
v3s16 p_blocks_min;
@ -184,7 +184,11 @@ void ClientMap::updateDrawList()
if (block->mesh)
block->mesh->updateCameraOffset(m_camera_offset);
#if !defined(__ANDROID__) && !defined(__IOS__)
float range = 100000 * BS;
#else
float range = m_control.wanted_range * BS * 4;
#endif
if (!m_control.range_all)
range = m_control.wanted_range * BS;

View File

@ -897,9 +897,6 @@ u16 GenericCAO::getLightPosition(v3s16 *pos)
void GenericCAO::updateNametag()
{
if (m_is_local_player) // No nametag for local player
return;
if (m_prop.nametag.empty()) {
// Delete nametag
if (m_nametag) {
@ -1229,7 +1226,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;
@ -1606,7 +1603,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 (expire_visuals) {
@ -1778,9 +1775,9 @@ void GenericCAO::processMessage(const std::string &data)
v2f(m_prop.visual_size.X, m_prop.visual_size.Y) * BS);
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;
updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
}
}
@ -1830,11 +1827,19 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
punchitem,
time_from_last_punch);
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
@ -1845,9 +1850,9 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
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;
updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
}
}

View File

@ -909,7 +909,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] = {

View File

@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
#include "event.h"
#include "mtevent.h"
#include <list>
#include <map>

View File

@ -315,11 +315,11 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
// give up
errorstream << "minetest can not continue without a valid font. "
errorstream << "MultiCraft can not continue without a valid font. "
"Please correct the 'font_path' setting or install the font "
"file in the proper location" << std::endl;
#else
errorstream << "FontEngine: Tried to load freetype fonts but Minetest was"
errorstream << "FontEngine: Tried to load freetype fonts but MultiCraft was"
" not compiled with that library." << std::endl;
#endif
abort();

View File

@ -338,7 +338,7 @@ public:
static void playerDamage(MtEvent *e, void *data)
{
SoundMaker *sm = (SoundMaker *)data;
sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
sm->m_sound->playSound(SimpleSoundSpec("player_damage", 1.0), false);
}
static void playerFallingDamage(MtEvent *e, void *data)
@ -595,11 +595,7 @@ public:
}
};
#ifdef __ANDROID__
#define SIZE_TAG "size[11,5.5]"
#else
#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
#endif
/****************************************************************************
@ -629,16 +625,21 @@ struct GameRunData {
bool left_punch;
bool reset_jump_timer;
float nodig_delay_timer;
float noplace_delay_timer;
float dig_time;
float dig_time_complete;
float repeat_rightclick_timer;
float object_hit_delay_timer;
float time_from_last_punch;
float pause_game_timer;
ClientActiveObject *selected_object;
float jump_timer;
float damage_flash;
float update_draw_list_timer;
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
float item_select_timer;
#endif
f32 fog_range;
@ -685,6 +686,12 @@ public:
void run();
void shutdown();
#if defined(__ANDROID__) || defined(__IOS__)
void pauseGame();
#endif
#ifdef __IOS__
void customStatustext(const std::wstring &text, float time);
#endif
protected:
@ -722,7 +729,7 @@ protected:
// Input related
void processUserInput(f32 dtime);
void processKeyInput();
void processItemSelection(u16 *new_playeritem);
void processItemSelection(f32 dtime, GameRunData *run_data);
void dropSelectedItem(bool single_item = false);
void openInventory();
@ -797,7 +804,7 @@ protected:
return input->wasKeyDown(k);
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
void handleAndroidChatInput();
#endif
@ -882,6 +889,7 @@ private:
scene::ISceneManager *smgr;
bool *kill;
std::string *error_message;
std::string wield_name;
bool *reconnect_requested;
scene::ISceneNode *skybox;
@ -920,7 +928,9 @@ private:
bool m_does_lost_focus_pause_game = false;
#ifdef __ANDROID__
int m_reset_HW_buffer_counter = 0;
#if defined(__ANDROID__) || defined(__IOS__)
bool m_cache_hold_aux1;
bool m_android_chat_open;
#endif
@ -959,7 +969,7 @@ Game::Game() :
readSettings();
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
m_cache_hold_aux1 = false; // This is initialised properly later
#endif
@ -1088,7 +1098,7 @@ void Game::run()
set_light_table(g_settings->getFloat("display_gamma"));
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
m_cache_hold_aux1 = g_settings->getBool("fast_move")
&& client->checkPrivilege("fast");
#endif
@ -1099,6 +1109,17 @@ void Game::run()
while (RenderingEngine::run()
&& !(*kill || g_gamecallback->shutdown_requested
|| (server && server->isShutdownRequested()))) {
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
if (!device->isWindowFocused()) {
sleep_ms(50);
continue;
}
#elif defined(__ANDROID__) || defined(__IOS__)
if (device->isWindowMinimized()) {
sleep_ms(50);
continue;
}
#endif
const irr::core::dimension2d<u32> &current_screen_size =
RenderingEngine::get_video_driver()->getScreenSize();
@ -1343,6 +1364,10 @@ bool Game::createClient(const std::string &playername,
return false;
}
#if defined(__ANDROID__) || defined(__IOS__)
porting::notifyServerConnect(!simple_singleplayer_mode);
#endif
if (!getServerContent(&connect_aborted)) {
if (error_message->empty() && !connect_aborted) {
// Should not happen if error messages are set properly
@ -1580,7 +1605,7 @@ bool Game::connectToServer(const std::string &playername,
} else {
wait_time += dtime;
// Only time out if we aren't waiting for the server we started
if (!address->empty() && wait_time > 10) {
if (!address->empty() && wait_time > 15) {
*error_message = "Connection timed out.";
errorstream << *error_message << std::endl;
break;
@ -1659,7 +1684,10 @@ bool Game::getServerContent(bool *aborted)
std::stringstream message;
std::fixed(message);
message.precision(0);
message << gettext("Media...") << " " << (client->mediaReceiveProgress()*100) << "%";
float receive = client->mediaReceiveProgress() * 100;
message << gettext("Media...");
if (receive > 0)
message << " " << receive << "%";
message.precision(2);
if ((USE_CURL == 0) ||
@ -1699,6 +1727,9 @@ inline void Game::updateInteractTimers(f32 dtime)
if (runData.object_hit_delay_timer >= 0)
runData.object_hit_delay_timer -= dtime;
if (runData.noplace_delay_timer >= 0)
runData.noplace_delay_timer -= dtime;
runData.time_from_last_punch += dtime;
}
@ -1872,20 +1903,22 @@ void Game::processUserInput(f32 dtime)
// Input handler step() (used by the random input generator)
input->step(dtime);
#ifdef __ANDROID__
auto formspec = m_game_ui->getFormspecGUI();
if (formspec)
formspec->getAndroidUIInput();
else
handleAndroidChatInput();
#if defined(__ANDROID__) || defined(__IOS__)
if (!porting::hasRealKeyboard()) {
auto formspec = m_game_ui->getFormspecGUI();
if (formspec)
formspec->getAndroidUIInput();
else
handleAndroidChatInput();
}
#endif
// Increase timer for double tap of "keymap_jump"
if (m_cache_doubletap_jump && runData.jump_timer <= 0.2f)
if (m_cache_doubletap_jump && runData.jump_timer <= 0.15f)
runData.jump_timer += dtime;
processKeyInput();
processItemSelection(&runData.new_playeritem);
processItemSelection(dtime, &runData);
}
@ -1901,7 +1934,7 @@ void Game::processKeyInput()
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
} else if (input->cancelPressed()) {
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
m_android_chat_open = false;
#endif
if (!gui_chat_console->isOpenInhibited()) {
@ -1987,7 +2020,7 @@ void Game::processKeyInput()
toggleDebug();
} else if (wasKeyDown(KeyType::TOGGLE_PROFILER)) {
m_game_ui->toggleProfiler();
} else if (wasKeyDown(KeyType::INCREASE_VIEWING_RANGE)) {
} else if (wasKeyDown(KeyType::INCREASE_VIEWING_RANGE) || wasKeyDown(KeyType::INCREASE_VIEWING_RANGE2)) {
increaseViewRange();
} else if (wasKeyDown(KeyType::DECREASE_VIEWING_RANGE)) {
decreaseViewRange();
@ -2015,13 +2048,18 @@ void Game::processKeyInput()
}
}
void Game::processItemSelection(u16 *new_playeritem)
void Game::processItemSelection(f32 dtime, GameRunData *run_data)
{
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
if (run_data->item_select_timer)
run_data->item_select_timer = MYMAX(0.0f, run_data->item_select_timer - dtime);
#endif
LocalPlayer *player = client->getEnv().getLocalPlayer();
/* Item selection using mouse wheel
*/
*new_playeritem = player->getWieldIndex();
run_data->new_playeritem = player->getWieldIndex();
s32 wheel = input->getMouseWheel();
u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1,
@ -2039,17 +2077,21 @@ void Game::processItemSelection(u16 *new_playeritem)
dir = 1;
}
if (dir < 0)
*new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0;
else if (dir > 0)
*new_playeritem = *new_playeritem > 0 ? *new_playeritem - 1 : max_item;
// else dir == 0
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
if (dir && !run_data->item_select_timer) {
run_data->item_select_timer = 0.05f;
#else
if (dir) {
#endif
run_data->new_playeritem += dir < 0 ? 1 : max_item;
run_data->new_playeritem %= max_item + 1;
}
/* Item selection using hotbar slot keys
*/
for (u16 i = 0; i <= max_item; i++) {
if (wasKeyDown((GameKeyType) (KeyType::SLOT_1 + i))) {
*new_playeritem = i;
run_data->new_playeritem = i;
break;
}
}
@ -2101,10 +2143,12 @@ void Game::openConsole(float scale, const wchar_t *line)
{
assert(scale > 0.0f && scale <= 1.0f);
#ifdef __ANDROID__
porting::showInputDialog(gettext("ok"), "", "", 2);
m_android_chat_open = true;
#else
#if defined(__ANDROID__) || defined(__IOS__)
if (!porting::hasRealKeyboard()) {
porting::showInputDialog(gettext("OK"), "", "", 2);
m_android_chat_open = true;
} else {
#endif
if (gui_chat_console->isOpenInhibited())
return;
gui_chat_console->openConsole(scale);
@ -2112,10 +2156,12 @@ void Game::openConsole(float scale, const wchar_t *line)
gui_chat_console->setCloseOnEnter(true);
gui_chat_console->replaceAndAddToHistory(line);
}
#if defined(__ANDROID__) || defined(__IOS__)
}
#endif
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
void Game::handleAndroidChatInput()
{
if (m_android_chat_open && porting::getInputDialogState() == 0) {
@ -2145,9 +2191,24 @@ void Game::toggleFreeMove()
void Game::toggleFreeMoveAlt()
{
if (m_cache_doubletap_jump && runData.jump_timer < 0.2f)
toggleFreeMove();
bool free_move = !g_settings->getBool("free_move");
bool creative = !g_settings->getBool("creative_mode");
if (simple_singleplayer_mode) {
if (m_cache_doubletap_jump && runData.jump_timer < 0.15f) {
if (!free_move || !creative)
toggleFreeMove();
}
} else {
if (client->checkPrivilege("fly") && runData.jump_timer < 0.15f) {
#if defined(__ANDROID__) || defined(__IOS__)
toggleFreeMove();
#else
if (m_cache_doubletap_jump)
toggleFreeMove();
#endif
}
}
runData.reset_jump_timer = true;
}
@ -2181,7 +2242,7 @@ void Game::toggleFast()
m_game_ui->showTranslatedStatusText("Fast mode disabled");
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
m_cache_hold_aux1 = fast_move && has_fast_privs;
#endif
}
@ -2249,6 +2310,7 @@ void Game::toggleMinimap(bool shift_pressed)
m_game_ui->m_flags.show_minimap = true;
switch (mode) {
#if !defined(__ANDROID__) && !defined(__IOS__)
case MINIMAP_MODE_SURFACEx1:
m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x1");
break;
@ -2266,7 +2328,16 @@ void Game::toggleMinimap(bool shift_pressed)
break;
case MINIMAP_MODE_RADARx4:
m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x4");
break;
break;
#else
case MINIMAP_MODE_SURFACEx1:
m_game_ui->showTranslatedStatusText("Minimap shown");
break;
case MINIMAP_MODE_RADARx1:
m_game_ui->showTranslatedStatusText("Minimap in radar mode");
break;
#endif
default:
mode = MINIMAP_MODE_OFF;
m_game_ui->m_flags.show_minimap = false;
@ -2381,10 +2452,17 @@ void Game::decreaseViewRange()
void Game::toggleFullViewRange()
{
draw_control->range_all = !draw_control->range_all;
#if !defined(__ANDROID__) && !defined(__IOS__)
if (draw_control->range_all)
m_game_ui->showTranslatedStatusText("Enabled unlimited viewing range");
else
m_game_ui->showTranslatedStatusText("Disabled unlimited viewing range");
#else
if (draw_control->range_all)
m_game_ui->showTranslatedStatusText("Enabled far viewing range");
else
m_game_ui->showTranslatedStatusText("Disabled far viewing range");
#endif
}
@ -2401,7 +2479,7 @@ void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
if ((device->isWindowActive() && device->isWindowFocused()
&& !isMenuActive()) || random_input) {
#ifndef __ANDROID__
#if !defined(__ANDROID__) && !defined(__IOS__)
if (!random_input) {
// Mac OSX gets upset if this is set every frame
if (device->getCursorControl()->isVisible())
@ -2420,7 +2498,7 @@ void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
} else {
#ifndef ANDROID
#if !defined(__ANDROID__) && !defined(__IOS__)
// Mac OSX gets upset if this is set every frame
if (!device->getCursorControl()->isVisible())
device->getCursorControl()->setVisible(true);
@ -2503,13 +2581,13 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
( (u32)(isKeyDown(KeyType::ZOOM) & 0x1) << 9)
);
#ifdef ANDROID
#if defined(__ANDROID__) || defined(__IOS__)
/* For Android, simulate holding down AUX1 (fast move) if the user has
* the fast_move setting toggled on. If there is an aux1 key defined for
* Android then its meaning is inverted (i.e. holding aux1 means walk and
* not fast)
*/
if (m_cache_hold_aux1) {
if (m_cache_hold_aux1 && !porting::hasRealKeyboard()) {
control.aux1 = control.aux1 ^ true;
keypress_bits ^= ((u32)(1U << 5));
}
@ -2539,6 +2617,15 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
inline void Game::step(f32 *dtime)
{
#if defined(__ANDROID__) || defined(__IOS__)
if (g_menumgr.pausesGame()) {
runData.pause_game_timer += *dtime;
if (runData.pause_game_timer > 120.f) {
g_gamecallback->disconnect();
return;
}
}
#endif
bool can_be_and_is_paused =
(simple_singleplayer_mode && g_menumgr.pausesGame());
@ -3293,10 +3380,13 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
ClientMap &map = client->getEnv().getClientMap();
bool digging = false;
if (runData.nodig_delay_timer <= 0.0 && input->getLeftState()
&& !runData.digging_blocked
&& client->checkPrivilege("interact")) {
handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
digging = true;
runData.noplace_delay_timer = 1.0;
}
// This should be done after digging handling
@ -3316,6 +3406,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
if ((input->getRightClicked() ||
runData.repeat_rightclick_timer >= m_repeat_right_click_time) &&
!digging && runData.noplace_delay_timer <= 0.0 &&
client->checkPrivilege("interact")) {
runData.repeat_rightclick_timer = 0;
infostream << "Ground right-clicked" << std::endl;
@ -3546,7 +3637,15 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
m_game_ui->setInfoText(infotext);
if (input->getLeftState()) {
const ItemDefinition &playeritem_def =
tool_item.getDefinition(itemdef_manager);
bool nohit_enabled = ((ItemGroupList) playeritem_def.groups)["nohit"] != 0;
#ifdef HAVE_TOUCHSCREENGUI
if (input->getRightClicked() && !nohit_enabled) {
#else
if (input->getLeftState() && !nohit_enabled) {
#endif
bool do_punch = false;
bool do_punch_damage = false;
@ -3576,7 +3675,11 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
if (!disable_send)
client->interact(INTERACT_START_DIGGING, pointed);
}
} else if (input->getRightClicked()) {
#ifdef HAVE_TOUCHSCREENGUI
} else if (input->getLeftClicked() || (input->getRightClicked() && nohit_enabled)) {
#else
} else if (input->getRightClicked() || (input->getLeftClicked() && nohit_enabled)) {
#endif
infostream << "Right-clicked object" << std::endl;
client->interact(INTERACT_PLACE, pointed); // place
}
@ -3658,6 +3761,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
client->setCrack(runData.dig_index, nodepos);
} else {
infostream << "Digging completed" << std::endl;
runData.noplace_delay_timer = 1.0;
client->interact(INTERACT_DIGGING_COMPLETED, pointed);
client->setCrack(-1, v3s16(0, 0, 0));
runData.dig_time = 0;
@ -3732,7 +3837,11 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
*/
if (draw_control->range_all) {
#if !defined(__ANDROID__) && !defined(__IOS__)
runData.fog_range = 100000 * BS;
#else
runData.fog_range = draw_control->wanted_range * BS * 4;
#endif
} else {
runData.fog_range = draw_control->wanted_range * BS;
}
@ -3862,6 +3971,12 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
ItemStack selected_item, hand_item;
ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
camera->wield(tool_item);
std::string item_desc = selected_item.getDefinition(itemdef_manager).description;
if (wield_name != item_desc) {
m_game_ui->showStatusText(utf8_to_wide(item_desc));
wield_name = item_desc;
}
}
/*
@ -3971,6 +4086,23 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
/*
End scene
*/
if (++m_reset_HW_buffer_counter > 500) {
/*
Periodically remove all mesh HW buffers.
Work around for a quirk in Irrlicht where a HW buffer is only
released after 20000 iterations (triggered from endScene()).
Without this, all loaded but unused meshes will retain their HW
buffers for at least 5 minutes, at which point looking up the HW buffers
becomes a bottleneck and the framerate drops (as much as 30%).
Tests showed that numbers between 50 and 1000 are good, so picked 500.
There are no other public Irrlicht APIs that allow interacting with the
HW buffers without tracking the status of every individual mesh.
The HW buffers for _visible_ meshes will be reinitialized in the next frame.
*/
infostream << "Game::updateFrame(): Removing all HW buffers." << std::endl;
driver->removeAllHardwareBuffers();
m_reset_HW_buffer_counter = 0;
}
driver->endScene();
stats->drawtime = tt_draw.stop(true);
@ -4009,6 +4141,14 @@ inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
u32 frametime_min = 1000 / (g_menumgr.pausesGame()
? g_settings->getFloat("pause_fps_max")
: g_settings->getFloat("fps_max"));
#if defined(__ANDROID__) || defined(__IOS__)
if (g_menumgr.pausesGame() && !device->isWindowFocused())
frametime_min = 1000;
#endif
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
// FPS limiting causes freezes on macOS
frametime_min = 0;
#endif
if (fps_timings->busy_time < frametime_min) {
fps_timings->sleep_time = frametime_min - fps_timings->busy_time;
@ -4076,6 +4216,28 @@ void Game::readSettings()
m_does_lost_focus_pause_game = g_settings->getBool("pause_on_lost_focus");
}
#if defined(__ANDROID__) || defined(__IOS__)
void Game::pauseGame()
{
if (g_menumgr.pausesGame() || !hud)
return;
g_touchscreengui->handleReleaseAll();
showPauseMenu();
runData.pause_game_timer = 0;
}
#endif
#ifdef __IOS__
void Game::customStatustext(const std::wstring &text, float time)
{
m_statustext = text;
if (m_statustext == L"")
runData.statustext_time = 0;
else
runData.statustext_time = time;
}
#endif
/****************************************************************************/
/****************************************************************************
Shutdown / cleanup
@ -4128,7 +4290,7 @@ void Game::showDeathFormspec()
#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
void Game::showPauseMenu()
{
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
static const std::string control_text = strgettext("Default Controls:\n"
"No menu visible:\n"
"- single tap: button activate\n"
@ -4177,35 +4339,38 @@ void Game::showPauseMenu()
str_formspec_escape(control_text);
#endif
#ifndef __IOS__
float ypos = simple_singleplayer_mode ? 0.7f : 0.1f;
#else
float ypos = 1.5f;
#endif
std::ostringstream os;
os << "formspec_version[1]" << SIZE_TAG
<< "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;"
<< "bgcolor[#00000060;true]"
<< "button_exit[3.5," << (ypos++) << ";4,0.5;btn_continue;"
<< strgettext("Continue") << "]";
if (!simple_singleplayer_mode) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;"
os << "button_exit[3.5," << (ypos++) << ";4,0.5;btn_change_password;"
<< strgettext("Change Password") << "]";
} else {
os << "field[4.95,0;5,1.5;;" << strgettext("Game paused") << ";]";
}
#ifndef __ANDROID__
#if !defined(__ANDROID__) && !defined(__IOS__)
#if USE_SOUND
if (g_settings->getBool("enable_sound")) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
os << "button_exit[3.5," << (ypos++) << ";4,0.5;btn_sound;"
<< strgettext("Sound Volume") << "]";
}
#endif
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;"
os << "button_exit[3.5," << (ypos++) << ";4,0.5;btn_key_config;"
<< strgettext("Change Keys") << "]";
#endif
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;"
os << "button_exit[3.5," << (ypos++) << ";4,0.5;btn_exit_menu;"
<< strgettext("Exit to Menu") << "]";
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
os << "button_exit[3.5," << (ypos++) << ";4,0.5;btn_exit_os;"
<< strgettext("Exit to OS") << "]"
<< "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]"
/* << "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]"
<< "textarea[0.4,0.25;3.9,6.25;;" << PROJECT_NAME_C " " VERSION_STRING "\n"
<< "\n"
<< strgettext("Game info:") << "\n";
@ -4243,7 +4408,7 @@ void Game::showPauseMenu()
}
}
os << ";]";
os << ";]"*/;
/* Create menu */
/* Note: FormspecFormSource and LocalFormspecHandler *
@ -4256,6 +4421,8 @@ void Game::showPauseMenu()
fs_src, txt_dst, client->getFormspecPrepend());
formspec->setFocus("btn_continue");
formspec->doPause = true;
runData.pause_game_timer = 0;
}
/****************************************************************************/
@ -4264,6 +4431,8 @@ void Game::showPauseMenu()
****************************************************************************/
/****************************************************************************/
static Game *g_game = NULL;
void the_game(bool *kill,
bool random_input,
InputHandler *input,
@ -4280,6 +4449,7 @@ void the_game(bool *kill,
bool simple_singleplayer_mode)
{
Game game;
g_game = &game;
/* Make a copy of the server address because if a local singleplayer server
* is created then this is updated and we don't want to change the value
@ -4309,5 +4479,25 @@ void the_game(bool *kill,
strgettext("\nCheck debug.txt for details.");
errorstream << error_message << std::endl;
}
g_game = NULL;
game.shutdown();
}
#if defined(__ANDROID__) || defined(__IOS__)
void external_pause_game()
{
if (!g_game)
return;
g_game->pauseGame();
}
#endif
#ifdef __IOS__
void external_statustext(const char *text, float duration)
{
if (!g_game)
return;
std::wstring s = narrow_to_wide(std::string(text));
g_game->customStatustext(s, duration);
}
#endif

View File

@ -65,7 +65,7 @@ void GameUI::init()
// Object infos are shown in this
m_guitext_info = gui::StaticText::add(guienv, L"",
core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5)
+ v2s32(100, 200), false, true, guiroot);
+ v2s32(100, 200) * RenderingEngine::getDisplayDensity(), false, true, guiroot);
// Status text (displays info when showing and hiding GUI stuff, etc.)
m_guitext_status = gui::StaticText::add(guienv, L"<Status>",
@ -95,13 +95,15 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
const GUIChatConsole *chat_console, float dtime)
{
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
LocalPlayer *player = client->getEnv().getLocalPlayer();
v3f player_position = player->getPosition();
std::ostringstream os(std::ios_base::binary);
if (m_flags.show_debug) {
static float drawtime_avg = 0;
drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
u16 fps = 1.0 / stats.dtime_jitter.avg;
std::ostringstream os(std::ios_base::binary);
os << std::fixed
<< PROJECT_NAME_C " " << g_version_hash
<< " | FPS: " << fps
@ -115,25 +117,28 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
<< (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
<< std::setprecision(3)
<< " | RTT: " << client->getRTT() << "s";
setStaticText(m_guitext, utf8_to_wide(os.str()).c_str());
} else {
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_debug);
m_guitext->setVisible(m_flags.show_hud);
if (m_flags.show_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)) << "\xC2\xB0 "
<< "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)) << "\xC2\xB0"
<< " | seed: " << ((u64)client->getMapSeed());
@ -157,7 +162,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
));
}
m_guitext2->setVisible(m_flags.show_debug);
m_guitext2->setVisible(m_flags.show_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);
@ -179,7 +184,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 ,
@ -220,10 +228,10 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
{
// Update gui element size and position
s32 chat_y = 5;
s32 chat_y = 5 + g_fontengine->getLineHeight();;
if (m_flags.show_debug)
chat_y += 2 * g_fontengine->getLineHeight();
chat_y += g_fontengine->getLineHeight();
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
@ -257,7 +265,7 @@ void GameUI::updateProfiler()
core::position2di upper_left(6, 50);
core::position2di lower_right = upper_left;
lower_right.X += size.Width + 10;
lower_right.Y += size.Height;
lower_right.Y += size.Height;
m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right));
}

View File

@ -103,7 +103,7 @@ Hud::Hud(gui::IGUIEnvironment *guienv, 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);
@ -332,7 +332,7 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
(e->number >> 0) & 0xFF);
std::wstring text = unescape_translate(utf8_to_wide(e->text));
core::dimension2d<u32> textsize = textfont->getDimension(text.c_str());
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
// The text size on Android is not proportional with the actual scaling
irr::gui::IGUIFont *font_scaled = font_size <= 3 ?
textfont : g_fontengine->getFont(font_size - 3);
@ -345,7 +345,7 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
text_height * e->scale.Y * m_scale_factor);
v2s32 offs(e->offset.X * m_scale_factor,
e->offset.Y * m_scale_factor);
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
if (e->offset.X < -20)
font_scaled->draw(text.c_str(), size + pos + offset + offs, color);
else
@ -464,6 +464,8 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
p += offset;
p.Y -= g_settings->getU16("hud_move_upwards");
v2s32 steppos;
switch (drawdir) {
case HUD_DIR_RIGHT_LEFT:
@ -575,7 +577,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 -= g_settings->getU16("hud_move_upwards");
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
if ((float) width / (float) window_size.X <=

View File

@ -23,6 +23,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gui/mainmenumanager.h"
#include "hud.h"
#if defined(__ANDROID__)
#include "porting_android.h"
#endif
#ifdef __IOS__
#include "porting_ios.h"
#endif
#if defined(__ANDROID__) || defined(__IOS__)
extern void external_pause_game();
#endif
void KeyCache::populate_nonchanging()
{
key[KeyType::ESC] = EscapeKey;
@ -67,6 +79,9 @@ void KeyCache::populate()
key[KeyType::CAMERA_MODE] = getKeySetting("keymap_camera_mode");
key[KeyType::INCREASE_VIEWING_RANGE] =
getKeySetting("keymap_increase_viewing_range_min");
#if defined(__MACH__) && defined(__APPLE__)
key[KeyType::INCREASE_VIEWING_RANGE2] = "=";
#endif
key[KeyType::DECREASE_VIEWING_RANGE] =
getKeySetting("keymap_decrease_viewing_range_min");
key[KeyType::RANGESELECT] = getKeySetting("keymap_rangeselect");
@ -129,6 +144,23 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
}
#endif
#ifdef __IOS__
if (event.EventType == irr::EET_APPLICATION_EVENT) {
int AppEvent = event.ApplicationEvent.EventType;
if (AppEvent == irr::EAET_DID_PAUSE) {
external_pause_game();
#ifdef ADS
ads_set_paused(true);
#endif
}
#ifdef ADS
if (AppEvent == irr::EAET_DID_RESUME)
ads_set_paused(false);
#endif
return true;
}
#endif
if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
/* TODO add a check like:
if (event.JoystickEvent != joystick_we_listen_for)
@ -159,6 +191,12 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
if (event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) {
rightreleased = true;
}
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
if (event.MouseInput.Event == EMIE_MOUSE_WHEEL_X) {
mouse_wheel -= event.MouseInput.Wheel;
return true;
}
#endif
if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
mouse_wheel += event.MouseInput.Wheel;
}
@ -172,8 +210,10 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
LL_NONE, // ELL_NONE
};
assert(event.LogEvent.Level < ARRLEN(irr_loglev_conv));
#if !defined(__ANDROID__) && !defined(__IOS__)
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

@ -65,6 +65,7 @@ public:
TOGGLE_PROFILER,
CAMERA_MODE,
INCREASE_VIEWING_RANGE,
INCREASE_VIEWING_RANGE2,
DECREASE_VIEWING_RANGE,
RANGESELECT,
ZOOM,

View File

@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "localplayer.h"
#include <cmath>
#include "event.h"
#include "mtevent.h"
#include "collision.h"
#include "nodedef.h"
#include "settings.h"
@ -290,6 +290,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 (touching_ground)
player_stepheight += (0.6f * BS);
#endif
v3f accel_f;
const v3f initial_position = position;
const v3f initial_speed = m_speed;
@ -634,10 +639,21 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
if (superspeed || (is_climbing && fast_climb) ||
((in_liquid || in_liquid_stable) && fast_climb))
speedH = speedH.normalize() * movement_speed_fast;
else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable)
else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable) {
speedH = speedH.normalize() * movement_speed_crouch;
else
if (!m_sneak_offset && !getParent() && (physics_override_speed != 0)) {
eye_offset_first += v3f(0,-3,0);
eye_offset_third += v3f(0,-3,0);
m_sneak_offset = true;
}
} else {
speedH = speedH.normalize() * movement_speed_walk;
if (m_sneak_offset && !getParent() && (physics_override_speed != 0)) {
eye_offset_first += v3f(0,3,0);
eye_offset_third += v3f(0,3,0);
m_sneak_offset = false;
}
}
// Acceleration increase
f32 incH = 0.0f; // Horizontal (X, Z)
@ -658,11 +674,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;
@ -906,6 +929,10 @@ 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
player_stepheight += (0.6 * BS);
#endif
v3f accel_f;
const v3f initial_position = position;
const v3f initial_speed = m_speed;
@ -1103,6 +1130,34 @@ 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)

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

@ -284,12 +284,19 @@ void Minimap::setMinimapMode(MinimapMode mode)
{
static const MinimapModeDef modedefs[MINIMAP_MODE_COUNT] = {
{false, 0, 0},
#if !defined(__ANDROID__) && !defined(__IOS__)
{false, m_surface_mode_scan_height, 256},
{false, m_surface_mode_scan_height, 128},
#endif
{false, m_surface_mode_scan_height, 64},
#if !defined(__ANDROID__) && !defined(__IOS__)
{true, 32, 128},
{true, 32, 64},
{true, 32, 32}
#endif
#if defined(__ANDROID__) || defined(__IOS__)
{true, 32, 32}
#endif
};
if (mode >= MINIMAP_MODE_COUNT)
@ -369,7 +376,7 @@ void Minimap::blitMinimapPixelsToImageSurface(
map_image->setPixel(x, data->map_size - z - 1, tilecolor);
u32 h = mmpixel->height;
const u32 h = 255; // full bright
heightmap_image->setPixel(x,data->map_size - z - 1,
video::SColor(255, h, h, h));
}
@ -403,8 +410,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));
}
}
@ -486,7 +498,7 @@ void Minimap::drawMinimap()
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->is_radar ? 0 : data->heightmap_texture;
if (m_enable_shaders && !data->is_radar) {
u16 sid = m_shdrsrc->getShader("minimap_shader", 1, 1);

View File

@ -33,6 +33,7 @@ class IShaderSource;
#define MINIMAP_MAX_SX 512
#define MINIMAP_MAX_SY 512
#if !defined(__ANDROID__) && !defined(__IOS__)
enum MinimapMode {
MINIMAP_MODE_OFF,
MINIMAP_MODE_SURFACEx1,
@ -43,6 +44,14 @@ enum MinimapMode {
MINIMAP_MODE_RADARx4,
MINIMAP_MODE_COUNT,
};
#else
enum MinimapMode {
MINIMAP_MODE_OFF,
MINIMAP_MODE_SURFACEx1,
MINIMAP_MODE_RADARx1,
MINIMAP_MODE_COUNT,
};
#endif
enum MinimapShape {
MINIMAP_SHAPE_SQUARE,

View File

@ -35,7 +35,7 @@ void RenderingCoreInterlaced::initMaterial()
IShaderSource *s = client->getShaderSource();
mat.UseMipMaps = false;
mat.ZBuffer = false;
mat.ZWriteEnable = false;
mat.setFlag(video::EMF_ZWRITE_ENABLE, false); // ZWriteEnable is bool on early 1.9 but E_ZWRITE on later 1.9
u32 shader = s->getShader("3d_interlaced_merge", TILE_MATERIAL_BASIC, 0);
mat.MaterialType = s->getShaderInfo(shader).material;
for (int k = 0; k < 3; ++k) {

View File

@ -38,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
@ -85,6 +85,12 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
{
sanity_check(!s_singleton);
#ifdef __ANDROID__
// Set correct resolution
g_settings->setU16("screen_w", porting::getDisplaySize().X);
g_settings->setU16("screen_h", porting::getDisplaySize().Y);
#endif
// Resolution selection
bool fullscreen = g_settings->getBool("fullscreen");
u16 screen_w = g_settings->getU16("screen_w");
@ -129,7 +135,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
params.EventReceiver = receiver;
params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
params.ZBufferBits = 24;
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
params.PrivateData = porting::app_global;
#endif
#if ENABLE_GLES
@ -148,6 +154,16 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
gui::EGST_WINDOWS_METALLIC, driver);
m_device->getGUIEnvironment()->setSkin(skin);
skin->drop();
#ifdef __IOS__
if (device) {
CIrrDeviceiOS* dev = (CIrrDeviceiOS*) device;
porting::setViewController(dev->getViewController());
#ifdef ADS
ads_startup(dev->getViewController());
#endif
}
#endif
}
RenderingEngine::~RenderingEngine()
@ -475,6 +491,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 = RenderingEngine::get_instance()->getWindowSize();
v2s32 textsize(g_fontengine->getTextWidth(text), g_fontengine->getLineHeight());
@ -485,6 +509,7 @@ void RenderingEngine::_draw_load_screen(const std::wstring &text,
guienv->addStaticText(text.c_str(), textrect, false, false);
guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
clouds = false; // disable clouds at loading time
bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
if (cloud_menu_background) {
g_menuclouds->step(dtime * 3);
@ -492,8 +517,14 @@ 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");
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)) {
@ -502,27 +533,78 @@ void RenderingEngine::_draw_load_screen(const std::wstring &text,
tsrc->getTexture("progress_bar_bg.png");
if (progress_img && progress_img_bg) {
#ifndef __ANDROID__
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 scale = RenderingEngine::getDisplayDensity();
scale = scale >= 1 ? scale : 1;
u32 imgW = rangelim(img_size.Width, 256, 1024) * scale;
u32 imgH = rangelim(img_size.Height, 32, 128) * scale;
float imgR = 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 = npot2(screensize.X / 2.0f);
if (imgW > (screensize.X * 0.7) && imgW >= 1024)
imgW /= 2;
u32 imgH = imgW * imgRatio;
float imgR = (float) (imgW) / img_size.Width;
#endif
v2s32 img_pos((screensize.X - imgW) / 2,
(screensize.Y - imgH) / 2);
draw2DImageFilterScaled(get_video_driver(), progress_img_bg,
core::rect<s32>(img_pos.X, img_pos.Y,
img_pos.X + imgW,
img_pos.Y + imgH),
core::rect<s32>(0, 0, img_size.Width,
img_size.Height),
0, 0, true);
draw2DImageFilterScaled(
driver, progress_img_bg,
core::rect<s32>(img_pos.X, img_pos.Y, img_pos.X + imgW, img_pos.Y + imgH),
core::rect<s32>(0, 0, img_size.Width, img_size.Height),
0, 0, true);
// rects for drawing a color progress bar
const static core::rect<s32> rects[] = {
core::rect<s32>( 4, 24, 5, 40),
core::rect<s32>( 5, 21, 6, 43),
core::rect<s32>( 6, 19, 7, 45),
core::rect<s32>( 7, 17, 8, 47),
core::rect<s32>( 8, 15, 9, 49),
core::rect<s32>( 9, 14, 10, 50),
core::rect<s32>( 10, 13, 11, 51),
core::rect<s32>( 11, 12, 12, 52),
core::rect<s32>( 12, 11, 13, 53),
core::rect<s32>( 13, 10, 14, 54),
core::rect<s32>( 14, 9, 15, 55),
core::rect<s32>( 15, 8, 17, 56),
core::rect<s32>( 17, 7, 19, 57),
core::rect<s32>( 19, 6, 21, 58),
core::rect<s32>( 21, 5, 24, 59),
core::rect<s32>( 24, 4, 488, 60),
core::rect<s32>(488, 5, 491, 59),
core::rect<s32>(491, 6, 493, 58),
core::rect<s32>(493, 7, 495, 57),
core::rect<s32>(495, 8, 497, 56),
core::rect<s32>(497, 9, 498, 55),
core::rect<s32>(498, 10, 499, 54),
core::rect<s32>(499, 11, 500, 53),
core::rect<s32>(500, 12, 501, 52),
core::rect<s32>(501, 13, 502, 51),
core::rect<s32>(502, 14, 503, 50),
core::rect<s32>(503, 15, 504, 49),
core::rect<s32>(504, 17, 505, 47),
core::rect<s32>(505, 19, 506, 45),
core::rect<s32>(506, 21, 507, 43),
core::rect<s32>(507, 24, 508, 40)
};
for (const auto & i : rects) {
const s32 clipx = (percent * imgW) / 100;
core::rect<s32> r(
MYMIN(i.UpperLeftCorner.X * imgR, clipx), i.UpperLeftCorner.Y * imgR,
MYMIN(i.LowerRightCorner.X * imgR, clipx), i.LowerRightCorner.Y * imgR
);
if (r.getArea() <= 0)
break;
get_video_driver()->draw2DRectangle(
video::SColor(255, 255 - percent * 2, percent * 2, 25),
r + img_pos, nullptr);
}
draw2DImageFilterScaled(get_video_driver(), progress_img,
core::rect<s32>(img_pos.X, img_pos.Y,
@ -641,7 +723,7 @@ const char *RenderingEngine::getVideoDriverFriendlyName(irr::video::E_DRIVER_TYP
return driver_names[type];
}
#ifndef __ANDROID__
#if !defined(__ANDROID__) && !defined(__IOS__)
#if defined(XORG_USED)
static float calcDisplayDensity()
@ -725,7 +807,7 @@ v2u32 RenderingEngine::getDisplaySize()
return deskres;
}
#else // __ANDROID__
#else // __ANDROID__/__IOS__
float RenderingEngine::getDisplayDensity()
{
return porting::getDisplayDensity();
@ -735,4 +817,4 @@ v2u32 RenderingEngine::getDisplaySize()
{
return porting::getDisplaySize();
}
#endif // __ANDROID__
#endif // __ANDROID__/__IOS__

View File

@ -48,10 +48,13 @@ Sky::Sky(s32 id, ITextureSource *tsrc) :
mat.Lighting = false;
#if ENABLE_GLES
mat.ZBuffer = video::ECFN_DISABLED;
#elif defined(__MACH__) && defined(__APPLE__) && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
// ugly but for making cpp_lint happy...
mat.ZBuffer = video::ECFN_DISABLED;
#else
mat.ZBuffer = video::ECFN_NEVER;
#endif
mat.ZWriteEnable = false;
mat.setFlag(video::EMF_ZWRITE_ENABLE, false); // ZWriteEnable is bool on early 1.9 but E_ZWRITE on later 1.9
mat.AntiAliasing = 0;
mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
@ -249,7 +252,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);
@ -272,7 +275,7 @@ void Sky::render()
}
driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
}
}
}*/
// Draw stars before sun and moon to be behind them
if (m_star_params.visible)

View File

@ -1015,7 +1015,7 @@ video::IImage* TextureSource::generateImage(const std::string &name)
#if ENABLE_GLES
#if !defined(__ANDROID__) && !defined(__IOS__)
static inline u16 get_GL_major_version()
{
const GLubyte *gl_version = glGetString(GL_VERSION);
@ -1036,6 +1036,13 @@ bool hasNPotSupport()
strstr((char *)glGetString(GL_EXTENSIONS), "GL_OES_texture_npot");
return supported;
}
#else
// gles3 has NPotSupport, but this is using too many resources
bool hasNPotSupport()
{
return false;
}
#endif
/**
* Check and align image to npot2 if required by hardware
@ -1057,13 +1064,15 @@ 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;
#ifdef __IOS__
if (height > 64 || width > 64) {
height /= 2;
width /= 2;
}
#endif
video::IImage *targetimage =
driver->createImage(video::ECF_A8R8G8B8,
@ -1244,8 +1253,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,

View File

@ -21,6 +21,7 @@
#cmakedefine01 USE_FREETYPE
#cmakedefine01 USE_CURSES
#cmakedefine01 USE_LEVELDB
#cmakedefine01 USE_SQLITE
#cmakedefine01 USE_LUAJIT
#cmakedefine01 USE_POSTGRESQL
#cmakedefine01 USE_PROMETHEUS

View File

@ -11,7 +11,7 @@
#if defined USE_CMAKE_CONFIG_H
#include "cmake_config.h"
#elif defined (__ANDROID__)
#elif defined(__ANDROID__) || defined(__APPLE__)
#define PROJECT_NAME "multicraft"
#define PROJECT_NAME_C "MultiCraft"
#define STATIC_SHAREDIR ""

View File

@ -110,5 +110,9 @@ 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 (14)
#else
#define TTF_DEFAULT_FONT_SIZE (18)
#endif
#define DEFAULT_FONT_SIZE (10)

View File

@ -313,9 +313,15 @@ bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamesp
Settings conf;
conf.set("gameid", gamespec.id);
#if !defined(__ANDROID__) && !defined(__APPLE__)
conf.set("backend", "sqlite3");
conf.set("player_backend", "sqlite3");
conf.set("auth_backend", "sqlite3");
#else
conf.set("backend", "leveldb");
conf.set("player_backend", "leveldb");
conf.set("auth_backend", "leveldb");
#endif
conf.setBool("creative_mode", g_settings->getBool("creative_mode"));
conf.setBool("enable_damage", g_settings->getBool("enable_damage"));

View File

@ -27,6 +27,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen/mapgen.h" // Mapgen::setDefaultSettings
#include "util/string.h"
#ifdef __APPLE__
#ifdef __IOS__
#import "SDVersion.h"
#else
#import <AppKit/AppKit.h>
#endif
#endif
void set_default_settings(Settings *settings)
{
// Client and server
@ -38,7 +46,7 @@ void set_default_settings(Settings *settings)
// 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");
@ -62,7 +70,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("enable_client_modding", "true");
settings->setDefault("max_out_chat_queue_size", "20");
settings->setDefault("pause_on_lost_focus", "false");
settings->setDefault("enable_register_confirmation", "true");
settings->setDefault("enable_register_confirmation", "false");
// Keymap
settings->setDefault("remote_port", "30000");
@ -169,7 +177,7 @@ void set_default_settings(Settings *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("fullscreen_bpp", "24");
@ -200,7 +208,7 @@ void set_default_settings(Settings *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");
@ -213,7 +221,7 @@ void set_default_settings(Settings *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");
@ -224,10 +232,12 @@ void set_default_settings(Settings *settings)
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", "true");
settings->setDefault("show_entity_selectionbox", "false");
settings->setDefault("texture_clean_transparent", "false");
settings->setDefault("texture_min_size", "64");
settings->setDefault("texture_min_size", "0");
settings->setDefault("ambient_occlusion_gamma", "2.2");
#if ENABLE_GLES
settings->setDefault("enable_shaders", "false");
@ -235,11 +245,11 @@ void set_default_settings(Settings *settings)
settings->setDefault("enable_shaders", "true");
#endif
settings->setDefault("enable_particles", "true");
settings->setDefault("arm_inertia", "true");
settings->setDefault("arm_inertia", "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");
@ -275,11 +285,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("aux1_descends", "false");
settings->setDefault("doubletap_jump", "false");
settings->setDefault("always_fly_fast", "true");
#ifdef __ANDROID__
settings->setDefault("autojump", "true");
#else
settings->setDefault("autojump", "false");
#endif
settings->setDefault("continuous_forward", "false");
settings->setDefault("enable_joysticks", "false");
settings->setDefault("joystick_id", "0");
@ -288,25 +294,48 @@ void set_default_settings(Settings *settings)
settings->setDefault("joystick_frustum_sensitivity", "170");
// Main menu
settings->setDefault("main_menu_style", "full");
settings->setDefault("main_menu_path", "");
settings->setDefault("serverlist_file", "favoriteservers.txt");
#if USE_FREETYPE
settings->setDefault("freetype", "true");
#if !defined(__ANDROID__) && !defined(__IOS__)
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", porting::getDataPath("fonts" DIR_DELIM "Retron2000.ttf"));
settings->setDefault("font_path_italic", porting::getDataPath("fonts" DIR_DELIM "Retron2000.ttf"));
settings->setDefault("font_path_bold", porting::getDataPath("fonts" DIR_DELIM "Retron2000.ttf"));
settings->setDefault("font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Retron2000.ttf"));
#endif
settings->setDefault("font_bold", "false");
settings->setDefault("font_italic", "false");
settings->setDefault("font_shadow", "1");
settings->setDefault("font_shadow_alpha", "127");
#if !defined(__ANDROID__) && !defined(__IOS__)
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("fallback_font_path", porting::getDataPath("fonts" DIR_DELIM "DroidSansFallbackFull.ttf"));
#else
#ifdef __ANDROID__
settings->setDefault("mono_font_path", "/system/fonts/DroidSansMono.ttf");
settings->setDefault("mono_font_path_italic", porting::getDataPath("fonts" DIR_DELIM "DroidSansMono.ttf"));
settings->setDefault("mono_font_path_bold", porting::getDataPath("fonts" DIR_DELIM "DroidSansMono.ttf"));
settings->setDefault("mono_font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "DroidSansMono.ttf"));
settings->setDefault("fallback_font_path", "/system/fonts/DroidSans.ttf");
#endif
#ifdef __IOS__
settings->setDefault("mono_font_path", g_settings->get("font_path"));
settings->setDefault("mono_font_path_italic", g_settings->get("font_path"));
settings->setDefault("mono_font_path_bold", g_settings->get("font_path"));
settings->setDefault("mono_font_path_bold_italic", g_settings->get("font_path"));
settings->setDefault("fallback_font_path", g_settings->get("font_path"));
#endif
#endif
settings->setDefault("fallback_font_shadow", "1");
settings->setDefault("fallback_font_shadow_alpha", "128");
@ -346,7 +375,7 @@ void set_default_settings(Settings *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("strict_protocol_version_checking", "false");
settings->setDefault("player_transfer_distance", "0");
settings->setDefault("max_simultaneous_block_sends_per_client", "40");
@ -392,7 +421,7 @@ void set_default_settings(Settings *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("full_block_send_enable_min_time_from_building", "2.0");
@ -402,7 +431,7 @@ void set_default_settings(Settings *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", "512");
@ -416,7 +445,7 @@ void set_default_settings(Settings *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 +453,7 @@ void set_default_settings(Settings *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
@ -453,56 +482,225 @@ void set_default_settings(Settings *settings)
settings->setDefault("enable_console", "false");
settings->setDefault("screen_dpi", "72");
settings->setDefault("mainmenu_last_selected_world", "1");
// Altered settings for macOS
#if defined(__MACH__) && defined(__APPLE__)
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
settings->setDefault("keymap_sneak", "KEY_SHIFT");
settings->setDefault("fps_max", "0");
settings->setDefault("keymap_toggle_debug", "KEY_KEY_V");
settings->setDefault("keymap_camera_mode", "KEY_KEY_C");
settings->setDefault("vsync", "true");
float ScaleFactor = [[NSScreen mainScreen] backingScaleFactor];
if (ScaleFactor >= 2)
settings->setDefault("screen_dpi", "128");
// Shaders work but may reduce performance on iGPU
settings->setDefault("enable_shaders", "false");
settings->setDefault("serverlist_url", "servers.multicraft.world");
settings->setDefault("TMPFolder", porting::path_cache);
#endif
// Altered settings for Android
#ifdef __ANDROID__
// Mobile Platform
#if defined(__ANDROID__) || defined(__IOS__)
settings->setDefault("screen_w", "0");
settings->setDefault("screen_h", "0");
settings->setDefault("fullscreen", "true");
settings->setDefault("touchtarget", "true");
settings->setDefault("TMPFolder", porting::path_cache);
settings->setDefault("touchscreen_threshold","20");
settings->setDefault("fixed_virtual_joystick", "false");
settings->setDefault("touchscreen_threshold", "20");
settings->setDefault("fixed_virtual_joystick", "true");
settings->setDefault("virtual_joystick_triggers_aux", "false");
settings->setDefault("smooth_lighting", "false");
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("pause_fps_max", "10");
settings->setDefault("max_objects_per_block", "20");
settings->setDefault("sqlite_synchronous", "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("curl_verify_cert", "false");
settings->setDefault("pause_on_lost_focus", "true");
settings->setDefault("max_objects_per_block", "16");
settings->setDefault("doubletap_jump", "true");
settings->setDefault("serverlist_url", "servers.multicraft.world");
settings->setDefault("gui_scaling_filter_txr2img", "false");
settings->setDefault("autosave_screensize", "false");
// Set the optimal settings depending on the memory size [Android] | model [iOS]
#ifdef __ANDROID__
float memoryMax = porting::getMemoryMax();
#elif __IOS__
float iOS_ver = [[[UIDevice currentDevice] systemVersion] floatValue];
#endif
#ifdef __ANDROID__
if (memoryMax < 2) {
// minimal settings for less than 2GB RAM
#elif __IOS__
if (iOS_ver < 11.0) {
// minimal settings for legacy 32-bit devices
settings->setDefault("enable_minimap", "false");
settings->setDefault("enable_clouds", "false");
#endif
settings->setDefault("client_unload_unused_data_timeout", "60");
settings->setDefault("client_mapblock_limit", "50");
settings->setDefault("fps_max", "30");
settings->setDefault("pause_fps_max", "5");
settings->setDefault("viewing_range", "25");
settings->setDefault("smooth_lighting", "false");
settings->setDefault("enable_3d_clouds", "false");
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("enable_weather", "false");
#ifdef __ANDROID__
} else if (memoryMax >= 2 && memoryMax < 4) {
// low settings for 2-4GB RAM
#elif __IOS__
} else if (iOS_ver < 13.0) {
// low settings
settings->setDefault("enable_minimap", "false");
#endif
settings->setDefault("client_unload_unused_data_timeout", "120");
settings->setDefault("client_mapblock_limit", "200");
settings->setDefault("fps_max", "35");
settings->setDefault("pause_fps_max", "10");
settings->setDefault("viewing_range", "30");
settings->setDefault("smooth_lighting", "false");
settings->setDefault("enable_3d_clouds", "false");
settings->setDefault("cloud_radius", "6");
settings->setDefault("active_block_range", "1");
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("enable_weather", "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] == iPadAir)) {
// medium settings
#endif
settings->setDefault("client_unload_unused_data_timeout", "300");
settings->setDefault("client_mapblock_limit", "300");
settings->setDefault("fps_max", "35");
settings->setDefault("viewing_range", "60");
settings->setDefault("cloud_radius", "6");
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", "80");
settings->setDefault("max_block_generate_distance", "5");
#ifdef __ANDROID__
settings->setDefault("video_driver", "ogles2");
settings->setDefault("enable_shaders", "true");
#elif __IOS__
if (@available(iOS 13, *)) {
#endif
// enable visual shader effects
settings->setDefault("enable_waving_water", "true");
settings->setDefault("enable_waving_leaves", "true");
settings->setDefault("enable_waving_plants", "true");
#ifdef __IOS__
}
#endif
}
// Android Settings
#ifdef __ANDROID__
settings->setDefault("video_driver", "ogles1");
settings->setDefault("enable_shaders", "false");
settings->setDefault("debug_log_level", "error");
// Apply settings according to screen size
float x_inches = (float) porting::getDisplaySize().X /
(160.f * porting::getDisplayDensity());
if (x_inches < 3.7f) {
std::string font_size_str_small = std::to_string(TTF_DEFAULT_FONT_SIZE - 1);
if (x_inches <= 3.7) {
// small 4" phones
settings->setDefault("hud_scaling", "0.55");
settings->setDefault("font_size", font_size_str_small);
settings->setDefault("mouse_sensitivity", "0.3");
} else if (x_inches > 3.7 && x_inches <= 4.5) {
// medium phones
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("font_size", font_size_str_small);
settings->setDefault("selectionbox_width", "6");
} else if (x_inches > 4.5 && x_inches <= 5.5) {
// large 6" phones
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");
settings->setDefault("mouse_sensitivity", "0.15");
settings->setDefault("selectionbox_width", "6");
} else if (x_inches > 5.5 && x_inches <= 6.5) {
// 7" tablets
settings->setDefault("hud_scaling", "0.9");
settings->setDefault("selectionbox_width", "6");
}
// Tablets >= 6.0 use non-Android defaults for these settings
#endif // Android
// iOS Settings
#ifdef __IOS__
// Switch to olges2 with shaders on the new iOS version
if (@available(iOS 13, *)) {
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");
settings->setDefault("password_save", "true");
// 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("mouse_sensitivity", "0.33");
} else if SDVersion4and7Inch {
// 4.7" iPhone
settings->setDefault("hud_scaling", "0.65");
settings->setDefault("mouse_sensitivity", "0.27");
} else if SDVersion5and5Inch {
// 5.5" iPhone Plus
settings->setDefault("hud_scaling", "0.7");
settings->setDefault("mouse_sensitivity", "0.3");
} else if (SDVersion5and8Inch || SDVersion6and1Inch || SDVersion6and5Inch) {
// 5.8+" iPhones
settings->setDefault("hud_scaling", "0.85");
settings->setDefault("mouse_sensitivity", "0.35");
settings->setDefault("selectionbox_width", "6");
} else if SDVersion7and9Inch {
// iPad mini
settings->setDefault("hud_scaling", "0.9");
settings->setDefault("mouse_sensitivity", "0.25");
settings->setDefault("selectionbox_width", "6");
} else {
// iPad
settings->setDefault("mouse_sensitivity", "0.3");
settings->setDefault("selectionbox_width", "6");
}
// Settings for the Rounded Screen and Home Bar
if (@available(iOS 11, *)) {
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
int bottomPadding = (int) window.safeAreaInsets.bottom;
if (bottomPadding > 0) {
settings->setDefault("hud_move_upwards", "20");
if (SDVersioniPhone12Series)
settings->setDefault("round_screen", "75");
else
settings->setDefault("round_screen", "35");
}
}
#endif // iOS
#endif
}

View File

@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "config.h"
#include "porting.h"
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
#include "settings.h" // For g_settings
#endif
@ -365,7 +365,7 @@ std::string TempPath()
compatible with lua's os.tmpname which under the default
configuration hardcodes mkstemp("/tmp/lua_XXXXXX").
*/
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
return g_settings->get("TMPFolder");
#else
return DIR_DELIM "tmp";

View File

@ -24,6 +24,15 @@ 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 __APPLE__
#ifdef __IOS__
#import <UIKit/UIKit.h>
#else
#import <AppKit/AppKit.h>
#endif
#endif
#if USE_GETTEXT && defined(_MSC_VER)
#include <windows.h>
@ -127,6 +136,10 @@ void init_gettext(const char *path, const std::string &configured_language,
// Add user specified locale to environment
setenv("LANGUAGE", configured_language.c_str(), 1);
#ifdef __ANDROID__
setenv("LANG", configured_language.c_str(), 1);
#endif
// Reload locale with changed environment
setlocale(LC_ALL, "");
#elif defined(_MSC_VER)
@ -203,6 +216,17 @@ void init_gettext(const char *path, const std::string &configured_language,
}
else {
/* set current system default locale */
#ifdef __ANDROID__
char lang[3] = {0};
AConfiguration_getLanguage(porting::app_global->config, lang);
setenv("LANG", lang, 1);
#endif
#ifdef __APPLE__
char lang[3] = {0};
NSString *syslang = [[NSLocale preferredLanguages] firstObject];
[syslang getBytes:lang maxLength:2 usedLength:nil encoding:NSASCIIStringEncoding options:0 range:NSMakeRange(0, 2) remainingRange:nil];
setenv("LANG", lang, 1);
#endif
setlocale(LC_ALL, "");
}

View File

@ -505,6 +505,16 @@ video::SColor GUIButton::getOverrideColor() const
return OverrideColor;
}
video::SColor GUIButton::getActiveColor() const
{
if (OverrideColorEnabled)
return OverrideColor;
IGUISkin* skin = Environment->getSkin();
if (skin)
return skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT);
return OverrideColor;
}
void GUIButton::enableOverrideColor(bool enable)
{
OverrideColorEnabled = enable;

View File

@ -102,6 +102,8 @@ public:
//! Gets the override color
virtual video::SColor getOverrideColor(void) const;
video::SColor getActiveColor() const; // IrrLicht 1.9; doesn't hurt in 1.8
//! Sets if the button text should use the override color or the color in the gui skin.
virtual void enableOverrideColor(bool enable);

View File

@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "gettext.h"
#include <string>
#include "touchscreengui.h"
#if USE_FREETYPE
#include "irrlicht_changes/CGUITTFont.h"
@ -134,6 +135,10 @@ void GUIChatConsole::closeConsoleAtOnce()
closeConsole();
m_height = 0;
recalculateConsolePosition();
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
g_touchscreengui->show();
#endif
}
f32 GUIChatConsole::getDesiredHeight() const
@ -422,7 +427,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
return true;
}
if (event.KeyInput.Key == KEY_ESCAPE) {
if (event.KeyInput.Key == KEY_ESCAPE || event.KeyInput.Key == KEY_CANCEL) {
closeConsoleAtOnce();
m_close_on_enter = false;
// inhibit open so the_game doesn't reopen immediately

View File

@ -45,7 +45,7 @@ GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
m_client(client), m_playername(playername), m_password(password),
m_aborted(aborted), m_tsrc(tsrc)
{
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
m_touchscreen_visible = false;
#endif
}
@ -73,7 +73,11 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
/*
Calculate new sizes and positions
*/
#ifdef __ANDROID__
const float s = m_gui_scale * porting::getDisplayDensity() / 2;
#else
const float s = m_gui_scale;
#endif
DesiredRect = core::rect<s32>(
screensize.X / 2 - 600 * s / 2,
screensize.Y / 2 - 360 * s / 2,
@ -162,7 +166,7 @@ void GUIConfirmRegistration::drawMenu()
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
gui::IGUIElement::draw();
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
getAndroidUIInput();
#endif
}
@ -251,18 +255,25 @@ 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")
return false;
std::string text = porting::getInputDialogValue();
gui::IGUIElement *e = getElementFromId(ID_confirmPassword);
if (e)
e->setText(utf8_to_wide(text).c_str());
// still waiting
if (porting::getInputDialogState() == -1)
return true;
m_jni_field_name.clear();
gui::IGUIElement *e = getElementFromId(ID_confirmPassword);
if (!e || e->getType() != irr::gui::EGUIET_EDIT_BOX)
return false;
std::string text = porting::getInputDialogValue();
e->setText(utf8_to_wide(text).c_str());
return false;
}
#endif

View File

@ -51,7 +51,7 @@ public:
bool processInput();
bool OnEvent(const SEvent &event);
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool getAndroidUIInput();
#endif

View File

@ -86,9 +86,11 @@ 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);
image->drop();
// 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;
newimage->drop();
return retval;
#else
return m_driver->getTexture(name.c_str());
@ -184,6 +186,8 @@ GUIEngine::GUIEngine(JoystickController *joystick,
m_script = new MainMenuScripting(this);
m_device = RenderingEngine::get_raw_device();
try {
m_script->setMainMenuData(&m_data->script_data);
m_data->script_data.errormessage = "";
@ -260,6 +264,15 @@ void GUIEngine::run()
}
while (RenderingEngine::run() && (!m_startgame) && (!m_kill)) {
#ifdef __IOS__
if (m_device->isWindowMinimized())
#else
if (!m_device->isWindowFocused())
#endif
{
sleep_ms(50);
continue;
}
const irr::core::dimension2d<u32> &current_screen_size =
RenderingEngine::get_video_driver()->getScreenSize();
@ -297,15 +310,18 @@ void GUIEngine::run()
driver->endScene();
u32 frametime_min = 1000 / g_settings->getFloat("pause_fps_max") / 2;
if (m_clouds_enabled)
cloudPostProcess();
else
sleep_ms(25);
sleep_ms(frametime_min);
m_script->step();
#ifdef __ANDROID__
m_menu->getAndroidUIInput();
#if defined(__ANDROID__) || defined(__IOS__)
if (!porting::hasRealKeyboard())
m_menu->getAndroidUIInput();
#endif
}
}
@ -385,7 +401,7 @@ void GUIEngine::cloudPostProcess()
if (busytime_u32 < frametime_min) {
u32 sleeptime = frametime_min - busytime_u32;
RenderingEngine::get_raw_device()->sleep(sleeptime);
m_device->sleep(sleeptime);
}
}

View File

@ -218,6 +218,9 @@ private:
/** scripting interface */
MainMenuScripting *m_script = nullptr;
/** irrlicht device */
IrrlichtDevice *m_device = nullptr;
/** script basefolder */
std::string m_scriptdir = "";

View File

@ -315,7 +315,7 @@ void GUIFormSpecMenu::parseSize(parserData* data, const std::string &element)
data->invsize.Y = MYMAX(0, stof(parts[1]));
lockSize(false);
#ifndef __ANDROID__
#if !defined(__ANDROID__) && !defined(__IOS__)
if (parts.size() == 3) {
if (parts[2] == "true") {
lockSize(true,v2u32(800,600));
@ -1414,13 +1414,17 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
{
std::vector<std::string> parts = split(element,';');
if ((parts.size() == 4) ||
((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION)))
if ((parts.size() >= 4) /*||
((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION))*/)
{
std::vector<std::string> v_pos = split(parts[0],',');
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);
@ -1444,12 +1448,16 @@ 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
@ -1583,6 +1591,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)
@ -1613,6 +1623,8 @@ void GUIFormSpecMenu::parseSimpleField(parserData *data,
ECI_IBEAM
);
spec.is_dynamic = is_dynamic;
createTextField(data, spec, rect, false);
m_fields.push_back(spec);
@ -1629,6 +1641,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);
@ -1677,6 +1691,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
@ -3093,15 +3109,15 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
// the image size can't be less than 0.3 inch
// multiplied by gui_scaling, even if this means
// the form doesn't fit the screen.
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
// For mobile devices these magic numbers are
// different and forms should always use the
// maximum screen space available.
double prefer_imgsize = mydata.screensize.Y / 10 * gui_scaling;
double fitx_imgsize = mydata.screensize.X /
((12.0 / 8.0) * (0.5 + mydata.invsize.X));
double fity_imgsize = mydata.screensize.Y /
((15.0 / 11.0) * (0.85 + mydata.invsize.Y));
double fitx_imgsize = floor(mydata.screensize.X /
(1.5 * (0.5 + mydata.invsize.X)));
double fity_imgsize = floor(mydata.screensize.Y /
(1.15 * (0.85 + mydata.invsize.Y)));
use_imgsize = MYMIN(prefer_imgsize,
MYMIN(fitx_imgsize, fity_imgsize));
#else
@ -3305,7 +3321,7 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro
}
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool GUIFormSpecMenu::getAndroidUIInput()
{
if (!hasAndroidUIInput())
@ -3555,7 +3571,7 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text,
v2u32 screenSize = Environment->getVideoDriver()->getScreenSize();
int tooltip_offset_x = m_btn_height;
int tooltip_offset_y = m_btn_height;
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
tooltip_offset_x *= 3;
tooltip_offset_y = 0;
if (m_pointer.X > (s32)screenSize.X / 2)
@ -4178,8 +4194,14 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
count = MYMIN(s_count, 10);
else if (button == BET_WHEEL_DOWN)
count = 1;
else // left
else { // left
#ifdef HAVE_TOUCHSCREENGUI
if (s.listname == "craft")
count = 1;
else
#endif
count = s_count;
}
if (!event.MouseInput.Shift) {
// no shift: select item
@ -4552,14 +4574,16 @@ 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) {
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;
};
@ -259,7 +261,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

View File

@ -33,6 +33,7 @@
#include <algorithm>
#include "mainmenumanager.h" // for g_gamecallback
#include "client/renderingengine.h"
#define KMaxButtonPerColumns 12
@ -119,7 +120,11 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
{
removeChildren();
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
const float s = m_gui_scale * RenderingEngine::getDisplayDensity() * 1.5;
#else
const float s = m_gui_scale;
#endif
DesiredRect = core::rect<s32>(
screensize.X / 2 - 835 * s / 2,
screensize.Y / 2 - 430 * s / 2,

View File

@ -27,6 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "porting.h"
#include "gettext.h"
#include "client/renderingengine.h"
const int ID_oldPassword = 256;
const int ID_newPassword1 = 257;
@ -79,7 +80,13 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
/*
Calculate new sizes and positions
*/
#if defined(__ANDROID__) || defined(__IOS__)
const float s = m_gui_scale * porting::getDisplayDensity() / 2;
#elif defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
const float s = m_gui_scale * RenderingEngine::getDisplayDensity() * 1.5;
#else
const float s = m_gui_scale;
#endif
DesiredRect = core::rect<s32>(
screensize.X / 2 - 580 * s / 2,
screensize.Y / 2 - 300 * s / 2,
@ -183,7 +190,7 @@ void GUIPasswordChange::drawMenu()
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
gui::IGUIElement::draw();
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
getAndroidUIInput();
#endif
}
@ -283,12 +290,16 @@ std::string GUIPasswordChange::getNameByID(s32 id)
return "";
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool GUIPasswordChange::getAndroidUIInput()
{
if (!hasAndroidUIInput())
return false;
// still waiting
if (porting::getInputDialogState() == -1)
return true;
gui::IGUIElement *e = nullptr;
if (m_jni_field_name == "old_password")
e = getElementFromId(ID_oldPassword);
@ -296,12 +307,13 @@ bool GUIPasswordChange::getAndroidUIInput()
e = getElementFromId(ID_newPassword1);
else if (m_jni_field_name == "new_password_2")
e = getElementFromId(ID_newPassword2);
if (e) {
std::string text = porting::getInputDialogValue();
e->setText(utf8_to_wide(text).c_str());
}
m_jni_field_name.clear();
if (!e || e->getType() != irr::gui::EGUIET_EDIT_BOX)
return false;
std::string text = porting::getInputDialogValue();
e->setText(utf8_to_wide(text).c_str());
return false;
}
#endif

View File

@ -46,7 +46,7 @@ public:
bool processInput();
bool OnEvent(const SEvent &event);
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool getAndroidUIInput();
#endif

View File

@ -78,12 +78,14 @@ GUITable::GUITable(gui::IGUIEnvironment *env,
setTabOrder(-1);
updateAbsolutePosition();
float density = RenderingEngine::getDisplayDensity();
#ifdef __ANDROID__
float gui_scaling = g_settings->getFloat("gui_scaling");
scale = density * gui_scaling;
#if defined(__ANDROID__) || defined(__IOS__)
density = 1; // dp scaling is applied by the skin
#endif
core::rect<s32> relative_rect = m_scrollbar->getRelativePosition();
s32 width = (relative_rect.getWidth() / (2.0 / 3.0)) * density *
g_settings->getFloat("gui_scaling");
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
@ -386,7 +388,11 @@ void GUITable::setTable(const TableOptions &options,
image = m_images[row->content_index];
// Get content width and update xmax
#if defined(__ANDROID__) || defined(__IOS__)
row->content_width = image ? image->getOriginalSize().Width * scale : 0;
#else
row->content_width = image ? image->getOriginalSize().Width : 0;
#endif
row->content_width = MYMAX(row->content_width, width);
s32 row_xmax = row->x + padding + row->content_width;
xmax = MYMAX(xmax, row_xmax);
@ -733,17 +739,31 @@ void GUITable::drawCell(const Cell *cell, video::SColor color,
core::rect<s32> source_rect(
core::position2d<s32>(0, 0),
image->getOriginalSize());
#if defined(__ANDROID__) || defined(__IOS__)
s32 imgh = source_rect.LowerRightCorner.Y * scale;
#else
s32 imgh = source_rect.LowerRightCorner.Y;
#endif
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);
#if defined(__ANDROID__) || defined(__IOS__)
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));
#else
core::rect<s32> image_pos(dest_pos.X, dest_pos.Y,
dest_pos.X + image->getOriginalSize().Width,
dest_pos.Y + image->getOriginalSize().Height);
#endif
draw2DImageFilterScaled(driver, image, image_pos, source_rect,
&client_clip, colors, true);
}
}
}
@ -855,9 +875,19 @@ bool GUITable::OnEvent(const SEvent &event)
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
// looks awful, works same
float wheel = event.MouseInput.Wheel;
if (wheel > 0.01) wheel = 2;
else if (wheel < -0.01) wheel = -2;
m_scrollbar->setPos(m_scrollbar->getPos() +
(s32) wheel *
- (s32) m_rowheight / 2);
#else
m_scrollbar->setPos(m_scrollbar->getPos() +
(event.MouseInput.Wheel < 0 ? -3 : 3) *
- (s32) m_rowheight / 2);
#endif
return true;
}

View File

@ -201,6 +201,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

@ -30,6 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "settings.h"
#include "gettext.h"
#include "client/renderingengine.h"
const int ID_soundText = 263;
const int ID_soundExitButton = 264;
@ -74,7 +75,11 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
/*
Calculate new sizes and positions
*/
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
const float s = m_gui_scale * RenderingEngine::getDisplayDensity() * 1.5;
#else
const float s = m_gui_scale;
#endif
DesiredRect = core::rect<s32>(
screensize.X / 2 - 380 * s / 2,
screensize.Y / 2 - 200 * s / 2,

View File

@ -32,13 +32,13 @@ GUIModalMenu::GUIModalMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
IMenuManager *menumgr) :
IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
core::rect<s32>(0, 0, 100, 100)),
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
m_jni_field_name(""),
#endif
m_menumgr(menumgr)
{
m_gui_scale = g_settings->getFloat("gui_scaling");
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
float d = porting::getDisplayDensity();
m_gui_scale *= 1.1 - 0.3 * d + 0.2 * d * d;
#endif
@ -114,7 +114,7 @@ void GUIModalMenu::removeChildren()
bool GUIModalMenu::preprocessEvent(const SEvent &event)
{
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
// clang-format off
// display software keyboard when clicking edit boxes
if (event.EventType == EET_MOUSE_INPUT_EVENT &&
@ -129,7 +129,7 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
std::string field_name = getNameByID(hovered->getID());
// read-only field
if (field_name.empty())
if (field_name.empty() || porting::hasRealKeyboard())
return retval;
m_jni_field_name = field_name;
@ -139,7 +139,8 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
std::string label = wide_to_utf8(getLabelByID(hovered->getID()));
if (label.empty())
label = "text";
message += gettext(label) + ":";
message += gettext(label.c_str());
message += ":";
// single line text input
int type = 2;
@ -248,7 +249,7 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
return false;
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
bool GUIModalMenu::hasAndroidUIInput()
{
// no dialog shown

View File

@ -53,7 +53,7 @@ public:
virtual bool preprocessEvent(const SEvent& event);
virtual bool OnEvent(const SEvent& event) { return false; };
virtual bool pausesGame() { return false; } // Used for pause menu
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
virtual bool getAndroidUIInput() { return false; }
bool hasAndroidUIInput();
#endif
@ -66,7 +66,7 @@ protected:
v2s32 m_old_pointer; // Mouse position after previous mouse event
v2u32 m_screensize_old;
float m_gui_scale;
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__IOS__)
v2s32 m_down_pos;
std::string m_jni_field_name;
#endif

View File

@ -1198,3 +1198,12 @@ void TouchScreenGUI::show()
Toggle(true);
}
void TouchScreenGUI::handleReleaseAll()
{
m_known_ids.clear();
if (m_move_id != -1)
handleReleaseEvent(m_move_id);
for (auto & m_button : m_buttons)
m_button.ids.clear();
}

View File

@ -198,6 +198,9 @@ public:
void hide();
void show();
// handle all buttons
void handleReleaseAll();
private:
IrrlichtDevice *m_device;
IGUIEnvironment *m_guienv;

View File

@ -382,7 +382,7 @@ const HTTPFetchResult * HTTPFetchOngoing::complete(CURLcode res)
}
if (res != CURLE_OK) {
errorstream << request.url << " not found ("
warningstream << request.url << " not found ("
<< curl_easy_strerror(res) << ")"
<< " (response code " << result.response_code << ")"
<< std::endl;

View File

@ -49,7 +49,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define HUD_PARAM_HOTBAR_SELECTED_IMAGE 3
#define HUD_HOTBAR_ITEMCOUNT_DEFAULT 8
#if !defined(__ANDROID__) && !defined(__IOS__)
#define HUD_HOTBAR_ITEMCOUNT_MAX 32
#else
#define HUD_HOTBAR_ITEMCOUNT_MAX 9
#endif
#define HOTBAR_IMAGE_SIZE 48

View File

@ -5,7 +5,6 @@
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "static_text.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include <IGUIFont.h>
#include <IVideoDriver.h>
@ -255,6 +254,10 @@ video::SColor StaticText::getOverrideColor() const
return ColoredText.getDefaultColor();
}
video::SColor StaticText::getActiveColor() const
{
return ColoredText.getDefaultColor();
}
//! Sets if the static text should use the overide color or the
//! color in the gui skin.
@ -640,6 +643,3 @@ void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWr
#endif // USE_FREETYPE
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -6,9 +6,6 @@
#pragma once
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIStaticText.h"
#include "irrArray.h"
@ -140,6 +137,8 @@ namespace gui
virtual video::SColor getOverrideColor() const;
#endif
video::SColor getActiveColor() const; // IrrLicht 1.9; doesn't hurt in 1.8
//! Sets if the static text should use the overide color or the
//! color in the gui skin.
virtual void enableOverrideColor(bool enable);
@ -274,5 +273,3 @@ inline void setStaticText(irr::gui::IGUIStaticText *static_text, const wchar_t *
{
setStaticText(static_text, EnrichedString(text, static_text->getOverrideColor()));
}
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -73,7 +73,7 @@ void set_light_table(float gamma)
params.gamma = rangelim(gamma, 0.33f, 3.0f);
// Boundary values should be fixed
light_LUT[0] = 0;
light_LUT[0] = 10;
light_LUT[LIGHT_SUN] = 255;
for (size_t i = 1; i < LIGHT_SUN; i++) {

View File

@ -35,6 +35,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <cerrno>
#include <cstring>
#ifdef __IOS__
#import <Foundation/Foundation.h>
#endif
const int BUFFER_LENGTH = 256;
class StringBuffer : public std::streambuf {
@ -152,6 +156,31 @@ AndroidSystemLogOutput g_android_log_output;
#endif
// iOS
#ifdef __IOS__
class IosSystemLogOutput : public ICombinedLogOutput {
public:
IosSystemLogOutput()
{
g_logger.addOutput(this);
}
~IosSystemLogOutput()
{
g_logger.removeOutput(this);
}
void logRaw(LogLevel lev, const std::string &line)
{
#if !NDEBUG
NSLog(@"%s", line.c_str());
#endif
}
};
IosSystemLogOutput g_ios_log_output;
#endif
///////////////////////////////////////////////////////////////////////////////

View File

@ -110,7 +110,11 @@ FileLogOutput file_log_output;
static OptionList allowed_options;
#ifdef __IOS__
int real_main(int argc, char *argv[])
#else
int main(int argc, char *argv[])
#endif
{
int retval;
debug_set_exception_handler();
@ -144,6 +148,9 @@ int main(int argc, char *argv[])
#ifdef __ANDROID__
porting::initAndroid();
porting::initializePathsAndroid();
#elif defined(__IOS__)
porting::initializePathsiOS();
porting::copyAssets();
#else
porting::initializePaths();
#endif
@ -184,7 +191,7 @@ int main(int argc, char *argv[])
if (g_settings->getBool("enable_console"))
porting::attachOrCreateConsole();
#ifndef __ANDROID__
#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(NDEBUG)
// Run unit tests
if (cmd_args.getFlag("run-unittests")) {
#if BUILD_UNITTESTS
@ -456,13 +463,9 @@ static bool setup_log_params(const Settings &cmd_args)
static bool create_userdata_path()
{
bool success;
#ifdef __ANDROID__
if (!fs::PathExists(porting::path_user)) {
success = fs::CreateDir(porting::path_user);
} else {
#if defined(__ANDROID__) || defined(__IOS__)
if (fs::PathExists(porting::path_user))
success = true;
}
#else
// Create user data directory
success = fs::CreateDir(porting::path_user);

View File

@ -43,7 +43,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "database/database.h"
#include "database/database-dummy.h"
#if USE_SQLITE
#include "database/database-sqlite3.h"
#endif
#include "script/scripting_server.h"
#include <deque>
#include <queue>
@ -195,8 +197,10 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
std::map<v3s16, MapBlock*> &modified_blocks,
bool remove_metadata)
{
#if USE_SQLITE
// Collect old node for rollback
RollbackNode rollback_oldnode(this, p, m_gamedef);
#endif
// This is needed for updating the lighting
MapNode oldnode = getNode(p);
@ -221,6 +225,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
modified_block.second->expireDayNightDiff();
}
#if USE_SQLITE
// Report for rollback
if(m_gamedef->rollback())
{
@ -229,6 +234,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
action.setSetNode(p, rollback_oldnode, rollback_newnode);
m_gamedef->rollback()->reportAction(action);
}
#endif
/*
Add neighboring liquid nodes and this node to transform queue.
@ -791,6 +797,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks,
n0.setLight(LIGHTBANK_DAY, 0, m_nodedef);
n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
#if USE_SQLITE
// Find out whether there is a suspect for this action
std::string suspect;
if (m_gamedef->rollback())
@ -808,7 +815,9 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks,
RollbackAction action;
action.setSetNode(p0, rollback_oldnode, rollback_newnode);
m_gamedef->rollback()->reportAction(action);
} else {
} else
#endif
{
// Set node
setNode(p0, n0);
}
@ -1219,8 +1228,13 @@ ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef,
Settings conf;
bool succeeded = conf.readConfigFile(conf_path.c_str());
if (!succeeded || !conf.exists("backend")) {
#if !defined(__ANDROID__) && !defined(__APPLE__)
// fall back to sqlite3
conf.set("backend", "sqlite3");
#else
// fall back to leveldb
conf.set("backend", "leveldb");
#endif
}
std::string backend = conf.get("backend");
dbase = createDatabase(backend, savedir, conf);
@ -1884,8 +1898,10 @@ MapDatabase *ServerMap::createDatabase(
const std::string &savedir,
Settings &conf)
{
#if USE_SQLITE
if (name == "sqlite3")
return new MapDatabaseSQLite3(savedir);
#endif
if (name == "dummy")
return new Database_Dummy();
#if USE_LEVELDB
@ -1904,7 +1920,7 @@ MapDatabase *ServerMap::createDatabase(
}
#endif
throw BaseException(std::string("Database backend ") + name + " not supported.");
throw ModError(std::string("Database backend ") + name + " not supported.");
}
void ServerMap::beginSave()

View File

@ -89,6 +89,7 @@ struct MapgenDesc {
// Of the remaining, v5 last due to age, v7 first due to being the default.
// The order of 'enum MapgenType' in mapgen.h must match this order.
static MapgenDesc g_reg_mapgens[] = {
//#if !defined(__ANDROID__) && !defined(__IOS__)
{"v7p", true},
{"v7", true},
{"valleys", true},
@ -98,6 +99,17 @@ static MapgenDesc g_reg_mapgens[] = {
{"fractal", true},
{"singlenode", true},
{"v6", true},
/*#else
{"v7p", true},
{"v7", false},
{"valleys", true},
{"carpathian", false},
{"v5", false},
{"flat", true},
{"fractal", false},
{"singlenode", false},
{"v6", false},
#endif*/
};
STATIC_ASSERT(
@ -161,16 +173,20 @@ Mapgen *Mapgen::createMapgen(MapgenType mgtype, MapgenParams *params,
EmergeParams *emerge)
{
switch (mgtype) {
//#if !defined(__ANDROID__) && !defined(__IOS__)
case MAPGEN_CARPATHIAN:
return new MapgenCarpathian((MapgenCarpathianParams *)params, emerge);
//#endif
case MAPGEN_FLAT:
return new MapgenFlat((MapgenFlatParams *)params, emerge);
//#if !defined(__ANDROID__) && !defined(__IOS__)
case MAPGEN_FRACTAL:
return new MapgenFractal((MapgenFractalParams *)params, emerge);
case MAPGEN_SINGLENODE:
return new MapgenSinglenode((MapgenSinglenodeParams *)params, emerge);
case MAPGEN_V5:
return new MapgenV5((MapgenV5Params *)params, emerge);
//#endif
case MAPGEN_V6:
return new MapgenV6((MapgenV6Params *)params, emerge);
case MAPGEN_V7:
@ -188,16 +204,20 @@ Mapgen *Mapgen::createMapgen(MapgenType mgtype, MapgenParams *params,
MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
{
switch (mgtype) {
//#if !defined(__ANDROID__) && !defined(__IOS__)
case MAPGEN_CARPATHIAN:
return new MapgenCarpathianParams;
//#endif
case MAPGEN_FLAT:
return new MapgenFlatParams;
//#if !defined(__ANDROID__) && !defined(__IOS__)
case MAPGEN_FRACTAL:
return new MapgenFractalParams;
case MAPGEN_SINGLENODE:
return new MapgenSinglenodeParams;
case MAPGEN_V5:
return new MapgenV5Params;
//#endif
case MAPGEN_V6:
return new MapgenV6Params;
case MAPGEN_V7:

View File

@ -685,6 +685,7 @@ void Channel::UpdateTimers(float dtime)
current_packet_successful = 0;
}
#if !(defined(__ANDROID__) && defined(__aarch64__))
/* dynamic window size */
float successful_to_lost_ratio = 0.0f;
bool done = false;
@ -725,6 +726,7 @@ void Channel::UpdateTimers(float dtime)
MIN_RELIABLE_WINDOW_SIZE);
}
}
#endif
}
if (bpm_counter > 10.0f) {

View File

@ -782,9 +782,9 @@ void ConnectionSendThread::sendPackets(float dtime)
if (!peer)
continue;
if (peer->m_increment_packets_remaining == 0) {
LOG(warningstream << m_connection->getDesc()
<< " Packet quota used up for peer_id=" << peerId
<< ", was " << peer_packet_quota << " pkts" << std::endl);
//LOG(warningstream << m_connection->getDesc()
// << " Packet quota used up for peer_id=" << peerId
// << ", was " << peer_packet_quota << " pkts" << std::endl);
}
}
}

View File

@ -178,8 +178,8 @@ void Server::handleCommand_Init(NetworkPacket* pkt)
std::string legacyPlayerNameCasing = playerName;
if (!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0) {
actionstream << "Server: Player with the name \"singleplayer\" tried "
if (!isSingleplayer() && strcasecmp(playername, "Player") == 0) {
actionstream << "Server: Player with the name \"Player\" tried "
"to connect from " << addr_s << std::endl;
DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_NAME);
return;
@ -1404,15 +1404,18 @@ void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt)
return;
}
#if USE_SQLITE
// If something goes wrong, this player is to blame
RollbackScopeActor rollback_scope(m_rollback,
std::string("player:")+player->getName());
// Check the target node for rollback data; leave others unnoticed
RollbackNode rn_old(&m_env->getMap(), p, this);
#endif
m_script->node_on_receive_fields(p, formname, fields, playersao);
#if USE_SQLITE
// Report rollback data
RollbackNode rn_new(&m_env->getMap(), p, this);
if (rollback() && rn_new != rn_old) {
@ -1420,6 +1423,7 @@ void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt)
action.setSetNode(p, rn_old, rn_new);
rollback()->reportAction(action);
}
#endif
}
void Server::handleCommand_InventoryFields(NetworkPacket* pkt)

View File

@ -127,6 +127,11 @@ bool UDPSocket::init(bool ipv6, bool noExceptions)
reinterpret_cast<char *>(&value), sizeof(value));
}
#ifdef __IOS__
int value = 1;
setsockopt(m_handle, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
#endif
return true;
}

View File

@ -39,7 +39,7 @@ struct ObjectProperties
std::string mesh = "";
v3f visual_size = v3f(1, 1, 1);
std::vector<std::string> textures;
std::string damage_texture_modifier = "^[brighten";
std::string damage_texture_modifier = "^[colorize:#FF000085";
std::vector<video::SColor> colors;
v2s16 spritediv = v2s16(1, 1);
v2s16 initial_sprite_basepos;

View File

@ -510,26 +510,6 @@ bool setSystemPaths()
#endif
void migrateCachePath()
{
const std::string local_cache_path = path_user + DIR_DELIM + "cache";
// Delete tmp folder if it exists (it only ever contained
// a temporary ogg file, which is no longer used).
if (fs::PathExists(local_cache_path + DIR_DELIM + "tmp"))
fs::RecursiveDelete(local_cache_path + DIR_DELIM + "tmp");
// Bail if migration impossible
if (path_cache == local_cache_path || !fs::PathExists(local_cache_path)
|| fs::PathExists(path_cache)) {
return;
}
if (!fs::Rename(local_cache_path, path_cache)) {
errorstream << "Failed to migrate local cache path "
"to system path!" << std::endl;
}
}
void initializePaths()
{
#if RUN_IN_PLACE
@ -598,8 +578,6 @@ void initializePaths()
// If neither works, use $PATH_USER/cache
path_cache = path_user + DIR_DELIM + "cache";
}
// Migrate cache folder to new location if possible
migrateCachePath();
# endif // _WIN32
#endif // RUN_IN_PLACE
@ -635,6 +613,14 @@ void initializePaths()
#endif // USE_GETTEXT
}
#ifndef __ANDROID__
// Dummy for other OS with a touchscreen
bool hasRealKeyboard()
{
return false;
}
#endif
////
//// OS-specific Secure Random
////

View File

@ -161,12 +161,6 @@ extern std::string path_cache;
*/
std::string getDataPath(const char *subpath);
/*
Move cache folder from path_user to the
system cache location if possible.
*/
void migrateCachePath();
/*
Initialize path_*.
*/
@ -282,7 +276,7 @@ inline u64 getDeltaMs(u64 old_time_ms, u64 new_time_ms)
inline const char *getPlatformName()
{
return
#if defined(ANDROID)
#if defined(__ANDROID__)
"Android"
#elif defined(__linux__)
"Linux"
@ -323,6 +317,9 @@ inline const char *getPlatformName()
;
}
// Touchscreen device specific function
bool hasRealKeyboard();
bool secure_rand_fill_buf(void *buf, size_t len);
// This attaches to the parents process console, or creates a new one if it doesnt exist.
@ -337,3 +334,7 @@ bool openURL(const std::string &url);
#ifdef __ANDROID__
#include "porting_android.h"
#endif
#ifdef __IOS__
#include "porting_ios.h"
#endif

View File

@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
extern int main(int argc, char *argv[]);
extern void external_pause_game();
void android_main(android_app *app)
{
@ -69,13 +70,24 @@ void android_main(android_app *app)
* ToDo: this doesn't work as expected, there's a workaround for it right now
*/
extern "C" {
JNIEXPORT void JNICALL Java_net_minetest_minetest_GameActivity_putMessageBoxResult(
JNIEXPORT void JNICALL Java_com_multicraft_game_GameActivity_putMessageBoxResult(
JNIEnv *env, jclass thiz, jstring text)
{
errorstream <<
"Java_net_minetest_minetest_GameActivity_putMessageBoxResult got: " <<
"Java_com_multicraft_game_GameActivity_putMessageBoxResult got: " <<
std::string((const char*) env->GetStringChars(text, nullptr)) << std::endl;
}
JNIEXPORT void JNICALL Java_com_multicraft_game_GameActivity_pauseGame(
JNIEnv *env, jclass clazz)
{
external_pause_game();
}
bool device_has_keyboard = false;
JNIEXPORT void JNICALL Java_com_multicraft_game_GameActivity_keyboardEvent(
JNIEnv *env, jclass clazz, jboolean hasKeyboard)
{
device_has_keyboard = hasKeyboard;
}
}
namespace porting {
@ -83,6 +95,8 @@ android_app *app_global;
JNIEnv *jnienv;
jclass nativeActivity;
static float device_memory_max = 0;
jclass findClass(const std::string &classname)
{
if (jnienv == nullptr)
@ -114,7 +128,7 @@ void initAndroid()
exit(-1);
}
nativeActivity = findClass("net/minetest/minetest/GameActivity");
nativeActivity = findClass("com/multicraft/game/GameActivity");
if (nativeActivity == nullptr)
errorstream <<
"porting::initAndroid unable to find java native activity class" <<
@ -124,7 +138,7 @@ void initAndroid()
// in the start-up code
__android_log_print(ANDROID_LOG_ERROR, PROJECT_NAME_C,
"Initializing GPROF profiler");
monstartup("libMinetest.so");
monstartup("libMultiCraft.so");
#endif
}
@ -187,12 +201,14 @@ void initializePathsAndroid()
"getAbsolutePath", "()Ljava/lang/String;");
std::string path_storage = getAndroidPath(cls_Env, nullptr,
mt_getAbsPath, "getExternalStorageDirectory");
std::string path_data = getAndroidPath(nativeActivity, app_global->activity->clazz, mt_getAbsPath,
"getFilesDir");
path_user = path_storage + DIR_DELIM + PROJECT_NAME_C;
path_share = path_storage + DIR_DELIM + PROJECT_NAME_C;
path_user = path_storage + DIR_DELIM + "Android/data/com.multicraft.game/files";
path_share = path_data;
path_locale = path_data + DIR_DELIM + "locale";
path_cache = getAndroidPath(nativeActivity,
app_global->activity->clazz, mt_getAbsPath, "getCacheDir");
migrateCachePath();
}
void showInputDialog(const std::string &acceptButton, const std::string &hint,
@ -254,6 +270,51 @@ std::string getInputDialogValue()
return text;
}
float getMemoryMax()
{
if (device_memory_max == 0) {
jmethodID getMemory = jnienv->GetMethodID(nativeActivity,
"getMemoryMax", "()F");
if (getMemory == nullptr)
assert("porting::getMemoryMax unable to find java method" == nullptr);
device_memory_max = jnienv->CallFloatMethod(
app_global->activity->clazz, getMemory);
}
return device_memory_max;
}
bool hasRealKeyboard()
{
return device_has_keyboard;
}
void notifyServerConnect(bool is_multiplayer)
{
jmethodID notifyConnect = jnienv->GetMethodID(nativeActivity,
"notifyServerConnect", "(Z)V");
FATAL_ERROR_IF(notifyConnect == nullptr,
"porting::notifyServerConnect unable to find java getDensity method");
auto param = (jboolean) is_multiplayer;
jnienv->CallVoidMethod(app_global->activity->clazz, notifyConnect, param);
}
void notifyExitGame()
{
jmethodID notifyExit = jnienv->GetMethodID(nativeActivity,
"notifyExitGame", "()V");
FATAL_ERROR_IF(notifyExit == nullptr,
"porting::notifyExit unable to find java getDensity method");
jnienv->CallVoidMethod(app_global->activity->clazz, notifyExit);
}
#ifndef SERVER
float getDisplayDensity()
{

View File

@ -72,6 +72,22 @@ int getInputDialogState();
*/
std::string getInputDialogValue();
/**
* get max device RAM as integer value
* returns -1 on failure
*/
float getMemoryMax();
/**
* notify java on server connection
*/
void notifyServerConnect(bool is_multiplayer);
/**
* notify java on game exit
*/
void notifyExitGame();
#ifndef SERVER
float getDisplayDensity();
v2u32 getDisplaySize();

View File

@ -1256,7 +1256,20 @@ ItemStack read_item(lua_State* L, int index, IItemDefManager *idef)
return istack;
} else {
throw LuaError("Expecting itemstack, itemstring, table or nil");
// throw LuaError("Expecting itemstack, itemstring, table or nil");
// Print a traceback
lua_getglobal(L, "debug");
lua_getfield(L, -1, "traceback");
lua_remove(L, -2); // Remove debug
lua_call(L, 0, 1);
std::string tb = lua_tostring(L, -1);
lua_remove(L, -2); // Remove the traceback
errorstream << "read_item(): Expecting itemstack, itemstring, "
<< "table or nil." << std::endl << tb << std::endl;
return ItemStack();
}
}

View File

@ -408,7 +408,7 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
} else {
push_objectRef(L, cobj->getId());
if (cobj->isGone())
warningstream << "ScriptApiBase::objectrefGetOrCreate(): "
actionstream << "ScriptApiBase::objectrefGetOrCreate(): "
<< "Pushing ObjectRef to removed/deactivated object"
<< ", this is probably a bug." << std::endl;
}

View File

@ -63,6 +63,7 @@ void ScriptApiSecurity::initializeSecurity()
"core",
"collectgarbage",
"DIR_DELIM",
"PLATFORM",
"error",
"getfenv",
"getmetatable",
@ -231,6 +232,7 @@ void ScriptApiSecurity::initializeSecurityClient()
"core",
"collectgarbage",
"DIR_DELIM",
"PLATFORM",
"error",
"getfenv",
"ipairs",
@ -629,7 +631,11 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L)
{
#ifndef SERVER
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
#if INDIRECT_SCRIPTAPI_RIDX
ScriptApiBase *script = (ScriptApiBase *) *(void**)(lua_touserdata(L, -1));
#else
ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
#endif
lua_pop(L, 1);
// Client implementation

View File

@ -335,6 +335,20 @@ int ModApiMainMenu::l_get_favorites(lua_State *L)
lua_settable(L, top_lvl2);
}
if (!server["server_id"].asString().empty()) {
lua_pushstring(L,"server_id");
std::string topush = server["server_id"].asString();
lua_pushstring(L, topush.c_str());
lua_settable(L, top_lvl2);
}
if (!server["mobile_friendly"].asString().empty()) {
lua_pushstring(L,"mobile_friendly");
std::string topush = server["mobile_friendly"].asString();
lua_pushstring(L, topush.c_str());
lua_settable(L, top_lvl2);
}
if (!server["proto_min"].asString().empty()) {
lua_pushstring(L, "proto_min");
lua_pushinteger(L, server["proto_min"].asInt());
@ -399,10 +413,10 @@ int ModApiMainMenu::l_get_favorites(lua_State *L)
lua_settable(L, top_lvl2);
}
if (server.isMember("ping")) {
float ping = server["ping"].asFloat();
lua_pushstring(L, "ping");
lua_pushnumber(L, ping);
if (server.isMember("lag")) {
float lag = server["lag"].asFloat();
lua_pushstring(L, "lag");
lua_pushnumber(L, lag);
lua_settable(L, top_lvl2);
}
@ -713,6 +727,16 @@ int ModApiMainMenu::l_get_gamepath(lua_State *L)
return 1;
}
/******************************************************************************/
int ModApiMainMenu::l_get_serverlistpath(lua_State *L)
{
std::string modpath = fs::RemoveRelativePathComponents(
porting::path_user + DIR_DELIM + "client" + DIR_DELIM +
"serverlist" + DIR_DELIM);
lua_pushstring(L, modpath.c_str());
return 1;
}
/******************************************************************************/
int ModApiMainMenu::l_get_texturepath(lua_State *L)
{
@ -1116,6 +1140,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(get_modpath);
API_FCT(get_clientmodpath);
API_FCT(get_gamepath);
API_FCT(get_serverlistpath);
API_FCT(get_texturepath);
API_FCT(get_texturepath_share);
API_FCT(get_cache_path);
@ -1147,6 +1172,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
API_FCT(get_modpath);
API_FCT(get_clientmodpath);
API_FCT(get_gamepath);
API_FCT(get_serverlistpath);
API_FCT(get_texturepath);
API_FCT(get_texturepath_share);
API_FCT(get_cache_path);

View File

@ -118,6 +118,8 @@ private:
static int l_get_gamepath(lua_State *L);
static int l_get_serverlistpath(lua_State *L);
static int l_get_texturepath(lua_State *L);
static int l_get_texturepath_share(lua_State *L);

View File

@ -246,7 +246,6 @@ int ModApiServer::l_get_player_information(lua_State *L)
lua_pushstring(L, lang_code.c_str());
lua_settable(L, table);
#ifndef NDEBUG
lua_pushstring(L,"serialization_version");
lua_pushnumber(L, ser_vers);
lua_settable(L, table);
@ -270,7 +269,6 @@ int ModApiServer::l_get_player_information(lua_State *L)
lua_pushstring(L,"state");
lua_pushstring(L,ClientInterface::state2Name(state).c_str());
lua_settable(L, table);
#endif
return 1;
}

View File

@ -118,7 +118,9 @@ void ServerScripting::InitializeModApi(lua_State *L, int top)
ModApiItemMod::Initialize(L, top);
ModApiMapgen::Initialize(L, top);
ModApiParticles::Initialize(L, top);
#if USE_SQLITE
ModApiRollback::Initialize(L, top);
#endif
ModApiServer::Initialize(L, top);
ModApiUtil::Initialize(L, top);
ModApiHttp::Initialize(L, top);

View File

@ -51,7 +51,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "modchannels.h"
#include "serverlist.h"
#include "util/string.h"
#if USE_SQLITE
#include "rollback.h"
#endif
#include "util/serialize.h"
#include "util/thread.h"
#include "defaultsettings.h"
@ -329,7 +331,9 @@ Server::~Server()
// Delete things in the reverse order of creation
delete m_emerge;
delete m_env;
#if USE_SQLITE
delete m_rollback;
#endif
delete m_banmanager;
delete m_itemdef;
delete m_nodedef;
@ -430,10 +434,12 @@ void Server::init()
// Initialize mapgens
m_emerge->initMapgens(servermap->getMapgenParams());
#if USE_SQLITE
if (g_settings->getBool("enable_rollback_recording")) {
// Create rollback manager
m_rollback = new RollbackManager(m_path_world, this);
}
#endif
// Give environment reference to scripting api
m_script->initializeEnvironment(m_env);
@ -632,7 +638,7 @@ void Server::AsyncRunStep(bool initial_step)
// send masterserver announce
{
float &counter = m_masterserver_timer;
if (!isSingleplayer() && (!counter || counter >= 300.0) &&
if (!isSingleplayer() && (!counter || counter >= 60.0) &&
g_settings->getBool("server_announce")) {
ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
ServerList::AA_START,
@ -3012,14 +3018,17 @@ void Server::handleChatInterfaceEvent(ChatEvent *evt)
std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
{
#if USE_SQLITE
// If something goes wrong, this player is to blame
RollbackScopeActor rollback_scope(m_rollback,
std::string("player:") + name);
#endif
if (g_settings->getBool("strip_color_codes"))
wmessage = unescape_enriched(wmessage);
if (player) {
const bool sscsm_com = wmessage.find(L"/admin \x01SSCSM_COM\x01", 0) == 0;
if (player && !sscsm_com) {
switch (player->canSendChatMessage()) {
case RPLAYER_CHATRESULT_FLOODING: {
std::wstringstream ws;
@ -3045,14 +3054,17 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna
L"It was refused. Send a shorter message";
}
auto message = trim(wide_to_utf8(wmessage));
if (message.find_first_of("\n\r") != std::wstring::npos) {
const std::string message = wide_to_utf8(wmessage);
if (trim(message).find_first_of("\n\r") != std::wstring::npos) {
return L"New lines are not permitted in chat messages";
}
// Run script hook, exit if script ate the chat message
if (m_script->on_chat_message(name, message))
if (m_script->on_chat_message(name, message)) {
if (!sscsm_com)
actionstream << name << " issued command: " << message << std::endl;
return L"";
}
// Line to send
std::wstring line;
@ -3152,16 +3164,18 @@ PlayerSAO *Server::getPlayerSAO(session_t peer_id)
std::wstring Server::getStatusString()
{
std::wostringstream os(std::ios_base::binary);
os << L"# Server: ";
// Disabled due to misuse.
/*os << L"# Server: ";
// Version
os << L"version=" << narrow_to_wide(g_version_string);
// Uptime
os << L", uptime=" << m_uptime_counter->get();
// Max lag estimate
os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);*/
// Information about clients
bool first = true;
/*bool first = true;
os << L", clients={";
if (m_env) {
std::vector<session_t> clients = m_clients.getClientIDs();
@ -3182,13 +3196,13 @@ std::wstring Server::getStatusString()
os << name;
}
}
os << L"}";
os << L"}";*/
if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
os /*<< std::endl*/ << L"# Server: " << " WARNING: Map saving is disabled." << std::endl;
if (!g_settings->get("motd").empty())
os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
os /*<< std::endl*/ << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
return os.str();
}
@ -3558,6 +3572,7 @@ bool Server::dynamicAddMedia(const std::string &filepath)
// actions: time-reversed list
// Return value: success/failure
#if USE_SQLITE
bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
std::list<std::string> *log)
{
@ -3599,6 +3614,7 @@ bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
// Call it done if less than half failed
return num_failed <= num_tried/2;
}
#endif
// IGameDef interface
// Under envlock

View File

@ -175,7 +175,9 @@ void PlayerSAO::step(float dtime, bool send_recommended)
MapNode n = m_env->getMap().getNode(p);
const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
// If node generates drown
if (c.drowning > 0 && m_hp > 0) {
bool noclip = m_privs.count("noclip") && g_settings->getBool("noclip");
int drowning = (c.walkable && c.drawtype != NDT_NODEBOX) ? 1 : c.drowning;
if (drowning > 0 && m_hp > 0 && !noclip) {
if (m_breath > 0)
setBreath(m_breath - 1);
@ -194,7 +196,8 @@ void PlayerSAO::step(float dtime, bool send_recommended)
MapNode n = m_env->getMap().getNode(p);
const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
// If player is alive & not drowning & not in ignore & not immortal, breathe
if (m_breath < m_prop.breath_max && c.drowning == 0 &&
int drowning = (c.walkable && c.drawtype != NDT_NODEBOX) ? 1 : c.drowning;
if (m_breath < m_prop.breath_max && drowning == 0 &&
n.getContent() != CONTENT_IGNORE && m_hp > 0)
setBreath(m_breath + 1);
}

View File

@ -40,7 +40,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gameparams.h"
#include "database/database-dummy.h"
#include "database/database-files.h"
#if USE_SQLITE
#include "database/database-sqlite3.h"
#endif
#if USE_POSTGRESQL
#include "database/database-postgresql.h"
#endif
@ -405,8 +407,13 @@ ServerEnvironment::ServerEnvironment(ServerMap *map,
std::string conf_path = path_world + DIR_DELIM + "world.mt";
Settings conf;
#if !defined(__ANDROID__) && !defined(__APPLE__)
std::string player_backend_name = "sqlite3";
std::string auth_backend_name = "sqlite3";
#else
std::string player_backend_name = "leveldb";
std::string auth_backend_name = "leveldb";
#endif
bool succeeded = conf.readConfigFile(conf_path.c_str());
@ -444,7 +451,7 @@ ServerEnvironment::ServerEnvironment(ServerMap *map,
}
}
if (player_backend_name == "files") {
/*if (player_backend_name == "files") {
warningstream << "/!\\ You are using old player file backend. "
<< "This backend is deprecated and will be removed in a future release /!\\"
<< std::endl << "Switching to SQLite3 or PostgreSQL is advised, "
@ -454,9 +461,9 @@ ServerEnvironment::ServerEnvironment(ServerMap *map,
if (auth_backend_name == "files") {
warningstream << "/!\\ You are using old auth file backend. "
<< "This backend is deprecated and will be removed in a future release /!\\"
<< std::endl << "Switching to SQLite3 is advised, "
<< std::endl << "Switching to LevelDB or SQLite3 is advised, "
<< "please read http://wiki.minetest.net/Database_backends." << std::endl;
}
}*/
m_player_database = openPlayerDatabase(player_backend_name, path_world, conf);
m_auth_database = openAuthDatabase(auth_backend_name, path_world, conf);
@ -692,7 +699,7 @@ void ServerEnvironment::loadMeta()
setTimeOfDay(args.exists("time_of_day") ?
// set day to early morning by default
args.getU64("time_of_day") : 5250);
args.getU64("time_of_day") : 6000);
m_last_clear_objects_time = args.exists("last_clear_objects_time") ?
// If missing, do as if clearObjects was never called
@ -1818,7 +1825,7 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
<<" objects)"<<std::endl;
bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
if (large_amount) {
errorstream<<"suspiciously large amount of objects detected: "
warningstream<<"suspiciously large amount of objects detected: "
<<block->m_static_objects.m_stored.size()<<" in "
<<PP(block->getPos())
<<"; removing all of them."<<std::endl;
@ -2078,9 +2085,10 @@ bool ServerEnvironment::saveStaticToBlock(
PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
const std::string &savedir, const Settings &conf)
{
#if USE_SQLITE
if (name == "sqlite3")
return new PlayerDatabaseSQLite3(savedir);
#endif
if (name == "dummy")
return new Database_Dummy();
@ -2101,7 +2109,7 @@ PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
if (name == "files")
return new PlayerDatabaseFiles(savedir + DIR_DELIM + "players");
throw BaseException(std::string("Database backend ") + name + " not supported.");
throw ModError(std::string("Database backend ") + name + " not supported.");
}
bool ServerEnvironment::migratePlayersDatabase(const GameParams &game_params,
@ -2194,8 +2202,10 @@ bool ServerEnvironment::migratePlayersDatabase(const GameParams &game_params,
AuthDatabase *ServerEnvironment::openAuthDatabase(
const std::string &name, const std::string &savedir, const Settings &conf)
{
#if USE_SQLITE
if (name == "sqlite3")
return new AuthDatabaseSQLite3(savedir);
#endif
#if USE_POSTGRESQL
if (name == "postgresql") {
@ -2213,7 +2223,7 @@ AuthDatabase *ServerEnvironment::openAuthDatabase(
return new AuthDatabaseLevelDB(savedir);
#endif
throw BaseException(std::string("Database backend ") + name + " not supported.");
throw ModError(std::string("Database backend ") + name + " not supported.");
}
bool ServerEnvironment::migrateAuthDatabase(

View File

@ -73,8 +73,14 @@ std::vector<ServerListSpec> getOnline()
u16 proto_version_min = CLIENT_PROTOCOL_VERSION_MIN;
#if !defined(__ANDROID__) && !defined(__APPLE__)
const std::string list = base64_decode("L2xpc3Q=");
#else
const std::string list = base64_decode("OjMwMDAvc2VydmVybGlzdC5qc29u");
#endif
geturl << g_settings->get("serverlist_url") <<
"/list?proto_version_min=" << proto_version_min <<
list << "?proto_version_min=" << proto_version_min <<
"&proto_version_max=" << CLIENT_PROTOCOL_VERSION_MAX;
Json::Value root = fetchJsonValue(geturl.str(), NULL);
@ -226,6 +232,7 @@ void sendAnnounce(AnnounceAction action,
server["name"] = g_settings->get("server_name");
server["description"] = g_settings->get("server_description");
server["version"] = g_version_string;
server["server_id"] = PROJECT_NAME;
server["proto_min"] = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MIN;
server["proto_max"] = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MAX;
server["url"] = g_settings->get("server_url");
@ -241,8 +248,7 @@ void sendAnnounce(AnnounceAction action,
for (const std::string &clients_name : clients_names) {
server["clients_list"].append(clients_name);
}
if (!gameid.empty())
server["gameid"] = gameid;
server["gameid"] = "MultiCraft";
}
if (action == AA_START) {
@ -274,4 +280,3 @@ void sendAnnounce(AnnounceAction action,
#endif
} // namespace ServerList

View File

@ -76,13 +76,13 @@ public:
{
SkyColor sky;
// Horizon colors
sky.day_horizon = video::SColor(255, 144, 211, 246);
sky.day_horizon = video::SColor(255, 5, 155, 245);
sky.indoors = video::SColor(255, 100, 100, 100);
sky.dawn_horizon = video::SColor(255, 186, 193, 240);
sky.dawn_horizon = video::SColor(255, 180, 186, 255);
sky.night_horizon = video::SColor(255, 64, 144, 255);
// Sky colors
sky.day_sky = video::SColor(255, 97, 181, 245);
sky.dawn_sky = video::SColor(255, 180, 186, 250);
sky.day_sky = video::SColor(255, 5, 155, 245);
sky.dawn_sky = video::SColor(255, 180, 186, 255);
sky.night_sky = video::SColor(255, 0, 107, 255);
return sky;
}

View File

@ -150,10 +150,9 @@ bool Thread::kill()
TerminateThread((HANDLE) m_thread_obj->native_handle(), 0);
CloseHandle((HANDLE) m_thread_obj->native_handle());
#else
// We need to pthread_kill instead on Android since NDKv5's pthread
// implementation is incomplete.
// We need to pthread_kill instead on Android pthread
# ifdef __ANDROID__
pthread_kill(getThreadHandle(), SIGKILL);
pthread_kill(getThreadHandle(), SIGQUIT);
# else
pthread_cancel(getThreadHandle());
# endif
@ -297,7 +296,7 @@ bool Thread::bindToProcessor(unsigned int proc_number)
return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
&answer, proc_number, getThreadHandle()) == 0;
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__IOS__)
struct thread_affinity_policy tapol;
@ -341,4 +340,3 @@ bool Thread::setPriority(int prio)
#endif
}

View File

@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <istream>
#include "util/container.h"
#include "util/numeric.h"
#ifndef ANDROID
#if !defined(__ANDROID__) && !defined(__APPLE__)
#include "cmake_config.h"
#endif
#if USE_SPATIAL

View File

@ -79,7 +79,7 @@ bool convert(const char *to, const char *from, char *outbuf,
return true;
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__APPLE__)
// Android need manual caring to support the full character set possible with wchar_t
const char *DEFAULT_ENCODING = "UTF-32LE";
#else
@ -97,7 +97,7 @@ std::wstring utf8_to_wide(const std::string &input)
char *outbuf = new char[outbuf_size];
memset(outbuf, 0, outbuf_size);
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__APPLE__)
// Android need manual caring to support the full character set possible with wchar_t
SANITY_CHECK(sizeof(wchar_t) == 4);
#endif
@ -209,7 +209,7 @@ wchar_t *narrow_to_wide_c(const char *str)
}
std::wstring narrow_to_wide(const std::string &mbs) {
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__APPLE__)
return utf8_to_wide(mbs);
#else
size_t wcl = mbs.size();
@ -225,7 +225,7 @@ std::wstring narrow_to_wide(const std::string &mbs) {
std::string wide_to_narrow(const std::wstring &wcs)
{
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__APPLE__)
return wide_to_utf8(wcs);
#else
size_t mbl = wcs.size() * 4;

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 413 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 294 B

View File

@ -4,5 +4,6 @@ mkdir cmakebuild
cd cmakebuild
cmake -DCMAKE_BUILD_TYPE=Debug \
-DRUN_IN_PLACE=TRUE -DENABLE_GETTEXT=TRUE \
-DBUILD_UNITTESTS=TRUE \
-DBUILD_SERVER=TRUE ${CMAKE_FLAGS} ..
make -j2