mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1588644fec | ||
|
|
0abd592038 | ||
|
|
909e799bdd | ||
|
|
5a9f181aff | ||
|
|
b0ba22a43d | ||
|
|
c89faebe4e | ||
|
|
059e149590 |
No files matched your search
+1
-11
@@ -4,27 +4,20 @@ modernize-*,\
|
||||
-modernize-avoid-c-arrays,\
|
||||
-modernize-make-unique,\
|
||||
-modernize-raw-string-literal,\
|
||||
-modernize-use-default-member-init,\
|
||||
-modernize-use-trailing-return-type,\
|
||||
-modernize-use-using,\
|
||||
performance-*,\
|
||||
-performance-no-int-to-ptr,\
|
||||
-performance-type-promotion-in-math-fn,\
|
||||
misc-*,\
|
||||
-misc-include-cleaner,\
|
||||
-misc-macro-parentheses,\
|
||||
-misc-misplaced-widening-cast,\
|
||||
-misc-no-recursion,\
|
||||
-misc-non-private-member-variables-in-classes,\
|
||||
-misc-static-assert,\
|
||||
-misc-unused-parameters,\
|
||||
-misc-use-anonymous-namespace,\
|
||||
readability-*,\
|
||||
-readability-avoid-const-params-in-decls,\
|
||||
-readability-else-after-return,\
|
||||
-readability-function-cognitive-complexity,\
|
||||
-readability-function-size,\
|
||||
-readability-identifier-length,\
|
||||
-readability-identifier-naming,\
|
||||
-readability-implicit-bool-conversion,\
|
||||
-readability-inconsistent-declaration-parameter-name,\
|
||||
@@ -36,13 +29,10 @@ readability-*,\
|
||||
"
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
|
||||
AnalyzeTemporaryDtors: false
|
||||
CheckOptions:
|
||||
- key: 'misc-assert-side-effect.AssertMacros'
|
||||
value: 'assert,Assert,Assertion'
|
||||
- key: 'misc-const-correctness.AnalyzeValues'
|
||||
value: 'false'
|
||||
- key: 'misc-const-correctness.TransformValues'
|
||||
value: 'false'
|
||||
- key: 'modernize-use-emplace.ContainersWithPushBack'
|
||||
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
|
||||
- key: 'readability-braces-around-statements.ShortStatementLines'
|
||||
|
||||
+5
-3
@@ -1,6 +1,8 @@
|
||||
|
||||
ci/ @asarium @z64555
|
||||
cmake/ @asarium
|
||||
|
||||
code/controlconfig/ @z64555
|
||||
code/executor/ @asarium
|
||||
|
||||
code/model/modelanimation*.* @bmagnu
|
||||
code/scpui/ @asarium
|
||||
|
||||
code/scripting/ @asarium
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- 'nightly_*'
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
QT_VERSION: 5.12.9
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
@@ -15,8 +15,21 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-a8ca321
|
||||
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 }}
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -24,8 +37,7 @@ jobs:
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
COMPILER: gcc-5
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -45,7 +57,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
@@ -61,12 +73,12 @@ jobs:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
@@ -95,36 +107,31 @@ 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.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: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
- name: Cache Qt
|
||||
id: cache-qt-win
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
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 }}
|
||||
@@ -135,19 +142,11 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
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:
|
||||
@@ -164,7 +163,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -184,12 +183,12 @@ jobs:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -209,128 +208,3 @@ jobs:
|
||||
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
|
||||
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh nightly
|
||||
|
||||
build_mac:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64, arm64]
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-mac
|
||||
# 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-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: 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: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
|
||||
- name: Run Tests
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Sign builds
|
||||
working-directory: ./build/bin
|
||||
run: |
|
||||
# make sure OpenAL framework is signed
|
||||
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
|
||||
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
|
||||
# make sure dylibs are signed
|
||||
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
|
||||
# sign binaries
|
||||
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
|
||||
# sign apps
|
||||
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
|
||||
- name: Package build result
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
|
||||
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- 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
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- 'release_*'
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
QT_VERSION: 5.12.9
|
||||
|
||||
jobs:
|
||||
create_release:
|
||||
@@ -16,17 +16,6 @@ jobs:
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
# Creates a release package page on github
|
||||
# create_release.inputs: (notable inputs)
|
||||
# allowUpdates=false if true, update an existing release if it exists
|
||||
# artifactErrorsFailBuild=false if true, fails the build should artifact read/write errors occur
|
||||
# artifacts optional set of paths to artifacts to upload to the release. comma delimited.
|
||||
# removeArtifacts=false if true, remove existing artifacts
|
||||
# replaceArtifacts=false if true, replace/overwrite existing artifacts
|
||||
# create_release.outputs:
|
||||
# id id of the created release
|
||||
# html_url HTML URL of the release
|
||||
# upload_url FTP URL of the release where assets are uploaded
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
|
||||
with:
|
||||
@@ -34,29 +23,45 @@ jobs:
|
||||
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:
|
||||
# Run this job for each configuration
|
||||
# The current config running is accesible with `matrix.configuration`
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
needs: create_release # Don't run this job until create_release is done and successful
|
||||
needs: create_release
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-a8ca321
|
||||
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 }}
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
ref: '${{ github.ref }}'
|
||||
submodules: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
COMPILER: gcc-5
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -76,16 +81,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
# Upload the url file for use with other runners
|
||||
# upload-artifact.inputs:
|
||||
# if-no-files-found=warn What to do if path fails to find any files.
|
||||
# warn Display a warning but do not fail the action
|
||||
# error Display an error and fail the action
|
||||
# ignore No display, No fail
|
||||
# retention-days=0 Days to keep the artifact.
|
||||
# 0 Use default retention policy of the repo
|
||||
# 1~90 Min 1, Max 90 days to keep the artifact unless changed by repo settings page
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
@@ -99,38 +95,38 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
|
||||
ref: '${{ github.ref }}'
|
||||
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
|
||||
# Grab the release builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
# Grab the debug builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
- name: Create Distribution package
|
||||
# Zip both builds together
|
||||
id: generate_package
|
||||
working-directory: ./builds
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
|
||||
- name: Upload result package
|
||||
# Stash the result to artifact filespace
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
- name: Publish result package
|
||||
# publish the zipped result
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
files: ${{ steps.generate_package.outputs.package_path }}
|
||||
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:
|
||||
@@ -143,44 +139,34 @@ jobs:
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
# Checkout repo
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
ref: '${{ github.ref }}'
|
||||
# - name: Cache Qt
|
||||
# # 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)
|
||||
# # Install Qt 32bit if matrix.arch == Win32
|
||||
# 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)
|
||||
# # Install Qt 64bit if matrix.arch == x64
|
||||
# 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: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
- name: Cache Qt
|
||||
id: cache-qt-win
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
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 }}
|
||||
@@ -191,19 +177,11 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
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:
|
||||
@@ -220,41 +198,43 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
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:
|
||||
fail-fast: false # Run the other jobs in the matrix instead of failing them
|
||||
matrix:
|
||||
arch: [Win32, x64]
|
||||
simd: [SSE2, AVX]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- 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@v3
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v3
|
||||
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
|
||||
@@ -263,159 +243,21 @@ jobs:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
SIMD: ${{ matrix.simd }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
|
||||
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
- name: Upload debug package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.debug_name }}
|
||||
path: ${{ steps.generate_package.outputs.debug_path }}
|
||||
|
||||
- name: Publish packages
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
files: |
|
||||
${{ steps.generate_package.outputs.package_path }}
|
||||
${{ steps.generate_package.outputs.debug_path }}
|
||||
|
||||
build_mac:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64, arm64]
|
||||
name: Mac
|
||||
needs: create_release
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-mac
|
||||
# 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-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
|
||||
- name: Run Tests
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Sign builds
|
||||
working-directory: ./build/bin
|
||||
run: |
|
||||
# make sure OpenAL framework is signed
|
||||
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
|
||||
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
|
||||
# make sure dylibs are signed
|
||||
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
|
||||
# sign binaries
|
||||
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
|
||||
# sign apps
|
||||
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
|
||||
- name: Package build result
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
|
||||
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
|
||||
- name: Create Distribution package
|
||||
id: generate_package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
- name: Publish result package
|
||||
uses: softprops/action-gh-release@v1
|
||||
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:
|
||||
files: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
post_build:
|
||||
name: Post builds to Nebula and Forum
|
||||
needs: [linux_zip, windows_zip, mac_zip]
|
||||
uses: ./.github/workflows/post-build-release.yaml
|
||||
with:
|
||||
linux_result: ${{ needs.linux_zip.result }}
|
||||
windows_result: ${{ needs.windows_zip.result }}
|
||||
mac_result: ${{ needs.mac_zip.result }}
|
||||
releaseTag: ${{ github.ref_name }}
|
||||
secrets: inherit
|
||||
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 }}
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- 'test/*'
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
QT_VERSION: 5.12.9
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
@@ -15,8 +15,21 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-a8ca321
|
||||
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 }}
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -30,8 +43,7 @@ jobs:
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
COMPILER: gcc-5
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -51,7 +63,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
@@ -68,12 +80,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
@@ -108,36 +120,31 @@ jobs:
|
||||
[[ "${{ 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: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
- name: Cache Qt
|
||||
id: cache-qt-win
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
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 }}
|
||||
@@ -148,19 +155,11 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
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:
|
||||
@@ -177,7 +176,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -198,12 +197,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -223,127 +222,3 @@ jobs:
|
||||
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
|
||||
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh test
|
||||
|
||||
build_mac:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64, arm64]
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-mac
|
||||
# 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-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: 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: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
|
||||
- name: Run Tests
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Sign builds
|
||||
working-directory: ./build/bin
|
||||
run: |
|
||||
# make sure OpenAL framework is signed
|
||||
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
|
||||
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
|
||||
# make sure dylibs are signed
|
||||
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
|
||||
# sign binaries
|
||||
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
|
||||
# sign apps
|
||||
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
|
||||
- name: Package build result
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
|
||||
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- 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
|
||||
@@ -1,56 +0,0 @@
|
||||
name: Build caches for master
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [gcc-9, gcc-13, clang-16]
|
||||
cmake_options: [""]
|
||||
include:
|
||||
# Also include configurations that check if the code compiles without the graphics backends
|
||||
- configuration: Debug
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
- configuration: Release
|
||||
compiler: gcc-13
|
||||
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-1ff82e8
|
||||
steps:
|
||||
- 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 ccache
|
||||
run: |
|
||||
ccache --set-config=sloppiness=pch_defines,time_macros
|
||||
ccache -p
|
||||
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
CCACHE_PATH: /usr/local/bin/ccache
|
||||
ENABLE_QTFRED: ON
|
||||
Qt5_DIR: /qt/${{ env.QT_VERSION }}/gcc_64/lib/cmake/Qt5
|
||||
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
|
||||
- name: Show CCache statistics
|
||||
run: ccache --show-stats
|
||||
@@ -1,82 +0,0 @@
|
||||
name: Post Release builds
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
# Trigger when called by other workflows
|
||||
inputs:
|
||||
linux_result: # job.result; either success, failure, canceled or skipped
|
||||
required: true
|
||||
type: string
|
||||
windows_result: # job.result
|
||||
required: true
|
||||
type: string
|
||||
mac_result: # job.result
|
||||
required: true
|
||||
type: string
|
||||
releaseTag:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
workflow_dispatch:
|
||||
# Trigger manually from Github
|
||||
inputs:
|
||||
releaseTag:
|
||||
description: Release Tag
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
GITHUB_REPO: ${{ github.repository }} # repo this workflow was called from
|
||||
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 }}
|
||||
RELEASE_TAG: ${{ inputs.releaseTag }}
|
||||
|
||||
jobs:
|
||||
post_builds:
|
||||
name: Post builds on Nebula and the forums
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Caller
|
||||
# Name of what called this yaml. Used to debug auto/manual step being triggered
|
||||
run: echo "github.event_name= ${{ github.event_name }}"
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
ref: ${{ env.RELEASE_TAG }}
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: pip install -r ci/post/requirements.txt
|
||||
|
||||
- name: Post Builds (Auto trigger)
|
||||
if: ${{ (github.event_name == 'workflow_call') || (github.event_name == 'push') }}
|
||||
env:
|
||||
LINUX_RESULT: ${{ inputs.linux_result }}
|
||||
WINDOWS_RESULT: ${{ inputs.windows_result }}
|
||||
MAC_RESULT: ${{ inputs.mac_result }}
|
||||
GITHUB_REPO: ${{ github.repository }} # repo this workflow was called from
|
||||
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 }}
|
||||
RELEASE_TAG: ${{ inputs.releaseTag }}
|
||||
run: python ci/post/main.py release
|
||||
|
||||
- name: Post Builds (Manual trigger)
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
# assume user knows what they're doing...
|
||||
env:
|
||||
LINUX_RESULT: success
|
||||
WINDOWS_RESULT: success
|
||||
MAC_RESULT: success
|
||||
run: |
|
||||
echo "releaseTag= ${{ env.RELEASE_TAG }}"
|
||||
echo "repository= ${{ github.repository }}"
|
||||
python ci/post/main.py release
|
||||
@@ -0,0 +1,153 @@
|
||||
name: Check a pull request
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.9
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
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
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-e977d36
|
||||
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'
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- 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
|
||||
- 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
|
||||
|
||||
build_windows:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [MSVC]
|
||||
arch: [Win32, x64]
|
||||
name: Windows
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- name: Prepare Environment
|
||||
run: choco install ninja
|
||||
- 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.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 }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
if [ "$COMPILER" = "MinGW" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-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" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "$COMPILER" = "MinGW" ]; then
|
||||
cmake --build . --config "$CONFIGURATION"
|
||||
else
|
||||
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
|
||||
fi
|
||||
- name: Run Tests
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "$COMPILER" = "MinGW" ]; then
|
||||
./bin/unittests --gtest_shuffle
|
||||
else
|
||||
"./bin/$CONFIGURATION/unittests" --gtest_shuffle
|
||||
fi
|
||||
@@ -0,0 +1,48 @@
|
||||
name: Publish Standalone docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build_images:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
include:
|
||||
- configuration: FastDebug
|
||||
latest_tag: latest_debug
|
||||
nightly_tag: nightly_debug
|
||||
release_tag: release_debug
|
||||
- configuration: Release
|
||||
latest_tag: latest
|
||||
nightly_tag: nightly
|
||||
release_tag: release
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- 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: Push latest tag
|
||||
run: |
|
||||
docker push ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }}
|
||||
|
||||
- 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 }}
|
||||
@@ -1,236 +0,0 @@
|
||||
name: Check a pull request
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [gcc-9, gcc-13, clang-16]
|
||||
cmake_options: [""]
|
||||
include:
|
||||
# Also include configurations that check if the code compiles without the graphics backends
|
||||
- configuration: Debug
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
- configuration: Release
|
||||
compiler: gcc-13
|
||||
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-1ff82e8
|
||||
steps:
|
||||
- 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 }}
|
||||
save: false # Caches are created by a separate job and only restored for PRs
|
||||
verbose: 1
|
||||
- name: Configure ccache
|
||||
run: ccache --set-config=sloppiness=pch_defines,time_macros
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
CCACHE_PATH: /usr/local/bin/ccache
|
||||
ENABLE_QTFRED: ON
|
||||
Qt5_DIR: /qt/${{ env.QT_VERSION }}/gcc_64/lib/cmake/Qt5
|
||||
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
|
||||
- name: Run Tests
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Show CCache statistics
|
||||
run: ccache --show-stats
|
||||
- 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
|
||||
|
||||
build_windows:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [MSVC]
|
||||
arch: [Win32, x64]
|
||||
name: Windows
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- name: Prepare Environment
|
||||
run: choco install ninja
|
||||
- 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.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: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
if [ "$COMPILER" = "MinGW" ]; then
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -DFSO_BUILD_WITH_VULKAN="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
|
||||
fi
|
||||
else
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
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" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
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=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
fi
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "$COMPILER" = "MinGW" ]; then
|
||||
cmake --build . --config "$CONFIGURATION"
|
||||
else
|
||||
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
|
||||
fi
|
||||
- name: Run Tests
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "$COMPILER" = "MinGW" ]; then
|
||||
./bin/unittests --gtest_shuffle
|
||||
else
|
||||
"./bin/$CONFIGURATION/unittests" --gtest_shuffle
|
||||
fi
|
||||
|
||||
build_mac:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64, arm64]
|
||||
cmake_options: [""]
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-mac
|
||||
# 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-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- 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 }}-${{ matrix.arch }}
|
||||
save: false # Caches are created by a separate job and only restored for PRs
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
|
||||
- name: Run Tests
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
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
|
||||
@@ -1,69 +0,0 @@
|
||||
name: Weekly Coverity Scan for Freespace Open
|
||||
# adapted from code by "albert-github" on the doxygen repository
|
||||
# many thanks for figuring this out first so it could be less painful for us!
|
||||
|
||||
#This mode is for testing
|
||||
#on: [push, pull_request]
|
||||
|
||||
# In production, push on a specific schedule
|
||||
on:
|
||||
schedule:
|
||||
- cron: "5 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
coverity_email: [email protected]
|
||||
coverity_token: ${{ secrets.COVERITY_TOKEN }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build FSO With Coverity Wrapper
|
||||
if: github.repository == 'scp-fs2open/fs2open.github.com'
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- { name: "GCC on ubuntu", os: ubuntu-latest, build_type: "Release" }
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
|
||||
# pipe results of wget to a log file because it's very verbose and rarely fails
|
||||
- name: Install Coverity
|
||||
run: |
|
||||
wget -o wgetlog.txt -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=${{ env.coverity_token }}&project=scp-fs2open/fs2open.github.com" -O coverity_tool.tgz
|
||||
mkdir cov-scan
|
||||
tar ax -f coverity_tool.tgz --strip-components=1 -C cov-scan
|
||||
|
||||
- name: Setup Environment
|
||||
run: |
|
||||
echo "$(pwd)/cov-scan/bin" >> $GITHUB_PATH
|
||||
echo "NPROC=$(getconf _NPROCESSORS_ONLN)" >> $GITHUB_ENV
|
||||
|
||||
- name: Configure CMake for FSO
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
|
||||
- name: Build FSO with Coverity Wrapper
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
run: cov-build --dir cov-int ninja -k 20 all
|
||||
|
||||
- name: Compress Results
|
||||
working-directory: ./build
|
||||
run: tar zcf cov-scan.tgz cov-int
|
||||
|
||||
#Comment this out when testing to keep from running into upload limits
|
||||
- name: Upload to Coverity
|
||||
run: |
|
||||
cd build
|
||||
curl --form token=${{ env.coverity_token }} --form email=${{ env.coverity_email }} --form [email protected] --form version="$(git rev-parse HEAD)" --form description="Automatic GHA scan" 'https://scan.coverity.com/builds?project=scp-fs2open/fs2open.github.com'
|
||||
@@ -250,7 +250,6 @@ documentation/doxygen/*
|
||||
projects/*
|
||||
/.vs
|
||||
CMakeSettings.json
|
||||
CMakePresets.json
|
||||
|
||||
# Weird files created by Linux
|
||||
.fuse_hidden*
|
||||
|
||||
@@ -4,4 +4,3 @@
|
||||
[submodule "lib/libRocket"]
|
||||
path = lib/libRocket
|
||||
url = https://github.com/asarium/libRocket.git
|
||||
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
language: bash
|
||||
sudo: required
|
||||
dist: xenial
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/cmake-3.8
|
||||
- $HOME/.ccache
|
||||
- $HOME/curl_cache
|
||||
addons:
|
||||
apt:
|
||||
packages: &global_deps
|
||||
- ninja-build
|
||||
- libopenal-dev
|
||||
- libreadline6-dev
|
||||
- libpng12-dev
|
||||
- libjpeg62-dev
|
||||
- liblua5.1-0-dev
|
||||
- libjansson-dev
|
||||
- libsdl2-dev
|
||||
- libfreetype6-dev
|
||||
- qt57base
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "scp-fs2open/fs2open.github.com"
|
||||
notification_email: [email protected]
|
||||
build_command: "ci/travis/script.sh"
|
||||
# must match TRAVIS_BRANCH check below
|
||||
branch_pattern: coverity_scan
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
# also note that fork's don't get access to secure keys
|
||||
# you have to test using a branch in the main repo
|
||||
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
|
||||
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
|
||||
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
|
||||
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
|
||||
# These declarations set DATACORDER_USER and DATACORDER_PASSWORD
|
||||
- secure: "dpBH/dDN3bmU/NFlh+2v9isNx9wX0ocoRy+W+kBXRH32sosUGp26REhMqgVRpBNP5oxPBU8ic5bEogxAYWCB+0xUygBbkxAwyMPgoA34s0OXdTCY/ofw14ni8qqV2Ffy7fQJbP/jkMURyiMHx3kBTxNv3YjxKJqLnOuOMlQLpT8="
|
||||
- secure: "tLMRBD1Ufp5iKNwlqPDVbbuczgusaXNoBJyAnPATpJq2YwlkW4j3PqP9rW5vd85+52xam2EOP20w9PoBR5J6FLdiXRu4Lf7yCEhSHFAgowVqQj8QcJpPlyXr90bM4emFGrGqpdxVwxyQ5AFhKwLuEZKsI14GYLN+UMEwpNCMing="
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "q619+eQTe7lv8UVphK4OIzU8Jw84KBbVkuprN2sWIubRcV3IbZr2+WahJoUMt+nyhiy3YjDYtstO2ZgkxupwnZgwGUBVIiD1c4SPuyy+HTjNMOtiVsEUHT2hf+xPAemWpTlK5HcwhMmHAOh6rt6dEj57QOg0gcmGiwD/tCbEriA="
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: "/tmp/builds/*"
|
||||
on:
|
||||
condition: '"$RELEASE_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: '"$NIGHTLY_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: $TEST_BUILD = true
|
||||
all_branches: true
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# note that gcc Debug MUST be 1st for Coverity
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-9 CXX=g++-9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- g++-9
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-9
|
||||
script:
|
||||
- ./ci/travis/script.sh
|
||||
- ./ci/travis/clang_tidy.sh
|
||||
- os: osx
|
||||
env: CONFIGURATION="Debug"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-9 CXX=g++-9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- g++-9
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-9
|
||||
script:
|
||||
- ./ci/travis/script.sh
|
||||
- ./ci/travis/clang_tidy.sh
|
||||
- os: osx
|
||||
env: CONFIGURATION="Release"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141 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
|
||||
allow_failures:
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
fast_finish: true
|
||||
|
||||
before_install:
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
# see note re gcc compiler above needing to be 1st
|
||||
# also note that branch_pattern & the TRAVIS_BRANCH check must match
|
||||
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
|
||||
# build process
|
||||
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
|
||||
- source "./ci/travis/check_release.sh"
|
||||
- "./ci/travis/before_install.sh"
|
||||
install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then export PATH="/c/Program Files/CMake/bin":$PATH; fi
|
||||
- "./ci/travis/install.sh"
|
||||
- export PATH=$HOME/cmake-3.6/bin:$PATH
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
|
||||
- "./ci/travis/before_script.sh"
|
||||
script:
|
||||
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
|
||||
+16
-18
@@ -39,14 +39,21 @@ endif(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
# Override standard CMake configurations
|
||||
set(CMAKE_CONFIGURATION_TYPES Debug Release FastDebug CACHE STRING "Available configurations" FORCE)
|
||||
|
||||
set(FSO_LANGUAGES C CXX)
|
||||
PROJECT(FS2_Open)
|
||||
|
||||
if(APPLE)
|
||||
set(FSO_LANGUAGES ${FSO_LANGUAGES} OBJC OBJCXX)
|
||||
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()
|
||||
endif()
|
||||
|
||||
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
|
||||
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
|
||||
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
|
||||
@@ -75,11 +82,9 @@ IF(RESET_INSTALL_PREFIX)
|
||||
ENDIF(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
ENDIF(RESET_INSTALL_PREFIX)
|
||||
|
||||
IF(WIN32 OR APPLE)
|
||||
OPTION(FSO_USE_SPEECH "Use text-to-speach libraries" ON)
|
||||
ENDIF(WIN32 OR APPLE)
|
||||
|
||||
IF (WIN32)
|
||||
OPTION(FSO_USE_SPEECH "Use Windows specific text-to-speach libraries" ON)
|
||||
|
||||
OPTION(FSO_USE_VOICEREC "Enable voice recognition support" ON)
|
||||
|
||||
OPTION(FSO_BUILD_FRED2 "Build FRED2 binary" ON)
|
||||
@@ -123,11 +128,8 @@ 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_OPENGL_DEBUG "Enables debug option for OpenGL" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_OPENXR_DEBUG "Enables debug option for OpenXR" OFF)
|
||||
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)
|
||||
@@ -140,9 +142,7 @@ 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_OPENGL_DEBUG)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_VULKAN)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENXR_DEBUG)
|
||||
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
include(cotire)
|
||||
@@ -207,10 +207,8 @@ include(package)
|
||||
include(doxygen)
|
||||
|
||||
# Print used options to log
|
||||
IF(WIN32 OR APPLE)
|
||||
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
|
||||
ENDIF()
|
||||
IF (WIN32)
|
||||
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
|
||||
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
|
||||
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
|
||||
elseif(UNIX)
|
||||
|
||||
-617
@@ -3,618 +3,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [23.2.0] - 2023-06-16
|
||||
### Changes
|
||||
|
||||
<details><summary> <b>Big Feature: MSAA</b> </summary>
|
||||
|
||||
> The return of a long forgotten feature, with optimizations and improvements
|
||||
> Noticeable reduction to artifacts caused by subpixel geometry and glinting.
|
||||
</details>
|
||||
|
||||
<details><summary> <b>Big Feature: SCPUI</b> </summary>
|
||||
|
||||
> A modernized approach to defining menus in FS
|
||||
> Tired of having your Menus in FSO be at a resolution of potato? Use SCPUI to have them rendered from Fake-HTML to the actual screensize as opposed to a prebuilt graphics!
|
||||
> Tired of being limited to whatever people in the SCP hardcoded in for buttons? Use SCPUI to define buttons and all other manner of shenanigans as Lua-code just as you like.
|
||||
> Tired of needing to replace a bajillion interface graphics to reskin FSO? Use SCPUI, and especially Mjn's existing collection of Lua, CSS, Fake-HTML and images, and you only need to replace about 250 graphics.
|
||||
</details>
|
||||
|
||||
<details><summary> <b>Big Feature: Localized Volumetric Nebulae</b> </summary>
|
||||
|
||||
> Allows specifying a POF as the "hull" of a nebula, which will be rendered using ray marching
|
||||
> Further details can be found on the [GitHub Pull Request](https://github.com/scp-fs2open/fs2open.github.com/pull/5231)
|
||||
> Note: As this is a new feature, many improvements and optimizations remain to be made
|
||||
> Adapted from Andrew Schneider's 2015 SIGGRAPH talk "The real-time volumetric cloudscapes of Horizon: Zero Dawn"
|
||||
</details>
|
||||
|
||||
<details><summary>Game: </summary>
|
||||
|
||||
- Per bank autoaim
|
||||
</details>
|
||||
|
||||
<details><summary>Animation: </summary>
|
||||
|
||||
- Fix CTD on bad legacy animation data
|
||||
- Add proper time wrapping for Animations
|
||||
- Actually handle a mssing `Fade_anim` properly
|
||||
</details>
|
||||
|
||||
<details><summary>Controls: </summary>
|
||||
|
||||
- Organize and map additional keys to librocket
|
||||
- Catch when SDL fails to open a joystick that is enumerated by the OS
|
||||
</details>
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- Add SpaceMouse support
|
||||
- Add pre-parse enums support
|
||||
- Add music player to FRED
|
||||
- Enhanced SEXP comments
|
||||
- FRED Dialog for Volumetrics
|
||||
- QoL improvements to Object Editor
|
||||
- Add FRED support for the "required weapon" feature
|
||||
- SEXP Tree search and filter
|
||||
</details>
|
||||
|
||||
<details><summary>QtFRED: </summary>
|
||||
|
||||
- Campaign Editor
|
||||
- Add SpaceMouse support
|
||||
- Make 'player starts in chase view' a toggle
|
||||
</details>
|
||||
|
||||
<details><summary>Graphics: </summary>
|
||||
|
||||
- "The other great shader flag removal effort"
|
||||
- Enhance handling of motion debris
|
||||
- Expose texture filtering as a built-in option
|
||||
- Improved particle culling and performance
|
||||
- Optimized trail renderer
|
||||
- Beam Particles
|
||||
- Multiple lighting profiles
|
||||
- Use volume particles for poofs
|
||||
- Optimize for simple trails
|
||||
- Kink shamed the laser bitmaps
|
||||
</details>
|
||||
|
||||
<details><summary>HUD: </summary>
|
||||
|
||||
- Flag to apply HUD shudder to chase view
|
||||
- Add missing HUD gauges
|
||||
- Explicitly do not split lines when making the message log
|
||||
</details>
|
||||
|
||||
<details><summary>Localization: </summary>
|
||||
|
||||
- Add some XSTR entries
|
||||
</details>
|
||||
|
||||
<details><summary>Modding: </summary>
|
||||
|
||||
- Mapify built-in strings
|
||||
- Allow `gameplay_profiles.tbl` to be an alias of `ai_profiles.tbl`
|
||||
- Modular rank table
|
||||
- Toggle auto-assigning personas
|
||||
- Add some parameters for corkscrew starting angle
|
||||
- Add clip planes to `game_settings.tbl`
|
||||
- Add `+Use ship` as a Template
|
||||
- Modular messages table
|
||||
- Add arbitrary curves support
|
||||
- Traitor overrides
|
||||
- Add support for loose lz4 compressed files
|
||||
- Add per-species warp effects
|
||||
</details>
|
||||
|
||||
<details><summary>Models: </summary>
|
||||
|
||||
- Fix submodel sanity check
|
||||
- Fix techroom modelnum references
|
||||
- Adjust movement sanity checks to account for more situations
|
||||
- Modular POF Features 2
|
||||
- Add fov values to .pof models
|
||||
- Add a Translation Moveable
|
||||
- Remove model octants
|
||||
- Fix glowpoints on animated submodels
|
||||
- Update type_flags when dock name changes
|
||||
- Add additional checks for Animation List handling of nonexistent polymodel instances
|
||||
- Virtual POFs: Modify Subsystems
|
||||
- Validate chunk size to avoid alignment crash and add align skip flag
|
||||
</details>
|
||||
|
||||
<details><summary>Multiplayer: </summary>
|
||||
|
||||
- Generic Lua Multiplayer RPC
|
||||
</details>
|
||||
|
||||
<details><summary>Performance: </summary>
|
||||
|
||||
- Increase sound update rate
|
||||
- Add `line of sight` as an optional AI override
|
||||
</details>
|
||||
|
||||
<details><summary>SEXPs: </summary>
|
||||
|
||||
- `turret-fired-since`, returns `true` if the specified turret has fired in the last `N` milliseconds
|
||||
- `is-ship-emp-active`, returns `true` if the specified ship or list of ships is currently under an EMP effect
|
||||
- `turret-has-primary` and `turret-has-secondary`, returns `true` if the specified turret contains the specified weapon
|
||||
- `has-armor-type`, returns `true` if the specified ship or subsystem has the specified armor type
|
||||
- `OPF_ANY_HUD_GAUGE` and `OPF_EVENT_NAME`, new Lua SEXP parameters
|
||||
- Enhance Dynamic SEXPs with parent parameters
|
||||
- Add "afterburn hard" AI goal flag
|
||||
</details>
|
||||
|
||||
<details><summary>Scripting: </summary>
|
||||
|
||||
- Add option to deprecate hooks
|
||||
- Get audiostream duration in float seconds
|
||||
- Lua method to check if the game has focus
|
||||
- `On warp complete` hook
|
||||
- Allow Lua to set the Discord presence to custom strings
|
||||
- Add virtvars for goal satisfaction and score
|
||||
- Allow scripts to read and add LuaEnums
|
||||
- Funcs and virtvars for SCPUI pause screen
|
||||
- Expose pausing weapon sounds
|
||||
- Make collision_group_id accessible to parse objects
|
||||
- Pass shortcut key character to Lua as a hook variable
|
||||
- Lua method to free all loaded models
|
||||
- `On Asteroid Created` hook
|
||||
- SCPUI methods required for handling closeup briefing icons
|
||||
- Expose some Nebula settings to Lua
|
||||
- SCPUI mission log
|
||||
- SCPUI APIsfor the Game Help UI, medals access, and control config
|
||||
- Force expand wings instead of toggle for SCPUI
|
||||
- Add misc. validity checks
|
||||
- Convert hotkey types to enum
|
||||
- Finalize SCPUI API
|
||||
- Blocking `On Frame` executor
|
||||
- SCPUI Hud Config API
|
||||
- Configurable restriction for ships that accept Lua player orders
|
||||
- Add `ship::isPlayer()`
|
||||
- Lua access to default countermeasures class
|
||||
- Flag to check if a ship or weapon class is player allowed
|
||||
- Add hooks for comm menu opening/closing
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Improve CFLAGS handling
|
||||
</details>
|
||||
|
||||
## [22.2.0] - 2022-08-06
|
||||
|
||||
```
|
||||
Changelog note:
|
||||
As of this version, in an attempt to make the changelog easier to navigate and read,
|
||||
each section will have collapsible subsections, ordered alphabetically by topic.
|
||||
Headlining features will always be on top.
|
||||
```
|
||||
### Added
|
||||
|
||||
<details><summary> <b>Big Feature: SEXP Containers</b> </summary>
|
||||
|
||||
> As opposed to a SEXP variable, which stores only one value, a SEXP container stores a collection of values.
|
||||
> Consequently, containers allow for handling data in much more sophisticated ways than variables.
|
||||
> Containers come in two types:
|
||||
> * List container - an ordered sequence of values, sort of a cross between Python lists and deques
|
||||
> * Map container - pairs of keys associated with data, like Lua tables or Python dictionaries
|
||||
> Further details in the [SEXP Containers announcement thread](https://www.hard-light.net/forums/index.php?topic=98209.0)
|
||||
</details>
|
||||
|
||||
<details><summary> <b>Big Feature: LuaAI</b> </summary>
|
||||
|
||||
> LuaAI allows scripters to add a new AI Goal (like ai-chase) that will run script instead of internal logic.
|
||||
> Adding a Lua AI section in a -sexp.tbm and a few functions to a corresponding -sct.tbm to define the AI logic in certain conditions. More documentation on these functions is available in the LuaAISEXP-Object of the Scripting Docs.
|
||||
</details>
|
||||
|
||||
<details><summary>AI:</summary>
|
||||
|
||||
- `$AI ignores aspect lock for leading:` Flag, which lets AI continue to lead their target while performing an Aspect Lock
|
||||
</details>
|
||||
|
||||
<details><summary>Animation: </summary>
|
||||
|
||||
- `pause on reverse` Flag
|
||||
</details>
|
||||
|
||||
<details><summary>Controls: </summary>
|
||||
|
||||
- Handle international keyboard layouts
|
||||
- Re-Add `-joy-info` command line flag, for slightly quicker Joystick GUID retrieval
|
||||
- Add `-controlconfig_tbl` command line flag to print out a template controlconfigdefaults.tbl
|
||||
</details>
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- Support the full number of nebula poofs using a multi-select list
|
||||
- Add the ability to edit nebula fog colors, since that previously was not part of the FRED UI
|
||||
- Flags `same-arrival-warp-when-docked` and `same-departure-warp-when-docked` to allow docked ships to still use custom warp parameters
|
||||
- Allow highlighting custom-colored events by drawing a border on them
|
||||
- Can now rotate objects relative to other objects in the Object Editor
|
||||
- Dialog to calculate relative distance and orientation between ships
|
||||
- Flag "Point using uvec" to point ships while incorporating the ship's uvec
|
||||
- `ai-attackable-if-no-collide` flag, which prevents turrets from ignoring a target with `no_collide`
|
||||
</details>
|
||||
|
||||
<details><summary>QtFRED: </summary>
|
||||
|
||||
- Reinforcements Dialog
|
||||
- Implemented Replace Data for Number and String
|
||||
- Texture Replacement Dialog
|
||||
- TBL Viewer in the Ship Editor
|
||||
</details>
|
||||
|
||||
<details><summary>Graphics: </summary>
|
||||
|
||||
- Allow particles to use a random chance for spawning through the `+Chance` parameter
|
||||
- Command-line parameter `-fov_cockpit` which allows setting an FoV for the cockpit model separately from the viewport FoV. This allows using custom FoVs without distorting the cockpit
|
||||
- Allow user to export environment map to a PNG from the F3 Lab by pressing M
|
||||
- Weapon lights: Configurable lighting data for weapons, both on a per-weapon basis and globally via lighting profiles
|
||||
- Implemented debug sphere queuing and rendering
|
||||
</details>
|
||||
|
||||
<details><summary>Localization: </summary>
|
||||
|
||||
- Make strings for Match Speed Indicator, Glide Indicator, and Afterburner Indicator translateable
|
||||
</details>
|
||||
|
||||
<details><summary>Modding: </summary>
|
||||
|
||||
- `game_settings.tbl` setting `$Supernova hits at zero:`, which causes Supernovae to hit when the timer gets to 0, instead of the default of hitting 5 seconds before the time is up
|
||||
- `game_settings.tbl` settings `$Show-subtitle uses pixels:` and `$Show-subtitle base resolution:`, which can be used in conjunction to scale subtitles
|
||||
- `game_settings.tbl` setting `$Always warn player about unbound keys used in Directives Gauge:`, to show such warning to players when needed (without it these warnings only apply to Training Missions)
|
||||
- Ship flags `fail-sound-locked-primary` and `fail-sound-locked-secondary` to allow the firing fail sound to play if the player tries to fire weapons that are locked
|
||||
- Subsystem Flag "hide turret from loadout stats"
|
||||
- Allow weapon to override turret name with `$Turret Name:`
|
||||
</details>
|
||||
|
||||
<details><summary>Multiplayer: </summary>
|
||||
|
||||
- Save PXO stats to local pilot file
|
||||
</details>
|
||||
|
||||
<details><summary>Performance: </summary>
|
||||
|
||||
- Preload subspace tunnel if the `mission-set-subspace` SEXP is used in the mission
|
||||
</details>
|
||||
|
||||
<details><summary>SEXPs: </summary>
|
||||
|
||||
- `cancel-future-waves`, for stopping wings that still had waves queued from spawning
|
||||
- Added optional flag to `show-subtitle-text` and `show-subtitle-image` to not change the subtitle aspect ratio
|
||||
- `set-nav-color` and `set-nav-visited-color`, which allows setting custom colors to Navpoints in a mission
|
||||
</details>
|
||||
|
||||
<details><summary>Scripting: </summary>
|
||||
|
||||
- Support for decals (see `decaldefinition` in the Scripting documentation)
|
||||
- Missile list iterator: `mn.getMissileList()`
|
||||
- Campaign Start hook: `On Campaign Begin`
|
||||
- Player Loaded hook: `On Player Loaded`
|
||||
- Added a few functions to get information on HUD gauges (check `HudGauge` in the Scripting documentation)
|
||||
- Function `ship.checkVisibility` which checks if a ship can appear on the viewer's radar
|
||||
- Function `hu.flashTargetBox` which causes the target box to flash
|
||||
- Function `hu.getTargetDistance` to return the distance to target as reported by the HUD
|
||||
- Function `mn.hasLineOfSight` which checks if one point has line of sight to the other
|
||||
- Function `mn.getLineOfSightFirstIntersect` which checks for line of sight and returns the distance of the first interruption if not
|
||||
- Variable `gr.CurrentResizeMode`, which can get or set the scaling mode to be used by the `gr.*` drawing methods
|
||||
- Function `gr.draw3dLine`, which draws a line in space between two points
|
||||
- Allow SCPUI to run `$On Briefing Stage:` hooks
|
||||
- New bindings to allow proper hooking into control actions based on the control's enumeration name
|
||||
- Allow scripted controls to override hardcoded functionality
|
||||
- Fennel script support
|
||||
- Lua BitOp 1.0.2 extension library, allowing the usage of bit operations
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Class encapsulation for Volition's linked list
|
||||
- Improve a debug console message to be more informative
|
||||
- Type-safe `TIMESTAMP` class
|
||||
- Add `timestamp_since()` function
|
||||
- Add methods to compare timestamps, calculate deltas from an existing timestamp and a number of milliseconds, and to calculate deltas between timestamps
|
||||
- Create a command line option for logging data packets
|
||||
- Add more information to Multi-related debug logging
|
||||
- Enable Doxygen for QTFred
|
||||
- Set up Mac builds on CI, allowing builds to be published automatically for Mac
|
||||
- Add some logging to `waitAsync`
|
||||
</details>
|
||||
|
||||
### Changed
|
||||
|
||||
<details><summary>Game: </summary>
|
||||
|
||||
- Only display one popup when the player gets to the main hall
|
||||
- Allow an unlimited number of ship flags to be parsed at once
|
||||
</details>
|
||||
|
||||
<details><summary>AI: </summary>
|
||||
|
||||
- Improve Player Orders to allow for a nearly unlimited number of player orders, as opposed to the 32 before
|
||||
- Update `ai_turn_towards_vector` to use a target velocity for banking
|
||||
</details>
|
||||
|
||||
<details><summary>Audio: </summary>
|
||||
|
||||
- Allow unlimited soundtracks and spooled music (Previously limited to 30 and 50 respectively)
|
||||
- Allow unlimited sound effects
|
||||
- Dynamically set the maximum number of audio channels based on how many the user's system can support
|
||||
</details>
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- CTRL+V is now add-paste (used to be CTRL+P)
|
||||
- CTRL+SHIFT+V is now overwrite-paste (used to be CTRL+V)
|
||||
- Replace `Always_show_goals` with `Toggle_showing_goals` which toggles whether the goals are shown, and works in any mission (instead of only Training Missions)
|
||||
- No longer disable icon dropdowns for models that have their own icons
|
||||
- No longer change the ship class when the icon type is a special popup
|
||||
- Make the number of player orders FRED can handle dynamic
|
||||
- Restore original Error Checking behavior where the function would exit after one check (for consistency)
|
||||
- Exclude player ships from Error Checking for ships in a wing sharing the same orders
|
||||
- Split "No subsystems found" and "Not all subsystems have a record in ships.tbl" warnings into two different warning flags
|
||||
</details>
|
||||
|
||||
<details><summary>Graphics: </summary>
|
||||
|
||||
- Improved light attenuation to look more real
|
||||
- Increase POF vertex limit, allowing up to `2^32 - 1` vertices to be used by a single subobject
|
||||
</details>
|
||||
|
||||
<details><summary>Performance: </summary>
|
||||
|
||||
- Delay `ai_new_maybe_reposition_attack_subsys` to only run once a second. Before this change, it could take around 13% of runtime in crowded missions
|
||||
- Cached subsystem indexing, speeding up subsystem lookups, which run for multiple ships, multiple times per frame
|
||||
</details>
|
||||
|
||||
<details><summary>Scripting: </summary>
|
||||
|
||||
- Enhance help text for Lua SEXPs
|
||||
- Converted the following Lua Hooks to the new format to add documentation: `On Death`, `On Game Init`, `On Ship Collision`
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Turn `insertion_sort` into a templated function that uses assignment
|
||||
- CMake: Update `PREBUILT_VERSION_NAME` to latest (mac libs)
|
||||
- Optimized space used in the new POF version
|
||||
- Cleanup model code
|
||||
- Cleanup beam light functions by consolidating some duplicated code and removing unreachable logic
|
||||
- Cleanup wing wave code
|
||||
- Move special parsing functions into new `parsehi.cpp` and `parsehi.h` files
|
||||
- Actually clear delayed SSM parsing data when it's no longer needed
|
||||
- Allow C++ to interact more with LuaTables, allowing it to extract userdata like objects or ships from them
|
||||
- Use `SCP_string` for constructing multi/event log lines
|
||||
- Replace `+Orders Accepted:` Bitfield with flag list
|
||||
- Handle deprecated command line flags programmatically, avoiding lots of code duplication
|
||||
- Set up debug_filter.cfg to have default filters that can be turned off
|
||||
</details>
|
||||
|
||||
### Removed
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- Remove the `Allow Daisy-Chained Docking` mission flag
|
||||
- Remove "Delete Item" from the right-click menu in the Event Editor
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Remove light filtering data which didn't work and increased code complexity
|
||||
- Remove a pointless assert that checked if `SEXP_NODE_INCREMENT` (a define, set at 250) was greater than zero
|
||||
</details>
|
||||
|
||||
### Fixed
|
||||
|
||||
<details><summary>Game: </summary>
|
||||
|
||||
- Missing whitespace in credits
|
||||
- Stopped destroyed submodels from showing in Techroom
|
||||
- Prevent a crash when an object dies in the same frame as their goal
|
||||
- Always record primary bank ammo capacity during ship creation, preventing situations where a ballistic weapon would accidentally be set to zero ammo
|
||||
- Properly remove ships from the Techroom when they're not in the Tech Database
|
||||
- Load the correct Techroom data after a Tech Database Reset
|
||||
- Don't tick Supernova timer while the game is paused
|
||||
- Make `set-camera-facing` use default identity orientation when the `$Use host orientation` flag is active and no host is present
|
||||
- When a hotkey text replacement string refers to an unbound control, use the name of the binding instead of "none"
|
||||
- Fix usage of default tech database flags
|
||||
- Prevent a crash in the loadout screen with a weapons-locked ship
|
||||
- Fix two crashes in the F3 lab
|
||||
- End the campaign properly when a mission is skipped, preventing crashing in some situations
|
||||
- Prevent a crash when a message is sent from an invalid source
|
||||
- Prevent a broken campaign state if the player quits the game from the options menu during the debriefing
|
||||
- Add some checks before converting a message to Command
|
||||
- Prevent accidentally skipping cutscenes caused by hitting the spacebar during a loading screen
|
||||
- Fixed an issue where ships would start with the wrong hull values in Red Alert missions
|
||||
</details>
|
||||
|
||||
<details><summary>AI: </summary>
|
||||
|
||||
- Fix turret swarm weapons by removing a few checks that are no longer valid
|
||||
- Fix a few issues with maneuvers
|
||||
</details>
|
||||
|
||||
<details><summary>Animations: </summary>
|
||||
|
||||
- Fix broken turret animations in the Techroom
|
||||
</details>
|
||||
|
||||
<details><summary>Audio: </summary>
|
||||
|
||||
- Fix cockpit engine sound volume changing unexpectedly
|
||||
- Fix a timing bug that would sometimes prevent music from being initialized when re-playing a mission
|
||||
- Check all possible extensions for audio files
|
||||
</details>
|
||||
|
||||
<details><summary>Controls: </summary>
|
||||
|
||||
- Flush the mouse state after toggling between `Use_mouse_to_fly` states, preventing situations where a stale mouse state would be used
|
||||
- Fix a conflict between Free Look View controls and directional thrust controls
|
||||
</details>
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- Prevent Ship Select Dialog from crashing if there are too many IFFs
|
||||
- Support saving nebula fog colors
|
||||
- Properly save `nav-carry-status` flag
|
||||
- Don't treat a bare `<argument>` as an error
|
||||
- Prevent adding duplicated variables and display an error to the user when they try
|
||||
- Clean up some parse problems
|
||||
- Fix assignment of alt-name when using the hash
|
||||
- Guard against off-by-one errors in `replace_one` and `replace_all`
|
||||
- Improve error checking of campaign loop branches
|
||||
- Improve error reporting for bad SEXP nodes
|
||||
- Prevent a crash with paste/add-paste when the clipboard was empty
|
||||
- Prevent rounding/conversion issues that caused FRED to think an angle or position was modified when it wasn't
|
||||
- Skip absent ships or wings when running `clear-goals`, instead of stopping the whole operation
|
||||
</details>
|
||||
|
||||
<details><summary>Graphics: </summary>
|
||||
|
||||
- Disable Lightshafts while the Supernova glare effect is active. This partial fix ensures the glare shows up with the correct brightness
|
||||
- Update and correctly load environment maps in F3 Lab
|
||||
- Correctly set textures and Team Colors with `change-ship-class`
|
||||
- Fixes Team Colors not working with `show-ship`
|
||||
- Correct positioning and angles for background bitmaps and suns
|
||||
- Clean up ship arrival and departure effects
|
||||
- Fix clearing a skybox model when it isn't the mission default
|
||||
- Fix an assertion with Fireball LODs which would wrongly trigger if the number of LODs was the same as the maximum
|
||||
</details>
|
||||
|
||||
<details><summary>HUD: </summary>
|
||||
|
||||
- Make HUD Target distance consistent
|
||||
- Fix a crash with scripted HUDs
|
||||
- Correctly update RTT Cockpit Gauges with `change-ship-class`
|
||||
- Ignore HUD brackets with a size of zero or less (instead of just crashing)
|
||||
- Squad menu wasn't scrolling properly with PageDown in some cases
|
||||
- Fix issues with loading of hud config presets
|
||||
- Fix parsing issues with HUD color presets
|
||||
- Continue parsing remaining gauges if one isn't found
|
||||
- Use translated strings both when saving and loading
|
||||
- Fix an issue where a target's orders would be displayed wrongly in the target box
|
||||
- Fix asteroid brackets disappearing or displaying wrong values
|
||||
</details>
|
||||
|
||||
<details><summary>Modding: </summary>
|
||||
|
||||
- Delay processing `$Player Weapon Precedence:` until after parsing, avoiding ships starting with the wrong weapons in some situations
|
||||
- Make the `$Player Weapon Precedence:` list actually give precedence
|
||||
- Empty `+Orders Accepted List:` entries were causing the ship to accept the default orders, instead of no orders as would be correct
|
||||
- Show a Warning if a turret submodel is not an immediate child of the base object and handle it as a single-part object to prevent a crash
|
||||
</details>
|
||||
|
||||
<details><summary>Multiplayer: </summary>
|
||||
|
||||
- Limit client collisions to prevent bugs, such as flinging players with high pings who collided multiple times between packet updates
|
||||
- Fix multiple timestamp issues
|
||||
- Multi messaging and multi pause screen
|
||||
- Make sure maintenance stuff (pings, voice, file xfer, etc.) isn't affected by pausing or time compression
|
||||
- Sync issues caused by options menu and screenshots
|
||||
- Prevent an error with long messages in PXO Chat by using proper buffer size
|
||||
- Fix some issues with Multiplayer SEXPs
|
||||
- Try to handle incompatible sexp packets better
|
||||
- Fix operator name issue with debug messages
|
||||
- Enable the new show-subtitle-text options
|
||||
- Improve interpolation, fixing the jerkiness that used to occur when the interpolation code basically guessed the timing on when packets were coming in
|
||||
- Fix rollback primary collisions, vastly improving accuracy on moving targets even at high pings
|
||||
- Fix the standalone ship being added to ship list
|
||||
- Stop non-printable keys adding text to multi message buffer
|
||||
- Prevent the standalone from crashing if a player tried to switch secondaries in a ship that doesn't have secondaries
|
||||
- Fix a standalone crash from disabled uniform buffer manager
|
||||
- Prevent a crash related to Observer-type players
|
||||
- Fix network issues on MacOS
|
||||
</details>
|
||||
|
||||
<details><summary>Scripting: </summary>
|
||||
|
||||
- Make hook conditions consistent and handle combinations that didn't work properly before
|
||||
- Fix `maybePlayCutscene` arguments
|
||||
- Add `isActive` checks for new-style script hooks
|
||||
- Sync the two `VIRTVAR`s for Orientation in subsystems and submodel instances, which behaved in different ways
|
||||
- Fixed a few timing and framerate related issues for playing movies via script
|
||||
- Ensure the Lua interpreter has enough space in its stack, and allow reserving more space if necessary
|
||||
- Fixed an memory leak in the Lua interpreter caused by string-eval sexps, which never cleaned up the generated code
|
||||
</details>
|
||||
|
||||
<details><summary>SEXPs: </summary>
|
||||
|
||||
- Avoid setting .rest for `Locked_sexp_true/false` with malformed SEXPs
|
||||
- Fix some memory management problems in the `for-*` operators, avoiding a memory leak
|
||||
- Fix crash when removing form-on-wing order with `remove-goal`
|
||||
- Fix `show-subtitle` SEXP which was missing the `width` argument
|
||||
- Reset volumes changed via `adjust-audio-volume` when the mission closes
|
||||
- Prevent too many dynamic SEXPs from breaking the SEXP system
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Check if index is valid before accessing `Weapon_info`, preventing CTDs under certain conditions
|
||||
- When `weapon_create` was called while `MAX_WEAPONS` was reached, the previous algorithm didn't achieve desired results, and simply locked up the game. Instead, we now simply won't allow a new weapon to be created in such condition
|
||||
- Refactored Supernova code and fixed some state transition issues in it
|
||||
- Prevent crashes in the event of a subsystem mismatch during `change_ship_type`
|
||||
- Change include order to fix compilation of unit tests on Mac
|
||||
- Patch freeing of SEXP nodes, preventing a crash in certain conditions
|
||||
- Fix a memory leak in model code
|
||||
- Fix a crash in the Ship Creation code if a ship's name was exactly the maximum allowed length
|
||||
- Removed vestigial bit-depth asserts for aabitmaps, preventing crashes with certain image types
|
||||
- Prevent a crash when Escort Priority was parsed for a ship not present in the Escort List
|
||||
- Fix a bunch of graphics functions to respect GR_STUB, preventing problems in standalone server
|
||||
- Clean up line endings in several files (replaced CRLF with LF basically everywhere)
|
||||
- Fixed a timestamp issue which helps lay the groundwork to add In-Game Joining to multiplayer
|
||||
- Prevent pilot and campaign files from having invalid values, by clamping them within the expected ranges when saving and loading
|
||||
- Also warn the player if such an invalid value was detected, telling them which setting had the wrong value and what it was reset to
|
||||
- Try to avoid assertions by preventing invalid types from being handled by `obj_team()`
|
||||
- Shut down the SEXP system before the Scripting system, otherwise a crash could happen if the SEXP system held references to Lua
|
||||
</details>
|
||||
|
||||
----
|
||||
|
||||
## [22.0.0] - 2022-04-01 ([Thread](https://www.hard-light.net/forums/index.php?topic=98125.0))
|
||||
### Changed
|
||||
- Controls5 PR (aka multi-joy)
|
||||
- Timing system upgrade
|
||||
- Model animation code upgrades
|
||||
|
||||
|
||||
## [21.4.0] - 2021-09-27 ([Thread](https://www.hard-light.net/forums/index.php?topic=97802.0))
|
||||
### Changed
|
||||
- Multiple features; see thread
|
||||
- Multiple bugfixes; see thread
|
||||
### Deprecations
|
||||
- `script-eval` has been deprecated in favor of `script-eval-block`
|
||||
- renamed `hud-set-retail-gauge-active` to `hud-set-builtin-gauge-active`
|
||||
|
||||
|
||||
## [21.2.0] - 2021-05-02 ([Thread](https://www.hard-light.net/forums/index.php?topic=97561.0))
|
||||
### Changed
|
||||
- Added a dynamic action system for more modder control of effects
|
||||
- Removed fireball limit
|
||||
- Fixed bomb intercept in multiplayer
|
||||
- Changed nebula fog distance from a linear to exponential model
|
||||
- Turrets on moving subobjects enabled
|
||||
- LZ4 Compression added for game files
|
||||
|
||||
|
||||
## [21.0.0] - 2021-01-27 ([Thread](https://www.hard-light.net/forums/index.php?topic=97293.0))
|
||||
### Changed
|
||||
- More OpenGL optimizations
|
||||
- Full type information output for Lua documentation. Very useful for writing Lua scripts.
|
||||
- A new -weaponspew command-line option for printing MediaVP-style statistics, plus a weapon comparison spreadsheet, to the debug log.
|
||||
- Improved ship lookup behavior in SEXPs for improved performance.
|
||||
- BPTC/BC7 texture compression support
|
||||
- Refactoring and new features for the ship lab.
|
||||
- Missile multi-lock. It's finally in an official build!
|
||||
- Enhancements to the model code in preparation for cool features in 21.2.
|
||||
- IPv6 support for multiplayer
|
||||
- A lot of general fixes for multiplayer.
|
||||
### Deprecated
|
||||
- Dropped support for Windows XP
|
||||
- Scripting:
|
||||
- `ba.getFrametime()`: The parameter value was used incorrectly inside the implementation. To avoid breaking existing scripts and to improve readability this has been split into `ba.getMissionFrametime()` and `ba.getRealFrametime()`.
|
||||
- `gr.drawMonochromeImage()`: `gr.drawImage()` got a new parameter for drawing monochrome images and is more flexible in general so the monochrome variant is no longer needed.
|
||||
|
||||
|
||||
## [19.0.0] - 2020-01-25 ([Thread](https://www.hard-light.net/forums/index.php?topic=96226.0))
|
||||
### Meta
|
||||
- With this release we decided to drop the "`3.Major_revision.Minor_revision`" versioning scheme in favor of a year based scheme since the Major and Minor versions did not have much meaning anymore. Instead the scheme will now be "`<year>.<number that is incremented every release>.0`". The last 0 is still there because some of our systems expect that. It will be gone at some point.
|
||||
@@ -637,7 +25,6 @@ Headlining features will always be on top.
|
||||
### Fixed
|
||||
- Refactored bitmap slot handling and removed the fixed upper limit on the number of bitmaps. No more bmpman corruption!
|
||||
|
||||
|
||||
## [3.8.0] - 2017-08-22 ([Release Thread](https://www.hard-light.net/forums/index.php?topic=93812.0))
|
||||
### Added
|
||||
- Support for APNG animations: [APNG](https://en.wikipedia.org/wiki/APNG) is a variant of the established PNG format which allows to store animations instead of single frames in a PNG file. This change allows to use these animation files in FSO which significantly improves usability for modders since they no longer have to store all individual frames as separate images.
|
||||
@@ -662,7 +49,6 @@ Headlining features will always be on top.
|
||||
### Fixed
|
||||
- "Tons" of bugfixes
|
||||
|
||||
|
||||
## [3.7.2] - 2015-04-23 ([Release thread](http://www.hard-light.net/forums/index.php?topic=89597.0))
|
||||
### Added
|
||||
- MediaVPS 2014 Support
|
||||
@@ -693,19 +79,16 @@ Headlining features will always be on top.
|
||||
- Raised the per-model debris limit to 48 (previously 32).
|
||||
- Increased the per-frame debris limit to 96 (previously 64)
|
||||
|
||||
|
||||
## [3.6.18] - 2013-03-01 ([Release thread](http://www.hard-light.net/forums/index.php?topic=83889.0))
|
||||
### Fixed
|
||||
- Critical damage bug which caused heavy balance issues in the game
|
||||
|
||||
|
||||
## [3.6.16] - 2013-01-31 ([Release thread](http://www.hard-light.net/forums/index.php?topic=83577.0))
|
||||
### Added
|
||||
- Diaspora TC support
|
||||
### Changed
|
||||
- Performance Improvements
|
||||
|
||||
|
||||
## [3.6.14] - 2012-10-23 - ([Release thread](https://www.hard-light.net/forums/index.php?topic=82648.0))
|
||||
### Added
|
||||
- Objecttype tables support for deciding how enemies respond to ship classes when disabled
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
FreeSpace2 *S*ource *C*ode *P*roject
|
||||
==
|
||||
[](https://travis-ci.org/scp-fs2open/fs2open.github.com)
|
||||
[](https://ci.appveyor.com/project/SirKnightly/fs2open-github-com/branch/master)
|
||||
[](https://scan.coverity.com/projects/870)
|
||||
|
||||
Building
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
version: 1.0.0.{build}
|
||||
image: Visual Studio 2015
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
clone_depth: 10
|
||||
environment:
|
||||
matrix:
|
||||
- BuildID: 0
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
PlatformToolset: v140
|
||||
QT_DIR: C:\Qt\5.9\msvc2015
|
||||
- BuildID: 1
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
|
||||
PlatformToolset: v140
|
||||
QT_DIR: C:\Qt\5.9\msvc2015_64
|
||||
before_build:
|
||||
- git submodule update --init --recursive
|
||||
build_script:
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/build.ps1
|
||||
test_script:
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/test.ps1
|
||||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
auth_token:
|
||||
secure: h55Scpy+3vmo1Yb7WlSIGA4d9DRnsbzUYc2LYsQdByQHZHbqrqjBpicH0D2FFLEO
|
||||
on:
|
||||
ReleaseBuild: true # deploy on release push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: scp.indiegames.us
|
||||
username:
|
||||
secure: SFivQZfatqWHXK1ijYK3GQ==
|
||||
password:
|
||||
secure: q6Zk/412o1ri+NEya1dl1Q==
|
||||
folder: public_html/builds/nightly/$(VersionName)
|
||||
on:
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: porphyrion.feralhosting.com
|
||||
username:
|
||||
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
|
||||
password:
|
||||
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
|
||||
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$(VersionName)
|
||||
on:
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: porphyrion.feralhosting.com
|
||||
username:
|
||||
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
|
||||
password:
|
||||
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
|
||||
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$(VersionName)
|
||||
on:
|
||||
TestBuild: true # deploy on test build push only
|
||||
@@ -0,0 +1,164 @@
|
||||
|
||||
class BuildConfig {
|
||||
[string]$Generator
|
||||
[string]$PackageType
|
||||
[string]$Toolset
|
||||
[string]$SimdType
|
||||
[string]$QtDir
|
||||
[Bool]$SourcePackage
|
||||
}
|
||||
|
||||
$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;
|
||||
# }
|
||||
)
|
||||
$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;
|
||||
# }
|
||||
)
|
||||
|
||||
$BuildConfigurations = $null
|
||||
|
||||
# Default values
|
||||
$ReleaseBuild = $false
|
||||
$NightlyBuild = $false
|
||||
$TestBuild = $false
|
||||
|
||||
# Set to true to test either the release or the nightly part of this script
|
||||
$ReleaseTest = $false
|
||||
$NightlyTest = $false
|
||||
$TestBuildTest = $false
|
||||
|
||||
if ($ReleaseTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)"))) {
|
||||
# Tag matches
|
||||
$ReleaseBuild = $true
|
||||
$PackageName = "fs2_open_$($matches[1])"
|
||||
$BuildConfigurations = $ReleaseConfigurations
|
||||
}
|
||||
|
||||
if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)"))) {
|
||||
# Tag matches
|
||||
$NightlyBuild = $true
|
||||
$PackageName = "nightly_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
$BuildConfigurations = $NightlyConfigurations
|
||||
}
|
||||
|
||||
if ($TestBuildTest -Or ([System.Convert]::ToInt32($env:APPVEYOR_PULL_REQUEST_NUMBER) -le 0 -And ("$env:APPVEYOR_REPO_BRANCH" -match "^test\/(.*)"))) {
|
||||
# Tag matches
|
||||
$TestBuild = $true
|
||||
$PackageName = "test_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
$BuildConfigurations = $NightlyConfigurations
|
||||
|
||||
# Override the revision string so that the builds are named correctly
|
||||
[System.IO.File]::WriteAllLines("$env:APPVEYOR_BUILD_FOLDER/version_override.cmake", "set(FSO_VERSION_REVISION_STR $env:VersionName)")
|
||||
}
|
||||
|
||||
# Multiply by 2 so that we can add 0 or 1 for debug or release Configs
|
||||
$buildID = [convert]::ToInt32($env:BuildID) * 2
|
||||
if ($Env:Configuration -eq "Release") {
|
||||
$buildID = $buildID + 1
|
||||
}
|
||||
|
||||
$DeployBuild = $false
|
||||
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
|
||||
$DeployBuild = $true
|
||||
}
|
||||
|
||||
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
|
||||
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
|
||||
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
|
||||
|
||||
New-Item build -type directory
|
||||
Set-Location -Path build
|
||||
|
||||
if ($DeployBuild) {
|
||||
# Release build
|
||||
if ($buildID -ge $BuildConfigurations.Length) {
|
||||
# Not needed
|
||||
exit 0
|
||||
}
|
||||
|
||||
$buildConfig = $BuildConfigurations[$buildID]
|
||||
|
||||
if ($buildConfig.SourcePackage -eq $True) {
|
||||
7z a -xr'!.git' "$($PackageName)-source-Win.zip" "$env:APPVEYOR_BUILD_FOLDER"
|
||||
Push-AppveyorArtifact "$($PackageName)-source-Win.zip"
|
||||
}
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
|
||||
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=ON `
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" `
|
||||
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
|
||||
|
||||
$Configs = @("Release", "FastDebug")
|
||||
foreach ($config in $Configs) {
|
||||
cmake --build . --config "$config" --target INSTALL -- /verbosity:minimal
|
||||
if (! ($?)) {
|
||||
Add-AppveyorMessage "A release build failed!"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
7z a -xr'!*.pdb' "$($PackageName)-builds-$($buildConfig.PackageType).zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
|
||||
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
|
||||
|
||||
7z a "$($PackageName)-debug-$($buildConfig.PackageType).7z" "$env:APPVEYOR_BUILD_FOLDER/../install/*.pdb"
|
||||
Push-AppveyorArtifact "$($PackageName)-debug-$($buildConfig.PackageType).7z"
|
||||
} else {
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
|
||||
-DFSO_BUILD_QTFRED=ON -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
|
||||
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
|
||||
|
||||
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
|
||||
|
||||
if (! ($?)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
|
||||
# Skip tests for deployment
|
||||
exit 0
|
||||
} else {
|
||||
write "Running unit tests..."
|
||||
# Run unit tests
|
||||
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
|
||||
|
||||
if (! ($?)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@ set -e
|
||||
SCRIPT=$(readlink -f "$0")
|
||||
HERE=$(dirname "$SCRIPT")
|
||||
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
COMMIT_RANGE=$1..$2
|
||||
|
||||
if ! git rev-list $COMMIT_RANGE 2>&1 >/dev/null; then
|
||||
@@ -21,5 +19,5 @@ 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)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
|
||||
-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"
|
||||
+16
-38
@@ -1,41 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$COMPILER" = "gcc-9" ]; then
|
||||
export CC=gcc-9
|
||||
export CXX=g++-9
|
||||
if [ "$COMPILER" = "gcc-5" ]; then
|
||||
export CC=gcc-5
|
||||
export CXX=g++-5
|
||||
fi
|
||||
if [ "$COMPILER" = "gcc-13" ]; then
|
||||
export CC=gcc-13
|
||||
export CXX=g++-13
|
||||
if [ "$COMPILER" = "gcc-10" ]; then
|
||||
export CC=gcc-10
|
||||
export CXX=g++-10
|
||||
fi
|
||||
if [ "$COMPILER" = "clang-16" ]; then
|
||||
export CC=clang-16
|
||||
export CXX=clang++-16
|
||||
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
|
||||
if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
CXXFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
|
||||
# TODO: Vulkan support is disabled on MacOS due to issues with the test suite not linking correctly
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
|
||||
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
|
||||
else
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
|
||||
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"
|
||||
|
||||
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
|
||||
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
|
||||
# force clang to silently allow -static-libstdc++ flag
|
||||
CXXFLAGS="$CXXFLAGS -Qunused-arguments"
|
||||
fi
|
||||
|
||||
if [ ! "$CCACHE_PATH" = "" ]; then
|
||||
echo "Using ccache at $CCACHE_PATH"
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER_LAUNCHER=$CCACHE_PATH -DCMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_PATH"
|
||||
fi
|
||||
|
||||
mkdir build
|
||||
@@ -45,14 +30,7 @@ export CXXFLAGS
|
||||
export CFLAGS
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
brew install ninja
|
||||
fi
|
||||
|
||||
# CMAKE_JOB_POOLS and CMAKE_JOB_POOL_LINK ensure that when using ninja, link operations are done sequentially
|
||||
# we have some build rules that do not play nice with parallel invocation and that fixes these issues
|
||||
|
||||
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS $PLATFORM_CMAKE_OPTIONS \
|
||||
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DCMAKE_BUILD_TYPE=$CONFIGURATION \
|
||||
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=${ENABLE_QTFRED:-OFF} \
|
||||
-DSHADERS_ENABLE_COMPILATION=ON -DCMAKE_JOB_POOLS=link=1 -DCMAKE_JOB_POOL_LINK=link ..
|
||||
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 ..
|
||||
@@ -10,27 +10,21 @@ source $HERE/dist_functions.sh
|
||||
if [ "$OS" = "Linux" ]; then
|
||||
tar -cvzf "$(get_package_name)-builds-Linux.tar.gz" *
|
||||
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Linux.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Linux.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux.tar.gz")" >> $GITHUB_OUTPUT
|
||||
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 "package_path=$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-$ARCH-$SIMD.zip" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip")" >> $GITHUB_OUTPUT
|
||||
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 "debug_path=$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
|
||||
echo "debug_name=$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
|
||||
echo "debug_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")" >> $GITHUB_OUTPUT
|
||||
elif [ "$OS" = "Mac" ]; then
|
||||
tar -cvzf "$(get_package_name)-builds-Mac-$ARCH.tar.gz" *.app
|
||||
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Mac-$ARCH.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Mac-$ARCH.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Mac-$ARCH.tar.gz")" >> $GITHUB_OUTPUT
|
||||
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
|
||||
@@ -5,14 +5,7 @@ HERE=$(dirname "$SCRIPT")
|
||||
|
||||
export LD_LIBRARY_PATH=$(pwd)/bin/lib:$LD_LIBRARY_PATH
|
||||
|
||||
# if on mac and building for architecture that doesn't match host
|
||||
# then unittests will fail so we just need to skip it (for now)
|
||||
if [ "$RUNNER_OS" = "macOS" ] && [ "$ARCH" != "$(uname -m)" ]; then
|
||||
echo "Skipping tests due to architecture mismatch!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$CONFIGURATION" = "Debug"] && [[ "$RUNNER_OS" != "macOS" ]] ; then
|
||||
if [ "$CONFIGURATION" = "Debug" ]; then
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$HERE/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
else
|
||||
|
||||
@@ -10,21 +10,11 @@ HERE=$(dirname "$SCRIPT")
|
||||
source $HERE/dist_functions.sh
|
||||
|
||||
if [ "$UPLOAD_TYPE" = "nightly" ]; then
|
||||
any_success=false
|
||||
if SSHPASS=$INDIEGAMES_SSHPASS upload_files_to_sftp "$INDIEGAMES_USER@scp.indiegames.us" "public_html/builds/nightly"; then
|
||||
any_success=true
|
||||
fi
|
||||
SSHPASS=$INDIEGAMES_SSHPASS upload_files_to_sftp "$INDIEGAMES_USER@scp.indiegames.us" "public_html/builds/nightly"
|
||||
|
||||
if SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/nightly"; then
|
||||
any_success=true
|
||||
fi
|
||||
|
||||
if [ "$any_success" = "false" ]; then
|
||||
echo "All uploads failed"
|
||||
exit 1
|
||||
fi
|
||||
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@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/test"
|
||||
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
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
# Retrives a log of commit messages and attempts to pretty them into a human-readbile format
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
import sys
|
||||
|
||||
from datetime import datetime
|
||||
from subprocess import check_output
|
||||
|
||||
MAX_PAGES = 100 # maximum number of PR pages to go through
|
||||
warnings = 0
|
||||
|
||||
def get_last_page(response: requests.Response) -> int:
|
||||
"""
|
||||
@brief Extract the last page number from the response header
|
||||
|
||||
@param[in] response The response from a GET call
|
||||
|
||||
@returns The page number of the last page, or MAX_PAGES
|
||||
"""
|
||||
|
||||
# The link header is a dictionary in string form, and for that matter the
|
||||
# value is in front of the key. It is of the form '<<url1>>; rel=<key1>, <url2>, <key2>'
|
||||
link = response.headers['link']
|
||||
link = link.split(',')
|
||||
for x in link:
|
||||
y = x.split(';') # <url>; rel=<key>
|
||||
if "last" not in y[1]: # look for rel='last'
|
||||
continue
|
||||
# grab the page number from the URL
|
||||
# group(0) is `page=123`, group(1) is `123`
|
||||
last_page = int( re.search(r'page=(\d+)', y[0]).group(1) )
|
||||
if not last_page:
|
||||
print("Error: Could not find page number in url! URL: %s", y[0])
|
||||
sys.exit(1)
|
||||
|
||||
if last_page > MAX_PAGES:
|
||||
return MAX_PAGES
|
||||
else:
|
||||
return last_page
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Retrieves a log of commit messages and attempts to pretty them into a human-readable format")
|
||||
parser.add_argument("start_date",
|
||||
help="Day of the earliest commit to add to the log.")
|
||||
parser.add_argument("-u", "--user", nargs=2, metavar=("NAME", "TOKEN"), default=["", ""],
|
||||
help="Github username and token/password")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
os.chdir(os.path.dirname(__file__)) # Change working directory to this file's directory
|
||||
start_date = datetime.strptime(args.start_date, "%Y-%m-%d")
|
||||
|
||||
print("start_date: {}".format(start_date))
|
||||
|
||||
# Retrive the git log for master, since start date, order by date, in ascending order, use YYYY-MM-DD date format,
|
||||
# each line is of the form "<author short date> | <message>", only grab commits from master,
|
||||
# output to `fsofordigest.txt`,
|
||||
|
||||
# check_output(("git log master", "--after=2021-09-15", "--date-order", "--reverse", "--date=short",
|
||||
# "--pretty=\"%as | %s\"", "--first-parent",
|
||||
# "--output fsofordigest.txt"), text=True)
|
||||
|
||||
# The commit messages are either of the form "<body> (#<PR_number>)" or "Merge pull request #<PR_number> from <source_repo>"
|
||||
# For our purposes, we want them be all of the form "<body> (#<PR_number>)"
|
||||
# Typically, the second form does not have a usable body, so we'll have to pull the PR title from github
|
||||
|
||||
# Github's REST API allows us to retrieve PR's, but due to it being HTTP requests it has to page in the data.
|
||||
# We can loop over the GET request and check for a merge date.
|
||||
# The GET request doesn't have sorting by merge date, but does have sorting by the last time it was updated... which is usually
|
||||
# also the merge date but not always.
|
||||
|
||||
# Key attributes within the PR JSON objects:
|
||||
# "merged_at: <date>" # Date the PR was merged in
|
||||
# "merged: <bool>" # If the PR was merged yet
|
||||
# "html_url: <string>" # URL of the PR's HEAD commit, used by some clients to pull in the PR branch
|
||||
# "number: <int>" # The PR id number
|
||||
# "title: <string>" # Title of the PR
|
||||
# "body: <string>" # The body paragraph detailing the PR
|
||||
# "labels: [label_object]" # All labels attached to this PR
|
||||
|
||||
changelog = {}
|
||||
url = "https://api.github.com/repos/scp-fs2open/fs2open.github.com/pulls"
|
||||
page = 1
|
||||
last_page = MAX_PAGES
|
||||
while page <= last_page:
|
||||
# GET <url>?base=master&sort=updated&direction=desc&state=closed&page=1
|
||||
response = requests.get(url,
|
||||
auth=(args.user[0], args.user[1]),
|
||||
params={
|
||||
"base": "master",
|
||||
"direction": "desc",
|
||||
"page": page,
|
||||
"state": "closed",
|
||||
"sort": "updated"
|
||||
})
|
||||
|
||||
# Check if good response
|
||||
if (response.status_code != 200) :
|
||||
print("Error: ", response.status_code)
|
||||
print(response.json()['message'])
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("Request successful: 200")
|
||||
print("page={}".format(page))
|
||||
|
||||
# Update the last_page index at first iteration and possibly last iteration
|
||||
# This should cover the edge case of a new PR being added to the database before this script is finished
|
||||
if (page == 1) or (page == last_page):
|
||||
last_page = get_last_page(response)
|
||||
print("last_page={}".format(last_page))
|
||||
|
||||
# assume pulls are organized from newest to oldest
|
||||
for pull in response.json():
|
||||
if (pull['state'] != 'closed'):
|
||||
# This pull is not merged, so ignore
|
||||
print("Found irrelevant pull, skipping...")
|
||||
print("state: {}; number: {}".format(pull['state'], pull['number']))
|
||||
continue
|
||||
|
||||
if (pull['merged_at'] == None):
|
||||
# This pull wasn't merged, skip
|
||||
print("Found closed pull #{} ({}), skipping...".format(pull['number'], pull['closed_at']))
|
||||
continue
|
||||
|
||||
merge_date = datetime.strptime(pull['merged_at'], "%Y-%m-%dT%H:%M:%SZ")
|
||||
updated_date = datetime.strptime(pull['updated_at'], "%Y-%m-%dT%H:%M:%SZ")
|
||||
if (merge_date < start_date) and (updated_date >= start_date):
|
||||
# This pull is too old, but was updated within our timeframe. skip
|
||||
print("Found old pull #{} ({}), skipping...".format(pull['number'], pull['merged_at']))
|
||||
continue
|
||||
|
||||
if (updated_date < start_date):
|
||||
# This pull is too old
|
||||
print("Found old pull #{} ({}), stopping loop...".format(pull['number'], pull['updated_at']))
|
||||
page = last_page + 1
|
||||
break
|
||||
|
||||
# Add the pull to the changelog, indexed by its pull.number
|
||||
if pull['number'] not in changelog:
|
||||
# only add if the key isn't there already
|
||||
changelog[pull['number']] = {
|
||||
"date": merge_date,
|
||||
"title": pull['title'],
|
||||
"labels": pull['labels'],
|
||||
"url": pull['html_url']
|
||||
}
|
||||
print("Added pull #{} ({})".format(pull['number'], merge_date))
|
||||
# Else, silently ignore duplicate (for now...)
|
||||
|
||||
page += 1 # iterate to next page
|
||||
|
||||
|
||||
# Write the changelog to file
|
||||
# 2021-09-28 | (#3661) Fix homing child weapons in niche circumstances
|
||||
print("Writing to change.log...")
|
||||
str = ''
|
||||
for key, value in changelog.items():
|
||||
str += "{} | (#{}) {} \n".format(value['date'].strftime("%Y-%m-%d"), key, value['title'])
|
||||
|
||||
with open("change.log", "w") as file:
|
||||
file.write(str)
|
||||
|
||||
print("Done!")
|
||||
|
||||
main()
|
||||
@@ -1,228 +0,0 @@
|
||||
import re # regex module
|
||||
from ftplib import FTP, error_perm
|
||||
from itertools import groupby
|
||||
from typing import List, Tuple, Dict
|
||||
|
||||
import requests # HTTP requests module
|
||||
|
||||
from util import retry_multi, GLOBAL_TIMEOUT # from util.py
|
||||
|
||||
|
||||
class ReleaseFile:
|
||||
"""! Class representing a Released file on Nebula
|
||||
|
||||
`name`: str
|
||||
Mod (or build) name,
|
||||
`url`: str
|
||||
Primary host URL,
|
||||
`group`: str
|
||||
Mod group string,
|
||||
`subgroup`: str
|
||||
Mod subgroup string,
|
||||
`mirrors`: List[str]
|
||||
List of URL's of FTP mirrors
|
||||
"""
|
||||
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
|
||||
|
||||
def __repr__(self):
|
||||
return repr((self.name))
|
||||
|
||||
|
||||
class SourceFile:
|
||||
"""! Class represeting a source file
|
||||
|
||||
`name`: str
|
||||
File name,
|
||||
`url`: str
|
||||
FTP URL,
|
||||
`group`
|
||||
<unknown>
|
||||
|
||||
@details More details
|
||||
"""
|
||||
def __init__(self, name, url, group):
|
||||
self.group = group
|
||||
self.url = url
|
||||
self.name = name
|
||||
|
||||
|
||||
class FileGroup:
|
||||
"""! Represents a file group
|
||||
|
||||
`name`: str
|
||||
Name of this group
|
||||
`files`: List[ReleaseFile]
|
||||
List of files within this group
|
||||
`mainFile`: str
|
||||
If this FileGroup has a subgroup, `mainFile` is the head of that group
|
||||
`subFiles`: List[ReleaseFile]
|
||||
Files within a subgroup
|
||||
"""
|
||||
|
||||
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)))
|
||||
|
||||
|
||||
def get_release_files(tag_name, config) -> Tuple[List[ReleaseFile], Dict[str, SourceFile]]:
|
||||
"""! Brief Gets the binary and source files from the Github Release server
|
||||
|
||||
@param[in] `tag_name` Git tag of the current release
|
||||
@param[in] `config` confi metadata set in main.py
|
||||
|
||||
@returns `List[ReleaseFile]` List of release files
|
||||
@returns `Dict[str, SourceFile]` Dictionary of source files
|
||||
|
||||
@details Sends an `HTTP GET` request to github using their REST API to retrieve metadata. The files are not
|
||||
actually downloaded here, just their metadata is gathered and organized in their respective container for later
|
||||
use.
|
||||
"""
|
||||
|
||||
@retry_multi(5) # retry at most 5 times
|
||||
def execute_request(path):
|
||||
"""!
|
||||
@brief Performs a GET request with the given path. To be used with Github's REST API.
|
||||
@returns If successful, returns a .JSON object
|
||||
"""
|
||||
headers = {
|
||||
"Accept": "application/vnd.github.v3+json"
|
||||
}
|
||||
url = "https://api.github.com" + path
|
||||
|
||||
# GET https://api.github.com/<path> Accept: "application/vnd.github.v3+json"
|
||||
|
||||
response = requests.get(url, headers=headers, timeout=GLOBAL_TIMEOUT)
|
||||
|
||||
response.raise_for_status() # Raise a RequestException if we failed, and trigger retry
|
||||
|
||||
return response.json()
|
||||
|
||||
build_group_regex = re.compile("fs2_open_.*-builds-([^.-]*)(-([^.]*))?.*") # regex for matching binary .zip's and .7z's
|
||||
source_file_regex = re.compile("fs2_open_.*-source-([^.]*)?.*") # regex for matching source .zip's and .7z's
|
||||
|
||||
# Get the github release metadata of the given tag name
|
||||
response = execute_request(
|
||||
"/repos/{}/releases/tags/{}".format(config["github"]["repo"], tag_name))
|
||||
|
||||
# Extract the binary and source files from the response["asset"] metadata
|
||||
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)
|
||||
|
||||
binary_files.sort(key=lambda ReleaseFile: ReleaseFile.name)
|
||||
|
||||
return binary_files, source_files
|
||||
|
||||
|
||||
def get_ftp_files(build_type, tag_name, config) -> List[ReleaseFile] :
|
||||
"""!
|
||||
@brief Gets file metadata for nightlies hosted on FTP, as determined by config["ftp"] attributes
|
||||
|
||||
@param [in] `build_type` Unknown str
|
||||
@param [in] `tag_name` Github tag name of the release
|
||||
@param [in] `config` config metadata set in main.py
|
||||
"""
|
||||
|
||||
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:
|
||||
# extract version
|
||||
version_str = tag_regex.match(tag_name).group(1)
|
||||
|
||||
# extract filepath w/ version
|
||||
# then list all ftp hits with that path
|
||||
path_template = config["ftp"]["path"]
|
||||
path = path_template.format(type=build_type, version=version_str)
|
||||
file_entries = list(ftp.mlsd(path, ["type"]))
|
||||
|
||||
# get all ftp hits of type file
|
||||
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:
|
||||
# from the file list, extract only nightly 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")
|
||||
|
||||
# construct the download URL list for all mirrors. The first listed ftp location is taken as the Primary
|
||||
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)
|
||||
|
||||
# Form the List[ReleaseFile] list with the download URL links
|
||||
out_data.append(ReleaseFile(file, primary_url, group_match, None, mirrors))
|
||||
|
||||
return out_data
|
||||
@@ -1,103 +0,0 @@
|
||||
from typing import List
|
||||
|
||||
import requests
|
||||
import semantic_version
|
||||
from mako.template import Template
|
||||
|
||||
from file_list import ReleaseFile
|
||||
|
||||
|
||||
class ForumAPI:
|
||||
POST_SIZE_MAX = 50000
|
||||
"""!
|
||||
Maximum number of characters allowed in a post, including BBCode (03/17/2022)
|
||||
|
||||
Check with HLP admins occasionally to verify this limit, they can set it in the forum's admin panel
|
||||
"""
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
def create_post(self, title, content, board):
|
||||
"""!
|
||||
@brief Create a post on the forums
|
||||
|
||||
@param[in] title Title of the post
|
||||
@param[in] content Body of the post
|
||||
@param[in] board Which board/forum to post to
|
||||
|
||||
@returns { "thread_url": <url_of_created_thread> }
|
||||
"""
|
||||
|
||||
if (self.config["hlp"]["api"] == "") or (self.config["hlp"]["key"] == ""):
|
||||
print("Post failed! No API or API_KEY given!")
|
||||
return
|
||||
|
||||
resp = requests.post(self.config["hlp"]["api"], data={
|
||||
"api_key": self.config["hlp"]["key"],
|
||||
"board": str(board),
|
||||
"subject": title,
|
||||
"body": content
|
||||
})
|
||||
|
||||
if resp.status_code != 200:
|
||||
print("Post failed! Response: %s" %resp.text)
|
||||
|
||||
return resp.json()
|
||||
|
||||
def post_nightly(self, date, revision, files, log, success):
|
||||
"""!
|
||||
@brief Post a new Nightly topic on the forums using nightly.mako
|
||||
|
||||
@param[in] date The date to use
|
||||
@param[in] version The build's version
|
||||
@param[in] groups dict[Any, file_list.FileGroup]; FileGroups of SSE2, AVX, etc.
|
||||
@param[in] sources URL's of builds on github or fs2net
|
||||
"""
|
||||
|
||||
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):
|
||||
"""!
|
||||
@brief Post a new Release topic on the forums using release.mako.
|
||||
|
||||
@param[in] date The date to use
|
||||
@param[in] version The build's version
|
||||
@param[in] groups dict[Any, file_list.FileGroup]; FileGroups of SSE2, AVX, etc.
|
||||
@param[in] sources URL's of builds on github or fs2net
|
||||
|
||||
@returns If Successful, the URL of the created post
|
||||
"""
|
||||
|
||||
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...")
|
||||
|
||||
json = self.create_post(title, rendered, self.config["release"]["hlp_board"])
|
||||
return json["thread_url"]
|
||||
@@ -1,85 +0,0 @@
|
||||
# Class for use with interfacing with github via HTTP requests
|
||||
|
||||
import requests
|
||||
|
||||
from util import retry_multi, GLOBAL_TIMEOUT
|
||||
|
||||
class GithubAPI:
|
||||
headers = {
|
||||
"Accept": "application/vnd.github.v3+json"
|
||||
}
|
||||
url_root = "https://api.github.com"
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
@retry_multi(5)
|
||||
def get(self, path):
|
||||
"""!
|
||||
@brief Performs a GET request with the given path. To be used with Github's REST API.
|
||||
@returns If successful, returns a .JSON object
|
||||
"""
|
||||
url = self.url_root + path
|
||||
|
||||
# GET https://api.github.com/<path> Accept: "application/vnd.github.v3+json"
|
||||
|
||||
response = requests.get(url, headers=self.headers, timeout=GLOBAL_TIMEOUT)
|
||||
|
||||
response.raise_for_status() # Raise a RequestException if we failed, and trigger retry
|
||||
|
||||
return response.json()
|
||||
|
||||
def get_release(self, tag_name):
|
||||
"""!
|
||||
@brief Retrieves the Github Release metadata as a JSON object
|
||||
@see https://docs.github.com/en/rest/reference/releases#get-a-release-by-tag-name
|
||||
"""
|
||||
return self.get("/repos/{}/releases/tags/{}".format(self.config["github"]["repo"], tag_name))
|
||||
|
||||
|
||||
def patch(self, path, data):
|
||||
"""!
|
||||
@brief Performs a PATCH request with the given path and body data (as dictionary)
|
||||
@returns If successful, returns a .JSON object
|
||||
"""
|
||||
url = self.url_root + path
|
||||
|
||||
response = requests.patch(url, headers=self.headers, timeout=GLOBAL_TIMEOUT, data=data)
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
return response.json()
|
||||
|
||||
def update_release(self, release_id, tag_name="", name="", body="", draft=None, prerelease=None):
|
||||
"""!
|
||||
@brief Updates a Github Release
|
||||
@param[in] release_id The id of the release, as obtained by get_release()
|
||||
@param[in] tag_name (optional) The git tag this release is associated with
|
||||
@param[in] name (optional) The name of the release
|
||||
@param[in] body (optional) Body text describing the release
|
||||
@param[in] draft (optional) If true, the release is marked as a "draft"
|
||||
@param[in] prerelease (optional) If true, the release is marked as a "prerelease"
|
||||
|
||||
@note If an optional argument is not provided, then its associated data is not changed
|
||||
"""
|
||||
path = "/repos/{}/releases/{}".format(self.config["github"]["repo"], release_id)
|
||||
|
||||
# Add to the data JSON if options are specified
|
||||
data = {}
|
||||
if tag_name != "":
|
||||
data["tag_name"] = tag_name
|
||||
|
||||
if name != "":
|
||||
data["name"] = name
|
||||
|
||||
if body != "":
|
||||
data["body"] = body
|
||||
|
||||
if draft != None:
|
||||
data["draft"] = data
|
||||
|
||||
if prerelease != None:
|
||||
data["prerelease"] = prerelease
|
||||
|
||||
self.patch(path, data)
|
||||
|
||||
@@ -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")
|
||||
-309
@@ -1,309 +0,0 @@
|
||||
# Post-build python script
|
||||
# Uploads build packages to Nebula and creates a forum post on https://www.hard-light.net
|
||||
# Uses the following environment variables (Set by the github action workflow before execution)
|
||||
|
||||
# FSO versioning
|
||||
# FSO_VERSION_MAJOR
|
||||
# FSO_VERSION_MINOR
|
||||
# FSO_VERSION_BUILD
|
||||
|
||||
# Credentials into IndieGames file host
|
||||
# INDIEGAMES_USER:
|
||||
# INDIEGAMES_SSHPASS:
|
||||
|
||||
# Credentials into Nebula Mod Database
|
||||
# NEBULA_USER:
|
||||
# NEBULA_PASSWORD:
|
||||
|
||||
# Credentials into hard-light.net for forum post
|
||||
# HLP_API:
|
||||
# HLP_KEY:
|
||||
|
||||
# LINUX_RESULT: bool, if the linux builds were successfully uploaded
|
||||
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from subprocess import check_output
|
||||
from datetime import datetime
|
||||
from itertools import groupby
|
||||
|
||||
import semantic_version
|
||||
|
||||
# local .py files
|
||||
import file_list
|
||||
import installer
|
||||
import nebula
|
||||
import forum
|
||||
|
||||
# Compile regexes for extracting version components
|
||||
MAJOR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_MAJOR (\d+)\)")
|
||||
MINOR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_MINOR (\d+)\)")
|
||||
BUILD_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_BUILD (\d+)\)")
|
||||
REVISION_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION (\d+)\)")
|
||||
REVISION_STR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION_STR (\w*)\)")
|
||||
|
||||
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):
|
||||
"""! Extracts the version component represented by `regex` from `text`
|
||||
|
||||
@param [in] `text` Filename with version string 'MAJOR.MINOR.BUILD'
|
||||
@param [in] `regex` Regex pattern of component to look for
|
||||
|
||||
@return The version component as integer
|
||||
"""
|
||||
match = regex.search(text)
|
||||
return int(match.group(1))
|
||||
|
||||
def _match_version_str(text, regex):
|
||||
"""! Extracts the version component represented by `regex` from `text`
|
||||
|
||||
@param [in] `text` Filename with version string 'MAJOR.MINOR.BUILD'
|
||||
@param [in] `regex` Regex pattern of component to look for
|
||||
|
||||
@return The version component as integer
|
||||
"""
|
||||
match = regex.search(text)
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def get_source_version(date_version: datetime, tag_name: str) -> semantic_version.Version:
|
||||
"""! Retrieves the version string from version_override.cmake (and version.cmake)
|
||||
|
||||
@param[in] `date_version` Date this build is published for release
|
||||
@param[in] `tag_name` Tag of this release, used to determine if release, rc, or nightly
|
||||
|
||||
@return If release: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD`
|
||||
@return If rc: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD-FSO_VERSION_REVISION_STR`
|
||||
@return If nightly: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD-FSO_VERSION_REVISION_STR` (uses both version_override.cmake and version.cmake)
|
||||
|
||||
@note This is the version used to identify in Nebula and the forums. version_override.cmake is used for the builds
|
||||
made by CI tools and version.cmake is used for builds made by devs.
|
||||
"""
|
||||
|
||||
with open(os.path.join("..", "..", "version_override.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)
|
||||
# revision = _match_version_number(filetext, REVISION_VERSION_PATTERN)
|
||||
revision_str = _match_version_str(filetext, REVISION_STR_VERSION_PATTERN)
|
||||
|
||||
print("Parsing version_override.cmake...")
|
||||
if "rc" in tag_name.lower():
|
||||
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, revision_str))
|
||||
|
||||
elif "release" in tag_name.lower():
|
||||
version = semantic_version.Version("{}.{}.{}".format(major, minor, build))
|
||||
|
||||
elif "nightly" in tag_name.lower():
|
||||
# Nightly's version_override.cmake only has FSO_VERSION_REVISION and FSO_VERSION_REVISION_STR set
|
||||
# So, we have to pull the rest of the version string from version.cmake
|
||||
print("Parsing version.cmake...")
|
||||
with open(os.path.join("..", "..", "cmake", "version.cmake"), "r") as f:
|
||||
major = _match_version_number(filetext, MAJOR_VERSION_PATTERN)
|
||||
minor = _match_version_number(filetext, MINOR_VERSION_PATTERN)
|
||||
build = _match_version_number(filetext, BUILD_VERSION_PATTERN)
|
||||
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, revision_str))
|
||||
|
||||
else:
|
||||
print(" ERROR: malformed tag_name %s" % tag_name)
|
||||
sys.exit(1)
|
||||
|
||||
print(" version: {}".format(version))
|
||||
print(" version.prerelease: {}".format(version.prerelease))
|
||||
return version
|
||||
|
||||
|
||||
def main():
|
||||
os.chdir(os.path.dirname(__file__)) # Change working directory to this file's directory
|
||||
|
||||
# Aggregate configuration data in a dictionary
|
||||
config = {
|
||||
"github": {
|
||||
"repo": os.environ["GITHUB_REPO"],
|
||||
},
|
||||
"ftp": {
|
||||
"host": "scp.indiegames.us",
|
||||
"user": os.environ["INDIEGAMES_USER"],
|
||||
"pass": os.environ["INDIEGAMES_SSHPASS"],
|
||||
"path": "public_html/builds/{type}/{version}/",
|
||||
"mirrors": (
|
||||
"https://perses.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
|
||||
"https://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,
|
||||
},
|
||||
}
|
||||
|
||||
# bail if this script is run from a workflow that doesn't identify as a release or nightly
|
||||
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)
|
||||
|
||||
linux_success = os.environ["LINUX_RESULT"] == "success"
|
||||
windows_success = os.environ["WINDOWS_RESULT"] == "success"
|
||||
if (sys.argv[1] == "release"):
|
||||
if not (linux_success and windows_success):
|
||||
# bail if this is a release and either build workflow failed
|
||||
print("ERROR: One or more builds failed to publish! Cannot post release.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
if not (linux_success or windows_success):
|
||||
# bail if this is a nightly build and both build workflows failed
|
||||
print("ERROR: All builds failed to publish! Cannot post nightly.")
|
||||
sys.exit(1)
|
||||
|
||||
# bail if tag_name doesn't match with sys.argv[1]
|
||||
tag_name = os.environ["RELEASE_TAG"] ##!< commit tag string
|
||||
if (sys.argv[1] == "release") and (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)
|
||||
|
||||
if (sys.argv[1] == "nightly") and (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)
|
||||
|
||||
# bail if tag_name does not exist in the repo
|
||||
if not check_output(("git", "show-ref", "--tags", "refs/tags/%s" % tag_name), text=True):
|
||||
print("ERROR: Couldn't find tag %s in repo (git show-ref)!" % tag_name)
|
||||
sys.exit(1)
|
||||
|
||||
# Populate version and date
|
||||
date = datetime.now() ##!< current date
|
||||
version = get_source_version(date.strftime(DATEFORMAT_VERSION), tag_name) ##!< form full version string
|
||||
|
||||
# find the previous tag release (used by nightly)
|
||||
tags = check_output(("git", "for-each-ref", "--sort=-taggerdate", "--format='%(tag)'", "refs/tags"), text=True).splitlines() # retrieve all tags in the repo by using git on the shell
|
||||
# NOTE: check_output returns canonical string representation. use repr() on strings its being compared to
|
||||
previous_tag = None
|
||||
found = False
|
||||
for tag in tags:
|
||||
if found:
|
||||
# Look for the "previous" tag with the same configuration ('release_' or 'nightly_')
|
||||
# Assumes older tags have a higher index than newer
|
||||
if tag.startswith("\'" + sys.argv[1] + "_"):
|
||||
previous_tag = tag
|
||||
break
|
||||
elif tag == repr(tag_name):
|
||||
# Ok, found the tag
|
||||
found = True
|
||||
|
||||
if not found:
|
||||
# couldn't find tag, bail
|
||||
print("ERROR: Couldn't find tag %s in repo! (git for-each-ref)" % tag_name)
|
||||
sys.exit(1)
|
||||
|
||||
if (sys.argv[1] == "nightly") and (not previous_tag):
|
||||
# couldn't find previous tag, bail
|
||||
print("ERROR: Could not find a previous tag for %s!" % tag_name)
|
||||
sys.exit(1)
|
||||
|
||||
if sys.argv[1] == "release":
|
||||
# Release specific action
|
||||
print("Retrieving file list...")
|
||||
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
|
||||
# split the file list into a dictionary of {group: files} pairs using `groupby()`
|
||||
# Since `groupby()` returns a iterator reference to the original files list, we have to do a weird hand toss
|
||||
# to save it as a dictionary
|
||||
## NOTE z64: files need to be sorted or else key duplication will occur!
|
||||
groups = {key: file_list.FileGroup(key, list(group)) for key, group in groupby(files, lambda g: g.group)}
|
||||
|
||||
# Error check for all group keys and subkeys to be used in the mako. Do this here for better debugging QoL
|
||||
if "Win32" in groups.keys():
|
||||
if "AVX" not in groups["Win32"].subFiles.keys():
|
||||
print("ERROR: No Win32-AVX builds were detected!")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("ERROR: No Win32 builds were detected!")
|
||||
sys.exit(1)
|
||||
|
||||
if "Win64" in groups.keys():
|
||||
if "AVX" not in groups["Win64"].subFiles.keys():
|
||||
print("ERROR: No x64-AVX builds were detected!")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("ERROR: No x64 builds were detected!")
|
||||
sys.exit(1)
|
||||
|
||||
if "Linux" not in groups.keys():
|
||||
print("ERROR: No Linux builds were detected!")
|
||||
sys.exit(1)
|
||||
|
||||
if "Mac" not in groups.keys():
|
||||
print("ERROR: No Mac builds were detected!")
|
||||
sys.exit(1)
|
||||
|
||||
# z64: What dose this do???
|
||||
# print(installer.render_installer_config(version, groups, config))
|
||||
|
||||
# Publish release builds to Nebula
|
||||
print("Publishing to Nebula...")
|
||||
nebula.submit_release(
|
||||
nebula.render_nebula_release(version, "rc" if version.prerelease else "stable", files, config),
|
||||
config)
|
||||
|
||||
# Publish forum post, using the release.mako template
|
||||
print("Publishing to Hard-light.net...")
|
||||
fapi = forum.ForumAPI(config)
|
||||
fapi.post_release(date.strftime(DATEFORMAT_FORUM), version, groups, sources)
|
||||
|
||||
else:
|
||||
# Dead for now, nightly publish is done elsewhere
|
||||
# Nightly specific action
|
||||
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)
|
||||
|
||||
print("Publishing to Nebula...")
|
||||
nebula.submit_release(
|
||||
nebula.render_nebula_release(version, "nightly", files, config),
|
||||
config)
|
||||
|
||||
# Compile commit messages into a log with all commits between this nightly and the previous nightly
|
||||
log = check_output(("git", "log", "%s^..%s^" % (previous_tag, tag_name), "--no-merges", "--stat", "--pretty=format:\"%s\"" % LOG_FORMAT.strip()))
|
||||
|
||||
# Publish forum post, using the nighty.mako template
|
||||
print("Publishing to Hard-light.net...")
|
||||
fapi = forum.ForumAPI(config)
|
||||
fapi.post_nightly(date.strftime(DATEFORMAT_FORUM), os.environ["GITHUB_SHA"], files, log, (linux_success and windows_success))
|
||||
|
||||
print("Done!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,252 +0,0 @@
|
||||
import os.path
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import requests
|
||||
|
||||
from file_list import ReleaseFile
|
||||
from util import retry_multi, GLOBAL_TIMEOUT
|
||||
|
||||
LINUX_KEY = "Linux"
|
||||
MACOSX_X64_KEY = "Mac-x86_64"
|
||||
MACOSX_ARM64_KEY = "Mac-arm64"
|
||||
WIN32_SSE2_KEY = "Win32-SSE2"
|
||||
WIN64_SSE2_KEY = "Win64-SSE2"
|
||||
WIN32_AVX_KEY = "Win32-AVX"
|
||||
WIN64_AVX_KEY = "Win64-AVX"
|
||||
|
||||
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_KEY: 'linux',
|
||||
MACOSX_X64_KEY: 'macosx',
|
||||
MACOSX_ARM64_KEY: 'macosx',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
WIN64_SSE2_KEY: 'windows',
|
||||
WIN32_AVX_KEY: 'windows',
|
||||
WIN64_AVX_KEY: 'windows'
|
||||
}
|
||||
|
||||
envs = {
|
||||
LINUX_KEY: 'linux && x86_64', # Linux only has 64bit builds
|
||||
MACOSX_X64_KEY: 'macosx && x86_64',
|
||||
MACOSX_ARM64_KEY: 'macosx && arm64',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
WIN64_SSE2_KEY: 'windows && x86_64',
|
||||
WIN32_AVX_KEY: 'windows && avx',
|
||||
WIN64_AVX_KEY: 'windows && avx && x86_64'
|
||||
}
|
||||
|
||||
subdirs = {
|
||||
WIN32_SSE2_KEY: 'x86',
|
||||
WIN64_SSE2_KEY: 'x64',
|
||||
WIN32_AVX_KEY: 'x86_avx',
|
||||
WIN64_AVX_KEY: '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_KEY 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.startswith('Mac') 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 = {
|
||||
"arm64": "arm64" in fn,
|
||||
"x64": "x64" in fn,
|
||||
"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
|
||||
@@ -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]
|
||||
@@ -1,76 +0,0 @@
|
||||
|
||||
<%def name="build(file)">[url=${file.url}]${file.filename}[/url]</%def>
|
||||
|
||||
[b]Change log:[/b] (chronologically ordered)
|
||||
PLACEHOLDER
|
||||
|
||||
[b]Deprecations:[/b]
|
||||
PLACEHOLDER
|
||||
|
||||
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. Any features listed under Deprecations 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=99015.0]23.2.1 Release Thread[/url][/size]
|
||||
|
||||
Launchers, if you don't have one already:
|
||||
[b]All platforms: [/b] For every day use, we recommend [url=https://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/url], an integrated solution for downloading and launching mods.
|
||||
|
||||
[hidden=Alternative Launchers]
|
||||
Cross-platform: [url=https://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (legacy project for a unified launcher)
|
||||
[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/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=https://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
|
||||
OS X: Soulstorm's [url=https://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
|
||||
Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=https://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
|
||||
|
||||
[img]https://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=https://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://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/url] and it will download the best build specifically for your PC!
|
||||
[/hidden]
|
||||
|
||||
[img]https://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=https://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]https://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]macOS[/size][/color]
|
||||
[size=8pt]macOS 10.9+[/size]
|
||||
[b]Intel (64-bit):[/b] ${build(groups["Mac"].subFiles["x86_64"])}
|
||||
[b]Apple Silicon:[/b] ${build(groups["Mac"].subFiles["arm64"])}
|
||||
|
||||
These builds are not signed and so by default will fail to launch. To run them simply right-click on the app, click open, then click open again on the security confirmation dialog. You should only have to do this once for each app.
|
||||
If running the game through Knossos or Knossos.NET this step should not be necessary.
|
||||
|
||||
[size=8pt][color=red][b]NOTE:[/b][/color] macOS builds currently have limited support and may exhibit issues not present on other platforms.[/size]
|
||||
|
||||
|
||||
[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=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=https://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=https://github.com/scp-fs2open/fs2open.github.com/projects/8]bugs ranked by priority[/url][/li]
|
||||
[/list]
|
||||
@@ -1,3 +0,0 @@
|
||||
Mako==1.2.2
|
||||
requests==2.32.0
|
||||
semantic-version==2.8.5
|
||||
@@ -1,46 +0,0 @@
|
||||
# miscellaneous utilities
|
||||
|
||||
import os
|
||||
import time
|
||||
from functools import wraps
|
||||
|
||||
from requests import RequestException
|
||||
|
||||
GLOBAL_TIMEOUT = 30
|
||||
|
||||
def retry_multi(max_retries):
|
||||
"""!
|
||||
@brief Decorator - Retry a function `max_retries` times.
|
||||
|
||||
@param [in] `max_retries` Maximum number of times to retry the decorated function before giving up
|
||||
|
||||
@details Intended for use with functions from the `request` module, only catches `RequestException`'s
|
||||
@note 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):
|
||||
"""
|
||||
@brief Expands the shell variable for the repo string from `config`
|
||||
"""
|
||||
|
||||
config["git"]["repo"] = os.path.expandvars(config["git"]["repo"])
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$NIGHTLY_BUILD" = true ]; then
|
||||
echo "Generating bintray config..."
|
||||
sed -e "s/\$VERSION_NAME/$VERSION_NAME/" ci/bintray.template.json > ci/bintray.json
|
||||
fi
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
sudo add-apt-repository -y "ppa:msulikowski/valgrind" # For fixing a bug with valgrind 3.11 which does not recognize the rdrand instruction
|
||||
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
|
||||
sudo add-apt-repository -y 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
|
||||
|
||||
sudo apt-get -yq update
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
fi
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
mkdir -p /tmp/builds
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
# Package the source code in release builds
|
||||
PARENT_DIR="$(basename "$PWD")"
|
||||
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
|
||||
export CXXFLAGS
|
||||
export CFLAGS
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
mkdir -p $config
|
||||
cd $config
|
||||
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release/$config" \
|
||||
-DFSO_BUILD_APPIMAGE=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_QTFRED=OFF ../..
|
||||
cd ..
|
||||
done
|
||||
else
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
|
||||
else
|
||||
cmake -G "Xcode" $CMAKE_OPTIONS ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -G "$CMAKE_GENERATOR" ..
|
||||
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 "$CMAKE_GENERATOR" -T "$CMAKE_TOOLSET" ..
|
||||
fi
|
||||
fi
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
RELEASE_BUILD=false
|
||||
NIGHTLY_BUILD=false
|
||||
TEST_BUILD=false
|
||||
|
||||
BUILD_DEPLOYMENT=false
|
||||
BUILD_CONFIGS="Release FastDebug"
|
||||
VERSION_NAME=""
|
||||
PACKAGE_NAME=""
|
||||
|
||||
RELEASE_PATTERN="^release_(.*)$"
|
||||
NIGHTLY_PATTERN="^nightly_(.*)$"
|
||||
TEST_BUILD_PATTERN="^test\/(.*)$"
|
||||
|
||||
# These are for testing
|
||||
NIGHTLY_TEST=false
|
||||
RELEASE_TEST=false
|
||||
TEST_BUILD_TEST=false
|
||||
|
||||
if [ "$RELEASE_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
|
||||
echo "This is a release tag!";
|
||||
RELEASE_BUILD=true;
|
||||
PACKAGE_NAME="fs2_open_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
|
||||
echo "This is a nightly tag!";
|
||||
NIGHTLY_BUILD=true;
|
||||
VERSION_NAME="${BASH_REMATCH[1]}";
|
||||
PACKAGE_NAME="nightly_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
if [ "$TEST_BUILD_TEST" = true ] || [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" =~ $TEST_BUILD_PATTERN ]]; then
|
||||
echo "This is a test build branch!";
|
||||
TEST_BUILD=true;
|
||||
if [ "$TEST_BUILD_TEST" = true ]; then
|
||||
VERSION_NAME="test";
|
||||
PACKAGE_NAME="test_test";
|
||||
else
|
||||
VERSION_NAME="${BASH_REMATCH[1]}";
|
||||
PACKAGE_NAME="test_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
|
||||
# Override the revision string so that the builds are named correctly
|
||||
echo "set(FSO_VERSION_REVISION_STR $VERSION_NAME)" > "$TRAVIS_BUILD_DIR/version_override.cmake"
|
||||
fi
|
||||
|
||||
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD" = true ]); then
|
||||
BUILD_DEPLOYMENT=true;
|
||||
fi
|
||||
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc-5.*$ ]])); then
|
||||
echo "Skipping non-release compiler";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if ([[ "$CONFIGURATION" == "Debug" ]]); then
|
||||
echo "Skipping non-release configuration";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
echo "Skipping non-release platform"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
export RELEASE_BUILD
|
||||
export NIGHTLY_BUILD
|
||||
export TEST_BUILD
|
||||
export BUILD_DEPLOYMENT
|
||||
export BUILD_CONFIGS
|
||||
export VERSION_NAME
|
||||
export PACKAGE_NAME
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
if [[ ! "$(curl -V)" == *"sftp"* ]]; then
|
||||
# Before
|
||||
echo "Before:"
|
||||
curl -V
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
|
||||
if [ -f ~/curl_cache/curl*.deb ]; then
|
||||
cd ~/curl_cache
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
else
|
||||
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
|
||||
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
|
||||
apt-get source curl
|
||||
sudo apt-get build-dep curl
|
||||
|
||||
cd curl-*
|
||||
export DEB_BUILD_OPTIONS="nocheck"
|
||||
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
|
||||
|
||||
cd ..
|
||||
dpkg -l | grep curl
|
||||
ls -al
|
||||
|
||||
if [ ! -d ~/curl_cache ]; then
|
||||
mkdir ~/curl_cache
|
||||
fi
|
||||
|
||||
cp libcurl3*.deb curl*.deb ~/curl_cache
|
||||
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew install libssh2
|
||||
|
||||
if [ -d ~/curl_cache/curl ]; then
|
||||
cd ~/curl_cache/curl
|
||||
sudo make install
|
||||
else
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
|
||||
curl -LO "https://curl.haxx.se/download/curl-7.64.0.tar.bz2"
|
||||
tar -xjf curl-7.64.0.tar.bz2
|
||||
|
||||
cd curl-7.64.0
|
||||
./configure --disable-debug --disable-dependency-tracking --disable-silent-rules --with-libssh2 --with-darwinssl --without-ca-bundle --without-ca-path
|
||||
make -j"$(sysctl hw.logicalcpu | cut -d " " -f 2)"
|
||||
|
||||
if [ ! -d ~/curl_cache ]; then
|
||||
mkdir ~/curl_cache
|
||||
fi
|
||||
|
||||
cp -a . ~/curl_cache/curl
|
||||
sudo make install
|
||||
fi
|
||||
export PATH=/usr/local/bin:$PATH
|
||||
fi
|
||||
|
||||
# After
|
||||
echo "After:"
|
||||
curl -V
|
||||
fi
|
||||
|
||||
cd /tmp/builds
|
||||
|
||||
for file in *; do
|
||||
if [ "$TEST_BUILD" = true ]; then
|
||||
# Upload to datacorder
|
||||
curl -k "sftp://porphyrion.feralhosting.com/www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
else
|
||||
# Upload to indiegames
|
||||
curl -k "sftp://scp.indiegames.us/~/public_html/builds/nightly/$VERSION_NAME/" --user "$INDIEGAMES_USER:$INDIEGAMES_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
|
||||
# Upload to datacorder
|
||||
curl -k "sftp://porphyrion.feralhosting.com/~/www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
fi
|
||||
done
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
FILENAME=
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
if [ ! -d "$HOME/cmake-3.8/bin" ]; then
|
||||
# If the cache does not currently contain CMake then download and install it
|
||||
mkdir -p $HOME/cmake-3.8/
|
||||
|
||||
wget -O /tmp/cmake.tar.gz --no-check-certificate https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz
|
||||
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake-3.8/ --strip-components=1
|
||||
fi
|
||||
export PATH=$HOME/cmake-3.8/bin:$PATH
|
||||
|
||||
cd $HOME
|
||||
|
||||
if [ "${BUILD_DEPLOYMENT}" = true ]; then
|
||||
wget -O appimagetool -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./appimagetool
|
||||
|
||||
wget -O linuxdeployqt -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./linuxdeployqt
|
||||
fi
|
||||
|
||||
sudo apt-get -yq install valgrind
|
||||
|
||||
if [[ "$CC" = "clang-9" ]]; then
|
||||
sudo apt-get -yq install clang-9 clang-tidy-9
|
||||
fi
|
||||
|
||||
if [[ "$CC" = "clang-4.0" ]]; then
|
||||
# Fix a header bug present in ubuntu...
|
||||
sudo ln -s /usr/include/libcxxabi/__cxxabi_config.h /usr/include/c++/v1/__cxxabi_config.h
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
gem install xcpretty
|
||||
|
||||
brew update
|
||||
brew outdated cmake || brew upgrade cmake
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
choco install mingw ninja
|
||||
fi
|
||||
|
||||
cmake --version
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
mkdir -p /tmp/builds
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
cd build
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cd "$config"
|
||||
|
||||
# Compile all targets
|
||||
ninja all
|
||||
|
||||
# Install Freespace2 targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -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 /tmp/release/$config/fso/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
|
||||
$HOME/appimagetool -n /tmp/release/$config/fso "/tmp/release/$config/fso/$FILENAME"
|
||||
|
||||
: <<'END'
|
||||
# Install qtFRED targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=qtFRED -P cmake_install.cmake
|
||||
|
||||
PREV="$(pwd)"
|
||||
cd /tmp/release/$config/qtfred
|
||||
|
||||
unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH
|
||||
$HOME/linuxdeployqt usr/qtfred.desktop -bundle-non-qt-libs
|
||||
# Move our AppRun script to the right location
|
||||
mv usr/AppRun AppRun
|
||||
|
||||
echo "Embed newer libstdc++ for distros that don't come with it (ubuntu 14.04)";
|
||||
mkdir -p usr/optional/; mkdir -p usr/optional/libstdc++/;
|
||||
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./usr/optional/libstdc++/;
|
||||
|
||||
$HOME/appimagetool -n . "$(find /tmp/release/$config/qtfred/usr/bin -name 'qtfred_*' -type f -printf "%f\n").AppImage"
|
||||
|
||||
cd "$PREV"
|
||||
END
|
||||
|
||||
cd ..
|
||||
done
|
||||
|
||||
cp `find /tmp/release -name '*.AppImage' -print` /tmp/release
|
||||
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-Linux.tar.gz *.AppImage)
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cd build
|
||||
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cmake --build . --config "$config" --target install | tee build.log \
|
||||
| xcpretty
|
||||
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://transfer.sh/build.log.tar.gz"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
done
|
||||
|
||||
ls -al /tmp/release
|
||||
|
||||
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-MacOSX.tar.gz *)
|
||||
fi
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -e
|
||||
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
ninja -k 20 all
|
||||
|
||||
if [ "$CONFIGURATION" = "Debug" ]; then
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
else
|
||||
./bin/unittests --gtest_shuffle
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
|
||||
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"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake --build . --config "$CONFIGURATION"
|
||||
else
|
||||
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
|
||||
fi
|
||||
fi
|
||||
@@ -1,16 +0,0 @@
|
||||
buildType:
|
||||
default: release
|
||||
description: R
|
||||
choices:
|
||||
release:
|
||||
short: Release
|
||||
long: Release builds
|
||||
buildType: Release
|
||||
fastDebug:
|
||||
short: FastDebug
|
||||
long: Debug with optimizations
|
||||
buildType: FastDebug
|
||||
debug:
|
||||
short: Debug
|
||||
long: Debug without optimizations
|
||||
buildType: Debug
|
||||
@@ -1,3 +1,15 @@
|
||||
|
||||
include(WriteCompilerDetectionHeader)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
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
|
||||
)
|
||||
+1
-1
@@ -8,7 +8,7 @@ if(DOXYGEN_FOUND)
|
||||
FILE(TO_NATIVE_PATH ${OUTPUT_DIR} OUTPUT_DIR)
|
||||
SET(OUTPUT_DIR \"${OUTPUT_DIR}\")
|
||||
|
||||
SET(INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/code" "${CMAKE_CURRENT_SOURCE_DIR}/freespace2" "${CMAKE_CURRENT_SOURCE_DIR}/fred2" "${CMAKE_CURRENT_SOURCE_DIR}/wxfred2" "${CMAKE_CURRENT_SOURCE_DIR}/qtfred")
|
||||
SET(INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/code" "${CMAKE_CURRENT_SOURCE_DIR}/freespace2" "${CMAKE_CURRENT_SOURCE_DIR}/fred2" "${CMAKE_CURRENT_SOURCE_DIR}/wxfred2")
|
||||
|
||||
SET(INPUT_DIRS)
|
||||
FOREACH(DIR IN LISTS INPUTS)
|
||||
|
||||
@@ -9,8 +9,6 @@ if (WIN32)
|
||||
if (NOT HAVE_SAPI_H)
|
||||
message(SEND_ERROR "sapi.h could not be found on your platform. Please disable speech support.")
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
# it should just work
|
||||
else()
|
||||
message(SEND_ERROR "Text to Speech is not supported on this platform!")
|
||||
endif()
|
||||
|
||||
@@ -7,15 +7,3 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
else()
|
||||
set(IS_64BIT FALSE)
|
||||
endif()
|
||||
|
||||
set(IS_ARM64 FALSE)
|
||||
|
||||
if (NOT "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # needed to cover Visual Studio generator
|
||||
if(CMAKE_GENERATOR_PLATFORM MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
endif()
|
||||
endif()
|
||||
@@ -22,14 +22,6 @@ SET(LIBRAY_DESTINATION "../Frameworks")
|
||||
|
||||
set(PLATFORM_MAC TRUE CACHE INTERNAL "" FORCE)
|
||||
|
||||
# Maybe override arm64 setting if we are compiling for different architecture
|
||||
# If not specified, or if it's a universal build, then this should do nothing
|
||||
if(CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
|
||||
set(IS_ARM64 TRUE)
|
||||
elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
|
||||
set(IS_ARM64 FALSE)
|
||||
endif()
|
||||
|
||||
# Generate and don't strip debug symbols
|
||||
# These settings don't seem to generate debug symbols for code and Freespace2
|
||||
# so those settings are set manually in code and Freespace2's CMakeLists.txt files
|
||||
|
||||
@@ -10,7 +10,6 @@ SET(WIN32_LIBS
|
||||
winmm
|
||||
ws2_32
|
||||
psapi
|
||||
shlwapi
|
||||
)
|
||||
|
||||
IF (MINGW)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#cmakedefine SCP_HAVE_MAX_ALIGN_T
|
||||
#cmakedefine SCP_HAVE_STD_MAX_ALIGN_T
|
||||
|
||||
#cmakedefine01 HAVE_STD_IS_TRIVIALLY_COPYABLE
|
||||
|
||||
#cmakedefine01 IS_64BIT
|
||||
#cmakedefine01 IS_ARM64
|
||||
|
||||
#cmakedefine01 SCP_HAVE_STRCASECMP
|
||||
#cmakedefine01 SCP_HAVE_STRNCASECMP
|
||||
|
||||
@@ -4,7 +4,7 @@ MESSAGE(STATUS "Doing configuration specific to Apple Clang...")
|
||||
# TODO: Actually add Mac specific flags here...
|
||||
|
||||
# Suppress specific warning
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fsigned-char -Wno-unknown-pragmas")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -funroll-loops -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
# Omit "conversion from string literal to 'char *' is deprecated" warnings.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings")
|
||||
@@ -13,6 +13,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-Wno-unused-variable")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Wextra -Wshadow -Wno-unused-parameter")
|
||||
+10
-35
@@ -33,7 +33,7 @@ set(COMPILER_FLAGS "")
|
||||
_enable_extra_compiler_warnings_flags()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
# Omit "argument unused during compilation" when clang is used with ccache.
|
||||
if(${CMAKE_CXX_COMPILER} MATCHES "ccache")
|
||||
@@ -83,48 +83,23 @@ if(SUPPORTS_SHIFT_NEGATIVE_VALUE)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-shift-negative-value")
|
||||
endif()
|
||||
|
||||
# Check if there is a user-set optimisation flag
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
# If no user-set opt flag, set -O2 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O2")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O2")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
||||
endif()
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
set(CXX_FLAGS_RELEASE "${CXX_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
|
||||
set(C_FLAGS_RELEASE "${C_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -Wshadow")
|
||||
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -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}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${CXX_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${C_FLAGS_RELEASE})
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
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_CXX_FLAGS_DEBUG ${CXX_FLAGS_DEBUG})
|
||||
set(CMAKE_C_FLAGS_DEBUG ${C_FLAGS_DEBUG})
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "")
|
||||
|
||||
if(DEFINED ENV{LDFLAGS})
|
||||
set(CMAKE_EXE_LINKER_FLAGS $ENV{LDFLAGS})
|
||||
endif()
|
||||
|
||||
if (CLANG_USE_LIBCXX)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
|
||||
endif()
|
||||
@@ -141,7 +116,7 @@ if (FSO_FATAL_WARNINGS)
|
||||
target_compile_options(compiler INTERFACE "-Werror")
|
||||
endif()
|
||||
|
||||
# Always define this to make sure that the fixed-width format macros are available
|
||||
# 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)
|
||||
|
||||
@@ -27,11 +27,6 @@ endif()
|
||||
set(COMPILER_FLAGS "")
|
||||
set(LINKER_FLAGS "")
|
||||
|
||||
# Don't ignore user-set LDFLAGS
|
||||
if(DEFINED ENV{LDFLAGS})
|
||||
set(LINKER_FLAGS $ENV{LDFLAGS})
|
||||
endif()
|
||||
|
||||
if (GCC_USE_GOLD)
|
||||
OPTION(GCC_INCREMENTAL_LINKING "Use incremental linking" OFF)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fuse-ld=gold")
|
||||
@@ -45,7 +40,7 @@ endif()
|
||||
_enable_extra_compiler_warnings_flags()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
|
||||
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
|
||||
@@ -113,41 +108,19 @@ if(SUPPORTS_STRINGOP_TRUNCATION)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-overflow")
|
||||
endif()
|
||||
|
||||
# Check if there is a user-set optimisation flag
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
|
||||
# If no user-set opt flag, set -O2 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O2")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O2")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
||||
endif()
|
||||
|
||||
set(CXX_FLAGS_RELEASE "${CXX_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
set(C_FLAGS_RELEASE "${C_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
|
||||
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -Wshadow")
|
||||
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -g -Wshadow")
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
# Always use the base flags and add our compiler flags at the back
|
||||
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${CXX_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${C_FLAGS_RELEASE})
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG ${CXX_FLAGS_DEBUG})
|
||||
set(CMAKE_C_FLAGS_DEBUG ${C_FLAGS_DEBUG})
|
||||
set(CMAKE_CXX_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
|
||||
set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${LINKER_FLAGS}")
|
||||
|
||||
@@ -187,7 +160,7 @@ if (FSO_FATAL_WARNINGS)
|
||||
target_compile_options(compiler INTERFACE "-Werror")
|
||||
endif()
|
||||
|
||||
# Always define this to make sure that the fixed-width format macros are available
|
||||
# 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)
|
||||
|
||||
@@ -46,13 +46,9 @@ target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
|
||||
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
|
||||
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /DYNAMICBASE:NO /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "")
|
||||
|
||||
if(NOT IS_ARM64)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DYNAMICBASE:NO")
|
||||
endif()
|
||||
|
||||
# Release
|
||||
set(CMAKE_C_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
|
||||
|
||||
+17
-30
@@ -67,43 +67,30 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
|
||||
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
|
||||
|
||||
MACRO(COPY_FILE_TO_TARGET _target _file)
|
||||
if (IS_DIRECTORY "${_file}")
|
||||
get_filename_component(_dirName "${_file}" NAME)
|
||||
if (PLATFORM_MAC AND ("${_file}" MATCHES ".framework$"))
|
||||
# This is stupid, but it preserves symlinks, unlike copy_directory_if_different.
|
||||
# Otherwise we end up creating duplicate files in the copied framework.
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND rsync -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/${_dirName}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
if(UNIX)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND cp -a "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
)
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
)
|
||||
endif()
|
||||
endmacro(COPY_FILE_TO_TARGET)
|
||||
|
||||
MACRO(COPY_FILES_TO_TARGET _target)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND mkdir -p "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
|
||||
)
|
||||
endif()
|
||||
|
||||
FOREACH(file IN LISTS TARGET_COPY_FILES)
|
||||
COPY_FILE_TO_TARGET("${_target}" "${file}")
|
||||
ENDFOREACH(file)
|
||||
|
||||
+2
-4
@@ -6,7 +6,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 24)
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 20)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 1)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
@@ -35,9 +35,7 @@ ELSE()
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_VERSION_MAJOR}_${FSO_VERSION_MINOR}_${FSO_VERSION_BUILD}_${FSO_VERSION_REVISION_STR}")
|
||||
ENDIF()
|
||||
|
||||
IF(IS_ARM64)
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_arm64")
|
||||
ELSEIF(IS_64BIT)
|
||||
IF(IS_64BIT)
|
||||
# This is a 64-bit builds
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_x64")
|
||||
ENDIF()
|
||||
|
||||
+5
-42
@@ -20,20 +20,12 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
|
||||
|
||||
if (FSO_BUILD_WITH_OPENGL)
|
||||
target_link_libraries(code PUBLIC OpenGL)
|
||||
if(FSO_BUILD_WITH_OPENGL_DEBUG)
|
||||
add_definitions(-DFS_OPENGL_DEBUG)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FSO_BUILD_WITH_OPENXR_DEBUG)
|
||||
add_definitions(-DFS_OPENXR_DEBUG)
|
||||
endif()
|
||||
|
||||
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)
|
||||
|
||||
@@ -54,6 +46,10 @@ 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)
|
||||
@@ -69,27 +65,6 @@ TARGET_LINK_LIBRARIES(code PUBLIC jansson)
|
||||
|
||||
target_link_libraries(code PUBLIC variant)
|
||||
|
||||
target_link_libraries(code PUBLIC any)
|
||||
|
||||
target_link_libraries(code PUBLIC optional)
|
||||
|
||||
target_link_libraries(code PUBLIC anl)
|
||||
|
||||
target_link_libraries(code PUBLIC hidapi::hidapi)
|
||||
|
||||
target_link_libraries(code PUBLIC imgui)
|
||||
|
||||
IF(NOT APPLE)
|
||||
target_link_libraries(code PUBLIC OpenXR::openxr_loader)
|
||||
target_include_directories(code PUBLIC OpenXR::Headers)
|
||||
ENDIF()
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
# On Linux, we need to access X11 window data.
|
||||
# On Windows, SDL already provides everything, so no need to do anything
|
||||
find_package(X11)
|
||||
target_link_libraries(code PUBLIC ${X11_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
# Headers for standalone "gui" on UNIX
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
|
||||
@@ -112,16 +87,7 @@ if (FSO_BUILD_WITH_OPENGL)
|
||||
target_compile_definitions(code PUBLIC WITH_OPENGL)
|
||||
endif()
|
||||
if (FSO_BUILD_WITH_VULKAN)
|
||||
find_package(Vulkan REQUIRED)
|
||||
if (Vulkan_FOUND)
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN)
|
||||
target_link_libraries(code PRIVATE Vulkan::Vulkan)
|
||||
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1 VK_NO_PROTOTYPES)
|
||||
else()
|
||||
message(WARNING "FSO_BUILD_WITH_VULKAN was set, but the package was unable to be found. Forcing OFF.")
|
||||
set(FSO_BUILD_WITH_VULKAN OFF CACHE BOOL "Enable compilation of the Vulkan renderer" FORCE)
|
||||
endif()
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN)
|
||||
endif()
|
||||
|
||||
include(shaders.cmake)
|
||||
@@ -137,6 +103,3 @@ set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYM
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT[variant=Debug] "NO")
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN[variant=Debug] "NO")
|
||||
|
||||
# Prevent GCC warnings in third-party BitOp... see GitHub #4366
|
||||
suppress_file_warnings(scripting/lua/bitop/bit.c)
|
||||
@@ -7,7 +7,6 @@ ActionDefinition::ActionDefinition(SCP_string name, SCP_vector<ActionParameter>
|
||||
: m_name(std::move(name)), m_parameters(std::move(parameters))
|
||||
{
|
||||
}
|
||||
ActionDefinition::~ActionDefinition() = default;
|
||||
|
||||
const SCP_string& ActionDefinition::getName() const
|
||||
{
|
||||
|
||||
@@ -15,7 +15,6 @@ struct ActionParameter {
|
||||
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;
|
||||
|
||||
@@ -47,7 +47,24 @@ void parseActionParameters(const SCP_vector<ActionParameter>& params,
|
||||
|
||||
const ActionDefinitionManager& ActionDefinitionManager::instance()
|
||||
{
|
||||
static const ActionDefinitionManager manager;
|
||||
static const ActionDefinitionManager manager = []() {
|
||||
ActionDefinitionManager newManager;
|
||||
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::MoveToSubmodel>("Move To Subobject")));
|
||||
newManager.addDefinition(std::unique_ptr<ActionDefinition>(
|
||||
new BuiltinActionDefinition<types::ParticleEffectAction>("Start Particle Effect")));
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::PlaySoundAction>("Play 3D Sound")));
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetDirectionAction>("Set Direction")));
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetPositionAction>("Set Position")));
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::WaitAction>("Wait")));
|
||||
|
||||
return newManager;
|
||||
}();
|
||||
return manager;
|
||||
}
|
||||
void ActionDefinitionManager::addDefinition(std::unique_ptr<ActionDefinition> def)
|
||||
@@ -127,19 +144,5 @@ std::unique_ptr<Action> ActionDefinitionManager::parseAction(const flagset<Progr
|
||||
|
||||
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
|
||||
@@ -19,7 +19,7 @@ class ActionDefinitionManager {
|
||||
static const ActionDefinitionManager& instance();
|
||||
|
||||
private:
|
||||
ActionDefinitionManager();
|
||||
ActionDefinitionManager() = default;
|
||||
|
||||
void addDefinition(std::unique_ptr<ActionDefinition> def);
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "BuiltinActionDefinition.h"
|
||||
@@ -15,7 +15,6 @@ class BuiltinActionDefinition : public ActionDefinition {
|
||||
: ActionDefinition(std::move(name), {{"parameter", expression::ValueTypeTraits<ActionValueType>::type}})
|
||||
{
|
||||
}
|
||||
~BuiltinActionDefinition() override = default;
|
||||
|
||||
flagset<ProgramContextFlags> getRequiredContext() const override
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ ProgramInstance::ProgramInstance(const actions::Program* program) : _program(pro
|
||||
|
||||
ProgramState ProgramInstance::step()
|
||||
{
|
||||
if (!_locals.host.isValid()) {
|
||||
if (!_locals.host.IsValid()) {
|
||||
return ProgramState::Done;
|
||||
}
|
||||
|
||||
@@ -123,9 +123,9 @@ Program& Program::operator=(const Program& other)
|
||||
Program& Program::operator=(Program&&) noexcept = default;
|
||||
Program::Program(Program&&) noexcept = default;
|
||||
|
||||
bool ProgramSet::isEmpty() const
|
||||
const SCP_vector<actions::Program>& ProgramSet::getPrograms() const
|
||||
{
|
||||
return _programs.empty();
|
||||
return _programs;
|
||||
}
|
||||
|
||||
ProgramSet::ProgramSet() = default;
|
||||
|
||||
@@ -84,7 +84,7 @@ class ProgramSet {
|
||||
ProgramSet();
|
||||
explicit ProgramSet(const flagset<ProgramContextFlags>& context_flags);
|
||||
|
||||
bool isEmpty() const;
|
||||
const SCP_vector<actions::Program>& getPrograms() const;
|
||||
|
||||
/**
|
||||
* @brief Starts the execution of all programs within this set with the specified parameters
|
||||
|
||||
@@ -18,7 +18,7 @@ struct ProgramLocals {
|
||||
matrix localOrient = vmd_identity_matrix;
|
||||
int hostSubobject = -1;
|
||||
|
||||
TIMESTAMP waitTimestamp = TIMESTAMP::invalid();
|
||||
int waitTimestamp = 0;
|
||||
|
||||
expression::ProgramVariables variables;
|
||||
};
|
||||
|
||||
@@ -14,12 +14,6 @@ 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;
|
||||
@@ -42,13 +36,6 @@ class ActionExpression {
|
||||
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:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "actions/expression/nodes/AbstractExpression.h"
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include "ParseContext.h"
|
||||
|
||||
#include "actions/expression/nodes/AbstractExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
|
||||
@@ -22,7 +22,19 @@ Value value_minus(const SCP_vector<Value>& parameters)
|
||||
|
||||
const FunctionManager& FunctionManager::instance()
|
||||
{
|
||||
static const FunctionManager manager;
|
||||
static const FunctionManager manager = []() {
|
||||
FunctionManager newManager;
|
||||
|
||||
newManager.addOperator("+", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_plus<int>);
|
||||
newManager.addOperator("+", {ValueType::Float, ValueType::Float}, ValueType::Float, value_plus<float>);
|
||||
newManager.addOperator("+", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_plus<vec3d>);
|
||||
|
||||
newManager.addOperator("-", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_minus<int>);
|
||||
newManager.addOperator("-", {ValueType::Float, ValueType::Float}, ValueType::Float, value_minus<float>);
|
||||
newManager.addOperator("-", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_minus<vec3d>);
|
||||
|
||||
return newManager;
|
||||
}();
|
||||
return manager;
|
||||
}
|
||||
void FunctionManager::addOperator(const SCP_string& name,
|
||||
@@ -75,16 +87,7 @@ const FunctionDefinition* FunctionManager::findOperator(const SCP_string& name,
|
||||
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>);
|
||||
}
|
||||
FunctionManager::FunctionManager() = default;
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parser.h>
|
||||
#include <Token.h>
|
||||
|
||||
#include "actions/expression/ParseContext.h"
|
||||
#include "actions/expression/Value.h"
|
||||
|
||||
#include <Parser.h>
|
||||
#include <Token.h>
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
@@ -26,7 +26,7 @@ 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());
|
||||
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);
|
||||
|
||||
@@ -37,19 +37,19 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto instance = object_get_model_instance(locals.host.objp());
|
||||
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);
|
||||
|
||||
model_instance_local_to_global_point_orient(&local_pos,
|
||||
find_submodel_instance_point_orient(&local_pos,
|
||||
&local_orient,
|
||||
&locals.localPosition,
|
||||
&locals.localOrient,
|
||||
pm,
|
||||
pmi,
|
||||
locals.hostSubobject);
|
||||
locals.hostSubobject,
|
||||
&locals.localPosition,
|
||||
&locals.localOrient);
|
||||
} else {
|
||||
local_pos = locals.localPosition;
|
||||
local_orient = locals.localOrient;
|
||||
@@ -59,7 +59,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
|
||||
auto direction = locals.variables.getValue({"locals", "direction"}).getVector();
|
||||
|
||||
source.moveToObject(locals.host.objp(), &local_pos);
|
||||
source.moveToObject(locals.host.objp, &local_pos);
|
||||
source.setOrientationFromNormalizedVec(&direction, true);
|
||||
|
||||
source.finish();
|
||||
|
||||
@@ -26,19 +26,19 @@ 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());
|
||||
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);
|
||||
|
||||
model_instance_local_to_global_point_orient(&local_pos,
|
||||
find_submodel_instance_point_orient(&local_pos,
|
||||
&local_orient,
|
||||
&locals.localPosition,
|
||||
&locals.localOrient,
|
||||
pm,
|
||||
pmi,
|
||||
locals.hostSubobject);
|
||||
locals.hostSubobject,
|
||||
&locals.localPosition,
|
||||
&locals.localOrient);
|
||||
} else {
|
||||
local_pos = locals.localPosition;
|
||||
local_orient = locals.localOrient;
|
||||
@@ -47,8 +47,8 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
|
||||
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;
|
||||
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());
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ WaitAction::~WaitAction() = default;
|
||||
|
||||
ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
|
||||
{
|
||||
if (!locals.waitTimestamp.isValid()) {
|
||||
if (!timestamp_valid(locals.waitTimestamp)) {
|
||||
auto waitTime = _waitTimeExpression.execute(locals.variables);
|
||||
|
||||
// Catch errors in the expression
|
||||
@@ -28,7 +28,7 @@ ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
|
||||
waitTime = 0.001f;
|
||||
}
|
||||
|
||||
locals.waitTimestamp = _timestamp(fl2i(waitTime * MILLISECONDS_PER_SECOND));
|
||||
locals.waitTimestamp = timestamp(fl2i(waitTime * TIMESTAMP_FREQUENCY));
|
||||
}
|
||||
if (!timestamp_elapsed(locals.waitTimestamp)) {
|
||||
// Wait until the timestamp is elapsed
|
||||
@@ -36,7 +36,7 @@ ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
|
||||
}
|
||||
// Timestamp is elapsed. The timestamp is elapsed so that timestamp_valid above returns false for the next wait
|
||||
// action
|
||||
locals.waitTimestamp = TIMESTAMP::invalid();
|
||||
locals.waitTimestamp = 0;
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
std::unique_ptr<Action> WaitAction::clone() const
|
||||
|
||||
@@ -52,6 +52,34 @@ void ai_free_slot(int ai_index)
|
||||
Ai_info[ai_index].shipnum = -1;
|
||||
}
|
||||
|
||||
int get_wingnum(int objnum)
|
||||
{
|
||||
int shipnum, ai_index;
|
||||
|
||||
shipnum = Objects[objnum].instance;
|
||||
|
||||
ai_index = Ships[shipnum].ai_index;
|
||||
|
||||
return Ai_info[ai_index].wing;
|
||||
}
|
||||
|
||||
void set_wingnum(int objnum, int wingnum)
|
||||
{
|
||||
int shipnum, ai_index;
|
||||
|
||||
Assert(Objects[objnum].type == OBJ_SHIP);
|
||||
|
||||
shipnum = Objects[objnum].instance;
|
||||
|
||||
Assert((shipnum >= 0) && (shipnum < MAX_SHIPS));
|
||||
|
||||
ai_index = Ships[shipnum].ai_index;
|
||||
|
||||
Assert( (ai_index >= 0) && (ai_index < MAX_AI_INFO) );
|
||||
|
||||
Ai_info[ai_index].wing = wingnum;
|
||||
}
|
||||
|
||||
const char *ai_get_goal_target_name(const char *name, int *index)
|
||||
{
|
||||
Assertion(name != nullptr && index != nullptr, "Arguments cannot be null!");
|
||||
|
||||
+88
-56
@@ -12,13 +12,11 @@
|
||||
#ifndef _AI_H
|
||||
#define _AI_H
|
||||
|
||||
#include "ai/aigoals.h"
|
||||
#include "ai/ai_profiles.h"
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "object/waypoint.h"
|
||||
#include "parse/sexp.h"
|
||||
#include "physics/physics.h"
|
||||
#include "ship/ship_flags.h"
|
||||
|
||||
@@ -34,14 +32,8 @@ typedef struct ai_flag_name {
|
||||
char flag_name[TOKEN_LENGTH];
|
||||
} ai_flag_name;
|
||||
|
||||
typedef struct ai_flag_description {
|
||||
AI::AI_Flags flag;
|
||||
SCP_string flag_desc;
|
||||
} ai_flag_description;
|
||||
|
||||
#define MAX_AI_FLAG_NAMES 2
|
||||
extern ai_flag_name Ai_flag_names[];
|
||||
extern ai_flag_description Ai_flag_descriptions[];
|
||||
extern const int Num_ai_flag_names;
|
||||
|
||||
// dock_orient_and_approach() modes.
|
||||
#define DOA_APPROACH 1 // Approach the current point on the path (aip->path_cur)
|
||||
@@ -56,19 +48,66 @@ extern const int Num_ai_flag_names;
|
||||
#define AIDO_DOCK_NOW 2 // Immediately move into dock position. For ships that start mission docked.
|
||||
#define AIDO_UNDOCK 3 // Set goal of undocking with object.
|
||||
|
||||
// Submodes for seeking safety.
|
||||
#define AISS_1 41 // Pick a spot to fly to.
|
||||
#define AISS_2 42 // Flying to spot.
|
||||
#define AISS_3 43 // Gotten near spot, fly about there.
|
||||
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2
|
||||
|
||||
#define MAX_AI_GOALS 5
|
||||
|
||||
// types of ai goals -- tyese types will help us to determination on which goals should
|
||||
// have priority over others (i.e. when a player issues a goal to a wing, then a seperate
|
||||
// goal to a ship in that wing). We would probably use this type in conjunction with
|
||||
// goal priority to establish which goal to follow
|
||||
#define AIG_TYPE_EVENT_SHIP 1 // from mission event direct to ship
|
||||
#define AIG_TYPE_EVENT_WING 2 // from mission event direct to wing
|
||||
#define AIG_TYPE_PLAYER_SHIP 3 // from player direct to ship
|
||||
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
|
||||
#define AIG_TYPE_DYNAMIC 5 // created on the fly
|
||||
|
||||
// Flags to ai_turn_towards_vector().
|
||||
#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 AITTV_FORCE_DELTA_BANK (1<<4) // Lafiel - Always use the provided delta bank and override calculated values
|
||||
|
||||
#define KAMIKAZE_HULL_ON_DEATH -1000.0f // Hull strength ship gets set to if it crash-dies.
|
||||
|
||||
// individual AI modes aka AI behaviors
|
||||
// structure for AI goals
|
||||
typedef struct ai_goal {
|
||||
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
|
||||
int ai_mode; // one of the AIM_* modes for this goal
|
||||
int ai_submode; // maybe need a submode
|
||||
int type; // one of the AIG_TYPE_* values above
|
||||
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
|
||||
fix time; // time at which this goal was issued.
|
||||
int priority; // how important is this goal -- number 0 - 100
|
||||
|
||||
const char *target_name; // name of the thing that this goal acts upon
|
||||
int target_name_index; // index of goal_target_name in Goal_target_names[][]
|
||||
waypoint_list *wp_list; // waypoints that this ship might fly.
|
||||
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
|
||||
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)
|
||||
|
||||
// unions for docking stuff.
|
||||
// (AIGF_DOCKER_INDEX_VALID and AIGF_DOCKEE_INDEX_VALID tell us to use indexes; otherwise we use names)
|
||||
// these are the dockpoints used on the docker and dockee ships, not the ships themselves
|
||||
union {
|
||||
const char *name;
|
||||
int index;
|
||||
} docker;
|
||||
|
||||
union {
|
||||
const char *name;
|
||||
int index;
|
||||
} dockee;
|
||||
|
||||
} ai_goal;
|
||||
|
||||
#define AIM_CHASE 0
|
||||
#define AIM_EVADE 1
|
||||
#define AIM_GET_BEHIND 2 // This mode is not actually implemented.
|
||||
#define AIM_GET_BEHIND 2
|
||||
#define AIM_STAY_NEAR 3 // Stay near another ship.
|
||||
#define AIM_STILL 4 // Sit still. Don't move. Hold your breath. Don't blink.
|
||||
#define AIM_GUARD 5 // Guard an object
|
||||
@@ -87,15 +126,15 @@ extern const int Num_ai_flag_names;
|
||||
#define AIM_BAY_DEPART 18 // Departing to a fighter bay, following path to do so
|
||||
#define AIM_SENTRYGUN 19 // AI mode for sentry guns only (floating turrets)
|
||||
#define AIM_WARP_OUT 20 // Commence warp out sequence. Point in legal direction. Then call John's code.
|
||||
#define AIM_FLY_TO_SHIP 21 // Rendezvous with a ship. Like stay-near, but non-perpetual.
|
||||
#define AIM_LUA 22 // Generic Lua-based AI mode
|
||||
#define AIM_FLY_TO_SHIP 21 // [Kazan] Fly to a ship, doesn't matter if it's hostile or friendly -- for Autopilot usage
|
||||
|
||||
#define MAX_AI_BEHAVIORS 23 // Number of AIM_xxxx types
|
||||
#define MAX_AI_BEHAVIORS 22 // Number of AIM_xxxx types
|
||||
|
||||
#define MAX_WAYPOINTS_PER_LIST 20
|
||||
#define MAX_ENEMY_DISTANCE 2500.0f // Maximum distance from which a ship will pursue an enemy.
|
||||
|
||||
#define MAX_AI_GOALS 5
|
||||
#define AI_GOAL_NONE -1
|
||||
|
||||
#define AI_ACTIVE_GOAL_DYNAMIC 999
|
||||
|
||||
typedef struct ai_class {
|
||||
@@ -180,12 +219,6 @@ typedef struct ai_class {
|
||||
#define AIS_UNDOCK_3 33
|
||||
#define AIS_UNDOCK_4 34
|
||||
|
||||
// Submodes for seeking safety.
|
||||
#define AISS_1 41 // Pick a spot to fly to.
|
||||
#define AISS_2 42 // Flying to spot.
|
||||
#define AISS_3 43 // Gotten near spot, fly about there.
|
||||
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2. (Not implemented.)
|
||||
|
||||
// Submodes for Guard behavior
|
||||
#define AIS_GUARD_PATROL 101
|
||||
#define AIS_GUARD_ATTACK 102
|
||||
@@ -234,12 +267,13 @@ extern pnode *Ppfp; // Free pointer in path points.
|
||||
// Goober5000 (based on the "you can only remember 7 things in short-term memory" assumption)
|
||||
#define MAX_IGNORE_NEW_OBJECTS 7
|
||||
|
||||
#define AI_DYNAMIC_PATH_RECHECK_DELAY 1*1000
|
||||
|
||||
typedef struct ai_info {
|
||||
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
|
||||
int shipnum; // Ship using this slot, -1 means none.
|
||||
int type; //
|
||||
int wing; // Member of what wing? -1 means none.
|
||||
|
||||
int behavior; // AI behavior; vestigial field from early development of FS1
|
||||
int mode;
|
||||
int previous_mode;
|
||||
int mode_time; // timestamp at which current mode elapses.
|
||||
@@ -277,7 +311,7 @@ typedef struct ai_info {
|
||||
|
||||
// Probably become obsolete, to be replaced by path_start, path_cur, etc.
|
||||
waypoint_list *wp_list; // waypoint list being followed
|
||||
int wp_index; // waypoint index in list
|
||||
size_t wp_index; // waypoint index in list
|
||||
int wp_flags; // waypoint flags, see WPF_xxxx
|
||||
int waypoint_speed_cap; // -1 no cap, otherwise cap - changed to int by Goober5000
|
||||
|
||||
@@ -296,7 +330,7 @@ typedef struct ai_info {
|
||||
fix path_next_check_time; // Last time checked to see if would collide with model.
|
||||
int path_goal_dist; // minimum distance to first path point to consider path reached
|
||||
int path_subsystem_next_check; // timestamp to next check if subsystem is still visible
|
||||
vec3d path_depart_rvec; //Rotational orientation associated with the path
|
||||
vec3d path_depart_orient; //Rotational orientation associated with the path
|
||||
|
||||
int submode;
|
||||
int previous_submode; // previous submode, get it?
|
||||
@@ -307,12 +341,8 @@ typedef struct ai_info {
|
||||
fix submode_start_time; // time at which we entered the current submode
|
||||
int submode_parm0; // parameter specific to current submode
|
||||
int submode_parm1; // SUSHI: Another optional parameter
|
||||
float submode_float0; // Goober5000: a float parameter
|
||||
fix next_predict_pos_time; // Next time to predict position.
|
||||
|
||||
int next_dynamic_path_check_time; //ETP: Time of next path check in ai_new_maybe_reposition_attack_subsys
|
||||
vec3d last_dynamic_path_goal; //ETP: Remebers last target location in ai_new_maybe_reposition_attack_subsys
|
||||
|
||||
//SUSHI: like last_predicted_enemy_pos, but for aiming (which currently ignores predicted position)
|
||||
//Unlike the predicted position stuff, also takes into account velocity
|
||||
//Only used against small ships
|
||||
@@ -373,6 +403,12 @@ typedef struct ai_info {
|
||||
float ai_turret_max_aim_update_delay;
|
||||
flagset<AI::Profile_Flags> ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
|
||||
|
||||
|
||||
union {
|
||||
float lead_scale; // Amount to lead current opponent by.
|
||||
float stay_near_distance; // Distance to stay within for AIM_STAY_NEAR mode.
|
||||
};
|
||||
|
||||
ship_subsys* targeted_subsys; // Targeted subobject on current target. NULL if none;
|
||||
ship_subsys* last_subsys_target; // last known subsystem target
|
||||
int targeted_subsys_parent; // Parent objnum of subobject, not necessarily targeted
|
||||
@@ -455,16 +491,8 @@ typedef struct ai_info {
|
||||
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
|
||||
|
||||
ai_lua_parameters lua_ai_target;
|
||||
} ai_info;
|
||||
|
||||
int ai_maybe_autoscale(int absolute_index = -1);
|
||||
int ai_get_autoscale_index(int absolute_index = -1);
|
||||
|
||||
// Goober5000
|
||||
typedef struct {
|
||||
vec3d docker_point;
|
||||
@@ -489,6 +517,11 @@ typedef struct {
|
||||
|
||||
extern int Mission_all_attack; // !0 means all teams attack all teams.
|
||||
|
||||
extern void update_ai_info_for_hit(int hitter_obj, int hit_obj);
|
||||
extern void ai_frame_all(void);
|
||||
|
||||
extern int find_guard_obj(void);
|
||||
|
||||
extern ai_info Ai_info[];
|
||||
extern ai_info *Player_ai;
|
||||
|
||||
@@ -499,8 +532,7 @@ extern int Num_ai_classes;
|
||||
extern int Ai_firing_enabled;
|
||||
|
||||
extern const char *Skill_level_names(int skill_level, int translate = 1);
|
||||
|
||||
extern control_info AI_ci;
|
||||
extern int Ai_goal_signature;
|
||||
|
||||
// need access to following data in AiBig.cpp
|
||||
extern object *Pl_objp;
|
||||
@@ -522,22 +554,24 @@ void ai_object_init(object * obj, int ai_index);
|
||||
// Called once a frame
|
||||
void ai_process( object * obj, int ai_index, float frametime );
|
||||
|
||||
int get_wingnum(int objnum);
|
||||
|
||||
void set_wingnum(int objnum, int wingnum);
|
||||
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);
|
||||
extern void ai_dock_with_object(object *docker, int docker_index, object *dockee, int dockee_index, int dock_type);
|
||||
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
|
||||
extern void ai_do_default_behavior(object *obj);
|
||||
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags, int start_index);
|
||||
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 vec3d ai_get_acc_limit(vec3d* vel_limit, const object* objp);
|
||||
extern void ai_turn_towards_vector(const vec3d *dest, object *objp, const vec3d *slide_vec, const vec3d *rel_pos, float bank_override, int flags, const vec3d *rvec = nullptr, const vec3d* turnrate_mod = nullptr);
|
||||
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 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
|
||||
@@ -560,7 +594,7 @@ extern void ai_attack_wing(object *attacker, int wingnum);
|
||||
extern void ai_deathroll_start(object *ship_obj);
|
||||
extern int set_target_objnum(ai_info *aip, int objnum);
|
||||
extern void ai_form_on_wing(object *objp, object *goal_objp);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist, int additional_data);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist);
|
||||
extern ship_subsys *set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum);
|
||||
extern void ai_rearm_repair( object *objp, int docker_index, object *goal_objp, int dockee_index );
|
||||
extern void ai_add_rearm_goal( object *requester_objp, object *support_objp );
|
||||
@@ -571,7 +605,7 @@ extern int ai_find_goal_index( ai_goal* aigp, int mode, int submode = -1, int pr
|
||||
extern void ai_do_safety(object *objp);
|
||||
|
||||
// used to get path info for fighter bay emerging and departing
|
||||
int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int path_mask);
|
||||
int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int path_mask, vec3d *pos, vec3d *fvec);
|
||||
int ai_acquire_depart_path(object *pl_objp, int parent_objnum, int path_mask);
|
||||
|
||||
// used by AiBig.cpp
|
||||
@@ -589,20 +623,17 @@ extern int ai_fire_primary_weapon(object *objp); //changed to return weather it
|
||||
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 bool ai_willing_to_afterburn_hard(ai_info* aip);
|
||||
extern void ai_afterburn_hard(object* objp, ai_info* aip);
|
||||
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);
|
||||
|
||||
extern int is_instructor(object *objp);
|
||||
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1);
|
||||
|
||||
float ai_get_weapon_speed(const ship_weapon *swp);
|
||||
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
|
||||
float ai_get_weapon_speed(ship_weapon *swp);
|
||||
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, vec3d *gun_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
|
||||
|
||||
// function to change rearm status for ai ships (called from sexpression code)
|
||||
extern void ai_set_good_rearm_time( int team, int time );
|
||||
extern void ai_set_bad_rearm_time(int team, int time);
|
||||
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_do_objects_docked_stuff(object *docker, int docker_point, object *dockee, int dockee_point, bool update_clients = true);
|
||||
@@ -621,8 +652,12 @@ int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float ra
|
||||
// moved to header file by Goober5000
|
||||
void ai_announce_ship_dying(object *dying_objp);
|
||||
|
||||
// added by kazan
|
||||
void ai_start_fly_to_ship(object *objp, int shipnum);
|
||||
void ai_fly_to_ship();
|
||||
|
||||
//Moved declaration here for player ship -WMC
|
||||
void ai_process_subobjects(int objnum);
|
||||
void process_subobjects(int objnum);
|
||||
|
||||
//SUSHI: Setting ai_info stuff from both ai class and ai profile
|
||||
void init_aip_from_class_and_profile(ai_info *aip, ai_class *aicp, ai_profile_t *profile);
|
||||
@@ -634,7 +669,4 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
|
||||
|
||||
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
|
||||
|
||||
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& excluded_object_ids = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
|
||||
|
||||
#endif
|
||||
+4
-36
@@ -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)
|
||||
@@ -32,8 +32,6 @@ namespace AI {
|
||||
Unload_primaries, // Fire primaries as fast as possible!
|
||||
Trying_unsuccessfully_to_warp, // Trying to warp, but can't warp at the moment
|
||||
Free_afterburner_use, // Use afterburners while following waypoints or flying towards objects
|
||||
Waypoints_no_formation, // wont get into formation when running waypoints as part of a wing
|
||||
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
@@ -47,9 +45,7 @@ namespace AI {
|
||||
Purge, // purge this goal next time we process
|
||||
Goals_purged, // this goal has already caused other goals to get purged
|
||||
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
|
||||
Target_own_team, // this attack goal is allowed to target friendlies
|
||||
Afterburn_hard, // afterburn as hard as possible to the goal
|
||||
Waypoints_in_reverse, // decrement instead of increment
|
||||
Target_own_team,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
@@ -125,7 +121,7 @@ namespace AI {
|
||||
Smart_shield_management,
|
||||
Smart_subsystem_targeting_for_turrets,
|
||||
Strict_turret_tagged_only_targeting,
|
||||
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in https://scp.indiegames.us/mantis/view.php?id=3198
|
||||
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,
|
||||
@@ -134,37 +130,9 @@ namespace AI {
|
||||
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,
|
||||
Ships_playing_dead_dont_manage_ets,
|
||||
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,
|
||||
Fighterbay_arrivals_use_carrier_orient,
|
||||
Fighterbay_departures_use_carrier_orient,
|
||||
Prevent_negative_turret_ammo,
|
||||
Fix_keep_safe_distance,
|
||||
Ignore_aspect_when_leading,
|
||||
Fix_good_rearm_time_bug,
|
||||
No_continuous_turn_on_attack,
|
||||
Fixed_removing_play_dead_order,
|
||||
Disable_bay_emerge_timeout,
|
||||
Adjusted_AI_class_autoscale,
|
||||
Carry_shield_difficulty_scaling_bug,
|
||||
Whackable_debris,
|
||||
Whackable_asteroids,
|
||||
Dynamic_goals_afterburn_hard,
|
||||
Player_orders_afterburn_hard,
|
||||
Hudsquadmsg_tactical_disarm_disable,
|
||||
Align_to_target_when_guarding_still,
|
||||
Debris_respects_big_damage,
|
||||
Dont_limit_change_in_speed_due_to_physics_whack,
|
||||
Guards_ignore_protected_attackers,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
+18
-192
@@ -58,26 +58,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;
|
||||
@@ -184,14 +164,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
if (optional_string("$Max Beam Friendly Fire Damage:"))
|
||||
parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$Max Weapon Friendly Fire Damage:")) {
|
||||
parse_float_list(profile->weapon_friendly_damage_cap, NUM_SKILL_LEVELS);
|
||||
}
|
||||
|
||||
if (optional_string("$Max Weapon Self Damage:")) {
|
||||
parse_float_list(profile->weapon_self_damage_cap, NUM_SKILL_LEVELS);
|
||||
}
|
||||
|
||||
if (optional_string("$Player Countermeasure Life Scale:"))
|
||||
parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS);
|
||||
|
||||
@@ -231,9 +203,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
if (optional_string("$Player Subsys Damage Factor:") || optional_string("$AI Damage Reduction to Player Subsys:"))
|
||||
parse_float_list(profile->subsys_damage_scale, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$Player Damage Inflicted Factor:"))
|
||||
parse_float_list(profile->player_damage_inflicted_scale, NUM_SKILL_LEVELS);
|
||||
|
||||
// represented in fractions of F1_0
|
||||
if (optional_string("$Predict Position Delay:"))
|
||||
{
|
||||
@@ -266,7 +235,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
if (optional_string("$Glide Attack Percent:")) {
|
||||
parse_float_list(profile->glide_attack_percent, NUM_SKILL_LEVELS);
|
||||
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
|
||||
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
|
||||
//While we're at it, verify the range
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
|
||||
if (profile->glide_attack_percent[i] < 0.0f || profile->glide_attack_percent[i] > 100.0f) {
|
||||
@@ -279,7 +248,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
if (optional_string("$Circle Strafe Percent:")) {
|
||||
parse_float_list(profile->circle_strafe_percent, NUM_SKILL_LEVELS);
|
||||
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
|
||||
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
|
||||
//While we're at it, verify the range
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
|
||||
if (profile->circle_strafe_percent[i] < 0.0f || profile->circle_strafe_percent[i] > 100.0f) {
|
||||
@@ -292,7 +261,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
if (optional_string("$Glide Strafe Percent:")) {
|
||||
parse_float_list(profile->glide_strafe_percent, NUM_SKILL_LEVELS);
|
||||
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
|
||||
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
|
||||
//While we're at it, verify the range
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
|
||||
if (profile->glide_strafe_percent[i] < 0.0f || profile->glide_strafe_percent[i] > 100.0f) {
|
||||
@@ -305,7 +274,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
if (optional_string("$Random Sidethrust Percent:")) {
|
||||
parse_float_list(profile->random_sidethrust_percent, NUM_SKILL_LEVELS);
|
||||
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
|
||||
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
|
||||
//While we're at it, verify the range
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
|
||||
if (profile->random_sidethrust_percent[i] < 0.0f || profile->random_sidethrust_percent[i] > 100.0f) {
|
||||
@@ -479,20 +448,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
|
||||
|
||||
if (optional_string("$exact los minimum detection radius:")) {
|
||||
stuff_float(&profile->los_min_detection_radius);
|
||||
}
|
||||
|
||||
set_flag(profile, "$fighterbay arrivals use carrier orientation:", AI::Profile_Flags::Fighterbay_arrivals_use_carrier_orient);
|
||||
|
||||
set_flag(profile, "$fighterbay departures use carrier orientation:", AI::Profile_Flags::Fighterbay_departures_use_carrier_orient);
|
||||
|
||||
set_flag(profile, "$debris damage respects 'big damage' flag:", AI::Profile_Flags::Debris_respects_big_damage);
|
||||
|
||||
set_flag(profile, "$don't limit change in speed due to physics whack:", AI::Profile_Flags::Dont_limit_change_in_speed_due_to_physics_whack);
|
||||
|
||||
set_flag(profile, "$guards ignore protected attackers:", AI::Profile_Flags::Guards_ignore_protected_attackers);
|
||||
|
||||
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
|
||||
if (optional_string("$ai path mode:"))
|
||||
{
|
||||
stuff_string(buf, F_NAME, NAME_LENGTH);
|
||||
@@ -525,12 +481,14 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
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));
|
||||
mprintf(("Warning: \"$override radius for subsystem path points:\" should be >= %i (read %i). Value will not be used. ", 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);
|
||||
}
|
||||
@@ -562,106 +520,22 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
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, "$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, "$ships playing dead don't manage ETS:", AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
set_flag(profile, "$ships with no shields can manage ETS:", AI::Profile_Flags::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 (optional_string("$turret target recheck time:"))
|
||||
{
|
||||
stuff_float(&profile->turret_target_recheck_time);
|
||||
if (profile->turret_target_recheck_time < 0) {
|
||||
Warning(LOCATION, "Turret target recheck time must be positive.");
|
||||
profile->turret_target_recheck_time = 2000.0f;
|
||||
}
|
||||
}
|
||||
|
||||
set_flag(profile, "$prevent negative turret ammo:", AI::Profile_Flags::Prevent_negative_turret_ammo);
|
||||
|
||||
set_flag(profile, "$fix keep-safe-distance:", AI::Profile_Flags::Fix_keep_safe_distance);
|
||||
|
||||
set_flag(profile, "$AI ignores aspect lock for leading:", AI::Profile_Flags::Ignore_aspect_when_leading);
|
||||
|
||||
set_flag(profile, "$fix good-rearm-time bug:", AI::Profile_Flags::Fix_good_rearm_time_bug);
|
||||
|
||||
set_flag(profile, "$no continuous turn on attack:", AI::Profile_Flags::No_continuous_turn_on_attack);
|
||||
|
||||
set_flag(profile, "$remove-goal properly removes play-dead order:", AI::Profile_Flags::Fixed_removing_play_dead_order);
|
||||
|
||||
set_flag(profile, "$bay arrivals not time limited:", AI::Profile_Flags::Disable_bay_emerge_timeout);
|
||||
|
||||
set_flag(profile, "$use adjusted AI class autoscale:", AI::Profile_Flags::Adjusted_AI_class_autoscale);
|
||||
|
||||
set_flag(profile, "$carry shield difficulty scaling bug:", AI::Profile_Flags::Carry_shield_difficulty_scaling_bug);
|
||||
|
||||
set_flag(profile, "$debris affected by physics whacks:", AI::Profile_Flags::Whackable_debris);
|
||||
|
||||
set_flag(profile, "$asteroids affected by physics whacks:", AI::Profile_Flags::Whackable_asteroids);
|
||||
|
||||
set_flag(profile, "$dynamic goals afterburn hard:", AI::Profile_Flags::Dynamic_goals_afterburn_hard);
|
||||
|
||||
set_flag(profile, "$player orders afterburn hard:", AI::Profile_Flags::Player_orders_afterburn_hard);
|
||||
|
||||
set_flag(profile, "$hud squad messages use tactical disarm/disable:", AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
|
||||
set_flag(profile, "$align to target when guarding stationary ship:", AI::Profile_Flags::Align_to_target_when_guarding_still);
|
||||
|
||||
if (optional_string("$rotation factor multiplier for player collisions:")) {
|
||||
stuff_float(&profile->rot_fac_multiplier_ply_collisions);
|
||||
}
|
||||
|
||||
// end of options ----------------------------------------
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
if (saved_Mp && (saved_Mp == Mp))
|
||||
{
|
||||
char tmp[60];
|
||||
memset(tmp, 0, 60);
|
||||
strncpy(tmp, Mp, 59);
|
||||
mprintf(("WARNING: Unrecognized parameter in %s: %s\n", filename, tmp));
|
||||
mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp));
|
||||
|
||||
Mp++;
|
||||
}
|
||||
@@ -696,21 +570,12 @@ void ai_profiles_init()
|
||||
// init retail entry first
|
||||
parse_ai_profiles_tbl(NULL);
|
||||
|
||||
// Allow mission_profiles.tbl to be a alias of ai_profiles.tbl, but only load one or the other.
|
||||
// mission_profiles.tbl would be newer so assume intended, but print to the log to be sure - Mjn
|
||||
char filename[MAX_FILENAME_LEN] = "ai_profiles.tbl";
|
||||
if (cf_exists_full("mission_profiles.tbl", CF_TYPE_TABLES)) {
|
||||
mprintf(("mission_profiles.tbl was found! Using that instead of ai_profiles.tbl...\n"));
|
||||
strcpy_s(filename, "mission_profiles.tbl");
|
||||
}
|
||||
|
||||
// now parse the supplied table (if any)
|
||||
if (cf_exists_full(filename, CF_TYPE_TABLES))
|
||||
parse_ai_profiles_tbl(filename);
|
||||
if (cf_exists_full("ai_profiles.tbl", CF_TYPE_TABLES))
|
||||
parse_ai_profiles_tbl("ai_profiles.tbl");
|
||||
|
||||
// parse any modular tables
|
||||
parse_modular_table("*-aip.tbm", parse_ai_profiles_tbl);
|
||||
parse_modular_table("*-msp.tbm", parse_ai_profiles_tbl);
|
||||
|
||||
// set default if specified
|
||||
temp = ai_profile_lookup(Default_profile_name);
|
||||
@@ -735,15 +600,11 @@ void ai_profile_t::reset()
|
||||
|
||||
flags.reset();
|
||||
|
||||
los_min_detection_radius = 10.0f;
|
||||
ai_path_mode = AI_PATH_MODE_NORMAL;
|
||||
ai_path_mode = 0;
|
||||
subsystem_path_radii = 0;
|
||||
bay_arrive_speed_mult = 1.0f;
|
||||
bay_depart_speed_mult = 1.0f;
|
||||
bay_arrive_speed_mult = 0;
|
||||
bay_depart_speed_mult = 0;
|
||||
second_order_lead_predict_factor = 0;
|
||||
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
|
||||
turret_target_recheck_time = 2000.0f;
|
||||
rot_fac_multiplier_ply_collisions = 0.0f;
|
||||
|
||||
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
|
||||
max_incoming_asteroids[i] = 0;
|
||||
@@ -766,12 +627,9 @@ void ai_profile_t::reset()
|
||||
shield_energy_scale[i] = 0;
|
||||
afterburner_recharge_scale[i] = 0;
|
||||
player_damage_scale[i] = 0;
|
||||
player_damage_inflicted_scale[i] = 0;
|
||||
|
||||
subsys_damage_scale[i] = 0;
|
||||
beam_friendly_damage_cap[i] = -1.f;
|
||||
weapon_friendly_damage_cap[i] = -1.f;
|
||||
weapon_self_damage_cap[i] = -1.f;
|
||||
beam_friendly_damage_cap[i] = 0;
|
||||
turn_time_scale[i] = 0;
|
||||
glide_attack_percent[i] = 0;
|
||||
circle_strafe_percent[i] = 0;
|
||||
@@ -818,42 +676,10 @@ 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);
|
||||
flags.set(AI::Profile_Flags::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);
|
||||
}
|
||||
// backwards compatible flag for a bug accidentally introduced during this time
|
||||
if (mod_supports_version(3, 6, 14) && !mod_supports_version(23, 1, 0)) {
|
||||
flags.set(AI::Profile_Flags::Carry_shield_difficulty_scaling_bug);
|
||||
}
|
||||
if (mod_supports_version(21, 4, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fixed_ship_weapon_collision);
|
||||
}
|
||||
if (mod_supports_version(22, 0, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fighterbay_arrivals_use_carrier_orient);
|
||||
flags.set(AI::Profile_Flags::Prevent_negative_turret_ammo);
|
||||
flags.set(AI::Profile_Flags::Fix_keep_safe_distance);
|
||||
}
|
||||
if (mod_supports_version(23, 0, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fix_good_rearm_time_bug);
|
||||
flags.set(AI::Profile_Flags::No_continuous_turn_on_attack);
|
||||
flags.set(AI::Profile_Flags::Fixed_removing_play_dead_order);
|
||||
}
|
||||
if (mod_supports_version(23, 2, 0)) {
|
||||
flags.set(AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
}
|
||||
if (mod_supports_version(23, 4, 0)) {
|
||||
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
}
|
||||
if (mod_supports_version(24, 2, 0)) {
|
||||
flags.set(AI::Profile_Flags::Debris_respects_big_damage);
|
||||
flags.set(AI::Profile_Flags::Force_beam_turret_fov);
|
||||
flags.set(AI::Profile_Flags::Guards_ignore_protected_attackers);
|
||||
}
|
||||
}
|
||||
+1
-19
@@ -17,11 +17,8 @@
|
||||
// AI Path types
|
||||
#define AI_PATH_MODE_NORMAL 0
|
||||
#define AI_PATH_MODE_ALT1 1
|
||||
|
||||
#define AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL 0
|
||||
#define AI_RANGE_AWARE_SEC_SEL_MODE_AWARE 1
|
||||
|
||||
#define MAX_AI_PROFILES 8
|
||||
#define MAX_AI_PROFILES 5
|
||||
|
||||
class ai_profile_t {
|
||||
public:
|
||||
@@ -53,12 +50,9 @@ public:
|
||||
float shield_energy_scale[NUM_SKILL_LEVELS]; // shield energy available
|
||||
float afterburner_recharge_scale[NUM_SKILL_LEVELS]; // speed of afterburner recharge
|
||||
float player_damage_scale[NUM_SKILL_LEVELS]; // damage applied to the player
|
||||
float player_damage_inflicted_scale[NUM_SKILL_LEVELS]; // damage applied by the player
|
||||
|
||||
float subsys_damage_scale[NUM_SKILL_LEVELS]; // damage applied to a player subsystem
|
||||
float beam_friendly_damage_cap[NUM_SKILL_LEVELS]; // damage cap values for friendly beam fire
|
||||
float weapon_friendly_damage_cap[NUM_SKILL_LEVELS];
|
||||
float weapon_self_damage_cap[NUM_SKILL_LEVELS];
|
||||
float turn_time_scale[NUM_SKILL_LEVELS]; // speed at which enemy ships turn
|
||||
float glide_attack_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "glide attack" move
|
||||
float circle_strafe_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "circle strafe" move
|
||||
@@ -101,9 +95,6 @@ public:
|
||||
|
||||
float detail_distance_mult[MAX_DETAIL_LEVEL + 1]; //MAX_DETAIL_LEVEL really needs to be 4
|
||||
|
||||
// minimum radius for the line-of-sight (los) detection --wookieejedi
|
||||
float los_min_detection_radius;
|
||||
|
||||
int ai_path_mode;
|
||||
|
||||
// radii to use for the radius for subsystem path points and default value --wookieejedi
|
||||
@@ -116,15 +107,6 @@ public:
|
||||
|
||||
// How much 0-1 of a second-order lead prediction factor to add to lead indicators. Affects only the HUD indicator, and autoaim.
|
||||
float second_order_lead_predict_factor;
|
||||
|
||||
//Controls if the AI is dumb enough to keep trying to use out-of-range secondaries.
|
||||
int ai_range_aware_secondary_select_mode;
|
||||
|
||||
// how often turrets shoulds check for new targets, milliseconds
|
||||
float turret_target_recheck_time;
|
||||
|
||||
// Multiplier value so the player can also experience rotational effects from collisions --wookieejedi
|
||||
float rot_fac_multiplier_ply_collisions;
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
+99
-268
@@ -17,13 +17,12 @@
|
||||
#include "io/timer.h"
|
||||
#include "math/staticrand.h"
|
||||
#include "mission/missionparse.h"
|
||||
#include "object/objcollide.h"
|
||||
#include "object/object.h"
|
||||
#include "ship/afterburner.h"
|
||||
#include "ship/ship.h"
|
||||
#include "utils/Random.h"
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma optimize("", off)
|
||||
#pragma auto_inline(off)
|
||||
@@ -67,6 +66,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
|
||||
void ai_big_strafe_position();
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
|
||||
extern int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
|
||||
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
|
||||
|
||||
@@ -76,15 +76,16 @@ extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d
|
||||
// If truly_random flag set (haha), then generate a pretty random number. Otherwise, generate a static rand which
|
||||
// tends to not change from frame to frame.
|
||||
// Try four times and choose nearest point to increase chance of getting a good point.
|
||||
void ai_bpap(const object *objp, const vec3d *attacker_objp_pos, const vec3d *attacker_objp_fvec, vec3d *attack_point, vec3d *local_attack_point, float fov, float weapon_travel_dist, vec3d *surface_normal, const ship_subsys *ss)
|
||||
void ai_bpap(object *objp, vec3d *attacker_objp_pos, vec3d *attacker_objp_fvec, vec3d *attack_point, vec3d *local_attack_point, float fov, float weapon_travel_dist, vec3d *surface_normal, ship_subsys *ss)
|
||||
{
|
||||
float nearest_dist;
|
||||
vec3d result_point, best_point;
|
||||
vec3d rel_point;
|
||||
int num_tries;
|
||||
int i;
|
||||
model_octant *octp;
|
||||
polymodel *pm;
|
||||
int i, q, octs[4];
|
||||
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
|
||||
polymodel* pm = model_get(sip->model_num);
|
||||
model_subsystem *tp = NULL;
|
||||
if (ss != NULL)
|
||||
tp = ss->system_info;
|
||||
@@ -92,53 +93,63 @@ void ai_bpap(const object *objp, const vec3d *attacker_objp_pos, const vec3d *at
|
||||
best_point = objp->pos;
|
||||
nearest_dist = weapon_travel_dist;
|
||||
|
||||
// attempt anywhere from 16 to 4 times, more if we're closer
|
||||
model_which_octant_distant_many(attacker_objp_pos, sip->model_num, &objp->orient, &objp->pos, &pm, octs);
|
||||
|
||||
num_tries = (int) (vm_vec_dist(&objp->pos, attacker_objp_pos)/objp->radius);
|
||||
|
||||
if (num_tries >= 4)
|
||||
num_tries = 1;
|
||||
else
|
||||
num_tries = (4 - num_tries) * 4;
|
||||
num_tries = 4 - num_tries;
|
||||
|
||||
vm_vec_zero(local_attack_point);
|
||||
// Index #0 is best one.
|
||||
if ( pm->octants[octs[0]].verts ) {
|
||||
*local_attack_point = *pm->octants[octs[0]].verts[0]; // Set just in case it doesn't get set below.
|
||||
} else {
|
||||
vm_vec_zero(local_attack_point);
|
||||
}
|
||||
|
||||
auto collision_tree = model_get_bsp_collision_tree(pm->submodel[pm->detail[0]].collision_tree_index);
|
||||
for (q=0; q<4; q++) {
|
||||
octp = &pm->octants[octs[q]];
|
||||
if (octp->nverts > 0) {
|
||||
|
||||
if (!collision_tree->poly_centers.empty()) {
|
||||
int num_polies = (int)collision_tree->poly_centers.size();
|
||||
if (num_tries > octp->nverts)
|
||||
num_tries = octp->nverts;
|
||||
|
||||
if (num_tries > num_polies)
|
||||
num_tries = num_polies;
|
||||
if (num_tries > octp->nverts)
|
||||
num_tries = octp->nverts;
|
||||
|
||||
for (i=0; i<num_tries; i++) {
|
||||
int index;
|
||||
float dist, dot;
|
||||
vec3d v2p;
|
||||
for (i=0; i<num_tries; i++) {
|
||||
int index;
|
||||
float dist, dot;
|
||||
vec3d v2p;
|
||||
|
||||
index = (int) (frand() * num_polies);
|
||||
index = (int) (frand() * (octp->nverts));
|
||||
|
||||
rel_point = collision_tree->poly_centers[index];
|
||||
vm_vec_unrotate(&result_point, &rel_point, &objp->orient);
|
||||
vm_vec_add2(&result_point, &objp->pos);
|
||||
rel_point = *octp->verts[index];
|
||||
vm_vec_unrotate(&result_point, &rel_point, &objp->orient);
|
||||
vm_vec_add2(&result_point, &objp->pos);
|
||||
|
||||
dist = vm_vec_normalized_dir(&v2p, &result_point, attacker_objp_pos);
|
||||
bool in_fov = false;
|
||||
dist = vm_vec_normalized_dir(&v2p, &result_point, attacker_objp_pos);
|
||||
bool in_fov = false;
|
||||
|
||||
dot = vm_vec_dot(&v2p, attacker_objp_fvec);
|
||||
if (tp == NULL) {
|
||||
if (dot > fov)
|
||||
in_fov = true;
|
||||
} else {
|
||||
in_fov = turret_fov_test(ss, attacker_objp_fvec, &v2p);
|
||||
}
|
||||
dot = vm_vec_dot(&v2p, attacker_objp_fvec);
|
||||
if (tp == NULL) {
|
||||
if (dot > fov)
|
||||
in_fov = true;
|
||||
} else {
|
||||
in_fov = turret_fov_test(ss, attacker_objp_fvec, &v2p);
|
||||
}
|
||||
|
||||
if (in_fov) {
|
||||
if (dist < nearest_dist) {
|
||||
nearest_dist = dist;
|
||||
best_point = result_point;
|
||||
*local_attack_point = rel_point;
|
||||
Assert( !vm_is_vec_nan(local_attack_point) );
|
||||
if (dot > (1.0f + fov)/2.0f) // If this point is quite good, quit searching for a better one.
|
||||
goto done_1;
|
||||
if (in_fov) {
|
||||
if (dist < nearest_dist) {
|
||||
nearest_dist = dist;
|
||||
best_point = result_point;
|
||||
*local_attack_point = rel_point;
|
||||
Assert( !vm_is_vec_nan(local_attack_point) );
|
||||
if (dot > (1.0f + fov)/2.0f) // If this point is quite good, quit searching for a better one.
|
||||
goto done_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,6 +173,8 @@ done_1:
|
||||
}
|
||||
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
|
||||
mc.model_instance_num = Ships[objp->instance].model_instance_num;
|
||||
mc.model_num = sip->model_num;
|
||||
mc.orient = &objp->orient;
|
||||
@@ -193,7 +206,7 @@ done_1:
|
||||
//
|
||||
// Note: Default value for fov is 1.0f 1.0f means don't use fov parameter.
|
||||
// If fov != 1.0f, try up to four times to find a point that's in the field of view.
|
||||
void ai_big_pick_attack_point_turret(const object *objp, ship_subsys *ssp, const vec3d *gpos, const vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
|
||||
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
|
||||
{
|
||||
if (!timestamp_elapsed(ssp->turret_pick_big_attack_point_timestamp)) {
|
||||
vec3d result_point;
|
||||
@@ -213,7 +226,7 @@ void ai_big_pick_attack_point_turret(const object *objp, ship_subsys *ssp, const
|
||||
// Note: Default value for fov is 1.0f 1.0f means don't use fov parameter.
|
||||
// If fov != 1.0f, try up to four times to find a point that's in the field of view.
|
||||
// Note, attacker_objp can be a ship or a weapon.
|
||||
void ai_big_pick_attack_point(const object *objp, const object *attacker_objp, vec3d *attack_point, float fov)
|
||||
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov)
|
||||
{
|
||||
Assert(objp->instance > -1);
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
@@ -393,7 +406,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
|
||||
|
||||
// get world pos of eye (stored in geye)
|
||||
ep = &(pm->view_positions[shipp->current_viewpoint]);
|
||||
model_instance_local_to_global_point( &geye, &ep->pnt, pm, pmi, 0, &Pl_objp->orient, &Pl_objp->pos );
|
||||
model_instance_find_world_point( &geye, &ep->pnt, pm, pmi, 0, &Pl_objp->orient, &Pl_objp->pos );
|
||||
|
||||
// get world pos of subsystem
|
||||
vm_vec_unrotate(&gsubpos, &aip->targeted_subsys->system_info->pnt, &En_objp->orient);
|
||||
@@ -411,7 +424,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
|
||||
}
|
||||
}
|
||||
|
||||
if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, true) ) {
|
||||
if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 1) ) {
|
||||
subsys_in_sight = 1;
|
||||
}
|
||||
}
|
||||
@@ -516,122 +529,6 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ai_new_maybe_reposition_attack_subsys() {
|
||||
|
||||
ai_info* aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
|
||||
if (aip->target_objnum < 0 || aip->targeted_subsys == nullptr)
|
||||
return false;
|
||||
|
||||
object* target_objp = &Objects[aip->target_objnum];
|
||||
|
||||
// dont bother with this if you're still far away
|
||||
if (vm_vec_dist(&Pl_objp->pos, &target_objp->pos) > target_objp->radius * 2.0f + 2000.0f)
|
||||
return false;
|
||||
|
||||
vec3d geye, gsubpos;
|
||||
eye* ep;
|
||||
polymodel* pm = model_get(Ship_info[Ships[Pl_objp->instance].ship_info_index].model_num);
|
||||
|
||||
// get world pos of eye (stored in geye)
|
||||
ep = &(pm->view_positions[Ships[Pl_objp->instance].current_viewpoint]);
|
||||
model_local_to_global_point(&geye, &ep->pnt, pm, 0, &Pl_objp->orient, &Pl_objp->pos);
|
||||
|
||||
// get world pos of subsystem
|
||||
get_subsystem_pos(&gsubpos, target_objp, aip->targeted_subsys);
|
||||
|
||||
// you're in sight! shoot it!
|
||||
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, false))
|
||||
return false;
|
||||
|
||||
// not in sight, gotta get there
|
||||
vec3d* good_pos = nullptr;
|
||||
vec3d world_goal_pos;
|
||||
// For performance reasons we only recheck once a second, otherwise we reuse the last found target.
|
||||
if (timestamp_elapsed(aip->next_dynamic_path_check_time)) {
|
||||
vec3d tgt2pl = Pl_objp->pos - target_objp->pos;
|
||||
vec3d tgt2subsys = gsubpos - target_objp->pos;
|
||||
float pl_dist = vm_vec_mag(&tgt2pl);
|
||||
float subsys_dist = vm_vec_mag(&tgt2subsys) * 1.3f; // add a bit to this, we don't want to go directly at the subsys, we want to go above it
|
||||
|
||||
float angle2subsys = vm_vec_delta_ang(&tgt2pl, &tgt2subsys, nullptr);
|
||||
float angle2goal = angle2subsys;
|
||||
if (angle2goal > 1.2f) // let's not try to go more than about 70 degrees around the ship
|
||||
angle2goal = 1.2f;
|
||||
|
||||
// we'll start by travelling along the sphere at our current distance around the ship
|
||||
// remember that goal_pos will be relative to our target_ship (so we can scale in and out easily)
|
||||
vec3d goal_pos, cross;
|
||||
vm_vec_cross(&cross, &tgt2pl, &tgt2subsys);
|
||||
vm_vec_normalize(&cross);
|
||||
vm_vec_negate(&cross);
|
||||
vm_rot_point_around_line(&goal_pos, &tgt2pl, angle2goal, &vmd_zero_vector, &cross);
|
||||
|
||||
// then scale in (or out) towards our subsys
|
||||
float new_radius = ((subsys_dist - pl_dist) * (angle2goal / angle2subsys)) + pl_dist;
|
||||
vm_vec_copy_scale(&world_goal_pos, &goal_pos, new_radius / pl_dist);
|
||||
world_goal_pos += target_objp->pos;
|
||||
|
||||
if (pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f)) {
|
||||
// ok best case won't work
|
||||
if (pl_dist > subsys_dist) {
|
||||
//we're farther away than the subsys, let's try at our current distance
|
||||
world_goal_pos = goal_pos + target_objp->pos;
|
||||
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
|
||||
good_pos = &world_goal_pos;
|
||||
}
|
||||
|
||||
// ok, let's start moving it away and see if that's better
|
||||
for (float i = 1.0f; i < 4.0f; i += 1.0f) {
|
||||
if (good_pos)
|
||||
break;
|
||||
|
||||
vm_vec_copy_scale(&world_goal_pos, &goal_pos, (new_radius / pl_dist) * powf(1.3f,i));
|
||||
world_goal_pos += target_objp->pos;
|
||||
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
|
||||
good_pos = &world_goal_pos;
|
||||
}
|
||||
|
||||
// welp this sucks, just run away i guess
|
||||
if (!good_pos) {
|
||||
vm_vec_copy_normalize(&world_goal_pos, &tgt2pl);
|
||||
world_goal_pos *= target_objp->radius + pl_dist;
|
||||
world_goal_pos += target_objp->pos;
|
||||
good_pos = &world_goal_pos;
|
||||
}
|
||||
}
|
||||
else
|
||||
good_pos = &world_goal_pos;
|
||||
aip->next_dynamic_path_check_time = timestamp( AI_DYNAMIC_PATH_RECHECK_DELAY );
|
||||
aip->last_dynamic_path_goal = *good_pos;
|
||||
|
||||
}
|
||||
else{ //Not enough time has passed till recheck.
|
||||
good_pos = &aip->last_dynamic_path_goal;
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(good_pos, Pl_objp, nullptr, nullptr, 0.0f, 0);
|
||||
float subsys_distance = vm_vec_dist(&Pl_objp->pos, &gsubpos);
|
||||
|
||||
// full speed until you're close, then slow down a bit
|
||||
accelerate_ship(aip, subsys_distance > 200.0f ? 1.0f : subsys_distance / 200.0f);
|
||||
|
||||
if (!(Ships[Pl_objp->instance].flags[Ship::Ship_Flags::Afterburner_locked])) {
|
||||
if (ai_willing_to_afterburn_hard(aip) && subsys_distance > 1000.0f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
else if (subsys_distance > 300.0f) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 2 * F1_0;
|
||||
}
|
||||
}
|
||||
} else
|
||||
afterburners_stop(Pl_objp);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// This function is only called from ai_big_chase_attack() when a ship is flying very slowly and
|
||||
// attacking a big ship. The ship should scan for enemy fighter/bombers... if any are close, then
|
||||
// return 1, otherwise return 0;
|
||||
@@ -649,17 +546,16 @@ int ai_big_maybe_start_strafe(ai_info *aip, ship_info *sip)
|
||||
// are near
|
||||
if ( sip->is_small_ship() ) {
|
||||
if ( timestamp_elapsed(aip->scan_for_enemy_timestamp) ) {
|
||||
ship_obj *so;
|
||||
object *test_objp;
|
||||
ship *test_sp;
|
||||
float dist_squared;
|
||||
|
||||
aip->scan_for_enemy_timestamp = timestamp(SCAN_FIGHTERS_INTERVAL);
|
||||
// iterate through ships, and see if any fighter/bomber from opposite team are near
|
||||
for (auto so: list_range(&Ship_obj_list)) {
|
||||
so = GET_FIRST(&Ship_obj_list);
|
||||
while( so != END_OF_LIST(&Ship_obj_list) ) {
|
||||
test_objp = &Objects[so->objnum];
|
||||
if (test_objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
test_sp = &Ships[test_objp->instance];
|
||||
|
||||
if ( iff_x_attacks_y(Ships[Pl_objp->instance].team, test_sp->team) ) {
|
||||
@@ -670,6 +566,7 @@ int ai_big_maybe_start_strafe(ai_info *aip, ship_info *sip)
|
||||
}
|
||||
}
|
||||
}
|
||||
so = GET_NEXT(so);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -694,9 +591,6 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
if (Pl_objp->phys_info.speed < 3.0f) {
|
||||
object *objp;
|
||||
for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
|
||||
if (objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
if ((objp->type == OBJ_WEAPON) && (iff_x_attacks_y(Ships[Pl_objp->instance].team, Weapons[objp->instance].team)))
|
||||
if (Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_LASER) {
|
||||
vec3d in_vec;
|
||||
@@ -743,11 +637,8 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
}
|
||||
|
||||
// see if Pl_objp needs to reposition to get a good shot at subsystem which is being attacked
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if ( ai_big_maybe_follow_subsys_path() ) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && !ai_willing_to_afterburn_hard(aip)) {
|
||||
if ( ai_big_maybe_follow_subsys_path() ) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
return;
|
||||
@@ -776,28 +667,14 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
|
||||
ai_turn_towards_vector(enemy_pos, Pl_objp, nullptr, rel_pos, 0.0f, 0, rvec);
|
||||
|
||||
// set an optimal range if applicable
|
||||
float optimal_range = 0.0f;
|
||||
ship_weapon* weapons = &Ships[Pl_objp->instance].weapons;
|
||||
weapon_info* wip = nullptr;
|
||||
ship* shipp = &Ships[Pl_objp->instance];
|
||||
|
||||
if (weapons->num_primary_banks >= 1 && weapons->current_primary_bank >= 0 && !shipp->flags[Ship::Ship_Flags::Primaries_locked]) {
|
||||
wip = &Weapon_info[weapons->primary_bank_weapons[weapons->current_primary_bank]];
|
||||
} else if (weapons->num_secondary_banks >= 1 && weapons->current_secondary_bank >= 0 && !shipp->flags[Ship::Ship_Flags::Secondaries_locked]) {
|
||||
wip = &Weapon_info[weapons->secondary_bank_weapons[weapons->current_secondary_bank]];
|
||||
}
|
||||
|
||||
if (wip != nullptr && wip->optimum_range > 0)
|
||||
optimal_range = wip->optimum_range;
|
||||
|
||||
// calc range of primary weapon
|
||||
weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
|
||||
|
||||
if ( aip->targeted_subsys != NULL ) {
|
||||
if (dist_to_enemy > (optimal_range > 0.0f ? optimal_range : (weapon_travel_dist-20))) {
|
||||
if (dist_to_enemy > (weapon_travel_dist-20)) {
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
ship *shipp = &Ships[Pl_objp->instance];
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
@@ -822,7 +699,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
} else if (dot_to_enemy < 0.75f) {
|
||||
accel = 0.75f;
|
||||
} else {
|
||||
if (dist_to_enemy > (optimal_range > 0.0f ? optimal_range : (weapon_travel_dist/2.0f))) {
|
||||
if (dist_to_enemy > weapon_travel_dist/2.0f) {
|
||||
accel = 1.0f;
|
||||
} else {
|
||||
accel = 1.0f - dot_to_enemy;
|
||||
@@ -839,9 +716,8 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
} else {
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
if (ai_willing_to_afterburn_hard(aip) && accel > 0.99f && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked])) {
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
} else if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
ship *shipp = &Ships[Pl_objp->instance];
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
@@ -860,9 +736,9 @@ void ai_big_chase_ct()
|
||||
ai_chase_ct();
|
||||
}
|
||||
|
||||
extern bool ai_select_secondary_weapon(object *objp, ship_weapon *swp, int priority1 = -1, int priority2 = -1);
|
||||
extern void ai_select_secondary_weapon(object *objp, ship_weapon *swp, int priority1 = -1, int priority2 = -1);
|
||||
extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *swip, bool burst);
|
||||
extern bool ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
|
||||
extern void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
|
||||
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time, float time_scale = 1.f);
|
||||
|
||||
extern void maybe_cheat_fire_synaptic(object *objp);
|
||||
@@ -881,19 +757,12 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
swp = &Ships[Pl_objp->instance].weapons;
|
||||
|
||||
float target_radius = En_objp->radius;
|
||||
|
||||
// normal subsystem attacking uses whether or not its on a path and skips this function entirely to stop "over-eager" firing
|
||||
// since the improved method doesnt use paths, refine the target radius to stop over-eager shooting
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing] && aip->targeted_subsys != nullptr)
|
||||
target_radius = aip->targeted_subsys->system_info->radius;
|
||||
|
||||
if (dot_to_enemy > 0.95f - 0.5f * target_radius/MAX(1.0f, target_radius + dist_to_enemy)) {
|
||||
if (dot_to_enemy > 0.95f - 0.5f * En_objp->radius/MAX(1.0f, En_objp->radius + dist_to_enemy)) {
|
||||
aip->time_enemy_in_range += flFrametime;
|
||||
|
||||
// Chance of hitting ship is based on dot product of firing ship's forward vector with vector to ship
|
||||
// and also the size of the target relative to distance to target.
|
||||
if (dot_to_enemy > std::max(0.5f, 0.90f + aip->ai_accuracy / 10.0f - En_objp->radius / std::max(1.0f, dist_to_enemy))) {
|
||||
if (dot_to_enemy > MAX(0.5f, 0.90f + aip->ai_accuracy/10.0f - En_objp->radius/MAX(1.0f,dist_to_enemy))) {
|
||||
|
||||
ship *temp_shipp;
|
||||
temp_shipp = &Ships[Pl_objp->instance];
|
||||
@@ -913,13 +782,13 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
}
|
||||
|
||||
if (tswp->num_secondary_banks > 0) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL))) {
|
||||
bool valid_secondary = ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP))) {
|
||||
ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
|
||||
int current_bank = tswp->current_secondary_bank;
|
||||
if (current_bank > -1 && valid_secondary) {
|
||||
if (current_bank > -1) {
|
||||
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
|
||||
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
// If ship is protected and very low on hits, don't fire missiles.
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
|
||||
@@ -928,7 +797,7 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
}
|
||||
}
|
||||
|
||||
if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank]) && weapon_target_satisfies_lock_restrictions(swip, En_objp)) {
|
||||
if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank])) {
|
||||
float firing_range;
|
||||
if (swip->wi_flags[Weapon::Info_Flags::Local_ssm])
|
||||
firing_range=swip->lssm_lock_range;
|
||||
@@ -958,11 +827,10 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
} else {
|
||||
t = swip->fire_wait;
|
||||
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
|
||||
swp->burst_counter[current_bank_adjusted] = Random::next(swip->burst_shots);
|
||||
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
|
||||
} else {
|
||||
swp->burst_counter[current_bank_adjusted] = 0;
|
||||
}
|
||||
swp->burst_seed[current_bank_adjusted] = Random::next();
|
||||
}
|
||||
} else {
|
||||
if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
|
||||
@@ -971,11 +839,10 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
} else {
|
||||
t = set_secondary_fire_delay(aip, temp_shipp, swip, false);
|
||||
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
|
||||
swp->burst_counter[current_bank_adjusted] = Random::next(swip->burst_shots);
|
||||
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
|
||||
} else {
|
||||
swp->burst_counter[current_bank_adjusted] = 0;
|
||||
}
|
||||
swp->burst_seed[current_bank_adjusted] = Random::next();
|
||||
}
|
||||
}
|
||||
swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (t*1000.0f));
|
||||
@@ -1012,8 +879,6 @@ void ai_big_switch_to_chase_mode(ai_info *aip)
|
||||
aip->submode_start_time = Missiontime;
|
||||
}
|
||||
|
||||
extern weapon_info* ai_get_weapon(ship_weapon* swp);
|
||||
|
||||
// Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
|
||||
void ai_big_chase()
|
||||
{
|
||||
@@ -1033,38 +898,16 @@ void ai_big_chase()
|
||||
player_pos = Pl_objp->pos;
|
||||
ai_big_pick_attack_point(En_objp, Pl_objp, &enemy_pos, 0.8f);
|
||||
|
||||
weapon_info* wip = ai_get_weapon(&shipp->weapons);
|
||||
bool ballistic_aiming = !IS_VEC_NULL(&The_mission.gravity) && wip && wip->gravity_const != 0.0f;
|
||||
bool valid_ballistic_trajectory = true;
|
||||
// Compute the predicted position of the center of the ship, then add the delta to the goal pos.
|
||||
if (En_objp->phys_info.speed > 3.0f) {
|
||||
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
|
||||
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
|
||||
vm_vec_sub2(&enemy_pos, &En_objp->pos);
|
||||
} else
|
||||
predicted_enemy_pos = En_objp->pos;
|
||||
|
||||
if (!ballistic_aiming) {
|
||||
// Compute the predicted position of the center of the ship, then add the delta to the goal pos.
|
||||
if (En_objp->phys_info.speed > 3.0f) {
|
||||
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
|
||||
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
|
||||
vm_vec_sub2(&enemy_pos, &En_objp->pos);
|
||||
} else
|
||||
predicted_enemy_pos = En_objp->pos;
|
||||
|
||||
if (aip->targeted_subsys != NULL) {
|
||||
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
|
||||
}
|
||||
} else {
|
||||
if (aip->targeted_subsys != NULL) {
|
||||
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
|
||||
}
|
||||
|
||||
vec3d gravity = The_mission.gravity * wip->gravity_const;
|
||||
vec3d target;
|
||||
valid_ballistic_trajectory =
|
||||
physics_lead_ballistic_trajectory(&player_pos, &enemy_pos, &En_objp->phys_info.vel, wip->max_speed, &gravity, &target);
|
||||
|
||||
if (valid_ballistic_trajectory) {
|
||||
enemy_pos = Pl_objp->pos + target * vm_vec_dist(&Pl_objp->pos, &enemy_pos);
|
||||
predicted_enemy_pos = enemy_pos;
|
||||
} else {
|
||||
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
|
||||
}
|
||||
if (aip->targeted_subsys != NULL) {
|
||||
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
|
||||
}
|
||||
|
||||
dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, &enemy_pos, &player_pos); // - En_objp->radius;
|
||||
@@ -1095,7 +938,7 @@ void ai_big_chase()
|
||||
// If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
|
||||
if ((dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags[AI::AI_Flags::Seek_lock])) {
|
||||
update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
|
||||
} else if (aip->targeted_subsys != NULL && !ballistic_aiming) {
|
||||
} else if (aip->targeted_subsys != NULL) {
|
||||
Assert(aip->targeted_subsys != NULL);
|
||||
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
|
||||
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
|
||||
@@ -1127,7 +970,7 @@ void ai_big_chase()
|
||||
}
|
||||
}
|
||||
|
||||
if (!aip->ai_profile_flags[AI::Profile_Flags::No_continuous_turn_on_attack] && aip->target_time < 2.0f)
|
||||
if (aip->target_time < 2.0f)
|
||||
if ((dot_to_enemy < 0.9f) || (dist_to_enemy > 300.0f)) {
|
||||
aip->submode = SM_CONTINUOUS_TURN;
|
||||
aip->submode_start_time = Missiontime - fl2f(2.75f); // This backdated start time allows immediate switchout.
|
||||
@@ -1196,10 +1039,7 @@ void ai_big_chase()
|
||||
float dist_normal_to_enemy;
|
||||
|
||||
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing])
|
||||
dist_normal_to_enemy = fl_abs((dist_to_enemy / vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
|
||||
else // I'm fairly sure this retail code VVV meant to use / instead of *
|
||||
dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
|
||||
dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
|
||||
} else {
|
||||
// don;t have normal so use a conservative value here
|
||||
dist_normal_to_enemy = 0.3f * dist_to_enemy;
|
||||
@@ -1335,7 +1175,7 @@ void ai_big_chase()
|
||||
// I noticed AI ships firing inappropriately when following a path near a big ship.
|
||||
// TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
|
||||
// a big ship
|
||||
if (aip->mode != AIM_EVADE && aip->path_start == -1 && (!ballistic_aiming || valid_ballistic_trajectory)) {
|
||||
if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
|
||||
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy);
|
||||
} else {
|
||||
if (flFrametime < 1.0f)
|
||||
@@ -1476,17 +1316,13 @@ void ai_big_strafe_attack()
|
||||
ai_info *aip;
|
||||
vec3d target_pos;
|
||||
vec3d rand_vec;
|
||||
float accel, t;
|
||||
float target_dist = 0.0f;
|
||||
float target_dot = 0.0f;
|
||||
float target_dist, target_dot, accel, t;
|
||||
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if (ai_big_maybe_follow_subsys_path(0))
|
||||
if ( ai_big_maybe_follow_subsys_path(0) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
if ( ai_big_strafe_maybe_retreat(&target_pos) )
|
||||
@@ -1509,7 +1345,7 @@ void ai_big_strafe_attack()
|
||||
if ( t > 0.0f && t < 1.5f ) {
|
||||
// set up goal_point for avoid path to turn towards
|
||||
aip->goal_point = Pl_objp->pos;
|
||||
switch(Random::next(4)) {
|
||||
switch(rand()%4) {
|
||||
case 0:
|
||||
vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec, 2.0f);
|
||||
break;
|
||||
@@ -1603,11 +1439,9 @@ void ai_big_strafe_glide_attack()
|
||||
flight_dot_to_enemy = vm_vec_dot(&target_objp->pos, &norm_vel_vec); //Angle between flight path and target ship
|
||||
|
||||
//If we're following a path, then we shouldn't be doing glide strafe
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if (ai_big_maybe_follow_subsys_path(0))
|
||||
if ( ai_big_maybe_follow_subsys_path(0) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Gets a point on the target ship to attack, as well as distance and the angle between the nose of the attacker and that point.
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
@@ -1741,7 +1575,7 @@ void ai_big_strafe_retreat1()
|
||||
if (Missiontime - aip->submode_start_time > fl2f(1.50f)) {
|
||||
// set up goal_point for avoid path to turn towards
|
||||
aip->prev_goal_point = Pl_objp->pos;
|
||||
switch(Random::next(4)) {
|
||||
switch(rand()%4) {
|
||||
case 0:
|
||||
vm_vec_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec);
|
||||
break;
|
||||
@@ -1841,7 +1675,7 @@ void ai_big_strafe()
|
||||
|
||||
/*
|
||||
if ( aip->goal_objnum != aip->target_objnum ) {
|
||||
UNREACHABLE("The goal objnum does not match the target objnum in ai_big_strafe(), please report to the SCP!"); // what is going on here? - Get Alan
|
||||
Int3(); // what is going on here? - Get Alan
|
||||
aip->mode = AIM_NONE;
|
||||
return;
|
||||
}
|
||||
@@ -1933,10 +1767,7 @@ int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
|
||||
weapon_objp = &Objects[weapon_objnum];
|
||||
Assert(weapon_objp->type == OBJ_WEAPON);
|
||||
|
||||
if (weapon_objp->parent < 0) {
|
||||
return 0;
|
||||
}
|
||||
Assert(weapon_objp->parent < MAX_OBJECTS);
|
||||
Assert(weapon_objp->parent >= 0 && weapon_objp->parent < MAX_OBJECTS);
|
||||
parent_objp = &Objects[weapon_objp->parent];
|
||||
if ( (parent_objp->signature != weapon_objp->parent_sig) || (parent_objp->type != OBJ_SHIP) ) {
|
||||
return 0;
|
||||
|
||||
+2
-2
@@ -24,8 +24,8 @@ void ai_big_subsys_path_cleanup(ai_info *aip);
|
||||
void ai_big_strafe();
|
||||
int ai_big_maybe_enter_strafe_mode(const object *objp, int weapon_objnum);
|
||||
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp);
|
||||
void ai_big_pick_attack_point(const object *objp, const object *attacker_objp, vec3d *attack_point, float fov=1.0f);
|
||||
void ai_big_pick_attack_point_turret(const object *objp, ship_subsys *ssp, const vec3d *gpos, const vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
|
||||
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov=1.0f);
|
||||
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
|
||||
|
||||
// default distance for following subsystem path points --wookieejedi
|
||||
// the value is 5 because that was the original value specified in ai_big_maybe_follow_subsys_path()
|
||||
|
||||
+1198
-2164
File diff suppressed because it is too large.
Load diff
+344
-514
File diff suppressed because it is too large.
Load diff
+10
-78
@@ -12,30 +12,15 @@
|
||||
#ifndef _AIGOALS_H
|
||||
#define _AIGOALS_H
|
||||
|
||||
#include "ai/ai_flags.h"
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "parse/sexp.h"
|
||||
#include "scripting/lua/LuaTypes.h"
|
||||
#include "scripting/lua/LuaValue.h"
|
||||
|
||||
struct wing;
|
||||
struct ai_info;
|
||||
struct ai_goal;
|
||||
|
||||
// macros for goals which get set via sexpressions in the mission code
|
||||
|
||||
// types of ai goals -- tyese types will help us to determination on which goals should
|
||||
// have priority over others (i.e. when a player issues a goal to a wing, then a seperate
|
||||
// goal to a ship in that wing). We would probably use this type in conjunction with
|
||||
// goal priority to establish which goal to follow
|
||||
#define AIG_TYPE_EVENT_SHIP 1 // from mission event direct to ship
|
||||
#define AIG_TYPE_EVENT_WING 2 // from mission event direct to wing
|
||||
#define AIG_TYPE_PLAYER_SHIP 3 // from player direct to ship
|
||||
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
|
||||
#define AIG_TYPE_DYNAMIC 5 // created on the fly
|
||||
|
||||
#define AI_GOAL_NONE -1
|
||||
|
||||
// IMPORTANT! If you add a new AI_GOAL_x define, be sure to update the functions
|
||||
// ai_update_goal_references() and query_referenced_in_ai_goals() or else risk breaking
|
||||
// Fred. If the goal you add doesn't have a target (such as chase_any), then you don't have
|
||||
@@ -73,17 +58,14 @@ struct ai_info;
|
||||
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
|
||||
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
|
||||
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x04000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x08000000
|
||||
#define AI_GOAL_DISARM_SHIP_TACTICAL (1<<28) // 0x10000000
|
||||
#define AI_GOAL_DISABLE_SHIP_TACTICAL (1<<29) // 0x20000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x03000000
|
||||
|
||||
// now the masks for ship types
|
||||
|
||||
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
|
||||
//WMC - Don't need these anymore. Whee!
|
||||
/*
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
@@ -100,53 +82,6 @@ struct ai_info;
|
||||
|
||||
#define MAX_AI_DOCK_NAMES 25
|
||||
|
||||
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
|
||||
|
||||
struct ai_lua_parameters {
|
||||
object_ship_wing_point_team target;
|
||||
luacpp::LuaValueList arguments;
|
||||
};
|
||||
|
||||
// structure for AI goals
|
||||
typedef struct ai_goal {
|
||||
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
|
||||
int ai_mode; // one of the AIM_* modes for this goal
|
||||
int ai_submode; // maybe need a submode
|
||||
int type; // one of the AIG_TYPE_* values above
|
||||
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
|
||||
fix time; // time at which this goal was issued.
|
||||
int priority; // how important is this goal -- number 0 - 100
|
||||
|
||||
const char *target_name; // name of the thing that this goal acts upon
|
||||
int target_name_index; // index of goal_target_name in Goal_target_names[][]
|
||||
waypoint_list *wp_list; // waypoints that this ship might fly.
|
||||
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
|
||||
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)
|
||||
|
||||
// extra goal-specific data
|
||||
int int_data;
|
||||
float float_data;
|
||||
|
||||
// unions for docking stuff.
|
||||
// (AIGF_DOCKER_INDEX_VALID and AIGF_DOCKEE_INDEX_VALID tell us to use indexes; otherwise we use names)
|
||||
// these are the dockpoints used on the docker and dockee ships, not the ships themselves
|
||||
union {
|
||||
const char *name;
|
||||
int index;
|
||||
} docker;
|
||||
|
||||
union {
|
||||
const char *name;
|
||||
int index;
|
||||
} dockee;
|
||||
|
||||
ai_lua_parameters lua_ai_target;
|
||||
|
||||
} ai_goal;
|
||||
|
||||
extern void ai_goal_reset(ai_goal *aigp, bool adding_goal = false, int ai_mode = AI_GOAL_NONE, int ai_submode = -1, int type = -1);
|
||||
|
||||
|
||||
typedef flag_def_list ai_goal_list;
|
||||
|
||||
extern ai_goal_list Ai_goal_names[];
|
||||
@@ -155,10 +90,7 @@ extern int Num_ai_goals;
|
||||
extern int Num_ai_dock_names;
|
||||
extern char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
|
||||
|
||||
extern const char *Ai_goal_text(int goal, int submode);
|
||||
|
||||
// every goal in a mission gets a unique signature
|
||||
extern int Ai_goal_signature;
|
||||
extern const char *Ai_goal_text(int goal);
|
||||
|
||||
// extern function definitions
|
||||
extern void ai_post_process_mission();
|
||||
@@ -168,17 +100,17 @@ extern void ai_process_mission_orders( int objnum, ai_info *aip );
|
||||
extern int ai_goal_num(ai_goal *goals);
|
||||
|
||||
// adds goals to ships/wing through sexpressions
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, const char *shipname, ai_info *aip);
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip);
|
||||
extern void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip );
|
||||
extern void ai_add_wing_goal_sexp( int sexp, int type, wing *wingp );
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, const char *actor_name);
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name );
|
||||
|
||||
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp );
|
||||
extern void ai_remove_wing_goal_sexp( int sexp, wing *wingp );
|
||||
|
||||
// adds goals to ships/sings through player orders
|
||||
extern void ai_add_ship_goal_player(int type, int mode, int submode, const char* shipname, ai_info* aip, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_wing_goal_player(int type, int mode, int submode, const char* shipname, int wingnum, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );
|
||||
extern void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum );
|
||||
|
||||
extern void ai_remove_ship_goal( ai_info *aip, int index );
|
||||
extern void ai_clear_ship_goals( ai_info *aip );
|
||||
@@ -189,8 +121,8 @@ extern void ai_copy_mission_wing_goal( ai_goal *aigp, ai_info *aip );
|
||||
extern void ai_mission_goal_complete( ai_info *aip );
|
||||
extern void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp );
|
||||
|
||||
extern void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *old_name, const char *new_name);
|
||||
extern bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char *name);
|
||||
extern void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, const char *new_name);
|
||||
extern int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name);
|
||||
extern char *ai_add_dock_name(const char *str);
|
||||
|
||||
extern int ai_query_goal_valid( int ship, int ai_goal_type );
|
||||
|
||||
@@ -14,24 +14,24 @@
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
//Returns true if the specified object is a stealth ship, false if not
|
||||
bool is_object_stealth_ship(const object* objp);
|
||||
bool is_object_stealth_ship(object* objp);
|
||||
|
||||
//Number of live turrets on the object attacking
|
||||
int num_turrets_attacking(const object *turret_parent, int target_objnum);
|
||||
int num_turrets_attacking(object *turret_parent, int target_objnum);
|
||||
|
||||
//Determine whether an object is targetable within a nebula (checks for stealth)
|
||||
bool object_is_targetable(const object *target, const ship *viewer);
|
||||
int object_is_targetable(object *target, ship *viewer);
|
||||
|
||||
//Returns the number of enemy fighters within threshold of pos.
|
||||
int num_nearby_fighters(int enemy_team_mask, const vec3d *pos, float threshold);
|
||||
int num_nearby_fighters(int enemy_team_mask, vec3d *pos, float threshold);
|
||||
|
||||
//Returns true if OK for *aip to fire its current weapon at its current target.
|
||||
bool check_ok_to_fire(int objnum, int target_objnum, const weapon_info *wip, int secondary_bank, const vec3d *firing_pos_global);
|
||||
int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int secondary_bank, ship_subsys* turret);
|
||||
|
||||
//Returns true if *aip has a line of sight to its current target.
|
||||
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, const vec3d *firing_pos_global);
|
||||
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, ship_subsys* turret);
|
||||
|
||||
//Does all the stuff needed to aim and fire a turret.
|
||||
void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss);
|
||||
void ai_fire_from_turret(ship *shipp, ship_subsys *ss);
|
||||
|
||||
#endif
|
||||
@@ -1,414 +0,0 @@
|
||||
#include "ai/ailua.h"
|
||||
|
||||
#include "hud/hudsquadmsg.h"
|
||||
#include "iff_defs/iff_defs.h"
|
||||
#include "parse/sexp/sexp_lookup.h"
|
||||
#include "parse/sexp/LuaAISEXP.h"
|
||||
#include "scripting/api/objs/ai_helper.h"
|
||||
#include "scripting/api/objs/enums.h"
|
||||
#include "scripting/api/objs/oswpt.h"
|
||||
#include "scripting/api/objs/ship.h"
|
||||
#include "scripting/scripting.h"
|
||||
|
||||
static std::unordered_map<int, ai_mode_lua> Lua_ai_modes;
|
||||
static std::unordered_map<int, player_order_lua> Lua_player_orders;
|
||||
|
||||
void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode) {
|
||||
Lua_ai_modes.emplace(sexp_op, mode);
|
||||
}
|
||||
|
||||
bool ai_lua_add_order(int sexp_op, player_order_lua order) {
|
||||
Player_orders.emplace_back(order.parseText, order.displayText, -1, sexp_op);
|
||||
Player_orders.back().localize();
|
||||
|
||||
Lua_player_orders.emplace(sexp_op, std::move(order));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ai_lua_has_mode(int sexp_op){
|
||||
return Lua_ai_modes.count(sexp_op) > 0;
|
||||
}
|
||||
|
||||
const ai_mode_lua* ai_lua_find_mode(int sexp_op){
|
||||
auto aiLuaMode = Lua_ai_modes.find(sexp_op);
|
||||
|
||||
if(aiLuaMode == Lua_ai_modes.end())
|
||||
return nullptr;
|
||||
else
|
||||
return &aiLuaMode->second;
|
||||
}
|
||||
|
||||
const player_order_lua* ai_lua_find_player_order(int sexp_op) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return nullptr;
|
||||
else
|
||||
return &aiLuaOrder->second;
|
||||
}
|
||||
|
||||
int ai_lua_get_num_general_orders() {
|
||||
int count = 0;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.generalOrder) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only)
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
const SCP_string &cat = order.second.category;
|
||||
|
||||
// If it's not a general order then move on
|
||||
if (!order.second.generalOrder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the order is not enabled then move on
|
||||
if (enabled_only && !order.second.cur_enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assertion((cat.length() > 0), "Lua general orders category name must be longer than 0 characters!");
|
||||
|
||||
for (size_t i = 0; i <= list.size(); i++) {
|
||||
|
||||
// reached the end of the list, so add it
|
||||
if (i == list.size()) {
|
||||
list.push_back(cat);
|
||||
break;
|
||||
}
|
||||
|
||||
// if it's already in the list then don't add it
|
||||
if (cat == list[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Provides a list of general orders for mission saving. You can only get one kind
|
||||
// of list at a time. If onlyEnabled and onlyValid are both true, for example, you will get
|
||||
// a list of onlyEnabled orders. If you need a list of enabled orders that are also valid, you'll
|
||||
// need to get both lists separately and compare.
|
||||
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled, bool onlyValid, const SCP_string& category)
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.generalOrder) {
|
||||
bool add = false;
|
||||
|
||||
// All general orders
|
||||
if (!onlyEnabled && !onlyValid && category.empty()) {
|
||||
add = true;
|
||||
} else {
|
||||
|
||||
// Only enabled orders
|
||||
if (onlyEnabled && order.second.cur_enabled) {
|
||||
add = true;
|
||||
|
||||
// Only valid orders
|
||||
} else if (onlyValid && order.second.cur_valid) {
|
||||
add = true;
|
||||
|
||||
// Only orders that match the category requested
|
||||
} else if ((!category.empty()) && (order.second.category == category)) {
|
||||
add = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (add) {
|
||||
list.push_back(order.second.parseText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int ai_lua_find_general_order_id(const SCP_string& name) {
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.parseText == name) {
|
||||
return order.first;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ai_lua_enable_general_order(int sexp_op, bool enable) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return;
|
||||
else
|
||||
aiLuaOrder->second.cur_enabled = enable;
|
||||
}
|
||||
|
||||
void ai_lua_validate_general_order(int sexp_op, bool validity)
|
||||
{
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return;
|
||||
else
|
||||
aiLuaOrder->second.cur_valid = validity;
|
||||
}
|
||||
|
||||
void ai_lua_reset_general_orders() {
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
ai_lua_enable_general_order(order.first, false);
|
||||
ai_lua_validate_general_order(order.first, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool ai_lua_is_general_order(int sexp_op) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return false;
|
||||
|
||||
return aiLuaOrder->second.generalOrder;
|
||||
}
|
||||
|
||||
void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua_ai, ai_info* aip) {
|
||||
if (!action.isValid()) {
|
||||
Error(LOCATION,
|
||||
"Lua AI SEXP called without a valid action function! A script probably failed to set the action for some reason.");
|
||||
return;
|
||||
}
|
||||
|
||||
luacpp::LuaValueList luaParameters;
|
||||
if (aip->shipnum >= 0){
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
|
||||
} else {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h())));
|
||||
}
|
||||
if (lua_ai.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
|
||||
}
|
||||
for (const auto& additionalParam : aip->lua_ai_target.arguments) {
|
||||
luaParameters.push_back(additionalParam);
|
||||
}
|
||||
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
|
||||
if (retVals[0].getValue<bool>()) {
|
||||
|
||||
// If we don't have a ship then it's a general order and we have nothing else to do
|
||||
if (aip->shipnum >= 0) {
|
||||
ai_mission_goal_complete(aip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ai_lua(ai_info* aip){
|
||||
Assertion(aip->mode == AIM_LUA, "Tried to invoke LuaAI on a ship not in LuaAI-Mode");
|
||||
|
||||
const auto& lua_ai = Lua_ai_modes.at(aip->submode);
|
||||
|
||||
const auto& lua_ai_sexp = lua_ai.sexp;
|
||||
const auto& action = lua_ai_sexp.getAction();
|
||||
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
|
||||
void ai_lua_start(ai_goal* aigp, object* objp){
|
||||
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
|
||||
|
||||
ai_info *aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
|
||||
aip->mode = AIM_LUA;
|
||||
aip->submode = aigp->ai_submode;
|
||||
aip->lua_ai_target = aigp->lua_ai_target;
|
||||
aip->submode_start_time = Missiontime;
|
||||
|
||||
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
|
||||
|
||||
const auto& lua_ai_sexp = lua_ai.sexp;
|
||||
const auto& action = lua_ai_sexp.getActionEnter();
|
||||
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
|
||||
// For sending general orders that don't run on a ship.
|
||||
// Essentially just runs arbitrary lua script when the command is called
|
||||
void ai_lua_start_general(int lua_sexp_id, int target_objnum)
|
||||
{
|
||||
//Create a dummy aip to pass the target data
|
||||
ai_info aip;
|
||||
aip.shipnum = -1;
|
||||
|
||||
if (target_objnum >= 0 && Objects[target_objnum].type == OBJ_SHIP) {
|
||||
aip.lua_ai_target = {object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]), {}};
|
||||
}
|
||||
|
||||
const auto& lua_ai = ai_lua_find_mode(lua_sexp_id);
|
||||
|
||||
const auto& lua_ai_sexp = lua_ai->sexp;
|
||||
const auto& action = lua_ai_sexp.getActionEnter();
|
||||
|
||||
run_ai_lua_action(action, *lua_ai, &aip);
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self) {
|
||||
ship* target = &Ships[Objects[target_objnum].instance];
|
||||
|
||||
const player_order_lua& order = *ai_lua_find_player_order(sexp_op);
|
||||
switch (order.targetRestrictions) {
|
||||
case player_order_lua::target_restrictions::TARGET_ALL:
|
||||
return true;
|
||||
case player_order_lua::target_restrictions::TARGET_OWN:
|
||||
return target->team == self->team;
|
||||
case player_order_lua::target_restrictions::TARGET_ALLIES:
|
||||
return !iff_x_attacks_y(self->team, target->team);
|
||||
case player_order_lua::target_restrictions::TARGET_ENEMIES:
|
||||
return iff_x_attacks_y(self->team, target->team);
|
||||
case player_order_lua::target_restrictions::TARGET_SAME_WING:
|
||||
return target->wingnum != -1 && self->wingnum == target->wingnum;
|
||||
case player_order_lua::target_restrictions::TARGET_PLAYER_WING:
|
||||
return target->wingnum != -1 && Ships[Player_obj->instance].wingnum == target->wingnum;
|
||||
case player_order_lua::target_restrictions::TARGET_ALL_CAPS:
|
||||
return Ship_info[target->ship_info_index].is_big_ship();
|
||||
case player_order_lua::target_restrictions::TARGET_ALLIED_CAPS:
|
||||
return !iff_x_attacks_y(self->team, target->team) && Ship_info[target->ship_info_index].is_big_ship();
|
||||
case player_order_lua::target_restrictions::TARGET_ENEMY_CAPS:
|
||||
return iff_x_attacks_y(self->team, target->team) && Ship_info[target->ship_info_index].is_big_ship();
|
||||
case player_order_lua::target_restrictions::TARGET_NOT_SELF:
|
||||
return self->objnum != target_objnum;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target_lua(const ai_mode_lua& mode, int target_objnum, ship* self) {
|
||||
|
||||
const auto& action = mode.sexp.getTargetRestrict();
|
||||
|
||||
if (!action.isValid())
|
||||
return true;
|
||||
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[self->objnum]))));
|
||||
if (mode.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]))));
|
||||
}
|
||||
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
|
||||
return retVals[0].getValue<bool>();
|
||||
}
|
||||
else {
|
||||
Error(LOCATION, "LuaAI target restriction function did not return a valid boolean!");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order) {
|
||||
const ai_mode_lua& mode = *ai_lua_find_mode(sexp_op);
|
||||
|
||||
//All targetless AI modes are fine
|
||||
if (mode.needsTarget) {
|
||||
|
||||
//No target is then not valid
|
||||
if (target_objnum == -1)
|
||||
return false;
|
||||
|
||||
//As of now, only accept ships
|
||||
if (Objects[target_objnum].type != OBJ_SHIP)
|
||||
return false;
|
||||
|
||||
if (!ai_lua_is_valid_target_intrinsic(sexp_op, target_objnum, self))
|
||||
return false;
|
||||
|
||||
// check if this order can be issued against the target
|
||||
ship *shipp = &Ships[Objects[target_objnum].instance];
|
||||
if (shipp->orders_allowed_against.find(order) == shipp->orders_allowed_against.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//If we haven't bailed yet, query the custom callback
|
||||
return ai_lua_is_valid_target_lua(mode, target_objnum, self);
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self)
|
||||
{
|
||||
const player_order_lua& order = *ai_lua_find_player_order(sexp_op);
|
||||
|
||||
switch (order.shipRestrictions) {
|
||||
case player_order_lua::ship_restrictions::ANY:
|
||||
return true;
|
||||
case player_order_lua::ship_restrictions::WING:
|
||||
return isWing;
|
||||
case player_order_lua::ship_restrictions::IN_PLAYER_WING:
|
||||
return self->wingnum != -1 && Ships[Player_obj->instance].wingnum == self->wingnum;
|
||||
case player_order_lua::ship_restrictions::PLAYER_WING:
|
||||
return isWing && self->wingnum != -1 && Ships[Player_obj->instance].wingnum == self->wingnum;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum){
|
||||
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
|
||||
|
||||
const auto& action = lua_ai.sexp.getAchievable();
|
||||
|
||||
if (!action.isValid())
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[objnum]))));
|
||||
if (lua_ai.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aigp->lua_ai_target.target)));
|
||||
}
|
||||
for (const auto& additionalParam : aigp->lua_ai_target.arguments) {
|
||||
luaParameters.push_back(additionalParam);
|
||||
}
|
||||
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::USERDATA) {
|
||||
scripting::api::enum_h enumData;
|
||||
retVals[0].getValue(scripting::api::l_Enum.Get(&enumData));
|
||||
if (!enumData.isValid()) {
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
|
||||
switch (enumData.index) {
|
||||
case scripting::api::LE_LUAAI_ACHIEVABLE:
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
case scripting::api::LE_LUAAI_NOT_YET_ACHIEVABLE:
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
case scripting::api::LE_LUAAI_UNACHIEVABLE:
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
default:
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook did not return any avilability enum!");
|
||||
}
|
||||
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ai/ai.h"
|
||||
#include "ai/aigoals.h"
|
||||
#include "mission/missionmessage.h"
|
||||
#include "ship/ship.h"
|
||||
#include "parse/sexp.h"
|
||||
#include "globalincs/globals.h"
|
||||
|
||||
namespace sexp { class LuaAISEXP; }
|
||||
|
||||
struct ai_mode_lua {
|
||||
const sexp::LuaAISEXP& sexp;
|
||||
bool needsTarget;
|
||||
const char* hudText;
|
||||
};
|
||||
|
||||
struct player_order_lua {
|
||||
int ai_message = MESSAGE_YESSIR;
|
||||
SCP_string parseText = "";
|
||||
SCP_string displayText = "";
|
||||
bool generalOrder = false;
|
||||
SCP_string category = "";
|
||||
bool cur_enabled = false;
|
||||
bool cur_valid = false;
|
||||
enum class target_restrictions : int { TARGET_ALLIES, TARGET_ALL, TARGET_OWN, TARGET_ENEMIES, TARGET_SAME_WING, TARGET_PLAYER_WING, TARGET_ALL_CAPS, TARGET_ALLIED_CAPS, TARGET_ENEMY_CAPS, TARGET_NOT_SELF } targetRestrictions = target_restrictions::TARGET_ALL;
|
||||
enum class ship_restrictions : int { ANY, WING, IN_PLAYER_WING, PLAYER_WING } shipRestrictions = ship_restrictions::ANY;
|
||||
};
|
||||
|
||||
|
||||
void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode);
|
||||
bool ai_lua_add_order(int sexp_op, player_order_lua order);
|
||||
bool ai_lua_has_mode(int sexp_op);
|
||||
const ai_mode_lua* ai_lua_find_mode(int sexp_op);
|
||||
const player_order_lua* ai_lua_find_player_order(int sexp_op);
|
||||
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only = true);
|
||||
int ai_lua_get_num_general_orders();
|
||||
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled = false, bool onlyValid = false, const SCP_string& category = "");
|
||||
int ai_lua_find_general_order_id(const SCP_string& name);
|
||||
void ai_lua_enable_general_order(int sexp_op, bool enable);
|
||||
void ai_lua_validate_general_order(int sexp_op, bool validity);
|
||||
void ai_lua_reset_general_orders();
|
||||
bool ai_lua_is_general_order(int sexp_op);
|
||||
void ai_lua(ai_info* aip);
|
||||
void ai_lua_start(ai_goal* aigp, object* objp);
|
||||
void ai_lua_start_general(int lua_sexp_id, int target_objnum);
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order);
|
||||
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self);
|
||||
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
|
||||
+461
-507
File diff suppressed because it is too large.
Load diff
@@ -397,6 +397,8 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
|
||||
|
||||
t1 = timer_get_fixed_seconds();
|
||||
for ( i = 0; i < frame_diff; i++ ) {
|
||||
anim_check_for_palette_change(instance);
|
||||
|
||||
// if we're playing backwards, every frame must be a keyframe and we set the data ptr here
|
||||
if(instance->direction == ANIM_DIRECT_REVERSE){
|
||||
if ( anim_instance_is_streamed(instance) ) {
|
||||
@@ -641,7 +643,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
|
||||
if (diff != 0) {
|
||||
if (ptr->height > 16) {
|
||||
nprintf(("ANI","ANI %s with size %dx%d (%.1f%% wasted)\n", ptr->name, ptr->width, ptr->height, waste));
|
||||
mprintf(("ANI %s with size %dx%d (%.1f%% wasted)\n", ptr->name, ptr->width, ptr->height, waste));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -670,7 +672,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
* @param file_mapped Whether to use memory-mapped file or not.
|
||||
*
|
||||
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
|
||||
* @return Pointer to anim that is loaded if success, NULL if failure.
|
||||
* @return Pointer to anim that is loaded if sucess, NULL if failure.
|
||||
*/
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
{
|
||||
@@ -788,6 +790,9 @@ anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
|
||||
cfclose(fp);
|
||||
|
||||
// store screen signature, so we can tell if palette changes
|
||||
ptr->screen_sig = gr_screen.signature;
|
||||
|
||||
anim_set_palette(ptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,23 +18,30 @@
|
||||
const int packer_code = PACKER_CODE;
|
||||
const int transparent_code = 254;
|
||||
|
||||
void anim_check_for_palette_change(anim_instance *instance) {
|
||||
if ( instance->parent->screen_sig != gr_screen.signature ) {
|
||||
instance->parent->screen_sig = gr_screen.signature;
|
||||
anim_set_palette(instance->parent);
|
||||
}
|
||||
}
|
||||
|
||||
anim_instance *init_anim_instance(anim *ptr, int bpp)
|
||||
{
|
||||
anim_instance *inst;
|
||||
|
||||
Assertion(ptr, "Bad pointer in init_anim_instance(), please report to the SCP!");
|
||||
if (!ptr) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( ptr->flags & ANF_STREAMED ) {
|
||||
Assertion(ptr->file_offset > -1, "Bad file offset of %d in init_anim_instance(), please report to the SCP!", ptr->file_offset);
|
||||
if ( ptr->file_offset < 0 ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
Assertion(ptr->data, "Bad data in init_anim_instance(), please report to the SCP!");
|
||||
if ( !ptr->data ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -90,6 +97,8 @@ ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap
|
||||
return NULL;
|
||||
}
|
||||
|
||||
anim_check_for_palette_change(inst);
|
||||
|
||||
if ( anim_instance_is_streamed(inst) ) {
|
||||
if ( xlate_pal ){
|
||||
inst->file_offset = unpack_frame_from_file(inst, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef struct anim {
|
||||
ubyte xparent_g; // green component for the transparent color in source image
|
||||
ubyte xparent_b; // blue component for the transparent color in source image
|
||||
int flags;
|
||||
uint screen_sig;
|
||||
int file_offset; // file offset to start of frame data
|
||||
int cache_file_offset;
|
||||
ubyte *cache;
|
||||
@@ -104,6 +105,7 @@ anim_instance *init_anim_instance(anim *ptr, int bpp);
|
||||
void free_anim_instance(anim_instance *inst);
|
||||
ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp);
|
||||
void anim_set_palette(anim *a);
|
||||
void anim_check_for_palette_change(anim_instance *inst);
|
||||
|
||||
|
||||
#endif /* __PACKUNPACK_H__ */
|
||||
+516
-1086
File diff suppressed because it is too large.
Load diff
+31
-50
@@ -14,28 +14,29 @@
|
||||
|
||||
#include "globalincs/globals.h" // for NAME_LENGTH
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "io/timer.h"
|
||||
|
||||
|
||||
class object;
|
||||
class polymodel;
|
||||
struct collision_info_struct;
|
||||
class model_draw_list;
|
||||
|
||||
#define MAX_ASTEROIDS 2000 //Increased from 512 to 2000 in 2022
|
||||
#define MAX_ASTEROIDS 512
|
||||
|
||||
#define NUM_ASTEROID_SIZES 3
|
||||
#define NUM_DEBRIS_SIZES 3
|
||||
#define NUM_DEBRIS_POFS 3 // Number of POFs per debris size
|
||||
|
||||
#define ASTEROID_TYPE_DEBRIS -1
|
||||
#define ASTEROID_TYPE_SMALL 0
|
||||
#define ASTEROID_TYPE_MEDIUM 1
|
||||
#define ASTEROID_TYPE_LARGE 2
|
||||
|
||||
// Only used for parsing & saving retail compatible mission files
|
||||
#define MAX_RETAIL_DEBRIS_TYPES 3
|
||||
// these should always be equal for the benefit of generic asteroids (c.f. asteroid_page_in)
|
||||
#define MAX_ACTIVE_DEBRIS_TYPES NUM_DEBRIS_SIZES
|
||||
|
||||
// Goober5000 - currently same as MAX_SHIP_DETAIL_LEVELS (put here to avoid an #include)
|
||||
#define MAX_ASTEROID_DETAIL_LEVELS 5
|
||||
|
||||
|
||||
// Data structure to track the active asteroids
|
||||
typedef struct asteroid_obj {
|
||||
asteroid_obj *next, *prev;
|
||||
@@ -47,29 +48,19 @@ extern asteroid_obj Asteroid_obj_list;
|
||||
// Data structure for determining a type and amount of other asteroids an
|
||||
// asteroid will split to when destroyed.
|
||||
typedef struct asteroid_split_info {
|
||||
int asteroid_type; //index position
|
||||
char name[NAME_LENGTH]; //asteroid name
|
||||
int min; //minimum asteroids to spawn
|
||||
int max; //maximum asteroids to spawn
|
||||
int asteroid_type;
|
||||
int min;
|
||||
int max;
|
||||
} asteroid_split_info;
|
||||
|
||||
// Data structure for storing asteroid subtype info. POFs, model pointer, model num, etc.
|
||||
typedef struct asteroid_subtype_info {
|
||||
char pof_filename[MAX_FILENAME_LEN];
|
||||
polymodel* model_pointer;
|
||||
int model_number;
|
||||
SCP_string type_name;
|
||||
} asteroid_subtype_info;
|
||||
|
||||
class asteroid_info
|
||||
{
|
||||
public:
|
||||
char name[NAME_LENGTH]; // name for the asteroid
|
||||
int type; // type of asteroid, 0 = small, 1 = medium, 2 = large, -1 = debris
|
||||
int num_detail_levels; // number of detail levels for this asteroid
|
||||
char pof_files[NUM_DEBRIS_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
|
||||
int num_detail_levels; // number of detail levels for this ship
|
||||
int detail_distance[MAX_ASTEROID_DETAIL_LEVELS]; // distance to change detail levels at
|
||||
float max_speed; // cap on speed for asteroid
|
||||
float rotational_vel_multiplier; // rotational velocity multiplier for asteroid --wookieejedi
|
||||
int damage_type_idx; //Damage type of the asteroid
|
||||
int damage_type_idx_sav; // stored value from table used to reset damage_type_idx
|
||||
float inner_rad; // radius within which maximum area effect damage is applied
|
||||
@@ -78,23 +69,26 @@ public:
|
||||
float blast; // maximum blast impulse from area effect explosion
|
||||
float initial_asteroid_strength; // starting strength of asteroid
|
||||
SCP_vector< asteroid_split_info > split_info;
|
||||
polymodel *modelp[NUM_DEBRIS_POFS];
|
||||
int model_num[NUM_DEBRIS_POFS];
|
||||
SCP_vector<int> explosion_bitmap_anims;
|
||||
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
|
||||
SCP_string display_name; // only used for hud targeting display and for debris
|
||||
float spawn_weight; // debris only, relative proportion to spawn compared to other types in its asteroid field
|
||||
float gravity_const; // multiplier for mission gravity
|
||||
SCP_vector<asteroid_subtype_info> subtypes;
|
||||
|
||||
asteroid_info( )
|
||||
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0),
|
||||
rotational_vel_multiplier(1), damage_type_idx(0),
|
||||
: num_detail_levels( 0 ), max_speed( 0 ), damage_type_idx( 0 ),
|
||||
damage_type_idx_sav( -1 ), inner_rad( 0 ), outer_rad( 0 ),
|
||||
damage( 0 ), blast( 0 ), initial_asteroid_strength( 0 ),
|
||||
fireball_radius_multiplier( -1 ), spawn_weight( 1 ), gravity_const( 0 )
|
||||
fireball_radius_multiplier( -1 )
|
||||
{
|
||||
name[ 0 ] = 0;
|
||||
display_name = "";
|
||||
memset( detail_distance, 0, sizeof( detail_distance ) );
|
||||
|
||||
for (int i = 0; i < NUM_DEBRIS_POFS; i++)
|
||||
{
|
||||
modelp[i] = NULL;
|
||||
model_num[i] = -1;
|
||||
pof_files[i][0] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -107,9 +101,9 @@ typedef struct asteroid {
|
||||
int model_instance_num;
|
||||
int asteroid_type; // 0..MAX_DEBRIS_TYPES
|
||||
int asteroid_subtype; // Index in asteroid_info for modelnum and modelp
|
||||
TIMESTAMP check_for_wrap; // timestamp to check for asteroid wrapping around field
|
||||
TIMESTAMP check_for_collide; // timestamp to check for asteroid colliding with escort ships
|
||||
TIMESTAMP final_death_time; // timestamp to swap in new models after explosion starts
|
||||
int check_for_wrap; // timestamp to check for asteroid wrapping around field
|
||||
int check_for_collide; // timestamp to check for asteroid colliding with escort ships
|
||||
int final_death_time; // timestamp to swap in new models after explosion starts
|
||||
int collide_objnum; // set to objnum that asteroid will be impacting soon
|
||||
int collide_objsig; // object signature corresponding to collide_objnum
|
||||
vec3d death_hit_pos; // hit pos that caused death
|
||||
@@ -120,7 +114,7 @@ typedef struct asteroid {
|
||||
// TYPEDEF FOR DEBRIS TYPE
|
||||
typedef enum {
|
||||
DG_ASTEROID,
|
||||
DG_DEBRIS
|
||||
DG_SHIP
|
||||
} debris_genre_t;
|
||||
|
||||
// TYPEDEF FOR FIELD TYPE
|
||||
@@ -133,7 +127,7 @@ typedef struct asteroid_field {
|
||||
vec3d min_bound; // Minimum range of field.
|
||||
vec3d max_bound; // Maximum range of field.
|
||||
float bound_rad;
|
||||
bool has_inner_bound;
|
||||
int has_inner_bound;
|
||||
vec3d inner_min_bound;
|
||||
vec3d inner_max_bound;
|
||||
vec3d vel; // Average asteroid moves at this velocity.
|
||||
@@ -141,11 +135,7 @@ typedef struct asteroid_field {
|
||||
int num_initial_asteroids; // Number of asteroids at creation.
|
||||
field_type_t field_type; // active throws and wraps, passive does not
|
||||
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
|
||||
SCP_vector<int> field_debris_type; // one of the debris type defines above
|
||||
SCP_vector<SCP_string> field_asteroid_type; // one of the asteroid subtypes
|
||||
bool enhanced_visibility_checks; // if true then range checks are overridden for spawning and wrapping asteroids in the field
|
||||
|
||||
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
|
||||
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
|
||||
} asteroid_field;
|
||||
|
||||
extern SCP_vector< asteroid_info > Asteroid_info;
|
||||
@@ -159,29 +149,20 @@ extern vec3d Asteroid_icon_closeup_position; // closeup position for asteroid f
|
||||
extern float Asteroid_icon_closeup_zoom; // zoom position for asteroid field briefing icon rendering
|
||||
|
||||
void asteroid_init();
|
||||
bool asteroid_is_within_view(vec3d *pos, float range, bool range_override = false);
|
||||
void asteroid_level_init();
|
||||
void asteroid_level_close();
|
||||
void asteroid_create_all();
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> asteroid_types);
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vector<int> debris_types, vec3d o_min, vec3d o_max, bool enhanced);
|
||||
void asteroid_render(object* obj, model_draw_list* scene);
|
||||
void asteroid_render(object * obj, model_draw_list *scene);
|
||||
void asteroid_delete( object *asteroid_objp );
|
||||
void asteroid_process_pre( object *asteroid_objp );
|
||||
void asteroid_process_post( object *asteroid_objp);
|
||||
int asteroid_check_collision( object *asteroid_objp, object * other_obj, vec3d * hitpos, collision_info_struct *asteroid_hit_info=NULL, vec3d* hitnormal=NULL );
|
||||
void asteroid_hit( object *pasteroid_objp, object *other_objp, vec3d *hitpos, float damage, vec3d* force );
|
||||
void asteroid_hit( object *pasteroid_objp, object *other_objp, vec3d *hitpos, float damage );
|
||||
int asteroid_count();
|
||||
int asteroid_collide_objnum(object *asteroid_objp);
|
||||
float asteroid_time_to_impact(object *asteroid_objp);
|
||||
void asteroid_show_brackets();
|
||||
void asteroid_target_closest_danger();
|
||||
void asteroid_add_target(object* objp);
|
||||
int get_asteroid_index(const char* asteroid_name);
|
||||
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes();
|
||||
|
||||
// need to extern for keycontrol debug commands
|
||||
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility = false);
|
||||
|
||||
// need to extern for multiplayer
|
||||
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
|
||||
|
||||
@@ -47,9 +47,10 @@ NavMessage NavMsgs[NP_NUM_MESSAGES];
|
||||
int audio_handle;
|
||||
int NavLinkDistance;
|
||||
// time offsets for autonav events
|
||||
TIMESTAMP LockAPConv;
|
||||
TIMESTAMP EndAPCinematic;
|
||||
TIMESTAMP MoveCamera;
|
||||
int LockAPConv;
|
||||
int EndAPCinematic;
|
||||
int MoveCamera;
|
||||
int camMovingTime;
|
||||
//float CameraSpeed;
|
||||
bool CinematicStarted, CameraMoving;
|
||||
vec3d cameraPos, cameraTarget;
|
||||
@@ -150,9 +151,6 @@ bool CanAutopilot(const vec3d *targetPos, bool send_msg)
|
||||
for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
|
||||
{
|
||||
object *other_objp = &Objects[so->objnum];
|
||||
if (other_objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
// attacks player?
|
||||
if (iff_x_attacks_y(obj_team(other_objp), obj_team(Player_obj))
|
||||
&& !(Ship_info[Ships[other_objp->instance].ship_info_index].flags[Ship::Info_Flags::Cargo])) // ignore cargo
|
||||
@@ -208,9 +206,8 @@ bool StartAutopilot()
|
||||
{
|
||||
// Check for support ship and dismiss it if it is not doing anything.
|
||||
// If the support ship is doing something then tell the user such.
|
||||
for (auto so: list_range(&Ship_obj_list))
|
||||
for ( object *objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
|
||||
{
|
||||
auto objp = &Objects[so->objnum];
|
||||
if ((objp->type == OBJ_SHIP) && !(objp->flags[Object::Object_Flags::Should_be_dead]))
|
||||
{
|
||||
Assertion((objp->instance >= 0) && (objp->instance < MAX_SHIPS),
|
||||
@@ -265,9 +262,9 @@ bool StartAutopilot()
|
||||
}
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics])
|
||||
LockAPConv = _timestamp(); // lock convergence instantly
|
||||
LockAPConv = timestamp(); // lock convergence instantly
|
||||
else
|
||||
LockAPConv = _timestamp(3 * MILLISECONDS_PER_SECOND); // 3 seconds before we lock convergence
|
||||
LockAPConv = timestamp(3000); // 3 seconds before we lock convergence
|
||||
Player_use_ai = 1;
|
||||
set_time_compression(1);
|
||||
lock_time_compression(true);
|
||||
@@ -405,7 +402,7 @@ bool StartAutopilot()
|
||||
&& Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
|
||||
{
|
||||
ai_info *aip = &Ai_info[Ships[i].ai_index];
|
||||
int wingnum = Ships[i].wingnum, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
|
||||
int wingnum = aip->wing, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
|
||||
vec3d goal_point;
|
||||
object *leader_objp = get_wing_leader(wingnum);
|
||||
|
||||
@@ -719,7 +716,7 @@ bool StartAutopilot()
|
||||
vm_vec_scale(&pos, 5*speed_cap*tc_factor); // pos is now scaled by 5 times the speed (5 seconds ahead)
|
||||
vm_vec_add(&pos, &pos, &Autopilot_flight_leader->pos); // pos is now 5*speed cap in front of player ship
|
||||
|
||||
switch (Random::next(24))
|
||||
switch (myrand()%24)
|
||||
// 8 different ways of getting perp points
|
||||
// 4 of which will not be used when capships are present (anything below, or straight above)
|
||||
{
|
||||
@@ -798,8 +795,7 @@ bool StartAutopilot()
|
||||
vm_vec_scale(&perp, Autopilot_flight_leader->radius+radius);
|
||||
|
||||
// randomly scale up/down by up to 20%
|
||||
// jg18 - original comment said [-20,20] but preserving existing behavior
|
||||
j = Random::next(-19, 20);
|
||||
j = 20-myrand()%40; // [-20,20]
|
||||
|
||||
vm_vec_scale(&perp, 1.0f+(float(j)/100.0f));
|
||||
vm_vec_add(&cameraPos, &pos, &perp);
|
||||
@@ -831,8 +827,9 @@ bool StartAutopilot()
|
||||
//CameraMoving = false;
|
||||
|
||||
|
||||
EndAPCinematic = _timestamp((10 * MILLISECONDS_PER_SECOND * tc_factor) + NPS_TICKRATE); // 10 objective seconds before end of cinematic
|
||||
MoveCamera = _timestamp(fl2i(5.5 * MILLISECONDS_PER_SECOND * tc_factor) + NPS_TICKRATE);
|
||||
EndAPCinematic = timestamp((10000*tc_factor)+NPS_TICKRATE); // 10 objective seconds before end of cinematic
|
||||
MoveCamera = timestamp((5500*tc_factor)+NPS_TICKRATE);
|
||||
camMovingTime = int(4.5*float(tc_factor));
|
||||
set_time_compression((float)tc_factor);
|
||||
}
|
||||
|
||||
@@ -869,7 +866,7 @@ void EndAutoPilot()
|
||||
Assert( CurrentNav >= 0 );
|
||||
|
||||
int goal = 0;
|
||||
const char *goal_name = NULL;
|
||||
char *goal_name = NULL;
|
||||
|
||||
if (Navs[CurrentNav].flags & NP_WAYPOINT)
|
||||
{
|
||||
@@ -925,7 +922,10 @@ void EndAutoPilot()
|
||||
if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
|
||||
&& (aigp->ai_mode == goal) )
|
||||
{
|
||||
ai_goal_reset(aigp);
|
||||
aigp->ai_mode = AI_GOAL_NONE;
|
||||
aigp->signature = -1;
|
||||
aigp->priority = -1;
|
||||
aigp->flags.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -946,7 +946,10 @@ void EndAutoPilot()
|
||||
if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
|
||||
&& (aigp->ai_mode == goal) )
|
||||
{
|
||||
ai_goal_reset(aigp);
|
||||
aigp->ai_mode = AI_GOAL_NONE;
|
||||
aigp->signature = -1;
|
||||
aigp->priority = -1;
|
||||
aigp->flags.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1011,7 +1014,7 @@ void nav_warp(bool prewarp=false)
|
||||
vm_vec_scale(&velocity, (float)Ai_info[Ships[Autopilot_flight_leader->instance].ai_index].waypoint_speed_cap);
|
||||
|
||||
// Find all ships that are supposed to autopilot with the player and move them
|
||||
// to the cinematic location or the final destination
|
||||
// to the cinimatic location or the final destination
|
||||
for (int i = 0; i < MAX_SHIPS; i++)
|
||||
{
|
||||
if (Ships[i].objnum != -1
|
||||
@@ -1020,12 +1023,11 @@ void nav_warp(bool prewarp=false)
|
||||
{
|
||||
vm_vec_add(&Objects[Ships[i].objnum].pos, &Objects[Ships[i].objnum].pos, &targetPos);
|
||||
Objects[Ships[i].objnum].phys_info.vel = velocity;
|
||||
|
||||
// retime collision pairs
|
||||
if (Objects[Ships[i].objnum].flags[Object::Object_Flags::Collides])
|
||||
obj_collide_obj_cache_stale(&Objects[Ships[i].objnum]);
|
||||
}
|
||||
}
|
||||
|
||||
// retime all collision pairs
|
||||
obj_collide_retime_cached_pairs();
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
@@ -1050,13 +1052,15 @@ void NavSystem_Do()
|
||||
if(cam != NULL)
|
||||
cam->set_rotation_facing(&Player_obj->pos);
|
||||
|
||||
if (timestamp_elapsed(MoveCamera) && !CameraMoving && vm_vec_mag(&cameraTarget) > 0.0f)
|
||||
if (timestamp() >= MoveCamera && !CameraMoving && vm_vec_mag(&cameraTarget) > 0.0f)
|
||||
{
|
||||
//Free_camera->set_position(&cameraTarget, float(camMovingTime), float(camMovingTime)/2.0f);
|
||||
//Free_camera->set_translation_velocity(&cameraTarget);
|
||||
CameraMoving = true;
|
||||
}
|
||||
|
||||
|
||||
if (timestamp_elapsed(EndAPCinematic) || !CanAutopilot())
|
||||
if (timestamp() >= EndAPCinematic || !CanAutopilot())
|
||||
{
|
||||
nav_warp();
|
||||
EndAutoPilot();
|
||||
@@ -1184,10 +1188,6 @@ void send_autopilot_msgID(int msgid)
|
||||
if (msgid < 0 || msgid >= NP_NUM_MESSAGES)
|
||||
return;
|
||||
|
||||
// bail out if message is not set
|
||||
if (NavMsgs[msgid].message[0] == '\0')
|
||||
return;
|
||||
|
||||
send_autopilot_msg(NavMsgs[msgid].message, NavMsgs[msgid].filename);
|
||||
}
|
||||
// ********************************************************************************************
|
||||
@@ -1217,7 +1217,7 @@ void send_autopilot_msg(const char *msg, const char *snd)
|
||||
}
|
||||
|
||||
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
|
||||
message_training_queue("autopilot builtin message", TIMESTAMP::immediate(), 5); // display message for five seconds
|
||||
message_training_queue("autopilot builtin message", timestamp(0), 5); // display message for five seconds
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
@@ -1227,15 +1227,6 @@ void NavSystem_Init()
|
||||
for (int i = 0; i < MAX_NAVPOINTS; i++)
|
||||
Navs[i].clear();
|
||||
|
||||
//Initialize all these as empty strings so we can detect and bail out later -Mjn
|
||||
for (int i = 0; i < NP_NUM_MESSAGES; i++)
|
||||
NavMsgs[i].message[0] = '\0';
|
||||
|
||||
//Set defaults here before parsing
|
||||
NavLinkDistance = 1000;
|
||||
AutopilotMinEnemyDistance = 5000;
|
||||
AutopilotMinAsteroidDistance = 1000;
|
||||
LockWeaponsDuringAutopilot = false;
|
||||
AutoPilotEngaged = false;
|
||||
CurrentNav = -1;
|
||||
audio_handle = -1;
|
||||
@@ -1243,9 +1234,10 @@ void NavSystem_Init()
|
||||
UseCutsceneBars = true;
|
||||
|
||||
// defaults... can be tabled or bound to mission later
|
||||
parse_autopilot_table("autopilot.tbl");
|
||||
|
||||
parse_modular_table("*-aplt.tbm", parse_autopilot_table);
|
||||
if (cf_exists_full("autopilot.tbl", CF_TYPE_TABLES))
|
||||
parse_autopilot_table("autopilot.tbl");
|
||||
else
|
||||
parse_autopilot_table(NULL);
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
@@ -1256,16 +1248,10 @@ void parse_autopilot_table(const char *filename)
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if (!Parsing_modular_table) {
|
||||
// if table doesn't exist, use the default table
|
||||
if (cf_exists_full(filename, CF_TYPE_TABLES))
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
else
|
||||
read_file_text_from_default(defaults_get_file("autopilot.tbl"));
|
||||
} else {
|
||||
if (filename == NULL)
|
||||
read_file_text_from_default(defaults_get_file("autopilot.tbl"));
|
||||
else
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
}
|
||||
|
||||
reset_parse();
|
||||
|
||||
@@ -1273,17 +1259,23 @@ void parse_autopilot_table(const char *filename)
|
||||
required_string("#Autopilot");
|
||||
|
||||
// autopilot link distance
|
||||
if (optional_string("$Link Distance:"))
|
||||
stuff_int(&NavLinkDistance);
|
||||
required_string("$Link Distance:");
|
||||
stuff_int(&NavLinkDistance);
|
||||
|
||||
if (optional_string("$Interrupt autopilot if enemy within distance:"))
|
||||
stuff_int(&AutopilotMinEnemyDistance);
|
||||
else
|
||||
AutopilotMinEnemyDistance = 5000;
|
||||
|
||||
if (optional_string("$Interrupt autopilot if asteroid within distance:"))
|
||||
stuff_int(&AutopilotMinAsteroidDistance);
|
||||
else
|
||||
AutopilotMinAsteroidDistance = 1000;
|
||||
|
||||
if (optional_string("$Lock Weapons During Autopilot:"))
|
||||
stuff_boolean(&LockWeaponsDuringAutopilot);
|
||||
else
|
||||
LockWeaponsDuringAutopilot = false;
|
||||
|
||||
// optional no cutscene bars
|
||||
if (optional_string("+No_Cutscene_Bars"))
|
||||
@@ -1298,14 +1290,13 @@ void parse_autopilot_table(const char *filename)
|
||||
"$Support Present:", "$Support Working:" };
|
||||
for (int i = 0; i < NP_NUM_MESSAGES; i++)
|
||||
{
|
||||
if (optional_string(msg_tags[i])) {
|
||||
required_string(msg_tags[i]);
|
||||
|
||||
required_string("+Msg:");
|
||||
stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
|
||||
required_string("+Msg:");
|
||||
stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
|
||||
|
||||
required_string("+Snd File:");
|
||||
stuff_string(NavMsgs[i].filename, F_NAME, 256);
|
||||
}
|
||||
required_string("+Snd File:");
|
||||
stuff_string(NavMsgs[i].filename, F_NAME, 256);
|
||||
}
|
||||
|
||||
|
||||
@@ -1589,18 +1580,3 @@ bool IsVisited(int nav)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void Nav_SetColor(const char *nav, bool visited, ubyte r, ubyte g, ubyte b)
|
||||
{
|
||||
int n = FindNav(nav);
|
||||
|
||||
if (n >= 0 && n < MAX_NAVPOINTS)
|
||||
{
|
||||
auto rgb = visited ? Navs[n].visited_color : Navs[n].normal_color;
|
||||
rgb[0] = r;
|
||||
rgb[1] = g;
|
||||
rgb[2] = b;
|
||||
}
|
||||
}
|
||||
@@ -29,30 +29,19 @@
|
||||
class NavPoint
|
||||
{
|
||||
public:
|
||||
char m_NavName[32] = { 0 };
|
||||
int flags = 0;
|
||||
ubyte normal_color[3] = { 0x80, 0x80, 0xFF };
|
||||
ubyte visited_color[3] = { 0xFF, 0xFF, 0x00 };
|
||||
char m_NavName[32];
|
||||
int flags;
|
||||
|
||||
const void *target_obj = nullptr;
|
||||
int waypoint_num = -1; //only used when flags & NP_WAYPOINT
|
||||
const void *target_obj;
|
||||
int waypoint_num; //only used when flags & NP_WAYPOINT
|
||||
|
||||
const vec3d *GetPosition();
|
||||
|
||||
// these assignments should match the initialization
|
||||
void clear()
|
||||
{
|
||||
m_NavName[0] = 0;
|
||||
flags = 0;
|
||||
|
||||
normal_color[0] = 0x80;
|
||||
normal_color[1] = 0x80;
|
||||
normal_color[2] = 0xFF;
|
||||
|
||||
visited_color[0] = 0xFF;
|
||||
visited_color[1] = 0xFF;
|
||||
visited_color[2] = 0x00;
|
||||
|
||||
target_obj = nullptr;
|
||||
waypoint_num = -1;
|
||||
}
|
||||
@@ -79,7 +68,7 @@ extern bool AutoPilotEngaged;
|
||||
extern int CurrentNav;
|
||||
extern NavPoint Navs[MAX_NAVPOINTS];
|
||||
extern NavMessage NavMsgs[NP_NUM_MESSAGES];
|
||||
extern TIMESTAMP LockAPConv;
|
||||
extern int LockAPConv;
|
||||
extern SCP_map<int,int> autopilot_wings;
|
||||
|
||||
// Cycles through the NavPoint List
|
||||
@@ -166,8 +155,6 @@ unsigned int DistanceTo(int nav);
|
||||
bool IsVisited(const char *nav);
|
||||
bool IsVisited(int nav);
|
||||
|
||||
void Nav_SetColor(const char *nav, bool visited, ubyte r, ubyte g, ubyte b);
|
||||
|
||||
void send_autopilot_msg(const char *msg, const char *snd=nullptr);
|
||||
void send_autopilot_msgID(int msgid);
|
||||
#endif
|
||||
|
||||
@@ -100,7 +100,7 @@ void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort fla
|
||||
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert = true );
|
||||
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
|
||||
const size_t BM_BLOCK_SIZE = 4096;
|
||||
|
||||
|
||||
+35
-123
@@ -53,7 +53,6 @@ MONITOR(SizeBitmapPage)
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Definition of public variables (declared as extern in bmpman.h).
|
||||
int ENVMAP = -1;
|
||||
int IRRMAP = -1;
|
||||
|
||||
size_t bm_texture_ram = 0;
|
||||
int Bm_paging = 0;
|
||||
@@ -425,7 +424,6 @@ DCF(bm_used, "Shows BmpMan Slot Usage") {
|
||||
|
||||
SCP_stringstream text;
|
||||
text << "BmpMan Used Slots\n";
|
||||
text << " " << std::dec << std::setw(4) << std::setfill('0') << none << ", NONE\n";
|
||||
text << " " << std::dec << std::setw(4) << std::setfill('0') << pcx << ", PCX\n";
|
||||
text << " " << std::dec << std::setw(4) << std::setfill('0') << user << ", User\n";
|
||||
text << " " << std::dec << std::setw(4) << std::setfill('0') << tga << ", TGA\n";
|
||||
@@ -586,59 +584,6 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
|
||||
return n;
|
||||
}
|
||||
|
||||
int bm_create_3d(int bpp, int w, int h, int d, void* data) {
|
||||
Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
|
||||
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int n = find_block_of(1);
|
||||
|
||||
// Out of bitmap slots
|
||||
if (n == -1)
|
||||
return -1;
|
||||
|
||||
// make sure that we have valid data
|
||||
if (data == nullptr) {
|
||||
UNREACHABLE("No valid data received for 3D Bitmap creation!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto entry = bm_get_entry(n);
|
||||
|
||||
memset(entry, 0, sizeof(bitmap_entry));
|
||||
|
||||
sprintf_safe(entry->filename, "TMP%dx%dx%d+%d", w, h, d, bpp);
|
||||
entry->type = BM_TYPE_3D;
|
||||
entry->comp_type = BM_TYPE_NONE;
|
||||
|
||||
entry->bm.w = (short)w;
|
||||
entry->bm.h = (short)h;
|
||||
entry->bm.d = (short)d;
|
||||
entry->bm.rowsize = (short)w;
|
||||
entry->bm.bpp = (ubyte)bpp;
|
||||
entry->bm.true_bpp = (ubyte)bpp;
|
||||
entry->bm.flags = (ubyte)BMP_TEX_XPARENT;
|
||||
entry->bm.data = 0;
|
||||
entry->bm.palette = nullptr;
|
||||
|
||||
entry->info.user.bpp = (ubyte)bpp;
|
||||
entry->info.user.data = data;
|
||||
entry->info.user.flags = (ubyte)BMP_TEX_XPARENT;
|
||||
|
||||
entry->signature = Bm_next_signature++;
|
||||
|
||||
entry->handle = n;
|
||||
entry->mem_taken = (w * h * d * (bpp >> 3));
|
||||
|
||||
entry->load_count++;
|
||||
|
||||
bm_update_memory_used(n, (int)entry->mem_taken);
|
||||
|
||||
gr_bm_create(bm_get_slot(n));
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void bm_convert_format(bitmap *bmp, ushort flags) {
|
||||
int idx;
|
||||
|
||||
@@ -647,9 +592,12 @@ void bm_convert_format(bitmap *bmp, ushort flags) {
|
||||
return;
|
||||
|
||||
if (Is_standalone) {
|
||||
Assert(bmp->bpp == 8);
|
||||
return;
|
||||
} else {
|
||||
if(!(flags & BMP_AABITMAP))
|
||||
if (flags & BMP_AABITMAP)
|
||||
Assert(bmp->bpp == 8);
|
||||
else
|
||||
Assert((bmp->bpp == 16) || (bmp->bpp == 32));
|
||||
}
|
||||
|
||||
@@ -682,7 +630,7 @@ void bm_free_data(bitmap_slot* bs, bool release)
|
||||
|
||||
// Don't free up memory for user defined bitmaps, since
|
||||
// BmpMan isn't the one in charge of allocating/deallocing them.
|
||||
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
|
||||
if (be->type==BM_TYPE_USER) {
|
||||
#ifdef BMPMAN_NDEBUG
|
||||
if ( be->data_size != 0 )
|
||||
bm_texture_ram -= be->data_size;
|
||||
@@ -738,7 +686,7 @@ void bm_free_data_fast(int handle)
|
||||
|
||||
// Don't free up memory for user defined bitmaps, since
|
||||
// BmpMan isn't the one in charge of allocating/deallocing them.
|
||||
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
|
||||
if (be->type == BM_TYPE_USER) {
|
||||
#ifdef BMPMAN_NDEBUG
|
||||
if ( be->data_size != 0 )
|
||||
bm_texture_ram -= be->data_size;
|
||||
@@ -946,27 +894,6 @@ int bm_get_info(int handle, int *w, int * h, ushort* flags, int *nframes, int *f
|
||||
}
|
||||
}
|
||||
|
||||
int bm_get_depth(int handle, int* depth) {
|
||||
bitmap* bmp;
|
||||
|
||||
if (!bm_inited) return -1;
|
||||
|
||||
auto entry = bm_get_entry(handle);
|
||||
|
||||
Assertion(entry->handle == handle, "Invalid bitmap handle %d passed to bm_get_info().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
|
||||
|
||||
if (entry->type != BM_TYPE_3D) {
|
||||
*depth = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bmp = &(entry->bm);
|
||||
|
||||
*depth = bmp->d;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int bm_get_num_mipmaps(int num) {
|
||||
auto entry = bm_get_entry(num);
|
||||
|
||||
@@ -1027,6 +954,10 @@ int bm_is_compressed(int num) {
|
||||
auto entry = bm_get_entry(num);
|
||||
BM_TYPE type = BM_TYPE_NONE;
|
||||
|
||||
//duh
|
||||
if (!Use_compressed_textures)
|
||||
return 0;
|
||||
|
||||
type = entry->comp_type;
|
||||
|
||||
switch (type) {
|
||||
@@ -1189,7 +1120,7 @@ static int bm_load_info(BM_TYPE type, const char *filename, CFILE *img_cfp, int
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bm_load(const char *real_filename, int dir_type) {
|
||||
int bm_load(const char *real_filename) {
|
||||
int free_slot = -1;
|
||||
int w, h, bpp = 8;
|
||||
int rc = 0;
|
||||
@@ -1221,7 +1152,6 @@ int bm_load(const char *real_filename, int dir_type) {
|
||||
if (Is_standalone) {
|
||||
char standalone_filename[MAX_FILENAME_LEN] = "right_bracket";
|
||||
strcpy_s(filename, standalone_filename);
|
||||
dir_type = CF_TYPE_INTERFACE;
|
||||
}
|
||||
|
||||
// safety catch for strcat...
|
||||
@@ -1234,11 +1164,11 @@ int bm_load(const char *real_filename, int dir_type) {
|
||||
// Lets find out what type it is
|
||||
{
|
||||
// see if it's already loaded (checks for any type with filename)
|
||||
if (bm_load_sub_fast(filename, &handle, dir_type))
|
||||
if (bm_load_sub_fast(filename, &handle))
|
||||
return handle;
|
||||
|
||||
// if we are still here then we need to fall back to a file-based search
|
||||
int rval = bm_load_sub_slow(filename, BM_NUM_TYPES, bm_ext_list, &img_cfp, dir_type);
|
||||
int rval = bm_load_sub_slow(filename, BM_NUM_TYPES, bm_ext_list, &img_cfp);
|
||||
|
||||
if (rval < 0)
|
||||
return -1;
|
||||
@@ -1294,7 +1224,7 @@ int bm_load(const char *real_filename, int dir_type) {
|
||||
entry->bm.palette = nullptr;
|
||||
entry->num_mipmaps = mm_lvl;
|
||||
entry->mem_taken = (size_t)bm_size;
|
||||
entry->dir_type = dir_type;
|
||||
entry->dir_type = CF_TYPE_ANY;
|
||||
entry->handle = handle;
|
||||
|
||||
entry->load_count++;
|
||||
@@ -1305,8 +1235,8 @@ int bm_load(const char *real_filename, int dir_type) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
int bm_load(const SCP_string& filename, int dir_type) {
|
||||
return bm_load(filename.c_str(), dir_type);
|
||||
int bm_load(const SCP_string& filename) {
|
||||
return bm_load(filename.c_str());
|
||||
}
|
||||
|
||||
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type) {
|
||||
@@ -1478,10 +1408,6 @@ static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug)
|
||||
bm_lock_user(handle, bs, bmp, true_bpp, flags);
|
||||
break;
|
||||
|
||||
case BM_TYPE_3D:
|
||||
bm_lock_user(handle, bs, bmp, true_bpp, flags, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", c_type);
|
||||
return -1;
|
||||
@@ -1498,7 +1424,7 @@ static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, float *total_time, bool can_drop_frames, int dir_type, bool rethrow_exceptions) {
|
||||
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, float *total_time, bool can_drop_frames, int dir_type) {
|
||||
int i, n;
|
||||
anim the_anim;
|
||||
CFILE *img_cfp = nullptr;
|
||||
@@ -1540,7 +1466,6 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
if (Is_standalone) {
|
||||
char standalone_filename[MAX_FILENAME_LEN] = "cursorweb";
|
||||
strcpy_s(filename, standalone_filename);
|
||||
dir_type = CF_TYPE_INTERFACE;
|
||||
}
|
||||
|
||||
// safety catch for strcat...
|
||||
@@ -1592,13 +1517,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
// MAX_FILENAME_LEN-10 == 5 character frame designator plus '.' plus 3 letter ext plus NULL terminator
|
||||
// we only check for -5 here since the filename should already have the extension on it, and it must have passed the previous check
|
||||
if (strlen(filename) > MAX_FILENAME_LEN - 5) {
|
||||
// Don't check PNGs yet, because a PNG could be a regular non-animated image
|
||||
if (type != BM_TYPE_PNG) {
|
||||
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
|
||||
if (img_cfp != nullptr)
|
||||
cfclose(img_cfp);
|
||||
return -1;
|
||||
}
|
||||
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
|
||||
if (img_cfp != nullptr)
|
||||
cfclose(img_cfp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// it's an effect file, any readable image type with eff being txt
|
||||
@@ -1609,7 +1531,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
cfclose(img_cfp);
|
||||
return -1;
|
||||
} else {
|
||||
nprintf(("BmpMan","BMPMAN: Found EFF (%s) with %d frames at %d fps.\n", filename, anim_frames, anim_fps));
|
||||
mprintf(("BMPMAN: Found EFF (%s) with %d frames at %d fps.\n", filename, anim_frames, anim_fps));
|
||||
}
|
||||
if (anim_fps == 0) {
|
||||
Error(LOCATION, "animation (%s) has invalid fps of 0, fix this!", filename);
|
||||
@@ -1672,20 +1594,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
img_size = the_apng.imgsize();
|
||||
}
|
||||
catch (const apng::ApngException& e) {
|
||||
if (img_cfp != nullptr)
|
||||
cfclose(img_cfp);
|
||||
if (rethrow_exceptions) {
|
||||
throw e;
|
||||
}
|
||||
else {
|
||||
nprintf(("apng","Failed to load apng: %s\n", e.what()));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now do the same filename length check that was deferred for PNGs above
|
||||
if (strlen(filename) > MAX_FILENAME_LEN - 5) {
|
||||
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
|
||||
mprintf(("Failed to load apng: %s\n", e.what() ));
|
||||
if (img_cfp != nullptr)
|
||||
cfclose(img_cfp);
|
||||
return -1;
|
||||
@@ -1880,7 +1789,7 @@ int bm_load_either(const char *filename, int *nframes, int *fps, int *keyframe,
|
||||
*fps = 0;
|
||||
int tidx = bm_load_animation(filename, nframes, fps, keyframe, nullptr, can_drop_frames, dir_type);
|
||||
if (tidx == -1) {
|
||||
tidx = bm_load(filename, dir_type);
|
||||
tidx = bm_load(filename);
|
||||
if (tidx != -1 && nframes != NULL)
|
||||
*nframes = 1;
|
||||
}
|
||||
@@ -1921,7 +1830,7 @@ int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type, bool
|
||||
}
|
||||
|
||||
int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **ext_list, CFILE **img_cfp, int dir_type) {
|
||||
auto res = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type);
|
||||
auto res = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, false);
|
||||
|
||||
// could not be found, or is invalid for some reason
|
||||
if (!res.found)
|
||||
@@ -1959,7 +1868,9 @@ bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) {
|
||||
}
|
||||
// otherwise do it as normal
|
||||
else {
|
||||
if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
|
||||
if (flags & BMP_AABITMAP) {
|
||||
Assert(bpp == 8);
|
||||
} else if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
|
||||
Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
|
||||
} else if ((flags & BMP_TEX_DXT1) || (flags & BMP_TEX_DXT3) || (flags & BMP_TEX_DXT5) || (flags & BMP_TEX_BC7)) {
|
||||
Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
|
||||
@@ -1969,6 +1880,8 @@ bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) {
|
||||
(be->type == BM_TYPE_CUBEMAP_DXT3) ||
|
||||
(be->type == BM_TYPE_CUBEMAP_DXT5));
|
||||
Assert(bpp >= 16);
|
||||
} else {
|
||||
Assert(0); //?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2474,7 +2387,7 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags
|
||||
bm_convert_format(bmp, flags);
|
||||
}
|
||||
|
||||
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert) {
|
||||
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) {
|
||||
auto be = &bs->entry;
|
||||
|
||||
// Unload any existing data
|
||||
@@ -2514,8 +2427,7 @@ void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort
|
||||
break;
|
||||
}
|
||||
|
||||
if (convert)
|
||||
bm_convert_format(bmp, flags);
|
||||
bm_convert_format(bmp, flags);
|
||||
}
|
||||
|
||||
int bm_make_render_target(int width, int height, int flags) {
|
||||
@@ -2599,7 +2511,7 @@ void *bm_malloc(int n, size_t size) {
|
||||
void bm_page_in_aabitmap(int handle, int nframes) {
|
||||
int i;
|
||||
|
||||
if (handle < 0)
|
||||
if (handle == -1)
|
||||
return;
|
||||
|
||||
Assert(bm_get_entry(handle)->handle == handle);
|
||||
@@ -2710,7 +2622,7 @@ void bm_page_in_stop() {
|
||||
}
|
||||
}
|
||||
|
||||
nprintf(("BmpMan","BMPMAN: %d/%d bitmap slots in use.\n", total_bitmaps, total_slots));
|
||||
mprintf(("Bmpman: %d/%d bitmap slots in use.\n", total_bitmaps, total_slots));
|
||||
#endif
|
||||
|
||||
Bm_paging = 0;
|
||||
@@ -3218,7 +3130,7 @@ int bm_unload_fast(int handle, int clear_render_targets) {
|
||||
return -1; // Already been released
|
||||
}
|
||||
|
||||
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
|
||||
if (be->type == BM_TYPE_USER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 1964 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user