1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-20 20:23:03 +02:00

Merge remote-tracking branch 'origin/develop' into terrain-rewrite

# Conflicts:
#	lib/Terrain.cpp
#	lib/Terrain.h
#	lib/battle/CBattleInfoEssentials.cpp
#	lib/rmg/ObstaclePlacer.cpp
#	lib/rmg/RiverPlacer.cpp
This commit is contained in:
Tomasz Zieliński 2022-09-27 07:50:17 +02:00
commit f386f42166
636 changed files with 4774 additions and 971 deletions

View File

@ -90,6 +90,12 @@ jobs:
preset: macos-arm-conan-ninja-release
conan_profile: macos-arm
artifact_platform: arm
- platform: ios
os: macos-12
test: 0
pack: 1
extension: ipa
preset: ios-release
- platform: mxe
os: ubuntu-20.04
mxe: i686-w64-mingw32.shared
@ -189,6 +195,8 @@ jobs:
cd '${{github.workspace}}/out/build/${{matrix.preset}}'
CPACK_PATH=`which -a cpack | grep -m1 -v -i chocolatey`
"$CPACK_PATH" -C ${{env.BUILD_TYPE}} ${{ matrix.cpack_args }}
test -f '${{github.workspace}}/CI/${{matrix.platform}}/post_pack.sh' \
&& '${{github.workspace}}/CI/${{matrix.platform}}/post_pack.sh' '${{github.workspace}}' "$(ls '${{ env.VCMI_PACKAGE_FILE_NAME }}'.*)"
rm -rf _CPack_Packages
- name: Additional logs

2
.gitignore vendored
View File

@ -39,6 +39,8 @@ doc/*
VCMI_VS11.sdf
*.ipch
VCMI_VS11.opensdf
.DS_Store
CMakeUserPresets.json
# Visual Studio
*.suo

View File

@ -13,7 +13,12 @@
#include "PossibleSpellcast.h"
#include "PotentialTargets.h"
VCMI_LIB_NAMESPACE_BEGIN
class CSpell;
VCMI_LIB_NAMESPACE_END
class EnemyInfo;
/*

View File

@ -33,7 +33,7 @@ endif()
add_library(BattleAI SHARED ${battleAI_SRCS} ${battleAI_HEADERS})
target_include_directories(BattleAI PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(BattleAI PRIVATE vcmi)
target_link_libraries(BattleAI PRIVATE ${VCMI_LIB_TARGET})
vcmi_set_output_dir(BattleAI "AI")
enable_pch(BattleAI)

View File

@ -9,11 +9,15 @@
*/
#pragma once
VCMI_LIB_NAMESPACE_BEGIN
namespace battle
{
class Unit;
}
VCMI_LIB_NAMESPACE_END
class EnemyInfo
{
public:

View File

@ -14,8 +14,12 @@
#include "../../lib/battle/Destination.h"
VCMI_LIB_NAMESPACE_BEGIN
class CSpell;
VCMI_LIB_NAMESPACE_END
class PossibleSpellcast
{
public:

View File

@ -18,9 +18,14 @@
#include "../../lib/battle/BattleProxy.h"
#include "../../lib/battle/CUnitState.h"
class HypotheticBattle;
VCMI_LIB_NAMESPACE_BEGIN
class CStack;
VCMI_LIB_NAMESPACE_END
class HypotheticBattle;
///Fake random generator, used by AI to evaluate random server behavior
class RNGStub : public vstd::RNG
{

View File

@ -13,3 +13,5 @@
// This header should be treated as a pre compiled header file(PCH) in the compiler building settings.
// Here you can add specific libraries and macros which are specific to this project.
VCMI_LIB_USING_NAMESPACE

View File

@ -15,9 +15,9 @@ assign_source_group(${emptyAI_SRCS} ${emptyAI_HEADERS})
add_library(EmptyAI SHARED ${emptyAI_SRCS} ${emptyAI_HEADERS})
target_include_directories(EmptyAI PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(EmptyAI PRIVATE vcmi)
target_link_libraries(EmptyAI PRIVATE ${VCMI_LIB_TARGET})
vcmi_set_output_dir(EmptyAI "AI")
enable_pch(EmptyAI)
install(TARGETS EmptyAI RUNTIME DESTINATION ${AI_LIB_DIR} LIBRARY DESTINATION ${AI_LIB_DIR})
install(TARGETS EmptyAI RUNTIME DESTINATION ${AI_LIB_DIR} LIBRARY DESTINATION ${AI_LIB_DIR} OPTIONAL)

View File

@ -25,8 +25,12 @@
#include "Pathfinding/AIPathfinder.h"
#include "Engine/Nullkiller.h"
VCMI_LIB_NAMESPACE_BEGIN
struct QuestInfo;
VCMI_LIB_NAMESPACE_END
class AIStatus
{
boost::mutex mx;

View File

@ -130,7 +130,7 @@ add_library(Nullkiller SHARED ${Nullkiller_SRCS} ${Nullkiller_HEADERS})
target_include_directories(Nullkiller PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(Nullkiller PRIVATE vcmi fuzzylite::fuzzylite)
target_link_libraries(Nullkiller PRIVATE ${VCMI_LIB_TARGET} fuzzylite::fuzzylite)
target_link_libraries(Nullkiller PRIVATE TBB::tbb)
@ -138,3 +138,6 @@ vcmi_set_output_dir(Nullkiller "AI")
enable_pch(Nullkiller)
install(TARGETS Nullkiller RUNTIME DESTINATION ${AI_LIB_DIR} LIBRARY DESTINATION ${AI_LIB_DIR})
if(APPLE_IOS)
install(IMPORTED_RUNTIME_ARTIFACTS TBB::tbb LIBRARY DESTINATION ${LIB_DIR}) # CMake 3.21+
endif()

View File

@ -11,8 +11,12 @@
#include <fl/Headers.h>
#include "../Goals/AbstractGoal.h"
VCMI_LIB_NAMESPACE_BEGIN
class CArmedInstance;
VCMI_LIB_NAMESPACE_END
class engineBase //subclasses create fuzzylite variables with "new" that are not freed - this is desired as fl::Engine wants to destroy these...
{
protected:

View File

@ -10,7 +10,12 @@
#pragma once
#include "FuzzyEngines.h"
VCMI_LIB_NAMESPACE_BEGIN
class CBank;
VCMI_LIB_NAMESPACE_END
class Nullkiller;
class DLL_EXPORT FuzzyHelper

View File

@ -12,9 +12,14 @@
#include "../Goals/CGoal.h"
#include "../Pathfinding/AIPathfinder.h"
VCMI_LIB_NAMESPACE_BEGIN
class CGWitchHut;
VCMI_LIB_NAMESPACE_END
class BuildingInfo;
class Nullkiller;
class CGWitchHut;
class RewardEvaluator
{

View File

@ -164,6 +164,7 @@ ExchangeResult ChainActor::tryExchangeNoLock(const ChainActor * specialActor, co
return baseActor->tryExchangeNoLock(specialActor, other);
}
VCMI_LIB_NAMESPACE_BEGIN
namespace vstd
{
template <class M, class Key, class F>
@ -180,6 +181,7 @@ namespace vstd
return v;
}
}
VCMI_LIB_NAMESPACE_END
ExchangeResult HeroActor::tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const
{

View File

@ -1,3 +1,4 @@
#pragma once
#include "../../Global.h"
VCMI_LIB_USING_NAMESPACE
#include "../../CCallback.h"

View File

@ -14,7 +14,7 @@ set(stupidAI_HEADERS
assign_source_group(${stupidAI_SRCS} ${stupidAI_HEADERS})
add_library(StupidAI SHARED ${stupidAI_SRCS} ${stupidAI_HEADERS})
target_link_libraries(StupidAI PRIVATE vcmi)
target_link_libraries(StupidAI PRIVATE ${VCMI_LIB_TARGET})
target_include_directories(StupidAI PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
vcmi_set_output_dir(StupidAI "AI")

View File

@ -4,4 +4,6 @@
// This header should be treated as a pre compiled header file(PCH) in the compiler building settings.
// Here you can add specific libraries and macros which are specific to this project.
// Here you can add specific libraries and macros which are specific to this project.
VCMI_LIB_USING_NAMESPACE

View File

@ -107,7 +107,7 @@ add_library(VCAI SHARED ${VCAI_SRCS} ${VCAI_HEADERS})
target_include_directories(VCAI PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(VCAI PRIVATE vcmi fuzzylite::fuzzylite)
target_link_libraries(VCAI PRIVATE ${VCMI_LIB_TARGET} fuzzylite::fuzzylite)
vcmi_set_output_dir(VCAI "AI")
enable_pch(VCAI)

View File

@ -11,8 +11,12 @@
#include <fl/Headers.h>
#include "Goals/AbstractGoal.h"
VCMI_LIB_NAMESPACE_BEGIN
class CArmedInstance;
VCMI_LIB_NAMESPACE_END
class engineBase //subclasses create fuzzylite variables with "new" that are not freed - this is desired as fl::Engine wants to destroy these...
{
protected:

View File

@ -10,8 +10,12 @@
#pragma once
#include "FuzzyEngines.h"
VCMI_LIB_NAMESPACE_BEGIN
class CBank;
VCMI_LIB_NAMESPACE_END
class DLL_EXPORT FuzzyHelper
{
public:

View File

@ -1,2 +1,4 @@
#pragma once
#include "../../Global.h"
VCMI_LIB_USING_NAMESPACE

View File

@ -29,8 +29,12 @@
extern FuzzyHelper * fh;
VCMI_LIB_NAMESPACE_BEGIN
class CGVisitableOPW;
VCMI_LIB_NAMESPACE_END
const double SAFE_ATTACK_CONSTANT = 1.5;
//one thread may be turn of AI and another will be handling a side effect for AI2

View File

@ -26,8 +26,12 @@
#include "../../lib/CondSh.h"
#include "Pathfinding/AIPathfinder.h"
VCMI_LIB_NAMESPACE_BEGIN
struct QuestInfo;
VCMI_LIB_NAMESPACE_END
class AIhelper;
class AIStatus

View File

@ -78,6 +78,9 @@ Andrii Danylchenko
Dmitry Orlov, <shubus.corporation@gmail.com>
* special buildings support in fan towns, new features and bug fixes
Andrey Cherkas aka nordsoft, <nordsoft@yahoo.com>
* new terrain support, random map generator features and various bug fixes
Andrey Cherkas aka nordsoft, <nordsoft@yahoo.com>
* new terrain support, random map generator features and various bug fixes
Andrey Filipenkov aka kambala-decapitator, <decapitator@ukr.net>
* iOS support, macOS improvements, various bug fixes

View File

@ -13,6 +13,8 @@
#include "lib/battle/CPlayerBattleCallback.h"
#include "lib/int3.h" // for int3
VCMI_LIB_NAMESPACE_BEGIN
class CGHeroInstance;
class CGameState;
struct CPath;
@ -20,18 +22,22 @@ class CGObjectInstance;
class CArmedInstance;
class BattleAction;
class CGTownInstance;
struct lua_State;
class CClient;
class IShipyard;
struct CGPathNode;
struct CGPath;
struct CPathsInfo;
class PathfinderConfig;
struct CPack;
struct CPackForServer;
class IBattleEventsReceiver;
class IGameEventsReceiver;
struct ArtifactLocation;
VCMI_LIB_NAMESPACE_END
class CClient;
struct lua_State;
class IBattleCallback
{
public:
@ -88,8 +94,6 @@ public:
virtual int bulkMergeStacks(ObjectInstanceID armyId, SlotID srcSlot) = 0;
};
struct CPackForServer;
class CBattleCallback : public IBattleCallback, public CPlayerBattleCallback
{
protected:

7
CI/ios/before_install.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
echo DEVELOPER_DIR=/Applications/Xcode_13.4.1.app >> $GITHUB_ENV
curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/latest/download/vcmi-ios-depends-xc13.2.1.txz' \
| tar -xf -
build/fix_install_paths.command

3
CI/ios/post_pack.sh Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
"$1/ios/zip2ipa.sh" "$2"

View File

@ -1,7 +1,10 @@
curl -LfsS -o "vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v140.7z" \
"https://github.com/vcmi/vcmi-deps-windows/releases/download/v1.4/vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v140.7z"
"https://github.com/vcmi/vcmi-deps-windows/releases/download/v1.5/vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v140.7z"
7z x "vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v140.7z"
rm -r -f vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug
mkdir -p vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug/bin
cp vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/bin/* vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug/bin
DUMPBIN_DIR=$(vswhere -latest -find **/dumpbin.exe | head -n 1)
dirname "$DUMPBIN_DIR" > $GITHUB_PATH

View File

@ -15,7 +15,6 @@ project(VCMI)
#
# Vckpg:
# - Improve install code once there is better way to deploy DLLs and Qt plugins
# - Move Vcpkg install BundleUtilities code from osx/CMakeLists.txt
#
# Other:
# - Cleanup remove_directory copy_directory if performance will be a problem.
@ -26,6 +25,18 @@ project(VCMI)
# It's used currently to make sure that 3rd-party dependencies in git submodules get proper FOLDER property
# - Make FindFuzzyLite check for the right version and disable FORCE_BUNDLED_FL by default
if(APPLE)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
set(APPLE_MACOS 1)
else()
set(APPLE_IOS 1)
endif()
endif()
if(APPLE_IOS)
set(BUILD_SINGLE_APP 1)
endif()
############################################
# User-provided options #
############################################
@ -41,10 +52,19 @@ set(VCMI_VERSION_MAJOR 1)
set(VCMI_VERSION_MINOR 0)
set(VCMI_VERSION_PATCH 0)
set(APP_SHORT_VERSION "${VCMI_VERSION_MAJOR}.${VCMI_VERSION_MINOR}")
if(NOT VCMI_VERSION_PATCH EQUAL 0)
string(APPEND APP_SHORT_VERSION ".${VCMI_VERSION_PATCH}")
endif()
option(ENABLE_ERM "Enable compilation of ERM scripting module" OFF)
option(ENABLE_LUA "Enable compilation of LUA scripting module" OFF)
option(ENABLE_LAUNCHER "Enable compilation of launcher" ON)
option(ENABLE_TEST "Enable compilation of unit tests" ON)
if(APPLE_IOS)
set(BUNDLE_IDENTIFIER_PREFIX "" CACHE STRING "Bundle identifier prefix")
else()
option(ENABLE_TEST "Enable compilation of unit tests" ON)
endif()
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.16.0")
option(ENABLE_PCH "Enable compilation using precompiled headers" ON)
endif(NOT ${CMAKE_VERSION} VERSION_LESS "3.16.0")
@ -53,7 +73,9 @@ option(ENABLE_DEBUG_CONSOLE "Enable debug console for Windows builds" ON)
option(ENABLE_MULTI_PROCESS_BUILDS "Enable /MP flag for MSVS solution" ON)
# Used for Snap packages and also useful for debugging
option(ENABLE_MONOLITHIC_INSTALL "Install everything in single directory on Linux and Mac" OFF)
if(NOT APPLE_IOS)
option(ENABLE_MONOLITHIC_INSTALL "Install everything in single directory on Linux and Mac" OFF)
endif()
# Allow to pass package name from Travis CI
set(PACKAGE_NAME_SUFFIX "" CACHE STRING "Suffix for CPack package name")
@ -133,6 +155,34 @@ set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL MinSizeRel Release RelWithDebInfo "")
# Release falls back to RelWithDebInfo, then MinSizeRel
set(CMAKE_MAP_IMPORTED_CONFIG_RELEASE Release RelWithDebInfo MinSizeRel "")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES)
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Debug] dwarf)
set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE NO)
set(CMAKE_XCODE_ATTRIBUTE_ENABLE_NS_ASSERTIONS NO)
set(CMAKE_XCODE_ATTRIBUTE_ENABLE_NS_ASSERTIONS[variant=Debug] YES)
set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION NO)
set(CMAKE_XCODE_ATTRIBUTE_MARKETING_VERSION ${APP_SHORT_VERSION})
set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH NO)
set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH[variant=Debug] YES)
if(BUILD_SINGLE_APP)
add_compile_definitions(SINGLE_PROCESS_APP=1)
endif()
if(APPLE_IOS)
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.0)
list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_PREFIX_PATH}") # required for Boost
set(CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH FALSE)
set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH FALSE)
set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED NO)
set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED_FOR_APPS YES)
set(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUNDLE_IDENTIFIER_PREFIX}.$(PRODUCT_NAME)")
set(CMAKE_XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2")
endif()
if(MINGW OR MSVC)
# Windows Vista or newer for FuzzyLite 6 to compile
add_definitions(-D_WIN32_WINNT=0x0600)
@ -209,7 +259,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR NOT WIN32) #so far all *nix compilers support suc
endif()
# Check if some platform-specific libraries are needed for linking
if(NOT WIN32)
if(NOT WIN32 AND NOT APPLE_IOS)
include(CheckLibraryExists)
# Shared memory functions used by Boost.Interprocess
@ -236,7 +286,12 @@ if(TARGET zlib::zlib)
add_library(ZLIB::ZLIB ALIAS zlib::zlib)
endif()
find_package(ffmpeg COMPONENTS avutil swscale avformat avcodec)
set(FFMPEG_COMPONENTS avutil swscale avformat avcodec)
if(APPLE_IOS)
list(APPEND FFMPEG_COMPONENTS swresample)
endif()
find_package(ffmpeg COMPONENTS ${FFMPEG_COMPONENTS})
option(FORCE_BUNDLED_MINIZIP "Force bundled Minizip library" OFF)
if(NOT FORCE_BUNDLED_MINIZIP)
find_package(minizip)
@ -306,14 +361,19 @@ elseif(APPLE)
set(LIB_DIR "." CACHE STRING "Where to install main library")
set(DATA_DIR "." CACHE STRING "Where to install data files")
else()
set(APP_BUNDLE_DIR "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_CONTENTS_DIR "${APP_BUNDLE_DIR}/Contents")
set(APP_BUNDLE_BINARY_DIR "${APP_BUNDLE_CONTENTS_DIR}/MacOS")
set(APP_BUNDLE_RESOURCES_DIR "${APP_BUNDLE_CONTENTS_DIR}/Resources")
if(APPLE_MACOS)
set(APP_BUNDLE_DIR "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_CONTENTS_DIR "${APP_BUNDLE_DIR}/Contents")
set(APP_BUNDLE_BINARY_DIR "${APP_BUNDLE_CONTENTS_DIR}/MacOS")
set(APP_BUNDLE_RESOURCES_DIR "${APP_BUNDLE_CONTENTS_DIR}/Resources")
set(BIN_DIR "${APP_BUNDLE_BINARY_DIR}" CACHE STRING "Where to install binaries")
set(LIB_DIR "${APP_BUNDLE_CONTENTS_DIR}/Frameworks" CACHE STRING "Where to install main library")
set(DATA_DIR "${APP_BUNDLE_RESOURCES_DIR}/Data" CACHE STRING "Where to install data files")
set(BIN_DIR "${APP_BUNDLE_BINARY_DIR}" CACHE STRING "Where to install binaries")
set(LIB_DIR "${APP_BUNDLE_CONTENTS_DIR}/Frameworks" CACHE STRING "Where to install main library")
set(DATA_DIR "${APP_BUNDLE_RESOURCES_DIR}/Data" CACHE STRING "Where to install data files")
else()
set(LIB_DIR "Frameworks")
set(DATA_DIR ".")
endif()
endif()
else()
# includes lib path which determines where to install shared libraries (either /lib or /lib64)
@ -349,6 +409,20 @@ set(SCRIPTING_LIB_DIR "${LIB_DIR}/scripting")
# Add subdirectories #
#######################################
if(APPLE_IOS)
add_subdirectory(ios)
endif()
include(VCMI_lib)
if(BUILD_SINGLE_APP)
add_subdirectory(lib_client)
add_subdirectory(lib_server)
set(VCMI_LIB_TARGET vcmi_lib_client)
else()
add_subdirectory(lib)
set(VCMI_LIB_TARGET vcmi)
endif()
if(ENABLE_ERM)
add_subdirectory(scripting/erm)
endif()
@ -359,13 +433,13 @@ if(NOT TARGET minizip::minizip)
add_subdirectory_with_folder("3rdparty" lib/minizip)
add_library(minizip::minizip ALIAS minizip)
endif()
add_subdirectory(lib)
add_subdirectory(client)
add_subdirectory(server)
add_subdirectory_with_folder("AI" AI)
if(ENABLE_LAUNCHER)
add_subdirectory(launcher)
endif()
add_subdirectory(client)
add_subdirectory(server)
add_subdirectory_with_folder("AI" AI)
if(ENABLE_TEST)
enable_testing()
add_subdirectory(test)
@ -376,11 +450,13 @@ endif()
#######################################
install(DIRECTORY config DESTINATION ${DATA_DIR})
install(DIRECTORY scripts DESTINATION ${DATA_DIR})
install(DIRECTORY Mods DESTINATION ${DATA_DIR})
if(ENABLE_LUA)
install(DIRECTORY scripts DESTINATION ${DATA_DIR})
endif()
# that script is useless for Windows
if(NOT WIN32)
# that script is useless for Windows and iOS
if(NOT WIN32 AND NOT APPLE_IOS)
install(FILES vcmibuilder DESTINATION ${BIN_DIR} PERMISSIONS
OWNER_WRITE OWNER_READ OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
@ -487,9 +563,9 @@ if(WIN32)
set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
# Use BundleUtilities to fix build when Vcpkg is used and disable it for MXE
if(NOT (${CMAKE_CROSSCOMPILING}))
add_subdirectory(osx)
add_subdirectory(win)
endif()
elseif(APPLE AND NOT ENABLE_MONOLITHIC_INSTALL)
elseif(APPLE_MACOS AND NOT ENABLE_MONOLITHIC_INSTALL)
set(CPACK_MONOLITHIC_INSTALL 1)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/osx/dmg_background.png")
@ -519,6 +595,10 @@ elseif(APPLE AND NOT ENABLE_MONOLITHIC_INSTALL)
# Bundle fixing code must be in separate directory to be executed after all other install code
add_subdirectory(osx)
elseif(APPLE_IOS)
set(CPACK_GENERATOR ZIP)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
set(CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_PROJECT_NAME};app;/")
else()
set(CPACK_GENERATOR TGZ)
endif()

View File

@ -2,19 +2,31 @@
"version": 2,
"configurePresets": [
{
"name": "default-release",
"name": "release-binary-dir",
"hidden": true,
"binaryDir": "${sourceDir}/out/build/${presetName}"
},
{
"name": "base-release",
"inherits": "release-binary-dir",
"hidden": true,
"binaryDir": "${sourceDir}/out/build/${presetName}",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
"PACKAGE_FILE_NAME" : "$env{VCMI_PACKAGE_FILE_NAME}",
"PACKAGE_NAME_SUFFIX" : "$env{VCMI_PACKAGE_NAME_SUFFIX}",
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"FORCE_BUNDLED_FL": "OFF",
"ENABLE_TEST": "OFF"
}
},
{
"name": "default-release",
"inherits": "base-release",
"hidden": true,
"generator": "Ninja",
"cacheVariables": {
"FORCE_BUNDLED_FL": "OFF"
}
},
{
"name" : "linux-release",
"inherits" : "default-release",
@ -87,6 +99,41 @@
"description": "VCMI MacOS Xcode",
"inherits": "default-release",
"generator": "Xcode"
},
{
"name": "ios-device",
"displayName": "Base iOS device",
"description": "Base VCMI preset for iOS device",
"generator": "Xcode",
"binaryDir": "../build-${presetName}",
"cacheVariables": {
"CMAKE_SYSTEM_NAME": "iOS",
"FORCE_BUNDLED_FL": "ON",
"FORCE_BUNDLED_MINIZIP": "ON"
}
},
{
"name": "ios-simulator",
"displayName": "Base iOS simulator",
"description": "Base VCMI preset for iOS simulator",
"inherits": "ios-device",
"cacheVariables": {
"CMAKE_OSX_SYSROOT": "iphonesimulator"
}
},
{
"name": "ios-release",
"displayName": "iOS release",
"description": "VCMI iOS release",
"inherits": [
"base-release",
"ios-device",
"release-binary-dir"
],
"cacheVariables": {
"BUNDLE_IDENTIFIER_PREFIX": "eu.vcmi",
"CMAKE_PREFIX_PATH": "${sourceDir}/build/iphoneos"
}
}
],
"buildPresets": [
@ -135,6 +182,16 @@
"name": "windows-msvc-relwithdebinfo",
"configurePreset": "windows-msvc-release",
"inherits": "default-release"
},
{
"name": "ios-release",
"configurePreset": "ios-release",
"inherits": "default-release",
"configuration": "Release",
"targets": ["vcmiclient"],
"nativeToolOptions": [
"CODE_SIGNING_ALLOWED_FOR_APPS=NO"
]
}
],
"testPresets": [
@ -172,4 +229,4 @@
"inherits": "default-release"
}
]
}
}

View File

@ -68,7 +68,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
# define VCMI_UNIX
# define VCMI_APPLE
# include "TargetConditionals.h"
# if TARGET_IPHONE_SIMULATOR
# if TARGET_OS_SIMULATOR || TARGET_IPHONE_SIMULATOR
# define VCMI_IOS
# define VCMI_IOS_SIM
# elif TARGET_OS_IPHONE
@ -82,10 +82,6 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
# error "VCMI supports only Windows, OSX, Linux and Android targets"
#endif
#ifdef VCMI_IOS
# error "iOS system isn't yet supported."
#endif
// Each compiler uses own way to supress fall through warning. Try to find it.
#ifdef __has_cpp_attribute
# if __has_cpp_attribute(fallthrough)
@ -268,11 +264,35 @@ template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
// should be used for variables that becomes unused in release builds (e.g. only used for assert checks)
#define UNUSED(VAR) ((void)VAR)
// old iOS SDKs compatibility
#ifdef VCMI_IOS
#include <AvailabilityVersions.h>
#ifndef __IPHONE_13_0
#define __IPHONE_13_0 130000
#endif
#endif // VCMI_IOS
// single-process build makes 2 copies of the main lib by wrapping it in a namespace
#ifdef VCMI_LIB_NAMESPACE
#define VCMI_LIB_NAMESPACE_BEGIN namespace VCMI_LIB_NAMESPACE {
#define VCMI_LIB_NAMESPACE_END }
#define VCMI_LIB_USING_NAMESPACE using namespace VCMI_LIB_NAMESPACE;
#define VCMI_LIB_WRAP_NAMESPACE(x) VCMI_LIB_NAMESPACE::x
#else
#define VCMI_LIB_NAMESPACE_BEGIN
#define VCMI_LIB_NAMESPACE_END
#define VCMI_LIB_USING_NAMESPACE
#define VCMI_LIB_WRAP_NAMESPACE(x) x
#endif
/* ---------------------------------------------------------------------------- */
/* VCMI standard library */
/* ---------------------------------------------------------------------------- */
#include <vstd/CLoggerBase.h>
VCMI_LIB_NAMESPACE_BEGIN
void inline handleException()
{
try
@ -743,3 +763,5 @@ namespace std
}
}
#endif // NO_STD_TOSTRING
VCMI_LIB_NAMESPACE_END

View File

@ -20,6 +20,7 @@ To use VCMI you need to own original data files.
* [Linux](https://wiki.vcmi.eu/Installation_on_Linux)
* [macOS](https://wiki.vcmi.eu/Installation_on_macOS)
* [Windows](https://wiki.vcmi.eu/Installation_on_Windows)
* [iOS](https://wiki.vcmi.eu/Installation_on_iOS)
## Building from source
@ -29,6 +30,7 @@ Platform support is constantly tested by continuous integration and CMake config
* [On Linux for Windows with MXE](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux/Cmake/MXE))
* [On macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(macOS))
* [On Windows using MSVC and Vcpkg](https://wiki.vcmi.eu/How_to_build_VCMI_(Windows/Vcpkg))
* [iOS on macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(iOS))
## Copyright and license

View File

@ -9,7 +9,11 @@
*/
#include "Version.h"
VCMI_LIB_NAMESPACE_BEGIN
namespace GameConstants
{
const char GIT_SHA1[] = "@GIT_SHA1@";
}
VCMI_LIB_NAMESPACE_END

View File

@ -1,6 +1,12 @@
#pragma once
#include "StdInc.h"
VCMI_LIB_NAMESPACE_BEGIN
namespace GameConstants
{
extern const char GIT_SHA1[];
}
VCMI_LIB_NAMESPACE_END

View File

@ -0,0 +1,21 @@
/*
* CFocusableHelper.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "CFocusableHelper.h"
#include "../Global.h"
#include "widgets/TextControls.h"
void removeFocusFromActiveInput()
{
if(CFocusable::inputWithFocus == nullptr)
return;
CFocusable::inputWithFocus->focus = false;
CFocusable::inputWithFocus->redraw();
CFocusable::inputWithFocus = nullptr;
}

11
client/CFocusableHelper.h Normal file
View File

@ -0,0 +1,11 @@
/*
* CFocusableHelper.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
void removeFocusFromActiveInput();

View File

@ -13,30 +13,34 @@
#include "../lib/ConstTransitivePtr.h"
VCMI_LIB_NAMESPACE_BEGIN
class CModHandler;
class CMapHandler;
class CHeroHandler;
class CCreatureHandler;
class CSpellHandler;
class CSkillHandler;
class CBuildingHandler;
class CObjectHandler;
class CSoundHandler;
class CMusicHandler;
class CObjectClassesHandler;
class CTownHandler;
class CGeneralTextHandler;
class CConsoleHandler;
class CCursorHandler;
class CGameState;
class IMainVideoPlayer;
class CServerHandler;
class BattleFieldHandler;
class ObstacleHandler;
class TerrainTypeHandler;
class CMap;
VCMI_LIB_NAMESPACE_END
class CMapHandler;
class CSoundHandler;
class CMusicHandler;
class CCursorHandler;
class IMainVideoPlayer;
class CServerHandler;
//a class for non-mechanical client GUI classes
class CClientState

View File

@ -159,7 +159,7 @@ static void SDLLogCallback(void* userdata,
#if defined(VCMI_WINDOWS) && !defined(__GNUC__) && defined(VCMI_WITH_DEBUG_CONSOLE)
int wmain(int argc, wchar_t* argv[])
#elif defined(VCMI_ANDROID)
#elif defined(VCMI_IOS) || defined(VCMI_ANDROID)
int SDL_main(int argc, char *argv[])
#else
int main(int argc, char * argv[])
@ -170,7 +170,7 @@ int main(int argc, char * argv[])
setenv("LANG", "C", 1);
#endif
#ifndef VCMI_ANDROID
#if !defined(VCMI_ANDROID) && !defined(VCMI_IOS)
// Correct working dir executable folder (not bundle folder) so we can use executable relative paths
boost::filesystem::current_path(boost::filesystem::system_complete(argv[0]).parent_path());
#endif
@ -217,12 +217,20 @@ int main(int argc, char * argv[])
if(vm.count("help"))
{
prog_help(opts);
#ifdef VCMI_IOS
exit(0);
#else
return 0;
#endif
}
if(vm.count("version"))
{
prog_version();
#ifdef VCMI_IOS
exit(0);
#else
return 0;
#endif
}
// Init old logging system and new (temporary) logging system
@ -410,7 +418,7 @@ int main(int argc, char * argv[])
CCS->musich->setVolume((ui32)settings["general"]["music"].Float());
logGlobal->info("Initializing screen and sound handling: %d ms", pomtime.getDiff());
}
#ifdef __APPLE__
#ifdef VCMI_MAC
// Ctrl+click should be treated as a right click on Mac OS X
SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, "1");
#endif
@ -1027,11 +1035,15 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
if (displayIndex < 0)
displayIndex = 0;
}
#ifdef VCMI_IOS
SDL_GetWindowSize(mainWindow, &w, &h);
#else
if(!checkVideoMode(displayIndex, w, h))
{
logGlobal->error("Error: SDL says that %dx%d resolution is not available!", w, h);
return false;
}
#endif
bool bufOnScreen = (screenBuf == screen);
bool realFullscreen = settings["video"]["realFullscreen"].Bool();
@ -1088,26 +1100,40 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
if(nullptr == mainWindow)
{
#if defined(VCMI_ANDROID) || defined(VCMI_IOS)
auto createWindow = [displayIndex](Uint32 extraFlags) -> bool {
mainWindow = SDL_CreateWindow(NAME.c_str(), SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), 0, 0, SDL_WINDOW_FULLSCREEN | extraFlags);
return mainWindow != nullptr;
};
#ifdef VCMI_ANDROID
mainWindow = SDL_CreateWindow(NAME.c_str(), SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex),SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), 0, 0, SDL_WINDOW_FULLSCREEN);
# ifdef VCMI_IOS
SDL_SetHint(SDL_HINT_IOS_HIDE_HOME_INDICATOR, "1");
SDL_SetHint(SDL_HINT_RETURN_KEY_HIDES_IME, "1");
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
// SDL on Android doesn't do proper letterboxing, and will show an annoying flickering in the blank space in case you're not using the full screen estate
Uint32 windowFlags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALLOW_HIGHDPI;
if(!createWindow(windowFlags | SDL_WINDOW_METAL))
{
logGlobal->warn("Metal unavailable, using OpenGLES");
createWindow(windowFlags);
}
# else
createWindow(0);
# endif // VCMI_IOS
// SDL on mobile doesn't do proper letterboxing, and will show an annoying flickering in the blank space in case you're not using the full screen estate
// That's why we need to make sure our width and height we'll use below have the same aspect ratio as the screen itself to ensure we fill the full screen estate
SDL_Rect screenRect;
if(SDL_GetDisplayBounds(0, &screenRect) == 0)
{
int screenWidth, screenHeight;
double aspect;
const auto screenWidth = screenRect.w;
const auto screenHeight = screenRect.h;
screenWidth = screenRect.w;
screenHeight = screenRect.h;
const auto aspect = static_cast<double>(screenWidth) / screenHeight;
aspect = (double)screenWidth / (double)screenHeight;
logGlobal->info("Screen size and aspect ration: %dx%d (%lf)", screenWidth, screenHeight, aspect);
logGlobal->info("Screen size and aspect ratio: %dx%d (%lf)", screenWidth, screenHeight, aspect);
if((double)w / aspect > (double)h)
{
@ -1124,8 +1150,7 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
{
logGlobal->error("Can't fix aspect ratio for screen");
}
#else
#else
if(fullscreen)
{
if(realFullscreen)
@ -1138,7 +1163,7 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
{
mainWindow = SDL_CreateWindow(NAME.c_str(), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex),SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex), w, h, 0);
}
#endif
#endif // defined(VCMI_ANDROID) || defined(VCMI_IOS)
if(nullptr == mainWindow)
{
@ -1161,7 +1186,7 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
}
else
{
#ifndef VCMI_ANDROID
#if !defined(VCMI_ANDROID) && !defined(VCMI_IOS)
if(fullscreen)
{
@ -1384,7 +1409,9 @@ static void handleEvent(SDL_Event & ev)
{
switch (ev.window.event) {
case SDL_WINDOWEVENT_RESTORED:
#ifndef VCMI_IOS
fullScreenChanged();
#endif
break;
}
return;

View File

@ -145,6 +145,22 @@ set(client_HEADERS
SDLRWwrapper.h
)
if(APPLE_IOS)
set(client_SRCS ${client_SRCS}
CFocusableHelper.cpp
ios/GameChatKeyboardHanlder.m
ios/main.m
ios/startSDL.mm
ios/utils.mm
)
set(client_HEADERS ${client_HEADERS}
CFocusableHelper.h
ios/GameChatKeyboardHanlder.h
ios/startSDL.h
ios/utils.h
)
endif()
assign_source_group(${client_SRCS} ${client_HEADERS} VCMI_client.rc)
if(ANDROID) # android needs client/server to be libraries, not executables, so we can't reuse the build part of this script
@ -160,7 +176,16 @@ if(ENABLE_DEBUG_CONSOLE)
else()
add_executable(vcmiclient WIN32 ${client_SRCS} ${client_HEADERS} ${client_ICON})
endif(ENABLE_DEBUG_CONSOLE)
add_dependencies(vcmiclient vcmiserver BattleAI StupidAI VCAI Nullkiller)
if(APPLE_IOS)
if(ENABLE_ERM)
add_dependencies(vcmiclient vcmiERM)
endif()
if(ENABLE_LUA)
add_dependencies(vcmiclient vcmiLua)
endif()
endif()
if(WIN32)
set_target_properties(vcmiclient
@ -173,15 +198,64 @@ if(WIN32)
target_link_libraries(vcmiclient SDL2::SDL2main)
endif()
target_compile_definitions(vcmiclient PRIVATE WINDOWS_IGNORE_PACKING_MISMATCH)
# TODO: very hacky, find proper solution to copy AI dlls into bin dir
if(MSVC)
add_custom_command(TARGET vcmiclient POST_BUILD
WORKING_DIRECTORY "$<TARGET_FILE_DIR:vcmiclient>"
COMMAND ${CMAKE_COMMAND} -E rename AI/fuzzylite.dll fuzzylite.dll
COMMAND ${CMAKE_COMMAND} -E rename AI/tbb.dll tbb.dll
)
endif()
elseif(APPLE_IOS)
target_link_libraries(vcmiclient PRIVATE
iOS_utils
# FFmpeg
bz2
iconv
z
"-framework AudioToolbox"
"-framework AVFoundation"
"-framework CoreMedia"
"-framework VideoToolbox"
)
set_target_properties(vcmiclient PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/ios/Info.plist"
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks"
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "$(CODE_SIGNING_ALLOWED_FOR_APPS)"
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AppIcon
)
foreach(XCODE_RESOURCE LaunchScreen.storyboard Images.xcassets Settings.bundle vcmi_logo.png)
set(XCODE_RESOURCE_PATH ios/${XCODE_RESOURCE})
target_sources(vcmiclient PRIVATE ${XCODE_RESOURCE_PATH})
set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
# workaround to prevent CMAKE_SKIP_PRECOMPILE_HEADERS being added as compile flag
# add max version condition when https://gitlab.kitware.com/cmake/cmake/-/merge_requests/7562 is merged
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22.0")
set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES LANGUAGE CXX)
endif()
endforeach()
set(CMAKE_EXE_LINKER_FLAGS "-Wl,-e,_client_main")
endif()
if(BUILD_SINGLE_APP)
target_link_libraries(vcmiclient PRIVATE vcmiserver)
if(ENABLE_LAUNCHER)
target_link_libraries(vcmiclient PRIVATE vcmilauncher)
endif()
endif()
target_link_libraries(vcmiclient PRIVATE
vcmi SDL2::SDL2 SDL2::Image SDL2::Mixer SDL2::TTF
${VCMI_LIB_TARGET} SDL2::SDL2 SDL2::Image SDL2::Mixer SDL2::TTF
)
if(ffmpeg_LIBRARIES)
target_link_libraries(vcmiclient PRIVATE
ffmpeg::swscale ffmpeg::avutil ffmpeg::avcodec ffmpeg::avformat
${ffmpeg_LIBRARIES}
)
else()
target_compile_definitions(vcmiclient PRIVATE DISABLE_VIDEO)
@ -193,7 +267,15 @@ target_include_directories(vcmiclient
vcmi_set_output_dir(vcmiclient "")
enable_pch(vcmiclient)
install(TARGETS vcmiclient DESTINATION ${BIN_DIR})
if(APPLE_IOS)
add_custom_command(TARGET vcmiclient POST_BUILD
COMMAND ${CMAKE_COMMAND} --install "${CMAKE_BINARY_DIR}" --component "${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}" --config "$<CONFIG>" --prefix "$<TARGET_BUNDLE_CONTENT_DIR:vcmiclient>"
COMMAND ${CMAKE_SOURCE_DIR}/ios/codesign.sh
)
install(TARGETS vcmiclient DESTINATION Payload COMPONENT app) # for ipa generation with cpack
else()
install(TARGETS vcmiclient DESTINATION ${BIN_DIR})
endif()
#install icons and desktop file on Linux
if(NOT WIN32 AND NOT APPLE)

View File

@ -19,30 +19,33 @@
#define sprintf_s snprintf
#endif
VCMI_LIB_NAMESPACE_BEGIN
class Artifact;
struct TryMoveHero;
class CGHeroInstance;
class CStack;
class CCreature;
struct CGPath;
class CCreatureSet;
class CGObjectInstance;
struct UpgradeInfo;
template <typename T> struct CondSh;
struct CPathsInfo;
VCMI_LIB_NAMESPACE_END
class CButton;
class CToggleGroup;
struct TryMoveHero;
class CGHeroInstance;
class CAdvMapInt;
class CCastleInterface;
class CBattleInterface;
class CStack;
class CComponent;
class CCreature;
struct SDL_Surface;
struct CGPath;
class CCreatureAnimation;
class CSelectableComponent;
class CCreatureSet;
class CGObjectInstance;
class CSlider;
struct UpgradeInfo;
template <typename T> struct CondSh;
class CInGameConsole;
class CInGameConsole;
union SDL_Event;
class CInfoWindow;
class IShowActivatable;
class ClickableL;
@ -52,7 +55,9 @@ class KeyInterested;
class MotionInterested;
class TimeInterested;
class IShowable;
struct CPathsInfo;
struct SDL_Surface;
union SDL_Event;
namespace boost
{

View File

@ -21,10 +21,15 @@
#include "mainmenu/CMainMenu.h"
#ifndef VCMI_ANDROID
#include "../lib/Interprocess.h"
#else
#ifdef VCMI_ANDROID
#include "../lib/CAndroidVMHelper.h"
#elif defined(VCMI_IOS)
#include "ios/utils.h"
#include "../server/CVCMIServer.h"
#include <dispatch/dispatch.h>
#else
#include "../lib/Interprocess.h"
#endif
#include "../lib/CConfigHandler.h"
#include "../lib/CGeneralTextHandler.h"
@ -76,7 +81,7 @@ public:
bool applyOnLobbyHandler(CServerHandler * handler, void * pack) const override
{
T * ptr = static_cast<T *>(pack);
logNetwork->trace("\tImmidiately apply on lobby: %s", typeList.getTypeInfo(ptr)->name());
logNetwork->trace("\tImmediately apply on lobby: %s", typeList.getTypeInfo(ptr)->name());
return ptr->applyOnLobbyHandler(handler);
}
@ -132,7 +137,7 @@ void CServerHandler::resetStateForLobby(const StartInfo::EMode mode, const std::
else
myNames.push_back(settings["general"]["playerName"].String());
#ifndef VCMI_ANDROID
#if !defined(VCMI_ANDROID) && !defined(VCMI_IOS)
shm.reset();
if(!settings["session"]["disable-shm"].Bool())
@ -181,6 +186,14 @@ void CServerHandler::startLocalServerAndConnect()
CAndroidVMHelper envHelper;
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "startServer", true);
}
#elif defined(SINGLE_PROCESS_APP)
boost::condition_variable cond;
threadRunLocalServer = std::make_shared<boost::thread>([&cond, this] {
setThreadName("CVCMIServer");
CVCMIServer::create(&cond, uuid);
onServerFinished();
});
threadRunLocalServer->detach();
#else
threadRunLocalServer = std::make_shared<boost::thread>(&CServerHandler::threadRunServer, this); //runs server executable;
#endif
@ -188,10 +201,7 @@ void CServerHandler::startLocalServerAndConnect()
th->update();
#ifndef VCMI_ANDROID
if(shm)
shm->sr->waitTillReady();
#else
#ifdef VCMI_ANDROID
logNetwork->info("waiting for server");
while(!androidTestServerReadyFlag.load())
{
@ -200,16 +210,40 @@ void CServerHandler::startLocalServerAndConnect()
}
logNetwork->info("waiting for server finished...");
androidTestServerReadyFlag = false;
#elif defined(SINGLE_PROCESS_APP)
{
#ifdef VCMI_IOS
dispatch_sync(dispatch_get_main_queue(), ^{
iOS_utils::showLoadingIndicator();
});
#endif
boost::mutex m;
boost::unique_lock<boost::mutex> lock{m};
logNetwork->info("waiting for server");
cond.wait(lock);
logNetwork->info("server is ready");
#ifdef VCMI_IOS
dispatch_sync(dispatch_get_main_queue(), ^{
iOS_utils::hideLoadingIndicator();
});
#endif
}
#else
if(shm)
shm->sr->waitTillReady();
#endif
logNetwork->trace("Waiting for server: %d ms", th->getDiff());
th->update(); //put breakpoint here to attach to server before it does something stupid
#ifndef VCMI_ANDROID
justConnectToServer(settings["server"]["server"].String(), shm ? shm->sr->port : 0);
#if !defined(VCMI_ANDROID) && !defined(VCMI_IOS)
const ui16 port = shm ? shm->sr->port : 0;
#else
justConnectToServer(settings["server"]["server"].String());
const ui16 port = 0;
#endif
justConnectToServer(settings["server"]["server"].String(), port);
logNetwork->trace("\tConnecting to the server: %d ms", th->getDiff());
}
@ -546,6 +580,11 @@ void CServerHandler::startCampaignScenario(std::shared_ptr<CCampaignState> cs)
SDL_PushEvent(&event);
}
void CServerHandler::showServerError(std::string txt)
{
CInfoWindow::showInfoDialog(txt, {});
}
int CServerHandler::howManyPlayerInterfaces()
{
int playerInts = 0;
@ -698,7 +737,7 @@ void CServerHandler::threadHandleConnection()
void CServerHandler::threadRunServer()
{
#ifndef VCMI_ANDROID
#if !defined(VCMI_ANDROID) && !defined(VCMI_IOS)
setThreadName("CServerHandler::threadRunServer");
const std::string logName = (VCMIDirs::get().userLogsPath() / "server_log.txt").string();
std::string comm = VCMIDirs::get().serverPath().string()
@ -739,9 +778,14 @@ void CServerHandler::threadRunServer()
logNetwork->error("Error: server failed to close correctly or crashed!");
logNetwork->error("Check %s for more info", logName);
}
onServerFinished();
#endif
}
void CServerHandler::onServerFinished()
{
threadRunLocalServer.reset();
CSH->campaignServerRestartLock.setn(false);
#endif
}
void CServerHandler::sendLobbyPack(const CPackForLobby & pack) const

View File

@ -14,7 +14,8 @@
#include "../lib/StartInfo.h"
#include "../lib/CondSh.h"
struct SharedMemory;
VCMI_LIB_NAMESPACE_BEGIN
class CConnection;
class PlayerColor;
struct StartInfo;
@ -23,9 +24,15 @@ class CMapInfo;
struct ClientPlayer;
struct CPack;
struct CPackForLobby;
class CClient;
template<typename T> class CApplier;
VCMI_LIB_NAMESPACE_END
struct SharedMemory;
class CClient;
class CBaseForLobbyApply;
// TODO: Add mutex so we can't set CONNECTION_CANCELLED if client already connected, but thread not setup yet
@ -76,6 +83,7 @@ class CServerHandler : public IServerAPI, public LobbyInfo
void threadHandleConnection();
void threadRunServer();
void onServerFinished();
void sendLobbyPack(const CPackForLobby & pack) const override;
public:
@ -137,6 +145,7 @@ public:
void startGameplay();
void endGameplay(bool closeConnection = true, bool restart = false);
void startCampaignScenario(std::shared_ptr<CCampaignState> cs = {});
void showServerError(std::string txt);
// TODO: LobbyState must be updated within game so we should always know how many player interfaces our client handle
int howManyPlayerInterfaces();

View File

@ -19,25 +19,22 @@
#include "../lib/CondSh.h"
#include "../lib/CPathfinder.h"
VCMI_LIB_NAMESPACE_BEGIN
struct CPack;
struct CPackForServer;
class CCampaignState;
class CBattleCallback;
class IGameEventsReceiver;
class IBattleEventsReceiver;
class CBattleGameInterface;
class CGameState;
class CGameInterface;
class CCallback;
class BattleAction;
class CClient;
struct CPathsInfo;
class BinaryDeserializer;
class BinarySerializer;
namespace boost { class thread; }
template<typename T> class CApplier;
class CBaseForCLApply;
#if SCRIPTING_ENABLED
namespace scripting
@ -51,6 +48,15 @@ namespace events
class EventBus;
}
VCMI_LIB_NAMESPACE_END
class CBattleCallback;
class CCallback;
class CClient;
class CBaseForCLApply;
namespace boost { class thread; }
template<typename T>
class ThreadSafeVector
{

View File

@ -13,18 +13,23 @@
#include "../lib/GameConstants.h"
#include "gui/Geometries.h"
struct SDL_Surface;
VCMI_LIB_NAMESPACE_BEGIN
class CGHeroInstance;
class CGTownInstance;
class CHeroClass;
struct SDL_Color;
struct InfoAboutHero;
struct InfoAboutTown;
class CGObjectInstance;
class ObjectTemplate;
class CAnimation;
class EntityService;
VCMI_LIB_NAMESPACE_END
struct SDL_Surface;
struct SDL_Color;
class CAnimation;
enum EFonts
{
FONT_BIG, FONT_CALLI, FONT_CREDITS, FONT_HIGH_SCORE, FONT_MEDIUM, FONT_SMALL, FONT_TIMES, FONT_TINY, FONT_VERD

View File

@ -137,3 +137,9 @@ void LobbyUpdateState::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler *
if(hostChanged)
lobby->toggleMode(handler->isHost());
}
void LobbyShowMessage::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * handler)
{
lobby->buttonStart->block(false);
handler->showServerError(message);
}

View File

@ -9,7 +9,12 @@
*/
#pragma once
struct SDL_RWops;
VCMI_LIB_NAMESPACE_BEGIN
class CInputStream;
VCMI_LIB_NAMESPACE_END
struct SDL_RWops;
SDL_RWops* MakeSDLRWops(std::unique_ptr<CInputStream> in);

View File

@ -7,3 +7,5 @@
// This header should be treated as a pre compiled header file(PCH) in the compiler building settings.
// Here you can add specific libraries and macros which are specific to this project.
VCMI_LIB_USING_NAMESPACE

View File

@ -12,8 +12,13 @@
#include "../../lib/battle/BattleHex.h"
#include "../widgets/Images.h"
class CBattleInterface;
VCMI_LIB_NAMESPACE_BEGIN
class CStack;
VCMI_LIB_NAMESPACE_END
class CBattleInterface;
class CCreatureAnimation;
struct CatapultProjectileInfo;
struct StackAttackedInfo;

View File

@ -19,14 +19,11 @@
#include "../../lib/spells/CSpellHandler.h" //CSpell::TAnimation
#include "../../lib/battle/CBattleInfoCallback.h"
class CLabel;
VCMI_LIB_NAMESPACE_BEGIN
class CCreatureSet;
class CGHeroInstance;
class CStack;
class CCallback;
class CButton;
class CToggleButton;
class CToggleGroup;
struct BattleResult;
struct BattleSpellCast;
struct CObstacleInstance;
@ -35,8 +32,21 @@ struct SetStackEffect;
class BattleAction;
class CGTownInstance;
struct CatapultAttack;
struct CatapultProjectileInfo;
struct BattleTriggerEffect;
struct BattleHex;
struct InfoAboutHero;
class CBattleGameInterface;
struct CustomEffectInfo;
class CSpell;
VCMI_LIB_NAMESPACE_END
class CLabel;
class CCallback;
class CButton;
class CToggleButton;
class CToggleGroup;
struct CatapultProjectileInfo;
class CBattleAnimation;
class CBattleHero;
class CBattleConsole;
@ -46,13 +56,8 @@ class CPlayerInterface;
class CCreatureAnimation;
struct ProjectileInfo;
class CClickableHex;
struct BattleHex;
struct InfoAboutHero;
class CBattleGameInterface;
struct CustomEffectInfo;
class CAnimation;
class IImage;
class CSpell;
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct StackAttackedInfo

View File

@ -13,8 +13,20 @@
#include "../../lib/battle/BattleHex.h"
#include "../windows/CWindowObject.h"
struct SDL_Surface;
VCMI_LIB_NAMESPACE_BEGIN
class CGHeroInstance;
struct BattleResult;
class CStack;
namespace battle
{
class Unit;
}
VCMI_LIB_NAMESPACE_END
struct SDL_Surface;
class CBattleInterface;
class CPicture;
class CFilledTexture;
@ -23,12 +35,6 @@ class CToggleButton;
class CToggleGroup;
class CLabel;
class CTextBox;
struct BattleResult;
class CStack;
namespace battle
{
class Unit;
}
class CAnimImage;
class CPlayerInterface;

View File

@ -21,8 +21,13 @@
#undef OUT
#endif
struct SDL_Surface;
VCMI_LIB_NAMESPACE_BEGIN
class JsonNode;
VCMI_LIB_NAMESPACE_END
struct SDL_Surface;
class CDefFile;
class ColorShifter;

View File

@ -13,6 +13,12 @@
#include "Geometries.h"
#include "SDL_Extensions.h"
VCMI_LIB_NAMESPACE_BEGIN
template <typename T> struct CondSh;
VCMI_LIB_NAMESPACE_END
class CFramerateManager;
class CGStatusBar;
class CIntObject;
@ -20,7 +26,6 @@ class IUpdateable;
class IShowActivatable;
class IShowable;
enum class EIntObjMouseBtnType;
template <typename T> struct CondSh;
// TODO: event handling need refactoring
enum EUserEvent

View File

@ -9,8 +9,12 @@
*/
#pragma once
VCMI_LIB_NAMESPACE_BEGIN
class JsonNode;
VCMI_LIB_NAMESPACE_END
struct Point;
struct SDL_Surface;
struct SDL_Color;

View File

@ -20,6 +20,10 @@
#include <dispatch/dispatch.h>
#endif
#ifdef VCMI_IOS
#include "ios/utils.h"
#endif
const SDL_Color Colors::YELLOW = { 229, 215, 123, 0 };
const SDL_Color Colors::WHITE = { 255, 243, 222, 0 };
const SDL_Color Colors::METALLIC_GOLD = { 173, 142, 66, 0 };
@ -790,15 +794,37 @@ SDL_Color CSDL_Ext::makeColor(ui8 r, ui8 g, ui8 b, ui8 a)
void CSDL_Ext::startTextInput(SDL_Rect * where)
{
auto impl = [](SDL_Rect * where)
{
if (SDL_IsTextInputActive() == SDL_FALSE)
{
SDL_StartTextInput();
}
SDL_SetTextInputRect(where);
};
#ifdef VCMI_APPLE
dispatch_async(dispatch_get_main_queue(), ^{
#endif
if (SDL_IsTextInputActive() == SDL_FALSE)
{
SDL_StartTextInput();
}
SDL_SetTextInputRect(where);
#ifdef VCMI_IOS
// TODO ios: looks like SDL bug actually, try fixing there
auto renderer = SDL_GetRenderer(mainWindow);
float scaleX, scaleY;
SDL_Rect viewport;
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
SDL_RenderGetViewport(renderer, &viewport);
const auto nativeScale = iOS_utils::screenScale();
auto rectInScreenCoordinates = *where;
rectInScreenCoordinates.x = (viewport.x + rectInScreenCoordinates.x) * scaleX / nativeScale;
rectInScreenCoordinates.y = (viewport.y + rectInScreenCoordinates.y) * scaleY / nativeScale;
rectInScreenCoordinates.w = rectInScreenCoordinates.w * scaleX / nativeScale;
rectInScreenCoordinates.h = rectInScreenCoordinates.h * scaleY / nativeScale;
impl(&rectInScreenCoordinates);
#else
impl(where);
#endif
#ifdef VCMI_APPLE
});

View File

@ -0,0 +1,23 @@
/*
* GameChatKeyboardHanlder.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface GameChatKeyboardHanlder : NSObject
@property (nonatomic, weak) UITextField * textFieldSDL;
- (void)triggerInput;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,107 @@
/*
* GameChatKeyboardHanlder.m, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#import "GameChatKeyboardHanlder.h"
#include <SDL_events.h>
static int watchReturnKey(void * userdata, SDL_Event * event);
static void sendKeyEvent(SDL_KeyCode keyCode)
{
SDL_Event keyEvent;
keyEvent.key = (SDL_KeyboardEvent){
.type = SDL_KEYDOWN,
.keysym.sym = keyCode,
};
SDL_PushEvent(&keyEvent);
}
static CGRect keyboardFrame(NSNotification * n, NSString * userInfoKey)
{
return [n.userInfo[userInfoKey] CGRectValue];
}
static CGRect keyboardFrameBegin(NSNotification * n) { return keyboardFrame(n, UIKeyboardFrameBeginUserInfoKey); }
static CGRect keyboardFrameEnd (NSNotification * n) { return keyboardFrame(n, UIKeyboardFrameEndUserInfoKey); }
@interface GameChatKeyboardHanlder ()
@property (nonatomic) BOOL wasChatMessageSent;
@end
@implementation GameChatKeyboardHanlder
- (void)triggerInput {
__auto_type notificationCenter = NSNotificationCenter.defaultCenter;
[notificationCenter addObserver:self selector:@selector(textDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil];
[notificationCenter addObserver:self selector:@selector(textDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];
[notificationCenter addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
[notificationCenter addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
self.wasChatMessageSent = NO;
sendKeyEvent(SDLK_TAB);
}
- (void)positionTextFieldAboveKeyboardRect:(CGRect)kbFrame {
__auto_type r = kbFrame;
r.size.height = CGRectGetHeight(self.textFieldSDL.frame);
r.origin.y -= r.size.height;
self.textFieldSDL.frame = r;
}
#pragma mark - Notifications
- (void)textDidBeginEditing:(NSNotification *)n {
self.textFieldSDL.hidden = NO;
self.textFieldSDL.text = nil;
// watch for pressing Return to ignore sending Escape key after keyboard is closed
SDL_AddEventWatch(watchReturnKey, (__bridge void *)self);
}
- (void)textDidEndEditing:(NSNotification *)n {
[NSNotificationCenter.defaultCenter removeObserver:self];
self.textFieldSDL.hidden = YES;
// discard chat message
if(!self.wasChatMessageSent)
sendKeyEvent(SDLK_ESCAPE);
}
- (void)keyboardWillChangeFrame:(NSNotification *)n {
// animate textfield together with keyboard
[UIView performWithoutAnimation:^{
[self positionTextFieldAboveKeyboardRect:keyboardFrameBegin(n)];
}];
NSTimeInterval kbAnimationDuration = [n.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
NSUInteger kbAnimationCurve = [n.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
[UIView animateWithDuration:kbAnimationDuration delay:0 options:(kbAnimationCurve << 16) animations:^{
[self positionTextFieldAboveKeyboardRect:keyboardFrameEnd(n)];
} completion:nil];
}
- (void)keyboardDidChangeFrame:(NSNotification *)n {
[self positionTextFieldAboveKeyboardRect:keyboardFrameEnd(n)];
}
@end
static int watchReturnKey(void * userdata, SDL_Event * event)
{
if(event->type == SDL_KEYDOWN && event->key.keysym.scancode == SDL_SCANCODE_RETURN)
{
__auto_type self = (__bridge GameChatKeyboardHanlder *)userdata;
self.wasChatMessageSent = YES;
SDL_DelEventWatch(watchReturnKey, userdata);
}
return 1;
}

View File

@ -0,0 +1,121 @@
{
"images" : [
{
"filename" : "Icon-App-20x20@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "Icon-App-20x20@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"filename" : "Icon-App-29x29@1x.png",
"idiom" : "iphone",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"filename" : "Icon-App-40x40@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "Icon-App-40x40@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "Icon-App-60x60@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "Icon-App-60x60@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "Icon-App-20x20@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"filename" : "Icon-App-20x20@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "Icon-App-29x29@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "Icon-App-29x29@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "Icon-App-40x40@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"filename" : "Icon-App-40x40@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "Icon-App-76x76@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"filename" : "Icon-App-76x76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "Icon-App-83.5x83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

60
client/ios/Info.plist Normal file
View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>VCMI</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>vcmi</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
<string>opengles-2</string>
</array>
<key>UIRequiresFullScreen</key>
<true/>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="vcmi_logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="xBx-rS-h4V">
<rect key="frame" x="87.5" y="233.5" width="200" height="200"/>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="Jnx-JV-IwA"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="xBx-rS-h4V" firstAttribute="centerY" secondItem="Jnx-JV-IwA" secondAttribute="centerY" id="OgR-oG-SHt"/>
<constraint firstItem="xBx-rS-h4V" firstAttribute="centerX" secondItem="Jnx-JV-IwA" secondAttribute="centerX" id="eTp-at-qVT"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="vcmi_logo.png" width="200" height="200"/>
</resources>
</document>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>StringsTable</key>
<string>Root</string>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Type</key>
<string>PSRadioGroupSpecifier</string>
<key>Title</key>
<string>LaunchType</string>
<key>Key</key>
<string>LaunchType</string>
<key>DefaultValue</key>
<integer>0</integer>
<key>Values</key>
<array>
<integer>0</integer>
<integer>1</integer>
</array>
<key>Titles</key>
<array>
<string>Launcher</string>
<string>Game</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@ -0,0 +1,3 @@
"LaunchType" = "App start type";
"Launcher" = "Launcher";
"Game" = "Game";

View File

@ -0,0 +1,3 @@
"LaunchType" = "Тип запуска приложения";
"Launcher" = "Конфигурация (лаунчер)";
"Game" = "Игра";

57
client/ios/main.m Normal file
View File

@ -0,0 +1,57 @@
/*
* main.m, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#import "startSDL.h"
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#include <stdlib.h>
static void startSDLManually(int argc, char * argv[])
{
id<UIApplicationDelegate> appDelegate;
@autoreleasepool {
__auto_type sdlAppDelegateClass = NSClassFromString(@"SDLUIKitDelegate");
NSCAssert(sdlAppDelegateClass != nil, @"SDL AppDelegate class doesn't exist");
NSCAssert(class_conformsToProtocol(sdlAppDelegateClass, @protocol(UIApplicationDelegate)), @"SDL AppDelegate doesn't conform to UIApplicationDelegate");
appDelegate = [sdlAppDelegateClass new];
}
UIApplication.sharedApplication.delegate = appDelegate;
int result = startSDL(argc, argv, YES);
exit(result);
}
int qt_main_wrapper(int argc, char * argv[]);
int client_main(int argc, char * argv[])
{
NSInteger launchType;
__auto_type envVar = getenv("VCMI_LAUNCH_TYPE");
if (envVar)
launchType = envVar[0] == '0' ? 0 : 1;
else {
@autoreleasepool {
launchType = [NSUserDefaults.standardUserDefaults integerForKey:@"LaunchType"];
}
}
if (launchType == 1)
return startSDL(argc, argv, NO);
@autoreleasepool {
id __block startGameObserver = [NSNotificationCenter.defaultCenter addObserverForName:@"StartGame" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
[NSNotificationCenter.defaultCenter removeObserver:startGameObserver];
startGameObserver = nil;
startSDLManually(argc, argv);
}];
return qt_main_wrapper(argc, argv);
}
}

19
client/ios/startSDL.h Normal file
View File

@ -0,0 +1,19 @@
/*
* startSDL.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#ifdef __OBJC__
#include <objc/objc.h>
#endif
#ifdef __cplusplus
extern "C"
#endif
int startSDL(int argc, char * argv[], BOOL startManually);

162
client/ios/startSDL.mm Normal file
View File

@ -0,0 +1,162 @@
/*
* startSDL.mm, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#import "startSDL.h"
#import "GameChatKeyboardHanlder.h"
#include "../Global.h"
#include "CMT.h"
#include "CServerHandler.h"
#include "CFocusableHelper.h"
#include <SDL_main.h>
#include <SDL_events.h>
#include <SDL_render.h>
#include <SDL_system.h>
#import <UIKit/UIKit.h>
@interface SDLViewObserver : NSObject <UIGestureRecognizerDelegate>
@property (nonatomic, strong) GameChatKeyboardHanlder * gameChatHandler;
@end
@implementation SDLViewObserver
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
[object removeObserver:self forKeyPath:keyPath];
UIView * view = [object valueForKeyPath:keyPath];
UITextField * textField;
for (UIView * v in view.subviews) {
if ([v isKindOfClass:[UITextField class]]) {
textField = (UITextField *)v;
break;
}
}
auto r = textField.frame;
r.size.height = 40;
textField.frame = r;
self.gameChatHandler.textFieldSDL = textField;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if(@available(iOS 13.0, *))
textField.backgroundColor = UIColor.systemBackgroundColor;
else
#endif
textField.backgroundColor = UIColor.whiteColor;
auto longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
longPress.minimumPressDuration = 0.2;
[view addGestureRecognizer:longPress];
auto pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
[view addGestureRecognizer:pinch];
}
#pragma mark - Gestures
- (void)handleLongPress:(UIGestureRecognizer *)gesture {
// send RMB click
SDL_EventType mouseButtonType;
switch (gesture.state)
{
case UIGestureRecognizerStateBegan:
mouseButtonType = SDL_MOUSEBUTTONDOWN;
break;
case UIGestureRecognizerStateEnded:
mouseButtonType = SDL_MOUSEBUTTONUP;
break;
default:
return;
}
auto renderer = SDL_GetRenderer(mainWindow);
float scaleX, scaleY;
SDL_Rect viewport;
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
SDL_RenderGetViewport(renderer, &viewport);
auto touchedPoint = [gesture locationInView:gesture.view];
auto screenScale = UIScreen.mainScreen.nativeScale;
Sint32 x = (int)touchedPoint.x * screenScale / scaleX - viewport.x;
Sint32 y = (int)touchedPoint.y * screenScale / scaleY - viewport.y;
SDL_Event rmbEvent;
rmbEvent.button = (SDL_MouseButtonEvent){
.type = mouseButtonType,
.button = SDL_BUTTON_RIGHT,
.clicks = 1,
.x = x,
.y = y,
};
SDL_PushEvent(&rmbEvent);
// small hack to prevent cursor jumping
if (mouseButtonType == SDL_MOUSEBUTTONUP)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.025 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
SDL_Event motionEvent;
motionEvent.motion = (SDL_MouseMotionEvent){
.type = SDL_MOUSEMOTION,
.x = x,
.y = y,
};
SDL_PushEvent(&motionEvent);
});
}
- (void)handlePinch:(UIGestureRecognizer *)gesture {
if(gesture.state != UIGestureRecognizerStateBegan || CSH->state != EClientState::GAMEPLAY)
return;
[self.gameChatHandler triggerInput];
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return [gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]];
}
@end
int startSDL(int argc, char * argv[], BOOL startManually)
{
@autoreleasepool {
auto observer = [SDLViewObserver new];
observer.gameChatHandler = [GameChatKeyboardHanlder new];
id __block sdlWindowCreationObserver = [NSNotificationCenter.defaultCenter addObserverForName:UIWindowDidBecomeKeyNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
[NSNotificationCenter.defaultCenter removeObserver:sdlWindowCreationObserver];
sdlWindowCreationObserver = nil;
UIWindow * sdlWindow = note.object;
[sdlWindow.rootViewController addObserver:observer forKeyPath:NSStringFromSelector(@selector(view)) options:NSKeyValueObservingOptionNew context:NULL];
}];
id textFieldObserver = [NSNotificationCenter.defaultCenter addObserverForName:UITextFieldTextDidEndEditingNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
removeFocusFromActiveInput();
}];
int result;
if (startManually)
{
// copied from -[SDLUIKitDelegate postFinishLaunch]
SDL_SetMainReady();
SDL_iOSSetEventPump(SDL_TRUE);
result = SDL_main(argc, argv);
SDL_iOSSetEventPump(SDL_FALSE);
}
else
result = SDL_UIKitRunApp(argc, argv, SDL_main);
[NSNotificationCenter.defaultCenter removeObserver:textFieldObserver];
return result;
}
}

18
client/ios/utils.h Normal file
View File

@ -0,0 +1,18 @@
/*
* utils.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
namespace iOS_utils
{
double screenScale();
void showLoadingIndicator();
void hideLoadingIndicator();
}

46
client/ios/utils.mm Normal file
View File

@ -0,0 +1,46 @@
/*
* utils.mm, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "utils.h"
#import <UIKit/UIKit.h>
namespace
{
UIActivityIndicatorView *indicator;
}
namespace iOS_utils
{
double screenScale()
{
return UIScreen.mainScreen.nativeScale;
}
void showLoadingIndicator()
{
NSCAssert(!indicator, @"activity indicator must be hidden before attempting to show it again");
indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[indicator startAnimating];
auto mainView = UIApplication.sharedApplication.keyWindow.rootViewController.view;
mainView.userInteractionEnabled = NO;
[mainView addSubview:indicator];
indicator.center = {CGRectGetMidX(mainView.bounds), CGRectGetMidY(mainView.bounds)};
}
void hideLoadingIndicator()
{
indicator.superview.userInteractionEnabled = YES;
[indicator stopAnimating];
[indicator removeFromSuperview];
indicator = nil;
}
}

BIN
client/ios/vcmi_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -10,8 +10,13 @@
#pragma once
#include "../windows/CWindowObject.h"
struct SDL_Surface;
VCMI_LIB_NAMESPACE_BEGIN
class CCampaignState;
VCMI_LIB_NAMESPACE_END
struct SDL_Surface;
class CButton;
class CTextBox;
class CToggleGroup;
@ -90,4 +95,4 @@ public:
std::shared_ptr<CButton> buttonDifficultyLeft;
std::shared_ptr<CButton> buttonDifficultyRight;
std::shared_ptr<CAnimImage> iconsMapSizes;
};
};

View File

@ -11,10 +11,15 @@
#include "CSelectionBase.h"
class CSelectionBase;
VCMI_LIB_NAMESPACE_BEGIN
struct StartInfo;
class CMapInfo;
VCMI_LIB_NAMESPACE_END
class CSelectionBase;
class CSavingScreen : public CSelectionBase
{
public:

View File

@ -11,6 +11,14 @@
#include "../mainmenu/CMainMenu.h"
VCMI_LIB_NAMESPACE_BEGIN
class CMapInfo;
struct StartInfo;
struct PlayerInfo;
VCMI_LIB_NAMESPACE_END
class CButton;
class CTextBox;
class CTextInput;
@ -21,9 +29,6 @@ class OptionsTab;
class SelectionTab;
class InfoCard;
class CChatBox;
class CMapInfo;
struct StartInfo;
struct PlayerInfo;
class CLabel;
class CFlagBox;
class CLabelGroup;

View File

@ -14,7 +14,12 @@
#include "../../lib/FunctionList.h"
#include "../../lib/GameConstants.h"
VCMI_LIB_NAMESPACE_BEGIN
class CMapGenOptions;
VCMI_LIB_NAMESPACE_END
class CToggleButton;
class CLabel;
class CLabelGroup;

View File

@ -129,7 +129,7 @@ static ESortBy getSortBySelectionScreen(ESelectionScreen Type)
}
SelectionTab::SelectionTab(ESelectionScreen Type)
: CIntObject(LCLICK | WHEEL | KEYBOARD | DOUBLECLICK), callOnSelect(nullptr), tabType(Type), selectionPos(0), sortModeAscending(true)
: CIntObject(LCLICK | WHEEL | KEYBOARD | DOUBLECLICK), callOnSelect(nullptr), tabType(Type), selectionPos(0), sortModeAscending(true), inputNameRect{32, 539, 350, 20}
{
OBJ_CONSTRUCTION;
@ -140,7 +140,7 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
sortingBy = _format;
background = std::make_shared<CPicture>("SCSELBCK.bmp", 0, 6);
pos = background->pos;
inputName = std::make_shared<CTextInput>(Rect(32, 539, 350, 20), Point(-32, -25), "GSSTRIP.bmp", 0);
inputName = std::make_shared<CTextInput>(inputNameRect, Point(-32, -25), "GSSTRIP.bmp", 0);
inputName->filters += CTextInput::filenameFilter;
labelMapSizes = std::make_shared<CLabel>(87, 62, FONT_SMALL, EAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[510]);
@ -273,6 +273,11 @@ void SelectionTab::clickLeft(tribool down, bool previousState)
{
select(line);
}
#ifdef VCMI_IOS
// focus input field if clicked inside it
else if(inputName && inputName->active && inputNameRect.isIn(GH.current->button.x, GH.current->button.y))
inputName->giveFocus();
#endif
}
}

View File

@ -90,6 +90,7 @@ private:
std::shared_ptr<CLabel> labelTabTitle;
std::shared_ptr<CLabel> labelMapSizes;
ESelectionScreen tabType;
Rect inputNameRect;
void parseMaps(const std::unordered_set<ResourceID> & files);
void parseSaves(const std::unordered_set<ResourceID> & files);

View File

@ -11,11 +11,16 @@
#include "../windows/CWindowObject.h"
VCMI_LIB_NAMESPACE_BEGIN
class JsonNode;
VCMI_LIB_NAMESPACE_END
class CLabel;
class CPicture;
class CButton;
struct SDL_Surface;
class JsonNode;
class CCampaignScreen : public CWindowObject
{

View File

@ -428,7 +428,9 @@ CMultiPlayers::CMultiPlayers(const std::string & firstPlayer, ESelectionScreen S
statusBar = CGStatusBar::create(std::make_shared<CPicture>(Rect(7, 381, 348, 18), 0)); //226, 472
inputNames[0]->setText(firstPlayer, true);
#ifndef VCMI_IOS
inputNames[0]->giveFocus();
#endif
}
void CMultiPlayers::onChange(std::string newText)
@ -490,6 +492,7 @@ void CSimpleJoinScreen::connectToServer()
{
textTitle->setText("Connecting...");
buttonOk->block(true);
CSDL_Ext::stopTextInput();
boost::thread(&CSimpleJoinScreen::connectThread, this, inputAddress->text, boost::lexical_cast<ui16>(inputPort->text));
}

View File

@ -12,7 +12,12 @@
#include "../windows/CWindowObject.h"
#include "../../lib/JsonNode.h"
VCMI_LIB_NAMESPACE_BEGIN
class CCampaignState;
VCMI_LIB_NAMESPACE_END
class CTextInput;
class CGStatusBar;
class CTextBox;

View File

@ -23,17 +23,22 @@
#undef OUT
#endif
VCMI_LIB_NAMESPACE_BEGIN
class CGObjectInstance;
class CGHeroInstance;
class CGBoat;
class CMap;
struct TerrainTile;
class PlayerColor;
VCMI_LIB_NAMESPACE_END
struct SDL_Surface;
struct SDL_Rect;
class CAnimation;
class IImage;
class CFadeAnimation;
class PlayerColor;
enum class EWorldViewIcon
{

View File

@ -13,21 +13,26 @@
#include "../../lib/FunctionList.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN
class CArmedInstance;
class CAnimation;
class CAnimImage;
class CShowableAnim;
class CFilledTexture;
class CGGarrison;
class CGObjectInstance;
class CGHeroInstance;
class CGTownInstance;
class CButton;
struct Component;
class CComponent;
struct InfoAboutArmy;
struct InfoAboutHero;
struct InfoAboutTown;
VCMI_LIB_NAMESPACE_END
class CAnimation;
class CAnimImage;
class CShowableAnim;
class CFilledTexture;
class CButton;
class CComponent;
class CHeroTooltip;
class CTownTooltip;
class CTextBox;

View File

@ -14,17 +14,21 @@
#include "../../lib/FunctionList.h"
VCMI_LIB_NAMESPACE_BEGIN
namespace config
{
struct ButtonInfo;
}
VCMI_LIB_NAMESPACE_END
struct SDL_Surface;
struct Rect;
class CAnimImage;
class CLabel;
class CAnimation;
namespace config
{
struct ButtonInfo;
}
/// Typical Heroes 3 button which can be inactive or active and can
/// hold further information if you right-click it
class CButton : public CKeyShortcut

View File

@ -11,12 +11,16 @@
#include "MiscWidgets.h"
VCMI_LIB_NAMESPACE_BEGIN
struct ArtifactLocation;
VCMI_LIB_NAMESPACE_END
class CArtifactsOfHero;
class CAnimImage;
class CButton;
struct ArtifactLocation;
class CArtifactHolder
{
public:

View File

@ -11,7 +11,12 @@
#include "../gui/CIntObject.h"
VCMI_LIB_NAMESPACE_BEGIN
struct Component;
VCMI_LIB_NAMESPACE_END
class CAnimImage;
class CLabel;

View File

@ -11,13 +11,18 @@
#include "../windows/CWindowObject.h"
VCMI_LIB_NAMESPACE_BEGIN
class CArmedInstance;
class CCreatureSet;
class CStackInstance;
VCMI_LIB_NAMESPACE_END
class CGarrisonInt;
class CButton;
class CArmedInstance;
class CAnimImage;
class CCreatureSet;
class CGarrisonSlot;
class CStackInstance;
class CLabel;
/// A single garrison slot which holds one creature of a specific amount

View File

@ -11,13 +11,18 @@
#include "../gui/CIntObject.h"
class CLabel;
class CCreatureAnim;
class CComponent;
VCMI_LIB_NAMESPACE_BEGIN
class CGGarrison;
struct InfoAboutArmy;
class CArmedInstance;
class IBonusBearer;
VCMI_LIB_NAMESPACE_END
class CLabel;
class CCreatureAnim;
class CComponent;
class CAnimImage;
/// Shows a text by moving the mouse cursor over the object

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