Merge branch 'master' into jgrpp
# Conflicts: # .github/workflows/ci-build.yml # .github/workflows/release-linux.yml # .github/workflows/release-macos.yml # .github/workflows/release-source.yml # .github/workflows/release.yml # CMakeLists.txt # COMPILING.md # src/ai/ai_core.cpp # src/ai/ai_gui.cpp # src/bridge_gui.cpp # src/company_gui.cpp # src/console_cmds.cpp # src/core/CMakeLists.txt # src/core/smallmap_type.hpp # src/disaster_vehicle.h # src/effectvehicle_base.h # src/fontcache.cpp # src/game/game_core.cpp # src/game/game_gui.cpp # src/gamelog.cpp # src/gamelog_internal.h # src/group_gui.cpp # src/linkgraph/linkgraph.h # src/misc.cpp # src/network/core/config.h # src/network/core/udp.cpp # src/network/network_chat_gui.cpp # src/network/network_content_gui.cpp # src/network/network_gui.cpp # src/newgrf.cpp # src/newgrf_gui.cpp # src/newgrf_profiling.cpp # src/newgrf_profiling.h # src/object_gui.cpp # src/openttd.cpp # src/openttd.h # src/order_gui.cpp # src/os/windows/font_win32.cpp # src/rail_gui.cpp # src/road.cpp # src/road_gui.cpp # src/saveload/afterload.cpp # src/saveload/saveload.h # src/script/api/script_controller.cpp # src/script/api/script_roadtypelist.cpp # src/script/script_config.cpp # src/script/script_config.hpp # src/script/script_instance.cpp # src/script/script_scanner.cpp # src/script/squirrel.cpp # src/script/squirrel_helper.hpp # src/settings_gui.cpp # src/settings_internal.h # src/settings_type.h # src/table/settings/network_private_settings.ini # src/timetable_gui.cpp # src/vehicle.cpp # src/vehicle_base.h # src/window_gui.h
This commit is contained in:
47
.github/workflows/ci-build.yml
vendored
47
.github/workflows/ci-build.yml
vendored
@@ -81,24 +81,30 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
linux:
|
||||
name: Linux
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- compiler: clang
|
||||
- name: Clang
|
||||
compiler: clang
|
||||
cxxcompiler: clang++
|
||||
libsdl: libsdl2-dev
|
||||
- compiler: gcc
|
||||
libraries: libsdl2-dev nlohmann-json3-dev
|
||||
- name: GCC - SDL2
|
||||
compiler: gcc
|
||||
cxxcompiler: g++
|
||||
libsdl: libsdl2-dev
|
||||
- compiler: gcc
|
||||
libraries: libsdl2-dev nlohmann-json3-dev
|
||||
- name: GCC - SDL1.2
|
||||
compiler: gcc
|
||||
cxxcompiler: g++
|
||||
libsdl: libsdl1.2-dev
|
||||
- compiler: gcc
|
||||
libraries: libsdl1.2-dev nlohmann-json3-dev
|
||||
- name: GCC - Dedicated
|
||||
compiler: gcc
|
||||
cxxcompiler: g++
|
||||
extra-cmake-parameters: -DOPTION_DEDICATED=ON -DCMAKE_CXX_FLAGS_INIT="-DRANDOM_DEBUG"
|
||||
# Compile without SDL / SDL2 / nlohmann-json, as that should compile fine too.
|
||||
|
||||
name: Linux (${{ matrix.name }})
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
@@ -132,7 +138,7 @@ jobs:
|
||||
liblzma-dev \
|
||||
libzstd-dev \
|
||||
liblzo2-dev \
|
||||
${{ matrix.libsdl }} \
|
||||
${{ matrix.libraries }} \
|
||||
zlib1g-dev \
|
||||
# EOF
|
||||
echo "::endgroup::"
|
||||
@@ -172,8 +178,6 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
macos:
|
||||
name: Mac OS
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -181,6 +185,8 @@ jobs:
|
||||
- arch: x64
|
||||
full_arch: x86_64
|
||||
|
||||
name: Mac OS (${{ matrix.arch }})
|
||||
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.13
|
||||
@@ -214,7 +220,7 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /usr/local/share/vcpkg/installed
|
||||
key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified
|
||||
key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-1 # Increase the number whenever dependencies are modified
|
||||
restore-keys: |
|
||||
${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}
|
||||
|
||||
@@ -225,6 +231,7 @@ jobs:
|
||||
liblzma \
|
||||
libpng \
|
||||
lzo \
|
||||
nlohmann-json \
|
||||
zlib \
|
||||
zstd \
|
||||
# EOF
|
||||
@@ -232,7 +239,7 @@ jobs:
|
||||
- name: Install OpenGFX
|
||||
run: |
|
||||
mkdir -p ~/Documents/OpenTTD/baseset
|
||||
cd ~/Documents//OpenTTD/baseset
|
||||
cd ~/Documents/OpenTTD/baseset
|
||||
|
||||
echo "::group::Download OpenGFX"
|
||||
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
|
||||
@@ -253,7 +260,7 @@ jobs:
|
||||
cd build
|
||||
|
||||
echo "::group::CMake"
|
||||
cmake ${GITHUB_WORKSPACE} \
|
||||
cmake .. \
|
||||
-DCMAKE_OSX_ARCHITECTURES=${{ matrix.full_arch }} \
|
||||
-DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-osx \
|
||||
-DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake \
|
||||
@@ -266,14 +273,14 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
windows:
|
||||
name: Windows
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, windows-2019]
|
||||
arch: [x86, x64]
|
||||
|
||||
name: Windows (${{ matrix.os }} / ${{ matrix.arch }})
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
@@ -300,7 +307,7 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vcpkg/installed
|
||||
key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified
|
||||
key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-1 # Increase the number whenever dependencies are modified
|
||||
restore-keys: |
|
||||
${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}
|
||||
|
||||
@@ -311,6 +318,7 @@ jobs:
|
||||
liblzma \
|
||||
libpng \
|
||||
lzo \
|
||||
nlohmann-json \
|
||||
zlib \
|
||||
zstd \
|
||||
# EOF
|
||||
@@ -358,8 +366,6 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
msys2:
|
||||
name: msys2
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -369,6 +375,8 @@ jobs:
|
||||
- msystem: MINGW32
|
||||
arch: i686
|
||||
|
||||
name: MinGW (${{ matrix.arch }})
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
@@ -394,6 +402,7 @@ jobs:
|
||||
mingw-w64-${{ matrix.arch }}-gcc
|
||||
mingw-w64-${{ matrix.arch }}-lzo2
|
||||
mingw-w64-${{ matrix.arch }}-libpng
|
||||
mingw-w64-${{ matrix.arch }}-nlohmann-json
|
||||
|
||||
- name: Install OpenGFX
|
||||
shell: bash
|
||||
|
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -49,10 +49,12 @@ jobs:
|
||||
liballegro4-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libfontconfig-dev \
|
||||
libharfbuzz-dev \
|
||||
libicu-dev \
|
||||
liblzma-dev \
|
||||
liblzo2-dev \
|
||||
libsdl2-dev \
|
||||
nlohmann-json3-dev \
|
||||
zlib1g-dev \
|
||||
# EOF
|
||||
echo "::endgroup::"
|
||||
|
@@ -120,6 +120,7 @@ find_package(LibLZMA)
|
||||
find_package(LZO)
|
||||
find_package(ZSTD 1.4)
|
||||
find_package(PNG)
|
||||
find_package(nlohmann_json)
|
||||
|
||||
if(WIN32 OR EMSCRIPTEN)
|
||||
# Windows uses WinHttp for HTTP requests.
|
||||
@@ -345,6 +346,7 @@ link_package(ZLIB TARGET ZLIB::ZLIB ENCOURAGED)
|
||||
link_package(LIBLZMA TARGET LibLZMA::LibLZMA ENCOURAGED)
|
||||
link_package(LZO)
|
||||
link_package(ZSTD TARGET ZSTD::ZSTD RECOMMENDED)
|
||||
link_package(nlohmann_json ENCOURAGED)
|
||||
|
||||
if(NOT WIN32 AND NOT EMSCRIPTEN)
|
||||
link_package(CURL ENCOURAGED)
|
||||
|
@@ -4,6 +4,7 @@
|
||||
|
||||
OpenTTD makes use of the following external libraries:
|
||||
|
||||
- (encouraged) nlohmann-json: JSON handling
|
||||
- (encouraged) zlib: (de)compressing of old (0.3.0-1.0.5) savegames, content downloads,
|
||||
heightmaps
|
||||
- (encouraged) liblzma: (de)compressing of savegames (1.1.0 and later)
|
||||
@@ -54,13 +55,14 @@ the `static` versions, and OpenTTD currently needs the following dependencies:
|
||||
- libzstd
|
||||
- libpng
|
||||
- lzo
|
||||
- nlohmann-json
|
||||
- zlib
|
||||
|
||||
To install both the x64 (64bit) and x86 (32bit) variants (though only one is necessary), you can use:
|
||||
|
||||
```ps
|
||||
.\vcpkg install liblzma:x64-windows-static zstd:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static zlib:x64-windows-static
|
||||
.\vcpkg install liblzma:x86-windows-static zstd:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static zlib:x86-windows-static
|
||||
.\vcpkg install liblzma:x64-windows-static zstd:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static nlohmann-json:x64-windows-static zlib:x64-windows-static
|
||||
.\vcpkg install liblzma:x86-windows-static zstd:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static nlohmann-json:x86-windows-static zlib:x86-windows-static
|
||||
```
|
||||
|
||||
You can open the folder (as a CMake project). CMake will be detected, and you can compile from there.
|
||||
|
@@ -71,6 +71,8 @@ function(set_options)
|
||||
if (OPTION_DOCS_ONLY)
|
||||
set(OPTION_TOOLS_ONLY ON PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
option(OPTION_SURVEY_KEY "Survey-key to use for the opt-in survey (empty if you have none)" "")
|
||||
endfunction()
|
||||
|
||||
# Show the values of the generic options.
|
||||
@@ -84,6 +86,12 @@ function(show_options)
|
||||
message(STATUS "Option Use assert - ${OPTION_USE_ASSERTS}")
|
||||
message(STATUS "Option Use threads - ${OPTION_USE_THREADS}")
|
||||
message(STATUS "Option Use NSIS - ${OPTION_USE_NSIS}")
|
||||
|
||||
if(OPTION_SURVEY_KEY)
|
||||
message(STATUS "Option Survey Key - USED")
|
||||
else()
|
||||
message(STATUS "Option Survey Key - NOT USED")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Add the definitions for the options that are selected.
|
||||
@@ -104,4 +112,8 @@ function(add_definitions_based_on_options)
|
||||
else()
|
||||
add_definitions(-DNDEBUG)
|
||||
endif()
|
||||
|
||||
if(OPTION_SURVEY_KEY)
|
||||
add_definitions(-DSURVEY_KEY="${OPTION_SURVEY_KEY}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
@@ -28,21 +28,21 @@ endmacro()
|
||||
macro(dump_class_templates NAME)
|
||||
string(REGEX REPLACE "^Script" "" REALNAME ${NAME})
|
||||
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<const ${NAME} *> { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<const ${NAME} &> { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<const ${NAME} *> { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<const ${NAME} &> { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };")
|
||||
if("${NAME}" STREQUAL "ScriptEvent")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };")
|
||||
elseif("${NAME}" STREQUAL "ScriptText")
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<Text *> {")
|
||||
string(APPEND SQUIRREL_EXPORT "\n static inline Text *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {")
|
||||
string(APPEND SQUIRREL_EXPORT "\n static inline Text *Get(HSQUIRRELVM vm, int index) {")
|
||||
string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_INSTANCE) {")
|
||||
string(APPEND SQUIRREL_EXPORT "\n return Param<ScriptText *>::Get(vm, index, ptr);")
|
||||
string(APPEND SQUIRREL_EXPORT "\n return Param<ScriptText *>::Get(vm, index);")
|
||||
string(APPEND SQUIRREL_EXPORT "\n }")
|
||||
string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_STRING) {")
|
||||
string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param<const char *>::Get(vm, index, ptr));")
|
||||
string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param<const std::string &>::Get(vm, index));")
|
||||
string(APPEND SQUIRREL_EXPORT "\n }")
|
||||
string(APPEND SQUIRREL_EXPORT "\n return nullptr;")
|
||||
string(APPEND SQUIRREL_EXPORT "\n }")
|
||||
@@ -299,7 +299,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
endif()
|
||||
string(APPEND SQUIRREL_EXPORT "\n /* Allow enums to be used as Squirrel parameters */")
|
||||
foreach(ENUM IN LISTS ENUMS)
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${ENUM}> { static inline ${ENUM} Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${ENUM}> { static inline ${ENUM} Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; } };")
|
||||
string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${ENUM}> { static inline int Set(HSQUIRRELVM vm, ${ENUM} res) { sq_pushinteger(vm, res); return 1; } };")
|
||||
endforeach()
|
||||
endif()
|
||||
@@ -631,6 +631,8 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
string(APPEND TYPES "a")
|
||||
elseif("${PARAM}" MATCHES "^Text")
|
||||
string(APPEND TYPES ".")
|
||||
elseif("${PARAM}" MATCHES "^std::string")
|
||||
string(APPEND TYPES ".")
|
||||
else()
|
||||
string(APPEND TYPES "x")
|
||||
endif()
|
||||
|
@@ -2,3 +2,6 @@ FROM emscripten/emsdk:3.1.37
|
||||
|
||||
COPY emsdk-liblzma.patch /
|
||||
RUN cd /emsdk/upstream/emscripten && patch -p1 < /emsdk-liblzma.patch
|
||||
|
||||
COPY emsdk-nlohmann-json.patch /
|
||||
RUN cd /emsdk/upstream/emscripten && patch -p1 < /emsdk-nlohmann-json.patch
|
||||
|
@@ -4,10 +4,11 @@ Please use docker with the supplied `Dockerfile` to build for emscripten.
|
||||
It takes care of a few things:
|
||||
- Use a version of emscripten we know works
|
||||
- Patch in LibLZMA support (as this is not supported by upstream)
|
||||
- Patch in nlohmann-json support (as this is not supported by upstream)
|
||||
|
||||
First, build the docker image by navigating in the folder this `README.md` is in, and executing:
|
||||
```
|
||||
docker build -t emsdk-lzma .
|
||||
docker build -t emsdk-openttd .
|
||||
```
|
||||
|
||||
Next, navigate back to the root folder of this project.
|
||||
@@ -15,15 +16,15 @@ Next, navigate back to the root folder of this project.
|
||||
Now we build the host tools first:
|
||||
```
|
||||
mkdir build-host
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-lzma cmake .. -DOPTION_TOOLS_ONLY=ON
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-lzma make -j$(nproc) tools
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-openttd cmake .. -DOPTION_TOOLS_ONLY=ON
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-openttd make -j$(nproc) tools
|
||||
```
|
||||
|
||||
Finally, we build the actual game:
|
||||
```
|
||||
mkdir build
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emcmake cmake .. -DHOST_BINARY_DIR=../build-host -DCMAKE_BUILD_TYPE=Release -DOPTION_USE_ASSERTS=OFF
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emmake make -j$(nproc)
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-openttd emcmake cmake .. -DHOST_BINARY_DIR=../build-host -DCMAKE_BUILD_TYPE=Release -DOPTION_USE_ASSERTS=OFF
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-openttd emmake make -j$(nproc)
|
||||
```
|
||||
|
||||
In the `build` folder you will now see `openttd.html`.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# LibLZMA is a recent addition to the emscripten SDK, so it is possible
|
||||
# someone hasn't updated their SDK yet. Test out if the SDK supports LibLZMA.
|
||||
# LibLZMA is a custom addition to the emscripten SDK, so it is possible
|
||||
# someone patched their SDK. Test out if the SDK supports LibLZMA.
|
||||
include(CheckCXXSourceCompiles)
|
||||
set(CMAKE_REQUIRED_FLAGS "-sUSE_LIBLZMA=1")
|
||||
|
||||
|
20
os/emscripten/cmake/Findnlohmann_json.cmake
Normal file
20
os/emscripten/cmake/Findnlohmann_json.cmake
Normal file
@@ -0,0 +1,20 @@
|
||||
# nlohmann-json is a custom addition to the emscripten SDK, so it is possible
|
||||
# someone patched their SDK. Test out if the SDK supports nlohmann-json.
|
||||
include(CheckCXXSourceCompiles)
|
||||
set(CMAKE_REQUIRED_FLAGS "-sUSE_NLOHMANN_JSON=1")
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <nlohmann/json.hpp>
|
||||
int main() { return 0; }"
|
||||
NLOHMANN_JSON_FOUND
|
||||
)
|
||||
|
||||
if (NLOHMANN_JSON_FOUND)
|
||||
add_library(nlohmann_json INTERFACE IMPORTED)
|
||||
set_target_properties(nlohmann_json PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "-sUSE_NLOHMANN_JSON=1"
|
||||
INTERFACE_LINK_LIBRARIES "-sUSE_NLOHMANN_JSON=1"
|
||||
)
|
||||
else()
|
||||
message(WARNING "You are using an emscripten SDK without nlohmann-json support. Please apply 'emsdk-nlohmann_json.patch' to your local emsdk installation.")
|
||||
endif()
|
93
os/emscripten/emsdk-nlohmann-json.patch
Normal file
93
os/emscripten/emsdk-nlohmann-json.patch
Normal file
@@ -0,0 +1,93 @@
|
||||
From 0edcedbea375e59f41df10acaee0c483d245751f Mon Sep 17 00:00:00 2001
|
||||
From: Patric Stout <truebrain@openttd.org>
|
||||
Date: Tue, 2 May 2023 21:48:08 +0200
|
||||
Subject: [PATCH] Add nlohmmann-json port
|
||||
|
||||
---
|
||||
src/settings.js | 4 ++++
|
||||
tools/ports/nlohmann_json.py | 46 ++++++++++++++++++++++++++++++++++++
|
||||
tools/settings.py | 1 +
|
||||
3 files changed, 51 insertions(+)
|
||||
create mode 100644 tools/ports/nlohmann_json.py
|
||||
|
||||
diff --git a/src/settings.js b/src/settings.js
|
||||
index f93140d..39f4366 100644
|
||||
--- a/src/settings.js
|
||||
+++ b/src/settings.js
|
||||
@@ -1483,6 +1483,10 @@ var USE_MPG123 = false;
|
||||
// [compile+link]
|
||||
var USE_FREETYPE = false;
|
||||
|
||||
+// 1 = use nlohmann-json from emscripten-ports
|
||||
+// [compile+link]
|
||||
+var USE_NLOHMANN_JSON = false;
|
||||
+
|
||||
// Specify the SDL_mixer version that is being linked against.
|
||||
// Doesn't *have* to match USE_SDL, but a good idea.
|
||||
// [compile+link]
|
||||
diff --git a/tools/ports/nlohmann_json.py b/tools/ports/nlohmann_json.py
|
||||
new file mode 100644
|
||||
index 0000000..9e44297
|
||||
--- /dev/null
|
||||
+++ b/tools/ports/nlohmann_json.py
|
||||
@@ -0,0 +1,46 @@
|
||||
+# Copyright 2023 The Emscripten Authors. All rights reserved.
|
||||
+# Emscripten is available under two separate licenses, the MIT license and the
|
||||
+# University of Illinois/NCSA Open Source License. Both these licenses can be
|
||||
+# found in the LICENSE file.
|
||||
+
|
||||
+import os
|
||||
+
|
||||
+TAG = '3.11.2'
|
||||
+HASH = '99d9e6d588cabe8913a37437f86acb5d4b8b98bce12423e633c11c13b61e6c7f92ef8f9a4e991baa590329ee2b5c09ca9db9894bee1e54bdd68e8d09d83cc245'
|
||||
+
|
||||
+
|
||||
+def needed(settings):
|
||||
+ return settings.USE_NLOHMANN_JSON
|
||||
+
|
||||
+
|
||||
+def get(ports, settings, shared):
|
||||
+ ports.fetch_project('nlohmann_json',
|
||||
+ f'https://github.com/nlohmann/json/releases/download/v{TAG}/include.zip',
|
||||
+ sha512hash=HASH)
|
||||
+
|
||||
+ def create(final):
|
||||
+ source_path = os.path.join(ports.get_dir(), 'nlohmann_json')
|
||||
+ source_path_include = os.path.join(source_path, 'include', 'nlohmann')
|
||||
+ ports.install_header_dir(source_path_include, 'nlohmann')
|
||||
+
|
||||
+ # write out a dummy cpp file, to create an empty library
|
||||
+ # this is needed as emscripten ports expect this, even if it is not used
|
||||
+ dummy_file = os.path.join(source_path, 'dummy.cpp')
|
||||
+ shared.safe_ensure_dirs(os.path.dirname(dummy_file))
|
||||
+ ports.write_file(dummy_file, 'static void dummy() {}')
|
||||
+
|
||||
+ ports.build_port(source_path, final, 'nlohmann_json', srcs=['dummy.cpp'])
|
||||
+
|
||||
+ return [shared.cache.get_lib('libnlohmann_json.a', create, what='port')]
|
||||
+
|
||||
+
|
||||
+def clear(ports, settings, shared):
|
||||
+ shared.cache.erase_lib('libnlohmann_json.a')
|
||||
+
|
||||
+
|
||||
+def process_args(ports):
|
||||
+ return []
|
||||
+
|
||||
+
|
||||
+def show():
|
||||
+ return 'nlohmann-json'
|
||||
diff --git a/tools/settings.py b/tools/settings.py
|
||||
index 10d6ca0..8536092 100644
|
||||
--- a/tools/settings.py
|
||||
+++ b/tools/settings.py
|
||||
@@ -47,6 +47,7 @@ PORTS_SETTINGS = {
|
||||
'USE_MPG123',
|
||||
'USE_GIFLIB',
|
||||
'USE_FREETYPE',
|
||||
+ 'USE_NLOHMANN_JSON',
|
||||
'SDL2_MIXER_FORMATS',
|
||||
'SDL2_IMAGE_FORMATS',
|
||||
'USE_SQLITE3',
|
||||
--
|
||||
2.34.1
|
3
src/3rdparty/squirrel/include/squirrel.h
vendored
3
src/3rdparty/squirrel/include/squirrel.h
vendored
@@ -307,7 +307,8 @@ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror,
|
||||
SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror);
|
||||
const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx);
|
||||
const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);
|
||||
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err);
|
||||
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err, SQInteger len = -1);
|
||||
static inline SQRESULT sq_throwerror(HSQUIRRELVM v, const std::string_view err) { return sq_throwerror(v, err.data(), err.size()); }
|
||||
void sq_reseterror(HSQUIRRELVM v);
|
||||
void sq_getlasterror(HSQUIRRELVM v);
|
||||
|
||||
|
4
src/3rdparty/squirrel/squirrel/sqapi.cpp
vendored
4
src/3rdparty/squirrel/squirrel/sqapi.cpp
vendored
@@ -930,9 +930,9 @@ void sq_resetobject(HSQOBJECT *po)
|
||||
po->_unVal.pUserPointer=nullptr;po->_type=OT_NULL;
|
||||
}
|
||||
|
||||
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err)
|
||||
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err, SQInteger len)
|
||||
{
|
||||
v->_lasterror=SQString::Create(_ss(v),err);
|
||||
v->_lasterror=SQString::Create(_ss(v),err, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@@ -120,9 +120,9 @@ public:
|
||||
/** Wrapper function for AIScanner::GetUniqueAIInfoList */
|
||||
static const ScriptInfoList *GetUniqueInfoList();
|
||||
/** Wrapper function for AIScanner::FindInfo */
|
||||
static class AIInfo *FindInfo(const char *name, int version, bool force_exact_match);
|
||||
static class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
/** Wrapper function for AIScanner::FindLibrary */
|
||||
static class AILibrary *FindLibrary(const char *library, int version);
|
||||
static class AILibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
/**
|
||||
* Rescans all searchpaths for available AIs. If a used AI is no longer
|
||||
|
@@ -33,7 +33,7 @@ class AIInfo *AIConfig::GetInfo() const
|
||||
return static_cast<class AIInfo *>(ScriptConfig::GetInfo());
|
||||
}
|
||||
|
||||
ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
ScriptInfo *AIConfig::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
return static_cast<ScriptInfo *>(AI::FindInfo(name, version, force_exact_match));
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ public:
|
||||
bool ResetInfo(bool force_exact_match);
|
||||
|
||||
protected:
|
||||
ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override;
|
||||
ScriptInfo *FindInfo(const std::string &name, int version, bool force_exact_match) override;
|
||||
};
|
||||
|
||||
#endif /* AI_CONFIG_HPP */
|
||||
|
@@ -81,7 +81,7 @@
|
||||
Backup<CompanyID> cur_company(_current_company, FILE_LINE);
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (c->is_ai) {
|
||||
SCOPE_INFO_FMT([&], "AI::GameLoop: %i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
|
||||
SCOPE_INFO_FMT([&], "AI::GameLoop: %i: %s (v%d)\n", (int)c->index, c->ai_info->GetName().c_str(), c->ai_info->GetVersion());
|
||||
PerformanceMeasurer framerate((PerformanceElement)(PFE_AI0 + c->index));
|
||||
cur_company.Change(c->index);
|
||||
c->ai_instance->GameLoop();
|
||||
@@ -205,8 +205,8 @@
|
||||
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
|
||||
if (_settings_game.ai_config[c] != nullptr && _settings_game.ai_config[c]->HasScript()) {
|
||||
if (!_settings_game.ai_config[c]->ResetInfo(true)) {
|
||||
DEBUG(script, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName());
|
||||
_settings_game.ai_config[c]->Change(nullptr);
|
||||
DEBUG(script, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName().c_str());
|
||||
_settings_game.ai_config[c]->Change(std::nullopt);
|
||||
if (Company::IsValidAiID(c)) {
|
||||
/* The code belonging to an already running AI was deleted. We can only do
|
||||
* one thing here to keep everything sane and that is kill the AI. After
|
||||
@@ -222,8 +222,8 @@
|
||||
}
|
||||
if (_settings_newgame.ai_config[c] != nullptr && _settings_newgame.ai_config[c]->HasScript()) {
|
||||
if (!_settings_newgame.ai_config[c]->ResetInfo(false)) {
|
||||
DEBUG(script, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName());
|
||||
_settings_newgame.ai_config[c]->Change(nullptr);
|
||||
DEBUG(script, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName().c_str());
|
||||
_settings_newgame.ai_config[c]->Change(std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,12 +307,12 @@
|
||||
return AI::scanner_info->GetUniqueInfoList();
|
||||
}
|
||||
|
||||
/* static */ AIInfo *AI::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
/* static */ AIInfo *AI::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
return AI::scanner_info->FindInfo(name, version, force_exact_match);
|
||||
}
|
||||
|
||||
/* static */ AILibrary *AI::FindLibrary(const char *library, int version)
|
||||
/* static */ AILibrary *AI::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
return AI::scanner_library->FindLibrary(library, version);
|
||||
}
|
||||
|
@@ -181,7 +181,7 @@ struct AIConfigWindow : public Window {
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_END) {
|
||||
if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_CONTENT_END) {
|
||||
if (this->selected_slot == INVALID_COMPANY || AIConfig::GetConfig(this->selected_slot) == nullptr) return;
|
||||
|
||||
ShowScriptTextfileWindow((TextfileType)(widget - WID_AIC_TEXTFILE), this->selected_slot);
|
||||
@@ -282,7 +282,7 @@ struct AIConfigWindow : public Window {
|
||||
this->SetWidgetDisabledState(WID_AIC_MOVE_UP, this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot - 1)));
|
||||
this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot + 1)));
|
||||
|
||||
for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) {
|
||||
for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
|
||||
this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == INVALID_COMPANY || (AIConfig::GetConfig(this->selected_slot)->GetTextfile(tft, this->selected_slot) == nullptr));
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include "../debug.h"
|
||||
#include "../string_func.h"
|
||||
#include "../rev.h"
|
||||
#include "../3rdparty/fmt/format.h"
|
||||
#include <set>
|
||||
|
||||
#include "../safeguards.h"
|
||||
@@ -23,7 +24,7 @@
|
||||
* Check if the API version provided by the AI is supported.
|
||||
* @param api_version The API version as provided by the AI.
|
||||
*/
|
||||
static bool CheckAPIVersion(const char *api_version)
|
||||
static bool CheckAPIVersion(const std::string &api_version)
|
||||
{
|
||||
static const std::set<std::string> versions = { "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14" };
|
||||
return versions.find(api_version) != versions.end();
|
||||
@@ -69,26 +70,26 @@ template <> const char *GetClassName<AIInfo, ScriptType::AI>() { return "AIInfo"
|
||||
SQInteger res = ScriptInfo::Constructor(vm, info);
|
||||
if (res != 0) return res;
|
||||
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) {
|
||||
if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "MinVersionToLoad")) {
|
||||
if (!info->engine->CallIntegerMethod(info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
} else {
|
||||
info->min_loadable_version = info->GetVersion();
|
||||
}
|
||||
/* When there is an UseAsRandomAI function, call it. */
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "UseAsRandomAI")) {
|
||||
if (!info->engine->CallBoolMethod(*info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "UseAsRandomAI")) {
|
||||
if (!info->engine->CallBoolMethod(info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR;
|
||||
} else {
|
||||
info->use_as_random = true;
|
||||
}
|
||||
/* Try to get the API version the AI is written for. */
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "GetAPIVersion")) {
|
||||
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "GetAPIVersion")) {
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!CheckAPIVersion(info->api_version)) {
|
||||
DEBUG(script, 1, "Loading info.nut from (%s.%d): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion());
|
||||
DEBUG(script, 1, "Loading info.nut from (%s.%d): GetAPIVersion returned invalid version", info->GetName().c_str(), info->GetVersion());
|
||||
return SQ_ERROR;
|
||||
}
|
||||
} else {
|
||||
info->api_version = stredup("0.7");
|
||||
info->api_version = "0.7";
|
||||
}
|
||||
|
||||
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
|
||||
@@ -104,15 +105,11 @@ template <> const char *GetClassName<AIInfo, ScriptType::AI>() { return "AIInfo"
|
||||
SQUserPointer instance;
|
||||
sq_getinstanceup(vm, 2, &instance, nullptr);
|
||||
AIInfo *info = (AIInfo *)instance;
|
||||
info->api_version = nullptr;
|
||||
info->api_version = fmt::format("{}.{}", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4));
|
||||
|
||||
SQInteger res = ScriptInfo::Constructor(vm, info);
|
||||
if (res != 0) return res;
|
||||
|
||||
char buf[8];
|
||||
seprintf(buf, lastof(buf), "%d.%d", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4));
|
||||
info->api_version = stredup(buf);
|
||||
|
||||
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
|
||||
sq_setinstanceup(vm, 2, nullptr);
|
||||
/* Register the AI to the base system */
|
||||
@@ -122,16 +119,10 @@ template <> const char *GetClassName<AIInfo, ScriptType::AI>() { return "AIInfo"
|
||||
|
||||
AIInfo::AIInfo() :
|
||||
min_loadable_version(0),
|
||||
use_as_random(false),
|
||||
api_version(nullptr)
|
||||
use_as_random(false)
|
||||
{
|
||||
}
|
||||
|
||||
AIInfo::~AIInfo()
|
||||
{
|
||||
free(this->api_version);
|
||||
}
|
||||
|
||||
bool AIInfo::CanLoadFromVersion(int version) const
|
||||
{
|
||||
if (version == -1) return true;
|
||||
@@ -139,11 +130,6 @@ bool AIInfo::CanLoadFromVersion(int version) const
|
||||
}
|
||||
|
||||
|
||||
AILibrary::~AILibrary()
|
||||
{
|
||||
free(this->category);
|
||||
}
|
||||
|
||||
/* static */ void AILibrary::RegisterAPI(Squirrel *engine)
|
||||
{
|
||||
/* Create the AILibrary class, and add the RegisterLibrary function */
|
||||
@@ -164,7 +150,7 @@ AILibrary::~AILibrary()
|
||||
}
|
||||
|
||||
/* Cache the category */
|
||||
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
|
||||
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
|
||||
delete library;
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@
|
||||
class AIInfo : public ScriptInfo {
|
||||
public:
|
||||
AIInfo();
|
||||
~AIInfo();
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
@@ -46,19 +45,18 @@ public:
|
||||
/**
|
||||
* Get the API version this AI is written for.
|
||||
*/
|
||||
const char *GetAPIVersion() const { return this->api_version; }
|
||||
const std::string &GetAPIVersion() const { return this->api_version; }
|
||||
|
||||
private:
|
||||
int min_loadable_version; ///< The AI can load savegame data if the version is equal or greater than this.
|
||||
bool use_as_random; ///< Should this AI be used when the user wants a "random AI"?
|
||||
const char *api_version; ///< API version used by this AI.
|
||||
std::string api_version; ///< API version used by this AI.
|
||||
};
|
||||
|
||||
/** All static information from an AI library like name, version, etc. */
|
||||
class AILibrary : public ScriptInfo {
|
||||
public:
|
||||
AILibrary() : ScriptInfo(), category(nullptr) {};
|
||||
~AILibrary();
|
||||
AILibrary() : ScriptInfo() {};
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
@@ -73,10 +71,10 @@ public:
|
||||
/**
|
||||
* Get the category this library is in.
|
||||
*/
|
||||
const char *GetCategory() const { return this->category; }
|
||||
const std::string &GetCategory() const { return this->category; }
|
||||
|
||||
private:
|
||||
const char *category; ///< The category this library is in.
|
||||
std::string category; ///< The category this library is in.
|
||||
};
|
||||
|
||||
#endif /* AI_INFO_HPP */
|
||||
|
@@ -69,7 +69,7 @@ void AIInstance::Died()
|
||||
if (info != nullptr) {
|
||||
ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING);
|
||||
|
||||
if (info->GetURL() != nullptr) {
|
||||
if (!info->GetURL().empty()) {
|
||||
ScriptLog::Info("Please report the error to the following URL:");
|
||||
ScriptLog::Info(info->GetURL());
|
||||
}
|
||||
@@ -82,12 +82,12 @@ void AIInstance::LoadDummyScript()
|
||||
Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI");
|
||||
}
|
||||
|
||||
int AIInstance::GetSetting(const char *name)
|
||||
int AIInstance::GetSetting(const std::string &name)
|
||||
{
|
||||
return AIConfig::GetConfig(_current_company)->GetSetting(name);
|
||||
}
|
||||
|
||||
ScriptInfo *AIInstance::FindLibrary(const char *library, int version)
|
||||
ScriptInfo *AIInstance::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
return (ScriptInfo *)AI::FindLibrary(library, version);
|
||||
}
|
||||
|
@@ -23,8 +23,8 @@ public:
|
||||
*/
|
||||
void Initialize(class AIInfo *info);
|
||||
|
||||
int GetSetting(const char *name) override;
|
||||
ScriptInfo *FindLibrary(const char *library, int version) override;
|
||||
int GetSetting(const std::string &name) override;
|
||||
ScriptInfo *FindLibrary(const std::string &library, int version) override;
|
||||
|
||||
private:
|
||||
void RegisterAPI() override;
|
||||
|
@@ -93,10 +93,10 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
|
||||
#undef GetAIInfo
|
||||
}
|
||||
|
||||
AIInfo *AIScannerInfo::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
AIInfo *AIScannerInfo::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
if (this->info_list.size() == 0) return nullptr;
|
||||
if (name == nullptr) return nullptr;
|
||||
if (name.empty()) return nullptr;
|
||||
|
||||
if (version == -1) {
|
||||
/* We want to load the latest version of this AI; so find it */
|
||||
@@ -146,7 +146,7 @@ void AIScannerLibrary::RegisterAPI(class Squirrel *engine)
|
||||
AILibrary::RegisterAPI(engine);
|
||||
}
|
||||
|
||||
AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version)
|
||||
AILibrary *AIScannerLibrary::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
/* Internally we store libraries as 'library.version' */
|
||||
std::string library_name = fmt::format("{}.{}", library, version);
|
||||
|
@@ -32,7 +32,7 @@ public:
|
||||
* @param force_exact_match Only match name+version, never latest.
|
||||
* @return nullptr if no match found, otherwise the AI that matched.
|
||||
*/
|
||||
class AIInfo *FindInfo(const char *name, int version, bool force_exact_match);
|
||||
class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
|
||||
/**
|
||||
* Set the Dummy AI.
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
* @param version The version the library should have.
|
||||
* @return The library if found, nullptr otherwise.
|
||||
*/
|
||||
class AILibrary *FindLibrary(const char *library, int version);
|
||||
class AILibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
protected:
|
||||
std::string GetScriptName(ScriptInfo *info) override;
|
||||
|
@@ -487,8 +487,8 @@ public:
|
||||
break;
|
||||
|
||||
case WID_AP_AIRPORT_LIST: {
|
||||
int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget<NWidgetBase>(widget)->pos_y) / this->line_height;
|
||||
if (num_clicked >= this->vscroll->GetCount()) break;
|
||||
int num_clicked = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget, 0, this->line_height);
|
||||
if (num_clicked == INT_MAX) break;
|
||||
const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked);
|
||||
if (as->IsAvailable()) this->SelectOtherAirport(num_clicked);
|
||||
break;
|
||||
|
@@ -193,10 +193,10 @@ class ReplaceVehicleWindow : public Window {
|
||||
|
||||
this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore)
|
||||
if (draw_left) {
|
||||
EngList_Sort(&list, &EngineNumberSorter);
|
||||
EngList_Sort(list, &EngineNumberSorter);
|
||||
} else {
|
||||
_engine_sort_direction = this->descending_sort_order;
|
||||
EngList_Sort(&list, _engine_sort_functions[this->window_number][this->sort_criteria]);
|
||||
EngList_Sort(list, _engine_sort_functions[this->window_number][this->sort_criteria]);
|
||||
}
|
||||
|
||||
this->engines[side].clear();
|
||||
@@ -617,12 +617,11 @@ public:
|
||||
} else {
|
||||
click_side = 1;
|
||||
}
|
||||
uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget);
|
||||
size_t engine_count = this->engines[click_side].size();
|
||||
|
||||
EngineID e = INVALID_ENGINE;
|
||||
if (i < engine_count) {
|
||||
const auto &item = this->engines[click_side][i];
|
||||
const auto it = this->vscroll[click_side]->GetScrolledItemFromWidget(this->engines[click_side], pt.y, this, widget);
|
||||
if (it != this->engines[click_side].end()) {
|
||||
const auto &item = *it;
|
||||
const Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL);
|
||||
if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) {
|
||||
/* toggle folded flag on engine */
|
||||
|
@@ -33,7 +33,7 @@ struct BaseConsist {
|
||||
|
||||
uint32 vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
|
||||
|
||||
virtual ~BaseConsist() {}
|
||||
virtual ~BaseConsist() = default;
|
||||
|
||||
void CopyConsistPropertiesFrom(const BaseConsist *src);
|
||||
};
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#define BASE_MEDIA_BASE_H
|
||||
|
||||
#include "fileio_func.h"
|
||||
#include "core/smallmap_type.hpp"
|
||||
#include "gfx_type.h"
|
||||
#include "textfile_type.h"
|
||||
#include "textfile_gui.h"
|
||||
|
@@ -29,7 +29,7 @@
|
||||
/** Base methods for 32bpp SSE blitters. */
|
||||
class Blitter_32bppSSE_Base {
|
||||
public:
|
||||
virtual ~Blitter_32bppSSE_Base() {}
|
||||
virtual ~Blitter_32bppSSE_Base() = default;
|
||||
|
||||
struct MapValue {
|
||||
uint8 m;
|
||||
|
@@ -273,7 +273,7 @@ public:
|
||||
*/
|
||||
virtual void PostResize() { };
|
||||
|
||||
virtual ~Blitter() { }
|
||||
virtual ~Blitter() = default;
|
||||
|
||||
template <typename SetPixelT> void DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel);
|
||||
};
|
||||
|
@@ -100,7 +100,8 @@ public:
|
||||
{
|
||||
if (widget == WID_BEM_MESSAGE) {
|
||||
*size = GetStringBoundingBox(STR_MISSING_GRAPHICS_ERROR);
|
||||
size->height = GetStringHeight(STR_MISSING_GRAPHICS_ERROR, size->width - WidgetDimensions::scaled.frametext.Horizontal()) + WidgetDimensions::scaled.frametext.Vertical();
|
||||
size->width += WidgetDimensions::scaled.frametext.Horizontal();
|
||||
size->height += WidgetDimensions::scaled.frametext.Vertical();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -277,9 +277,9 @@ public:
|
||||
switch (widget) {
|
||||
default: break;
|
||||
case WID_BBS_BRIDGE_LIST: {
|
||||
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BBS_BRIDGE_LIST);
|
||||
if (i < this->bridges->size()) {
|
||||
this->BuildBridge(i);
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(*this->bridges, pt.y, this, WID_BBS_BRIDGE_LIST);
|
||||
if (it != this->bridges->end()) {
|
||||
this->BuildBridge(it - this->bridges->begin());
|
||||
delete this;
|
||||
}
|
||||
break;
|
||||
|
@@ -41,6 +41,8 @@
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
/**
|
||||
@@ -1702,14 +1704,14 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
|
||||
|
||||
/* make engines first, and then wagons, sorted by selected sort_criteria */
|
||||
_engine_sort_direction = false;
|
||||
EngList_Sort(&list, TrainEnginesThenWagonsSorter);
|
||||
EngList_Sort(list, TrainEnginesThenWagonsSorter);
|
||||
|
||||
/* and then sort engines */
|
||||
_engine_sort_direction = this->descending_sort_order;
|
||||
EngList_SortPartial(&list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines);
|
||||
EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines);
|
||||
|
||||
/* and finally sort wagons */
|
||||
EngList_SortPartial(&list, _engine_sort_functions[0][this->sort_criteria], num_engines, list.size() - num_engines);
|
||||
EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], num_engines, list.size() - num_engines);
|
||||
}
|
||||
|
||||
/* Figure out what road vehicle EngineIDs to put in the list */
|
||||
@@ -1833,7 +1835,7 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
|
||||
}
|
||||
|
||||
_engine_sort_direction = this->descending_sort_order;
|
||||
EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
|
||||
EngList_Sort(this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
|
||||
|
||||
this->eng_list.swap(list);
|
||||
AddChildren(this->eng_list, list, INVALID_ENGINE, 0);
|
||||
@@ -1860,11 +1862,10 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
|
||||
break;
|
||||
|
||||
case WID_BV_LIST: {
|
||||
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST);
|
||||
size_t num_items = this->eng_list.size();
|
||||
EngineID e = INVALID_ENGINE;
|
||||
if (i < num_items) {
|
||||
const auto &item = this->eng_list[i];
|
||||
const auto it = this->vscroll->GetScrolledItemFromWidget(this->eng_list, pt.y, this, WID_BV_LIST);
|
||||
if (it != this->eng_list.end()) {
|
||||
const auto &item = *it;
|
||||
const Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL);
|
||||
if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) {
|
||||
/* toggle folded flag on engine */
|
||||
@@ -2637,7 +2638,7 @@ struct BuildVehicleWindowTrainAdvanced final : BuildVehicleWindowBase {
|
||||
|
||||
/* Sort */
|
||||
_engine_sort_direction = state.descending_sort_order;
|
||||
EngList_Sort(&list, sorters[state.sort_criteria]);
|
||||
EngList_Sort(list, sorters[state.sort_criteria]);
|
||||
}
|
||||
|
||||
/* Generate the list of vehicles */
|
||||
|
@@ -759,9 +759,9 @@ private:
|
||||
return r < 0;
|
||||
}
|
||||
|
||||
void AddChildren(GUIGroupList *source, GroupID parent, int indent)
|
||||
void AddChildren(GUIGroupList &source, GroupID parent, int indent)
|
||||
{
|
||||
for (const Group *g : *source) {
|
||||
for (const Group *g : source) {
|
||||
if (g->parent != parent) continue;
|
||||
this->groups.push_back(g);
|
||||
this->indents.push_back(indent);
|
||||
@@ -793,7 +793,7 @@ private:
|
||||
|
||||
list.Sort(&GroupNameSorter);
|
||||
|
||||
AddChildren(&list, INVALID_GROUP, 0);
|
||||
AddChildren(list, INVALID_GROUP, 0);
|
||||
}
|
||||
|
||||
this->groups.shrink_to_fit();
|
||||
|
@@ -3351,8 +3351,8 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
||||
IConsoleHelp(" Select one or more GRFs for profiling.");
|
||||
IConsoleHelp("Usage: newgrf_profile unselect <grf-num>...");
|
||||
IConsoleHelp(" Unselect one or more GRFs from profiling. Use the keyword \"all\" instead of a GRF number to unselect all. Removing an active profiler aborts data collection.");
|
||||
IConsoleHelp("Usage: newgrf_profile start [<num-days>]");
|
||||
IConsoleHelp(" Begin profiling all selected GRFs. If a number of days is provided, profiling stops after that many in-game days.");
|
||||
IConsoleHelp("Usage: 'newgrf_profile start [<num-ticks>]':");
|
||||
IConsoleHelp(" Begin profiling all selected GRFs. If a number of ticks is provided, profiling stops after that many game ticks. There are 74 ticks in a calendar day.");
|
||||
IConsoleHelp("Usage: newgrf_profile stop");
|
||||
IConsoleHelp(" End profiling and write the collected data to CSV files.");
|
||||
IConsoleHelp("Usage: newgrf_profile abort");
|
||||
@@ -3433,15 +3433,9 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
||||
if (started > 0) {
|
||||
IConsolePrintF(CC_DEBUG, "Started profiling for GRFID%s %s", (started > 1) ? "s" : "", grfids.c_str());
|
||||
if (argc >= 3) {
|
||||
int days = std::max(atoi(argv[2]), 1);
|
||||
_newgrf_profile_end_date = _date + days;
|
||||
|
||||
char datestrbuf[32]{ 0 };
|
||||
SetDParam(0, _newgrf_profile_end_date);
|
||||
GetString(datestrbuf, STR_JUST_DATE_ISO, lastof(datestrbuf));
|
||||
IConsolePrintF(CC_DEBUG, "Profiling will automatically stop on game date %s", datestrbuf);
|
||||
} else {
|
||||
_newgrf_profile_end_date = MAX_DAY;
|
||||
uint64 ticks = std::max(atoi(argv[2]), 1);
|
||||
NewGRFProfiler::StartTimer(ticks);
|
||||
IConsolePrintF(CC_DEBUG, "Profiling will automatically stop after %u ticks.", (uint)ticks);
|
||||
}
|
||||
} else if (_newgrf_profilers.empty()) {
|
||||
IConsolePrintF(CC_WARNING, "No GRFs selected for profiling, did not start.");
|
||||
@@ -3462,7 +3456,7 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
||||
for (NewGRFProfiler &pr : _newgrf_profilers) {
|
||||
pr.Abort();
|
||||
}
|
||||
_newgrf_profile_end_date = MAX_DAY;
|
||||
NewGRFProfiler::AbortTimer();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -29,7 +29,6 @@ add_files(
|
||||
random_func.hpp
|
||||
serialisation.cpp
|
||||
serialisation.hpp
|
||||
smallmap_type.hpp
|
||||
smallstack_type.hpp
|
||||
smallvec_type.hpp
|
||||
tinystring_type.hpp
|
||||
|
@@ -86,7 +86,7 @@ class ZeroedMemoryAllocator
|
||||
{
|
||||
public:
|
||||
ZeroedMemoryAllocator() {}
|
||||
virtual ~ZeroedMemoryAllocator() {}
|
||||
virtual ~ZeroedMemoryAllocator() = default;
|
||||
|
||||
/**
|
||||
* Memory allocator for a single class instance.
|
||||
|
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file smallmap_type.hpp Simple mapping class targeted for small sets of data. Stored data shall be POD ("Plain Old Data")! */
|
||||
|
||||
#ifndef SMALLMAP_TYPE_HPP
|
||||
#define SMALLMAP_TYPE_HPP
|
||||
|
||||
#include "smallvec_type.hpp"
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* Implementation of simple mapping class.
|
||||
* It has inherited accessors from std::vector().
|
||||
* @tparam T Key type.
|
||||
* @tparam U Value type.
|
||||
* @tparam S Unit of allocation.
|
||||
*
|
||||
* @see std::vector
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
struct SmallMap : std::vector<std::pair<T, U> > {
|
||||
typedef std::pair<T, U> Pair;
|
||||
typedef Pair *iterator;
|
||||
typedef const Pair *const_iterator;
|
||||
|
||||
/** Creates new SmallMap. Data are initialized in std::vector constructor */
|
||||
inline SmallMap() { }
|
||||
/** Data are freed in std::vector destructor */
|
||||
inline ~SmallMap() { }
|
||||
|
||||
/**
|
||||
* Finds given key in this map
|
||||
* @param key key to find
|
||||
* @return &Pair(key, data) if found, this->End() if not
|
||||
*/
|
||||
inline typename std::vector<Pair>::const_iterator Find(const T &key) const
|
||||
{
|
||||
return std::find_if(std::vector<Pair>::begin(), std::vector<Pair>::end(), [&key](const Pair &pair) { return key == pair.first; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds given key in this map
|
||||
* @param key key to find
|
||||
* @return &Pair(key, data) if found, this->End() if not
|
||||
*/
|
||||
inline Pair *Find(const T &key)
|
||||
{
|
||||
for (uint i = 0; i < std::vector<Pair>::size(); i++) {
|
||||
if (key == std::vector<Pair>::operator[](i).first) return &std::vector<Pair>::operator[](i);
|
||||
}
|
||||
return this->End();
|
||||
}
|
||||
|
||||
inline const Pair *End() const
|
||||
{
|
||||
return std::vector<Pair>::data() + std::vector<Pair>::size();
|
||||
}
|
||||
|
||||
inline Pair *End()
|
||||
{
|
||||
return std::vector<Pair>::data() + std::vector<Pair>::size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether a key is assigned in this map.
|
||||
* @param key key to test
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &key) const
|
||||
{
|
||||
return this->Find(key) != std::vector<Pair>::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a key is assigned in this map.
|
||||
* @param key key to test
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &key)
|
||||
{
|
||||
return this->Find(key) != this->End();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given pair from this map
|
||||
* @param pair pair to remove
|
||||
* @note it has to be pointer to pair in this map. It is overwritten by the last item.
|
||||
*/
|
||||
inline void Erase(Pair *pair)
|
||||
{
|
||||
assert(pair >= std::vector<Pair>::data() && pair < this->End());
|
||||
auto distance = pair - std::vector<Pair>::data();
|
||||
std::vector<Pair>::erase(std::vector<Pair>::begin() + distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given key from this map
|
||||
* @param key key to remove
|
||||
* @return true iff the key was found
|
||||
* @note last item is moved to its place, so don't increase your iterator if true is returned!
|
||||
*/
|
||||
inline bool Erase(const T &key)
|
||||
{
|
||||
Pair *pair = this->Find(key);
|
||||
if (pair == this->End()) return false;
|
||||
|
||||
this->Erase(pair);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new item to this map.
|
||||
* @param key key
|
||||
* @param data data
|
||||
* @return true iff the key wasn't already present
|
||||
*/
|
||||
inline bool Insert(const T &key, const U &data)
|
||||
{
|
||||
if (this->Contains(key)) return false;
|
||||
std::vector<Pair>::emplace_back(key, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data belonging to this key
|
||||
* @param key key
|
||||
* @return data belonging to this key
|
||||
* @note if this key wasn't present, new entry is created
|
||||
*/
|
||||
inline U &operator[](const T &key)
|
||||
{
|
||||
for (uint i = 0; i < std::vector<Pair>::size(); i++) {
|
||||
if (key == std::vector<Pair>::operator[](i).first) return std::vector<Pair>::operator[](i).second;
|
||||
}
|
||||
Pair &n = std::vector<Pair>::emplace_back();
|
||||
n.first = key;
|
||||
return n.second;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SMALLMAP_TYPE_HPP */
|
@@ -24,6 +24,7 @@
|
||||
#include "screenshot.h"
|
||||
#include "gfx_func.h"
|
||||
#include "network/network.h"
|
||||
#include "network/network_survey.h"
|
||||
#include "language.h"
|
||||
#include "fontcache.h"
|
||||
#include "news_gui.h"
|
||||
@@ -308,12 +309,12 @@ char *CrashLog::LogConfiguration(char *buffer, const char *last) const
|
||||
if (c->ai_info == nullptr) {
|
||||
buffer += seprintf(buffer, last, " %2i: Human\n", (int)c->index);
|
||||
} else {
|
||||
buffer += seprintf(buffer, last, " %2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
|
||||
buffer += seprintf(buffer, last, " %2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName().c_str(), c->ai_info->GetVersion());
|
||||
}
|
||||
}
|
||||
|
||||
if (Game::GetInfo() != nullptr) {
|
||||
buffer += seprintf(buffer, last, " GS: %s (v%d)\n", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion());
|
||||
buffer += seprintf(buffer, last, " GS: %s (v%d)\n", Game::GetInfo()->GetName().c_str(), Game::GetInfo()->GetVersion());
|
||||
}
|
||||
buffer += seprintf(buffer, last, "\n");
|
||||
|
||||
@@ -1173,6 +1174,10 @@ bool CrashLog::MakeCrashSavegameAndScreenshot() const
|
||||
printf("Writing crash screenshot failed.\n\n");
|
||||
}
|
||||
|
||||
if (_game_mode == GM_NORMAL) {
|
||||
_survey.Transmit(NetworkSurveyHandler::Reason::CRASH, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -161,7 +161,7 @@ public:
|
||||
const char *crash_buffer_write = nullptr;
|
||||
|
||||
/** Stub destructor to silence some compilers. */
|
||||
virtual ~CrashLog() {}
|
||||
virtual ~CrashLog() = default;
|
||||
|
||||
char *FillCrashLog(char *buffer, const char *last);
|
||||
void FlushCrashLogBuffer();
|
||||
|
@@ -322,10 +322,6 @@ static void OnNewDay()
|
||||
SetWindowDirty(WC_STATUS_BAR, 0);
|
||||
}
|
||||
|
||||
if (!_newgrf_profilers.empty() && _newgrf_profile_end_date <= _date) {
|
||||
NewGRFProfiler::FinishAll();
|
||||
}
|
||||
|
||||
if (_network_server) NetworkServerDailyLoop();
|
||||
|
||||
DisasterDailyLoop();
|
||||
|
@@ -445,6 +445,8 @@ struct DepotWindow : Window {
|
||||
DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const
|
||||
{
|
||||
const NWidgetCore *matrix_widget = this->GetWidget<NWidgetCore>(WID_D_MATRIX);
|
||||
/* Make X relative to widget. Y is left alone for GetScrolledRowFromWidget(). */
|
||||
x -= matrix_widget->pos_x;
|
||||
/* In case of RTL the widgets are swapped as a whole */
|
||||
if (_current_text_dir == TD_RTL) x = matrix_widget->current_x - x;
|
||||
|
||||
@@ -456,12 +458,12 @@ struct DepotWindow : Window {
|
||||
xm = x % this->resize.step_width;
|
||||
if (xt >= this->num_columns) return MODE_ERROR;
|
||||
}
|
||||
ym = y % this->resize.step_height;
|
||||
ym = (y - matrix_widget->pos_y) % this->resize.step_height;
|
||||
|
||||
uint row = y / this->resize.step_height;
|
||||
if (row >= this->vscroll->GetCapacity()) return MODE_ERROR;
|
||||
int row = this->vscroll->GetScrolledRowFromWidget(y, this, WID_D_MATRIX);
|
||||
if (row == INT_MAX) return MODE_ERROR;
|
||||
|
||||
uint pos = ((row + this->vscroll->GetPosition()) * this->num_columns) + xt;
|
||||
uint pos = (row * this->num_columns) + xt;
|
||||
|
||||
if (this->vehicle_list.size() + this->wagon_list.size() <= pos) {
|
||||
/* Clicking on 'line' / 'block' without a vehicle */
|
||||
@@ -762,11 +764,9 @@ struct DepotWindow : Window {
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_D_MATRIX: { // List
|
||||
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_D_MATRIX);
|
||||
this->DepotClick(pt.x - nwi->pos_x, pt.y - nwi->pos_y);
|
||||
case WID_D_MATRIX: // List
|
||||
this->DepotClick(pt.x, pt.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_D_BUILD: // Build vehicle
|
||||
ResetObjectToPlace();
|
||||
@@ -849,8 +849,7 @@ struct DepotWindow : Window {
|
||||
|
||||
GetDepotVehiclePtData gdvp = { nullptr, nullptr };
|
||||
const Vehicle *v = nullptr;
|
||||
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_D_MATRIX);
|
||||
DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp);
|
||||
DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp);
|
||||
|
||||
if (this->type == VEH_TRAIN) v = gdvp.wagon;
|
||||
|
||||
@@ -1021,11 +1020,10 @@ struct DepotWindow : Window {
|
||||
return;
|
||||
}
|
||||
|
||||
NWidgetBase *matrix = this->GetWidget<NWidgetBase>(widget);
|
||||
const Vehicle *v = nullptr;
|
||||
GetDepotVehiclePtData gdvp = {nullptr, nullptr};
|
||||
|
||||
if (this->GetVehicleFromDepotWndPt(pt.x - matrix->pos_x, pt.y - matrix->pos_y, &v, &gdvp) != MODE_DRAG_VEHICLE) return;
|
||||
if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) != MODE_DRAG_VEHICLE) return;
|
||||
|
||||
VehicleID new_vehicle_over = INVALID_VEHICLE;
|
||||
if (gdvp.head != nullptr) {
|
||||
@@ -1058,11 +1056,10 @@ struct DepotWindow : Window {
|
||||
this->sel = INVALID_VEHICLE;
|
||||
this->SetDirty();
|
||||
|
||||
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_D_MATRIX);
|
||||
if (this->type == VEH_TRAIN) {
|
||||
GetDepotVehiclePtData gdvp = { nullptr, nullptr };
|
||||
|
||||
if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) {
|
||||
if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) {
|
||||
if (gdvp.wagon != nullptr && gdvp.wagon->index == sel && _ctrl_pressed) {
|
||||
DoCommandP(Vehicle::Get(sel)->tile, Vehicle::Get(sel)->index, true,
|
||||
CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE));
|
||||
@@ -1073,7 +1070,7 @@ struct DepotWindow : Window {
|
||||
ShowVehicleViewWindow(gdvp.head);
|
||||
}
|
||||
}
|
||||
} else if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, nullptr) == MODE_DRAG_VEHICLE && v != nullptr && sel == v->index) {
|
||||
} else if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, nullptr) == MODE_DRAG_VEHICLE && v != nullptr && sel == v->index) {
|
||||
ShowVehicleViewWindow(v);
|
||||
}
|
||||
break;
|
||||
|
@@ -33,7 +33,7 @@ public:
|
||||
*/
|
||||
virtual void Stop() = 0;
|
||||
|
||||
virtual ~Driver() { }
|
||||
virtual ~Driver() = default;
|
||||
|
||||
/** The type of driver */
|
||||
enum Type {
|
||||
|
@@ -323,10 +323,10 @@ void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID eng
|
||||
* @param el list to be sorted
|
||||
* @param compare function for evaluation of the quicksort
|
||||
*/
|
||||
void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare)
|
||||
void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare)
|
||||
{
|
||||
if (el->size() < 2) return;
|
||||
std::sort(el->begin(), el->end(), compare);
|
||||
if (el.size() < 2) return;
|
||||
std::sort(el.begin(), el.end(), compare);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,11 +336,11 @@ void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare)
|
||||
* @param begin start of sorting
|
||||
* @param num_items count of items to be sorted
|
||||
*/
|
||||
void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, size_t begin, size_t num_items)
|
||||
void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, size_t begin, size_t num_items)
|
||||
{
|
||||
if (num_items < 2) return;
|
||||
assert(begin < el->size());
|
||||
assert(begin + num_items <= el->size());
|
||||
std::sort(el->begin() + begin, el->begin() + begin + num_items, compare);
|
||||
assert(begin < el.size());
|
||||
assert(begin + num_items <= el.size());
|
||||
std::sort(el.begin() + begin, el.begin() + begin + num_items, compare);
|
||||
}
|
||||
|
||||
|
@@ -32,8 +32,8 @@ struct GUIEngineListItem {
|
||||
typedef GUIList<GUIEngineListItem, CargoID> GUIEngineList;
|
||||
|
||||
typedef bool EngList_SortTypeFunction(const GUIEngineListItem&, const GUIEngineListItem&); ///< argument type for #EngList_Sort.
|
||||
void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare);
|
||||
void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, size_t begin, size_t num_items);
|
||||
void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare);
|
||||
void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, size_t begin, size_t num_items);
|
||||
|
||||
StringID GetEngineCategoryName(EngineID engine);
|
||||
StringID GetEngineInfoString(EngineID engine);
|
||||
|
@@ -1259,7 +1259,7 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r
|
||||
* @return the number of found files, i.e. the number of times that
|
||||
* AddFile returned true.
|
||||
*/
|
||||
uint FileScanner::Scan(const char *extension, const char *directory, bool recursive)
|
||||
uint FileScanner::Scan(const char *extension, const std::string &directory, bool recursive)
|
||||
{
|
||||
std::string path(directory);
|
||||
AppendPathSeparator(path);
|
||||
|
@@ -41,10 +41,10 @@ protected:
|
||||
Subdirectory subdir; ///< The current sub directory we are searching through
|
||||
public:
|
||||
/** Destruct the proper one... */
|
||||
virtual ~FileScanner() {}
|
||||
virtual ~FileScanner() = default;
|
||||
|
||||
uint Scan(const char *extension, Subdirectory sd, bool tars = true, bool recursive = true);
|
||||
uint Scan(const char *extension, const char *directory, bool recursive = true);
|
||||
uint Scan(const char *extension, const std::string &directory, bool recursive = true);
|
||||
|
||||
/**
|
||||
* Add a file with the given filename.
|
||||
|
@@ -412,7 +412,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c
|
||||
/* Show files */
|
||||
FiosFileScanner scanner(fop, callback_proc, file_list);
|
||||
if (subdir == NO_DIRECTORY) {
|
||||
scanner.Scan(nullptr, _fios_path->c_str(), false);
|
||||
scanner.Scan(nullptr, *_fios_path, false);
|
||||
} else {
|
||||
scanner.Scan(nullptr, subdir, true, true);
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ enum SaveLoadInvalidateWindowData {
|
||||
SLIWD_FILTER_CHANGES, ///< The filename filter has changed (via the editbox)
|
||||
};
|
||||
|
||||
typedef SmallMap<uint, CompanyProperties *> CompanyPropertiesMap;
|
||||
using CompanyPropertiesMap = std::map<uint, std::unique_ptr<CompanyProperties>>;
|
||||
|
||||
/**
|
||||
* Container for loading in mode SL_LOAD_CHECK.
|
||||
|
@@ -55,9 +55,6 @@ void LoadCheckData::Clear()
|
||||
this->current_date = 0;
|
||||
this->settings = {};
|
||||
|
||||
for (auto &pair : this->companies) {
|
||||
delete pair.second;
|
||||
}
|
||||
companies.clear();
|
||||
|
||||
GamelogFree(this->gamelog_action, this->gamelog_actions);
|
||||
|
@@ -167,14 +167,14 @@ const Sprite *TrueTypeFontCache::GetGlyph(GlyphID key)
|
||||
|
||||
const void *TrueTypeFontCache::GetFontTable(uint32 tag, size_t &length)
|
||||
{
|
||||
const FontTable::iterator iter = this->font_tables.Find(tag);
|
||||
if (iter != this->font_tables.data() + this->font_tables.size()) {
|
||||
const auto iter = this->font_tables.find(tag);
|
||||
if (iter != this->font_tables.end()) {
|
||||
length = iter->second.first;
|
||||
return iter->second.second;
|
||||
}
|
||||
|
||||
const void *result = this->InternalGetFontTable(tag, length);
|
||||
|
||||
this->font_tables.Insert(tag, std::pair<size_t, const void *>(length, result));
|
||||
this->font_tables[tag] = std::pair<size_t, const void *>(length, result);
|
||||
return result;
|
||||
}
|
||||
|
@@ -10,8 +10,8 @@
|
||||
#ifndef TRUETYPEFONTCACHE_H
|
||||
#define TRUETYPEFONTCACHE_H
|
||||
|
||||
#include "../core/smallmap_type.hpp"
|
||||
#include "../fontcache.h"
|
||||
#include "../3rdparty/cpp-btree/btree_map.h"
|
||||
|
||||
|
||||
static const int MAX_FONT_SIZE = 72; ///< Maximum font size.
|
||||
@@ -28,7 +28,7 @@ protected:
|
||||
int req_size; ///< Requested font size.
|
||||
int used_size; ///< Used font size.
|
||||
|
||||
typedef SmallMap<uint32, std::pair<size_t, const void *> > FontTable; ///< Table with font table cache
|
||||
using FontTable = btree::btree_map<uint32_t, std::pair<size_t, const void *>>; ///< Table with font table cache
|
||||
FontTable font_tables; ///< Cached font tables.
|
||||
|
||||
/** Container for information about a glyph. */
|
||||
|
@@ -362,7 +362,7 @@ static const PerformanceElement DISPLAY_ORDER_PFE[PFE_MAX] = {
|
||||
static const char * GetAIName(int ai_index)
|
||||
{
|
||||
if (!Company::IsValidAiID(ai_index)) return "";
|
||||
return Company::Get(ai_index)->ai_info->GetName();
|
||||
return Company::Get(ai_index)->ai_info->GetName().c_str();
|
||||
}
|
||||
|
||||
/** @hideinitializer */
|
||||
|
@@ -91,9 +91,9 @@ public:
|
||||
/** Wrapper function for GameScanner::GetUniqueInfoList */
|
||||
static const ScriptInfoList *GetUniqueInfoList();
|
||||
/** Wrapper function for GameScannerInfo::FindInfo */
|
||||
static class GameInfo *FindInfo(const char *name, int version, bool force_exact_match);
|
||||
static class GameInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
/** Wrapper function for GameScanner::FindLibrary */
|
||||
static class GameLibrary *FindLibrary(const char *library, int version);
|
||||
static class GameLibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
/**
|
||||
* Get the current active instance.
|
||||
|
@@ -32,7 +32,7 @@ class GameInfo *GameConfig::GetInfo() const
|
||||
return static_cast<class GameInfo *>(ScriptConfig::GetInfo());
|
||||
}
|
||||
|
||||
ScriptInfo *GameConfig::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
ScriptInfo *GameConfig::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
return static_cast<ScriptInfo *>(Game::FindInfo(name, version, force_exact_match));
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ public:
|
||||
bool ResetInfo(bool force_exact_match);
|
||||
|
||||
protected:
|
||||
ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override;
|
||||
ScriptInfo *FindInfo(const std::string &name, int version, bool force_exact_match) override;
|
||||
};
|
||||
|
||||
#endif /* GAME_CONFIG_HPP */
|
||||
|
@@ -171,8 +171,8 @@
|
||||
* the GameConfig. If not, remove the Game from the list. */
|
||||
if (_settings_game.game_config != nullptr && _settings_game.game_config->HasScript()) {
|
||||
if (!_settings_game.game_config->ResetInfo(true)) {
|
||||
DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_game.game_config->GetName());
|
||||
_settings_game.game_config->Change(nullptr);
|
||||
DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_game.game_config->GetName().c_str());
|
||||
_settings_game.game_config->Change(std::nullopt);
|
||||
if (Game::instance != nullptr) {
|
||||
delete Game::instance;
|
||||
Game::instance = nullptr;
|
||||
@@ -184,8 +184,8 @@
|
||||
}
|
||||
if (_settings_newgame.game_config != nullptr && _settings_newgame.game_config->HasScript()) {
|
||||
if (!_settings_newgame.game_config->ResetInfo(false)) {
|
||||
DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_newgame.game_config->GetName());
|
||||
_settings_newgame.game_config->Change(nullptr);
|
||||
DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_newgame.game_config->GetName().c_str());
|
||||
_settings_newgame.game_config->Change(std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,12 +236,12 @@
|
||||
return Game::scanner_info->GetUniqueInfoList();
|
||||
}
|
||||
|
||||
/* static */ GameInfo *Game::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
/* static */ GameInfo *Game::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
return Game::scanner_info->FindInfo(name, version, force_exact_match);
|
||||
}
|
||||
|
||||
/* static */ GameLibrary *Game::FindLibrary(const char *library, int version)
|
||||
/* static */ GameLibrary *Game::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
return Game::scanner_library->FindLibrary(library, version);
|
||||
}
|
||||
|
@@ -246,7 +246,7 @@ struct GSConfigWindow : public Window {
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
if (widget >= WID_GSC_TEXTFILE && widget < WID_GSC_TEXTFILE + TFT_END) {
|
||||
if (widget >= WID_GSC_TEXTFILE && widget < WID_GSC_TEXTFILE + TFT_CONTENT_END) {
|
||||
if (GameConfig::GetConfig() == nullptr) return;
|
||||
|
||||
ShowScriptTextfileWindow((TextfileType)(widget - WID_GSC_TEXTFILE), (CompanyID)OWNER_DEITY);
|
||||
@@ -273,13 +273,13 @@ struct GSConfigWindow : public Window {
|
||||
break;
|
||||
|
||||
case WID_GSC_SETTINGS: {
|
||||
Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
|
||||
int num = (pt.y - r.top) / this->line_height + this->vscroll->GetPosition();
|
||||
if (num >= (int)this->visible_settings.size()) break;
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->visible_settings, pt.y, this, widget);
|
||||
if (it == this->visible_settings.end()) break;
|
||||
|
||||
const ScriptConfigItem &config_item = *this->visible_settings[num];
|
||||
const ScriptConfigItem &config_item = **it;
|
||||
if (!this->IsEditableItem(config_item)) return;
|
||||
|
||||
int num = it - this->visible_settings.begin();
|
||||
if (this->clicked_row != num) {
|
||||
this->DeleteChildWindows(WC_QUERY_STRING);
|
||||
HideDropDownMenu(this);
|
||||
@@ -289,6 +289,7 @@ struct GSConfigWindow : public Window {
|
||||
|
||||
bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0;
|
||||
|
||||
Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
|
||||
int x = pt.x - r.left;
|
||||
if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x;
|
||||
|
||||
@@ -413,7 +414,7 @@ struct GSConfigWindow : public Window {
|
||||
|
||||
this->SetWidgetDisabledState(WID_GSC_CHANGE, !UserIsAllowedToChangeGameScript() || !IsEditable());
|
||||
|
||||
for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) {
|
||||
for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
|
||||
this->SetWidgetDisabledState(WID_GSC_TEXTFILE + tft, GameConfig::GetConfig()->GetTextfile(tft, (CompanyID)OWNER_DEITY) == nullptr);
|
||||
}
|
||||
this->RebuildVisibleSettings();
|
||||
|
@@ -21,7 +21,7 @@
|
||||
* Check if the API version provided by the Game is supported.
|
||||
* @param api_version The API version as provided by the Game.
|
||||
*/
|
||||
static bool CheckAPIVersion(const char *api_version)
|
||||
static bool CheckAPIVersion(const std::string &api_version)
|
||||
{
|
||||
static const std::set<std::string> versions = { "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14" };
|
||||
return versions.find(api_version) != versions.end();
|
||||
@@ -60,22 +60,22 @@ template <> const char *GetClassName<GameInfo, ScriptType::GS>() { return "GSInf
|
||||
SQInteger res = ScriptInfo::Constructor(vm, info);
|
||||
if (res != 0) return res;
|
||||
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) {
|
||||
if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "MinVersionToLoad")) {
|
||||
if (!info->engine->CallIntegerMethod(info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
} else {
|
||||
info->min_loadable_version = info->GetVersion();
|
||||
}
|
||||
/* When there is an IsSelectable function, call it. */
|
||||
if (info->engine->MethodExists(*info->SQ_instance, "IsDeveloperOnly")) {
|
||||
if (!info->engine->CallBoolMethod(*info->SQ_instance, "IsDeveloperOnly", &info->is_developer_only, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info->engine->MethodExists(info->SQ_instance, "IsDeveloperOnly")) {
|
||||
if (!info->engine->CallBoolMethod(info->SQ_instance, "IsDeveloperOnly", &info->is_developer_only, MAX_GET_OPS)) return SQ_ERROR;
|
||||
} else {
|
||||
info->is_developer_only = false;
|
||||
}
|
||||
/* Try to get the API version the AI is written for. */
|
||||
if (!info->CheckMethod("GetAPIVersion")) return SQ_ERROR;
|
||||
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!CheckAPIVersion(info->api_version)) {
|
||||
DEBUG(script, 1, "Loading info.nut from (%s.%d): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion());
|
||||
DEBUG(script, 1, "Loading info.nut from (%s.%d): GetAPIVersion returned invalid version", info->GetName().c_str(), info->GetVersion());
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
@@ -88,16 +88,10 @@ template <> const char *GetClassName<GameInfo, ScriptType::GS>() { return "GSInf
|
||||
|
||||
GameInfo::GameInfo() :
|
||||
min_loadable_version(0),
|
||||
is_developer_only(false),
|
||||
api_version(nullptr)
|
||||
is_developer_only(false)
|
||||
{
|
||||
}
|
||||
|
||||
GameInfo::~GameInfo()
|
||||
{
|
||||
free(this->api_version);
|
||||
}
|
||||
|
||||
bool GameInfo::CanLoadFromVersion(int version) const
|
||||
{
|
||||
if (version == -1) return true;
|
||||
@@ -105,11 +99,6 @@ bool GameInfo::CanLoadFromVersion(int version) const
|
||||
}
|
||||
|
||||
|
||||
GameLibrary::~GameLibrary()
|
||||
{
|
||||
free(this->category);
|
||||
}
|
||||
|
||||
/* static */ void GameLibrary::RegisterAPI(Squirrel *engine)
|
||||
{
|
||||
/* Create the GameLibrary class, and add the RegisterLibrary function */
|
||||
@@ -130,7 +119,7 @@ GameLibrary::~GameLibrary()
|
||||
}
|
||||
|
||||
/* Cache the category */
|
||||
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
|
||||
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
|
||||
delete library;
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@
|
||||
class GameInfo : public ScriptInfo {
|
||||
public:
|
||||
GameInfo();
|
||||
~GameInfo();
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
@@ -36,21 +35,20 @@ public:
|
||||
/**
|
||||
* Get the API version this Game is written for.
|
||||
*/
|
||||
const char *GetAPIVersion() const { return this->api_version; }
|
||||
const std::string &GetAPIVersion() const { return this->api_version; }
|
||||
|
||||
bool IsDeveloperOnly() const override { return this->is_developer_only; }
|
||||
|
||||
private:
|
||||
int min_loadable_version; ///< The Game can load savegame data if the version is equal or greater than this.
|
||||
bool is_developer_only; ///< Is the script selectable by non-developers?
|
||||
const char *api_version; ///< API version used by this Game.
|
||||
std::string api_version; ///< API version used by this Game.
|
||||
};
|
||||
|
||||
/** All static information from an Game library like name, version, etc. */
|
||||
class GameLibrary : public ScriptInfo {
|
||||
public:
|
||||
GameLibrary() : ScriptInfo(), category(nullptr) {};
|
||||
~GameLibrary();
|
||||
GameLibrary() : ScriptInfo() {};
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
@@ -65,10 +63,10 @@ public:
|
||||
/**
|
||||
* Get the category this library is in.
|
||||
*/
|
||||
const char *GetCategory() const { return this->category; }
|
||||
const std::string &GetCategory() const { return this->category; }
|
||||
|
||||
private:
|
||||
const char *category; ///< The category this library is in.
|
||||
std::string category; ///< The category this library is in.
|
||||
};
|
||||
|
||||
#endif /* GAME_INFO_HPP */
|
||||
|
@@ -52,12 +52,12 @@ void GameInstance::RegisterAPI()
|
||||
if (!this->LoadCompatibilityScripts(this->versionAPI, GAME_DIR)) this->Died();
|
||||
}
|
||||
|
||||
int GameInstance::GetSetting(const char *name)
|
||||
int GameInstance::GetSetting(const std::string &name)
|
||||
{
|
||||
return GameConfig::GetConfig()->GetSetting(name);
|
||||
}
|
||||
|
||||
ScriptInfo *GameInstance::FindLibrary(const char *library, int version)
|
||||
ScriptInfo *GameInstance::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
return (ScriptInfo *)Game::FindLibrary(library, version);
|
||||
}
|
||||
@@ -72,7 +72,7 @@ void GameInstance::Died()
|
||||
if (info != nullptr) {
|
||||
ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING);
|
||||
|
||||
if (info->GetURL() != nullptr) {
|
||||
if (!info->GetURL().empty()) {
|
||||
ScriptLog::Info("Please report the error to the following URL:");
|
||||
ScriptLog::Info(info->GetURL());
|
||||
}
|
||||
|
@@ -23,8 +23,8 @@ public:
|
||||
*/
|
||||
void Initialize(class GameInfo *info);
|
||||
|
||||
int GetSetting(const char *name) override;
|
||||
ScriptInfo *FindLibrary(const char *library, int version) override;
|
||||
int GetSetting(const std::string &name) override;
|
||||
ScriptInfo *FindLibrary(const std::string &library, int version) override;
|
||||
|
||||
private:
|
||||
void RegisterAPI() override;
|
||||
|
@@ -33,10 +33,10 @@ void GameScannerInfo::RegisterAPI(class Squirrel *engine)
|
||||
GameInfo::RegisterAPI(engine);
|
||||
}
|
||||
|
||||
GameInfo *GameScannerInfo::FindInfo(const char *name, int version, bool force_exact_match)
|
||||
GameInfo *GameScannerInfo::FindInfo(const std::string &name, int version, bool force_exact_match)
|
||||
{
|
||||
if (this->info_list.size() == 0) return nullptr;
|
||||
if (name == nullptr) return nullptr;
|
||||
if (name.empty()) return nullptr;
|
||||
|
||||
if (version == -1) {
|
||||
/* We want to load the latest version of this Game script; so find it */
|
||||
@@ -86,7 +86,7 @@ void GameScannerLibrary::RegisterAPI(class Squirrel *engine)
|
||||
GameLibrary::RegisterAPI(engine);
|
||||
}
|
||||
|
||||
GameLibrary *GameScannerLibrary::FindLibrary(const char *library, int version)
|
||||
GameLibrary *GameScannerLibrary::FindLibrary(const std::string &library, int version)
|
||||
{
|
||||
/* Internally we store libraries as 'library.version' */
|
||||
std::string library_name = fmt::format("{}.{}", library, version);
|
||||
|
@@ -23,7 +23,7 @@ public:
|
||||
* @param force_exact_match Only match name+version, never latest.
|
||||
* @return nullptr if no match found, otherwise the game script that matched.
|
||||
*/
|
||||
class GameInfo *FindInfo(const char *name, int version, bool force_exact_match);
|
||||
class GameInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
|
||||
protected:
|
||||
std::string GetScriptName(ScriptInfo *info) override;
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
* @param version The version the library should have.
|
||||
* @return The library if found, nullptr otherwise.
|
||||
*/
|
||||
class GameLibrary *FindLibrary(const char *library, int version);
|
||||
class GameLibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
protected:
|
||||
std::string GetScriptName(ScriptInfo *info) override;
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "debug.h"
|
||||
#include "date_func.h"
|
||||
#include "rev.h"
|
||||
#include "3rdparty/cpp-btree/btree_map.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -160,7 +161,7 @@ struct GRFPresence{
|
||||
GRFPresence(const GRFConfig *gc) : gc(gc), was_missing(false) {}
|
||||
GRFPresence() = default;
|
||||
};
|
||||
typedef SmallMap<uint32, GRFPresence> GrfIDMapping;
|
||||
typedef btree::btree_map<uint32, GRFPresence> GrfIDMapping;
|
||||
|
||||
/**
|
||||
* Prints active gamelog
|
||||
@@ -249,25 +250,25 @@ void GamelogPrint(GamelogPrintProc *proc)
|
||||
const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum);
|
||||
buf += seprintf(buf, lastof(buffer), "Added NewGRF: ");
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfadd.grfid, lc->grfadd.md5sum, gc);
|
||||
GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
|
||||
if (gm != grf_names.End() && !gm->second.was_missing) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was already added!");
|
||||
auto gm = grf_names.find(lc->grfrem.grfid);
|
||||
if (gm != grf_names.end() && !gm->second.was_missing) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was already added!");
|
||||
grf_names[lc->grfadd.grfid] = gc;
|
||||
break;
|
||||
}
|
||||
|
||||
case GLCT_GRFREM: {
|
||||
/* A NewGRF got removed from the game, either manually or by it missing when loading the game. */
|
||||
GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
|
||||
auto gm = grf_names.find(lc->grfrem.grfid);
|
||||
buf += seprintf(buf, lastof(buffer), la->at == GLAT_LOAD ? "Missing NewGRF: " : "Removed NewGRF: ");
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfrem.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr);
|
||||
if (gm == grf_names.End()) {
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfrem.grfid, nullptr, gm != grf_names.end() ? gm->second.gc : nullptr);
|
||||
if (gm == grf_names.end()) {
|
||||
buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
} else {
|
||||
if (la->at == GLAT_LOAD) {
|
||||
/* Missing grfs on load are not removed from the configuration */
|
||||
gm->second.was_missing = true;
|
||||
} else {
|
||||
grf_names.Erase(gm);
|
||||
grf_names.erase(gm);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -278,38 +279,38 @@ void GamelogPrint(GamelogPrintProc *proc)
|
||||
const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum);
|
||||
buf += seprintf(buf, lastof(buffer), "Compatible NewGRF loaded: ");
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfcompat.grfid, lc->grfcompat.md5sum, gc);
|
||||
if (!grf_names.Contains(lc->grfcompat.grfid)) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
if (grf_names.find(lc->grfcompat.grfid) == grf_names.end()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
grf_names[lc->grfcompat.grfid] = gc;
|
||||
break;
|
||||
}
|
||||
|
||||
case GLCT_GRFPARAM: {
|
||||
/* A parameter of a NewGRF got changed after the game was started. */
|
||||
GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
|
||||
auto gm = grf_names.find(lc->grfrem.grfid);
|
||||
buf += seprintf(buf, lastof(buffer), "GRF parameter changed: ");
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfparam.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr);
|
||||
if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfparam.grfid, nullptr, gm != grf_names.end() ? gm->second.gc : nullptr);
|
||||
if (gm == grf_names.end()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
break;
|
||||
}
|
||||
|
||||
case GLCT_GRFMOVE: {
|
||||
/* The order of NewGRFs got changed, which might cause some other NewGRFs to behave differently. */
|
||||
GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
|
||||
auto gm = grf_names.find(lc->grfrem.grfid);
|
||||
buf += seprintf(buf, lastof(buffer), "GRF order changed: %08X moved %d places %s",
|
||||
BSWAP32(lc->grfmove.grfid), abs(lc->grfmove.offset), lc->grfmove.offset >= 0 ? "down" : "up" );
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfmove.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr);
|
||||
if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfmove.grfid, nullptr, gm != grf_names.end() ? gm->second.gc : nullptr);
|
||||
if (gm == grf_names.end()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
break;
|
||||
}
|
||||
|
||||
case GLCT_GRFBUG: {
|
||||
/* A specific bug in a NewGRF, that could cause wide spread problems, has been noted during the execution of the game. */
|
||||
GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
|
||||
auto gm = grf_names.find(lc->grfrem.grfid);
|
||||
assert (lc->grfbug.bug == GBUG_VEH_LENGTH);
|
||||
|
||||
buf += seprintf(buf, lastof(buffer), "Rail vehicle changes length outside a depot: GRF ID %08X, internal ID 0x%X", BSWAP32(lc->grfbug.grfid), (uint)lc->grfbug.data);
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfbug.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr);
|
||||
if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfbug.grfid, nullptr, gm != grf_names.end() ? gm->second.gc : nullptr);
|
||||
if (gm == grf_names.end()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -58,6 +58,7 @@ bool _check_special_modes;
|
||||
std::atomic<bool> _exit_game;
|
||||
GameMode _game_mode;
|
||||
SwitchMode _switch_mode; ///< The next mainloop command.
|
||||
std::chrono::steady_clock::time_point _switch_mode_time; ///< The time when the switch mode was requested.
|
||||
PauseMode _pause_mode;
|
||||
uint32 _pause_countdown;
|
||||
Palette _cur_palette;
|
||||
|
@@ -103,8 +103,8 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, std::string_view s
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fontMapping.Contains(buff - buff_begin)) {
|
||||
fontMapping.Insert(buff - buff_begin, f);
|
||||
if (fontMapping.count(buff - buff_begin) == 0) {
|
||||
fontMapping[buff - buff_begin] = f;
|
||||
}
|
||||
f = Layouter::GetFont(state.fontsize, state.cur_colour);
|
||||
}
|
||||
@@ -112,8 +112,8 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, std::string_view s
|
||||
/* Better safe than sorry. */
|
||||
*buff = '\0';
|
||||
|
||||
if (!fontMapping.Contains(buff - buff_begin)) {
|
||||
fontMapping.Insert(buff - buff_begin, f);
|
||||
if (fontMapping.count(buff - buff_begin) == 0) {
|
||||
fontMapping[buff - buff_begin] = f;
|
||||
}
|
||||
line.layout = T::GetParagraphLayout(buff_begin, buff, fontMapping);
|
||||
line.state_after = state;
|
||||
@@ -296,12 +296,11 @@ ptrdiff_t Layouter::GetCharAtPosition(int x) const
|
||||
*/
|
||||
Font *Layouter::GetFont(FontSize size, TextColour colour)
|
||||
{
|
||||
FontColourMap::iterator it = fonts[size].Find(colour);
|
||||
if (it != fonts[size].End()) return it->second;
|
||||
FontColourMap::iterator it = fonts[size].find(colour);
|
||||
if (it != fonts[size].end()) return it->second.get();
|
||||
|
||||
Font *f = new Font(size, colour);
|
||||
fonts[size].emplace_back(colour, f);
|
||||
return f;
|
||||
fonts[size][colour] = std::make_unique<Font>(size, colour);
|
||||
return fonts[size][colour].get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,9 +309,6 @@ Font *Layouter::GetFont(FontSize size, TextColour colour)
|
||||
*/
|
||||
void Layouter::ResetFontCache(FontSize size)
|
||||
{
|
||||
for (auto &pair : fonts[size]) {
|
||||
delete pair.second;
|
||||
}
|
||||
fonts[size].clear();
|
||||
|
||||
/* We must reset the linecache since it references the just freed fonts */
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "fontcache.h"
|
||||
#include "gfx_func.h"
|
||||
#include "core/smallmap_type.hpp"
|
||||
#include "core/math_func.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -84,20 +84,20 @@ public:
|
||||
Font(FontSize size, TextColour colour);
|
||||
};
|
||||
|
||||
/** Mapping from index to font. */
|
||||
typedef SmallMap<int, Font *> FontMap;
|
||||
/** Mapping from index to font. The pointer is owned by FontColourMap. */
|
||||
using FontMap = std::map<int, Font *>;
|
||||
|
||||
/**
|
||||
* Interface to glue fallback and normal layouter into one.
|
||||
*/
|
||||
class ParagraphLayouter {
|
||||
public:
|
||||
virtual ~ParagraphLayouter() {}
|
||||
virtual ~ParagraphLayouter() = default;
|
||||
|
||||
/** Visual run contains data about the bit of text with the same font. */
|
||||
class VisualRun {
|
||||
public:
|
||||
virtual ~VisualRun() {}
|
||||
virtual ~VisualRun() = default;
|
||||
virtual const Font *GetFont() const = 0;
|
||||
virtual int GetGlyphCount() const = 0;
|
||||
virtual const GlyphID *GetGlyphs() const = 0;
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
/** A single line worth of VisualRuns. */
|
||||
class Line {
|
||||
public:
|
||||
virtual ~Line() {}
|
||||
virtual ~Line() = default;
|
||||
virtual int GetLeading() const = 0;
|
||||
virtual int GetWidth() const = 0;
|
||||
virtual int CountRuns() const = 0;
|
||||
@@ -173,7 +173,7 @@ private:
|
||||
|
||||
static LineCacheItem &GetCachedParagraphLayout(std::string_view str, const FontState &state);
|
||||
|
||||
typedef SmallMap<TextColour, Font *> FontColourMap;
|
||||
using FontColourMap = std::map<TextColour, std::unique_ptr<Font>>;
|
||||
static FontColourMap fonts[FS_END];
|
||||
public:
|
||||
static Font *GetFont(FontSize size, TextColour colour);
|
||||
|
@@ -266,7 +266,7 @@ const ParagraphLayouter::VisualRun &FallbackParagraphLayout::FallbackLine::GetVi
|
||||
*/
|
||||
FallbackParagraphLayout::FallbackParagraphLayout(WChar *buffer, int length, FontMap &runs) : buffer_begin(buffer), buffer(buffer), runs(runs)
|
||||
{
|
||||
assert(runs.End()[-1].first == length);
|
||||
assert(runs.rbegin()->first == length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,15 +295,15 @@ std::unique_ptr<const ParagraphLayouter::Line> FallbackParagraphLayout::NextLine
|
||||
if (*this->buffer == '\0') {
|
||||
/* Only a newline. */
|
||||
this->buffer = nullptr;
|
||||
l->emplace_back(this->runs.front().second, this->buffer, 0, 0);
|
||||
l->emplace_back(this->runs.begin()->second, this->buffer, 0, 0);
|
||||
return l;
|
||||
}
|
||||
|
||||
int offset = this->buffer - this->buffer_begin;
|
||||
FontMap::iterator iter = this->runs.data();
|
||||
FontMap::iterator iter = this->runs.begin();
|
||||
while (iter->first <= offset) {
|
||||
iter++;
|
||||
assert(iter != this->runs.End());
|
||||
++iter;
|
||||
assert(iter != this->runs.end());
|
||||
}
|
||||
|
||||
const FontCache *fc = iter->second->fc;
|
||||
@@ -325,8 +325,8 @@ std::unique_ptr<const ParagraphLayouter::Line> FallbackParagraphLayout::NextLine
|
||||
if (this->buffer == next_run) {
|
||||
int w = l->GetWidth();
|
||||
l->emplace_back(iter->second, begin, this->buffer - begin, w);
|
||||
iter++;
|
||||
assert(iter != this->runs.End());
|
||||
++iter;
|
||||
assert(iter != this->runs.end());
|
||||
|
||||
next_run = this->buffer_begin + iter->first;
|
||||
begin = this->buffer;
|
||||
|
@@ -1349,13 +1349,9 @@ struct PaymentRatesGraphWindow : BaseGraphWindow {
|
||||
}
|
||||
|
||||
case WID_CPR_MATRIX: {
|
||||
uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX);
|
||||
if (row >= this->vscroll->GetCount()) return;
|
||||
|
||||
for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
|
||||
if (row-- > 0) continue;
|
||||
|
||||
ToggleBit(_legend_excluded_cargo, cs->Index());
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(_sorted_standard_cargo_specs, pt.y, this, WID_CPR_MATRIX);
|
||||
if (it != _sorted_standard_cargo_specs.end()) {
|
||||
ToggleBit(_legend_excluded_cargo, (*it)->Index());
|
||||
this->UpdateExcludedData();
|
||||
this->UpdateCargoExcludingGraphs();
|
||||
break;
|
||||
|
@@ -172,17 +172,15 @@ private:
|
||||
Money money_last_year;
|
||||
uint32 occupancy_ratio;
|
||||
|
||||
/** return true if group has children */
|
||||
void AddChildren(GUIGroupList *source, GroupID parent, int indent)
|
||||
void AddChildren(GUIGroupList &source, GroupID parent, int indent)
|
||||
{
|
||||
for (const Group *g : *source) {
|
||||
for (const Group *g : source) {
|
||||
if (g->parent != parent) continue;
|
||||
this->groups.push_back(g);
|
||||
this->indents.push_back(indent);
|
||||
if (g->folded) {
|
||||
/* Test if this group has children at all. If not, the folded flag should be cleared to avoid lingering unfold buttons in the list. */
|
||||
auto child = std::find_if(source->begin(), source->end(), [g](const Group *child){ return child->parent == g->index; });
|
||||
bool has_children = child != source->end();
|
||||
bool has_children = std::any_of(source.begin(), source.end(), [g](const Group *child){ return child->parent == g->index; });
|
||||
Group::Get(g->index)->folded = has_children;
|
||||
} else {
|
||||
AddChildren(source, g->index, indent + 1);
|
||||
@@ -230,7 +228,7 @@ private:
|
||||
|
||||
list.Sort(&GroupNameSorter);
|
||||
|
||||
AddChildren(&list, INVALID_GROUP, 0);
|
||||
AddChildren(list, INVALID_GROUP, 0);
|
||||
|
||||
this->groups.shrink_to_fit();
|
||||
this->groups.RebuildDone();
|
||||
@@ -761,10 +759,11 @@ public:
|
||||
break;
|
||||
|
||||
case WID_GL_LIST_GROUP: { // Matrix Group
|
||||
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
|
||||
if (id_g >= this->groups.size()) return;
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
if (it == this->groups.end()) return;
|
||||
|
||||
if (groups[id_g]->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) {
|
||||
size_t id_g = it - this->groups.begin();
|
||||
if ((*it)->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) {
|
||||
/* The group has children, check if the user clicked the fold / unfold button. */
|
||||
NWidgetCore *group_display = this->GetWidget<NWidgetCore>(widget);
|
||||
int x = _current_text_dir == TD_RTL ?
|
||||
@@ -801,10 +800,10 @@ public:
|
||||
}
|
||||
|
||||
case WID_GL_LIST_VEHICLE: { // Matrix Vehicle
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE);
|
||||
if (id_v >= this->vehgroups.size()) return; // click out of list bound
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
|
||||
if (it == this->vehgroups.end()) return; // click out of list bound
|
||||
|
||||
const GUIVehicleGroup &vehgroup = this->vehgroups[id_v];
|
||||
const GUIVehicleGroup &vehgroup = *it;
|
||||
|
||||
const Vehicle *v = nullptr;
|
||||
|
||||
@@ -937,8 +936,8 @@ public:
|
||||
break;
|
||||
|
||||
case WID_GL_LIST_GROUP: { // Matrix group
|
||||
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = id_g >= this->groups.size() ? INVALID_GROUP : this->groups[id_g]->index;
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = it == this->groups.end() ? INVALID_GROUP : (*it)->index;
|
||||
|
||||
if (this->group_sel != new_g && g->parent != new_g) {
|
||||
DoCommandP(0, this->group_sel | (1 << 16), new_g, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_SET_PARENT));
|
||||
@@ -970,8 +969,8 @@ public:
|
||||
this->group_over = INVALID_GROUP;
|
||||
this->SetDirty();
|
||||
|
||||
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index;
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = it == this->groups.end() ? NEW_GROUP : (*it)->index;
|
||||
|
||||
DoCommandP(0, new_g, vindex | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr);
|
||||
break;
|
||||
@@ -983,10 +982,10 @@ public:
|
||||
this->group_over = INVALID_GROUP;
|
||||
this->SetDirty();
|
||||
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE);
|
||||
if (id_v >= this->vehgroups.size()) return; // click out of list bound
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
|
||||
if (it == this->vehgroups.end()) return; // click out of list bound
|
||||
|
||||
const GUIVehicleGroup &vehgroup = this->vehgroups[id_v];
|
||||
const GUIVehicleGroup &vehgroup = *it;
|
||||
switch (this->grouping) {
|
||||
case GB_NONE: {
|
||||
const Vehicle *v = vehgroup.GetSingleVehicle();
|
||||
@@ -1171,8 +1170,8 @@ public:
|
||||
break;
|
||||
|
||||
case WID_GL_LIST_GROUP: { // ... the list of custom groups.
|
||||
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
|
||||
new_group_over = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index;
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
new_group_over = it == this->groups.end() ? NEW_GROUP : (*it)->index;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -170,53 +170,41 @@ static void ParseHotkeys(Hotkey *hotkey, const char *value)
|
||||
* by a '+'.
|
||||
* @param keycode The keycode to convert to a string.
|
||||
* @return A string representation of this keycode.
|
||||
* @note The return value is a static buffer, stredup the result before calling
|
||||
* this function again.
|
||||
*/
|
||||
static const char *KeycodeToString(uint16 keycode)
|
||||
static std::string KeycodeToString(uint16 keycode)
|
||||
{
|
||||
static char buf[32];
|
||||
buf[0] = '\0';
|
||||
bool first = true;
|
||||
std::string str;
|
||||
if (keycode & WKC_GLOBAL_HOTKEY) {
|
||||
strecat(buf, "GLOBAL", lastof(buf));
|
||||
first = false;
|
||||
str += "GLOBAL";
|
||||
}
|
||||
if (keycode & WKC_SHIFT) {
|
||||
if (!first) strecat(buf, "+", lastof(buf));
|
||||
strecat(buf, "SHIFT", lastof(buf));
|
||||
first = false;
|
||||
if (!str.empty()) str += "+";
|
||||
str += "SHIFT";
|
||||
}
|
||||
if (keycode & WKC_CTRL) {
|
||||
if (!first) strecat(buf, "+", lastof(buf));
|
||||
strecat(buf, "CTRL", lastof(buf));
|
||||
first = false;
|
||||
if (!str.empty()) str += "+";
|
||||
str += "CTRL";
|
||||
}
|
||||
if (keycode & WKC_ALT) {
|
||||
if (!first) strecat(buf, "+", lastof(buf));
|
||||
strecat(buf, "ALT", lastof(buf));
|
||||
first = false;
|
||||
if (!str.empty()) str += "+";
|
||||
str += "ALT";
|
||||
}
|
||||
if (keycode & WKC_META) {
|
||||
if (!first) strecat(buf, "+", lastof(buf));
|
||||
strecat(buf, "META", lastof(buf));
|
||||
first = false;
|
||||
if (!str.empty()) str += "+";
|
||||
str += "META";
|
||||
}
|
||||
if (!first) strecat(buf, "+", lastof(buf));
|
||||
if (!str.empty()) str += "+";
|
||||
keycode = keycode & ~WKC_SPECIAL_KEYS;
|
||||
|
||||
for (uint i = 0; i < lengthof(_keycode_to_name); i++) {
|
||||
if (_keycode_to_name[i].keycode == keycode) {
|
||||
strecat(buf, _keycode_to_name[i].name, lastof(buf));
|
||||
return buf;
|
||||
str += _keycode_to_name[i].name;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
assert(keycode < 128);
|
||||
char key[2];
|
||||
key[0] = keycode;
|
||||
key[1] = '\0';
|
||||
strecat(buf, key, lastof(buf));
|
||||
return buf;
|
||||
str.push_back(keycode);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,19 +212,15 @@ static const char *KeycodeToString(uint16 keycode)
|
||||
* keycodes are attached to the hotkey they are split by a comma.
|
||||
* @param hotkey The keycodes of this hotkey need to be converted to a string.
|
||||
* @return A string representation of all keycodes.
|
||||
* @note The return value is a static buffer, stredup the result before calling
|
||||
* this function again.
|
||||
*/
|
||||
const char *SaveKeycodes(const Hotkey *hotkey)
|
||||
std::string SaveKeycodes(const Hotkey *hotkey)
|
||||
{
|
||||
static char buf[128];
|
||||
buf[0] = '\0';
|
||||
std::string str;
|
||||
for (uint i = 0; i < hotkey->keycodes.size(); i++) {
|
||||
const char *str = KeycodeToString(hotkey->keycodes[i]);
|
||||
if (i > 0) strecat(buf, ",", lastof(buf));
|
||||
strecat(buf, str, lastof(buf));
|
||||
if (i > 0) str += ",";
|
||||
str += KeycodeToString(hotkey->keycodes[i]);
|
||||
}
|
||||
return buf;
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -652,9 +652,9 @@ public:
|
||||
}
|
||||
|
||||
case WID_DPI_MATRIX_WIDGET: {
|
||||
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_DPI_MATRIX_WIDGET);
|
||||
if (y != INT_MAX) { // Is it within the boundaries of available data?
|
||||
this->selected_type = this->list[y];
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->list, pt.y, this, WID_DPI_MATRIX_WIDGET);
|
||||
if (it != this->list.end()) { // Is it within the boundaries of available data?
|
||||
this->selected_type = *it;
|
||||
this->UpdateAvailability();
|
||||
|
||||
const IndustrySpec *indsp = GetIndustrySpec(this->selected_type);
|
||||
@@ -1764,12 +1764,12 @@ public:
|
||||
break;
|
||||
|
||||
case WID_ID_INDUSTRY_LIST: {
|
||||
uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WidgetDimensions::scaled.framerect.top);
|
||||
if (p < this->industries.size()) {
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->industries, pt.y, this, WID_ID_INDUSTRY_LIST, WidgetDimensions::scaled.framerect.top);
|
||||
if (it != this->industries.end()) {
|
||||
if (_ctrl_pressed) {
|
||||
ShowExtraViewportWindow(this->industries[p]->location.tile);
|
||||
ShowExtraViewportWindow((*it)->location.tile);
|
||||
} else {
|
||||
ScrollMainWindowToTile(this->industries[p]->location.tile);
|
||||
ScrollMainWindowToTile((*it)->location.tile);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@@ -14,8 +14,6 @@
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include <string>
|
||||
|
||||
/** Types of groups */
|
||||
enum IniGroupType {
|
||||
IGT_VARIABLES = 0, ///< Values of the form "landscape = hilly".
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "genworld.h"
|
||||
#include "network/network_gui.h"
|
||||
#include "network/network_content.h"
|
||||
#include "network/network_survey.h"
|
||||
#include "landscape_type.h"
|
||||
#include "landscape.h"
|
||||
#include "strings_func.h"
|
||||
@@ -504,7 +505,10 @@ void ShowSelectGameWindow()
|
||||
|
||||
static void AskExitGameCallback(Window *w, bool confirmed)
|
||||
{
|
||||
if (confirmed) _exit_game = true;
|
||||
if (confirmed) {
|
||||
_survey.Transmit(NetworkSurveyHandler::Reason::EXIT, true);
|
||||
_exit_game = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AskExitGame()
|
||||
|
@@ -40,7 +40,7 @@ public:
|
||||
/**
|
||||
* Virtual destructor has to be defined because of virtual Run().
|
||||
*/
|
||||
virtual ~DemandHandler() {}
|
||||
virtual ~DemandHandler() = default;
|
||||
};
|
||||
|
||||
#endif /* DEMANDS_H */
|
||||
|
@@ -30,10 +30,6 @@ public:
|
||||
FlowMapper(bool scale) : scale(scale) {}
|
||||
virtual void Run(LinkGraphJob &job) const;
|
||||
|
||||
/**
|
||||
* Virtual destructor has to be defined because of virtual Run().
|
||||
*/
|
||||
virtual ~FlowMapper() {}
|
||||
private:
|
||||
|
||||
/**
|
||||
|
@@ -17,11 +17,6 @@ public:
|
||||
* @param job Job to be initialized.
|
||||
*/
|
||||
virtual void Run(LinkGraphJob &job) const { job.Init(); }
|
||||
|
||||
/**
|
||||
* Virtual destructor has to be defined because of virtual Run().
|
||||
*/
|
||||
virtual ~InitHandler() {}
|
||||
};
|
||||
|
||||
#endif /* INIT_H */
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#define LINKGRAPH_H
|
||||
|
||||
#include "../core/pool_type.hpp"
|
||||
#include "../core/smallmap_type.hpp"
|
||||
#include "../core/bitmath_func.hpp"
|
||||
#include "../station_base.h"
|
||||
#include "../cargotype.h"
|
||||
|
@@ -29,7 +29,7 @@ public:
|
||||
/**
|
||||
* Destroy the handler. Must be given due to virtual Run.
|
||||
*/
|
||||
virtual ~ComponentHandler() {}
|
||||
virtual ~ComponentHandler() = default;
|
||||
|
||||
/**
|
||||
* Run the handler. A link graph handler must not read or write any data
|
||||
|
@@ -82,11 +82,6 @@ public:
|
||||
* @param graph Component to be calculated.
|
||||
*/
|
||||
virtual void Run(LinkGraphJob &job) const { Tpass pass(job); }
|
||||
|
||||
/**
|
||||
* Destructor. Has to be given because of virtual Run().
|
||||
*/
|
||||
virtual ~MCFHandler() {}
|
||||
};
|
||||
|
||||
#endif /* MCF_H */
|
||||
|
32
src/misc.cpp
32
src/misc.cpp
@@ -39,9 +39,11 @@
|
||||
#include "cargopacket.h"
|
||||
#include "tbtr_template_vehicle_func.h"
|
||||
#include "event_logs.h"
|
||||
#include "3rdparty/monocypher/monocypher.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
std::string _savegame_id; ///< Unique ID of the current savegame.
|
||||
|
||||
extern TileIndex _cur_tileloop_tile;
|
||||
extern TileIndex _aux_tileloop_tile;
|
||||
@@ -66,6 +68,36 @@ void InitializeCheats();
|
||||
void InitializeNPF();
|
||||
void InitializeOldNames();
|
||||
|
||||
/**
|
||||
* Generate a unique ID.
|
||||
*/
|
||||
std::string GenerateUid(std::string_view subject)
|
||||
{
|
||||
extern void NetworkRandomBytesWithFallback(void *buf, size_t n);
|
||||
extern std::string BytesToHexString(const byte *data, uint length);
|
||||
|
||||
uint8 random_bytes[32];
|
||||
NetworkRandomBytesWithFallback(random_bytes, lengthof(random_bytes));
|
||||
|
||||
uint8 digest[16];
|
||||
|
||||
crypto_blake2b_ctx ctx;
|
||||
crypto_blake2b_init (&ctx, lengthof(digest));
|
||||
crypto_blake2b_update(&ctx, random_bytes, lengthof(random_bytes));
|
||||
crypto_blake2b_update(&ctx, (const byte *)subject.data(), subject.size());
|
||||
crypto_blake2b_final (&ctx, digest);
|
||||
|
||||
return BytesToHexString(digest, lengthof(digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique savegame ID.
|
||||
*/
|
||||
void GenerateSavegameId()
|
||||
{
|
||||
_savegame_id = GenerateUid("OpenTTD Savegame ID");
|
||||
}
|
||||
|
||||
void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings)
|
||||
{
|
||||
/* Make sure there isn't any window that can influence anything
|
||||
|
@@ -28,6 +28,8 @@ add_files(
|
||||
network_server.h
|
||||
network_stun.cpp
|
||||
network_stun.h
|
||||
network_survey.cpp
|
||||
network_survey.h
|
||||
network_turn.cpp
|
||||
network_turn.h
|
||||
network_type.h
|
||||
|
@@ -282,7 +282,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
* of course totally unneeded ;) */
|
||||
if (sockets != nullptr) {
|
||||
NetworkAddress address(runp->ai_addr, (int)runp->ai_addrlen);
|
||||
if (sockets->Contains(address)) continue;
|
||||
if (std::any_of(sockets->begin(), sockets->end(), [&address](const auto &p) { return p.second == address; })) continue;
|
||||
}
|
||||
sock = func(runp);
|
||||
if (sock == INVALID_SOCKET) continue;
|
||||
@@ -307,7 +307,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
}
|
||||
|
||||
NetworkAddress addr(runp->ai_addr, (int)runp->ai_addrlen);
|
||||
(*sockets)[addr] = sock;
|
||||
(*sockets)[sock] = addr;
|
||||
sock = INVALID_SOCKET;
|
||||
}
|
||||
freeaddrinfo (ai);
|
||||
|
@@ -14,13 +14,13 @@
|
||||
#include "config.h"
|
||||
#include "../../company_type.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../core/smallmap_type.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class NetworkAddress;
|
||||
typedef std::vector<NetworkAddress> NetworkAddressList; ///< Type for a list of addresses.
|
||||
typedef SmallMap<NetworkAddress, SOCKET> SocketList; ///< Type for a mapping between address and socket.
|
||||
using SocketList = std::map<SOCKET, NetworkAddress>; ///< Type for a mapping between address and socket.
|
||||
|
||||
/**
|
||||
* Wrapper for (un)resolved network addresses; there's no reason to transform
|
||||
|
@@ -67,3 +67,13 @@ const char *NetworkContentMirrorUriString()
|
||||
{
|
||||
return GetEnv("OTTD_CONTENT_MIRROR_URI", "https://binaries.openttd.org/bananas");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI string for the survey from the environment variable OTTD_SURVEY_URI,
|
||||
* or when it has not been set a hard coded URI of the production server.
|
||||
* @return The survey's URI string.
|
||||
*/
|
||||
const char *NetworkSurveyUriString()
|
||||
{
|
||||
return GetEnv("OTTD_SURVEY_URI", "https://survey-participate.openttd.org/");
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ const char *NetworkCoordinatorConnectionString();
|
||||
const char *NetworkStunConnectionString();
|
||||
const char *NetworkContentServerConnectionString();
|
||||
const char *NetworkContentMirrorUriString();
|
||||
const char *NetworkSurveyUriString();
|
||||
|
||||
static const uint16 NETWORK_COORDINATOR_SERVER_PORT = 3976; ///< The default port of the Game Coordinator server (TCP)
|
||||
static const uint16 NETWORK_STUN_SERVER_PORT = 3975; ///< The default port of the STUN server (TCP)
|
||||
@@ -27,6 +28,8 @@ static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The d
|
||||
|
||||
static const uint16 UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet
|
||||
static const uint16 UDP_MTU_SHORT = 1400; ///< Number of bytes we can pack in a single UDP packet (conservative)
|
||||
|
||||
static const std::string NETWORK_SURVEY_DETAILS_LINK = "https://survey.openttd.org/participate"; ///< Link with more details & privacy statement of the survey.
|
||||
/*
|
||||
* Technically a TCP packet could become 64kiB, however the high bit is kept so it becomes possible in the future
|
||||
* to go to (significantly) larger packets if needed. This would entail a strategy such as employed for UTF-8.
|
||||
@@ -47,6 +50,7 @@ static const uint16 COMPAT_MTU = 1460; ///< Numbe
|
||||
static const byte NETWORK_GAME_ADMIN_VERSION = 3; ///< What version of the admin network do we use?
|
||||
static const byte NETWORK_GAME_INFO_VERSION = 6; ///< What version of game-info do we use?
|
||||
static const byte NETWORK_COORDINATOR_VERSION = 6; ///< What version of game-coordinator-protocol do we use?
|
||||
static const byte NETWORK_SURVEY_VERSION = 1; ///< What version of the survey do we use?
|
||||
|
||||
static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0'
|
||||
static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0'
|
||||
|
@@ -48,7 +48,7 @@ public:
|
||||
NetworkSocketHandler() { this->has_quit = false; }
|
||||
|
||||
/** Close the socket when destructing the socket handler */
|
||||
virtual ~NetworkSocketHandler() {}
|
||||
virtual ~NetworkSocketHandler() = default;
|
||||
|
||||
/**
|
||||
* Mark the connection as closed.
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../core/alloc_func.hpp"
|
||||
#include "address.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "tcp.h"
|
||||
|
||||
constexpr int HTTP_429_TOO_MANY_REQUESTS = 429;
|
||||
|
||||
/** Callback for when the HTTP handler has something to tell us. */
|
||||
struct HTTPCallback {
|
||||
/**
|
||||
@@ -40,7 +42,7 @@ struct HTTPCallback {
|
||||
virtual bool IsCancelled() const = 0;
|
||||
|
||||
/** Silentium */
|
||||
virtual ~HTTPCallback() {}
|
||||
virtual ~HTTPCallback() = default;
|
||||
};
|
||||
|
||||
/** Base socket handler for HTTP traffic. */
|
||||
|
@@ -117,6 +117,7 @@ void HttpThread()
|
||||
|
||||
/* Reset to default settings. */
|
||||
curl_easy_reset(curl);
|
||||
curl_slist *headers = nullptr;
|
||||
|
||||
if (_debug_net_level >= 5) {
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
@@ -147,8 +148,16 @@ void HttpThread()
|
||||
|
||||
/* Prepare POST body and URI. */
|
||||
if (!request->data.empty()) {
|
||||
/* When the payload starts with a '{', it is a JSON payload. */
|
||||
if (StrStartsWith(request->data, "{")) {
|
||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||
} else {
|
||||
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request->data.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_URL, request->uri.c_str());
|
||||
|
||||
@@ -175,11 +184,17 @@ void HttpThread()
|
||||
/* Perform the request. */
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
|
||||
if (res == CURLE_OK) {
|
||||
Debug(net, 1, "HTTP request succeeded");
|
||||
request->callback->OnReceiveData(nullptr, 0);
|
||||
} else {
|
||||
Debug(net, (request->callback->IsCancelled() || _http_thread_exit) ? 1 : 0, "HTTP request failed: {}", curl_easy_strerror(res));
|
||||
long status_code = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);
|
||||
|
||||
/* No need to be verbose about rate limiting. */
|
||||
Debug(net, (request->callback->IsCancelled() || _http_thread_exit || status_code == HTTP_429_TOO_MANY_REQUESTS) ? 1 : 0, "HTTP request failed: status_code: {}, error: {}", status_code, curl_easy_strerror(res));
|
||||
request->callback->OnFailure();
|
||||
}
|
||||
}
|
||||
|
@@ -131,7 +131,8 @@ void NetworkHTTPRequest::WinHttpCallback(DWORD code, void *info, DWORD length)
|
||||
|
||||
/* If there is any error, we simply abort the request. */
|
||||
if (status_code >= 400) {
|
||||
Debug(net, 0, "HTTP request failed: status-code {}", status_code);
|
||||
/* No need to be verbose about rate limiting. */
|
||||
Debug(net, status_code == HTTP_429_TOO_MANY_REQUESTS ? 1 : 0, "HTTP request failed: status-code {}", status_code);
|
||||
this->finished = true;
|
||||
this->callback->OnFailure();
|
||||
return;
|
||||
@@ -242,7 +243,9 @@ void NetworkHTTPRequest::Connect()
|
||||
if (data.empty()) {
|
||||
WinHttpSendRequest(this->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, reinterpret_cast<DWORD_PTR>(this));
|
||||
} else {
|
||||
WinHttpSendRequest(this->request, L"Content-Type: application/x-www-form-urlencoded\r\n", -1, const_cast<char *>(data.c_str()), static_cast<DWORD>(data.size()), static_cast<DWORD>(data.size()), reinterpret_cast<DWORD_PTR>(this));
|
||||
/* When the payload starts with a '{', it is a JSON payload. */
|
||||
LPCWSTR content_type = StrStartsWith(data, "{") ? L"Content-Type: application/json\r\n" : L"Content-Type: application/x-www-form-urlencoded\r\n";
|
||||
WinHttpSendRequest(this->request, content_type, -1, const_cast<char *>(data.c_str()), static_cast<DWORD>(data.size()), static_cast<DWORD>(data.size()), reinterpret_cast<DWORD_PTR>(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -565,7 +565,7 @@ public:
|
||||
* @param status The reason the connection got closed.
|
||||
*/
|
||||
virtual NetworkRecvStatus CloseConnection(NetworkRecvStatus status) = 0;
|
||||
virtual ~NetworkGameSocketHandler() {}
|
||||
virtual ~NetworkGameSocketHandler() = default;
|
||||
|
||||
/**
|
||||
* Sets the client info for this socket handler.
|
||||
|
@@ -114,7 +114,7 @@ public:
|
||||
|
||||
/* take care of listener port */
|
||||
for (auto &s : sockets) {
|
||||
FD_SET(s.second, &read_fd);
|
||||
FD_SET(s.first, &read_fd);
|
||||
}
|
||||
|
||||
tv.tv_sec = tv.tv_usec = 0; // don't block at all.
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
|
||||
/* accept clients.. */
|
||||
for (auto &s : sockets) {
|
||||
if (FD_ISSET(s.second, &read_fd)) AcceptClient(s.second);
|
||||
if (FD_ISSET(s.first, &read_fd)) AcceptClient(s.first);
|
||||
}
|
||||
|
||||
/* read stuff from clients */
|
||||
@@ -164,7 +164,7 @@ public:
|
||||
static void CloseListeners()
|
||||
{
|
||||
for (auto &s : sockets) {
|
||||
closesocket(s.second);
|
||||
closesocket(s.first);
|
||||
}
|
||||
sockets.clear();
|
||||
DEBUG(net, 5, "[%s] Closed listeners", Tsocket::GetName());
|
||||
|
@@ -61,7 +61,7 @@ bool NetworkUDPSocketHandler::Listen()
|
||||
void NetworkUDPSocketHandler::CloseSocket()
|
||||
{
|
||||
for (auto &s : this->sockets) {
|
||||
closesocket(s.second);
|
||||
closesocket(s.first);
|
||||
}
|
||||
this->sockets.clear();
|
||||
}
|
||||
@@ -113,20 +113,20 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a
|
||||
NetworkAddress send(*recv);
|
||||
|
||||
/* Not the same type */
|
||||
if (!send.IsFamily(s.first.GetAddress()->ss_family)) continue;
|
||||
if (!send.IsFamily(s.second.GetAddress()->ss_family)) continue;
|
||||
|
||||
p->PrepareToSend();
|
||||
|
||||
if (broadcast) {
|
||||
/* Enable broadcast */
|
||||
unsigned long val = 1;
|
||||
if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
|
||||
if (setsockopt(s.first, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
|
||||
DEBUG(net, 1, "Setting broadcast mode failed: %s", NetworkError::GetLast().AsString());
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the buffer */
|
||||
ssize_t res = p->TransferOut<int>(sendto, s.second, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
|
||||
ssize_t res = p->TransferOut<int>(sendto, s.first, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
|
||||
DEBUG(net, 7, "sendto(%s)", NetworkAddressDumper().GetAddressAsString(&send));
|
||||
|
||||
/* Check for any errors, but ignore it otherwise */
|
||||
@@ -151,8 +151,8 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
||||
socklen_t client_len = sizeof(client_addr);
|
||||
|
||||
/* Try to receive anything */
|
||||
SetNonBlocking(s.second); // Some OSes seem to lose the non-blocking status of the socket
|
||||
ssize_t nbytes = p.TransferIn<int>(recvfrom, s.second, 0, (struct sockaddr *)&client_addr, &client_len);
|
||||
SetNonBlocking(s.first); // Some OSes seem to lose the non-blocking status of the socket
|
||||
ssize_t nbytes = p.TransferIn<int>(recvfrom, s.first, 0, (struct sockaddr *)&client_addr, &client_len);
|
||||
|
||||
/* Did we get the bytes for the base header of the packet? */
|
||||
if (nbytes <= 0) break; // No data, i.e. no packet
|
||||
|
@@ -102,6 +102,8 @@ static_assert((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS
|
||||
/** The amount of clients connected */
|
||||
byte _network_clients_connected = 0;
|
||||
|
||||
extern std::string GenerateUid(std::string_view subject);
|
||||
|
||||
/**
|
||||
* Return whether there is any client connected or trying to connect at all.
|
||||
* @return whether we have any client activity
|
||||
@@ -1298,24 +1300,7 @@ void NetworkGameLoop()
|
||||
|
||||
static void NetworkGenerateServerId()
|
||||
{
|
||||
Md5 checksum;
|
||||
uint8 digest[16];
|
||||
char hex_output[16 * 2 + 1];
|
||||
char coding_string[NETWORK_NAME_LENGTH];
|
||||
int di;
|
||||
|
||||
seprintf(coding_string, lastof(coding_string), "%d%s", (uint)Random(), "OpenTTD Server ID");
|
||||
|
||||
/* Generate the MD5 hash */
|
||||
checksum.Append((const uint8*)coding_string, strlen(coding_string));
|
||||
checksum.Finish(digest);
|
||||
|
||||
for (di = 0; di < 16; ++di) {
|
||||
seprintf(hex_output + di * 2, lastof(hex_output), "%02x", digest[di]);
|
||||
}
|
||||
|
||||
/* _settings_client.network.network_id is our id */
|
||||
_settings_client.network.network_id = hex_output;
|
||||
_settings_client.network.network_id = GenerateUid("OpenTTD Server ID");
|
||||
}
|
||||
|
||||
std::string BytesToHexString(const byte *data, uint length)
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "network.h"
|
||||
#include "network_client.h"
|
||||
#include "network_base.h"
|
||||
#include "../3rdparty/fmt/format.h"
|
||||
|
||||
#include "../widgets/network_chat_widget.h"
|
||||
|
||||
@@ -28,6 +29,7 @@
|
||||
|
||||
#include <stdarg.h> /* va_list */
|
||||
#include <deque>
|
||||
#include <optional>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -326,18 +328,16 @@ struct NetworkChatWindow : public Window {
|
||||
* Find the next item of the list of things that can be auto-completed.
|
||||
* @param item The current indexed item to return. This function can, and most
|
||||
* likely will, alter item, to skip empty items in the arrays.
|
||||
* @return Returns the char that matched to the index.
|
||||
* @return Returns the view that matched to the index.
|
||||
*/
|
||||
const char *ChatTabCompletionNextItem(uint *item)
|
||||
std::optional<std::string> ChatTabCompletionNextItem(uint *item)
|
||||
{
|
||||
static char chat_tab_temp_buffer[64];
|
||||
|
||||
/* First, try clients */
|
||||
if (*item < MAX_CLIENT_SLOTS) {
|
||||
/* Skip inactive clients */
|
||||
for (NetworkClientInfo *ci : NetworkClientInfo::Iterate(*item)) {
|
||||
*item = ci->index;
|
||||
return ci->client_name.c_str();
|
||||
return ci->client_name;
|
||||
}
|
||||
*item = MAX_CLIENT_SLOTS;
|
||||
}
|
||||
@@ -349,12 +349,11 @@ struct NetworkChatWindow : public Window {
|
||||
for (const Town *t : Town::Iterate(*item - MAX_CLIENT_SLOTS)) {
|
||||
/* Get the town-name via the string-system */
|
||||
SetDParam(0, t->index);
|
||||
GetString(chat_tab_temp_buffer, STR_TOWN_NAME, lastof(chat_tab_temp_buffer));
|
||||
return &chat_tab_temp_buffer[0];
|
||||
return GetString(STR_TOWN_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,13 +361,14 @@ struct NetworkChatWindow : public Window {
|
||||
* the word right from that as to complete. It also writes a \0 at the
|
||||
* position of the space (if any). If nothing found, buf is returned.
|
||||
*/
|
||||
static char *ChatTabCompletionFindText(char *buf)
|
||||
static std::string_view ChatTabCompletionFindText(std::string_view &buf)
|
||||
{
|
||||
char *p = strrchr(buf, ' ');
|
||||
if (p == nullptr) return buf;
|
||||
auto it = buf.find_last_of(' ');
|
||||
if (it == std::string_view::npos) return buf;
|
||||
|
||||
*p = '\0';
|
||||
return p + 1;
|
||||
std::string_view res = buf.substr(it + 1);
|
||||
buf.remove_suffix(res.size() + 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,46 +376,44 @@ struct NetworkChatWindow : public Window {
|
||||
*/
|
||||
void ChatTabCompletion()
|
||||
{
|
||||
static char _chat_tab_completion_buf[NETWORK_CHAT_LENGTH];
|
||||
assert(this->message_editbox.text.max_bytes == lengthof(_chat_tab_completion_buf));
|
||||
static std::string _chat_tab_completion_buf;
|
||||
|
||||
Textbuf *tb = &this->message_editbox.text;
|
||||
size_t len, tb_len;
|
||||
uint item;
|
||||
char *tb_buf, *pre_buf;
|
||||
const char *cur_name;
|
||||
uint item = 0;
|
||||
bool second_scan = false;
|
||||
|
||||
item = 0;
|
||||
/* Create views, so we do not need to copy the data for now. */
|
||||
std::string_view pre_buf = _chat_tab_completion_active ? std::string_view(_chat_tab_completion_buf) : std::string_view(tb->buf);
|
||||
std::string_view tb_buf = ChatTabCompletionFindText(pre_buf);
|
||||
|
||||
/* Copy the buffer so we can modify it without damaging the real data */
|
||||
pre_buf = (_chat_tab_completion_active) ? stredup(_chat_tab_completion_buf) : stredup(tb->buf);
|
||||
/*
|
||||
* Comparing pointers of the data, as both "Hi:<tab>" and "Hi: Hi:<tab>" will result in
|
||||
* tb_buf and pre_buf being "Hi:", which would be equal in content but not in context.
|
||||
*/
|
||||
bool begin_of_line = tb_buf.data() == pre_buf.data();
|
||||
|
||||
tb_buf = ChatTabCompletionFindText(pre_buf);
|
||||
tb_len = strlen(tb_buf);
|
||||
|
||||
while ((cur_name = ChatTabCompletionNextItem(&item)) != nullptr) {
|
||||
std::optional<std::string> cur_item;
|
||||
while ((cur_item = ChatTabCompletionNextItem(&item)).has_value()) {
|
||||
std::string_view cur_name = cur_item.value();
|
||||
item++;
|
||||
|
||||
if (_chat_tab_completion_active) {
|
||||
/* We are pressing TAB again on the same name, is there another name
|
||||
* that starts with this? */
|
||||
if (!second_scan) {
|
||||
size_t offset;
|
||||
size_t length;
|
||||
std::string_view view;
|
||||
|
||||
/* If we are completing at the begin of the line, skip the ': ' we added */
|
||||
if (tb_buf == pre_buf) {
|
||||
offset = 0;
|
||||
length = (tb->bytes - 1) - 2;
|
||||
if (begin_of_line) {
|
||||
view = std::string_view(tb->buf, (tb->bytes - 1) - 2);
|
||||
} else {
|
||||
/* Else, find the place we are completing at */
|
||||
offset = strlen(pre_buf) + 1;
|
||||
length = (tb->bytes - 1) - offset;
|
||||
size_t offset = pre_buf.size() + 1;
|
||||
view = std::string_view(tb->buf + offset, (tb->bytes - 1) - offset);
|
||||
}
|
||||
|
||||
/* Compare if we have a match */
|
||||
if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true;
|
||||
if (cur_name == view) second_scan = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -423,21 +421,19 @@ struct NetworkChatWindow : public Window {
|
||||
/* Now any match we make on _chat_tab_completion_buf after this, is perfect */
|
||||
}
|
||||
|
||||
len = strlen(cur_name);
|
||||
if (tb_len < len && StrStartsWith(cur_name, tb_buf)) {
|
||||
if (tb_buf.size() < cur_name.size() && StrStartsWith(cur_name, tb_buf)) {
|
||||
/* Save the data it was before completion */
|
||||
if (!second_scan) seprintf(_chat_tab_completion_buf, lastof(_chat_tab_completion_buf), "%s", tb->buf);
|
||||
if (!second_scan) _chat_tab_completion_buf = tb->buf;
|
||||
_chat_tab_completion_active = true;
|
||||
|
||||
/* Change to the found name. Add ': ' if we are at the start of the line (pretty) */
|
||||
if (pre_buf == tb_buf) {
|
||||
this->message_editbox.text.Print("%s: ", cur_name);
|
||||
if (begin_of_line) {
|
||||
this->message_editbox.text.Assign(fmt::format("{}: ", cur_name));
|
||||
} else {
|
||||
this->message_editbox.text.Print("%s %s", pre_buf, cur_name);
|
||||
this->message_editbox.text.Assign(fmt::format("{} {}", pre_buf, cur_name));
|
||||
}
|
||||
|
||||
this->SetDirty();
|
||||
free(pre_buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -449,7 +445,6 @@ struct NetworkChatWindow : public Window {
|
||||
|
||||
this->SetDirty();
|
||||
}
|
||||
free(pre_buf);
|
||||
}
|
||||
|
||||
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "../thread.h"
|
||||
#include "../crashlog.h"
|
||||
#include "../core/checksum_func.hpp"
|
||||
#include "../core/alloc_func.hpp"
|
||||
#include "../fileio_func.h"
|
||||
#include "../debug_settings.h"
|
||||
#include "../3rdparty/monocypher/monocypher.h"
|
||||
|
@@ -57,7 +57,7 @@ struct ContentCallback {
|
||||
virtual void OnDownloadComplete(ContentID cid) {}
|
||||
|
||||
/** Silentium */
|
||||
virtual ~ContentCallback() {}
|
||||
virtual ~ContentCallback() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -791,7 +791,7 @@ public:
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) {
|
||||
if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_CONTENT_END) {
|
||||
if (this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE) return;
|
||||
|
||||
ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected);
|
||||
@@ -800,11 +800,11 @@ public:
|
||||
|
||||
switch (widget) {
|
||||
case WID_NCL_MATRIX: {
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX);
|
||||
if (id_v >= this->content.size()) return; // click out of bounds
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->content, pt.y, this, WID_NCL_MATRIX);
|
||||
if (it == this->content.end()) return; // click out of bounds
|
||||
|
||||
this->selected = this->content[id_v];
|
||||
this->list_pos = id_v;
|
||||
this->selected = *it;
|
||||
this->list_pos = it - this->content.begin();
|
||||
|
||||
const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
|
||||
if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
|
||||
@@ -998,7 +998,7 @@ public:
|
||||
this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all);
|
||||
this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade);
|
||||
this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == nullptr || this->selected->url.empty());
|
||||
for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) {
|
||||
for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
|
||||
this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE || this->selected->GetTextfile(tft) == nullptr);
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user