Merge branch 'master' into jgrpp
# Conflicts: # .gitignore # CMakeLists.txt # src/3rdparty/optional/optional.hpp # src/group_cmd.cpp # src/industry_cmd.cpp # src/misc_gui.cpp # src/video/sdl2_v.cpp
This commit is contained in:
49
.github/workflows/ci-build.yml
vendored
49
.github/workflows/ci-build.yml
vendored
@@ -10,6 +10,55 @@ env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
|
||||
jobs:
|
||||
emscripten:
|
||||
name: Emscripten
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container:
|
||||
# If you change this version, change the number in the cache step too.
|
||||
image: emscripten/emsdk:2.0.10
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /emsdk/upstream/emscripten/cache
|
||||
key: 2.0.10-${{ runner.os }}
|
||||
|
||||
- name: Build (host tools)
|
||||
run: |
|
||||
mkdir build-host
|
||||
cd build-host
|
||||
|
||||
echo "::group::CMake"
|
||||
cmake .. -DOPTION_TOOLS_ONLY=ON
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build"
|
||||
echo "Running on $(nproc) cores"
|
||||
make -j$(nproc) tools
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Install GCC problem matcher
|
||||
uses: ammaraskar/gcc-problem-matcher@master
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
echo "::group::CMake"
|
||||
emcmake cmake .. -DHOST_BINARY_DIR=../build-host
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build"
|
||||
echo "Running on $(nproc) cores"
|
||||
emmake make -j$(nproc)
|
||||
echo "::endgroup::"
|
||||
|
||||
linux:
|
||||
name: Linux
|
||||
|
||||
|
133
.github/workflows/preview_build.yml
vendored
Normal file
133
.github/workflows/preview_build.yml
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
name: Preview build
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types:
|
||||
- Preview*
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
name: Build preview
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container:
|
||||
# If you change this version, change the number in the cache step too.
|
||||
image: emscripten/emsdk:2.0.10
|
||||
# uid=1001(runner) gid=121(docker)
|
||||
options: -u 1001:121
|
||||
|
||||
steps:
|
||||
- name: Update deployment status to in progress
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
|
||||
mediaType: |
|
||||
previews:
|
||||
- ant-man
|
||||
- flash
|
||||
owner: ${{ github.event.repository.owner.login }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
deployment_id: ${{ github.event.client_payload.deployment_id }}
|
||||
state: in_progress
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.client_payload.sha }}
|
||||
|
||||
- name: Name branch
|
||||
run: |
|
||||
name=$(echo "${{ github.event.client_payload.folder }}")
|
||||
git checkout -b ${name}
|
||||
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /emsdk/upstream/emscripten/cache
|
||||
key: 2.0.10-${{ runner.os }}
|
||||
|
||||
- name: Build (host tools)
|
||||
run: |
|
||||
mkdir build-host
|
||||
cd build-host
|
||||
|
||||
echo "::group::CMake"
|
||||
cmake .. -DOPTION_TOOLS_ONLY=ON
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build"
|
||||
echo "Running on $(nproc) cores"
|
||||
make -j$(nproc) tools
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Install GCC problem matcher
|
||||
uses: ammaraskar/gcc-problem-matcher@master
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
echo "::group::CMake"
|
||||
emcmake cmake .. \
|
||||
-DHOST_BINARY_DIR=../build-host \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
# EOF
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build"
|
||||
echo "Running on $(nproc) cores"
|
||||
emmake make -j$(nproc)
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Publish preview
|
||||
run: |
|
||||
# setuptools is missing in this Docker image, which breaks installing
|
||||
# awscli. So we need to do this in two steps to recover sanity.
|
||||
pip3 install setuptools
|
||||
pip3 install awscli
|
||||
|
||||
~/.local/bin/aws s3 cp --only-show-errors build/openttd.data s3://${{ secrets.PREVIEW_S3_BUCKET }}/${{ github.event.client_payload.folder }}/
|
||||
~/.local/bin/aws s3 cp --only-show-errors build/openttd.html s3://${{ secrets.PREVIEW_S3_BUCKET }}/${{ github.event.client_payload.folder }}/
|
||||
~/.local/bin/aws s3 cp --only-show-errors build/openttd.js s3://${{ secrets.PREVIEW_S3_BUCKET }}/${{ github.event.client_payload.folder }}/
|
||||
~/.local/bin/aws s3 cp --only-show-errors build/openttd.wasm s3://${{ secrets.PREVIEW_S3_BUCKET }}/${{ github.event.client_payload.folder }}/
|
||||
|
||||
# Invalidate the cache of the CloudFront distribution
|
||||
~/.local/bin/aws cloudfront create-invalidation --distribution-id ${{ secrets.PREVIEW_CF_DISTRIBUTION_ID }} --paths "/${{ github.event.client_payload.folder }}/*"
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
|
||||
- name: Update deployment status to success
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
|
||||
mediaType: |
|
||||
previews:
|
||||
- ant-man
|
||||
- flash
|
||||
owner: ${{ github.event.repository.owner.login }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
deployment_id: ${{ github.event.client_payload.deployment_id }}
|
||||
state: success
|
||||
environment_url: https://preview.openttd.org/${{ github.event.client_payload.folder }}/
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
|
||||
- if: failure()
|
||||
name: Update deployment status to failure
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
|
||||
mediaType: |
|
||||
previews:
|
||||
- ant-man
|
||||
- flash
|
||||
owner: ${{ github.event.repository.owner.login }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
deployment_id: ${{ github.event.client_payload.deployment_id }}
|
||||
state: failure
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
66
.github/workflows/preview_label.yml
vendored
Normal file
66
.github/workflows/preview_label.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
name: Preview label
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- labeled
|
||||
|
||||
env:
|
||||
TEAM_CORE_DEVELOPER: core-developers
|
||||
|
||||
jobs:
|
||||
check_preview_label:
|
||||
name: Check for preview label
|
||||
if: github.event.action == 'labeled' && github.event.label.name == 'preview'
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Check if label was added by core developer
|
||||
id: core_developer
|
||||
continue-on-error: true
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: GET /orgs/OpenTTD/teams/${{ env.TEAM_CORE_DEVELOPER }}/memberships/${{ github.event.sender.login }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
|
||||
- if: steps.core_developer.outcome == 'failure'
|
||||
name: Remove preview label if not core developer
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/preview
|
||||
owner: ${{ github.event.repository.owner.login }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
issue_number: ${{ github.event.number }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
|
||||
- if: steps.core_developer.outcome == 'success'
|
||||
name: Create deployment
|
||||
id: deployment
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: POST /repos/{owner}/{repo}/deployments
|
||||
mediaType: |
|
||||
previews:
|
||||
- ant-man
|
||||
- flash
|
||||
owner: ${{ github.event.repository.owner.login }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
task: deploy:preview
|
||||
auto_merge: false
|
||||
required_contexts: "[]"
|
||||
environment: preview-pr-${{ github.event.number }}
|
||||
description: "Preview for Pull Request #${{ github.event.number }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
|
||||
- if: steps.core_developer.outcome == 'success'
|
||||
name: Trigger 'preview build'
|
||||
uses: peter-evans/repository-dispatch@v1
|
||||
with:
|
||||
token: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
event-type: "Preview build #${{ github.event.number }}"
|
||||
client-payload: '{"folder": "pr${{ github.event.number }}", "sha": "${{ github.event.pull_request.head.sha }}", "deployment_id": "${{ fromJson(steps.deployment.outputs.data).id }}"}'
|
66
.github/workflows/preview_push.yml
vendored
Normal file
66
.github/workflows/preview_push.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
name: Preview push
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
check_new_preview:
|
||||
name: Check preview needs update
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Check if earlier preview exists
|
||||
id: earlier_preview
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: GET /repos/{owner}/{repo}/deployments
|
||||
owner: ${{ github.event.repository.owner.login }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
environment: preview-pr-${{ github.event.number }}
|
||||
per_page: 1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
|
||||
- if: toJson(fromJson(steps.earlier_preview.outputs.data)) != '[]'
|
||||
name: Check for preview label
|
||||
id: preview_label
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: GET /repos/{owner}/{repo}/issues/{issue_number}/labels
|
||||
owner: ${{ github.event.repository.owner.login }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
issue_number: ${{ github.event.number }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
|
||||
- if: toJson(fromJson(steps.earlier_preview.outputs.data)) != '[]' && contains(fromJson(steps.preview_label.outputs.data).*.name, 'preview')
|
||||
name: Create deployment
|
||||
id: deployment
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: POST /repos/{owner}/{repo}/deployments
|
||||
mediaType: |
|
||||
previews:
|
||||
- ant-man
|
||||
- flash
|
||||
owner: ${{ github.event.repository.owner.login }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
task: deploy:preview
|
||||
auto_merge: false
|
||||
required_contexts: "[]"
|
||||
environment: preview-pr-${{ github.event.number }}
|
||||
description: "Preview for Pull Request #${{ github.event.number }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
|
||||
- if: toJson(fromJson(steps.earlier_preview.outputs.data)) != '[]' && contains(fromJson(steps.preview_label.outputs.data).*.name, 'preview')
|
||||
name: Trigger 'preview build'
|
||||
uses: peter-evans/repository-dispatch@v1
|
||||
with:
|
||||
token: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
|
||||
event-type: "Preview build #${{ github.event.number }}"
|
||||
client-payload: '{"folder": "pr${{ github.event.number }}", "sha": "${{ github.event.pull_request.head.sha }}", "deployment_id": "${{ fromJson(steps.deployment.outputs.data).id }}"}'
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,5 @@
|
||||
/.vs
|
||||
/build*/
|
||||
/build*
|
||||
CMakeSettings.json
|
||||
docs/aidocs/*
|
||||
docs/gamedocs/*
|
||||
|
144
CMakeLists.txt
144
CMakeLists.txt
@@ -10,6 +10,10 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||
message(FATAL_ERROR "In-source builds not allowed. Please run \"cmake ..\" from the bin directory")
|
||||
endif()
|
||||
|
||||
if (EMSCRIPTEN)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/os/emscripten/cmake")
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
|
||||
|
||||
@@ -27,6 +31,61 @@ set_directory_options()
|
||||
include(Static)
|
||||
set_static_if_needed()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||
set(CMAKE_CXX_EXTENSIONS NO)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS YES)
|
||||
|
||||
# An empty target for the tools
|
||||
add_custom_target(tools)
|
||||
|
||||
include(Endian)
|
||||
add_endian_definition()
|
||||
|
||||
include(CompileFlags)
|
||||
compile_flags()
|
||||
|
||||
if(APPLE OR UNIX)
|
||||
add_definitions(-DUNIX)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
find_package(Doxygen)
|
||||
endif()
|
||||
|
||||
list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/rev.cpp")
|
||||
if(WIN32)
|
||||
list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/ottdres.rc")
|
||||
endif()
|
||||
|
||||
# Documentation
|
||||
if(DOXYGEN_EXECUTABLE)
|
||||
add_custom_target(docs)
|
||||
add_custom_target(docs_source
|
||||
${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/docs
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Generating documentation for source"
|
||||
)
|
||||
add_dependencies(docs_source
|
||||
find_version
|
||||
)
|
||||
add_dependencies(docs
|
||||
docs_source
|
||||
)
|
||||
endif()
|
||||
|
||||
include(AddCustomXXXTimestamp)
|
||||
|
||||
if(OPTION_TOOLS_ONLY)
|
||||
if(HOST_BINARY_DIR)
|
||||
unset(HOST_BINARY_DIR CACHE)
|
||||
endif()
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/src)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Prefer -pthread over -lpthread, which is often the better option of the two.
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD YES)
|
||||
# Make sure we have Threads available.
|
||||
@@ -98,10 +157,6 @@ find_package(Xaudio2)
|
||||
|
||||
find_package(Grfcodec)
|
||||
|
||||
if(UNIX)
|
||||
find_package(Doxygen)
|
||||
endif()
|
||||
|
||||
# IPO is only properly supported from CMake 3.9. Despite the fact we are
|
||||
# CMake 3.5, still enable IPO if we detect we are 3.9+.
|
||||
if(POLICY CMP0069)
|
||||
@@ -129,47 +184,7 @@ if(APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# C++17 for MSVC
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
else()
|
||||
# C++11 for all other targets
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||
set(CMAKE_CXX_EXTENSIONS NO)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS YES)
|
||||
|
||||
list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/rev.cpp")
|
||||
if(WIN32)
|
||||
list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/ottdres.rc")
|
||||
endif()
|
||||
|
||||
# An empty target for the tools
|
||||
add_custom_target(tools)
|
||||
|
||||
# Documentation
|
||||
if(DOXYGEN_EXECUTABLE)
|
||||
add_custom_target(docs)
|
||||
add_custom_target(docs_source
|
||||
${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/docs
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Generating documentation for source"
|
||||
)
|
||||
add_dependencies(docs_source
|
||||
find_version
|
||||
)
|
||||
add_dependencies(docs
|
||||
docs_source
|
||||
)
|
||||
endif()
|
||||
|
||||
include(SourceList)
|
||||
include(Endian)
|
||||
add_endian_definition()
|
||||
|
||||
# Needed by rev.cpp
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
@@ -178,9 +193,6 @@ include_directories(${CMAKE_SOURCE_DIR}/src/3rdparty/squirrel/include)
|
||||
|
||||
include(MSVCFilters)
|
||||
|
||||
include(CompileFlags)
|
||||
compile_flags()
|
||||
|
||||
add_executable(openttd WIN32 ${GENERATED_SOURCE_FILES})
|
||||
set_target_properties(openttd PROPERTIES OUTPUT_NAME "${BINARY_NAME}")
|
||||
# All other files are added via target_sources()
|
||||
@@ -215,7 +227,6 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
include(AddCustomXXXTimestamp)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/src)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/media/baseset)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/bin)
|
||||
@@ -248,10 +259,6 @@ endif()
|
||||
set_target_properties(openttd PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
|
||||
process_compile_flags()
|
||||
|
||||
if(APPLE OR UNIX)
|
||||
add_definitions(-DUNIX)
|
||||
endif()
|
||||
|
||||
include(LinkPackage)
|
||||
link_package(PNG TARGET PNG::PNG ENCOURAGED)
|
||||
link_package(ZLIB TARGET ZLIB::ZLIB ENCOURAGED)
|
||||
@@ -288,6 +295,39 @@ if(APPLE)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
add_library(WASM::WASM INTERFACE IMPORTED)
|
||||
|
||||
# Allow heap-growth, and start with a bigger memory size.
|
||||
target_link_libraries(WASM::WASM INTERFACE "-s ALLOW_MEMORY_GROWTH=1")
|
||||
target_link_libraries(WASM::WASM INTERFACE "-s INITIAL_MEMORY=33554432")
|
||||
|
||||
# Export functions to Javascript.
|
||||
target_link_libraries(WASM::WASM INTERFACE "-s EXPORTED_FUNCTIONS='[\"_main\", \"_em_openttd_add_server\"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||
|
||||
# Preload all the files we generate during build.
|
||||
# As we do not compile with FreeType / FontConfig, we also have no way to
|
||||
# render several languages (like Chinese, ..), so where do you draw the
|
||||
# line what languages to include and which not? In the end, especially as
|
||||
# the more languages you add the slower downloading becomes, we decided to
|
||||
# only ship the English language.
|
||||
target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/baseset@/baseset")
|
||||
target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/lang/english.lng@/lang/english.lng")
|
||||
target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_SOURCE_DIR}/bin/ai@/ai")
|
||||
target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_SOURCE_DIR}/bin/game@/game")
|
||||
|
||||
# We use IDBFS for persistent storage.
|
||||
target_link_libraries(WASM::WASM INTERFACE "-lidbfs.js")
|
||||
|
||||
# Use custom pre-js and shell.html.
|
||||
target_link_libraries(WASM::WASM INTERFACE "--pre-js ${CMAKE_SOURCE_DIR}/os/emscripten/pre.js")
|
||||
target_link_libraries(WASM::WASM INTERFACE "--shell-file ${CMAKE_SOURCE_DIR}/os/emscripten/shell.html")
|
||||
|
||||
# Build the .html (which builds the .js, .wasm, and .data too).
|
||||
set_target_properties(openttd PROPERTIES SUFFIX ".html")
|
||||
target_link_libraries(openttd WASM::WASM)
|
||||
endif()
|
||||
|
||||
if(NOT PERSONAL_DIR STREQUAL "(not set)")
|
||||
add_definitions(
|
||||
-DWITH_PERSONAL_DIR
|
||||
|
@@ -83,9 +83,9 @@ make
|
||||
|
||||
## Supported compilers
|
||||
|
||||
Every compiler that is supported by CMake and supports C++11, should be
|
||||
Every compiler that is supported by CMake and supports C++17, should be
|
||||
able to compile OpenTTD. As the exact list of compilers changes constantly,
|
||||
we refer to the compiler manual to see if it supports C++11, and to CMake
|
||||
we refer to the compiler manual to see if it supports C++17, and to CMake
|
||||
to see if it supports your compiler.
|
||||
|
||||
## Compilation of base sets
|
||||
|
@@ -55,8 +55,20 @@ function(set_options)
|
||||
option(OPTION_DEDICATED "Build dedicated server only (no GUI)" OFF)
|
||||
option(OPTION_INSTALL_FHS "Install with Filesystem Hierarchy Standard folders" ${DEFAULT_OPTION_INSTALL_FHS})
|
||||
option(OPTION_USE_ASSERTS "Use assertions; leave enabled for nightlies, betas, and RCs" ON)
|
||||
option(OPTION_USE_THREADS "Use threads" ON)
|
||||
if(EMSCRIPTEN)
|
||||
# Although pthreads is supported, it is not in a way yet that is
|
||||
# useful for us.
|
||||
option(OPTION_USE_THREADS "Use threads" OFF)
|
||||
else()
|
||||
option(OPTION_USE_THREADS "Use threads" ON)
|
||||
endif()
|
||||
option(OPTION_USE_NSIS "Use NSIS to create windows installer; enable only for stable releases" OFF)
|
||||
option(OPTION_TOOLS_ONLY "Build only tools target" OFF)
|
||||
option(OPTION_DOCS_ONLY "Build only docs target" OFF)
|
||||
|
||||
if (OPTION_DOCS_ONLY)
|
||||
set(OPTION_TOOLS_ONLY ON PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Show the values of the generic options.
|
||||
|
@@ -5,6 +5,7 @@ set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/os/macosx/openttd.icns")
|
||||
set(CPACK_BUNDLE_PLIST "${CMAKE_CURRENT_BINARY_DIR}/Info.plist")
|
||||
set(CPACK_BUNDLE_STARTUP_COMMAND "${CMAKE_SOURCE_DIR}/os/macosx/launch.sh")
|
||||
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/os/macosx/splash.png")
|
||||
set(CPACK_DMG_FORMAT "UDBZ")
|
||||
|
||||
# Create a temporary Info.plist.in, where we will fill in the version via
|
||||
# CPackProperties.cmake.in. This because at this point in time the version
|
||||
|
4
os/emscripten/Dockerfile
Normal file
4
os/emscripten/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM emscripten/emsdk
|
||||
|
||||
COPY emsdk-liblzma.patch /
|
||||
RUN cd /emsdk/upstream/emscripten && patch -p1 < /emsdk-liblzma.patch
|
40
os/emscripten/README.md
Normal file
40
os/emscripten/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
## How to build with Emscripten
|
||||
|
||||
Building with Emscripten works with emsdk 2.0.10 and above.
|
||||
|
||||
Currently there is no LibLZMA support upstream; for this we suggest to apply
|
||||
the provided patch in this folder to your emsdk installation.
|
||||
|
||||
For convenience, a Dockerfile is supplied that does this patches for you
|
||||
against upstream emsdk docker. Best way to use it:
|
||||
|
||||
Build the docker image:
|
||||
```
|
||||
docker build -t emsdk-lzma .
|
||||
```
|
||||
|
||||
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 -j5 tools
|
||||
```
|
||||
|
||||
Next, build the game with emscripten:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emcmake cmake .. -DHOST_BINARY_DIR=$(pwd)/build-host -DCMAKE_BUILD_TYPE=RelWithDebInfo -DOPTION_USE_ASSERTS=OFF
|
||||
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emmake make -j5
|
||||
```
|
||||
|
||||
And now you have in your build folder files like "openttd.html".
|
||||
|
||||
To run it locally, you would have to start a local webserver, like:
|
||||
|
||||
```
|
||||
cd build
|
||||
python3 -m http.server
|
||||
````
|
||||
|
||||
Now you can play the game via http://127.0.0.1:8000/openttd.html .
|
20
os/emscripten/cmake/FindLibLZMA.cmake
Normal file
20
os/emscripten/cmake/FindLibLZMA.cmake
Normal file
@@ -0,0 +1,20 @@
|
||||
# LibLZMA is a recent addition to the emscripten SDK, so it is possible
|
||||
# someone hasn't updated his SDK yet. Test out if the SDK supports LibLZMA.
|
||||
include(CheckCXXSourceCompiles)
|
||||
set(CMAKE_REQUIRED_FLAGS "-sUSE_LIBLZMA=1")
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <lzma.h>
|
||||
int main() { return 0; }"
|
||||
LIBLZMA_FOUND
|
||||
)
|
||||
|
||||
if (LIBLZMA_FOUND)
|
||||
add_library(LibLZMA::LibLZMA INTERFACE IMPORTED)
|
||||
set_target_properties(LibLZMA::LibLZMA PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "-sUSE_LIBLZMA=1"
|
||||
INTERFACE_LINK_LIBRARIES "-sUSE_LIBLZMA=1"
|
||||
)
|
||||
else()
|
||||
message(WARNING "You are using an emscripten SDK without LibLZMA support. Many savegames won't be able to load in OpenTTD. Please apply 'emsdk-liblzma.patch' to your local emsdk installation.")
|
||||
endif()
|
7
os/emscripten/cmake/FindPNG.cmake
Normal file
7
os/emscripten/cmake/FindPNG.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
add_library(PNG::PNG INTERFACE IMPORTED)
|
||||
set_target_properties(PNG::PNG PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "-sUSE_LIBPNG=1"
|
||||
INTERFACE_LINK_LIBRARIES "-sUSE_LIBPNG=1"
|
||||
)
|
||||
|
||||
set(PNG_FOUND on)
|
7
os/emscripten/cmake/FindSDL2.cmake
Normal file
7
os/emscripten/cmake/FindSDL2.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
add_library(SDL2::SDL2 INTERFACE IMPORTED)
|
||||
set_target_properties(SDL2::SDL2 PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "-sUSE_SDL=2"
|
||||
INTERFACE_LINK_LIBRARIES "-sUSE_SDL=2"
|
||||
)
|
||||
|
||||
set(SDL2_FOUND on)
|
7
os/emscripten/cmake/FindZLIB.cmake
Normal file
7
os/emscripten/cmake/FindZLIB.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
add_library(ZLIB::ZLIB INTERFACE IMPORTED)
|
||||
set_target_properties(ZLIB::ZLIB PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "-sUSE_ZLIB=1"
|
||||
INTERFACE_LINK_LIBRARIES "-sUSE_ZLIB=1"
|
||||
)
|
||||
|
||||
set(ZLIB_FOUND on)
|
213
os/emscripten/emsdk-liblzma.patch
Normal file
213
os/emscripten/emsdk-liblzma.patch
Normal file
@@ -0,0 +1,213 @@
|
||||
From 90dd4d4c6b1cedec338ff5b375fffca93700f7bc Mon Sep 17 00:00:00 2001
|
||||
From: milek7 <me@milek7.pl>
|
||||
Date: Tue, 8 Dec 2020 01:03:31 +0100
|
||||
Subject: [PATCH] Add liblzma port
|
||||
|
||||
---
|
||||
Source: https://github.com/emscripten-core/emscripten/pull/12990
|
||||
|
||||
Modifed by OpenTTD to have the bare minimum needed to work. Otherwise there
|
||||
are constantly conflicts when trying to apply this patch to different versions
|
||||
of emsdk.
|
||||
|
||||
diff --git a/embuilder.py b/embuilder.py
|
||||
index 818262190ed..ab7d5adb7b2 100755
|
||||
--- a/embuilder.py
|
||||
+++ b/embuilder.py
|
||||
@@ -60,6 +60,7 @@
|
||||
'harfbuzz',
|
||||
'icu',
|
||||
'libjpeg',
|
||||
+ 'liblzma',
|
||||
'libpng',
|
||||
'ogg',
|
||||
'regal',
|
||||
@@ -197,6 +198,8 @@ def main():
|
||||
build_port('ogg', libname('libogg'))
|
||||
elif what == 'libjpeg':
|
||||
build_port('libjpeg', libname('libjpeg'))
|
||||
+ elif what == 'liblzma':
|
||||
+ build_port('liblzma', libname('liblzma'))
|
||||
elif what == 'libpng':
|
||||
build_port('libpng', libname('libpng'))
|
||||
elif what == 'sdl2':
|
||||
diff --git a/src/settings.js b/src/settings.js
|
||||
index 61cd98939ba..be6fcb678c6 100644
|
||||
--- a/src/settings.js
|
||||
+++ b/src/settings.js
|
||||
@@ -1197,6 +1197,9 @@ var USE_BZIP2 = 0;
|
||||
// 1 = use libjpeg from emscripten-ports
|
||||
var USE_LIBJPEG = 0;
|
||||
|
||||
+// 1 = use liblzma from emscripten-ports
|
||||
+var USE_LIBLZMA = 0;
|
||||
+
|
||||
// 1 = use libpng from emscripten-ports
|
||||
var USE_LIBPNG = 0;
|
||||
|
||||
diff --git a/tools/ports/liblzma.py b/tools/ports/liblzma.py
|
||||
new file mode 100644
|
||||
index 00000000000..e9567ef36ff
|
||||
--- /dev/null
|
||||
+++ b/tools/ports/liblzma.py
|
||||
@@ -0,0 +1,160 @@
|
||||
+# Copyright 2020 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
|
||||
+import shutil
|
||||
+
|
||||
+VERSION = '5.2.5'
|
||||
+HASH = '7443674247deda2935220fbc4dfc7665e5bb5a260be8ad858c8bd7d7b9f0f868f04ea45e62eb17c0a5e6a2de7c7500ad2d201e2d668c48ca29bd9eea5a73a3ce'
|
||||
+
|
||||
+
|
||||
+def needed(settings):
|
||||
+ return settings.USE_LIBLZMA
|
||||
+
|
||||
+
|
||||
+def get(ports, settings, shared):
|
||||
+ libname = ports.get_lib_name('liblzma')
|
||||
+ ports.fetch_project('liblzma', 'https://tukaani.org/xz/xz-' + VERSION + '.tar.gz', 'xz-' + VERSION, sha512hash=HASH)
|
||||
+
|
||||
+ def create():
|
||||
+ ports.clear_project_build('liblzma')
|
||||
+
|
||||
+ source_path = os.path.join(ports.get_dir(), 'liblzma', 'xz-' + VERSION)
|
||||
+ dest_path = os.path.join(ports.get_build_dir(), 'liblzma')
|
||||
+
|
||||
+ shared.try_delete(dest_path)
|
||||
+ os.makedirs(dest_path)
|
||||
+ shutil.rmtree(dest_path, ignore_errors=True)
|
||||
+ shutil.copytree(source_path, dest_path)
|
||||
+
|
||||
+ build_flags = ['-DHAVE_CONFIG_H', '-DTUKLIB_SYMBOL_PREFIX=lzma_', '-fvisibility=hidden']
|
||||
+ exclude_dirs = ['xzdec', 'xz', 'lzmainfo']
|
||||
+ exclude_files = ['crc32_small.c', 'crc64_small.c', 'crc32_tablegen.c', 'crc64_tablegen.c', 'price_tablegen.c', 'fastpos_tablegen.c'
|
||||
+ 'tuklib_exit.c', 'tuklib_mbstr_fw.c', 'tuklib_mbstr_width.c', 'tuklib_open_stdxxx.c', 'tuklib_progname.c']
|
||||
+ include_dirs_rel = ['../common', 'api', 'common', 'check', 'lz', 'rangecoder', 'lzma', 'delta', 'simple']
|
||||
+
|
||||
+ open(os.path.join(dest_path, 'src', 'config.h'), 'w').write(config_h)
|
||||
+
|
||||
+ final = os.path.join(dest_path, libname)
|
||||
+ include_dirs = [os.path.join(dest_path, 'src', 'liblzma', p) for p in include_dirs_rel]
|
||||
+ ports.build_port(os.path.join(dest_path, 'src'), final, flags=build_flags, exclude_dirs=exclude_dirs, exclude_files=exclude_files, includes=include_dirs)
|
||||
+
|
||||
+ ports.install_headers(os.path.join(dest_path, 'src', 'liblzma', 'api'), 'lzma.h')
|
||||
+ ports.install_headers(os.path.join(dest_path, 'src', 'liblzma', 'api', 'lzma'), '*.h', 'lzma')
|
||||
+
|
||||
+ return final
|
||||
+
|
||||
+ return [shared.Cache.get(libname, create, what='port')]
|
||||
+
|
||||
+
|
||||
+def clear(ports, settings, shared):
|
||||
+ shared.Cache.erase_file(ports.get_lib_name('liblzma'))
|
||||
+
|
||||
+
|
||||
+def process_args(ports):
|
||||
+ return []
|
||||
+
|
||||
+
|
||||
+def show():
|
||||
+ return 'liblzma (USE_LIBLZMA=1; public domain)'
|
||||
+
|
||||
+
|
||||
+config_h = r'''
|
||||
+#define ASSUME_RAM 128
|
||||
+#define ENABLE_NLS 1
|
||||
+#define HAVE_CHECK_CRC32 1
|
||||
+#define HAVE_CHECK_CRC64 1
|
||||
+#define HAVE_CHECK_SHA256 1
|
||||
+#define HAVE_CLOCK_GETTIME 1
|
||||
+#define HAVE_DCGETTEXT 1
|
||||
+#define HAVE_DECL_CLOCK_MONOTONIC 1
|
||||
+#define HAVE_DECL_PROGRAM_INVOCATION_NAME 1
|
||||
+#define HAVE_DECODERS 1
|
||||
+#define HAVE_DECODER_ARM 1
|
||||
+#define HAVE_DECODER_ARMTHUMB 1
|
||||
+#define HAVE_DECODER_DELTA 1
|
||||
+#define HAVE_DECODER_IA64 1
|
||||
+#define HAVE_DECODER_LZMA1 1
|
||||
+#define HAVE_DECODER_LZMA2 1
|
||||
+#define HAVE_DECODER_POWERPC 1
|
||||
+#define HAVE_DECODER_SPARC 1
|
||||
+#define HAVE_DECODER_X86 1
|
||||
+#define HAVE_DLFCN_H 1
|
||||
+#define HAVE_ENCODERS 1
|
||||
+#define HAVE_ENCODER_ARM 1
|
||||
+#define HAVE_ENCODER_ARMTHUMB 1
|
||||
+#define HAVE_ENCODER_DELTA 1
|
||||
+#define HAVE_ENCODER_IA64 1
|
||||
+#define HAVE_ENCODER_LZMA1 1
|
||||
+#define HAVE_ENCODER_LZMA2 1
|
||||
+#define HAVE_ENCODER_POWERPC 1
|
||||
+#define HAVE_ENCODER_SPARC 1
|
||||
+#define HAVE_ENCODER_X86 1
|
||||
+#define HAVE_FCNTL_H 1
|
||||
+#define HAVE_FUTIMENS 1
|
||||
+#define HAVE_GETOPT_H 1
|
||||
+#define HAVE_GETOPT_LONG 1
|
||||
+#define HAVE_GETTEXT 1
|
||||
+#define HAVE_IMMINTRIN_H 1
|
||||
+#define HAVE_INTTYPES_H 1
|
||||
+#define HAVE_LIMITS_H 1
|
||||
+#define HAVE_MBRTOWC 1
|
||||
+#define HAVE_MEMORY_H 1
|
||||
+#define HAVE_MF_BT2 1
|
||||
+#define HAVE_MF_BT3 1
|
||||
+#define HAVE_MF_BT4 1
|
||||
+#define HAVE_MF_HC3 1
|
||||
+#define HAVE_MF_HC4 1
|
||||
+#define HAVE_OPTRESET 1
|
||||
+#define HAVE_POSIX_FADVISE 1
|
||||
+#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1
|
||||
+#define HAVE_PTHREAD_PRIO_INHERIT 1
|
||||
+#define HAVE_STDBOOL_H 1
|
||||
+#define HAVE_STDINT_H 1
|
||||
+#define HAVE_STDLIB_H 1
|
||||
+#define HAVE_STRINGS_H 1
|
||||
+#define HAVE_STRING_H 1
|
||||
+#define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1
|
||||
+#define HAVE_SYS_PARAM_H 1
|
||||
+#define HAVE_SYS_STAT_H 1
|
||||
+#define HAVE_SYS_TIME_H 1
|
||||
+#define HAVE_SYS_TYPES_H 1
|
||||
+#define HAVE_UINTPTR_T 1
|
||||
+#define HAVE_UNISTD_H 1
|
||||
+#define HAVE_VISIBILITY 1
|
||||
+#define HAVE_WCWIDTH 1
|
||||
+#define HAVE__BOOL 1
|
||||
+#define HAVE___BUILTIN_ASSUME_ALIGNED 1
|
||||
+#define HAVE___BUILTIN_BSWAPXX 1
|
||||
+#define MYTHREAD_POSIX 1
|
||||
+#define NDEBUG 1
|
||||
+#define PACKAGE "xz"
|
||||
+#define PACKAGE_BUGREPORT "lasse.collin@tukaani.org"
|
||||
+#define PACKAGE_NAME "XZ Utils"
|
||||
+#define PACKAGE_STRING "XZ Utils 5.2.5"
|
||||
+#define PACKAGE_TARNAME "xz"
|
||||
+#define PACKAGE_VERSION "5.2.5"
|
||||
+#define SIZEOF_SIZE_T 4
|
||||
+#define STDC_HEADERS 1
|
||||
+#define TUKLIB_CPUCORES_SYSCONF 1
|
||||
+#define TUKLIB_FAST_UNALIGNED_ACCESS 1
|
||||
+#define TUKLIB_PHYSMEM_SYSCONF 1
|
||||
+#ifndef _ALL_SOURCE
|
||||
+# define _ALL_SOURCE 1
|
||||
+#endif
|
||||
+#ifndef _GNU_SOURCE
|
||||
+# define _GNU_SOURCE 1
|
||||
+#endif
|
||||
+#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
+# define _POSIX_PTHREAD_SEMANTICS 1
|
||||
+#endif
|
||||
+#ifndef _TANDEM_SOURCE
|
||||
+# define _TANDEM_SOURCE 1
|
||||
+#endif
|
||||
+#ifndef __EXTENSIONS__
|
||||
+# define __EXTENSIONS__ 1
|
||||
+#endif
|
||||
+#define VERSION "5.2.5"
|
||||
+'''
|
BIN
os/emscripten/loading.png
Executable file
BIN
os/emscripten/loading.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
93
os/emscripten/pre.js
Normal file
93
os/emscripten/pre.js
Normal file
@@ -0,0 +1,93 @@
|
||||
Module.arguments.push('-mnull', '-snull', '-vsdl:relative_mode');
|
||||
Module['websocket'] = { url: function(host, port, proto) {
|
||||
/* openttd.org hosts a WebSocket proxy for the content service. */
|
||||
if (host == "content.openttd.org" && port == 3978 && proto == "tcp") {
|
||||
return "wss://content.openttd.org/";
|
||||
}
|
||||
|
||||
/* Everything else just tries to make a default WebSocket connection.
|
||||
* If you run your own server you can setup your own WebSocket proxy in
|
||||
* front of it and let people connect to your server via the proxy. You
|
||||
* are best to add another "if" statement as above for this. */
|
||||
return null;
|
||||
} };
|
||||
|
||||
Module.preRun.push(function() {
|
||||
personal_dir = '/home/web_user/.openttd';
|
||||
content_download_dir = personal_dir + '/content_download'
|
||||
|
||||
/* Because of the "-c" above, all user-data is stored in /user_data. */
|
||||
FS.mkdir(personal_dir);
|
||||
FS.mount(IDBFS, {}, personal_dir);
|
||||
|
||||
Module.addRunDependency('syncfs');
|
||||
FS.syncfs(true, function (err) {
|
||||
/* FS.mkdir() tends to fail if parent folders do not exist. */
|
||||
if (!FS.analyzePath(content_download_dir).exists) {
|
||||
FS.mkdir(content_download_dir);
|
||||
}
|
||||
if (!FS.analyzePath(content_download_dir + '/baseset').exists) {
|
||||
FS.mkdir(content_download_dir + '/baseset');
|
||||
}
|
||||
|
||||
/* Check if the OpenGFX baseset is already downloaded. */
|
||||
if (!FS.analyzePath(content_download_dir + '/baseset/opengfx-0.6.0.tar').exists) {
|
||||
window.openttd_downloaded_opengfx = true;
|
||||
FS.createPreloadedFile(content_download_dir + '/baseset', 'opengfx-0.6.0.tar', 'https://installer.cdn.openttd.org/emscripten/opengfx-0.6.0.tar', true, true);
|
||||
} else {
|
||||
/* Fake dependency increase, so the counter is stable. */
|
||||
Module.addRunDependency('opengfx');
|
||||
Module.removeRunDependency('opengfx');
|
||||
}
|
||||
|
||||
Module.removeRunDependency('syncfs');
|
||||
});
|
||||
|
||||
window.openttd_syncfs_shown_warning = false;
|
||||
window.openttd_syncfs = function() {
|
||||
/* Copy the virtual FS to the persistent storage. */
|
||||
FS.syncfs(false, function (err) { });
|
||||
|
||||
/* On first time, warn the user about the volatile behaviour of
|
||||
* persistent storage. */
|
||||
if (!window.openttd_syncfs_shown_warning) {
|
||||
window.openttd_syncfs_shown_warning = true;
|
||||
Module.onWarningFs();
|
||||
}
|
||||
}
|
||||
|
||||
window.openttd_exit = function() {
|
||||
Module.onExit();
|
||||
}
|
||||
|
||||
window.openttd_abort = function() {
|
||||
Module.onAbort();
|
||||
}
|
||||
|
||||
window.openttd_server_list = function() {
|
||||
add_server = Module.cwrap("em_openttd_add_server", null, ["string", "number"]);
|
||||
|
||||
/* Add servers that support WebSocket here. Example:
|
||||
* add_server("localhost", 3979); */
|
||||
}
|
||||
|
||||
/* https://github.com/emscripten-core/emscripten/pull/12995 implements this
|
||||
* properly. Till that time, we use a polyfill. */
|
||||
SOCKFS.websocket_sock_ops.createPeer_ = SOCKFS.websocket_sock_ops.createPeer;
|
||||
SOCKFS.websocket_sock_ops.createPeer = function(sock, addr, port)
|
||||
{
|
||||
let func = Module['websocket']['url'];
|
||||
Module['websocket']['url'] = func(addr, port, (sock.type == 2) ? 'udp' : 'tcp');
|
||||
let ret = SOCKFS.websocket_sock_ops.createPeer_(sock, addr, port);
|
||||
Module['websocket']['url'] = func;
|
||||
return ret;
|
||||
}
|
||||
});
|
||||
|
||||
Module.postRun.push(function() {
|
||||
/* Check if we downloaded OpenGFX; if so, sync the virtual FS back to the
|
||||
* IDBFS so OpenGFX is stored persistent. */
|
||||
if (window['openttd_downloaded_opengfx']) {
|
||||
FS.syncfs(false, function (err) { });
|
||||
}
|
||||
});
|
205
os/emscripten/shell.html
Normal file
205
os/emscripten/shell.html
Normal file
File diff suppressed because one or more lines are too long
@@ -9075,7 +9075,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
--Accounting--
|
||||
GetCosts(): -5947
|
||||
Should be: -5947
|
||||
GetName(): Road Vehicle 1
|
||||
GetName(): Road Vehicle #1
|
||||
SetName(): true
|
||||
GetName(): MyVehicleName
|
||||
CloneVehicle(): 13
|
||||
|
23
src/3rdparty/optional/LICENSE_1_0.txt
vendored
23
src/3rdparty/optional/LICENSE_1_0.txt
vendored
@@ -1,23 +0,0 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
1066
src/3rdparty/optional/optional.hpp
vendored
1066
src/3rdparty/optional/optional.hpp
vendored
File diff suppressed because it is too large
Load Diff
33
src/3rdparty/optional/ottd_optional.h
vendored
33
src/3rdparty/optional/ottd_optional.h
vendored
@@ -1,33 +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 ottd_optional.h Header to select between native. */
|
||||
|
||||
#ifndef OTTD_OPTIONAL_H
|
||||
#define OTTD_OPTIONAL_H
|
||||
|
||||
#if defined(__has_include)
|
||||
# if __has_include(<version>)
|
||||
# include <version>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (__cplusplus >= 201703L) || (defined(__cpp_lib_optional) && __cpp_lib_optional >= 201606L)
|
||||
|
||||
/* Native std::optional. */
|
||||
#include <optional>
|
||||
namespace opt = std;
|
||||
|
||||
#else
|
||||
|
||||
/* No std::optional, use local copy instead. */
|
||||
#include "optional.hpp"
|
||||
namespace opt = std::experimental;
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* OTTD_OPTIONAL_H */
|
@@ -1,3 +1,11 @@
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(settingsgen)
|
||||
add_subdirectory(strgen)
|
||||
|
||||
if(OPTION_TOOLS_ONLY)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(ai)
|
||||
add_subdirectory(blitter)
|
||||
@@ -11,11 +19,8 @@ add_subdirectory(network)
|
||||
add_subdirectory(os)
|
||||
add_subdirectory(pathfinder)
|
||||
add_subdirectory(saveload)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(settingsgen)
|
||||
add_subdirectory(sound)
|
||||
add_subdirectory(spriteloader)
|
||||
add_subdirectory(strgen)
|
||||
add_subdirectory(table)
|
||||
add_subdirectory(video)
|
||||
add_subdirectory(widgets)
|
||||
|
@@ -55,15 +55,15 @@ bool BaseSet<T, Tnum_files, Tsearch_in_tars>::FillSetDetails(IniFile *ini, const
|
||||
}
|
||||
|
||||
fetch_metadata("shortname");
|
||||
for (uint i = 0; item->value.value()[i] != '\0' && i < 4; i++) {
|
||||
this->shortname |= ((uint8)item->value.value()[i]) << (i * 8);
|
||||
for (uint i = 0; (*item->value)[i] != '\0' && i < 4; i++) {
|
||||
this->shortname |= ((uint8)(*item->value)[i]) << (i * 8);
|
||||
}
|
||||
|
||||
fetch_metadata("version");
|
||||
this->version = atoi(item->value->c_str());
|
||||
|
||||
item = metadata->GetItem("fallback", false);
|
||||
this->fallback = (item != nullptr && item->value && item->value.value() != "0" && item->value.value() != "false");
|
||||
this->fallback = (item != nullptr && item->value && *item->value != "0" && *item->value != "false");
|
||||
|
||||
/* For each of the file types we want to find the file, MD5 checksums and warning messages. */
|
||||
IniGroup *files = ini->GetGroup("files");
|
||||
|
@@ -442,8 +442,7 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
|
||||
/* Re-check bridge building possibility is initial bridge builindg query indicated a bridge type dependent failure */
|
||||
if (query_per_bridge_type && DoCommand(end, start, type | brd_type, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)) | DC_QUERY_COST, CMD_BUILD_BRIDGE).Failed()) continue;
|
||||
/* bridge is accepted, add to list */
|
||||
/*C++17: BuildBridgeData &item = */ bl->emplace_back();
|
||||
BuildBridgeData &item = bl->back();
|
||||
BuildBridgeData &item = bl->emplace_back();
|
||||
item.index = brd_type;
|
||||
item.spec = GetBridgeSpec(brd_type);
|
||||
/* Add to terraforming & bulldozing costs the cost of the
|
||||
|
@@ -142,8 +142,7 @@ struct SmallMap : std::vector<std::pair<T, U> > {
|
||||
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;
|
||||
}
|
||||
/*C++17: Pair &n = */ std::vector<Pair>::emplace_back();
|
||||
Pair &n = std::vector<Pair>::back();
|
||||
Pair &n = std::vector<Pair>::emplace_back();
|
||||
n.first = key;
|
||||
return n.second;
|
||||
}
|
||||
|
@@ -26,14 +26,14 @@
|
||||
* | | | | | | | */
|
||||
/** The original currency specifications. */
|
||||
static const CurrencySpec origin_currency_specs[CURRENCY_END] = {
|
||||
{ 1, "", CF_NOEURO, "\xC2\xA3", "", 0, STR_GAME_OPTIONS_CURRENCY_GBP }, ///< british pound
|
||||
{ 1, "", CF_NOEURO, u8"\u00a3", "", 0, STR_GAME_OPTIONS_CURRENCY_GBP }, ///< british pound
|
||||
{ 2, "", CF_NOEURO, "$", "", 0, STR_GAME_OPTIONS_CURRENCY_USD }, ///< american dollar
|
||||
{ 2, "", CF_ISEURO, "\xE2\x82\xAC", "", 0, STR_GAME_OPTIONS_CURRENCY_EUR }, ///< euro
|
||||
{ 220, "", CF_NOEURO, "\xC2\xA5", "", 0, STR_GAME_OPTIONS_CURRENCY_JPY }, ///< japanese yen
|
||||
{ 2, "", CF_ISEURO, u8"\u20ac", "", 0, STR_GAME_OPTIONS_CURRENCY_EUR }, ///< euro
|
||||
{ 220, "", CF_NOEURO, u8"\u00a5", "", 0, STR_GAME_OPTIONS_CURRENCY_JPY }, ///< japanese yen
|
||||
{ 27, "", 2002, "", NBSP "S.", 1, STR_GAME_OPTIONS_CURRENCY_ATS }, ///< austrian schilling
|
||||
{ 81, "", 2002, "BEF" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_BEF }, ///< belgian franc
|
||||
{ 2, "", CF_NOEURO, "CHF" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_CHF }, ///< swiss franc
|
||||
{ 41, "", CF_NOEURO, "", NBSP "K\xC4\x8D", 1, STR_GAME_OPTIONS_CURRENCY_CZK }, ///< czech koruna
|
||||
{ 41, "", CF_NOEURO, "", NBSP u8"K\u010d", 1, STR_GAME_OPTIONS_CURRENCY_CZK }, ///< czech koruna
|
||||
{ 4, "", 2002, "DM" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_DEM }, ///< deutsche mark
|
||||
{ 11, "", CF_NOEURO, "", NBSP "kr", 1, STR_GAME_OPTIONS_CURRENCY_DKK }, ///< danish krone
|
||||
{ 333, "", 2002, "Pts" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_ESP }, ///< spanish peseta
|
||||
@@ -45,7 +45,7 @@ static const CurrencySpec origin_currency_specs[CURRENCY_END] = {
|
||||
{ 3873, "", 2002, "", NBSP "L.", 1, STR_GAME_OPTIONS_CURRENCY_ITL }, ///< italian lira
|
||||
{ 4, "", 2002, "NLG" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_NLG }, ///< dutch gulden
|
||||
{ 12, "", CF_NOEURO, "", NBSP "Kr", 1, STR_GAME_OPTIONS_CURRENCY_NOK }, ///< norwegian krone
|
||||
{ 6, "", CF_NOEURO, "", NBSP "z\xC5\x82", 1, STR_GAME_OPTIONS_CURRENCY_PLN }, ///< polish zloty
|
||||
{ 6, "", CF_NOEURO, "", NBSP u8"z\u0142", 1, STR_GAME_OPTIONS_CURRENCY_PLN }, ///< polish zloty
|
||||
{ 5, "", CF_NOEURO, "", NBSP "Lei", 1, STR_GAME_OPTIONS_CURRENCY_RON }, ///< romanian leu
|
||||
{ 50, "", CF_NOEURO, "", NBSP "p", 1, STR_GAME_OPTIONS_CURRENCY_RUR }, ///< russian rouble
|
||||
{ 479, "", 2007, "", NBSP "SIT", 1, STR_GAME_OPTIONS_CURRENCY_SIT }, ///< slovenian tolar
|
||||
@@ -55,7 +55,7 @@ static const CurrencySpec origin_currency_specs[CURRENCY_END] = {
|
||||
{ 4, "", CF_NOEURO, "R$" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_BRL }, ///< brazil real
|
||||
{ 31, "", 2011, "", NBSP "EEK", 1, STR_GAME_OPTIONS_CURRENCY_EEK }, ///< estonian krooni
|
||||
{ 4, "", 2015, "", NBSP "Lt", 1, STR_GAME_OPTIONS_CURRENCY_LTL }, ///< lithuanian litas
|
||||
{ 1850, "", CF_NOEURO, "\xE2\x82\xA9", "", 0, STR_GAME_OPTIONS_CURRENCY_KRW }, ///< south korean won
|
||||
{ 1850, "", CF_NOEURO, u8"\u20a9", "", 0, STR_GAME_OPTIONS_CURRENCY_KRW }, ///< south korean won
|
||||
{ 13, "", CF_NOEURO, "R" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_ZAR }, ///< south african rand
|
||||
{ 1, "", CF_NOEURO, "", "", 2, STR_GAME_OPTIONS_CURRENCY_CUSTOM }, ///< custom currency (add further languages below)
|
||||
{ 3, "", CF_NOEURO, "", NBSP "GEL", 1, STR_GAME_OPTIONS_CURRENCY_GEL }, ///< Georgian Lari
|
||||
@@ -63,9 +63,9 @@ static const CurrencySpec origin_currency_specs[CURRENCY_END] = {
|
||||
{ 80, "", CF_NOEURO, "", NBSP "rub", 1, STR_GAME_OPTIONS_CURRENCY_RUB }, ///< New Russian Ruble
|
||||
{ 24, "", CF_NOEURO, "$", "", 0, STR_GAME_OPTIONS_CURRENCY_MXN }, ///< Mexican peso
|
||||
{ 40, "", CF_NOEURO, "NTD" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_NTD }, ///< new taiwan dollar
|
||||
{ 8, "", CF_NOEURO, "\xC2\xA5", "", 0, STR_GAME_OPTIONS_CURRENCY_CNY }, ///< chinese renminbi
|
||||
{ 8, "", CF_NOEURO, u8"\u00a5", "", 0, STR_GAME_OPTIONS_CURRENCY_CNY }, ///< chinese renminbi
|
||||
{ 10, "", CF_NOEURO, "HKD" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_HKD }, ///< hong kong dollar
|
||||
{ 90, "", CF_NOEURO, "\xE2\x82\xB9", "", 0, STR_GAME_OPTIONS_CURRENCY_INR }, ///< Indian Rupee
|
||||
{ 90, "", CF_NOEURO, u8"\u20b9", "", 0, STR_GAME_OPTIONS_CURRENCY_INR }, ///< Indian Rupee
|
||||
};
|
||||
|
||||
/** Array of currencies used by the system */
|
||||
|
@@ -496,8 +496,7 @@ void EngineOverrideManager::ResetToDefaultMapping()
|
||||
this->clear();
|
||||
for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
|
||||
for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) {
|
||||
/*C++17: EngineIDMapping &eid = */ this->emplace_back();
|
||||
EngineIDMapping &eid = this->back();
|
||||
EngineIDMapping &eid = this->emplace_back();
|
||||
eid.type = type;
|
||||
eid.grfid = INVALID_GRFID;
|
||||
eid.internal_id = internal_id;
|
||||
|
@@ -126,8 +126,7 @@ public:
|
||||
*/
|
||||
inline FiosItem *Append()
|
||||
{
|
||||
/*C++17: return &*/ this->files.emplace_back();
|
||||
return &this->files.back();
|
||||
return &this->files.emplace_back();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -26,7 +26,6 @@
|
||||
#include "safeguards.h"
|
||||
|
||||
static const int ASCII_LETTERSTART = 32; ///< First printable ASCII letter.
|
||||
static const int MAX_FONT_SIZE = 72; ///< Maximum font size.
|
||||
|
||||
/** Default heights for the different sizes of fonts. */
|
||||
static const int _default_font_height[FS_END] = {10, 6, 18, 10};
|
||||
@@ -200,6 +199,8 @@ void UpdateFontHeightCache()
|
||||
|
||||
FreeTypeSettings _freetype;
|
||||
|
||||
static const int MAX_FONT_SIZE = 72; ///< Maximum font size.
|
||||
|
||||
static const byte FACE_COLOUR = 1;
|
||||
static const byte SHADOW_COLOUR = 2;
|
||||
|
||||
|
24
src/gfx.cpp
24
src/gfx.cpp
@@ -2090,6 +2090,30 @@ void SetAnimatedMouseCursor(const AnimCursor *table)
|
||||
SwitchAnimatedCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cursor position on mouse movement for relative modes.
|
||||
* @param delta_x How much change in the X position.
|
||||
* @param delta_y How much change in the Y position.
|
||||
*/
|
||||
void CursorVars::UpdateCursorPositionRelative(int delta_x, int delta_y)
|
||||
{
|
||||
if (this->fix_at) {
|
||||
this->delta.x = delta_x;
|
||||
this->delta.y = delta_y;
|
||||
} else {
|
||||
int last_position_x = this->pos.x;
|
||||
int last_position_y = this->pos.y;
|
||||
|
||||
this->pos.x = Clamp(this->pos.x + delta_x, 0, _cur_resolution.width - 1);
|
||||
this->pos.y = Clamp(this->pos.y + delta_y, 0, _cur_resolution.height - 1);
|
||||
|
||||
this->delta.x = last_position_x - this->pos.x;
|
||||
this->delta.y = last_position_y - this->pos.y;
|
||||
|
||||
this->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cursor position on mouse movement.
|
||||
* @param x New X position.
|
||||
|
@@ -144,6 +144,7 @@ struct CursorVars {
|
||||
/* Drag data */
|
||||
bool vehchain; ///< vehicle chain is dragged
|
||||
|
||||
void UpdateCursorPositionRelative(int delta_x, int delta_y);
|
||||
bool UpdateCursorPosition(int x, int y, bool queued_warp);
|
||||
|
||||
private:
|
||||
@@ -163,7 +164,9 @@ struct DrawPixelInfo {
|
||||
union Colour {
|
||||
uint32 data; ///< Conversion of the channel information to a 32 bit number.
|
||||
struct {
|
||||
#if TTD_ENDIAN == TTD_BIG_ENDIAN
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
uint8 r, g, b, a; ///< colour channels as used in browsers
|
||||
#elif TTD_ENDIAN == TTD_BIG_ENDIAN
|
||||
uint8 a, r, g, b; ///< colour channels in BE order
|
||||
#else
|
||||
uint8 b, g, r, a; ///< colour channels in LE order
|
||||
@@ -178,7 +181,9 @@ union Colour {
|
||||
* @param a The channel for the alpha/transparency.
|
||||
*/
|
||||
Colour(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) :
|
||||
#if TTD_ENDIAN == TTD_BIG_ENDIAN
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
r(r), g(g), b(b), a(a)
|
||||
#elif TTD_ENDIAN == TTD_BIG_ENDIAN
|
||||
a(a), r(r), g(g), b(b)
|
||||
#else
|
||||
b(b), g(g), r(r), a(a)
|
||||
|
@@ -504,11 +504,11 @@ bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path, const char *ful
|
||||
IniItem *item;
|
||||
|
||||
fetch_metadata("palette");
|
||||
this->palette = (item->value.value()[0] == 'D' || item->value.value()[0] == 'd') ? PAL_DOS : PAL_WINDOWS;
|
||||
this->palette = ((*item->value)[0] == 'D' || (*item->value)[0] == 'd') ? PAL_DOS : PAL_WINDOWS;
|
||||
|
||||
/* Get optional blitter information. */
|
||||
item = metadata->GetItem("blitter", false);
|
||||
this->blitter = (item != nullptr && item->value.value()[0] == '3') ? BLT_32BPP : BLT_8BPP;
|
||||
this->blitter = (item != nullptr && (*item->value)[0] == '3') ? BLT_32BPP : BLT_8BPP;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@@ -473,6 +473,8 @@ CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||
InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type, 1);
|
||||
InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
|
||||
InvalidateWindowData(WC_COMPANY_COLOUR, g->owner, g->vehicle_type);
|
||||
InvalidateWindowClassesData(WC_VEHICLE_VIEW);
|
||||
InvalidateWindowClassesData(WC_VEHICLE_DETAILS);
|
||||
InvalidateWindowData(WC_TEMPLATEGUI_MAIN, 0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -609,6 +611,8 @@ CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
|
||||
SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
|
||||
InvalidateWindowData(GetWindowClassForVehicleType(v->type), VehicleListIdentifier(VL_GROUP_LIST, v->type, _current_company).Pack());
|
||||
InvalidateWindowData(WC_VEHICLE_VIEW, v->index);
|
||||
InvalidateWindowData(WC_VEHICLE_DETAILS, v->index);
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
|
@@ -2633,8 +2633,7 @@ struct IndustryCargoesWindow : public Window {
|
||||
_displayed_industries.set(it);
|
||||
|
||||
this->fields.clear();
|
||||
/*C++17: CargoesRow &row = */ this->fields.emplace_back();
|
||||
CargoesRow &row = this->fields.back();
|
||||
CargoesRow &row = this->fields.emplace_back();
|
||||
row.columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS);
|
||||
row.columns[1].MakeEmpty(CFT_SMALL_EMPTY);
|
||||
row.columns[2].MakeEmpty(CFT_SMALL_EMPTY);
|
||||
@@ -2649,8 +2648,7 @@ struct IndustryCargoesWindow : public Window {
|
||||
int num_cust = CountMatchingAcceptingIndustries(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)) + houses_accept;
|
||||
int num_indrows = max(3, max(num_supp, num_cust)); // One is needed for the 'it' industry, and 2 for the cargo labels.
|
||||
for (int i = 0; i < num_indrows; i++) {
|
||||
/*C++17: CargoesRow &row = */ this->fields.emplace_back();
|
||||
CargoesRow &row = this->fields.back();
|
||||
CargoesRow &row = this->fields.emplace_back();
|
||||
row.columns[0].MakeEmpty(CFT_EMPTY);
|
||||
row.columns[1].MakeCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo));
|
||||
row.columns[2].MakeEmpty(CFT_EMPTY);
|
||||
@@ -2713,8 +2711,7 @@ struct IndustryCargoesWindow : public Window {
|
||||
_displayed_industries.reset();
|
||||
|
||||
this->fields.clear();
|
||||
/*C++17: CargoesRow &row = */ this->fields.emplace_back();
|
||||
CargoesRow &row = this->fields.back();
|
||||
CargoesRow &row = this->fields.emplace_back();
|
||||
row.columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS);
|
||||
row.columns[1].MakeEmpty(CFT_SMALL_EMPTY);
|
||||
row.columns[2].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS);
|
||||
@@ -2727,8 +2724,7 @@ struct IndustryCargoesWindow : public Window {
|
||||
int num_cust = CountMatchingAcceptingIndustries(&cid, 1) + houses_accept;
|
||||
int num_indrows = max(num_supp, num_cust);
|
||||
for (int i = 0; i < num_indrows; i++) {
|
||||
/*C++17: CargoesRow &row = */ this->fields.emplace_back();
|
||||
CargoesRow &row = this->fields.back();
|
||||
CargoesRow &row = this->fields.emplace_back();
|
||||
row.columns[0].MakeEmpty(CFT_EMPTY);
|
||||
row.columns[1].MakeCargo(&cid, 1);
|
||||
row.columns[2].MakeEmpty(CFT_EMPTY);
|
||||
|
@@ -13,6 +13,9 @@
|
||||
#include "string_func.h"
|
||||
#include "fileio_func.h"
|
||||
#include <fstream>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500)
|
||||
# include <unistd.h>
|
||||
@@ -115,6 +118,10 @@ bool IniFile::SaveToDisk(const char *filename)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "fileio_type.h"
|
||||
#include <string>
|
||||
#include "3rdparty/optional/ottd_optional.h"
|
||||
#include <optional>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -27,7 +27,7 @@ enum IniGroupType {
|
||||
struct IniItem {
|
||||
IniItem *next; ///< The next item in this group
|
||||
std::string name; ///< The name of this item
|
||||
opt::optional<std::string> value; ///< The value of this item
|
||||
std::optional<std::string> value; ///< The value of this item
|
||||
std::string comment; ///< The comment associated with this item
|
||||
|
||||
IniItem(struct IniGroup *parent, const std::string &name);
|
||||
|
@@ -5825,10 +5825,10 @@ STR_INDUSTRY_NAME_SUGAR_MINE :Sugar Mine
|
||||
##id 0x6000
|
||||
STR_SV_EMPTY :
|
||||
STR_SV_UNNAMED :Unnamed
|
||||
STR_SV_TRAIN_NAME :Train {COMMA}
|
||||
STR_SV_ROAD_VEHICLE_NAME :Road Vehicle {COMMA}
|
||||
STR_SV_SHIP_NAME :Ship {COMMA}
|
||||
STR_SV_AIRCRAFT_NAME :Aircraft {COMMA}
|
||||
STR_SV_TRAIN_NAME :Train #{COMMA}
|
||||
STR_SV_ROAD_VEHICLE_NAME :Road Vehicle #{COMMA}
|
||||
STR_SV_SHIP_NAME :Ship #{COMMA}
|
||||
STR_SV_AIRCRAFT_NAME :Aircraft #{COMMA}
|
||||
|
||||
STR_SV_STNAME :{STRING1}
|
||||
STR_SV_STNAME_NORTH :{STRING1} North
|
||||
@@ -6135,6 +6135,7 @@ STR_FORMAT_BUOY_NAME :{TOWN} Buoy
|
||||
STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Buoy #{COMMA}
|
||||
STR_FORMAT_COMPANY_NUM :(Company {COMMA})
|
||||
STR_FORMAT_GROUP_NAME :Group {COMMA}
|
||||
STR_FORMAT_GROUP_VEHICLE_NAME :{GROUP} #{COMMA}
|
||||
STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING}
|
||||
STR_FORMAT_WAYPOINT_NAME :{TOWN} Waypoint
|
||||
STR_FORMAT_WAYPOINT_NAME_SERIAL :{TOWN} Waypoint #{COMMA}
|
||||
|
134
src/misc_gui.cpp
134
src/misc_gui.cpp
@@ -450,73 +450,73 @@ static WindowDesc _about_desc(
|
||||
);
|
||||
|
||||
static const char * const _credits[] = {
|
||||
"Original design by Chris Sawyer",
|
||||
"Original graphics by Simon Foster",
|
||||
"",
|
||||
"The OpenTTD team (in alphabetical order):",
|
||||
" Grzegorz Duczy\xC5\x84ski (adf88) - General coding (since 1.7.2)",
|
||||
" Albert Hofkamp (Alberth) - GUI expert (since 0.7)",
|
||||
" Matthijs Kooijman (blathijs) - Pathfinder-guru, Debian port (since 0.3)",
|
||||
" Ulf Hermann (fonsinchen) - Cargo Distribution (since 1.3)",
|
||||
" Christoph Elsenhans (frosch) - General coding (since 0.6)",
|
||||
" Lo\xC3\xAF""c Guilloux (glx) - General / Windows Expert (since 0.4.5)",
|
||||
" Charles Pigott (LordAro) - General / Correctness police (since 1.9)",
|
||||
" Michael Lutz (michi_cc) - Path based signals (since 0.7)",
|
||||
" Niels Martin Hansen (nielsm) - Music system, general coding (since 1.9)",
|
||||
" Owen Rudge (orudge) - Forum host, OS/2 port (since 0.1)",
|
||||
" Peter Nelson (peter1138) - Spiritual descendant from NewGRF gods (since 0.4.5)",
|
||||
" Ingo von Borstel (planetmaker) - General, Support (since 1.1)",
|
||||
" Remko Bijker (Rubidium) - Lead coder and way more (since 0.4.5)",
|
||||
" Jos\xC3\xA9 Soler (Terkhen) - General coding (since 1.0)",
|
||||
" Leif Linse (Zuu) - AI/Game Script (since 1.2)",
|
||||
"",
|
||||
"Inactive Developers:",
|
||||
" Jean-Fran\xC3\xA7ois Claeys (Belugas) - GUI, NewGRF and more (0.4.5 - 1.0)",
|
||||
" Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles (0.3 - 0.7)",
|
||||
" Victor Fischer (Celestar) - Programming everywhere you need him to (0.3 - 0.6)",
|
||||
" Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;) (0.4.5 - 0.6)",
|
||||
" Jonathan Coome (Maedhros) - High priest of the NewGRF Temple (0.5 - 0.6)",
|
||||
" Attila B\xC3\xA1n (MiHaMiX) - Developer WebTranslator 1 and 2 (0.3 - 0.5)",
|
||||
" Zden\xC4\x9Bk Sojka (SmatZ) - Bug finder and fixer (0.6 - 1.3)",
|
||||
" Christoph Mallon (Tron) - Programmer, code correctness police (0.3 - 0.5)",
|
||||
" Patric Stout (TrueBrain) - NoAI, NoGo, Network (0.3 - 1.2), sys op (active)",
|
||||
" Thijs Marinussen (Yexo) - AI Framework, General (0.6 - 1.3)",
|
||||
"",
|
||||
"Retired Developers:",
|
||||
" Tam\xC3\xA1s Farag\xC3\xB3 (Darkvater) - Ex-Lead coder (0.3 - 0.5)",
|
||||
" Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3 - 0.3)",
|
||||
" Emil Djupfeld (egladil) - MacOSX (0.4.5 - 0.6)",
|
||||
" Simon Sasburg (HackyKid) - Many bugfixes (0.4 - 0.4.5)",
|
||||
" Ludvig Strigeus (ludde) - Original author of OpenTTD, main coder (0.1 - 0.3)",
|
||||
" Cian Duffy (MYOB) - BeOS port / manual writing (0.1 - 0.3)",
|
||||
" Petr Baudi\xC5\xA1 (pasky) - Many patches, NewGRF support (0.3 - 0.3)",
|
||||
" Benedikt Br\xC3\xBCggemeier (skidd13) - Bug fixer and code reworker (0.6 - 0.7)",
|
||||
" Serge Paquet (vurlix) - 2nd contributor after ludde (0.1 - 0.3)",
|
||||
"",
|
||||
"Special thanks go out to:",
|
||||
" Josef Drexler - For his great work on TTDPatch",
|
||||
" Marcin Grzegorczyk - Track foundations and for describing TTD internals",
|
||||
" Stefan Mei\xC3\x9Fner (sign_de) - For his work on the console",
|
||||
" Mike Ragsdale - OpenTTD installer",
|
||||
" Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
|
||||
" Richard Kempton (richK) - additional airports, initial TGP implementation",
|
||||
"",
|
||||
" Alberto Demichelis - Squirrel scripting language \xC2\xA9 2003-2008",
|
||||
" L. Peter Deutsch - MD5 implementation \xC2\xA9 1999, 2000, 2002",
|
||||
" Michael Blunck - Pre-signals and semaphores \xC2\xA9 2003",
|
||||
" George - Canal/Lock graphics \xC2\xA9 2003-2004",
|
||||
" Andrew Parkhouse (andythenorth) - River graphics",
|
||||
" David Dallaston (Pikka) - Tram tracks",
|
||||
" All Translators - Who made OpenTTD a truly international game",
|
||||
" Bug Reporters - Without whom OpenTTD would still be full of bugs!",
|
||||
"",
|
||||
"",
|
||||
"Developer of this patchpack:",
|
||||
" Jonathan G. Rennison (JGR)",
|
||||
"",
|
||||
"",
|
||||
"And last but not least:",
|
||||
" Chris Sawyer - For an amazing game!"
|
||||
u8"Original design by Chris Sawyer",
|
||||
u8"Original graphics by Simon Foster",
|
||||
u8"",
|
||||
u8"The OpenTTD team (in alphabetical order):",
|
||||
u8" Grzegorz Duczy\u0144ski (adf88) - General coding (since 1.7.2)",
|
||||
u8" Albert Hofkamp (Alberth) - GUI expert (since 0.7)",
|
||||
u8" Matthijs Kooijman (blathijs) - Pathfinder-guru, Debian port (since 0.3)",
|
||||
u8" Ulf Hermann (fonsinchen) - Cargo Distribution (since 1.3)",
|
||||
u8" Christoph Elsenhans (frosch) - General coding (since 0.6)",
|
||||
u8" Lo\u00efc Guilloux (glx) - General / Windows Expert (since 0.4.5)",
|
||||
u8" Charles Pigott (LordAro) - General / Correctness police (since 1.9)",
|
||||
u8" Michael Lutz (michi_cc) - Path based signals (since 0.7)",
|
||||
u8" Niels Martin Hansen (nielsm) - Music system, general coding (since 1.9)",
|
||||
u8" Owen Rudge (orudge) - Forum host, OS/2 port (since 0.1)",
|
||||
u8" Peter Nelson (peter1138) - Spiritual descendant from NewGRF gods (since 0.4.5)",
|
||||
u8" Ingo von Borstel (planetmaker) - General, Support (since 1.1)",
|
||||
u8" Remko Bijker (Rubidium) - Lead coder and way more (since 0.4.5)",
|
||||
u8" Jos\u00e9 Soler (Terkhen) - General coding (since 1.0)",
|
||||
u8" Leif Linse (Zuu) - AI/Game Script (since 1.2)",
|
||||
u8"",
|
||||
u8"Inactive Developers:",
|
||||
u8" Jean-Fran\u00e7ois Claeys (Belugas) - GUI, NewGRF and more (0.4.5 - 1.0)",
|
||||
u8" Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles (0.3 - 0.7)",
|
||||
u8" Victor Fischer (Celestar) - Programming everywhere you need him to (0.3 - 0.6)",
|
||||
u8" Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;) (0.4.5 - 0.6)",
|
||||
u8" Jonathan Coome (Maedhros) - High priest of the NewGRF Temple (0.5 - 0.6)",
|
||||
u8" Attila B\u00e1n (MiHaMiX) - Developer WebTranslator 1 and 2 (0.3 - 0.5)",
|
||||
u8" Zden\u011bk Sojka (SmatZ) - Bug finder and fixer (0.6 - 1.3)",
|
||||
u8" Christoph Mallon (Tron) - Programmer, code correctness police (0.3 - 0.5)",
|
||||
u8" Patric Stout (TrueBrain) - NoAI, NoGo, Network (0.3 - 1.2), sys op (active)",
|
||||
u8" Thijs Marinussen (Yexo) - AI Framework, General (0.6 - 1.3)",
|
||||
u8"",
|
||||
u8"Retired Developers:",
|
||||
u8" Tam\u00e1s Farag\u00f3 (Darkvater) - Ex-Lead coder (0.3 - 0.5)",
|
||||
u8" Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3 - 0.3)",
|
||||
u8" Emil Djupfeld (egladil) - MacOSX (0.4.5 - 0.6)",
|
||||
u8" Simon Sasburg (HackyKid) - Many bugfixes (0.4 - 0.4.5)",
|
||||
u8" Ludvig Strigeus (ludde) - Original author of OpenTTD, main coder (0.1 - 0.3)",
|
||||
u8" Cian Duffy (MYOB) - BeOS port / manual writing (0.1 - 0.3)",
|
||||
u8" Petr Baudi\u0161 (pasky) - Many patches, NewGRF support (0.3 - 0.3)",
|
||||
u8" Benedikt Br\u00fcggemeier (skidd13) - Bug fixer and code reworker (0.6 - 0.7)",
|
||||
u8" Serge Paquet (vurlix) - 2nd contributor after ludde (0.1 - 0.3)",
|
||||
u8"",
|
||||
u8"Special thanks go out to:",
|
||||
u8" Josef Drexler - For his great work on TTDPatch",
|
||||
u8" Marcin Grzegorczyk - Track foundations and for describing TTD internals",
|
||||
u8" Stefan Mei\u00dfner (sign_de) - For his work on the console",
|
||||
u8" Mike Ragsdale - OpenTTD installer",
|
||||
u8" Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
|
||||
u8" Richard Kempton (richK) - additional airports, initial TGP implementation",
|
||||
u8"",
|
||||
u8" Alberto Demichelis - Squirrel scripting language \u00a9 2003-2008",
|
||||
u8" L. Peter Deutsch - MD5 implementation \u00a9 1999, 2000, 2002",
|
||||
u8" Michael Blunck - Pre-signals and semaphores \u00a9 2003",
|
||||
u8" George - Canal/Lock graphics \u00a9 2003-2004",
|
||||
u8" Andrew Parkhouse (andythenorth) - River graphics",
|
||||
u8" David Dallaston (Pikka) - Tram tracks",
|
||||
u8" All Translators - Who made OpenTTD a truly international game",
|
||||
u8" Bug Reporters - Without whom OpenTTD would still be full of bugs!",
|
||||
u8"",
|
||||
u8"",
|
||||
u8"Developer of this patchpack:",
|
||||
u8" Jonathan G. Rennison (JGR)",
|
||||
u8"",
|
||||
u8"",
|
||||
u8"And last but not least:",
|
||||
u8" Chris Sawyer - For an amazing game!"
|
||||
};
|
||||
|
||||
struct AboutWindow : public Window {
|
||||
|
@@ -265,6 +265,18 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
this->address_length = (int)runp->ai_addrlen;
|
||||
assert(sizeof(this->address) >= runp->ai_addrlen);
|
||||
memcpy(&this->address, runp->ai_addr, runp->ai_addrlen);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten doesn't zero sin_zero, but as we compare addresses
|
||||
* to see if they are the same address, we need them to be zero'd.
|
||||
* Emscripten is, as far as we know, the only OS not doing this.
|
||||
*
|
||||
* https://github.com/emscripten-core/emscripten/issues/12998
|
||||
*/
|
||||
if (this->address.ss_family == AF_INET) {
|
||||
sockaddr_in *address_ipv4 = (sockaddr_in *)&this->address;
|
||||
memset(address_ipv4->sin_zero, 0, sizeof(address_ipv4->sin_zero));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -297,7 +309,15 @@ static SOCKET ConnectLoopProc(addrinfo *runp)
|
||||
|
||||
if (!SetNoDelay(sock)) DEBUG(net, 1, "[%s] setting TCP_NODELAY failed", type);
|
||||
|
||||
if (connect(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) {
|
||||
int err = connect(sock, runp->ai_addr, (int)runp->ai_addrlen);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten is asynchronous, and as such a connect() is still in
|
||||
* progress by the time the call returns. */
|
||||
if (err != 0 && errno != EINPROGRESS)
|
||||
#else
|
||||
if (err != 0)
|
||||
#endif
|
||||
{
|
||||
DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, strerror(errno));
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
|
@@ -99,6 +99,16 @@ typedef unsigned long in_addr_t;
|
||||
# include <errno.h>
|
||||
# include <sys/time.h>
|
||||
# include <netdb.h>
|
||||
|
||||
# if defined(__EMSCRIPTEN__)
|
||||
/* Emscripten doesn't support AI_ADDRCONFIG and errors out on it. */
|
||||
# undef AI_ADDRCONFIG
|
||||
# define AI_ADDRCONFIG 0
|
||||
/* Emscripten says it supports FD_SETSIZE fds, but it really only supports 64.
|
||||
* https://github.com/emscripten-core/emscripten/issues/1711 */
|
||||
# undef FD_SETSIZE
|
||||
# define FD_SETSIZE 64
|
||||
# endif
|
||||
#endif /* UNIX */
|
||||
|
||||
/* OS/2 stuff */
|
||||
@@ -160,6 +170,28 @@ typedef unsigned long in_addr_t;
|
||||
|
||||
#endif /* OS/2 */
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/**
|
||||
* Emscripten doesn't set 'addrlen' for accept(), getsockname(), getpeername()
|
||||
* and recvfrom(), which confuses other functions and causes them to crash.
|
||||
* This function needs to be called after these four functions to make sure
|
||||
* 'addrlen' is patched up.
|
||||
*
|
||||
* https://github.com/emscripten-core/emscripten/issues/12996
|
||||
*
|
||||
* @param address The address returned by those four functions.
|
||||
* @return The correct value for addrlen.
|
||||
*/
|
||||
static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address)
|
||||
{
|
||||
switch (address.ss_family) {
|
||||
case AF_INET6: return sizeof(struct sockaddr_in6);
|
||||
case AF_INET: return sizeof(struct sockaddr_in);
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Try to set the socket into non-blocking mode.
|
||||
* @param d The socket to set the non-blocking more for.
|
||||
@@ -167,12 +199,16 @@ typedef unsigned long in_addr_t;
|
||||
*/
|
||||
static inline bool SetNonBlocking(SOCKET d)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
u_long nonblocking = 1;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return true;
|
||||
#else
|
||||
# ifdef _WIN32
|
||||
u_long nonblocking = 1;
|
||||
# else
|
||||
int nonblocking = 1;
|
||||
#endif
|
||||
# endif
|
||||
return ioctlsocket(d, FIONBIO, &nonblocking) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,10 +233,14 @@ static inline bool SetBlocking(SOCKET d)
|
||||
*/
|
||||
static inline bool SetNoDelay(SOCKET d)
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return true;
|
||||
#else
|
||||
/* XXX should this be done at all? */
|
||||
int b = 1;
|
||||
/* The (const char*) cast is needed for windows */
|
||||
return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@@ -42,6 +42,9 @@ public:
|
||||
socklen_t sin_len = sizeof(sin);
|
||||
SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
|
||||
if (s == INVALID_SOCKET) return;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
sin_len = FixAddrLenForEmscripten(sin);
|
||||
#endif
|
||||
|
||||
SetNonBlocking(s); // XXX error handling?
|
||||
|
||||
|
@@ -164,6 +164,9 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
||||
/* Did we get the bytes for the base header of the packet? */
|
||||
if (nbytes <= 0) break; // No data, i.e. no packet
|
||||
if (nbytes <= 2) continue; // Invalid data; try next packet
|
||||
#ifdef __EMSCRIPTEN__
|
||||
client_len = FixAddrLenForEmscripten(client_addr);
|
||||
#endif
|
||||
|
||||
NetworkAddress address(client_addr, client_len);
|
||||
p.PrepareToRead();
|
||||
|
@@ -1122,3 +1122,14 @@ bool IsNetworkCompatibleVersion(const char *other, bool extended)
|
||||
{
|
||||
return strncmp(_openttd_revision, other, (extended ? NETWORK_LONG_REVISION_LENGTH : NETWORK_REVISION_LENGTH) - 1) == 0;
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
extern "C" {
|
||||
|
||||
void CDECL em_openttd_add_server(const char *host, int port)
|
||||
{
|
||||
NetworkUDPQueryServer(NetworkAddress(host, port), true);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@@ -23,6 +23,10 @@
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
extern bool HasScenario(const ContentInfo *ci, bool md5sum);
|
||||
@@ -296,6 +300,13 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin
|
||||
{
|
||||
bytes = 0;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten is loaded via an HTTPS connection. As such, it is very
|
||||
* difficult to make HTTP connections. So always use the TCP method of
|
||||
* downloading content. */
|
||||
fallback = true;
|
||||
#endif
|
||||
|
||||
ContentIDList content;
|
||||
for (const ContentInfo *ci : this->infos) {
|
||||
if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue;
|
||||
@@ -542,6 +553,10 @@ void ClientNetworkContentSocketHandler::AfterDownload()
|
||||
unlink(GetFullFilename(this->curInfo, false));
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
|
||||
#endif
|
||||
|
||||
this->OnDownloadComplete(this->curInfo->id);
|
||||
} else {
|
||||
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR);
|
||||
|
@@ -41,6 +41,9 @@
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
#endif
|
||||
|
||||
static void ShowNetworkStartServerWindow();
|
||||
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
|
||||
@@ -490,6 +493,14 @@ public:
|
||||
this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
|
||||
this->SetFocusedWidget(WID_NG_FILTER);
|
||||
|
||||
/* As the master-server doesn't support "websocket" servers yet, we
|
||||
* let "os/emscripten/pre.js" hardcode a list of servers people can
|
||||
* join. This means the serverlist is curated for now, but it is the
|
||||
* best we can offer. */
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
|
||||
#endif
|
||||
|
||||
this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
|
||||
this->server = this->last_joined;
|
||||
if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address);
|
||||
@@ -630,6 +641,12 @@ public:
|
||||
this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr);
|
||||
this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr || !sel->info.version_compatible || sel->info.compatible);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
this->SetWidgetDisabledState(WID_NG_FIND, true);
|
||||
this->SetWidgetDisabledState(WID_NG_ADD, true);
|
||||
this->SetWidgetDisabledState(WID_NG_START, true);
|
||||
#endif
|
||||
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
|
@@ -1951,8 +1951,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, cons
|
||||
tmp_layout.clear();
|
||||
for (;;) {
|
||||
/* no relative bounding box support */
|
||||
/*C++17: DrawTileSeqStruct &dtss = */ tmp_layout.emplace_back();
|
||||
DrawTileSeqStruct &dtss = tmp_layout.back();
|
||||
DrawTileSeqStruct &dtss = tmp_layout.emplace_back();
|
||||
MemSetT(&dtss, 0);
|
||||
|
||||
dtss.delta_x = buf->ReadByte();
|
||||
@@ -5159,8 +5158,7 @@ static void NewSpriteGroup(ByteReader *buf)
|
||||
/* Loop through the var adjusts. Unfortunately we don't know how many we have
|
||||
* from the outset, so we shall have to keep reallocing. */
|
||||
do {
|
||||
/*C++17: DeterministicSpriteGroupAdjust &adjust = */ adjusts.emplace_back();
|
||||
DeterministicSpriteGroupAdjust &adjust = adjusts.back();
|
||||
DeterministicSpriteGroupAdjust &adjust = adjusts.emplace_back();
|
||||
|
||||
/* The first var adjust doesn't have an operation specified, so we set it to add. */
|
||||
adjust.operation = adjusts.size() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf->ReadByte();
|
||||
|
@@ -664,8 +664,7 @@ uint32 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_groun
|
||||
|
||||
/* Create a copy of the spritelayout, so we can modify some values.
|
||||
* Also include the groundsprite into the sequence for easier processing. */
|
||||
/*C++17: DrawTileSeqStruct *result = &*/ result_seq.emplace_back();
|
||||
DrawTileSeqStruct *result = &result_seq.back();
|
||||
DrawTileSeqStruct *result = &result_seq.emplace_back();
|
||||
result->image = ground;
|
||||
result->delta_x = 0;
|
||||
result->delta_y = 0;
|
||||
@@ -675,8 +674,7 @@ uint32 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_groun
|
||||
foreach_draw_tile_seq(dtss, this->seq) {
|
||||
result_seq.push_back(*dtss);
|
||||
}
|
||||
result_seq.emplace_back() /*C++17: .MakeTerminator()*/;
|
||||
result_seq.back().MakeTerminator();
|
||||
result_seq.emplace_back().MakeTerminator();
|
||||
/* Determine the var10 values the action-1-2-3 chains needs to be resolved for,
|
||||
* and apply the default sprite offsets (unless disabled). */
|
||||
const TileLayoutRegisters *regs = this->registers;
|
||||
|
@@ -87,6 +87,11 @@
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
# include <emscripten/html5.h>
|
||||
#endif
|
||||
|
||||
void CallLandscapeTick();
|
||||
void IncreaseDate();
|
||||
void MusicLoop();
|
||||
@@ -123,6 +128,15 @@ void CDECL usererror(const char *s, ...)
|
||||
ShowOSErrorBox(buf, false);
|
||||
if (VideoDriver::GetInstance() != nullptr) VideoDriver::GetInstance()->Stop();
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_exit_pointerlock();
|
||||
/* In effect, the game ends here. As emscripten_set_main_loop() caused
|
||||
* the stack to be unwound, the code after MainLoop() in
|
||||
* openttd_main() is never executed. */
|
||||
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
|
||||
EM_ASM(if (window["openttd_abort"]) openttd_abort());
|
||||
#endif
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@@ -3293,8 +3293,7 @@ bool AfterLoadGame()
|
||||
cur_skip = prev_tile_skip;
|
||||
}
|
||||
|
||||
/*C++17: uint &this_skip = */ skip_frames.push_back(prev_tile_skip);
|
||||
uint &this_skip = skip_frames.back();
|
||||
uint &this_skip = skip_frames.emplace_back(prev_tile_skip);
|
||||
|
||||
/* The following 3 curves now take longer than before */
|
||||
switch (u->state) {
|
||||
|
@@ -191,8 +191,7 @@ static void Load_EIDS()
|
||||
_engine_mngr.clear();
|
||||
|
||||
while (SlIterateArray() != -1) {
|
||||
/*C++17: EngineIDMapping *eid = &*/ _engine_mngr.emplace_back();
|
||||
EngineIDMapping *eid = &_engine_mngr.back();
|
||||
EngineIDMapping *eid = &_engine_mngr.emplace_back();
|
||||
SlObject(eid, _engine_id_mapping_desc);
|
||||
}
|
||||
}
|
||||
|
@@ -46,6 +46,9 @@
|
||||
#include "../scope.h"
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "../tbtr_template_vehicle.h"
|
||||
|
||||
@@ -2928,6 +2931,10 @@ static void SaveFileDone()
|
||||
|
||||
InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
|
||||
_sl.saveinprogress = false;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friends) */
|
||||
|
@@ -192,8 +192,7 @@ static void Load_WAYP()
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
/*C++17: OldWaypoint *wp = &*/ _old_waypoints.emplace_back();
|
||||
OldWaypoint *wp = &_old_waypoints.back();
|
||||
OldWaypoint *wp = &_old_waypoints.emplace_back();
|
||||
|
||||
wp->index = index;
|
||||
SlObject(wp, _old_waypoint_desc);
|
||||
|
@@ -1,5 +1,9 @@
|
||||
add_subdirectory(api)
|
||||
|
||||
if(OPTION_TOOLS_ONLY)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_files(
|
||||
script_config.cpp
|
||||
script_config.hpp
|
||||
|
@@ -131,6 +131,10 @@ foreach(API "ai;AI" "game;GS" "template;Template")
|
||||
)
|
||||
endforeach()
|
||||
|
||||
if(OPTION_TOOLS_ONLY)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_library(openttd::script_api ALIAS script_api)
|
||||
|
||||
|
||||
|
@@ -118,8 +118,7 @@ public:
|
||||
text += stored_size;
|
||||
}
|
||||
while (length > 0) {
|
||||
/*C++17: OutputBuffer &block =*/ this->output_buffer.emplace_back();
|
||||
OutputBuffer &block = this->output_buffer.back();
|
||||
OutputBuffer &block = this->output_buffer.emplace_back();
|
||||
block.Clear(); // Initialize the new block.
|
||||
size_t stored_size = block.Add(text, length);
|
||||
length -= stored_size;
|
||||
|
@@ -22,6 +22,10 @@ if (NOT HOST_BINARY_DIR)
|
||||
add_dependencies(tools strgen)
|
||||
endif()
|
||||
|
||||
if(OPTION_TOOLS_ONLY)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Source Files
|
||||
add_files(strgen_base.cpp)
|
||||
|
||||
|
@@ -15,10 +15,10 @@
|
||||
#include <string>
|
||||
|
||||
/** A non-breaking space. */
|
||||
#define NBSP "\xC2\xA0"
|
||||
#define NBSP u8"\u00a0"
|
||||
|
||||
/** A left-to-right marker, marks the next character as left-to-right. */
|
||||
#define LRM "\xE2\x80\x8E"
|
||||
#define LRM u8"\u200e"
|
||||
|
||||
/**
|
||||
* Valid filter types for IsValidChar.
|
||||
|
@@ -74,8 +74,7 @@ void StringFilter::SetFilterTerm(const char *str)
|
||||
|
||||
/* Add to word */
|
||||
if (word == nullptr) {
|
||||
/*C++17: word = &*/ this->word_index.push_back({dest, false});
|
||||
word = &this->word_index.back();
|
||||
word = &this->word_index.emplace_back(WordState{ dest, false });
|
||||
}
|
||||
|
||||
memcpy(dest, pos, len);
|
||||
|
@@ -1758,6 +1758,11 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg
|
||||
int64 args_array[] = {(int64)(size_t)v->name.c_str()};
|
||||
StringParameters tmp_params(args_array);
|
||||
buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
|
||||
} else if (v->group_id != DEFAULT_GROUP) {
|
||||
/* The vehicle has no name, but is member of a group, so print group name */
|
||||
int64 args_array[] = {v->group_id, v->unitnumber};
|
||||
StringParameters tmp_params(args_array);
|
||||
buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_VEHICLE_NAME, &tmp_params, last);
|
||||
} else {
|
||||
int64 args_array[] = {v->unitnumber};
|
||||
StringParameters tmp_params(args_array);
|
||||
|
1150
src/table/townname.h
1150
src/table/townname.h
File diff suppressed because it is too large
Load Diff
@@ -359,7 +359,7 @@ static void Xunzip(byte **bufp, size_t *sizep)
|
||||
}
|
||||
|
||||
/* Check for the byte-order-mark, and skip it if needed. */
|
||||
char *p = this->text + (strncmp("\xEF\xBB\xBF", this->text, 3) == 0 ? 3 : 0);
|
||||
char *p = this->text + (strncmp(u8"\ufeff", this->text, 3) == 0 ? 3 : 0);
|
||||
|
||||
/* Make sure the string is a valid UTF-8 sequence. */
|
||||
str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
|
||||
|
@@ -505,7 +505,7 @@ static char *MakeFinnishTownName(char *buf, const char *last, uint32 seed)
|
||||
strstr(orig, "A") != nullptr || strstr(orig, "O") != nullptr || strstr(orig, "U") != nullptr) {
|
||||
buf = strecpy(buf, "la", last);
|
||||
} else {
|
||||
buf = strecpy(buf, "l\xC3\xA4", last);
|
||||
buf = strecpy(buf, u8"l\u00e4", last);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
@@ -1013,8 +1013,7 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
|
||||
* Do this for all tiles (like trees), not only objects. */
|
||||
ClearedObjectArea *coa = FindClearedObject(end_tile);
|
||||
if (coa == nullptr) {
|
||||
/*C++17: coa = &*/ _cleared_object_areas.push_back({end_tile, TileArea(end_tile, 1, 1)});
|
||||
coa = &_cleared_object_areas.back();
|
||||
coa = &_cleared_object_areas.emplace_back(ClearedObjectArea{ end_tile, TileArea(end_tile, 1, 1) });
|
||||
}
|
||||
|
||||
/* Hide the tile from the terraforming command */
|
||||
|
@@ -31,6 +31,10 @@
|
||||
#include "../3rdparty/mingw-std-threads/mingw.mutex.h"
|
||||
#include "../3rdparty/mingw-std-threads/mingw.condition_variable.h"
|
||||
#endif
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
# include <emscripten/html5.h>
|
||||
#endif
|
||||
|
||||
#if defined(WITH_FCITX)
|
||||
#include <fcitx/frontend.h>
|
||||
@@ -61,6 +65,11 @@ static volatile bool _draw_continue;
|
||||
static Palette _local_palette;
|
||||
static SDL_Palette *_sdl_palette;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/** Whether we just had a window-enter event. */
|
||||
static bool _cursor_new_in_window = false;
|
||||
#endif
|
||||
|
||||
#define MAX_DIRTY_RECTS 100
|
||||
static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS];
|
||||
static int _num_dirty_rects;
|
||||
@@ -578,6 +587,9 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h, bool resize)
|
||||
bool VideoDriver_SDL::ClaimMousePointer()
|
||||
{
|
||||
SDL_ShowCursor(0);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -796,9 +808,27 @@ int VideoDriver_SDL::PollEvent()
|
||||
|
||||
switch (ev.type) {
|
||||
case SDL_MOUSEMOTION:
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (_cursor_new_in_window) {
|
||||
/* The cursor just moved into the window; this means we don't
|
||||
* know the absolutely position yet to move relative from.
|
||||
* Before this time, SDL didn't know it either, and this is
|
||||
* why we postpone it till now. Update the absolute position
|
||||
* for this once, and work relative after. */
|
||||
_cursor.pos.x = ev.motion.x;
|
||||
_cursor.pos.y = ev.motion.y;
|
||||
_cursor.dirty = true;
|
||||
|
||||
_cursor_new_in_window = false;
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
} else {
|
||||
_cursor.UpdateCursorPositionRelative(ev.motion.xrel, ev.motion.yrel);
|
||||
}
|
||||
#else
|
||||
if (_cursor.UpdateCursorPosition(ev.motion.x, ev.motion.y, true)) {
|
||||
SDL_WarpMouseInWindow(_sdl_window, _cursor.pos.x, _cursor.pos.y);
|
||||
}
|
||||
#endif
|
||||
HandleMouseEvents();
|
||||
break;
|
||||
|
||||
@@ -932,6 +962,12 @@ int VideoDriver_SDL::PollEvent()
|
||||
} else if (ev.window.event == SDL_WINDOWEVENT_ENTER) {
|
||||
// mouse entered the window, enable cursor
|
||||
_cursor.in_window = true;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Disable relative mouse mode for the first mouse motion,
|
||||
* so we can pick up the absolutely position again. */
|
||||
_cursor_new_in_window = true;
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
#endif
|
||||
} else if (ev.window.event == SDL_WINDOWEVENT_LEAVE) {
|
||||
// mouse left the window, undraw cursor
|
||||
UndrawMouseCursor();
|
||||
@@ -968,7 +1004,8 @@ const char *VideoDriver_SDL::Start(const StringList &parm)
|
||||
/* Explicitly disable hardware acceleration. Enabling this causes
|
||||
* UpdateWindowSurface() to update the window's texture instead of
|
||||
* its surface. */
|
||||
SDL_SetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION , "0");
|
||||
SDL_SetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION, "0");
|
||||
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
|
||||
|
||||
/* Just on the offchance the audio subsystem started before the video system,
|
||||
* check whether any part of SDL has been initialised before getting here.
|
||||
@@ -1012,19 +1049,114 @@ void VideoDriver_SDL::Stop()
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver_SDL::MainLoop()
|
||||
void VideoDriver_SDL::LoopOnce()
|
||||
{
|
||||
uint32 cur_ticks = SDL_GetTicks();
|
||||
uint32 last_cur_ticks = cur_ticks;
|
||||
uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK;
|
||||
uint32 mod;
|
||||
int numkeys;
|
||||
const Uint8 *keys;
|
||||
uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
|
||||
InteractiveRandom(); // randomness
|
||||
|
||||
while (PollEvent() == -1) {}
|
||||
if (_exit_game) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten is event-driven, and as such the main loop is inside
|
||||
* the browser. So if _exit_game goes true, the main loop ends (the
|
||||
* cancel call), but we still have to call the cleanup that is
|
||||
* normally done at the end of the main loop for non-Emscripten.
|
||||
* After that, Emscripten just halts, and the HTML shows a nice
|
||||
* "bye, see you next time" message. */
|
||||
emscripten_cancel_main_loop();
|
||||
MainLoopCleanup();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
mod = SDL_GetModState();
|
||||
keys = SDL_GetKeyboardState(&numkeys);
|
||||
|
||||
#if defined(_DEBUG)
|
||||
if (_shift_pressed)
|
||||
#else
|
||||
/* Speedup when pressing tab, except when using ALT+TAB
|
||||
* to switch to another application */
|
||||
if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0)
|
||||
#endif /* defined(_DEBUG) */
|
||||
{
|
||||
if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
|
||||
} else if (_fast_forward & 2) {
|
||||
_fast_forward = 0;
|
||||
}
|
||||
|
||||
cur_ticks = SDL_GetTicks();
|
||||
if (SDL_TICKS_PASSED(cur_ticks, next_tick) || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) {
|
||||
_realtime_tick += cur_ticks - last_cur_ticks;
|
||||
last_cur_ticks = cur_ticks;
|
||||
next_tick = cur_ticks + MILLISECONDS_PER_TICK;
|
||||
|
||||
bool old_ctrl_pressed = _ctrl_pressed;
|
||||
bool old_shift_pressed = _shift_pressed;
|
||||
|
||||
_ctrl_pressed = !!(mod & KMOD_CTRL) != _invert_ctrl;
|
||||
_shift_pressed = !!(mod & KMOD_SHIFT) != _invert_shift;
|
||||
|
||||
/* determine which directional keys are down */
|
||||
_dirkeys =
|
||||
(keys[SDL_SCANCODE_LEFT] ? 1 : 0) |
|
||||
(keys[SDL_SCANCODE_UP] ? 2 : 0) |
|
||||
(keys[SDL_SCANCODE_RIGHT] ? 4 : 0) |
|
||||
(keys[SDL_SCANCODE_DOWN] ? 8 : 0);
|
||||
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
|
||||
if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
|
||||
|
||||
/* The gameloop is the part that can run asynchronously. The rest
|
||||
* except sleeping can't. */
|
||||
if (_draw_mutex != nullptr) draw_lock.unlock();
|
||||
|
||||
GameLoop();
|
||||
|
||||
if (_draw_mutex != nullptr) draw_lock.lock();
|
||||
|
||||
GameLoopPaletteAnimations();
|
||||
|
||||
UpdateWindows();
|
||||
_local_palette = _cur_palette;
|
||||
} else {
|
||||
/* Release the thread while sleeping */
|
||||
if (_draw_mutex != nullptr) {
|
||||
draw_lock.unlock();
|
||||
CSleep(1);
|
||||
draw_lock.lock();
|
||||
} else {
|
||||
/* Emscripten is running an event-based mainloop; there is already some
|
||||
* downtime between each iteration, so no need to sleep. */
|
||||
#ifndef __EMSCRIPTEN__
|
||||
CSleep(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
NetworkDrawChatMessage();
|
||||
DrawMouseCursor();
|
||||
}
|
||||
|
||||
/* End of the critical part. */
|
||||
if (_draw_mutex != nullptr && !HasModalProgress()) {
|
||||
_draw_signal->notify_one();
|
||||
} else {
|
||||
/* Oh, we didn't have threads, then just draw unthreaded */
|
||||
CheckPaletteAnim();
|
||||
DrawSurfaceToScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver_SDL::MainLoop()
|
||||
{
|
||||
cur_ticks = SDL_GetTicks();
|
||||
last_cur_ticks = cur_ticks;
|
||||
next_tick = cur_ticks + MILLISECONDS_PER_TICK;
|
||||
|
||||
CheckPaletteAnim();
|
||||
|
||||
std::thread draw_thread;
|
||||
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||
if (_draw_threaded) {
|
||||
/* Initialise the mutex first, because that's the thing we *need*
|
||||
* directly in the newly created thread. */
|
||||
@@ -1055,82 +1187,20 @@ void VideoDriver_SDL::MainLoop()
|
||||
|
||||
DEBUG(driver, 1, "SDL2: using %sthreads", _draw_threaded ? "" : "no ");
|
||||
|
||||
for (;;) {
|
||||
uint32 prev_cur_ticks = cur_ticks; // to check for wrapping
|
||||
InteractiveRandom(); // randomness
|
||||
|
||||
while (PollEvent() == -1) {}
|
||||
if (_exit_game) break;
|
||||
|
||||
mod = SDL_GetModState();
|
||||
keys = SDL_GetKeyboardState(&numkeys);
|
||||
|
||||
#if defined(_DEBUG)
|
||||
if (_shift_pressed)
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Run the main loop event-driven, based on RequestAnimationFrame. */
|
||||
emscripten_set_main_loop_arg(&this->EmscriptenLoop, this, 0, 1);
|
||||
#else
|
||||
/* Speedup when pressing tab, except when using ALT+TAB
|
||||
* to switch to another application */
|
||||
if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0)
|
||||
#endif /* defined(_DEBUG) */
|
||||
{
|
||||
if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
|
||||
} else if (_fast_forward & 2) {
|
||||
_fast_forward = 0;
|
||||
}
|
||||
|
||||
cur_ticks = SDL_GetTicks();
|
||||
if (SDL_TICKS_PASSED(cur_ticks, next_tick) || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) {
|
||||
_realtime_tick += cur_ticks - last_cur_ticks;
|
||||
last_cur_ticks = cur_ticks;
|
||||
next_tick = cur_ticks + MILLISECONDS_PER_TICK;
|
||||
|
||||
bool old_ctrl_pressed = _ctrl_pressed;
|
||||
bool old_shift_pressed = _shift_pressed;
|
||||
|
||||
_ctrl_pressed = !!(mod & KMOD_CTRL) != _invert_ctrl;
|
||||
_shift_pressed = !!(mod & KMOD_SHIFT) != _invert_shift;
|
||||
|
||||
/* determine which directional keys are down */
|
||||
_dirkeys =
|
||||
(keys[SDL_SCANCODE_LEFT] ? 1 : 0) |
|
||||
(keys[SDL_SCANCODE_UP] ? 2 : 0) |
|
||||
(keys[SDL_SCANCODE_RIGHT] ? 4 : 0) |
|
||||
(keys[SDL_SCANCODE_DOWN] ? 8 : 0);
|
||||
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
|
||||
if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
|
||||
|
||||
/* The gameloop is the part that can run asynchronously. The rest
|
||||
* except sleeping can't. */
|
||||
if (_draw_mutex != nullptr) draw_lock.unlock();
|
||||
|
||||
GameLoop();
|
||||
|
||||
if (_draw_mutex != nullptr) draw_lock.lock();
|
||||
|
||||
GameLoopPaletteAnimations();
|
||||
|
||||
UpdateWindows();
|
||||
_local_palette = _cur_palette;
|
||||
} else {
|
||||
/* Release the thread while sleeping */
|
||||
if (_draw_mutex != nullptr) draw_lock.unlock();
|
||||
CSleep(1);
|
||||
if (_draw_mutex != nullptr) draw_lock.lock();
|
||||
|
||||
NetworkDrawChatMessage();
|
||||
DrawMouseCursor();
|
||||
}
|
||||
|
||||
/* End of the critical part. */
|
||||
if (_draw_mutex != nullptr && !HasModalProgress()) {
|
||||
_draw_signal->notify_one();
|
||||
} else {
|
||||
/* Oh, we didn't have threads, then just draw unthreaded */
|
||||
CheckPaletteAnim();
|
||||
DrawSurfaceToScreen();
|
||||
}
|
||||
while (!_exit_game) {
|
||||
LoopOnce();
|
||||
}
|
||||
|
||||
MainLoopCleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void VideoDriver_SDL::MainLoopCleanup()
|
||||
{
|
||||
if (_draw_mutex != nullptr) {
|
||||
_draw_continue = false;
|
||||
/* Sending signal if there is no thread blocked
|
||||
@@ -1146,6 +1216,15 @@ void VideoDriver_SDL::MainLoop()
|
||||
_draw_mutex = nullptr;
|
||||
_draw_signal = nullptr;
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_exit_pointerlock();
|
||||
/* In effect, the game ends here. As emscripten_set_main_loop() caused
|
||||
* the stack to be unwound, the code after MainLoop() in
|
||||
* openttd_main() is never executed. */
|
||||
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
|
||||
EM_ASM(if (window["openttd_exit"]) openttd_exit());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VideoDriver_SDL::ChangeResolution(int w, int h)
|
||||
|
@@ -42,12 +42,26 @@ public:
|
||||
const char *GetName() const override { return "sdl"; }
|
||||
private:
|
||||
int PollEvent();
|
||||
void LoopOnce();
|
||||
void MainLoopCleanup();
|
||||
bool CreateMainSurface(uint w, uint h, bool resize);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Convert a constant pointer back to a non-constant pointer to a member function. */
|
||||
static void EmscriptenLoop(void *self) { ((VideoDriver_SDL *)self)->LoopOnce(); }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is true to indicate that keyboard input is in text input mode, and SDL_TEXTINPUT events are enabled.
|
||||
*/
|
||||
bool edit_box_focused;
|
||||
|
||||
uint32 cur_ticks;
|
||||
uint32 last_cur_ticks;
|
||||
uint32 next_tick;
|
||||
|
||||
std::thread draw_thread;
|
||||
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||
};
|
||||
|
||||
/** Factory for the SDL video driver. */
|
||||
|
@@ -816,8 +816,7 @@ static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y,
|
||||
{
|
||||
assert((image & SPRITE_MASK) < MAX_SPRITES);
|
||||
|
||||
/*C++17: TileSpriteToDraw &ts = */ _vd.tile_sprites_to_draw.emplace_back();
|
||||
TileSpriteToDraw &ts = _vd.tile_sprites_to_draw.back();
|
||||
TileSpriteToDraw &ts = _vd.tile_sprites_to_draw.emplace_back();
|
||||
ts.image = image;
|
||||
ts.pal = pal;
|
||||
ts.sub = sub;
|
||||
@@ -1038,8 +1037,7 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w,
|
||||
return;
|
||||
}
|
||||
|
||||
/*C++17: ParentSpriteToDraw &ps = */ _vd.parent_sprites_to_draw.emplace_back();
|
||||
ParentSpriteToDraw &ps = _vd.parent_sprites_to_draw.back();
|
||||
ParentSpriteToDraw &ps = _vd.parent_sprites_to_draw.emplace_back();
|
||||
ps.x = tmp_x;
|
||||
ps.y = tmp_y;
|
||||
|
||||
@@ -1180,8 +1178,7 @@ void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool tran
|
||||
|
||||
*_vd.last_child = (uint)_vd.child_screen_sprites_to_draw.size();
|
||||
|
||||
/*C++17: ChildScreenSpriteToDraw &cs = */ _vd.child_screen_sprites_to_draw.emplace_back();
|
||||
ChildScreenSpriteToDraw &cs = _vd.child_screen_sprites_to_draw.back();
|
||||
ChildScreenSpriteToDraw &cs = _vd.child_screen_sprites_to_draw.emplace_back();
|
||||
cs.image = image;
|
||||
cs.pal = pal;
|
||||
cs.sub = sub;
|
||||
@@ -1201,8 +1198,7 @@ void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool tran
|
||||
static void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width)
|
||||
{
|
||||
assert(width != 0);
|
||||
/*C++17: StringSpriteToDraw &ss = */ _vd.string_sprites_to_draw.emplace_back();
|
||||
StringSpriteToDraw &ss = _vd.string_sprites_to_draw.back();
|
||||
StringSpriteToDraw &ss = _vd.string_sprites_to_draw.emplace_back();
|
||||
ss.string = string;
|
||||
ss.x = x;
|
||||
ss.y = y;
|
||||
|
Reference in New Issue
Block a user