Compare commits

..
Author SHA1 Message Date
Tyler Blount 6b7fc0b6a3 Don't reset target restrictions during table load
Prevents an issue with load order causing target restrictions to be reset.
2020-05-20 14:45:24 -06:00
Tyler Blount 2e4bef0d09 Remove unneeded code and some style changes 2020-05-20 12:25:13 -06:00
Tyler Blount 172952cb0f Correctly implement fixes from #73 2020-05-20 12:25:13 -06:00
Tyler Blount 72c27bdbe8 CI and Lock fixes 2020-05-20 12:25:13 -06:00
Tyler Blount bd4de16007 Use correct comparison 2020-05-20 12:25:13 -06:00
Tyler Blount 2e560f2ddb Fix some CI errors 2020-05-20 12:25:12 -06:00
Tyler Blount d35d3d25f8 Finally fix no dumbfire
also some miscellaneous changes
2020-05-20 12:25:12 -06:00
Tyler Blount 2d5111f14b Perhaps this works? 2020-05-20 12:25:12 -06:00
Tyler Blount d95754d6b4 No Dumbfire fix
Another fix for MLMs associated with the No Dumbfire flag.
2020-05-20 12:25:12 -06:00
Tyler Blount 5e3d4c6cfd More fixes
Contains changes related to failed CI builds and feedback.
2020-05-20 12:25:12 -06:00
Tyler Blount deca820c9e Lost fixes
These were lost during a rebase at one point. Will leave this commit as separate to avoid issues in the future.
2020-05-20 12:25:12 -06:00
Swifty 21c298271b Initial commit of multilock missile features. 2020-05-20 12:25:11 -06:00
1305 changed files with 41826 additions and 127604 deletions

No files matched your search

+4 -5
View File
@@ -3,18 +3,17 @@ Language: Cpp
Standard: Cpp11
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: true
AllowAllArgumentsOnNextLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
+5 -6
View File
@@ -1,22 +1,20 @@
---
Checks: "-*,\
modernize-*,\
-modernize-avoid-c-arrays,\
-modernize-make-unique,\
-modernize-raw-string-literal,\
-modernize-use-trailing-return-type,\
-modernize-use-using,\
-modernize-make-unique,\
-modernize-use-trailing-return-type,\
-modernize-avoid-c-arrays,\
performance-*,\
-performance-type-promotion-in-math-fn,\
misc-*,\
-misc-macro-parentheses,\
-misc-misplaced-widening-cast,\
-misc-non-private-member-variables-in-classes,\
-misc-static-assert,\
-misc-unused-parameters,\
-misc-non-private-member-variables-in-classes,\
readability-*,\
-readability-avoid-const-params-in-decls,\
-readability-else-after-return,\
-readability-function-size,\
-readability-identifier-naming,\
-readability-implicit-bool-conversion,\
@@ -26,6 +24,7 @@ readability-*,\
-readability-named-parameter,\
-readability-qualified-auto,\
-readability-uppercase-literal-suffix,\
-readability-else-after-return,\
"
WarningsAsErrors: ''
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
-4
View File
@@ -9,7 +9,3 @@ indent_style = tab
[*.{yml,yaml}]
indent_style = space
indent_size = 2
[*.sh]
indent_style = space
indent_size = 4
-10
View File
@@ -1,10 +0,0 @@
cmake/ @asarium
code/executor/ @asarium
code/scpui/ @asarium
code/scripting/ @asarium
code/controlconfig/ @z64555
-237
View File
@@ -1,237 +0,0 @@
name: Build Nightly package
on:
push:
tags:
- 'nightly_*'
env:
QT_VERSION: 5.12.9
jobs:
build_linux:
strategy:
matrix:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: |
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Generate AppImage
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: linux-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/install/*.AppImage
linux_zip:
name: Build Linux distribution zip
needs: build_linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0'
- name: Download Release builds
uses: actions/download-artifact@v1
with:
name: linux-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: linux-FastDebug
path: builds
- name: Create Distribution package
working-directory: ./builds
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
- name: Upload result package
working-directory: ./builds
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh nightly
build_windows:
strategy:
matrix:
configuration: [FastDebug, Release]
arch: [Win32, x64]
simd: [SSE2]
name: Windows
runs-on: windows-2019
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'Win32' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win32_msvc2017
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'x64' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win64_msvc2017_64
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCHITECTURE: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
shell: bash
run: |
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=ON -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" --target INSTALL -- /verbosity:minimal
ls -alR "$(pwd)/install"
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
windows_zip:
name: Build Windows distribution zip
needs: build_windows
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [Win32, x64]
simd: [SSE2]
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0'
- name: Download Release builds
uses: actions/download-artifact@v1
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Create Distribution package
working-directory: ./builds
shell: bash
env:
ARCH: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
- name: Upload result package
working-directory: ./builds
shell: bash
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh nightly
post_builds:
# Post nightlies if at least one job was successful
if: ${{ needs.linux_zip == "success" || needs.windows_zip == "success" }}
name: Post builds on Nebula and the forums
needs: [linux_zip, windows_zip]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
name: Checkout
with:
fetch-depth: '0'
- name: Install Python dependencies
run: pip install -r ci/post/requirements.txt
- name: Post builds
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
NEBULA_USER: ${{ secrets.NEBULA_USER }}
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
LINUX_RESULT: ${{ needs.linux_zip.result }}
WINDOWS_RESULT: ${{ needs.windows_zip.result }}
run: python ci/post/main.py nightly
-288
View File
@@ -1,288 +0,0 @@
name: Build Release package
on:
push:
tags:
- 'release_*'
env:
QT_VERSION: 5.12.9
jobs:
create_release:
name: Create GitHub release
runs-on: ubuntu-latest
steps:
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Store upload URL
run: |
echo -n "${{ steps.create_release.outputs.upload_url }}" > upload_url
- name: Persist upload URL
uses: actions/upload-artifact@v2
with:
name: upload_url
path: ${{ github.workspace }}/upload_url
build_linux:
strategy:
matrix:
configuration: [FastDebug, Release]
name: Linux
needs: create_release
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: |
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Generate AppImage
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: linux-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/install/*.AppImage
linux_zip:
name: Build Linux distribution zip
needs: build_linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0'
- name: Download upload URL
uses: actions/download-artifact@v1
with:
name: upload_url
path: .
- name: Extract upload URL
id: extractUploadUrl
run: echo "::set-output name=upload_url::$(cat upload_url)"
- name: Download Release builds
uses: actions/download-artifact@v1
with:
name: linux-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: linux-FastDebug
path: builds
- name: Create Distribution package
id: generate_package
working-directory: ./builds
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
- name: Upload result package
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.extractUploadUrl.outputs.upload_url }}
asset_path: ${{ steps.generate_package.outputs.package_path }}
asset_name: ${{ steps.generate_package.outputs.package_name }}
asset_content_type: ${{ steps.generate_package.outputs.package_mime }}
build_windows:
strategy:
matrix:
configuration: [FastDebug, Release]
arch: [Win32, x64]
simd: [SSE2, AVX]
needs: create_release
name: Windows
runs-on: windows-2019
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'Win32' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win32_msvc2017
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'x64' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win64_msvc2017_64
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCHITECTURE: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
shell: bash
run: |
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=ON -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" --target INSTALL -- /verbosity:minimal
ls -alR "$(pwd)/install"
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
windows_zip:
name: Build Windows distribution zip
needs: build_windows
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [Win32, x64]
simd: [SSE2, AVX]
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0'
- name: Download upload URL
uses: actions/download-artifact@v1
with:
name: upload_url
path: .
- name: Extract upload URL
id: extractUploadUrl
run: echo "::set-output name=upload_url::$(cat upload_url)"
- name: Download Release builds
uses: actions/download-artifact@v1
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Create Distribution package
id: generate_package
working-directory: ./builds
shell: bash
env:
ARCH: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
- name: Upload result package
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.extractUploadUrl.outputs.upload_url }}
asset_path: ${{ steps.generate_package.outputs.package_path }}
asset_name: ${{ steps.generate_package.outputs.package_name }}
asset_content_type: ${{ steps.generate_package.outputs.package_mime }}
- name: Upload debug symbols
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.extractUploadUrl.outputs.upload_url }}
asset_path: ${{ steps.generate_package.outputs.debug_path }}
asset_name: ${{ steps.generate_package.outputs.debug_name }}
asset_content_type: ${{ steps.generate_package.outputs.debug_mime }}
post_builds:
name: Post builds on Nebula and the forums
needs: [linux_zip, windows_zip]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
name: Checkout
with:
fetch-depth: '0'
- name: Install Python dependencies
run: pip install -r ci/post/requirements.txt
- name: Post builds
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
NEBULA_USER: ${{ secrets.NEBULA_USER }}
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
LINUX_RESULT: ${{ needs.linux_zip.result }}
WINDOWS_RESULT: ${{ needs.windows_zip.result }}
run: python ci/post/main.py release
-226
View File
@@ -1,226 +0,0 @@
name: Build Test package
on:
push:
branches:
- 'test/*'
env:
QT_VERSION: 5.12.9
jobs:
build_linux:
strategy:
matrix:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set up test version
shell: bash
run: |
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: |
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Generate AppImage
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: linux-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/install/*.AppImage
linux_zip:
name: Build Linux distribution zip
needs: build_linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
steps:
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v1
with:
name: linux-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: linux-FastDebug
path: builds
- name: Create Distribution package
working-directory: ./builds
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
- name: Upload result package
working-directory: ./builds
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh test
build_windows:
strategy:
matrix:
configuration: [FastDebug, Release]
arch: [Win32, x64]
simd: [SSE2]
name: Windows
runs-on: windows-2019
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set up test version
shell: bash
run: |
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"
- name: Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'Win32' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win32_msvc2017
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'x64' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win64_msvc2017_64
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCHITECTURE: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
shell: bash
run: |
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
-DFSO_BUILD_QTFRED=ON -DFSO_BUILD_TESTS=ON \
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
-G "Visual Studio 16 2019" -T "v142" ..
- name: Compile
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
shell: bash
run: |
cmake --build . --config "$CONFIGURATION" --target INSTALL -- /verbosity:minimal
ls -alR "$(pwd)/install"
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
windows_zip:
name: Build Windows distribution zip
needs: build_windows
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [Win32, x64]
simd: [SSE2]
steps:
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v1
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Create Distribution package
working-directory: ./builds
shell: bash
env:
ARCH: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
- name: Upload result package
working-directory: ./builds
shell: bash
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh test
-62
View File
@@ -1,62 +0,0 @@
name: Build caches for master
on:
push:
branches:
- master
env:
QT_VERSION: 5.12.9
jobs:
build_linux:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [gcc-5, gcc-10]
cmake_options: [""]
include:
# Also include configurations that check if the code compiles without the graphics backends
- configuration: Debug
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
- configuration: Release
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
-21
View File
@@ -1,21 +0,0 @@
name: Push a new nightly tag
on:
schedule:
- cron: '0 6 * * *'
jobs:
tag:
if: github.repository == 'scp-fs2open/fs2open.github.com'
runs-on: ubuntu-latest
steps:
- name: Prepare environment
run: |
git config --global user.email '[email protected]'
git config --global user.name SirKnightly
- name: Checkout repo
uses: actions/checkout@v2
- name: Create tag
run: git tag "nightly_$(date '+%Y%m%d')_$(git rev-parse --short HEAD)"
- name: Push tag
run: git push --tags
+50 -78
View File
@@ -2,78 +2,76 @@ name: Check a pull request
on: [pull_request]
env:
QT_VERSION: 5.12.9
jobs:
build_linux:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [gcc-5, gcc-10, clang-9]
cmake_options: [""]
include:
# Also include configurations that check if the code compiles without the graphics backends
- configuration: Debug
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
- configuration: Release
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
compiler: [gcc-5, gcc-9, clang-4.0]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
runs-on: ubuntu-16.04
steps:
- name: Cache Qt
id: cache-qt-lin
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- name: Prepare Environment
env:
DEBIAN_FRONTEND: noninteractive
run: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo add-apt-repository ppa:beineri/opt-qt571-xenial
sudo add-apt-repository ppa:msulikowski/valgrind # For fixing a bug with valgrind 3.11 which does not recognize the rdrand instruction
sudo apt-get -yq update
sudo apt-get -yq install cmake ninja-build libopenal-dev libreadline6-dev libpng12-dev libjpeg62-dev liblua5.1-0-dev libjansson-dev libsdl2-dev libfreetype6-dev valgrind qt57base g++-5 g++-9 clang-4.0 clang-tidy-4.0 libc++-dev libc++abi-dev
# Fix a header bug present in ubuntu...
sudo ln -s /usr/include/libcxxabi/__cxxabi_config.h /usr/include/c++/v1/__cxxabi_config.h
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
run: |
if [ "$COMPILER" = "gcc-5" ]; then
export CC=gcc-5
export CXX=g++-5
fi
if [ "$COMPILER" = "gcc-9" ]; then
export CC=gcc-9
export CXX=g++-9
fi
if [ "$COMPILER" = "clang-4.0" ]; then
export CC=clang-4.0
export CXX=clang++-4.0
fi
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
if [[ "$CC" =~ ^clang.*$ ]]; then
CXXFLAGS="$CXXFLAGS -stdlib=libc++"
fi
mkdir build
cd build
export CXXFLAGS
export CFLAGS
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON ..
- name: Compile
working-directory: ./build
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
run: ninja -k 20 all
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Run Clang Tidy
# Clang-tidy reuses the precompiled headers so this only makes sense for the clang compilers
if: startsWith(matrix.compiler, 'clang-')
run: $GITHUB_WORKSPACE/ci/linux/clang_tidy.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
- name: Process clang-tidy warnings
if: startsWith(matrix.compiler, 'clang-')
uses: asarium/clang-tidy-action@v1
with:
fixesFile: clang-fixes.yaml
run: |
if [ "$CONFIGURATION" = "Debug" ]; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$GITHUB_WORKSPACE/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
else
./bin/unittests --gtest_shuffle
fi
build_windows:
strategy:
matrix:
@@ -89,31 +87,6 @@ jobs:
name: Checkout
with:
submodules: true
- name: Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'Win32' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win32_msvc2017
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'x64' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win64_msvc2017_64
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -129,8 +102,7 @@ jobs:
-DFSO_BUILD_FRED2="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
else
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
-DFSO_BUILD_QTFRED=ON -T "v142" -A "$ARCHITECTURE" ..
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" -T "v142" -A "$ARCHITECTURE" ..
fi
- name: Compile
working-directory: ./build
@@ -3,8 +3,7 @@ name: Publish Standalone docker image
on:
push:
tags:
- 'nightly_*'
- 'release_*'
- '*'
jobs:
build_images:
@@ -13,9 +12,13 @@ jobs:
configuration: [FastDebug, Release]
include:
- configuration: FastDebug
tag_suffix: -debug
latest_tag: latest_debug
nightly_tag: nightly_debug
release_tag: release_debug
- configuration: Release
tag_suffix: ""
latest_tag: latest
nightly_tag: nightly
release_tag: release
fail-fast: false
runs-on: ubuntu-latest
steps:
@@ -23,30 +26,23 @@ jobs:
name: Checkout
with:
submodules: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker login
run: echo ${{ secrets.DOCKER_ACCESSTOKEN }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Docker build
run: docker build --build-arg build_type=${{ matrix.configuration }} -f docker/standalone/Dockerfile -t ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }} .
- name: Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v1
with:
images: ghcr.io/scp-fs2open/standalone_server
tag-latest: false
- name: Push latest tag
run: |
docker push ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }}
- name: Login to GitHub Docker Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
file: ./docker/standalone/Dockerfile
push: true
tags: ${{ steps.docker_meta.outputs.tags }}${{ matrix.tag_suffix }}
labels: ${{ steps.docker_meta.outputs.labels }}
build-args: |
build_type=${{ matrix.configuration }}
- name: Push nightly tag
if: contains(github.ref, 'refs/tags/nightly_')
run: |
docker tag ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }} ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.nightly_tag }}
docker push ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.nightly_tag }}
- name: Push release tag
if: contains(github.ref, 'refs/tags/release_')
run: |
docker tag ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }} ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.release_tag }}
docker push ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.release_tag }}
+28 -2
View File
@@ -86,6 +86,19 @@ matrix:
packages:
- g++-9
- *global_deps
- os: linux
env: CONFIGURATION="Debug" CC=clang-4.0 CXX=clang++-4.0 CMAKE_OPTIONS="-DCLANG_USE_LIBCXX=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- clang-4.0
- libc++-dev
- libc++abi-dev
- os: linux
env: CONFIGURATION="Debug" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
@@ -103,7 +116,7 @@ matrix:
env: CONFIGURATION="Debug"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
@@ -127,6 +140,19 @@ matrix:
packages:
- g++-9
- *global_deps
- os: linux
env: CONFIGURATION="Release" CC=clang-4.0 CXX=clang++-4.0 CMAKE_OPTIONS="-DCLANG_USE_LIBCXX=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- clang-4.0
- libc++-dev
- libc++abi-dev
- os: linux
env: CONFIGURATION="Release" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
@@ -144,7 +170,7 @@ matrix:
env: CONFIGURATION="Release"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
# There is a GCC compiler bug with MinGW that causes compilation failures on Windows at the moment
+3 -19
View File
@@ -8,7 +8,6 @@ if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
endif()
include(cmake/util.cmake)
include(cmake/embed_file.cmake)
# Set a few policies
set_policy(CMP0051 NEW)
@@ -44,14 +43,9 @@ PROJECT(FS2_Open)
find_program(CCACHE_PROGRAM ccache)
# Currently only GCC support ccache properly without generating additional warnings
if(CCACHE_PROGRAM AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if(NOT CMAKE_C_COMPILER_LAUNCHER)
message(STATUS "Using ccache for C compilation: ${CCACHE_PROGRAM}")
SET(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()
if(NOT CMAKE_CXX_COMPILER_LAUNCHER)
message(STATUS "Using ccache for C++ compilation: ${CCACHE_PROGRAM}")
SET(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()
message(STATUS "Using ccache for compilation: ${CCACHE_PROGRAM}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}")
endif()
IF(CMAKE_CROSSCOMPILING)
@@ -127,10 +121,6 @@ option(FSO_RELEASE_LOGGING "Enable logging output for release builds" OFF)
OPTION(FSO_BUILD_WITH_FFMPEG "Enable the usage of FFmpeg for sound and custscenes" ON)
OPTION(FSO_BUILD_WITH_OPENGL "Enable compilation of the OpenGL renderer" ON)
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" ON)
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
@@ -141,8 +131,6 @@ mark_as_advanced(FORCE FSO_INSTALL_DEBUG_FILES)
mark_as_advanced(FORCE ENABLE_COTIRE)
mark_as_advanced(FORCE FSO_RELEASE_LOGGING)
mark_as_advanced(FORCE FSO_BUILD_WITH_FFMPEG)
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL)
mark_as_advanced(FORCE FSO_BUILD_WITH_VULKAN)
# Include cotire file from https://github.com/sakra/cotire/
include(cotire)
@@ -169,8 +157,6 @@ ADD_SUBDIRECTORY(tools)
ADD_SUBDIRECTORY(lib)
ADD_SUBDIRECTORY(parsers)
ADD_SUBDIRECTORY(code)
ADD_SUBDIRECTORY(freespace2)
@@ -219,5 +205,3 @@ message(STATUS "Building qtFRED: ${FSO_BUILD_QTFRED}")
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
message(STATUS "Release logging: ${FSO_RELEASE_LOGGING}")
message(STATUS "With FFmpeg: ${FSO_BUILD_WITH_FFMPEG}")
message(STATUS "With OpenGL: ${FSO_BUILD_WITH_OPENGL}")
message(STATUS "With Vulkan: ${FSO_BUILD_WITH_VULKAN}")
-7
View File
@@ -12,11 +12,4 @@ Modifications by members of the FreeSpace Source Code Project are
released under whatever terms the individual authors choose, but the
above notice continues to apply to all fs2_open code.
All modifications made on or after November 1, 2020, shall be released under
the terms within [Unlicense](Unlicense.md). Modifications made before said date are released
under the previous terms with the exception of modifications made by members
of the FreeSpace Source Code Project that opt-in to the terms of Unlicense. Additionally,
a list of contributors who have opted in to the Unlicense terms can be found
in [**Licensing**](https://github.com/scp-fs2open/fs2open.github.com/wiki/Licensing).
See [**Licensing**](https://github.com/scp-fs2open/fs2open.github.com/wiki/Licensing) for more information.
-24
View File
@@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to [**Unlicense**](https://unlicense.org).
+2 -2
View File
@@ -8,11 +8,11 @@ environment:
matrix:
- BuildID: 0
CMAKE_GENERATOR: Visual Studio 14 2015
PlatformToolset: v140
PlatformToolset: v140_xp
QT_DIR: C:\Qt\5.9\msvc2015
- BuildID: 1
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
PlatformToolset: v140
PlatformToolset: v140_xp
QT_DIR: C:\Qt\5.9\msvc2015_64
before_build:
- git submodule update --init --recursive
+48 -48
View File
@@ -9,56 +9,56 @@ class BuildConfig {
}
$NightlyConfigurations = @(
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# },
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$false;
# }
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9\msvc2015_64";
SourcePackage=$false;
},
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9\msvc2015";
SourcePackage=$false;
}
)
$ReleaseConfigurations = @(
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$true;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32-AVX";
# Toolset="v140";
# SimdType="AVX";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$false;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64-AVX";
# Toolset="v140";
# SimdType="AVX";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# }
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9\msvc2015";
SourcePackage=$true;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32-AVX";
Toolset="v140_xp";
SimdType="AVX";
QtDir="C:\Qt\5.9\msvc2015";
SourcePackage=$false;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9\msvc2015_64";
SourcePackage=$false;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64-AVX";
Toolset="v140_xp";
SimdType="AVX";
QtDir="C:\Qt\5.9\msvc2015_64";
SourcePackage=$false;
}
)
$BuildConfigurations = $null
-23
View File
@@ -1,23 +0,0 @@
#!/usr/bin/env bash
set -e
SCRIPT=$(readlink -f "$0")
HERE=$(dirname "$SCRIPT")
COMMIT_RANGE=$1..$2
if ! git rev-list $COMMIT_RANGE 2>&1 >/dev/null; then
echo "\$COMMIT_RANGE ($COMMIT_RANGE) is not valid for this build (probably caused by a rebase)."
exit 0
fi
# In order to get a proper diff without irrelevant changes, we need to determine where we branched off from the base
# branch
BASE_COMMIT=$(git merge-base $1 $2)
echo "Running clang-tidy on changed files"
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
-regex '(code(?!\/graphics\/shaders\/compiled)|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
-clang-tidy-binary /usr/bin/clang-tidy-9 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
-36
View File
@@ -1,36 +0,0 @@
#!/usr/bin/env bash
if [ "$COMPILER" = "gcc-5" ]; then
export CC=gcc-5
export CXX=g++-5
fi
if [ "$COMPILER" = "gcc-10" ]; then
export CC=gcc-10
export CXX=g++-10
fi
if [ "$COMPILER" = "clang-9" ]; then
# Work around bug in clang that uses the wrong installation directory: https://bugs.llvm.org/show_bug.cgi?id=47460
export CC=$(readlink -f $(which clang-9))
export CXX=$(readlink -f $(which clang++-9))
fi
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
fi
mkdir build
cd build
export CXXFLAGS
export CFLAGS
export LD_LIBRARY_PATH
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS \
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_BUILD_APPIMAGE=ON -DCMAKE_BUILD_TYPE=$CONFIGURATION \
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON \
-DSHADERS_ENABLE_COMPILATION=ON ..
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env bash
SCRIPT=$(readlink -f "$0")
HERE=$(dirname "$SCRIPT")
OS="$1"
source $HERE/dist_functions.sh
if [ "$OS" = "Linux" ]; then
tar -cvzf "$(get_package_name)-builds-Linux.tar.gz" *
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-Linux.tar.gz"
echo "::set-output name=package_name::$(get_package_name)-builds-Linux.tar.gz"
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux.tar.gz")"
elif [ "$OS" = "Windows" ]; then
7z a -xr'!*.pdb' "$(get_package_name)-builds-$ARCH-$SIMD.zip" "*"
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip"
echo "::set-output name=package_name::$(get_package_name)-builds-$ARCH-$SIMD.zip"
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip")"
7z a "$(get_package_name)-debug-$ARCH-$SIMD.7z" "*.pdb"
echo "::set-output name=debug_path::$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z"
echo "::set-output name=debug_name::$(get_package_name)-debug-$ARCH-$SIMD.7z"
echo "::set-output name=debug_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")"
else
echo "Invalid OS: $OS"
fi
-70
View File
@@ -1,70 +0,0 @@
function get_package_name() {
if git describe --match 'nightly_*' --exact-match 2>/dev/null >/dev/null; then
echo -n "$(git describe --match "nightly_*" --exact-match)"
return
fi
if git describe --match 'release_*' --exact-match 2>/dev/null >/dev/null; then
echo -n "$(git describe --match "release_*" --exact-match | sed 's/release_/fs2_open_/i')"
return
fi
if [[ "$(git branch --show-current)" =~ ^test\/(.*)$ ]]; then
echo -n "test_${BASH_REMATCH[1]}"
return
fi
echo "unknown_config"
}
function get_version_name() {
if git describe --match 'nightly_*' --exact-match 2>/dev/null >/dev/null; then
local tag_name=$(git describe --match "nightly_*" --exact-match)
# Use the bash regex matching for getting the relevant part of the tag name
[[ $tag_name =~ ^nightly_(.*)$ ]]
echo -n "${BASH_REMATCH[1]}"
return
fi
if git describe --match 'release_*' --exact-match 2>/dev/null >/dev/null; then
local tag_name=$(git describe --match "release_*" --exact-match)
# Use the bash regex matching for getting the relevant part of the tag name
[[ $tag_name =~ ^release_(.*)$ ]]
echo -n "${BASH_REMATCH[1]}"
return
fi
if [[ "$(git branch --show-current)" =~ ^test\/(.*)$ ]]; then
echo -n "${BASH_REMATCH[1]}"
return
fi
echo "unknown_config"
}
function upload_files_to_sftp() {
# We need empty glob patterns to "disappear" in the for loop below since this will be run for different configurations
# where it may be possible that some of the file patterns will not be present
shopt -s nullglob
echo "cd $2/" > sftp_batch
echo "mkdir $(get_version_name)" >> sftp_batch
# Create directory but do not cause an error if it already exists
sshpass -e sftp -oBatchMode=no -o "StrictHostKeyChecking no" -b sftp_batch $1 || true
echo "cd $2/$(get_version_name)/" > sftp_batch
for file in *.tar.gz *.7z *.zip; do
echo "put $file" >> sftp_batch
done
echo "bye" >> sftp_batch
sshpass -e sftp -oBatchMode=no -o "StrictHostKeyChecking no" -b sftp_batch $1
rm sftp_batch
}
-14
View File
@@ -1,14 +0,0 @@
#!/usr/bin/env bash
INSTALL_FOLDER=$1
# Install Freespace2 targets
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER -DCOMPONENT=Freespace2 -P cmake_install.cmake
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
FILENAME="$(find $INSTALL_FOLDER/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
appimagetool -n $INSTALL_FOLDER "$INSTALL_FOLDER/$FILENAME"
chmod +x "$INSTALL_FOLDER/$FILENAME"
ls -al $INSTALL_FOLDER
-13
View File
@@ -1,13 +0,0 @@
#!/usr/bin/env bash
SCRIPT=$(readlink -f "$0")
HERE=$(dirname "$SCRIPT")
export LD_LIBRARY_PATH=$(pwd)/bin/lib:$LD_LIBRARY_PATH
if [ "$CONFIGURATION" = "Debug" ]; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$HERE/valgrind.supp" ./bin/unittests --gtest_shuffle
else
./bin/unittests --gtest_shuffle
fi
-21
View File
@@ -1,21 +0,0 @@
#!/usr/bin/env bash
set -e
UPLOAD_TYPE=$1
SCRIPT=$(readlink -f "$0")
HERE=$(dirname "$SCRIPT")
source $HERE/dist_functions.sh
if [ "$UPLOAD_TYPE" = "nightly" ]; then
SSHPASS=$INDIEGAMES_SSHPASS upload_files_to_sftp "$INDIEGAMES_USER@scp.indiegames.us" "public_html/builds/nightly"
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly"
elif [ "$UPLOAD_TYPE" = "test" ]; then
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/test"
else
echo "Unknown upload type $UPLOAD_TYPE"
exit 1
fi
-128
View File
@@ -1,128 +0,0 @@
import re
from ftplib import FTP, error_perm
from typing import List, Tuple, Dict
import requests
from util import retry_multi, GLOBAL_TIMEOUT
class ReleaseFile:
def __init__(self, name, url, group, subgroup=None, mirrors=None):
if mirrors is None:
mirrors = []
self.mirrors = mirrors
self.subgroup = subgroup
self.group = group
self.url = url
self.name = name
self.base_url = "/".join(url.split('/')[0:-1]) + "/"
self.filename = url.split('/')[-1]
# A list of tuples of (filename, hash)
self.content_hashes = None
self.hash = None
self.size = 0
class SourceFile:
def __init__(self, name, url, group):
self.group = group
self.url = url
self.name = name
def get_release_files(tag_name, config) -> Tuple[List[ReleaseFile], Dict[str, SourceFile]]:
@retry_multi(5)
def execute_request(path):
headers = {
"Accept": "application/vnd.github.v3+json"
}
url = "https://api.github.com" + path
response = requests.get(url, headers=headers, timeout=GLOBAL_TIMEOUT)
response.raise_for_status()
return response.json()
build_group_regex = re.compile("fs2_open_.*-builds-([^.-]*)(-([^.]*))?.*")
source_file_regex = re.compile("fs2_open_.*-source-([^.]*)?.*")
response = execute_request(
"/repos/{}/{}/releases/tags/{}".format(config["github"]["user"], config["github"]["repo"], tag_name))
binary_files = []
source_files = {}
for asset in response["assets"]:
url = asset["browser_download_url"]
name = asset["name"]
group_match = build_group_regex.match(name)
if group_match is not None:
platform = group_match.group(1)
# x64 is the Visual Studio name but for consistency we need Win64
if platform == "x64":
platform = "Win64"
binary_files.append(ReleaseFile(name, url, platform, group_match.group(3)))
else:
group_match = source_file_regex.match(name)
if group_match is None:
continue
group = group_match.group(1)
source_files[group] = SourceFile(name, url, group)
return binary_files, source_files
def get_ftp_files(build_type, tag_name, config):
tag_regex = re.compile("nightly_(.*)")
build_group_regex = re.compile("nightly_.*-builds-([^.]+).*")
files = []
try:
with FTP(config["ftp"]["host"], config["ftp"]["user"], config["ftp"]["pass"]) as ftp:
version_str = tag_regex.match(tag_name).group(1)
path_template = config["ftp"]["path"]
path = path_template.format(type=build_type, version=version_str)
file_entries = list(ftp.mlsd(path, ["type"]))
for entry in file_entries:
if entry[1]["type"] == "file":
files.append(entry[0])
except error_perm:
print("Received permanent FTP error!")
return []
out_data = []
for file in files:
file_match = build_group_regex.match(file)
if file_match is None:
print("Ignoring non nightly file '{}'".format(file))
continue
group_match = file_match.group(1)
primary_url = None
mirrors = []
# x64 is the name Visual Studio uses but Win64 works better for us since that gets displayed in the nightly post
if "x64" in group_match:
group_match = group_match.replace("x64", "Win64")
for mirror in config["ftp"]["mirrors"]:
download_url = mirror.format(type=build_type, version=version_str, file=file)
if primary_url is None:
primary_url = download_url
else:
mirrors.append(download_url)
out_data.append(ReleaseFile(file, primary_url, group_match, None, mirrors))
return out_data
-82
View File
@@ -1,82 +0,0 @@
from itertools import groupby
from typing import List
import requests
import semantic_version
from mako.template import Template
from file_list import ReleaseFile
class FileGroup:
def __init__(self, name, files: List[ReleaseFile]):
self.files = files
self.name = name
if len(files) == 1:
self.mainFile = files[0]
self.subFiles = {}
else:
self.mainFile = None
subFiles = []
for file in files:
# We only have subcategories for Windows where SSE2 is the main group
if file.subgroup == "SSE2":
self.mainFile = file
else:
subFiles.append(file)
self.subFiles = dict(((x[0], next(x[1])) for x in groupby(subFiles, lambda f: f.subgroup)))
class ForumAPI:
def __init__(self, config):
self.config = config
def create_post(self, title, content, board):
resp = requests.post(self.config["hlp"]["api"], data={
"api_key": self.config["hlp"]["key"],
"board": str(board),
"subject": title,
"body": content
})
if resp.text != "OK":
print("Post failed!")
def post_nightly(self, date, revision, files, log, success):
print("Posting nightly thread...")
title = "Nightly: {} - Revision {}".format(date, revision)
template = Template(filename=self.config["templates"]["nightly"])
rendered = template.render_unicode(**{
"date": date,
"revision": revision,
"files": files,
"log": log,
"success": success
})
print("Creating post...")
self.create_post(title, rendered, self.config["nightly"]["hlp_board"])
def post_release(self, date, version: semantic_version.Version, groups, sources):
print("Posting release thread...")
title = "Release: {}".format(version)
template = Template(
filename=self.config["templates"]["release"].format(major=version.major, minor=version.minor),
module_directory='/tmp/mako_modules')
rendered = template.render_unicode(**{
"date": date,
"version": version,
"groups": groups,
"sources": sources
}).strip("\n")
print("Creating post...")
self.create_post(title, rendered, self.config["release"]["hlp_board"])
-88
View File
@@ -1,88 +0,0 @@
import os
import hashlib
import tarfile
import traceback
import zipfile
from tempfile import NamedTemporaryFile
from zipfile import ZipFile
import requests
import sys
from mako.template import Template
from file_list import ReleaseFile
from util import GLOBAL_TIMEOUT
def _download_file(url, dest_file, session):
print("Downloading " + url)
# NOTE the stream=True parameter
r = session.get(url, stream=True, timeout=GLOBAL_TIMEOUT)
for chunk in r.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
dest_file.write(chunk)
dest_file.flush()
def _gen_hash(fileobj, hash_alg):
h = hashlib.new(hash_alg)
while True:
data = fileobj.read(4096)
if not data:
break
h.update(data)
return h.hexdigest()
def get_hashed_file_list(file: ReleaseFile, session: requests.Session = None, hash_alg: str = "sha256"):
if session is None:
session = requests.Session()
with NamedTemporaryFile('w+b', suffix=file.filename) as local_file:
_download_file(file.url, local_file, session)
filename = local_file.name
hash_list = []
local_file.seek(0)
file.hash = _gen_hash(local_file, hash_alg)
file.size = os.stat(filename).st_size
try:
if tarfile.is_tarfile(filename):
with tarfile.open(filename) as archive:
for entry in archive:
if not entry.isfile():
continue
print("Computing hash for " + entry.name)
fileobj = archive.extractfile(entry)
hash_list.append((entry.path, _gen_hash(fileobj, hash_alg)))
elif zipfile.is_zipfile(filename):
with ZipFile(filename) as archive:
for entry in archive.infolist():
# Python 3.6 has is_dir but that version is relatively new so we'll use the "safe" version here
if entry.filename.endswith('/'):
continue
print("Computing hash for " + entry.filename)
with archive.open(entry) as fileobj:
hash_list.append((entry.filename, _gen_hash(fileobj, hash_alg)))
else:
raise NotImplementedError("Unsupported archive type!")
except:
traceback.print_exception(*sys.exc_info())
return
file.content_hashes = hash_list
def render_installer_config(version, groups, config):
template = Template(filename=config["templates"]["installer"], module_directory='/tmp/mako_modules')
return template.render(**{
"version": version,
"groups": groups,
}).strip("\n")
-152
View File
@@ -1,152 +0,0 @@
import sys
import os
import re
from subprocess import check_output
from datetime import datetime
from itertools import groupby
import semantic_version
import file_list
import installer
import nebula
import forum
MAJOR_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_MAJOR (\d+)\)")
MINOR_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_MINOR (\d+)\)")
BUILD_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_BUILD (\d+)\)")
LOG_FORMAT = """
------------------------------------------------------------------------%n
commit %h%nAuthor: %an <%ad>%n
Commit: %cn <%cd>%n%n %s
"""
DATEFORMAT_VERSION = "%Y%m%d"
DATEFORMAT_FORUM = "%d %B %Y"
def _match_version_number(text, regex):
match = regex.search(text)
return int(match.group(1))
def get_source_version(date_version):
with open(os.path.join("..", "..", "cmake", "version.cmake"), "r") as f:
filetext = f.read()
major = _match_version_number(filetext, MAJOR_VERSION_PATTERN)
minor = _match_version_number(filetext, MINOR_VERSION_PATTERN)
build = _match_version_number(filetext, BUILD_VERSION_PATTERN)
return semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, date_version))
def main():
os.chdir(os.path.dirname(__file__))
config = {
"github": {
"user": "scp-fs2open",
"repo": "fs2open.github.com",
},
"ftp": {
"host": "scp.indiegames.us",
"user": os.environ["INDIEGAMES_USER"],
"pass": os.environ["INDIEGAMES_SSHPASS"],
"path": "public_html/builds/{type}/{version}/",
"mirrors": (
"https://porphyrion.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
"http://scp.indiegames.us/builds/{type}/{version}/{file}",
),
},
"nebula": {
"user": os.environ["NEBULA_USER"],
"password": os.environ["NEBULA_PASSWORD"],
},
"hlp": {
"api": os.environ["HLP_API"],
"key": os.environ["HLP_KEY"],
},
"templates": {
"nightly": "nightly.mako",
"release": "release.mako",
},
"nightly": {
"hlp_board": 173,
},
"release": {
"hlp_board": 50,
},
}
if sys.argv[1] not in ("release", "nightly"):
print("ERROR: Invalid release mode %s passed. Expected release or nightly!" % sys.argv[1])
sys.exit(1)
tag_name = os.path.basename(os.environ["GITHUB_REF"])
date = datetime.now()
version = get_source_version(date.strftime(DATEFORMAT_VERSION))
success = os.environ["LINUX_RESULT"] == "success" and os.environ["WINDOWS_RESULT"] == "success"
tags = check_output(("git", "for-each-ref", "--sort=-taggerdate", "--format", "%(tag)", "refs/tags")).splitlines()
previous_tag = None
found = False
for tag in tags:
if found:
if tag.startswith(sys.argv[1] + "_"):
previous_tag = tag
break
elif tag == tag_name:
found = True
if not found:
print("ERROR: Couldn't find tag %s in repo!" % tag_name)
sys.exit(1)
if not previous_tag:
print("ERROR: Could not find a previous tag for %s!" % tag_name)
sys.exit(1)
if sys.argv[1] == "release":
if not tag_name.startswith("release_"):
print("ERROR: Invalid tag name detected. Expected release_ prefix for release builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
files, sources = file_list.get_release_files(tag_name, config)
print("Hashing files")
for file in files:
installer.get_hashed_file_list(file)
# Construct the file groups
groups = dict(((x[0], file_list.FileGroup(x[0], list(x[1]))) for x in groupby(files, lambda g: g.group)))
print(installer.render_installer_config(version, groups, config))
nebula.submit_release(
nebula.render_nebula_release(version, "rc" if version.prerelease else "stable", "files", config),
config)
fapi = forum.ForumAPI(config)
fapi.post_release(date.strftime(DATEFORMAT_FORUM), version, groups, sources)
else:
if not tag_name.startswith("nightly_"):
print("ERROR: Invalid tag name detected. Expected nightly_ prefix for nightly builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
print("Retrieving file list")
files = file_list.get_ftp_files("nightly", tag_name, config)
print("Hashing files")
for file in files:
installer.get_hashed_file_list(file)
nebula.submit_release(nebula.render_nebula_release(version, "nightly", files, config), config)
log = check_output(("git", "log", "%s^..%s^" % (previous_tag, tag_name), "--no-merges", "--stat", "--pretty=format:\"%s\"" % LOG_FORMAT.strip()))
fapi = forum.ForumAPI(config)
fapi.post_nightly(date.strftime(DATEFORMAT_FORUM), os.environ["GITHUB_SHA"], files, log, success)
main()
-240
View File
@@ -1,240 +0,0 @@
import os.path
import sys
import traceback
import requests
from util import retry_multi, GLOBAL_TIMEOUT
metadata = {
'type': 'engine',
'title': 'FSO',
'notes': '',
'banner': 'https://fsnebula.org/storage/0d/e7/bf64bcdea9a9c115969cfb784e1ca457d24a7c2da4fc6f213521c3bb6abb.png',
'screenshots': [],
'videos': [],
'first_release': '2017-09-24',
'cmdline': '',
'mod_flag': ['FSO'],
'tile': 'https://fsnebula.org/storage/ec/cc/0bf23e028c26d5175ff52d003bff85b0a17b0ddfc1130d65bdf6d36f6324.png',
'logo': None,
'release_thread': None,
'description': '',
'id': 'FSO',
'packages': [],
}
platforms = {
'Linux': 'linux',
'MacOSX': 'macosx',
'Win32-SSE2': 'windows',
'Win64-SSE2': 'windows',
'Win32-AVX': 'windows',
'Win64-AVX': 'windows'
}
envs = {
'Linux': 'linux && x86_64', # Linux only has 64bit builds
'MacOSX': 'macosx',
'Win32-SSE2': 'windows',
'Win64-SSE2': 'windows && x86_64',
'Win32-AVX': 'windows && avx',
'Win64-AVX': 'windows && avx && x86_64'
}
subdirs = {
'Win32-SSE2': 'x86',
'Win64-SSE2': 'x64',
'Win32-AVX': 'x86_avx',
'Win64-AVX': 'x64_avx'
}
def render_nebula_release(version, stability, files, config):
meta = metadata.copy()
meta['version'] = str(version)
meta['stability'] = stability # This can be one of ('stable', 'rc', 'nightly')
for file in files:
if file.content_hashes is None:
# The extraction probably failed which is why we don't have any hashes
continue
group = file.group
# release.py sets subgroup but nightly.py doesn't which means we have to normalize group here.
if file.subgroup:
group += '-' + file.subgroup
pkg = {
'name': group,
'notes': '',
'is_vp': False,
'files': [{
'dest': platforms[group] + '/' + subdirs.get(group, ''),
'filesize': file.size,
'checksum': ['sha256', file.hash],
'urls': [file.url] + file.mirrors,
'filename': file.name
}],
'environment': envs.get(group),
'filelist': [],
'status': 'required',
'folder': None,
'dependencies': [],
'executables': []
}
for fn, checksum in file.content_hashes:
if group in subdirs:
dest_fn = subdirs[group] + '/' + fn
else:
dest_fn = fn
# If the group is a known platform then we put the binaries into a separate subfolder for each platform
if group in platforms:
dest_fn = platforms[group] + '/' + dest_fn
pkg['filelist'].append({
'orig_name': fn,
'checksum': ('sha256', checksum),
'archive': file.name,
'filename': dest_fn
})
if group == 'Linux' and fn.endswith('.AppImage'):
if 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
else:
label = 'QtFRED'
else:
if '-FASTDBG' in fn:
label = 'Fast Debug'
else:
label = None
props = {
"x64": True, # All Linux builds are 64-bit
"sse2": True, # Linux builds are forced to compile with SSE2 but not AVX
"avx": False,
"avx2": False,
}
pkg['executables'].append({
'file': dest_fn,
'label': label,
'properties': props,
})
elif group == 'MacOSX' and fn.startswith(os.path.basename(fn) + '.app/'):
if 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
else:
label = 'QtFRED'
else:
if '-FASTDBG' in fn:
label = 'Fast Debug'
else:
label = None
props = {
"x64": True, # All Mac builds are 64-bit
"sse2": True, # There are no forced options on mac but 64-bit always implies SSE2 so we set that here
"avx": False,
"avx2": False,
}
pkg['executables'].append({
'file': dest_fn,
'label': label,
'properties': props,
})
elif group.startswith('Win') and fn.endswith('.exe'):
if 'fred2' in fn:
if '-FASTDBG' in fn:
label = 'FRED2 Debug'
else:
label = 'FRED2'
elif 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
else:
label = 'QtFRED'
else:
if '-FASTDBG' in fn:
label = 'Fast Debug'
else:
label = None
props = {
"x64": "x64" in fn,
"sse2": "SSE2" in fn or "AVX" in fn, # AVX implies SSE2
"avx": "AVX" in fn, # This conveniently also covers the AVX2 case since AVX2 implies AVX
"avx2": "AVX2" in fn,
}
pkg['executables'].append({
'file': dest_fn,
'label': label,
'properties': props,
})
meta["packages"].append(pkg)
return meta
@retry_multi(5)
def nebula_request(session, kind, path, **kwargs):
uri = "https://fsnebula.org/api/1/{}".format(path)
request_args = {
"timeout": GLOBAL_TIMEOUT
}
request_args.update(kwargs)
return session.request(kind, uri, **request_args)
def submit_release(meta, config):
try:
with requests.Session() as session:
print('Logging into Nebula...')
result = nebula_request(session, 'post', 'login', data={
'user': config['nebula']['user'],
'password': config['nebula']['password']
})
if result.status_code != 200:
print('Login failed!')
return False
data = result.json()
if not data['result']:
print('Login failed!')
return False
print('Submitting release...')
result = nebula_request(session, 'post', 'mod/release', headers={
'X-KN-TOKEN': data['token']
}, json=meta)
if result.status_code != 200:
print('Request failed!')
return False
data = result.json()
if not data['result']:
print('ERROR: ' + data['reason'])
return False
print('Success!')
return True
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
return False
-27
View File
@@ -1,27 +0,0 @@
Here is the nightly for ${date} - Revision ${revision}
% if not success:
[b][color=red]At least one of the nightly builds failed![/color][/b]
% endif
% for file in files:
Group: ${file.group}
[url=${file.url}]${file.name}[/url] \
%for mirror in file.mirrors:
%if loop.first:
(\
%endif
[url=${mirror}]Mirror[/url]\
%if loop.last:
)\
%else:
, \
%endif
%endfor
% endfor
[code]
${log}
[/code]
-80
View File
@@ -1,80 +0,0 @@
<%def name="build(file)">[url=${file.url}]${file.filename}[/url]</%def>
[b]Change log:[/b] (chronologically ordered)
[b]Bugfixes and behavior changes:[/b] Check these first if something breaks (most of these changes can be reverted / disabled).
[list]
[li]Wrap Docking getTime in a timestamp ([gh]#3701[/gh])[/li]
[li]expand some sexp documentation ([gh]#3671[/gh])[/li]
[li]Fix warnings concerning ballistic weapons ([gh]#3683[/gh])[/li]
[li]Initialize team visibility before using it ([gh]#3695[/gh])[/li]
[li]Actually fix the goal's target being sent ([gh]#3665[/gh])[/li]
[li]Safety for replace-texture ([gh]#3694[/gh])[/li]
[li]Fix issue 3685 ([gh]#3688[/gh])[/li]
[li]Exclude dead subsys from targeting ([gh]#3614[/gh])[/li]
[li]Fix scripted kills ([gh]#3679[/gh])[/li]
[li]Fix homing child weapons in niche circumstances ([gh]#3661[/gh])[/li]
[/list]
[b]Deprecations:[/b]
[list][li]None[/li][/list]
Deprecations are a mechanism in FSO where a certain feature or aspect of the engine has changed or is no longer supported. Since this would normally break existing mods we have the mod table feature "[tt]$Target Version:[/tt]" with which a mod can specify what version of FSO it was developed with. The features listed above will be removed or changed when the target version of a mod is at least the version released in this post.
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=97293.0]21.0 Release Thread[/url][/size]
Launchers, if you don't have one already:
[b]All platforms: [/b] For every day use, we recommend [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url], an integrated solution for downloading and launching mods.
[hidden=Alternative Launchers]
Cross-platform: [url=http://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (ongoing project for a unified launcher, you should upgrade to the latest RC/test build if you have not yet)
[b]Important:[/b] For best compatibility with FSO 3.8 and later you should use at least wxLauncher 0.12.
Windows: [url=http://scp.fsmods.net/files/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=http://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
OS X: Soulstorm's [url=http://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
Linux: [url=http://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=http://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
[img]http://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
[size=8pt]Compiled using GitHub Actions on Windows Server 2019 (10.0.17763), Visual Studio Enterprise 2019[/size]
[b]64-bit:[/b] ${build(groups["Win64"].mainFile)}
[b]32-bit:[/b] ${build(groups["Win32"].mainFile)}
[size=8pt]This one is based on the SSE2 Optimizations from the MSVC Compiler.[/size]
[hidden=Alternative builds]
[b]64-bit AVX:[/b] ${build(groups["Win64"].subFiles["AVX"])}
[size=8pt]This one is based on the AVX Optimizations from the MSVC Compiler (fastest build if your CPU supports AVX instructions).[/size]
[b]32-bit AVX:[/b] ${build(groups["Win32"].subFiles["AVX"])}
[size=8pt]This one is based on the AVX Optimizations from the MSVC Compiler.[/size]
[b]What are those SSE, SSE2 and AVX builds I keep seeing everywhere?[/b]
[url=http://www.hard-light.net/forums/index.php?topic=65628.0]Your answer is in this topic.[/url]
Don't want to deal with that? Use [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url] and it will download the best build specifically for your PC!
[/hidden]
[img]http://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
${build(groups["Linux"].mainFile)}
These builds use a mechanism called [url=http://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
[img]http://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]OS X[/size][/color]
[b][color=red]Not available[/color][/b] We recently lost access to our Mac CI environment which we usually used for compiling these builds so for the time being, there will be no builds for this OS.
[hidden=TrackIR Users]
[size=12pt]Important!![/size]
An external DLL is required for FSO to use TrackIR functions. The following DLL is simply unpacked in to your main FreeSpace2 root dir.
TrackIR is only supported on Windows.
[url=http://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=http://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
Known issues:
[list]
[li][url=https://github.com/scp-fs2open/fs2open.github.com/issues]Github issues[/url] and [url=https://github.com/scp-fs2open/fs2open.github.com/pulls]pending pull requests[/url][/li]
[li]See the list of [url=http://scp.indiegames.us/mantis/search.php?project_id=1&status_id%5B%5D=10&status_id%5B%5D=20&status_id%5B%5D=30&status_id%5B%5D=40&status_id%5B%5D=50&priority_id%5B%5D=40&priority_id%5B%5D=50&priority_id%5B%5D=60&sticky_issues=on&sortby=last_updated&dir=DESC&per_page=200&hide_status_id=-2]Fix for next release[/url] bugs - mark a bug as an elevated priority (high, urgent, immediate) to get it included in that filter.[/li]
[/list]
-3
View File
@@ -1,3 +0,0 @@
Mako==1.1.5
requests==2.26.0
semantic-version==2.8.5
-37
View File
@@ -1,37 +0,0 @@
import os
import time
from functools import wraps
from requests import RequestException
GLOBAL_TIMEOUT = 30
def retry_multi(max_retries):
"""
Retry a function `max_retries` times.
This has been copied from https://stackoverflow.com/a/23892489
"""
def retry(func):
@wraps(func)
def wrapper(*args, **kwargs):
num_retries = 0
while num_retries <= max_retries:
try:
ret = func(*args, **kwargs)
break
except RequestException:
if num_retries == max_retries:
raise
num_retries += 1
time.sleep(5)
return ret
return wrapper
return retry
def expand_config_vars(config):
config["git"]["repo"] = os.path.expandvars(config["git"]["repo"])
@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
#
#===- clang-tidy-diff.py - ClangTidy Diff Checker ------------*- python -*--===#
#
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e
if ! git rev-list $TRAVIS_COMMIT_RANGE 2>1 >/dev/null; then
echo "\$TRAVIS_COMMIT_RANGE ($TRAVIS_COMMIT_RANGE) is not valid for this build (probably caused by a rebase)."
exit 0
fi
cd "$TRAVIS_BUILD_DIR"
echo "Running clang-tidy on changed files"
git diff -U0 --no-color $TRAVIS_COMMIT_RANGE | \
$TRAVIS_BUILD_DIR/ci/travis/clang-tidy-diff.py -path "$TRAVIS_BUILD_DIR/build" -p1 \
-regex '(code|freespace2|qtfred|testsrc|build|tools)\/.*\.(cpp|h)' \
-clang-tidy-binary /usr/bin/clang-tidy-9 -j$(nproc) -quiet 2>/dev/null | \
tee clang-tidy-output.txt
if [[ -n $(grep "warning: " clang-tidy-output.txt) ]] || [[ -n $(grep "error: " clang-tidy-output.txt) ]]; then
echo "Errors or warnings were detected in the clang-tidy output!"
exit 1
else
echo -e "\033[1;32m\xE2\x9C\x93 passed:\033[0m clang-tidy test succeeded";
fi
+1 -1
View File
@@ -18,7 +18,7 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
XCODE_RET=${PIPESTATUS[0]}
if [ "$XCODE_RET" -ne "0" ]; then
tar -cvzf build.log.tar.gz build.log
curl --upload-file build.log.tar.gz "https://keep.sh"
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
exit $XCODE_RET
fi
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
@@ -145,19 +145,20 @@
fun:dl_open_worker
}
{
dlopen leak
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:_dl_exception_create
fun:_dl_signal_error
fun:_dl_map_object
fun:dl_open_worker
fun:_dl_catch_exception
fun:_dl_open
fun:dlopen_doit
fun:_dl_catch_exception
fun:_dl_catch_error
fun:_dlerror_run
fun:dlopen@@GLIBC_2.2.5
obj:*
obj:*
fun:call_init.part.0
fun:call_init
fun:_dl_init
fun:dl_open_worker
}
+14
View File
@@ -1,3 +1,17 @@
include(WriteCompilerDetectionHeader)
set(CMAKE_CXX_STANDARD_REQUIRED 11)
set(CMAKE_CXX_STANDARD 11)
set(REQUIRED_CXX_FEATURES cxx_rvalue_references cxx_nullptr)
get_property(CMAKE_CXX_KNOWN_FEATURES GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
write_compiler_detection_header(
FILE "${GENERATED_SOURCE_DIR}/scp_compiler_detection.h"
PREFIX SCP
COMPILERS AppleClang Clang GNU MSVC
FEATURES ${CMAKE_CXX_KNOWN_FEATURES}
VERSION 3.2
)
-114
View File
@@ -1,114 +0,0 @@
set(_EMBEDD_FILE_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
function(target_embed_files _target)
set(options)
set(oneValueArgs RELATIVE_TO PATH_TYPE_PREFIX)
set(multiValueArgs FILES)
cmake_parse_arguments(EMBED "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (NOT DEFINED EMBED_RELATIVE_TO)
set(EMBED_RELATIVE_TO "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
if (NOT IS_ABSOLUTE "${EMBED_RELATIVE_TO}")
get_filename_component(EMBED_RELATIVE_TO "${EMBED_RELATIVE_TO}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
foreach (file ${EMBED_FILES})
get_filename_component(_absoluteFile "${file}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(RELATIVE_PATH _pathType "${EMBED_RELATIVE_TO}" "${_absoluteFile}")
get_filename_component(_pathType ${_pathType} DIRECTORY)
if (DEFINED EMBED_PATH_TYPE_PREFIX)
if (_pathType)
set(_pathType "${EMBED_PATH_TYPE_PREFIX}/${_pathType}")
else()
# Avoid trailing / when we are in the same directory
set(_pathType "${EMBED_PATH_TYPE_PREFIX}")
endif()
endif()
if (NOT _pathType)
# If it is still empty then we need to work around yet another annoying CMake behavior where it ignores
# "empty" property strings
set(_pathType ".")
endif()
set_property(TARGET ${_target} APPEND PROPERTY EMBEDDED_FILES "${_absoluteFile}")
set_property(TARGET ${_target} APPEND PROPERTY EMBEDDED_FILES_BASE_DIR "${EMBED_RELATIVE_TO}")
set_property(TARGET ${_target} APPEND PROPERTY EMBEDDED_FILES_PATH_TYPE "${_pathType}")
endforeach()
endfunction()
function(handle_embedded_files _target)
get_target_property(_filesToEmbed ${_target} EMBEDDED_FILES)
get_target_property(_baseDirs ${_target} EMBEDDED_FILES_BASE_DIR)
get_target_property(_pathTypes ${_target} EMBEDDED_FILES_PATH_TYPE)
SET(DEF_OUT_FILES)
set(INCLUDE_LIST)
set(ARRAY_ELEMENTS)
list(LENGTH _filesToEmbed _numFiles)
FOREACH(i RANGE ${_numFiles})
# Why must CMake always do the unexpected thing? The foreach variant includes the last index as opposed to every
# other sensible language which does not include it...
if (i GREATER_EQUAL _numFiles)
break()
endif()
list(GET _filesToEmbed ${i} _filePath)
list(GET _baseDirs ${i} _baseDir)
list(GET _pathTypes ${i} _pathType)
if (_pathType STREQUAL ".")
# Handle the workaround we had to do for empty path types
set(_pathType "")
endif()
file(RELATIVE_PATH _relativeFilePath "${_baseDir}" "${_filePath}")
SET(_outputBasePath "${CMAKE_CURRENT_BINARY_DIR}/embedded_files/${_relativeFilePath}")
# For some reason this is needed...
get_filename_component(_outputDirectory ${_outputBasePath} DIRECTORY)
file(MAKE_DIRECTORY ${_outputDirectory})
# Retrieve the path type name from the relative path
file(TO_NATIVE_PATH "${_pathType}" _pathType)
if (MINGW)
# There is a bug in CMake where it thinks MinGW uses forward slashes for paths but we need backslashes for Windows builds
string(REPLACE "/" "\\" _pathType "${_pathType}")
endif()
# Properly escape back slashes in strings
string(REPLACE "\\" "\\\\" _pathType "${_pathType}")
get_filename_component(FILE_NAME "${_relativeFilePath}" NAME)
string(MAKE_C_IDENTIFIER "${_relativeFilePath}" FIELD_NAME)
set(HEADER_FILE "${_outputBasePath}.h")
set(SOURCE_FILE "${_outputBasePath}.cpp")
set(ALL_OUTPUTS "${HEADER_FILE}" "${SOURCE_FILE}")
set(FIELD_NAME "Embedded_${FIELD_NAME}")
set(INCLUDE_LIST "${INCLUDE_LIST}\n#include \"${HEADER_FILE}\"")
set(ARRAY_ELEMENTS "${ARRAY_ELEMENTS}\n\t{ \"${_pathType}\", \"${FILE_NAME}\" , ${FIELD_NAME} , ${FIELD_NAME}_size },")
add_custom_command(
OUTPUT ${ALL_OUTPUTS}
COMMAND embedfile "${_filePath}" "${_outputBasePath}" "${FIELD_NAME}"
MAIN_DEPENDENCY "${_filePath}"
COMMENT "Generating string file for ${_filePath}"
)
list(APPEND DEF_OUT_FILES ${ALL_OUTPUTS})
ENDFOREACH()
configure_file("${_EMBEDD_FILE_BASE_DIR}/embedded_files.inc.in" "${CMAKE_CURRENT_BINARY_DIR}/embedded_files/embedded_files.inc")
target_include_directories(${_target} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/embedded_files")
target_sources(${_target} PRIVATE ${DEF_OUT_FILES})
source_group("Generated Files\\Embedded Files" FILES ${DEF_OUT_FILES})
endfunction()
+2 -2
View File
@@ -20,8 +20,8 @@ target_link_libraries(platform INTERFACE ${WIN32_LIBS})
target_compile_definitions(platform INTERFACE WIN32 USE_OPENAL _WINDOWS)
# Specify minimum Windows version for the headers (currently this is Vista)
target_compile_definitions(platform INTERFACE NTDDI_VERSION=0x06000000 _WIN32_WINNT=0x0600)
# Specify minimum Windows version for the headers (currently this is XP)
target_compile_definitions(platform INTERFACE NTDDI_VERSION=0x05010000 _WIN32_WINNT=0x0501)
SET(EXE_GUI_TYPE WIN32)
set(PLATFORM_WINDOWS TRUE CACHE INTERNAL "" FORCE)
+3
View File
@@ -21,6 +21,8 @@ endif()
set(CMAKE_EXTRA_INCLUDE_FILES "cstddef")
CHECK_TYPE_SIZE("std::max_align_t" STD_MAX_ALIGN_T LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES "type_traits")
CHECK_TYPE_SIZE("std::is_trivially_copyable<int>" STD_IS_TRIVIALLY_COPYABLE LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES)
CHECK_TYPE_SIZE("char32_t" CHAR32_T LANGUAGE CXX)
@@ -40,6 +42,7 @@ CHECK_FUNCTION_EXISTS(strlwr SCP_HAVE_STRLWR)
CHECK_INCLUDE_FILE("strings.h" SCP_HAVE_STRINGS_H)
check_symbol_exists(snprintf "stdio.h" SCP_HAVE_SNPRINTF)
check_symbol_exists(_snprintf "stdio.h" SCP_HAVE__SNPRINTF)
set(PLATFORM_CHECK_HEADER "${GENERATED_SOURCE_DIR}/platformChecks.h")
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/platformChecks.h.in "${PLATFORM_CHECK_HEADER}")
+2
View File
@@ -8,6 +8,8 @@
#cmakedefine SCP_HAVE_MAX_ALIGN_T
#cmakedefine SCP_HAVE_STD_MAX_ALIGN_T
#cmakedefine01 HAVE_STD_IS_TRIVIALLY_COPYABLE
#cmakedefine01 IS_64BIT
#cmakedefine01 SCP_HAVE_STRCASECMP
-12
View File
@@ -23,7 +23,6 @@ endif()
if (CLANG_USE_LIBCXX)
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -stdlib=libc++")
target_link_libraries(compiler INTERFACE "c++" "c++abi")
endif()
# Initialize with an empty string to make sure we always get a clean start
@@ -118,14 +117,3 @@ endif()
# Always define this to make sure that the fixed width format macros are available
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
# GNU ar: Create thin archive files.
# Requires binutils-2.19 or later.
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcTP <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> qTP <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qcTP <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> qTP <TARGET> <LINK_FLAGS> <OBJECTS>")
endif()
target_link_libraries(compiler INTERFACE m)
+8 -39
View File
@@ -8,8 +8,6 @@ MESSAGE(STATUS "Doing configuration specific to gcc...")
option(GCC_ENABLE_LEAK_CHECK "Enable -fsanitize=leak" OFF)
option(GCC_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)
option(GCC_ENABLE_SANITIZE_UNDEFINED "Enable -fsanitize=undefined" OFF)
option(GCC_USE_GOLD "Use the gold linker instead of the standard linker" OFF)
option(GCC_GENERATE_GDB_INDEX "Adds linker option to generate the gdb index for debug builds" OFF)
# These are the default values
set(C_BASE_FLAGS "-march=native -pipe")
@@ -25,16 +23,6 @@ endif()
# Initialize with an empty string to make sure we always get a clean start
set(COMPILER_FLAGS "")
set(LINKER_FLAGS "")
if (GCC_USE_GOLD)
OPTION(GCC_INCREMENTAL_LINKING "Use incremental linking" OFF)
set(LINKER_FLAGS "${LINKER_FLAGS} -fuse-ld=gold")
if (GCC_INCREMENTAL_LINKING)
set(LINKER_FLAGS "${LINKER_FLAGS} -fno-use-linker-plugin -Wl,-z,norelro -Wl,--incremental")
endif()
endif()
# This is a slight hack since our flag setup is a bit more complicated
_enable_extra_compiler_warnings_flags()
@@ -42,11 +30,9 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
if (NOT GCC_INCREMENTAL_LINKING)
# Place each function and data in its own section so the linker can
# perform dead code elimination
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdata-sections -ffunction-sections")
endif()
# Place each function and data in its own section so the linker can
# perform dead code elimination
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdata-sections -ffunction-sections")
if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
# Force color diagnostics for Ninja generator
@@ -112,7 +98,7 @@ set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variabl
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
# Always use the base flags and add our compiler flags at the back
# Always use the base flags and add our compiler flags at the bacl
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
@@ -122,7 +108,7 @@ set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
set(CMAKE_CXX_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
set(CMAKE_EXE_LINKER_FLAGS "${LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "")
IF (MINGW)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++ -Wl,--enable-auto-import")
@@ -135,25 +121,17 @@ endif()
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g")
if (GCC_GENERATE_GDB_INDEX)
# For pure debug binaries, generate a gdb index for better debugging
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -Wl,--gdb-index")
endif()
IF(NOT MINGW)
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -rdynamic")
# Allow the linker to perform dead code elimination; this is considered
# experimental for COFF and PE formats and thus disabled for Windows builds
# (https://sourceware.org/binutils/docs/ld/Options.html)
if (NOT GCC_INCREMENTAL_LINKING AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
endif()
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
ENDIF(NOT MINGW)
IF(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-zignore")
ENDIF()
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,-zignore")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
if (FSO_FATAL_WARNINGS)
# Make warnings fatal if the right variable is set
@@ -162,12 +140,3 @@ endif()
# Always define this to make sure that the fixed width format macros are available
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS=1)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
# GNU ar: Create thin archive files.
# Requires binutils-2.19 or later.
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcTP <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> qTP <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qcTP <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> qTP <TARGET> <LINK_FLAGS> <OBJECTS>")
endif()
-3
View File
@@ -17,9 +17,6 @@ ELSE("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
MESSAGE(STATUS "No special handling for this compiler present, good luck!")
ENDIF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
find_package(Threads REQUIRED)
target_link_libraries(compiler INTERFACE Threads::Threads)
# Copy release settings to FastDebug
set(CMAKE_C_FLAGS_FASTDEBUG "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_RELEASE}")
+7 -43
View File
@@ -140,34 +140,14 @@ macro(set_if_not_defined VAR VALUE)
endif()
endmacro(set_if_not_defined)
function(set_precompiled_header _target _headerPath)
if (COMMAND target_precompile_headers)
target_compile_definitions(${_target} PRIVATE CMAKE_PCH)
target_precompile_headers(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${_headerPath}>")
else()
if (ENABLE_COTIRE)
message("${_headerPath}")
set_target_properties(${_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${_headerPath}")
macro(configure_cotire target)
if(ENABLE_COTIRE)
# Disable unity build as it doesn't work well for us
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
# Disable unity build as it doesn't work well for us
set_target_properties(${_target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
cotire(${_target})
else()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${_headerPath}>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
ELSE()
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
ENDIF()
endif()
cotire(${target})
endif()
endfunction()
endmacro(configure_cotire)
macro(add_target_copy_files)
foreach(file ${ARGN})
@@ -204,7 +184,7 @@ function(detect_simd_instructions _out_var)
endfunction()
function (check_linker_flag _flag _out_var)
SET(CMAKE_REQUIRED_LINK_OPTIONS "${_flag}")
SET(CMAKE_REQUIRED_FLAGS "${_flag}")
CHECK_C_COMPILER_FLAG("" ${_out_var})
endfunction(check_linker_flag)
@@ -218,22 +198,6 @@ function(suppress_warnings _target)
endif()
endfunction(suppress_warnings)
# Suppresses warnings for the specified files
function(suppress_file_warnings)
if (MSVC)
set_source_files_properties(
${ARGN}
PROPERTIES
COMPILE_FLAGS "/W0")
else()
# Assume everything else uses GCC style options
set_source_files_properties(
${ARGN}
PROPERTIES
COMPILE_FLAGS "-w")
endif()
endfunction(suppress_file_warnings)
function(list_target_dependencies _target _out_var)
set(out_list)
+3 -3
View File
@@ -6,9 +6,9 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 21)
set_if_not_defined(FSO_VERSION_MINOR 4)
set_if_not_defined(FSO_VERSION_BUILD 1)
set_if_not_defined(FSO_VERSION_MAJOR 20)
set_if_not_defined(FSO_VERSION_MINOR 1)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
set_if_not_defined(FSO_VERSION_REVISION 0)
+24 -29
View File
@@ -1,12 +1,13 @@
include(util)
INCLUDE(source_groups.cmake)
INCLUDE(voice_rec.cmake)
ADD_LIBRARY(code STATIC ${source_files} ${VOICE_REC_FILES})
target_compile_features(code PUBLIC cxx_std_11)
target_compile_features(code PUBLIC ${REQUIRED_CXX_FEATURES})
INCLUDE(default_files.cmake)
if (MSVC)
target_compile_definitions(code PUBLIC "PDB_DEBUGGING=1")
@@ -18,15 +19,12 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${FREESPACE_HEADERS})
TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR})
TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
if (FSO_BUILD_WITH_OPENGL)
target_link_libraries(code PUBLIC OpenGL)
endif()
target_link_libraries(code PUBLIC OpenGL)
TARGET_LINK_LIBRARIES(code PUBLIC openal)
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC lz4)
TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
@@ -47,13 +45,7 @@ target_link_libraries(code PUBLIC libRocket)
target_link_libraries(code PUBLIC pcp)
if (FSO_BUILD_WITH_VULKAN)
target_link_libraries(code PUBLIC vulkan-hpp)
endif()
target_link_libraries(code PUBLIC parsers)
target_link_libraries(code PUBLIC mdns)
target_link_libraries(code PUBLIC vulkan-hpp)
enable_clang_tidy(code)
@@ -64,8 +56,6 @@ ENDIF(FSO_USE_SPEECH)
TARGET_LINK_LIBRARIES(code PUBLIC jansson)
target_link_libraries(code PUBLIC variant)
# Headers for standalone "gui" on UNIX
IF(UNIX)
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
@@ -77,6 +67,22 @@ IF(FSO_BUILD_TOOLS)
ADD_SUBDIRECTORY(cfileextractor)
ENDIF(FSO_BUILD_TOOLS)
if (ENABLE_COTIRE)
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h")
else()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
ELSE()
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
ENDIF()
endif()
if (FSO_RELEASE_LOGGING)
target_compile_definitions(code PUBLIC SCP_RELEASE_LOGGING)
endif()
@@ -84,20 +90,9 @@ endif()
if (FSO_BUILD_WITH_FFMPEG)
target_compile_definitions(code PUBLIC WITH_FFMPEG)
endif()
if (FSO_BUILD_WITH_OPENGL)
target_compile_definitions(code PUBLIC WITH_OPENGL)
endif()
if (FSO_BUILD_WITH_VULKAN)
target_compile_definitions(code PUBLIC WITH_VULKAN)
endif()
include(shaders.cmake)
target_embed_files(code FILES ${default_files_files} RELATIVE_TO "def_files")
handle_embedded_files(code)
set_precompiled_header(code "${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h")
include(util)
configure_cotire(code)
# Ensure that Xcode generates debug symbols on macOS for Debug builds
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
-8
View File
@@ -1,8 +0,0 @@
#include "Action.h"
namespace actions {
Action::~Action() = default;
}
-23
View File
@@ -1,23 +0,0 @@
#pragma once
#include "common.h"
namespace actions {
enum class ActionResult
{
Finished,
Errored,
Wait
};
class Action {
public:
virtual ~Action() = 0;
virtual ActionResult execute(ProgramLocals& locals) const = 0;
virtual std::unique_ptr<Action> clone() const = 0;
};
} // namespace actions
-21
View File
@@ -1,21 +0,0 @@
#include "ActionDefinition.h"
namespace actions {
ActionDefinition::ActionDefinition(SCP_string name, SCP_vector<ActionParameter> parameters)
: m_name(std::move(name)), m_parameters(std::move(parameters))
{
}
ActionDefinition::~ActionDefinition() = default;
const SCP_string& ActionDefinition::getName() const
{
return m_name;
}
const SCP_vector<ActionParameter>& ActionDefinition::getParameters() const
{
return m_parameters;
}
} // namespace actions
-33
View File
@@ -1,33 +0,0 @@
#pragma once
#include "Action.h"
#include "actions/expression/ActionExpression.h"
#include "actions/expression/Value.h"
namespace actions {
struct ActionParameter {
SCP_string name;
expression::ValueType type;
};
class ActionDefinition {
public:
ActionDefinition(SCP_string name, SCP_vector<ActionParameter> parameters);
virtual ~ActionDefinition();
const SCP_string& getName() const;
const SCP_vector<actions::ActionParameter>& getParameters() const;
virtual flagset<ProgramContextFlags> getRequiredContext() const = 0;
virtual std::unique_ptr<Action> createAction(
const SCP_unordered_map<SCP_string, expression::ActionExpression>& parameterExpressions) const = 0;
private:
SCP_string m_name;
SCP_vector<ActionParameter> m_parameters;
};
} // namespace actions
-145
View File
@@ -1,145 +0,0 @@
#include "ActionDefinitionManager.h"
#include "BuiltinActionDefinition.h"
#include "actions/types/MoveToSubmodel.h"
#include "actions/types/ParticleEffectAction.h"
#include "actions/types/PlaySoundAction.h"
#include "actions/types/SetDirectionAction.h"
#include "actions/types/SetPositionAction.h"
#include "actions/types/WaitAction.h"
#include "utils/join_string.h"
namespace actions {
namespace {
void parseActionParameters(const SCP_vector<ActionParameter>& params,
SCP_unordered_map<SCP_string, expression::ActionExpression>& parameterExpressions,
const expression::ParseContext& context)
{
// We do not impose a set order of the parameters so we need to do something similar to the outer loop and
// check for every possibility in a loop.
for (size_t i = 0; i < params.size(); ++i) {
// We might be doing some empty loops here in case of errors but there is a bound so this will finish
// eventually
for (const auto& parameter : params) {
// Do not check for parameters which we already found
if (parameterExpressions.find(parameter.name) != parameterExpressions.end()) {
continue;
}
const auto paramString = "+" + parameter.name + ":";
if (!optional_string(paramString.c_str())) {
continue;
}
// We found our parameter!
parameterExpressions[parameter.name] =
expression::ActionExpression::parseFromTable(parameter.type, context);
break;
}
}
}
} // namespace
const ActionDefinitionManager& ActionDefinitionManager::instance()
{
static const ActionDefinitionManager manager;
return manager;
}
void ActionDefinitionManager::addDefinition(std::unique_ptr<ActionDefinition> def)
{
m_definitions.push_back(std::move(def));
}
std::unique_ptr<Action> ActionDefinitionManager::parseAction(const flagset<ProgramContextFlags>& context_flags,
const expression::ParseContext& context) const
{
// We search through all definitions for every time we want to check for an action. This is not the most efficient
// way to handle this since it results in an O(n^2) runtime. A better alternative would be to either construct a
// regex with all the accepted actions as alternatives (although runtime of this is also doubtful) or peek at the
// next token, extract the relevant part (The stuff between "+" and ":") and then look that up in a map. Then we
// would get down to O(n).
// Since this only happens at parse time, this is good enough for now.
for (const auto& actionDef : m_definitions) {
const auto parseString = "+" + actionDef->getName() + ":";
if (!optional_string(parseString.c_str())) {
continue;
}
SCP_unordered_map<SCP_string, expression::ActionExpression> parameterExpressions;
const auto& params = actionDef->getParameters();
if (params.size() == 1) {
// Single parameters are expected to be placed directly after the action name
parameterExpressions[params.front().name] =
expression::ActionExpression::parseFromTable(params.front().type, context);
} else {
parseActionParameters(params, parameterExpressions, context);
if (parameterExpressions.size() != params.size()) {
SCP_vector<ActionParameter> missingParameters;
std::copy_if(params.cbegin(),
params.cend(),
std::back_inserter(missingParameters),
[&parameterExpressions](const ActionParameter& param) {
const auto iter = parameterExpressions.find(param.name);
return iter == parameterExpressions.cend();
});
SCP_vector<SCP_string> missingParameterNames;
std::transform(missingParameters.cbegin(),
missingParameters.cend(),
std::back_inserter(missingParameterNames),
[](const ActionParameter& param) { return "+" + param.name; });
const auto namesList = util::join_container(missingParameterNames, ", ");
error_display(0, "Missing parameters for action '%s': %s", parseString.c_str(), namesList.c_str());
// Fix up the parameter list so that we can continue parsing
for (const auto& missingParam : missingParameters) {
parameterExpressions[missingParam.name] = expression::ActionExpression();
}
}
}
auto actionInstance = actionDef->createAction(parameterExpressions);
const auto requiredFlags = actionDef->getRequiredContext();
if ((context_flags & requiredFlags) != requiredFlags) {
// We are missing at least one context flag so this action is not valid here. We still return the action
// here though since that is the only way we can keep parsing the table without throwing random error
// messages at the user. However, this will trigger an Assertion (in debug) or crashes when the action is
// actually run later.
error_display(0,
"The action %s is not available in the current context. This will lead to an Assertion failure when "
"this action is triggered.",
parseString.c_str());
}
return actionInstance;
}
return std::unique_ptr<Action>();
}
ActionDefinitionManager::ActionDefinitionManager()
{
addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::MoveToSubmodel>("Move To Subobject")));
addDefinition(std::unique_ptr<ActionDefinition>(
new BuiltinActionDefinition<types::ParticleEffectAction>("Start Particle Effect")));
addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::PlaySoundAction>("Play 3D Sound")));
addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetDirectionAction>("Set Direction")));
addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetPositionAction>("Set Position")));
addDefinition(std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::WaitAction>("Wait")));
}
} // namespace actions
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include "ActionDefinition.h"
namespace actions {
class ActionDefinitionManager {
public:
// This type is supposed to be global so it may not be copied
ActionDefinitionManager(const ActionDefinitionManager&) = delete;
ActionDefinitionManager& operator=(const ActionDefinitionManager&) = delete;
ActionDefinitionManager(ActionDefinitionManager&&) noexcept = default;
ActionDefinitionManager& operator=(ActionDefinitionManager&&) noexcept = default;
std::unique_ptr<Action> parseAction(const flagset<ProgramContextFlags>& context_flags,
const expression::ParseContext& context) const;
static const ActionDefinitionManager& instance();
private:
ActionDefinitionManager();
void addDefinition(std::unique_ptr<ActionDefinition> def);
SCP_vector<std::unique_ptr<ActionDefinition>> m_definitions;
};
} // namespace actions
-37
View File
@@ -1,37 +0,0 @@
#pragma once
#include "ActionDefinition.h"
#include "expression/Value.h"
namespace actions {
template <typename TAction>
class BuiltinActionDefinition : public ActionDefinition {
using ActionValueType = typename TAction::ValueType;
public:
BuiltinActionDefinition(SCP_string name)
: ActionDefinition(std::move(name), {{"parameter", expression::ValueTypeTraits<ActionValueType>::type}})
{
}
~BuiltinActionDefinition() override = default;
flagset<ProgramContextFlags> getRequiredContext() const override
{
return flagset<ProgramContextFlags>(TAction::getRequiredExecutionContextFlags());
}
std::unique_ptr<Action> createAction(
const SCP_unordered_map<SCP_string, expression::ActionExpression>& parameterExpressions) const override
{
const auto paramIter = parameterExpressions.find("parameter");
// This should have been caught earlier
Assertion(paramIter != parameterExpressions.cend(), "Could not find built-in parameter!");
return std::unique_ptr<Action>(new TAction(paramIter->second.template asTyped<ActionValueType>()));
}
};
} // namespace actions
-174
View File
@@ -1,174 +0,0 @@
#include "Program.h"
#include "Action.h"
#include "actions/ActionDefinitionManager.h"
#include "executor/global_executors.h"
#include "tracing/Monitor.h"
#include "tracing/categories.h"
#include "tracing/tracing.h"
namespace {
using namespace actions;
tracing::Monitor<int> RunningProgramsMonitor("RunningPrograms", 0);
struct ProgramRunner {
tracing::RunningCounter runningCounter{RunningProgramsMonitor};
ProgramInstance instance;
explicit ProgramRunner(const ProgramInstance& _instance) : instance(_instance) {}
executor::Executor::CallbackResult operator()()
{
TRACE_SCOPE(tracing::ProgramStepOne);
auto res = instance.step();
switch (res) {
case ProgramState::Running:
// If the program is still running then we need to reschedule our execution
return executor::Executor::CallbackResult::Reschedule;
case ProgramState::Done:
case ProgramState::Errored:
default:
return executor::Executor::CallbackResult::Done;
}
}
};
} // namespace
namespace actions {
ProgramInstance::ProgramInstance(const actions::Program* program) : _program(program) {}
ProgramState ProgramInstance::step()
{
if (!_locals.host.IsValid()) {
return ProgramState::Done;
}
auto& actions = _program->getActions();
for (; _currentInstruction < actions.size(); ++_currentInstruction) {
auto& action = actions[_currentInstruction];
auto result = action->execute(_locals);
if (result == ActionResult::Errored) {
return ProgramState::Errored;
}
if (result == ActionResult::Wait) {
// Action is not done yet, call again next frame
return ProgramState::Running;
}
// Action finished, run next action in program
}
// End of program reached, we are done now
return ProgramState::Done;
}
ProgramLocals& ProgramInstance::locals()
{
return _locals;
}
const ProgramLocals& ProgramInstance::locals() const
{
return _locals;
}
const SCP_vector<std::unique_ptr<actions::Action>>& Program::getActions() const
{
return _actions;
}
Program::Program() = default;
ProgramInstance Program::newInstance() const
{
return ProgramInstance(this);
}
void Program::parseActions(const flagset<ProgramContextFlags>& context_flags, const expression::ParseContext& context)
{
while (true) {
auto action = ActionDefinitionManager::instance().parseAction(context_flags, context);
if (!action) {
break;
}
_actions.push_back(std::move(action));
}
}
Program::Program(const Program& other) { *this = other; }
Program& Program::operator=(const Program& other)
{
_actions.clear();
_actions.reserve(other._actions.size());
for (auto& action : other._actions) {
_actions.emplace_back(action->clone());
}
return *this;
}
Program& Program::operator=(Program&&) noexcept = default;
Program::Program(Program&&) noexcept = default;
bool ProgramSet::isEmpty() const
{
return _programs.empty();
}
ProgramSet::ProgramSet() = default;
ProgramSet::ProgramSet(const flagset<ProgramContextFlags>& context_flags) : _contextFlags(context_flags) {}
void ProgramSet::start(object* objp, const vec3d* local_pos, const matrix* local_orient, int submodel) const
{
if (_contextFlags[ProgramContextFlags::HasObject]) {
Assertion(objp != nullptr, "Invalid object pointer supplied.");
}
if (_contextFlags[ProgramContextFlags::HasSubobject]) {
Assertion(submodel >= 0, "Invalid subobject supplied.");
}
for (const auto& prog : _programs) {
auto instance = prog.newInstance();
instance.locals().host = object_h(objp);
instance.locals().localPosition = *local_pos;
instance.locals().localOrient = *local_orient;
instance.locals().hostSubobject = submodel;
instance.locals().variables = getDefaultTableVariables();
// Just use the executor system to take care of running this program
executor::OnSimulationExecutor->post(ProgramRunner(instance));
}
}
ProgramSet ProgramSet::parseProgramSet(const char* tag, const flagset<ProgramContextFlags>& context_flags)
{
ProgramSet set(context_flags);
const auto parseContext = getTableParseContext();
while (optional_string(tag)) {
Program p;
p.parseActions(context_flags, parseContext);
set._programs.push_back(std::move(p));
}
return set;
}
} // namespace actions
-112
View File
@@ -1,112 +0,0 @@
#pragma once
#include "globalincs/pstypes.h"
#include "Action.h"
#include "common.h"
namespace actions {
class Program;
class ProgramSet;
enum class ProgramState
{
Running,
Done,
Errored
};
/**
* @brief An instance of a program execution
*
* A program instance contains all information related to a single execution of a program. A program instance is
* independent from other instances. Local variables used by actions are stored in a specific structure which can be
* used by actions to keep track of state in this specific instance.
*/
class ProgramInstance {
size_t _currentInstruction = 0;
ProgramLocals _locals;
const Program* _program = nullptr;
public:
explicit ProgramInstance(const Program* program);
ProgramState step();
ProgramLocals& locals();
const ProgramLocals& locals() const;
};
/**
* @brief A program specified in a table
*
* A program is a sequential collection of Actions which are executed in sequence.
*/
class Program {
SCP_vector<std::unique_ptr<Action>> _actions;
public:
Program();
Program(const Program& other);
Program& operator=(const Program& other);
Program(Program&& other) noexcept;
Program& operator=(Program&& other) noexcept;
const SCP_vector<std::unique_ptr<actions::Action>>& getActions() const;
/**
* @brief Creates a new program instance from this program
*
* The program instance is initialized to its initial values.
*
* @return The new program instance
*/
ProgramInstance newInstance() const;
void parseActions(const flagset<ProgramContextFlags>& context_flags, const expression::ParseContext& context);
};
/**
* @brief A set of parsed programs
*
* Programs are parsed in sets of zero or more programs to make it possible for the content creator to split up
* programs.
*/
class ProgramSet {
flagset<ProgramContextFlags> _contextFlags;
SCP_vector<Program> _programs;
public:
ProgramSet();
explicit ProgramSet(const flagset<ProgramContextFlags>& context_flags);
bool isEmpty() const;
/**
* @brief Starts the execution of all programs within this set with the specified parameters
* @param objp The object on which this program is executed
* @param local_pos The local position relative to the object or the subsystem if specified
* @param local_orien The local orientation relative to the object or the subsystem if specified
* @param submodel The submodel of the model to which this program is attached to.
*/
void start(object* objp, const vec3d* local_pos, const matrix* local_orient, int submodel = -1) const;
/**
* @brief Parses a program set of zero or more programs
*
* The tag is entirely optional and if it doesn't appear in the current table then an empty set will be returned
* which does nothing if started.
*
* @param tag The tag which is required before a program can be specified
* @param context_flags A set of flags which specify in which environment the program will be used. This is used
* mainly for validating the used actions.
* @return The parsed program set.
*/
static ProgramSet parseProgramSet(const char* tag, const flagset<ProgramContextFlags>& context_flags = {});
};
} // namespace actions
-27
View File
@@ -1,27 +0,0 @@
#include "common.h"
namespace actions {
expression::ParseContext getTableParseContext()
{
expression::ParseContext ctx;
auto& locals = ctx.variables.addScope("locals");
locals.addMember("position", expression::ValueType::Vector);
locals.addMember("direction", expression::ValueType::Vector);
return ctx;
}
expression::ProgramVariables getDefaultTableVariables()
{
expression::ProgramVariables vars;
vars.setValue({"locals", "position"}, expression::Value(vmd_zero_vector));
vars.setValue({"locals", "direction"}, expression::Value(vmd_zero_vector));
return vars;
}
} // namespace actions
-59
View File
@@ -1,59 +0,0 @@
#pragma once
#include "globalincs/flagset.h"
#include "actions/expression/ParseContext.h"
#include "actions/expression/ProgramVariables.h"
#include "math/vecmat.h"
#include "object/object.h"
class object;
class ship_subsys;
namespace actions {
struct ProgramLocals {
object_h host;
vec3d localPosition = vmd_zero_vector;
matrix localOrient = vmd_identity_matrix;
int hostSubobject = -1;
int waitTimestamp = 0;
expression::ProgramVariables variables;
};
/**
* @brief A list of flags for altering the program parsing behavior
*
* This should be used for differentiating between different program environments when validating the program (e.g. a
* particle effect requires an object host).
*/
// clang-format off
FLAG_LIST(ProgramContextFlags) {
HasObject = 0, //!< The program will be started with an object host
HasSubobject, //!< The program will be started with a subobject host
NUM_VALUES
};
// clang-format on
/**
* @brief Constructs the "table" parse context
*
* This is the context that is available when parsing a program from an external table (e.g. ships or weapons).
*
* @return The parse context
*/
expression::ParseContext getTableParseContext();
/**
* @brief Gets a program variables instance initialized with the default values
*
* The values are consistent with what is required for the default table parse context;
*
* @return The program variables
*/
expression::ProgramVariables getDefaultTableVariables();
} // namespace actions
@@ -1,66 +0,0 @@
#include "ActionExpression.h"
#include "ExpressionParser.h"
#include "TypeDefinition.h"
#include "actions/expression/nodes/AbstractExpression.h"
namespace actions {
namespace expression {
namespace {
SCP_string getTypeName(ValueType type)
{
const auto& typeDef = TypeDefinition::forValueType(type);
return typeDef.getName();
}
} // namespace
ActionExpression ActionExpression::parseFromTable(ValueType expectedReturnType, const ParseContext& context)
{
SCP_string expressionText;
stuff_string(expressionText, F_NAME);
ExpressionParser parser(expressionText);
auto expression = parser.parse(context);
if (!expression) {
error_display(0, "Failed to parse action expression:\n%s", parser.getErrorText().c_str());
return ActionExpression();
}
auto type = expression->getExpressionType();
// Check if the type this evaluates to matches what we expect
if (!checkTypeWithImplicitConversion(type, expectedReturnType)) {
error_display(0,
"Expression evaluates to type <%s> but <%s> was expected!",
getTypeName(type).c_str(),
getTypeName(expectedReturnType).c_str());
return ActionExpression();
}
// Everything is valid
return ActionExpression(expression);
}
Value ActionExpression::execute(const ProgramVariables& variables) const
{
// Do not crash on invalid expressions
if (!isValid()) {
return Value();
}
return m_expression->execute(variables);
}
bool ActionExpression::isValid() const
{
return m_expression != nullptr;
}
} // namespace expression
} // namespace actions
@@ -1,83 +0,0 @@
#pragma once
#include "ParseContext.h"
#include "ProgramVariables.h"
#include "TypeDefinition.h"
#include "parse/parselo.h"
namespace actions {
namespace expression {
namespace nodes {
class AbstractExpression;
}
template <typename T>
class TypedActionExpression;
/**
* @brief An expression that can be executed to compute a value at runtime
*
* This is the basis of having dynamic values in actions by allowing mods to specify complex expressions that make use
* of variables and functions for computing their values at runtime.
*/
class ActionExpression {
public:
ActionExpression() = default;
Value execute(const ProgramVariables& variables) const;
bool isValid() const;
template <typename T>
TypedActionExpression<T> asTyped() const;
static ActionExpression parseFromTable(ValueType expectedReturnType, const ParseContext& context);
protected:
explicit ActionExpression(std::shared_ptr<nodes::AbstractExpression> expression)
: m_expression(std::move(expression))
{
}
std::shared_ptr<nodes::AbstractExpression> m_expression;
};
/**
* @brief An action expression with a specific type specified at compile time
*
* This is most useful for built-in actions that have the required type fixed at compile time.
*
* @tparam T The type of the expression value.
*/
template <typename T>
class TypedActionExpression {
public:
explicit TypedActionExpression(ActionExpression expression) : m_expression(std::move(expression)) {}
T execute(const ProgramVariables& variables) const
{
// Do not crash on invalid expressions
if (!m_expression.isValid()) {
return T();
}
return m_expression.execute(variables).template get<T>();
}
static TypedActionExpression<T> parseFromTable(const ParseContext& context)
{
return ActionExpression::parseFromTable(ValueTypeTraits<T>::type, context).template asTyped<T>();
}
private:
ActionExpression m_expression;
};
template <typename T>
TypedActionExpression<T> ActionExpression::asTyped() const
{
return TypedActionExpression<T>(*this);
}
} // namespace expression
} // namespace actions
@@ -1,194 +0,0 @@
#include "ExpressionParser.h"
#include "actions/expression/nodes/FunctionCallExpression.h"
#include "actions/expression/nodes/LiteralExpression.h"
#include "actions/expression/nodes/RandomRangeExpression.h"
#include "actions/expression/nodes/VariableReferenceExpression.h"
#include "actions/expression/nodes/VectorConstructorExpression.h"
#include "libs/antlr/ErrorListener.h"
PUSH_SUPPRESS_WARNINGS
#include "action_expression/generated/ActionExpressionLexer.h"
#include "action_expression/generated/ActionExpressionParser.h"
#include "action_expression/generated/ActionExpressionVisitor.h"
POP_SUPPRESS_WARNINGS
namespace actions {
namespace expression {
namespace {
class ExpressionBuilderVisitor : public ActionExpressionVisitor {
public:
antlrcpp::Any visitExpression_main(ActionExpressionParser::Expression_mainContext* context) override
{
return visit(context->expression());
}
antlrcpp::Any visitExpression(ActionExpressionParser::ExpressionContext* context) override
{
if (context->value_expression() != nullptr) {
return visit(context->value_expression());
}
if (context->parenthesis_expression()) {
return visit(context->parenthesis_expression());
}
if (context->random_range_expression()) {
return visit(context->random_range_expression());
}
if (context->variable_reference_expression()) {
return visit(context->variable_reference_expression());
}
// This is an operator so treat it as one.
antlr4::Token* operatorTok;
SCP_string operatorText;
if (context->PLUS() != nullptr) {
operatorTok = context->PLUS()->getSymbol();
operatorText = context->PLUS()->getText();
} else {
operatorTok = context->MINUS()->getSymbol();
operatorText = context->MINUS()->getText();
}
const auto leftExpr = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
const auto rightExpr = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
auto operatorExpression = std::make_shared<nodes::FunctionCallExpression>(operatorTok,
true,
std::move(operatorText),
SCP_vector<std::shared_ptr<nodes::AbstractExpression>>{leftExpr, rightExpr});
return std::static_pointer_cast<nodes::AbstractExpression>(operatorExpression);
}
antlrcpp::Any visitVariable_reference_expression(
ActionExpressionParser::Variable_reference_expressionContext* context) override
{
const auto identifiers = context->IDENTIFIER();
SCP_vector<SCP_string> partNames;
partNames.reserve(identifiers.size());
std::transform(identifiers.begin(),
identifiers.end(),
std::back_inserter(partNames),
[](antlr4::tree::TerminalNode* node) { return node->getText(); });
SCP_vector<antlr4::Token*> partTokens;
partTokens.reserve(identifiers.size());
std::transform(identifiers.begin(),
identifiers.end(),
std::back_inserter(partTokens),
[](antlr4::tree::TerminalNode* node) { return node->getSymbol(); });
auto expression =
std::make_shared<nodes::VariableReferenceExpression>(std::move(partNames), std::move(partTokens));
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
}
antlrcpp::Any visitRandom_range_expression(ActionExpressionParser::Random_range_expressionContext* context) override
{
auto expression = std::make_shared<nodes::RandomRangeExpression>(context->RAND_L_PAREN()->getSymbol(),
visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>(),
visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>());
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
}
antlrcpp::Any visitLiteral_expression(ActionExpressionParser::Literal_expressionContext* context) override
{
std::shared_ptr<nodes::LiteralExpression> expression;
if (context->FLOAT() != nullptr) {
expression = std::make_shared<nodes::LiteralExpression>(context->FLOAT()->getSymbol(),
Value(std::stof(context->FLOAT()->getText())));
} else if (context->INT() != nullptr) {
expression = std::make_shared<nodes::LiteralExpression>(context->INT()->getSymbol(),
Value(std::stoi(context->INT()->getText())));
} else {
const auto idText = context->STRING()->getText();
// Cut off the first and last characters since those are the < > braces
expression = std::make_shared<nodes::LiteralExpression>(context->STRING()->getSymbol(),
Value(idText.substr(1, idText.size() - 2)));
}
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
}
antlrcpp::Any visitParenthesis_expression(ActionExpressionParser::Parenthesis_expressionContext* context) override
{
return visit(context->expression());
}
antlrcpp::Any visitValue_expression(ActionExpressionParser::Value_expressionContext* context) override
{
return visitChildren(context);
}
antlrcpp::Any visitVec3d_constructor(ActionExpressionParser::Vec3d_constructorContext* context) override
{
auto xExpression = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
auto yExpression = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
auto zExpression = visit(context->expression(2)).as<std::shared_ptr<nodes::AbstractExpression>>();
auto expression = std::make_shared<nodes::VectorConstructorExpression>(context->L_PAREN()->getSymbol(),
xExpression,
yExpression,
zExpression);
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
}
};
} // namespace
ExpressionParser::ExpressionParser(SCP_string expressionText) : m_expressionText(std::move(expressionText)) {}
std::shared_ptr<nodes::AbstractExpression> ExpressionParser::parse(const ParseContext& context)
{
antlr4::ANTLRInputStream input(m_expressionText);
ActionExpressionLexer lexer(&input);
antlr4::CommonTokenStream tokens(&lexer);
::ActionExpressionParser parser(&tokens);
// By default we log to stderr which we do not want
parser.removeErrorListeners();
libs::antlr::ErrorListener errListener;
parser.addErrorListener(&errListener);
antlr4::tree::ParseTree* tree = parser.expression_main();
std::shared_ptr<nodes::AbstractExpression> exprReturn;
if (errListener.diagnostics.empty()) {
// Only do semantic checking if syntax is valid
ExpressionBuilderVisitor builder;
exprReturn = tree->accept(&builder).as<std::shared_ptr<nodes::AbstractExpression>>();
if (!exprReturn->validate(&parser, context)) {
exprReturn = nullptr;
} else {
exprReturn->validationDone();
}
}
if (!errListener.diagnostics.empty()) {
SCP_stringstream outStream;
for (const auto& diag : errListener.diagnostics) {
SCP_string tokenUnderline;
if (diag.tokenLength > 1) {
tokenUnderline = SCP_string(diag.tokenLength - 1, '~');
}
outStream << m_expressionText << "\n"
<< SCP_string(diag.columnInLine, ' ') << "^" << tokenUnderline << "\n"
<< diag.errorMessage << "\n";
}
m_errorText = outStream.str();
return nullptr;
}
return exprReturn;
}
const SCP_string& ExpressionParser::getErrorText() const
{
return m_errorText;
}
} // namespace expression
} // namespace actions
@@ -1,27 +0,0 @@
#pragma once
#include "globalincs/pstypes.h"
#include "ParseContext.h"
#include "actions/expression/nodes/AbstractExpression.h"
namespace actions {
namespace expression {
class ExpressionParser {
public:
ExpressionParser(SCP_string expressionText);
std::shared_ptr<nodes::AbstractExpression> parse(const ParseContext& context);
const SCP_string& getErrorText() const;
private:
SCP_string m_expressionText;
SCP_string m_errorText;
};
} // namespace expression
} // namespace actions
@@ -1,90 +0,0 @@
#include "FunctionManager.h"
#include "TypeDefinition.h"
#include "math/vecmat.h"
namespace actions {
namespace expression {
namespace {
template <typename T>
Value value_plus(const SCP_vector<Value>& parameters)
{
return Value(parameters[0].get<T>() + parameters[1].get<T>());
}
template <typename T>
Value value_minus(const SCP_vector<Value>& parameters)
{
return Value(parameters[0].get<T>() - parameters[1].get<T>());
}
} // namespace
const FunctionManager& FunctionManager::instance()
{
static const FunctionManager manager;
return manager;
}
void FunctionManager::addOperator(const SCP_string& name,
std::initializer_list<ValueType> parameterTypes,
ValueType returnType,
FunctionImplementation implementation)
{
m_operators[name].push_back({name, parameterTypes, returnType, std::move(implementation)});
}
const FunctionDefinition* FunctionManager::findOperator(const SCP_string& name,
const SCP_vector<ValueType>& parameters) const
{
const auto iter = m_operators.find(name);
if (iter == m_operators.end()) {
return nullptr;
}
// Prefer exact matches
for (const auto& funcDef : iter->second) {
if (funcDef.parameterTypes == parameters) {
return &funcDef;
}
}
// Now check if there are matches with implicit conversions
for (const auto& funcDef : iter->second) {
// Reject functions with different amount of elements
if (funcDef.parameterTypes.size() != parameters.size()) {
continue;
}
auto funcParamIter = funcDef.parameterTypes.cbegin();
auto actualParamIter = parameters.cbegin();
bool match = true;
for (; funcParamIter != funcDef.parameterTypes.cend(); ++funcParamIter, ++actualParamIter) {
if (!checkTypeWithImplicitConversion(*actualParamIter, *funcParamIter)) {
// Also doesn't match with implicit conversions
match = false;
break;
}
}
if (match) {
return &funcDef;
}
}
return nullptr;
}
FunctionManager::FunctionManager()
{
addOperator("+", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_plus<int>);
addOperator("+", {ValueType::Float, ValueType::Float}, ValueType::Float, value_plus<float>);
addOperator("+", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_plus<vec3d>);
addOperator("-", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_minus<int>);
addOperator("-", {ValueType::Float, ValueType::Float}, ValueType::Float, value_minus<float>);
addOperator("-", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_minus<vec3d>);
}
} // namespace expression
} // namespace actions
-45
View File
@@ -1,45 +0,0 @@
#pragma once
#include "Value.h"
namespace actions {
namespace expression {
using FunctionImplementation = std::function<Value(const SCP_vector<Value>& parameters)>;
struct FunctionDefinition {
SCP_string name;
SCP_vector<ValueType> parameterTypes;
ValueType returnType;
FunctionImplementation implementation;
};
class FunctionManager {
public:
// This type is supposed to be global so it may not be copied
FunctionManager(const FunctionManager&) = delete;
FunctionManager& operator=(const FunctionManager&) = delete;
FunctionManager(FunctionManager&&) noexcept = default;
FunctionManager& operator=(FunctionManager&&) noexcept = default;
void addOperator(const SCP_string& name,
std::initializer_list<ValueType> parameterTypes,
ValueType returnType,
FunctionImplementation implementation);
const FunctionDefinition* findOperator(const SCP_string& name, const SCP_vector<ValueType>& parameterTypes) const;
static const FunctionManager& instance();
private:
FunctionManager();
SCP_unordered_map<SCP_string, SCP_vector<FunctionDefinition>> m_operators;
};
} // namespace expression
} // namespace actions
-13
View File
@@ -1,13 +0,0 @@
#pragma once
#include "ProgramVariables.h"
namespace actions {
namespace expression {
struct ParseContext {
ProgramVariablesDefinition variables;
};
} // namespace expression
} // namespace actions
@@ -1,61 +0,0 @@
#include "ProgramVariables.h"
namespace actions {
namespace expression {
ProgramVariablesDefinition& ProgramVariablesDefinition::addScope(const SCP_string& name)
{
auto scope = std::unique_ptr<ProgramVariablesDefinition>(new ProgramVariablesDefinition());
auto scopePtr = scope.get();
m_scopes.insert(std::make_pair(name, std::move(scope)));
return *scopePtr;
}
void ProgramVariablesDefinition::addMember(const SCP_string& name, ValueType type)
{
m_memberTypes[name] = type;
}
ProgramVariablesDefinition* ProgramVariablesDefinition::getScope(const SCP_string& name) const
{
const auto iter = m_scopes.find(name);
if (iter == m_scopes.cend()) {
return nullptr;
}
return iter->second.get();
}
ValueType ProgramVariablesDefinition::getMemberType(const SCP_string& name) const
{
const auto iter = m_memberTypes.find(name);
if (iter == m_memberTypes.cend()) {
return ValueType::Invalid;
}
return iter->second;
}
Value ProgramVariables::getValue(std::initializer_list<const char*> memberPathParts) const
{
return getValue<decltype(memberPathParts)>(memberPathParts);
}
void ProgramVariables::setValue(std::initializer_list<const char*> memberPathParts, Value value)
{
setValue<decltype(memberPathParts)>(memberPathParts, std::move(value));
}
Value ProgramVariables::getValue(const SCP_string& fullMemberName) const
{
const auto iter = m_values.find(fullMemberName);
// This should have been validated earlier
Assertion(iter != m_values.end(), "Could not find member %s in variables!", fullMemberName.c_str());
return iter->second;
}
} // namespace expression
} // namespace actions
@@ -1,61 +0,0 @@
#pragma once
#include "Value.h"
#include "utils/join_string.h"
namespace actions {
namespace expression {
struct ProgramVariables {
public:
template <typename TContainer>
static SCP_string getMemberName(const TContainer& memberPathParts)
{
return util::join_container(memberPathParts, ".");
}
template <typename TContainer>
Value getValue(const TContainer& memberPathParts) const
{
const auto name = getMemberName(memberPathParts);
return getValue(name);
}
Value getValue(std::initializer_list<const char*> memberPathParts) const;
Value getValue(const SCP_string& fullMemberName) const;
template <typename TContainer>
void setValue(const TContainer& memberPathParts, Value value)
{
const auto name = getMemberName(memberPathParts);
m_values[name] = std::move(value);
}
void setValue(std::initializer_list<const char*> memberPathParts, Value value);
private:
SCP_unordered_map<SCP_string, Value> m_values;
};
class ProgramVariablesDefinition {
public:
ProgramVariablesDefinition& addScope(const SCP_string& name);
void addMember(const SCP_string& name, ValueType type);
ProgramVariablesDefinition* getScope(const SCP_string& name) const;
ValueType getMemberType(const SCP_string& name) const;
private:
SCP_unordered_map<SCP_string, std::unique_ptr<ProgramVariablesDefinition>> m_scopes;
SCP_unordered_map<SCP_string, ValueType> m_memberTypes;
};
} // namespace expression
} // namespace actions
@@ -1,60 +0,0 @@
#include "TypeDefinition.h"
namespace actions {
namespace expression {
// Integers can be safely converted to floats (for the most part)
TypeDefinition TypeDefinition::s_integer("Integer", {ValueType::Float});
// No implicit conversions here
TypeDefinition TypeDefinition::s_float("Float", {});
TypeDefinition TypeDefinition::s_vector("Vector", {});
// Identifiers are a technicality needed for making non-math values work but they have no further use other than their
// string content
TypeDefinition TypeDefinition::s_identifier("Identifier", {});
TypeDefinition::TypeDefinition(SCP_string name, SCP_vector<actions::expression::ValueType> allowedImplicitConversion)
: m_name(std::move(name)), m_allowedImplicitConversions(std::move(allowedImplicitConversion))
{
}
const SCP_string& TypeDefinition::getName() const
{
return m_name;
}
const SCP_vector<actions::expression::ValueType>& TypeDefinition::getAllowedImplicitConversions() const
{
return m_allowedImplicitConversions;
}
const TypeDefinition& TypeDefinition::forValueType(ValueType type)
{
switch (type) {
case ValueType::Integer:
return s_integer;
case ValueType::Float:
return s_float;
case ValueType::Vector:
return s_vector;
case ValueType::String:
return s_identifier;
default:
UNREACHABLE("Invalid value type!");
return s_integer; // Make compiler happy
}
}
bool checkTypeWithImplicitConversion(ValueType currentType, ValueType expectedType)
{
if (currentType == expectedType) {
// No need to consider implicit conversions;
return true;
}
const auto& currentTypeDef = TypeDefinition::forValueType(currentType);
const auto& allowedConversions = currentTypeDef.getAllowedImplicitConversions();
// For now, no transitiv conversions are allowed
return std::find(allowedConversions.cbegin(), allowedConversions.cend(), expectedType) != allowedConversions.cend();
}
} // namespace expression
} // namespace actions
-40
View File
@@ -1,40 +0,0 @@
#pragma once
#include "Value.h"
namespace actions {
namespace expression {
class TypeDefinition {
public:
TypeDefinition(SCP_string name, SCP_vector<actions::expression::ValueType> allowedImplicitConversion);
const SCP_string& getName() const;
const SCP_vector<actions::expression::ValueType>& getAllowedImplicitConversions() const;
static const TypeDefinition& forValueType(ValueType type);
// This type is supposed to be global so it may not be copied
TypeDefinition(const TypeDefinition&) = delete;
TypeDefinition& operator=(const TypeDefinition&) = delete;
TypeDefinition(TypeDefinition&&) = delete;
TypeDefinition& operator=(TypeDefinition&&) = delete;
private:
SCP_string m_name;
// The types this type is allowed to implicitly convert to
SCP_vector<ValueType> m_allowedImplicitConversions;
static TypeDefinition s_integer;
static TypeDefinition s_float;
static TypeDefinition s_vector;
static TypeDefinition s_identifier;
};
bool checkTypeWithImplicitConversion(ValueType currentType, ValueType expectedType);
} // namespace expression
} // namespace actions
-80
View File
@@ -1,80 +0,0 @@
#include "Value.h"
#include "math/vecmat.h"
namespace actions {
namespace expression {
Value::Value(int val) : m_value(val) {}
Value::Value(float val) : m_value(val) {}
Value::Value(const vec3d& val) : m_value(val) {}
Value::Value(SCP_string val) : m_value(std::move(val)) {}
ValueType actions::expression::Value::getType() const
{
switch (m_value.index()) {
case 1:
return ValueType::Integer;
case 2:
return ValueType::Float;
case 3:
return ValueType::Vector;
case 4:
return ValueType::String;
default:
return ValueType::Invalid;
}
}
int Value::getInteger() const
{
return get<int>();
}
float Value::getFloat() const
{
return get<float>();
}
vec3d Value::getVector() const
{
return get<vec3d>();
}
SCP_string Value::getIdentifier() const
{
return get<SCP_string>();
}
bool operator==(const Value& lhs, const Value& rhs)
{
return lhs.m_value == rhs.m_value;
}
bool operator!=(const Value& lhs, const Value& rhs)
{
return !(rhs == lhs);
}
std::ostream& operator<<(std::ostream& os, const Value& value)
{
os << "Value<";
switch (value.getType()) {
case ValueType::Invalid:
os << "INVALID";
break;
case ValueType::Integer:
os << value.get<int>();
break;
case ValueType::Float:
os << value.get<float>();
break;
case ValueType::Vector:
os << value.get<vec3d>();
break;
case ValueType::String:
os << value.get<SCP_string>();
break;
}
os << ">";
return os;
}
} // namespace expression
} // namespace actions
-104
View File
@@ -1,104 +0,0 @@
#pragma once
#include "globalincs/pstypes.h"
#include <mpark/variant.hpp>
namespace actions {
namespace expression {
namespace detail {
template <typename ToType>
struct implicit_conversion {
template <typename T>
ToType operator()(const T&)
{
throw std::runtime_error("Invalid implicit conversion.");
}
};
template<>
struct implicit_conversion<float> {
inline float operator()(int val) {
return i2fl(val);
}
template <typename T>
float operator()(const T&)
{
throw std::runtime_error("Invalid implicit conversion.");
}
};
} // namespace detail
enum class ValueType
{
Invalid,
Integer,
Float,
Vector,
String,
};
template <typename T>
struct ValueTypeTraits;
template <>
struct ValueTypeTraits<int> {
static constexpr ValueType type = ValueType::Integer;
};
template <>
struct ValueTypeTraits<float> {
static constexpr ValueType type = ValueType::Float;
};
template <>
struct ValueTypeTraits<vec3d> {
static constexpr ValueType type = ValueType::Vector;
};
template <>
struct ValueTypeTraits<SCP_string> {
static constexpr ValueType type = ValueType::String;
};
class Value {
public:
Value() = default;
explicit Value(int val);
explicit Value(float val);
explicit Value(const vec3d& val);
explicit Value(SCP_string val);
ValueType getType() const;
int getInteger() const;
float getFloat() const;
vec3d getVector() const;
SCP_string getIdentifier() const;
template <typename T>
T get() const
{
const auto currentType = getType();
const auto expectedType = ValueTypeTraits<T>::type;
if (currentType == expectedType) {
// No conversion necessary
return mpark::get<T>(m_value);
}
return mpark::visit(detail::implicit_conversion<T>{}, m_value);
}
friend bool operator==(const Value& lhs, const Value& rhs);
friend bool operator!=(const Value& lhs, const Value& rhs);
friend std::ostream& operator<<(std::ostream& os, const Value& value);
private:
mpark::variant<mpark::monostate, int, float, vec3d, SCP_string> m_value;
};
} // namespace expression
} // namespace actions
@@ -1,31 +0,0 @@
#include "AbstractExpression.h"
namespace actions {
namespace expression {
namespace nodes {
AbstractExpression::AbstractExpression(antlr4::Token* token) : m_token(token) {}
AbstractExpression::~AbstractExpression() = default;
antlr4::Token* AbstractExpression::getToken() const
{
return m_token;
}
ValueType AbstractExpression::getExpressionType() const
{
// Since expressions are immutable, caching this will be more efficient
if (m_cachedType == ValueType::Invalid) {
m_cachedType = determineReturnType();
}
return m_cachedType;
}
void AbstractExpression::validationDone()
{
// This pointer will become invalid after this so reset it now to avoid issues
m_token = nullptr;
}
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,38 +0,0 @@
#pragma once
#include "actions/expression/ParseContext.h"
#include "actions/expression/Value.h"
#include <Parser.h>
#include <Token.h>
namespace actions {
namespace expression {
namespace nodes {
class AbstractExpression {
public:
AbstractExpression(antlr4::Token* token);
virtual ~AbstractExpression();
virtual Value execute(const ProgramVariables& variables) const = 0;
virtual bool validate(antlr4::Parser* parser, const ParseContext& context) = 0;
virtual void validationDone();
ValueType getExpressionType() const;
antlr4::Token* getToken() const;
protected:
virtual ValueType determineReturnType() const = 0;
antlr4::Token* m_token = nullptr;
mutable ValueType m_cachedType = ValueType::Invalid;
};
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,95 +0,0 @@
#include "FunctionCallExpression.h"
#include "actions/expression/TypeDefinition.h"
namespace actions {
namespace expression {
namespace nodes {
FunctionCallExpression::FunctionCallExpression(antlr4::Token* token,
bool isOperator,
SCP_string functionName,
SCP_vector<std::shared_ptr<AbstractExpression>> parameterExpressions)
: AbstractExpression(token), m_isOperator(isOperator), m_functionName(std::move(functionName)),
m_parameterExpressions(std::move(parameterExpressions))
{
}
FunctionCallExpression::~FunctionCallExpression() = default;
Value FunctionCallExpression::execute(const ProgramVariables& variables) const
{
SCP_vector<Value> parameterValues;
parameterValues.reserve(m_parameterExpressions.size());
std::transform(m_parameterExpressions.cbegin(),
m_parameterExpressions.cend(),
std::back_inserter(parameterValues),
[&variables](const std::shared_ptr<AbstractExpression>& expression) { return expression->execute(variables); });
return m_functionDef->implementation(parameterValues);
}
bool FunctionCallExpression::validate(antlr4::Parser* parser, const ParseContext& context)
{
bool valid = true;
for (const auto& paramExpression : m_parameterExpressions) {
valid &= paramExpression->validate(parser, context);
}
if (!valid) {
// Exit early if there were errors since the values below are meaningless otherwise
return false;
}
Assertion(m_isOperator, "Non-operator functions are not supported yet!");
SCP_vector<ValueType> parameterTypes;
std::transform(m_parameterExpressions.cbegin(),
m_parameterExpressions.cend(),
std::back_inserter(parameterTypes),
[](const std::shared_ptr<AbstractExpression>& expression) { return expression->getExpressionType(); });
const auto functionDef = FunctionManager::instance().findOperator(m_functionName, parameterTypes);
if (functionDef == nullptr) {
SCP_stringstream paramListStream;
if (!parameterTypes.empty()) {
paramListStream << "<" << TypeDefinition::forValueType(parameterTypes.front()).getName() << ">";
for (auto iter = parameterTypes.cbegin() + 1; iter != parameterTypes.cend(); ++iter) {
paramListStream << ", <" << TypeDefinition::forValueType(*iter).getName() << ">";
}
}
parser->notifyErrorListeners(m_token,
SCP_string("Could not find a definition for the ") + (m_isOperator ? "operator" : "function") + " '" +
m_functionName + "' with parameters (" + paramListStream.str() + ")",
nullptr);
return false;
}
m_functionDef = functionDef;
return true;
}
ValueType FunctionCallExpression::determineReturnType() const
{
return m_functionDef->returnType;
}
void FunctionCallExpression::validationDone()
{
AbstractExpression::validationDone();
// We no longer need this so we can save some memory
m_functionName.clear();
m_functionName.shrink_to_fit();
for (const auto& paramExpression : m_parameterExpressions) {
paramExpression->validationDone();
}
}
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,38 +0,0 @@
#pragma once
#include "AbstractExpression.h"
#include "actions/expression/FunctionManager.h"
#include "actions/expression/Value.h"
namespace actions {
namespace expression {
namespace nodes {
class FunctionCallExpression : public AbstractExpression {
public:
FunctionCallExpression(antlr4::Token* token,
bool isOperator,
SCP_string functionName,
SCP_vector<std::shared_ptr<AbstractExpression>> parameterExpressions);
~FunctionCallExpression() override;
Value execute(const ProgramVariables& variables) const override;
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
void validationDone() override;
protected:
ValueType determineReturnType() const override;
private:
bool m_isOperator;
SCP_string m_functionName;
const FunctionDefinition* m_functionDef = nullptr;
SCP_vector<std::shared_ptr<AbstractExpression>> m_parameterExpressions;
};
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,30 +0,0 @@
#include "LiteralExpression.h"
namespace actions {
namespace expression {
namespace nodes {
LiteralExpression::LiteralExpression(antlr4::Token* token, Value literalValue)
: AbstractExpression(token), m_literalValue(std::move(literalValue))
{
}
LiteralExpression::~LiteralExpression() = default;
Value LiteralExpression::execute(const ProgramVariables& /*variables*/) const
{
return m_literalValue;
}
bool LiteralExpression::validate(antlr4::Parser* /*parser*/, const ParseContext& /*context*/)
{
// Literals are always valid
return true;
}
ValueType LiteralExpression::determineReturnType() const
{
return m_literalValue.getType();
}
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,28 +0,0 @@
#pragma once
#include "AbstractExpression.h"
#include "actions/expression/Value.h"
namespace actions {
namespace expression {
namespace nodes {
class LiteralExpression : public AbstractExpression {
public:
LiteralExpression(antlr4::Token* token, Value literalValue);
~LiteralExpression() override;
Value execute(const ProgramVariables& variables) const override;
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
protected:
ValueType determineReturnType() const override;
private:
Value m_literalValue;
};
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,108 +0,0 @@
#include "RandomRangeExpression.h"
#include "actions/expression/TypeDefinition.h"
#include "utils/RandomRange.h"
namespace actions {
namespace expression {
namespace nodes {
namespace {
template <typename T>
Value executeHelper(const Value& leftVal, const Value& rightVal)
{
auto leftContentVal = leftVal.get<T>();
auto rightContentVal = rightVal.get<T>();
if (leftContentVal == rightContentVal) {
// no need to do random stuff here
return Value(rightContentVal);
}
if (rightContentVal < leftContentVal) {
// We can fix this issue
std::swap(leftContentVal, rightContentVal);
}
// Might be a bit inefficient not to cache this somehow but the bounds can be dynamic
return Value(util::UniformRange<T>(leftContentVal, rightContentVal).next());
}
} // namespace
RandomRangeExpression::RandomRangeExpression(antlr4::Token* token,
std::shared_ptr<AbstractExpression> leftExpression,
std::shared_ptr<AbstractExpression> rightExpression)
: AbstractExpression(token), m_leftExpression(std::move(leftExpression)),
m_rightExpression(std::move(rightExpression))
{
}
RandomRangeExpression::~RandomRangeExpression() = default;
Value RandomRangeExpression::execute(const ProgramVariables& variables) const
{
const auto leftVal = m_leftExpression->execute(variables);
const auto rightVal = m_rightExpression->execute(variables);
if (leftVal.getType() == ValueType::Integer) {
return executeHelper<int>(leftVal, rightVal);
} else {
return executeHelper<float>(leftVal, rightVal);
}
}
bool RandomRangeExpression::validate(antlr4::Parser* parser, const ParseContext& context)
{
bool valid = true;
valid &= m_leftExpression->validate(parser, context);
valid &= m_rightExpression->validate(parser, context);
if (!valid) {
// Exit early if there were errors since the values below are meaningless otherwise
return false;
}
const auto leftType = m_leftExpression->getExpressionType();
const auto rightType = m_rightExpression->getExpressionType();
const auto& leftTypedef = TypeDefinition::forValueType(leftType);
const auto& rightTypedef = TypeDefinition::forValueType(rightType);
// Both values must be the same
if (leftType != rightType) {
parser->notifyErrorListeners(m_rightExpression->getToken(),
"Inconsistent types for random range. Must be the same but got <" + leftTypedef.getName() + "> and <" +
rightTypedef.getName() + ">.",
nullptr);
return false;
}
// And we only support floats or integers
if (leftType != ValueType::Float && leftType != ValueType::Integer) {
parser->notifyErrorListeners(m_leftExpression->getToken(),
"Invalid parameter type for random range. Must be <Float> or <Integer> but got <" + leftTypedef.getName() +
">.",
nullptr);
return false;
}
// Everything is fine.
return true;
}
ValueType RandomRangeExpression::determineReturnType() const
{
// Return type is the same as the contained return types
return m_leftExpression->getExpressionType();
}
void RandomRangeExpression::validationDone()
{
AbstractExpression::validationDone();
m_leftExpression->validationDone();
m_rightExpression->validationDone();
}
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,30 +0,0 @@
#pragma once
#include "AbstractExpression.h"
namespace actions {
namespace expression {
namespace nodes {
class RandomRangeExpression : public AbstractExpression {
public:
RandomRangeExpression(antlr4::Token* token,
std::shared_ptr<AbstractExpression> leftExpression,
std::shared_ptr<AbstractExpression> rightExpression);
~RandomRangeExpression() override;
Value execute(const ProgramVariables& variables) const override;
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
void validationDone() override;
protected:
ValueType determineReturnType() const override;
private:
std::shared_ptr<AbstractExpression> m_leftExpression;
std::shared_ptr<AbstractExpression> m_rightExpression;
};
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,69 +0,0 @@
#include "VariableReferenceExpression.h"
namespace actions {
namespace expression {
namespace nodes {
VariableReferenceExpression::VariableReferenceExpression(SCP_vector<SCP_string> references,
SCP_vector<antlr4::Token*> referenceTokens)
: AbstractExpression(referenceTokens.back()), m_references(std::move(references)),
m_referenceTokens(std::move(referenceTokens))
{
}
VariableReferenceExpression::~VariableReferenceExpression() = default;
Value VariableReferenceExpression::execute(const ProgramVariables& variables) const
{
return variables.getValue(m_fullVariablePath);
}
bool VariableReferenceExpression::validate(antlr4::Parser* parser, const ParseContext& context)
{
// Start out in the global scope
auto currentScope = &context.variables;
SCP_string currentScopeName("<global>");
for (size_t i = 0; i < m_references.size() - 1; ++i) {
const auto nextScope = currentScope->getScope(m_references[i]);
if (nextScope == nullptr) {
parser->notifyErrorListeners(m_referenceTokens[i],
"Could not find scope " + m_references[i] + " in scope " + currentScopeName + ".",
nullptr);
return false;
}
currentScope = nextScope;
currentScopeName = m_references[i];
}
auto variableType = currentScope->getMemberType(m_references.back());
if (variableType == ValueType::Invalid) {
parser->notifyErrorListeners(m_referenceTokens.back(),
"Could not find variable " + m_references.back() + " in scope " + currentScopeName + ".",
nullptr);
return false;
}
// Cache this so we don't duplicate all this code in determineReturnType()
m_variableType = variableType;
m_fullVariablePath = ProgramVariables::getMemberName(m_references);
return true;
}
ValueType VariableReferenceExpression::determineReturnType() const
{
return m_variableType;
}
void VariableReferenceExpression::validationDone()
{
AbstractExpression::validationDone();
// Clear these since they are not necessary anymore
m_references.clear();
m_referenceTokens.clear();
}
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,32 +0,0 @@
#pragma once
#include "AbstractExpression.h"
namespace actions {
namespace expression {
namespace nodes {
class VariableReferenceExpression : public AbstractExpression {
public:
VariableReferenceExpression(const SCP_vector<SCP_string> references,
SCP_vector<antlr4::Token*> referenceTokens);
~VariableReferenceExpression() override;
Value execute(const ProgramVariables& variables) const override;
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
void validationDone() override;
protected:
ValueType determineReturnType() const override;
private:
ValueType m_variableType = ValueType::Invalid;
SCP_string m_fullVariablePath;
SCP_vector<SCP_string> m_references;
SCP_vector<antlr4::Token*> m_referenceTokens;
};
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,87 +0,0 @@
#include "VectorConstructorExpression.h"
#include "actions/expression/TypeDefinition.h"
namespace actions {
namespace expression {
namespace nodes {
VectorConstructorExpression::VectorConstructorExpression(antlr4::Token* token,
std::shared_ptr<AbstractExpression> xExpression,
std::shared_ptr<AbstractExpression> yExpression,
std::shared_ptr<AbstractExpression> zExpression)
: AbstractExpression(token), m_xExpression(std::move(xExpression)), m_yExpression(std::move(yExpression)),
m_zExpression(std::move(zExpression))
{
}
VectorConstructorExpression::~VectorConstructorExpression() = default;
Value VectorConstructorExpression::execute(const ProgramVariables& variables) const
{
auto xValue = m_xExpression->execute(variables);
auto yValue = m_yExpression->execute(variables);
auto zValue = m_zExpression->execute(variables);
vec3d vecVal;
vecVal.xyz.x = xValue.getFloat();
vecVal.xyz.y = yValue.getFloat();
vecVal.xyz.z = zValue.getFloat();
return Value(vecVal);
}
bool VectorConstructorExpression::validate(antlr4::Parser* parser, const ParseContext& context)
{
bool valid = true;
valid &= m_xExpression->validate(parser, context);
valid &= m_yExpression->validate(parser, context);
valid &= m_zExpression->validate(parser, context);
if (!valid) {
// Exit early if there were errors since the values below are meaningless otherwise
return false;
}
if (!checkTypeWithImplicitConversion(m_xExpression->getExpressionType(), ValueType::Float)) {
const auto& typeDef = TypeDefinition::forValueType(m_xExpression->getExpressionType());
parser->notifyErrorListeners(m_xExpression->getToken(),
"Invalid value type for vector constructor. Expected <Float>, got <" + typeDef.getName() + ">",
nullptr);
valid = false;
}
if (!checkTypeWithImplicitConversion(m_yExpression->getExpressionType(), ValueType::Float)) {
const auto& typeDef = TypeDefinition::forValueType(m_yExpression->getExpressionType());
parser->notifyErrorListeners(m_yExpression->getToken(),
"Invalid value type for vector constructor. Expected <Float>, got <" + typeDef.getName() + ">",
nullptr);
valid = false;
}
if (!checkTypeWithImplicitConversion(m_zExpression->getExpressionType(), ValueType::Float)) {
const auto& typeDef = TypeDefinition::forValueType(m_zExpression->getExpressionType());
parser->notifyErrorListeners(m_zExpression->getToken(),
"Invalid value type for vector constructor. Expected <Float>, got <" + typeDef.getName() + ">",
nullptr);
valid = false;
}
return valid;
}
ValueType VectorConstructorExpression::determineReturnType() const
{
// No need to look at the expressions here since we will always be a vector
return ValueType::Vector;
}
void VectorConstructorExpression::validationDone()
{
AbstractExpression::validationDone();
m_xExpression->validationDone();
m_yExpression->validationDone();
m_zExpression->validationDone();
}
} // namespace nodes
} // namespace expression
} // namespace actions
@@ -1,34 +0,0 @@
#pragma once
#include "AbstractExpression.h"
#include "actions/expression/Value.h"
namespace actions {
namespace expression {
namespace nodes {
class VectorConstructorExpression : public AbstractExpression {
public:
VectorConstructorExpression(antlr4::Token* token,
std::shared_ptr<AbstractExpression> xExpression,
std::shared_ptr<AbstractExpression> yExpression,
std::shared_ptr<AbstractExpression> zExpression);
~VectorConstructorExpression() override;
Value execute(const ProgramVariables& variables) const override;
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
void validationDone() override;
protected:
ValueType determineReturnType() const override;
private:
std::shared_ptr<AbstractExpression> m_xExpression;
std::shared_ptr<AbstractExpression> m_yExpression;
std::shared_ptr<AbstractExpression> m_zExpression;
};
} // namespace nodes
} // namespace expression
} // namespace actions
-79
View File
@@ -1,79 +0,0 @@
#include "MoveToSubmodel.h"
#include "math/vecmat.h"
#include "parse/parselo.h"
#include "ship/ship.h"
#include <utility>
namespace actions {
namespace types {
flagset<ProgramContextFlags> MoveToSubmodel::getRequiredExecutionContextFlags()
{
return flagset<ProgramContextFlags>{ProgramContextFlags::HasObject, ProgramContextFlags::HasSubobject};
}
MoveToSubmodel::MoveToSubmodel(expression::TypedActionExpression<ValueType> subObjectExpression)
: m_subObjectExpression(std::move(subObjectExpression))
{
}
MoveToSubmodel::~MoveToSubmodel() = default;
ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
{
// The calling code should ensure that this never happens
Assertion(locals.hostSubobject >= 0, "Did not have a valid host subobject.");
auto instance = object_get_model_instance(locals.host.objp);
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
auto pmi = model_get_instance(instance);
auto pm = model_get(pmi->model_num);
const auto destinationSubObject = m_subObjectExpression.execute(locals.variables);
bool goToParent = false;
if (destinationSubObject == "<parent>") {
goToParent = true;
}
if (goToParent) {
// Special case when we simply want to go to our parent without explicitly specifying its name
auto parentSubobject = pm->submodel[locals.hostSubobject].parent;
if (parentSubobject < 0) {
Warning(LOCATION,
"Current program subobject %s on model %s has no parent!",
pm->submodel[locals.hostSubobject].name,
pm->filename);
return ActionResult::Errored;
}
// We have a valid parent so this move will work properly
locals.hostSubobject = parentSubobject;
return ActionResult::Finished;
}
// We need to do a linear search for the right subobject
for (int i = 0; i < pm->n_models; ++i) {
const auto submodel = pm->submodel[i];
if (subsystem_stricmp(destinationSubObject.c_str(), submodel.name) == 0) {
// Found something!
locals.hostSubobject = i;
return ActionResult::Finished;
}
}
Warning(LOCATION, "Could not find subobject %s in model %s!", destinationSubObject.c_str(), pm->filename);
return ActionResult::Errored;
}
std::unique_ptr<Action> MoveToSubmodel::clone() const
{
return std::unique_ptr<Action>(new MoveToSubmodel(*this));
}
} // namespace types
} // namespace actions
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include "globalincs/flagset.h"
#include "actions/Action.h"
#include "actions/expression/ActionExpression.h"
namespace actions {
namespace types {
class MoveToSubmodel : public Action {
public:
using ValueType = SCP_string;
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
explicit MoveToSubmodel(expression::TypedActionExpression<ValueType> subObjectExpression);
~MoveToSubmodel() override;
ActionResult execute(ProgramLocals& locals) const override;
std::unique_ptr<Action> clone() const override;
private:
expression::TypedActionExpression<ValueType> m_subObjectExpression;
};
} // namespace types
} // namespace actions
@@ -1,76 +0,0 @@
#include "ParticleEffectAction.h"
#include "math/vecmat.h"
#include "parse/parselo.h"
#include "ship/ship.h"
#include <utility>
namespace actions {
namespace types {
flagset<ProgramContextFlags> ParticleEffectAction::getRequiredExecutionContextFlags()
{
return flagset<ProgramContextFlags>{ProgramContextFlags::HasObject};
}
ParticleEffectAction::ParticleEffectAction(expression::TypedActionExpression<ValueType> effectExpression)
: m_effectExpression(std::move(effectExpression))
{
}
ParticleEffectAction::~ParticleEffectAction() = default;
ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
{
auto effectIdx = particle::ParticleManager::get()->getEffectByName(m_effectExpression.execute(locals.variables));
if (!effectIdx.isValid()) {
// In case the parsing code failed
return ActionResult::Errored;
}
using namespace particle;
auto source = ParticleManager::get()->createSource(effectIdx);
vec3d local_pos;
matrix local_orient;
if (locals.hostSubobject != -1) {
auto instance = object_get_model_instance(locals.host.objp);
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
auto pmi = model_get_instance(instance);
auto pm = model_get(pmi->model_num);
find_submodel_instance_point_orient(&local_pos,
&local_orient,
pm,
pmi,
locals.hostSubobject,
&locals.localPosition,
&locals.localOrient);
} else {
local_pos = locals.localPosition;
local_orient = locals.localOrient;
}
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
auto direction = locals.variables.getValue({"locals", "direction"}).getVector();
source.moveToObject(locals.host.objp, &local_pos);
source.setOrientationFromNormalizedVec(&direction, true);
source.finish();
return ActionResult::Finished;
}
std::unique_ptr<Action> ParticleEffectAction::clone() const
{
return std::unique_ptr<Action>(new ParticleEffectAction(*this));
}
} // namespace types
} // namespace actions
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include "actions/Action.h"
#include "actions/expression/ActionExpression.h"
#include "particle/ParticleManager.h"
namespace actions {
namespace types {
class ParticleEffectAction : public Action {
public:
using ValueType = SCP_string;
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
explicit ParticleEffectAction(expression::TypedActionExpression<ValueType> effectExpression);
~ParticleEffectAction() override;
ActionResult execute(ProgramLocals& locals) const override;
std::unique_ptr<Action> clone() const override;
private:
expression::TypedActionExpression<ValueType> m_effectExpression;
};
} // namespace types
} // namespace actions
-65
View File
@@ -1,65 +0,0 @@
//
//
#include "PlaySoundAction.h"
#include "ship/ship.h"
#include <utility>
namespace actions {
namespace types {
flagset<ProgramContextFlags> PlaySoundAction::getRequiredExecutionContextFlags()
{
return flagset<ProgramContextFlags>{ProgramContextFlags::HasObject};
}
PlaySoundAction::PlaySoundAction(expression::TypedActionExpression<ValueType> soundIdExpression)
: m_soundIdExpression(std::move(soundIdExpression))
{
}
PlaySoundAction::~PlaySoundAction() = default;
ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
{
vec3d local_pos;
matrix local_orient;
if (locals.hostSubobject != -1) {
auto instance = object_get_model_instance(locals.host.objp);
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
auto pmi = model_get_instance(instance);
auto pm = model_get(pmi->model_num);
find_submodel_instance_point_orient(&local_pos,
&local_orient,
pm,
pmi,
locals.hostSubobject,
&locals.localPosition,
&locals.localOrient);
} else {
local_pos = locals.localPosition;
local_orient = locals.localOrient;
}
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
vec3d global_pos;
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp->orient);
global_pos += locals.host.objp->pos;
const auto soundId = gamesnd_get_by_name(m_soundIdExpression.execute(locals.variables).c_str());
// Sound is not attached to the host but the object sound system currently only supports persistent sounds
snd_play_3d(gamesnd_get_game_sound(soundId), &global_pos, &Eye_position);
return ActionResult::Finished;
}
std::unique_ptr<Action> PlaySoundAction::clone() const
{
return std::unique_ptr<Action>(new PlaySoundAction(*this));
}
} // namespace types
} // namespace actions
-28
View File
@@ -1,28 +0,0 @@
#pragma once
#include "actions/Action.h"
#include "actions/expression/ActionExpression.h"
#include "gamesnd/gamesnd.h"
namespace actions {
namespace types {
class PlaySoundAction : public Action {
public:
using ValueType = SCP_string;
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
explicit PlaySoundAction(expression::TypedActionExpression<ValueType> soundIdExpression);
~PlaySoundAction() override;
ActionResult execute(ProgramLocals& locals) const override;
std::unique_ptr<Action> clone() const override;
private:
expression::TypedActionExpression<ValueType> m_soundIdExpression;
};
} // namespace types
} // namespace actions
-39
View File
@@ -1,39 +0,0 @@
#include "SetDirectionAction.h"
#include "math/vecmat.h"
#include "parse/parselo.h"
#include <utility>
namespace actions {
namespace types {
flagset<ProgramContextFlags> SetDirectionAction::getRequiredExecutionContextFlags()
{
return flagset<ProgramContextFlags>{};
}
SetDirectionAction::SetDirectionAction(expression::TypedActionExpression<vec3d> newDirExpression)
: m_newDirExpression(std::move(newDirExpression))
{
}
SetDirectionAction::~SetDirectionAction() = default;
ActionResult SetDirectionAction::execute(ProgramLocals& locals) const
{
auto dir = m_newDirExpression.execute(locals.variables);
vm_vec_normalize_safe(&dir);
locals.variables.setValue({"locals", "direction"}, expression::Value(dir));
return ActionResult::Finished;
}
std::unique_ptr<Action> SetDirectionAction::clone() const
{
return std::unique_ptr<Action>(new SetDirectionAction(*this));
}
} // namespace types
} // namespace actions
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include "actions/Action.h"
#include "actions/expression/ActionExpression.h"
namespace actions {
namespace types {
class SetDirectionAction : public Action {
public:
using ValueType = vec3d;
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
SetDirectionAction(expression::TypedActionExpression<ValueType> newDirExpression);
~SetDirectionAction() override;
ActionResult execute(ProgramLocals& locals) const override;
std::unique_ptr<Action> clone() const override;
private:
expression::TypedActionExpression<ValueType> m_newDirExpression;
};
} // namespace types
} // namespace actions
-34
View File
@@ -1,34 +0,0 @@
#include "SetPositionAction.h"
#include "parse/parselo.h"
#include <utility>
namespace actions {
namespace types {
flagset<ProgramContextFlags> SetPositionAction::getRequiredExecutionContextFlags()
{
return flagset<ProgramContextFlags>{};
}
SetPositionAction::SetPositionAction(expression::TypedActionExpression<ValueType> newPositionExpression)
: m_newPosExpression(std::move(newPositionExpression))
{
}
SetPositionAction::~SetPositionAction() = default;
ActionResult SetPositionAction::execute(ProgramLocals& locals) const
{
locals.variables.setValue({"locals", "position"}, expression::Value(m_newPosExpression.execute(locals.variables)));
return ActionResult::Finished;
}
std::unique_ptr<Action> SetPositionAction::clone() const
{
return std::unique_ptr<Action>(new SetPositionAction(*this));
}
} // namespace types
} // namespace actions
-28
View File
@@ -1,28 +0,0 @@
#pragma once
#include "actions/Action.h"
#include "actions/expression/ActionExpression.h"
namespace actions {
namespace types {
class SetPositionAction : public Action {
public:
using ValueType = vec3d;
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
SetPositionAction(expression::TypedActionExpression<ValueType> newPositionExpression);
~SetPositionAction() override;
ActionResult execute(ProgramLocals& locals) const override;
std::unique_ptr<Action> clone() const override;
private:
expression::TypedActionExpression<vec3d> m_newPosExpression;
};
} // namespace types
} // namespace actions
-48
View File
@@ -1,48 +0,0 @@
#include "WaitAction.h"
#include "io/timer.h"
#include "parse/parselo.h"
namespace actions {
namespace types {
flagset<ProgramContextFlags> WaitAction::getRequiredExecutionContextFlags()
{
return flagset<ProgramContextFlags>{};
}
WaitAction::WaitAction(expression::TypedActionExpression<float> waitTimeExpression)
: _waitTimeExpression(std::move(waitTimeExpression))
{
}
WaitAction::~WaitAction() = default;
ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
{
if (!timestamp_valid(locals.waitTimestamp)) {
auto waitTime = _waitTimeExpression.execute(locals.variables);
// Catch errors in the expression
if (waitTime < 0.001f) {
waitTime = 0.001f;
}
locals.waitTimestamp = timestamp(fl2i(waitTime * TIMESTAMP_FREQUENCY));
}
if (!timestamp_elapsed(locals.waitTimestamp)) {
// Wait until the timestamp is elapsed
return ActionResult::Wait;
}
// Timestamp is elapsed. The timestamp is elapsed so that timestamp_valid above returns false for the next wait
// action
locals.waitTimestamp = 0;
return ActionResult::Finished;
}
std::unique_ptr<Action> WaitAction::clone() const
{
return std::unique_ptr<Action>(new WaitAction(*this));
}
} // namespace types
} // namespace actions
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include "actions/Action.h"
#include "actions/common.h"
#include "actions/expression/ActionExpression.h"
#include "utils/RandomRange.h"
namespace actions {
namespace types {
class WaitAction : public Action {
public:
using ValueType = float;
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
explicit WaitAction(expression::TypedActionExpression<ValueType> waitTimeExpression);
~WaitAction() override;
ActionResult execute(ProgramLocals& locals) const override;
std::unique_ptr<Action> clone() const override;
private:
expression::TypedActionExpression<ValueType> _waitTimeExpression;
};
} // namespace types
} // namespace actions
+2 -1
View File
@@ -36,7 +36,8 @@ int ai_get_slot(int shipnum)
return i;
}
Error( LOCATION, "Couldn't get AI slot, please tell a coder!");
Warning( LOCATION, "Couldn't get AI slot" );
Int3();
return -1;
}
+10 -18
View File
@@ -70,7 +70,6 @@ extern ai_flag_name Ai_flag_names[];
#define AITTV_FAST (1<<0) // Turn fast, not slowed down based on skill level.
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
#define AITTV_IGNORE_BANK (1<<2) // Goober5000 - ignore bank when turning
#define AITTV_SLOW_BANK_ACCEL (1<<3) // Asteroth - used by formation flying
#define KAMIKAZE_HULL_ON_DEATH -1000.0f // Hull strength ship gets set to if it crash-dies.
@@ -183,7 +182,6 @@ typedef struct ai_class {
// Submode definitions.
// Note: These need to be renamed to be of the form: AIS_mode_xxxx
// Cyborg17 -- If you add submodes for AI_CHASE, you *have to* add entries to Submode_text[] in aicode.cpp
#define SM_CONTINUOUS_TURN 1 // takes parm: vector_id {0..3 = right, -right, up, -up}
#define SM_ATTACK 2
#define SM_EVADE_SQUIGGLE 3
@@ -405,6 +403,7 @@ typedef struct ai_info {
union {
float lead_scale; // Amount to lead current opponent by.
float stay_near_distance; // Distance to stay within for AIM_STAY_NEAR mode.
};
@@ -471,8 +470,8 @@ typedef struct ai_info {
fix avoid_check_timestamp; // timestamp at which to next check for having to avoid ship
vec3d big_collision_normal; // Global normal of collision with big ship. Helps find direction to fly away from big ship. Set for each collision.
vec3d big_recover_1_direction; // A relative direction to fly towards when recovering from collision with a big ship, stage 1.
vec3d big_recover_2_pos; // Global point to fly towards when recovering from collision with a big ship, stage 2.
vec3d big_recover_pos_1; // Global point to fly towards when recovering from collision with a big ship, stage 1.
vec3d big_recover_pos_2; // Global point to fly towards when recovering from collision with a big ship, stage 2.
int big_recover_timestamp; // timestamp at which it's OK to re-enter stage 1.
int abort_rearm_timestamp; // time at which this rearm should be aborted in a multiplayer game.
@@ -486,13 +485,7 @@ typedef struct ai_info {
flagset<AI::Maneuver_Override_Flags> ai_override_flags; // flags for marking ai overrides from sexp or lua systems
control_info ai_override_ci; // ai override control info
int ai_override_lat_timestamp; // mark for when to end the current lateral maneuver override
int ai_override_rot_timestamp; // mark for when to end the current rotational maneuver override
int form_obj_slotnum; // for flying in formation object mode, the position in the formation
int multilock_check_timestamp; // when to check for multilock next
SCP_vector<std::pair<int, ship_subsys*>> ai_missile_locks_firing; // a list of missile locks (locked objnum, locked subsys) the ai is currently firing
int ai_override_timestamp; // mark for when to end the current override
} ai_info;
// Goober5000
@@ -563,7 +556,7 @@ const char *ai_get_goal_target_name(const char *name, int *index);
void ai_clear_goal_target_names();
extern void init_ai_system(void);
extern void ai_attack_object(object *attacker, object *attacked, int ship_info_index = -1);
extern void ai_attack_object(object *attacker, object *attacked, ship_subsys *ssp, int ship_info_index = -1);
extern void ai_evade_object(object *evader, object *evaded);
extern void ai_ignore_object(object *ignorer, object *ignored, int ignore_new);
extern void ai_ignore_wing(object *ignorer, int wingnum);
@@ -573,7 +566,7 @@ extern void ai_do_default_behavior(object *obj);
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum);
extern void ai_turn_towards_vector(vec3d *dest, object *objp, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, vec3d* turnrate_mod = nullptr);
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, int sexp_flags = 0);
extern void init_ai_object(int objnum);
extern void ai_init(void); // Call this one to parse ai.tbl.
extern void ai_level_init(void); // Call before each level to reset AI
@@ -586,7 +579,8 @@ extern void ai_update_danger_weapon(int objnum, int weapon_objnum);
// called externally from MissionParse.cpp to position ships in wings upon arrival into the
// mission.
extern void get_absolute_wing_pos(vec3d *result_pos, object *leader_objp, int wingnum, int wing_index, bool formation_object_flag, bool autopilot = false);
extern void get_absolute_wing_pos( vec3d *result_pos, object *leader_objp, int wing_index, int formation_object_flag);
extern void get_absolute_wing_pos_autopilot( vec3d *result_pos, object *leader_objp, int wing_index, int formation_object_flag);
// Interface from goals code to AI. Set ship to guard. *objp guards *other_objp
extern void ai_set_guard_object(object *objp, object *other_objp);
@@ -624,7 +618,7 @@ extern int might_collide_with_ship(object *obj1, object *obj2, float dot_to_enem
extern int ai_fire_primary_weapon(object *objp); //changed to return weather it fired-Bobboau
extern int ai_fire_secondary_weapon(object *objp);
extern float ai_get_weapon_dist(ship_weapon *swp);
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override, matrix* target_orient = nullptr, int flags = 0);
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override);
extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip);
@@ -636,7 +630,7 @@ void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, vec3d *gun_pos,
// function to change rearm status for ai ships (called from sexpression code)
extern void ai_set_rearm_status( int team, int new_status );
extern void ai_good_secondary_time( int team, int weapon_index, int num_weapons, const char *shipname );
extern void ai_good_secondary_time( int team, int weapon_index, int num_weapons, char *shipname );
extern void ai_do_objects_docked_stuff(object *docker, int docker_point, object *dockee, int dockee_point, bool update_clients = true);
extern void ai_do_objects_undocked_stuff( object *docker, object *dockee );
@@ -669,6 +663,4 @@ void ai_update_aim(ai_info *aip);
//SUSHI: Random evasive sidethrust
void do_random_sidethrust(ai_info *aip, ship_info *sip);
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
#endif
+3 -18
View File
@@ -5,7 +5,7 @@
namespace AI {
FLAG_LIST(AI_Flags) {
Formation_wing, // Fly in formation as part of wing. Also used when flying waypoints.
Formation_wing, // Fly in formation as part of wing.
Awaiting_repair, // Awaiting a repair ship.
Being_repaired, // Currently docked with repair ship.
Repairing, // Repairing a ship (or going to repair a ship)
@@ -63,9 +63,7 @@ namespace AI {
Dont_bank_when_turning, // maps to CIF_DONT_BANK_WHEN_TURNING
Dont_clamp_max_velocity, // maps to CIF_DONT_CLAMP_MAX_VELOCITY
Instantaneous_acceleration, // maps to CIF_INSTANTANEOUS_ACCELERATION
Lateral_never_expire, // don't clear the lateral maneuver when the timestamp is up
Rotational_never_expire, // don't clear the rotational maneuver when the timestamp is up
Dont_override_old_maneuvers,// doesn't clear any previous maneuvers
Never_expire, // don't clear the maneuver when the timestamp is up
NUM_VALUES
};
@@ -120,26 +118,13 @@ namespace AI {
Smart_secondary_weapon_selection,
Smart_shield_management,
Smart_subsystem_targeting_for_turrets,
Strict_turret_tagged_only_targeting,
Strict_turred_tagged_only_targeting,
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in http://scp.indiegames.us/mantis/view.php?id=3198
Turrets_ignore_target_radius,
Use_actual_primary_range,
Use_subsystem_path_point_radii,
Use_additive_weapon_velocity,
Use_newtonian_dampening,
Use_only_single_fov_for_turrets,
No_turning_directional_bias,
Use_axial_turnrate_differences,
all_nonshielded_ships_can_manage_ets,
fightercraft_nonshielded_ships_can_manage_ets,
Better_collision_avoidance,
Require_exact_los,
Improved_missile_avoidance,
Friendlies_use_countermeasure_firechance,
Improved_subsystem_attack_pathing,
Fixed_ship_weapon_collision,
No_shield_damage_from_ship_collisions,
Reset_last_hit_target_time_for_player_hits,
NUM_VALUES
};
+7 -99
View File
@@ -8,7 +8,6 @@
#include "ai/ai_profiles.h"
#include "ai/aibig.h"
#include "def_files/def_files.h"
#include "globalincs/pstypes.h"
#include "localization/localize.h"
@@ -58,26 +57,6 @@ int ai_path_type_match(char *p)
return -1;
}
const char* AI_secondary_range_aware_select_modes[] = {
"retail",
"aware",
};
int Num_ai_secondary_range_aware_select_modes = sizeof(AI_secondary_range_aware_select_modes) / sizeof(char*);
int ai_secondary_range_select_mode_match(char* p)
{
int i;
for (i = 0; i < Num_ai_secondary_range_aware_select_modes; i++)
{
if (!stricmp(AI_secondary_range_aware_select_modes[i], p))
return i;
}
return -1;
}
void parse_ai_profiles_tbl(const char *filename)
{
int i;
@@ -466,8 +445,7 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$support don't add primaries:", AI::Profile_Flags::Support_dont_add_primaries);
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
if (optional_string("$ai path mode:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
@@ -484,7 +462,7 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$fix ai path order bug:", AI::Profile_Flags::Fix_ai_path_order_bug);
set_flag(profile, "$strict turret-tagged-only targeting:", AI::Profile_Flags::Strict_turret_tagged_only_targeting);
set_flag(profile, "$strict turret-tagged-only targeting:", AI::Profile_Flags::Strict_turred_tagged_only_targeting);
set_flag(profile, "$aspect bomb invulnerability fix:", AI::Profile_Flags::Aspect_invulnerability_fix);
@@ -494,18 +472,8 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
if (optional_string("$override radius for subsystem path points:")) {
int path_radii;
stuff_int(&path_radii);
if (path_radii >= Minimum_subsystem_path_pt_dist) {
profile->subsystem_path_radii = path_radii;
} else {
mprintf(("Warning: \"$override radius for subsystem path points:\" should be >= %i (read %i). Value will not be used.\n", Minimum_subsystem_path_pt_dist, path_radii));
}
}
set_flag(profile, "$use POF radius for subsystem path points:", AI::Profile_Flags::Use_subsystem_path_point_radii);
profile->bay_arrive_speed_mult = 1.0f;
profile->bay_depart_speed_mult = 1.0f;
if (optional_string("$bay arrive speed multiplier:")) {
stuff_float(&profile->bay_arrive_speed_mult);
}
@@ -530,56 +498,7 @@ void parse_ai_profiles_tbl(const char *filename)
stuff_boolean(&temp);
profile->flags.set(AI::Profile_Flags::Allow_primary_link_at_start, !temp);
}
if (optional_string("$lead indicator second-order prediction factor:")) {
stuff_float(&profile->second_order_lead_predict_factor);
if (profile->second_order_lead_predict_factor > 1 || profile->second_order_lead_predict_factor < 0) {
mprintf(("Warning: \"$lead indicator second-order prediction factor\" must be 0 - 1, resetting to 0.\"\n"));
profile->second_order_lead_predict_factor = 0;
}
}
if (optional_string("$ships with no shields can manage ETS:"))
{
mprintf(("Warning: \"$ships with no shields can manage ETS\" flag is deprecated in favor of \"$any ship with no shields can manage ETS\"\n"));
bool temp;
stuff_boolean(&temp);
profile->flags.set(AI::Profile_Flags::all_nonshielded_ships_can_manage_ets, temp);
}
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
set_flag(profile, "$respect ship axial turnrate differences:", AI::Profile_Flags::Use_axial_turnrate_differences);
set_flag(profile, "$any ship with no shields can manage ETS:", AI::Profile_Flags::all_nonshielded_ships_can_manage_ets);
set_flag(profile, "$fighters/bombers with no shields can manage ETS:", AI::Profile_Flags::fightercraft_nonshielded_ships_can_manage_ets);
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_collision_avoidance);
set_flag(profile, "$improved missile avoidance for fightercraft:", AI::Profile_Flags::Improved_missile_avoidance);
set_flag(profile, "$friendly ships use AI profile countermeasure chance:", AI::Profile_Flags::Friendlies_use_countermeasure_firechance);
set_flag(profile, "$improved subsystem attack pathing:", AI::Profile_Flags::Improved_subsystem_attack_pathing);
set_flag(profile, "$fixed ship-weapon collisions:", AI::Profile_Flags::Fixed_ship_weapon_collision);
//Intention is to expand this feature to include a preference for close or long range weapons
//hence using something besides a simple flag.
if (optional_string("$AI secondary range awareness:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
int j = ai_secondary_range_select_mode_match(buf);
if (j >= 0) {
profile->ai_range_aware_secondary_select_mode = j;
}
else {
Warning(LOCATION, "Invalid ai secondary range awareness mode '%s' specified", buf);
}
}
set_flag(profile, "$no shield damage from ship collisions:", AI::Profile_Flags::No_shield_damage_from_ship_collisions);
set_flag(profile, "$reset last_hit_target_time for player hits:", AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits);
// if we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
@@ -652,12 +571,9 @@ void ai_profile_t::reset()
flags.reset();
ai_path_mode = AI_PATH_MODE_NORMAL;
subsystem_path_radii = 0;
bay_arrive_speed_mult = 1.0f;
bay_depart_speed_mult = 1.0f;
second_order_lead_predict_factor = 0;
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
ai_path_mode = 0;
bay_arrive_speed_mult = 0;
bay_depart_speed_mult = 0;
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
max_incoming_asteroids[i] = 0;
@@ -729,17 +645,9 @@ void ai_profile_t::reset()
flags.set(AI::Profile_Flags::Fix_ai_path_order_bug);
flags.set(AI::Profile_Flags::Aspect_invulnerability_fix);
flags.set(AI::Profile_Flags::Use_actual_primary_range);
flags.set(AI::Profile_Flags::fightercraft_nonshielded_ships_can_manage_ets);
}
// this flag has been enabled ever since 3.7.2
if (mod_supports_version(3, 7, 2)) {
flags.set(AI::Profile_Flags::Fix_ramming_stationary_targets_bug);
}
// and this flag has been enabled ever since 3.6.10
if (mod_supports_version(3, 6, 10)) {
flags.set(AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits);
}
if (mod_supports_version(21, 4, 0)) {
flags.set(AI::Profile_Flags::Fixed_ship_weapon_collision);
}
}
Loaded 100 of 1305 files, more files were not shown because too many files have changed in this diff. Show more