Compare commits
37 Commits
devtest-20
...
devtest-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
759dc34e03 | ||
|
|
668ab78b1b | ||
|
|
c754d6a892 | ||
|
|
e9108479b5 | ||
|
|
857da21b0f | ||
|
|
73bba97aaa | ||
|
|
d6e9cdab5b | ||
|
|
1a177bc2de | ||
|
|
e0b3e631fe | ||
|
|
2518a353af | ||
|
|
989800efff | ||
|
|
c02846e2cb | ||
|
|
09db4a0e25 | ||
|
|
a85da9d86c | ||
|
|
920d00bbae | ||
|
|
62475279ee | ||
|
|
d8e979d283 | ||
|
|
299b8880dd | ||
|
|
61027e4067 | ||
|
|
a7249c10dc | ||
|
|
611d12ac78 | ||
|
|
ef9f26a60d | ||
|
|
aeaffc0a8e | ||
|
|
e3084e230e | ||
|
|
4c01c772f8 | ||
|
|
ed94f7680a | ||
|
|
408d66cdaf | ||
|
|
c4a0f2f169 | ||
|
|
26b28d26da | ||
|
|
8ded6dafd4 | ||
|
|
57a94ad667 | ||
|
|
53933a4d8f | ||
|
|
6606d7dd93 | ||
|
|
7a256dcafa | ||
|
|
7899c52b6d | ||
|
|
919c670502 | ||
|
|
aac3174efc |
55
.github/workflows/ci.yaml
vendored
Normal file
55
.github/workflows/ci.yaml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches: [ bleed ]
|
||||
|
||||
jobs:
|
||||
linux-mono:
|
||||
name: Linux (mono)
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Check Code
|
||||
run: |
|
||||
mono --version
|
||||
make check
|
||||
|
||||
- name: Check Mods
|
||||
run: |
|
||||
sudo apt-get install lua5.1
|
||||
make check-scripts
|
||||
make test
|
||||
|
||||
windows:
|
||||
name: Windows (Net 5.0)
|
||||
runs-on: windows-2019
|
||||
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install .NET 5
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.x'
|
||||
|
||||
- name: Check Code
|
||||
shell: powershell
|
||||
run: |
|
||||
# Work around runtime failures on the GH Actions runner
|
||||
dotnet nuget locals all --clear
|
||||
.\make.ps1 check
|
||||
dotnet build OpenRA.Test\OpenRA.Test.csproj -c Debug --nologo -p:TargetPlatform=win-x64
|
||||
dotnet test bin\OpenRA.Test.dll --test-adapter-path:.
|
||||
|
||||
- name: Check Mods
|
||||
run: |
|
||||
chocolatey install lua --version 5.1.5.52
|
||||
$ENV:Path = $ENV:Path + ";C:\Program Files (x86)\Lua\5.1\"
|
||||
.\make.ps1 check-scripts
|
||||
.\make.ps1 test
|
||||
107
.github/workflows/documentation.yml
vendored
Normal file
107
.github/workflows/documentation.yml
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
name: Deploy Documentation
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Git Tag'
|
||||
required: true
|
||||
default: 'release-xxxxxxxx'
|
||||
|
||||
jobs:
|
||||
wiki:
|
||||
name: Update Wiki
|
||||
if: github.repository == 'openra/openra'
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.tag }}
|
||||
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
make all
|
||||
|
||||
- name: Clone Wiki
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: openra/openra.wiki
|
||||
token: ${{ secrets.DOCS_TOKEN }}
|
||||
path: wiki
|
||||
|
||||
- name: Update Wiki (Playtest)
|
||||
if: startsWith(github.event.inputs.tag, 'playtest-')
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
./utility.sh all --settings-docs "${GIT_TAG}" > "wiki/Settings (playtest).md"
|
||||
|
||||
- name: Update Wiki (Release)
|
||||
if: startsWith(github.event.inputs.tag, 'release-')
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
./utility.sh all --settings-docs "${GIT_TAG}" > "wiki/Settings.md"
|
||||
|
||||
- name: Push Wiki
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
cd wiki
|
||||
git config --local user.email "actions@github.com"
|
||||
git config --local user.name "GitHub Actions"
|
||||
git add --all
|
||||
git commit -m "Update auto-generated documentation for ${GIT_TAG}"
|
||||
git push origin master
|
||||
|
||||
docs:
|
||||
name: Update docs.openra.net
|
||||
if: github.repository == 'openra/openra'
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.tag }}
|
||||
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
make all
|
||||
|
||||
- name: Clone docs.openra.net
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: openra/docs
|
||||
token: ${{ secrets.DOCS_TOKEN }}
|
||||
path: docs
|
||||
|
||||
- name: Update docs.openra.net (Playtest)
|
||||
if: startsWith(github.event.inputs.tag, 'playtest-')
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
./utility.sh all --docs "${GIT_TAG}" > "docs/api/playtest/traits.md"
|
||||
./utility.sh all --weapon-docs "${GIT_TAG}" > "docs/api/playtest/weapons.md"
|
||||
./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/playtest/lua.md"
|
||||
|
||||
- name: Update docs.openra.net (Release)
|
||||
if: startsWith(github.event.inputs.tag, 'release-')
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
./utility.sh all --docs "${GIT_TAG}" > "docs/api/release/traits.md"
|
||||
./utility.sh all --weapon-docs "${GIT_TAG}" > "docs/api/release/weapons.md"
|
||||
./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/release/lua.md"
|
||||
|
||||
- name: Push docs.openra.net
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
cd docs
|
||||
git config --local user.email "actions@github.com"
|
||||
git config --local user.name "GitHub Actions"
|
||||
git add --all
|
||||
git commit -m "Update auto-generated documentation for ${GIT_TAG}"
|
||||
git push origin master
|
||||
|
||||
88
.github/workflows/itch.yml
vendored
Normal file
88
.github/workflows/itch.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
name: Deploy itch.io Packages
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Git Tag'
|
||||
required: true
|
||||
default: 'release-xxxxxxxx'
|
||||
|
||||
jobs:
|
||||
itch:
|
||||
name: Deploy to itch.io
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.repository == 'openra/openra'
|
||||
steps:
|
||||
- name: Download Packages
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}-x64.exe"
|
||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}-x64-winportable.zip" -O "OpenRA-${GIT_TAG}-x64-win-itch.zip"
|
||||
wget -q "https://github.com${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}.dmg"
|
||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Dune-2000-x86_64.AppImage"
|
||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Red-Alert-x86_64.AppImage"
|
||||
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Tiberian-Dawn-x86_64.AppImage"
|
||||
wget -q "https://raw.githubusercontent.com/${{ github.repository }}/${GIT_TAG}/packaging/.itch.toml"
|
||||
zip -u "OpenRA-${GIT_TAG}-x64-win-itch.zip" .itch.toml
|
||||
|
||||
- name: Publish Windows Installer
|
||||
uses: josephbmanley/butler-publish-itchio-action@master
|
||||
env:
|
||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||
CHANNEL: win
|
||||
ITCH_GAME: openra
|
||||
ITCH_USER: openra-developers
|
||||
VERSION: ${{ github.event.inputs.tag }}
|
||||
PACKAGE: OpenRA-${{ github.event.inputs.tag }}}-x64.exe"
|
||||
|
||||
- name: Publish Windows Itch Bundle
|
||||
uses: josephbmanley/butler-publish-itchio-action@master
|
||||
env:
|
||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||
CHANNEL: itch
|
||||
ITCH_GAME: openra
|
||||
ITCH_USER: openra-developers
|
||||
VERSION: ${{ github.event.inputs.tag }}
|
||||
PACKAGE: OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip
|
||||
|
||||
- name: Publish macOS Package
|
||||
uses: josephbmanley/butler-publish-itchio-action@master
|
||||
env:
|
||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||
CHANNEL: macos
|
||||
ITCH_GAME: openra
|
||||
ITCH_USER: openra-developers
|
||||
VERSION: ${{ github.event.inputs.tag }}
|
||||
PACKAGE: OpenRA-${{ github.event.inputs.tag }}}.dmg"
|
||||
|
||||
- name: Publish RA AppImage
|
||||
uses: josephbmanley/butler-publish-itchio-action@master
|
||||
env:
|
||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||
CHANNEL: linux-ra
|
||||
ITCH_GAME: openra
|
||||
ITCH_USER: openra-developers
|
||||
VERSION: ${{ github.event.inputs.tag }}
|
||||
PACKAGE: OpenRA-Red-Alert-x86_64.AppImage
|
||||
|
||||
- name: Publish TD AppImage
|
||||
uses: josephbmanley/butler-publish-itchio-action@master
|
||||
env:
|
||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||
CHANNEL: linux-cnc
|
||||
ITCH_GAME: openra
|
||||
ITCH_USER: openra-developers
|
||||
VERSION: ${{ github.event.inputs.tag }}
|
||||
PACKAGE: OpenRA-Tiberian-Dawn-x86_64.AppImage
|
||||
|
||||
- name: Publish D2k AppImage
|
||||
uses: josephbmanley/butler-publish-itchio-action@master
|
||||
env:
|
||||
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
|
||||
CHANNEL: linux-d2k
|
||||
ITCH_GAME: openra
|
||||
ITCH_USER: openra-developers
|
||||
VERSION: ${{ github.event.inputs.tag }}
|
||||
PACKAGE: OpenRA-Dune-2000-x86_64.AppImage
|
||||
99
.github/workflows/packaging.yml
vendored
Normal file
99
.github/workflows/packaging.yml
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
name: Release Packaging
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'release-*'
|
||||
- 'playtest-*'
|
||||
- 'devtest-*'
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Linux AppImages
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Prepare Environment
|
||||
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
|
||||
|
||||
- name: Package AppImages
|
||||
run: |
|
||||
mkdir -p build/linux
|
||||
./packaging/linux/buildpackage.sh "${GIT_TAG}" "${PWD}/build/linux"
|
||||
|
||||
- name: Upload Packages
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
file: build/linux/*
|
||||
|
||||
macos:
|
||||
name: macOS Disk Images
|
||||
runs-on: macos-10.15
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install .NET 5
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.x'
|
||||
|
||||
- name: Prepare Environment
|
||||
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
|
||||
|
||||
- name: Package Disk Images
|
||||
env:
|
||||
MACOS_DEVELOPER_IDENTITY: ${{ secrets.MACOS_DEVELOPER_IDENTITY }}
|
||||
MACOS_DEVELOPER_CERTIFICATE_BASE64: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_BASE64 }}
|
||||
MACOS_DEVELOPER_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_PASSWORD }}
|
||||
MACOS_DEVELOPER_USERNAME: ${{ secrets.MACOS_DEVELOPER_USERNAME }}
|
||||
MACOS_DEVELOPER_PASSWORD: ${{ secrets.MACOS_DEVELOPER_PASSWORD }}
|
||||
run: |
|
||||
mkdir -p build/macos
|
||||
./packaging/macos/buildpackage.sh "${GIT_TAG}" "${PWD}/build/macos"
|
||||
|
||||
- name: Upload Packages
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
file: build/macos/*
|
||||
|
||||
windows:
|
||||
name: Windows Installers
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install .NET 5
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.x'
|
||||
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
|
||||
sudo apt install nsis wine64
|
||||
|
||||
- name: Package Installers
|
||||
run: |
|
||||
mkdir -p build/windows
|
||||
./packaging/windows/buildpackage.sh "${GIT_TAG}" "${PWD}/build/windows"
|
||||
|
||||
- name: Upload Packages
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
file: build/windows/*
|
||||
92
.travis.yml
92
.travis.yml
@@ -1,92 +0,0 @@
|
||||
# Travis-CI Build for OpenRA
|
||||
# see travis-ci.org for details
|
||||
|
||||
language: csharp
|
||||
mono: 6.4.0
|
||||
os: linux
|
||||
dist: xenial
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
- os: osx
|
||||
if: tag IS present
|
||||
osx_image: xcode10
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- lua5.1
|
||||
- dpkg
|
||||
- zsync
|
||||
- imagemagick
|
||||
|
||||
# Environment variables
|
||||
env:
|
||||
secure: "C0+Hlfa0YGErxUuWV00Tj6p45otC/D3YwYFuLpi2mj1rDFn/4dgh5WRngjvdDBVbXJ3duaZ78jPHWm1jr7vn2jqj9yETsCIK9psWd38ep/FEBM0SDr6MUD89OuXk/YyvxJAE+UXF6bXg7giey09g/CwBigjMW7ynET3wNAWPHPs="
|
||||
|
||||
# Fetch dependencies
|
||||
# Run the build script
|
||||
# Check source code with StyleCop
|
||||
# call OpenRA to check for YAML errors
|
||||
# Run the NUnit tests
|
||||
script:
|
||||
- make all
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||
make check || travis_terminate 1;
|
||||
make check-scripts || travis_terminate 1;
|
||||
make test || travis_terminate 1;
|
||||
mono ~/.nuget/packages/nunit.consolerunner/3.11.1/tools/nunit3-console.exe --noresult bin/OpenRA.Test.dll || travis_terminate 1;
|
||||
fi
|
||||
|
||||
# Only watch the development branch and tagged release.
|
||||
branches:
|
||||
only:
|
||||
- /^release-.*$/
|
||||
- /^playtest-.*$/
|
||||
- /^devtest-.*$/
|
||||
- /^prep-.*$/
|
||||
- bleed
|
||||
|
||||
# Notify developers when build passed/failed.
|
||||
notifications:
|
||||
irc:
|
||||
if: repo = OpenRA/OpenRA
|
||||
template:
|
||||
- "%{repository}#%{build_number} %{commit} %{author}: %{message} %{build_url}"
|
||||
channels:
|
||||
- "irc.freenode.net#openra"
|
||||
use_notice: true
|
||||
skip_join: true
|
||||
|
||||
before_deploy:
|
||||
- if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
wget https://mirrors.edge.kernel.org/ubuntu/pool/universe/n/nsis/nsis-common_3.04-1_all.deb;
|
||||
wget https://mirrors.edge.kernel.org/ubuntu/pool/universe/n/nsis/nsis_3.04-1_amd64.deb;
|
||||
sudo dpkg -i nsis-common_3.04-1_all.deb;
|
||||
sudo dpkg -i nsis_3.04-1_amd64.deb;
|
||||
echo ${TRAVIS_REPO_SLUG};
|
||||
if [[ "${TRAVIS_REPO_SLUG}" == "OpenRA/OpenRA" ]]; then
|
||||
cd packaging && ./update-wiki.sh ${TRAVIS_TAG} && ./update-docs.sh ${TRAVIS_TAG} && cd ..;
|
||||
fi;
|
||||
fi
|
||||
- export PATH=${PATH}:${HOME}/usr/bin
|
||||
- DOTVERSION=`echo ${TRAVIS_TAG} | sed "s/-/\\./g"`
|
||||
- cd packaging
|
||||
- mkdir build
|
||||
- ./package-all.sh ${TRAVIS_TAG} ${PWD}/build/
|
||||
- if [[ "${TRAVIS_REPO_SLUG}" == "OpenRA/OpenRA" ]]; then
|
||||
./upload-itch.sh ${TRAVIS_TAG} ${PWD}/build/;
|
||||
fi
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
token: ${GH_DEPLOY_API_KEY}
|
||||
file_glob: true
|
||||
file: build/*
|
||||
skip_cleanup: true
|
||||
on:
|
||||
all_branches: true
|
||||
tags: true
|
||||
10
INSTALL.md
10
INSTALL.md
@@ -8,18 +8,16 @@ Windows
|
||||
|
||||
Compiling OpenRA requires the following dependencies:
|
||||
* [Windows PowerShell >= 4.0](http://microsoft.com/powershell) (included by default in recent Windows 10 versions)
|
||||
* [.NET Framework 4.7.2 (Developer Pack)](https://dotnet.microsoft.com/download/dotnet-framework/net472) (or via Visual Studio 2017)
|
||||
* [.NET Core 2.2 SDK](https://dotnet.microsoft.com/download/dotnet-core/2.2) (or via Visual Studio 2017)
|
||||
* [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/5.0) (or via Visual Studio)
|
||||
|
||||
|
||||
To compile OpenRA, open the `OpenRA.sln` solution in the main folder, build it from the command-line with MSBuild or use the Makefile analogue command `make all` scripted in PowerShell syntax.
|
||||
To compile OpenRA, open the `OpenRA.sln` solution in the main folder, build it from the command-line with `dotnet` or use the Makefile analogue command `make all` scripted in PowerShell syntax.
|
||||
|
||||
Run the game with `launch-game.cmd`. It can be handed arguments that specify the exact mod one wishes to run, for example, run `launch-game.cmd Game.Mod=ra` to launch Red Alert, `launch-game.cmd Game.Mod=cnc` to start Tiberian dawn or `launch-game.cmd Game.Mod=d2k` to launch Dune 2000.
|
||||
|
||||
Linux
|
||||
=====
|
||||
|
||||
Mono, version 5.18 or later, is required to compile OpenRA. You can add the [upstream mono repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version if your system packages are not sufficient.
|
||||
Mono, version 6.4 or later, is required to compile OpenRA. You can add the [upstream mono repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version if your system packages are not sufficient.
|
||||
|
||||
To compile OpenRA, run `make` from the command line. After this one can run the game with `./launch-game.sh`. It is also possible to specify the mod you wish to run from the command line, e.g. with `./launch-game.sh Game.Mod=ts` if you wish to try the experimental Tiberian Sun mod.
|
||||
|
||||
@@ -99,7 +97,7 @@ macOS
|
||||
=====
|
||||
|
||||
Before compiling OpenRA you must install the following dependencies:
|
||||
* [Mono >= 5.18](https://www.mono-project.com/download/stable/#download-mac)
|
||||
* [Mono >= 6.4](https://www.mono-project.com/download/stable/#download-mac)
|
||||
|
||||
To compile OpenRA, run `make` from the command line. Run with `./launch-game.sh`.
|
||||
|
||||
|
||||
12
Makefile
12
Makefile
@@ -28,14 +28,14 @@
|
||||
############################## TOOLCHAIN ###############################
|
||||
#
|
||||
# List of .NET assemblies that we can guarantee exist
|
||||
WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.exe OpenRA.Utility.exe OpenRA.Server.exe OpenRA.Platforms.Default.dll OpenRA.Game.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll
|
||||
WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.dll OpenRA.Utility.dll OpenRA.Server.dll OpenRA.Platforms.Default.dll OpenRA.Game.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll
|
||||
|
||||
# These are explicitly shipped alongside our core files by the packaging script
|
||||
WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Eluant.dll BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.Core.dll DiscordRPC.dll Newtonsoft.Json.dll
|
||||
|
||||
# These are shipped in our custom minimal mono runtime and also available in the full system-installed .NET/mono stack
|
||||
# This list *must* be kept in sync with the files packaged by the AppImageSupport and OpenRALauncherOSX repositories
|
||||
WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll netstandard.dll
|
||||
WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll netstandard.dll Microsoft.Win32.Registry.dll System.Security.AccessControl.dll System.Security.Principal.Windows.dll System.Xml.Linq.dll System.Runtime.Serialization.dll
|
||||
|
||||
######################### UTILITIES/SETTINGS ###########################
|
||||
#
|
||||
@@ -78,13 +78,13 @@ endif
|
||||
endif
|
||||
endif
|
||||
|
||||
OPENRA_UTILITY = ENGINE_DIR=".." $(MONO) --debug bin/OpenRA.Utility.exe
|
||||
OPENRA_UTILITY = ENGINE_DIR=".." $(MONO) --debug bin/OpenRA.Utility.dll
|
||||
|
||||
##################### DEVELOPMENT BUILDS AND TESTS #####################
|
||||
#
|
||||
all:
|
||||
@command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.18."; exit 1)
|
||||
@$(MSBUILD) -t:Build -restore -p:Configuration=Release -p:TargetPlatform=$(TARGETPLATFORM)
|
||||
@$(MSBUILD) -t:Build -restore -p:Configuration=Release -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true -p:DefineConstants="MONO"
|
||||
ifeq ($(TARGETPLATFORM), unix-generic)
|
||||
@./configure-system-libraries.sh
|
||||
endif
|
||||
@@ -92,13 +92,13 @@ endif
|
||||
|
||||
clean:
|
||||
@-$(RM_RF) ./bin ./*/bin ./*/obj
|
||||
@$(MSBUILD) -t:Clean
|
||||
@$(MSBUILD) -t:Clean -p:Mono=true
|
||||
@-$(RM_F) IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP
|
||||
|
||||
check:
|
||||
@echo
|
||||
@echo "Compiling in debug mode..."
|
||||
@$(MSBUILD) -t:build -restore -p:Configuration=Debug
|
||||
@$(MSBUILD) -t:build -restore -p:Configuration=Debug -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true -p:DefineConstants="MONO"
|
||||
@echo
|
||||
@echo "Checking runtime assemblies..."
|
||||
@$(OPENRA_UTILITY) all --check-runtime-assemblies $(WHITELISTED_OPENRA_ASSEMBLIES) $(WHITELISTED_THIRDPARTY_ASSEMBLIES) $(WHITELISTED_CORE_ASSEMBLIES)
|
||||
|
||||
@@ -297,6 +297,7 @@ namespace OpenRA
|
||||
EngineVersion = "Unknown";
|
||||
|
||||
Console.WriteLine("Engine version is {0}", EngineVersion);
|
||||
Console.WriteLine("Runtime: {0}", Platform.RuntimeVersion);
|
||||
|
||||
// Special case handling of Game.Mod argument: if it matches a real filesystem path
|
||||
// then we use this to override the mod search path, and replace it with the mod id
|
||||
@@ -329,9 +330,16 @@ namespace OpenRA
|
||||
try
|
||||
{
|
||||
var rendererPath = Path.Combine(Platform.BinDir, "OpenRA.Platforms." + p + ".dll");
|
||||
var assembly = Assembly.LoadFile(rendererPath);
|
||||
|
||||
#if !MONO
|
||||
var loader = new AssemblyLoader(rendererPath);
|
||||
var platformType = loader.LoadDefaultAssembly().GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t));
|
||||
|
||||
#else
|
||||
var assembly = Assembly.LoadFile(rendererPath);
|
||||
var platformType = assembly.GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t));
|
||||
#endif
|
||||
|
||||
if (platformType == null)
|
||||
throw new InvalidOperationException("Platform dll must include exactly one IPlatform implementation.");
|
||||
|
||||
@@ -934,9 +942,11 @@ namespace OpenRA
|
||||
AdvertiseOnline = false
|
||||
};
|
||||
|
||||
// Always connect to local games using the same loopback connection
|
||||
// Exposing multiple endpoints introduces a race condition on the client's PlayerIndex (sometimes 0, sometimes 1)
|
||||
// This would break the Restart button, which relies on the PlayerIndex always being the same for local servers
|
||||
var endpoints = new List<IPEndPoint>
|
||||
{
|
||||
new IPEndPoint(IPAddress.IPv6Loopback, 0),
|
||||
new IPEndPoint(IPAddress.Loopback, 0)
|
||||
};
|
||||
server = new Server.Server(endpoints, settings, ModData, ServerType.Local);
|
||||
|
||||
@@ -119,6 +119,8 @@ namespace OpenRA
|
||||
IsBot = runtimePlayer.IsBot,
|
||||
FactionName = runtimePlayer.Faction.Name,
|
||||
FactionId = runtimePlayer.Faction.InternalName,
|
||||
DisplayFactionName = runtimePlayer.DisplayFaction.Name,
|
||||
DisplayFactionId = runtimePlayer.DisplayFaction.InternalName,
|
||||
Color = runtimePlayer.Color,
|
||||
Team = client.Team,
|
||||
SpawnPoint = runtimePlayer.SpawnPoint,
|
||||
@@ -157,6 +159,10 @@ namespace OpenRA
|
||||
public string FactionId;
|
||||
public Color Color;
|
||||
|
||||
/// <summary>The faction (including Random, etc.) that was selected in the lobby.</summary>
|
||||
public string DisplayFactionName;
|
||||
public string DisplayFactionId;
|
||||
|
||||
/// <summary>The team ID on start-up, or 0 if the player is not part of a team.</summary>
|
||||
public int Team;
|
||||
public int SpawnPoint;
|
||||
|
||||
@@ -168,10 +168,7 @@ namespace OpenRA.Graphics
|
||||
for (var x = 0; x < template.Size.X; x++)
|
||||
{
|
||||
var tile = new TerrainTile(template.Id, (byte)(i++));
|
||||
var tileInfo = tileset.GetTileInfo(tile);
|
||||
|
||||
// Empty tile
|
||||
if (tileInfo == null)
|
||||
if (!tileset.TryGetTileInfo(tile, out var tileInfo))
|
||||
continue;
|
||||
|
||||
var sprite = TileSprite(tile);
|
||||
|
||||
@@ -206,6 +206,8 @@ namespace OpenRA
|
||||
public readonly MiniYaml NotificationDefinitions;
|
||||
public readonly MiniYaml TranslationDefinitions;
|
||||
|
||||
public readonly Dictionary<CPos, TerrainTile> ReplacedInvalidTerrainTiles = new Dictionary<CPos, TerrainTile>();
|
||||
|
||||
// Generated data
|
||||
public readonly MapGrid Grid;
|
||||
public IReadOnlyPackage Package { get; private set; }
|
||||
@@ -287,7 +289,6 @@ namespace OpenRA
|
||||
this.modData = modData;
|
||||
var size = new Size(width, height);
|
||||
Grid = modData.Manifest.Get<MapGrid>();
|
||||
var tileRef = new TerrainTile(tileset.Templates.First().Key, 0);
|
||||
|
||||
Title = "Name your map here";
|
||||
Author = "Your name here";
|
||||
@@ -310,7 +311,7 @@ namespace OpenRA
|
||||
Tiles.CellEntryChanged += UpdateRamp;
|
||||
}
|
||||
|
||||
Tiles.Clear(tileRef);
|
||||
Tiles.Clear(tileset.DefaultTerrainTile);
|
||||
|
||||
PostInit();
|
||||
}
|
||||
@@ -430,12 +431,18 @@ namespace OpenRA
|
||||
foreach (var uv in AllCells.MapCoords)
|
||||
CustomTerrain[uv] = byte.MaxValue;
|
||||
|
||||
// Cache initial ramp state
|
||||
// Replace invalid tiles and cache ramp state
|
||||
var tileset = Rules.TileSet;
|
||||
foreach (var uv in AllCells)
|
||||
foreach (var uv in AllCells.MapCoords)
|
||||
{
|
||||
var tile = tileset.GetTileInfo(Tiles[uv]);
|
||||
Ramp[uv] = tile != null ? tile.RampType : (byte)0;
|
||||
if (!tileset.TryGetTileInfo(Tiles[uv], out var info))
|
||||
{
|
||||
ReplacedInvalidTerrainTiles[uv.ToCPos(this)] = Tiles[uv];
|
||||
Tiles[uv] = tileset.DefaultTerrainTile;
|
||||
info = tileset.GetTileInfo(tileset.DefaultTerrainTile);
|
||||
}
|
||||
|
||||
Ramp[uv] = info.RampType;
|
||||
}
|
||||
|
||||
AllEdgeCells = UpdateEdgeCells();
|
||||
@@ -443,8 +450,7 @@ namespace OpenRA
|
||||
|
||||
void UpdateRamp(CPos cell)
|
||||
{
|
||||
var tile = Rules.TileSet.GetTileInfo(Tiles[cell]);
|
||||
Ramp[cell] = tile != null ? tile.RampType : (byte)0;
|
||||
Ramp[cell] = Rules.TileSet.GetTileInfo(Tiles[cell]).RampType;
|
||||
}
|
||||
|
||||
void InitializeCellProjection()
|
||||
@@ -670,32 +676,26 @@ namespace OpenRA
|
||||
Color left, right;
|
||||
var tileset = Rules.TileSet;
|
||||
var type = tileset.GetTileInfo(Tiles[uv]);
|
||||
if (type != null)
|
||||
if (type.MinColor != type.MaxColor)
|
||||
{
|
||||
if (type.MinColor != type.MaxColor)
|
||||
{
|
||||
left = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor);
|
||||
right = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor);
|
||||
}
|
||||
else
|
||||
left = right = type.MinColor;
|
||||
|
||||
if (tileset.MinHeightColorBrightness != 1.0f || tileset.MaxHeightColorBrightness != 1.0f)
|
||||
{
|
||||
var scale = float2.Lerp(tileset.MinHeightColorBrightness, tileset.MaxHeightColorBrightness, Height[uv] * 1f / Grid.MaximumTerrainHeight);
|
||||
left = Color.FromArgb((int)(scale * left.R).Clamp(0, 255), (int)(scale * left.G).Clamp(0, 255), (int)(scale * left.B).Clamp(0, 255));
|
||||
right = Color.FromArgb((int)(scale * right.R).Clamp(0, 255), (int)(scale * right.G).Clamp(0, 255), (int)(scale * right.B).Clamp(0, 255));
|
||||
}
|
||||
left = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor);
|
||||
right = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor);
|
||||
}
|
||||
else
|
||||
left = right = Color.Black;
|
||||
left = right = type.MinColor;
|
||||
|
||||
if (tileset.MinHeightColorBrightness != 1.0f || tileset.MaxHeightColorBrightness != 1.0f)
|
||||
{
|
||||
var scale = float2.Lerp(tileset.MinHeightColorBrightness, tileset.MaxHeightColorBrightness, Height[uv] * 1f / Grid.MaximumTerrainHeight);
|
||||
left = Color.FromArgb((int)(scale * left.R).Clamp(0, 255), (int)(scale * left.G).Clamp(0, 255), (int)(scale * left.B).Clamp(0, 255));
|
||||
right = Color.FromArgb((int)(scale * right.R).Clamp(0, 255), (int)(scale * right.G).Clamp(0, 255), (int)(scale * right.B).Clamp(0, 255));
|
||||
}
|
||||
|
||||
return (left, right);
|
||||
}
|
||||
|
||||
public byte[] SavePreview()
|
||||
{
|
||||
var tileset = Rules.TileSet;
|
||||
var actorTypes = Rules.Actors.Values.Where(a => a.HasTraitInfo<IMapPreviewSignatureInfo>());
|
||||
var actors = ActorDefinitions.Where(a => actorTypes.Where(ai => ai.Name == a.Value.Value).Any());
|
||||
var positions = new List<(MPos Position, Color Color)>();
|
||||
@@ -715,76 +715,73 @@ namespace OpenRA
|
||||
foreach (var worldimpsi in worldimpsis)
|
||||
worldimpsi.PopulateMapPreviewSignatureCells(this, worldActorInfo, null, positions);
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
var isRectangularIsometric = Grid.Type == MapGridType.RectangularIsometric;
|
||||
|
||||
// Fudge the heightmap offset by adding as much extra as we need / can.
|
||||
// This tries to correct for our incorrect assumption that MPos == PPos
|
||||
var heightOffset = Math.Min(Grid.MaximumTerrainHeight, MapSize.Y - Bounds.Bottom);
|
||||
var width = Bounds.Width;
|
||||
var height = Bounds.Height + heightOffset;
|
||||
|
||||
var bitmapWidth = width;
|
||||
if (isRectangularIsometric)
|
||||
bitmapWidth = 2 * bitmapWidth - 1;
|
||||
|
||||
var stride = bitmapWidth * 4;
|
||||
var pxStride = 4;
|
||||
var minimapData = new byte[stride * height];
|
||||
(Color Left, Color Right) terrainColor = default((Color, Color));
|
||||
|
||||
for (var y = 0; y < height; y++)
|
||||
{
|
||||
var isRectangularIsometric = Grid.Type == MapGridType.RectangularIsometric;
|
||||
|
||||
// Fudge the heightmap offset by adding as much extra as we need / can.
|
||||
// This tries to correct for our incorrect assumption that MPos == PPos
|
||||
var heightOffset = Math.Min(Grid.MaximumTerrainHeight, MapSize.Y - Bounds.Bottom);
|
||||
var width = Bounds.Width;
|
||||
var height = Bounds.Height + heightOffset;
|
||||
|
||||
var bitmapWidth = width;
|
||||
if (isRectangularIsometric)
|
||||
bitmapWidth = 2 * bitmapWidth - 1;
|
||||
|
||||
var stride = bitmapWidth * 4;
|
||||
var pxStride = 4;
|
||||
var minimapData = new byte[stride * height];
|
||||
(Color Left, Color Right) terrainColor = default((Color, Color));
|
||||
|
||||
for (var y = 0; y < height; y++)
|
||||
for (var x = 0; x < width; x++)
|
||||
{
|
||||
for (var x = 0; x < width; x++)
|
||||
var uv = new MPos(x + Bounds.Left, y + Bounds.Top);
|
||||
|
||||
// FirstOrDefault will return a (MPos.Zero, Color.Transparent) if positions is empty
|
||||
var actorColor = positions.FirstOrDefault(ap => ap.Position == uv).Color;
|
||||
if (actorColor.A == 0)
|
||||
terrainColor = GetTerrainColorPair(uv);
|
||||
|
||||
if (isRectangularIsometric)
|
||||
{
|
||||
var uv = new MPos(x + Bounds.Left, y + Bounds.Top);
|
||||
|
||||
// FirstOrDefault will return a (MPos.Zero, Color.Transparent) if positions is empty
|
||||
var actorColor = positions.FirstOrDefault(ap => ap.Position == uv).Color;
|
||||
if (actorColor.A == 0)
|
||||
terrainColor = GetTerrainColorPair(uv);
|
||||
|
||||
if (isRectangularIsometric)
|
||||
// Odd rows are shifted right by 1px
|
||||
var dx = uv.V & 1;
|
||||
var xOffset = pxStride * (2 * x + dx);
|
||||
if (x + dx > 0)
|
||||
{
|
||||
// Odd rows are shifted right by 1px
|
||||
var dx = uv.V & 1;
|
||||
var xOffset = pxStride * (2 * x + dx);
|
||||
if (x + dx > 0)
|
||||
{
|
||||
var z = y * stride + xOffset - pxStride;
|
||||
var c = actorColor.A == 0 ? terrainColor.Left : actorColor;
|
||||
minimapData[z++] = c.R;
|
||||
minimapData[z++] = c.G;
|
||||
minimapData[z++] = c.B;
|
||||
minimapData[z] = c.A;
|
||||
}
|
||||
|
||||
if (xOffset < stride)
|
||||
{
|
||||
var z = y * stride + xOffset;
|
||||
var c = actorColor.A == 0 ? terrainColor.Right : actorColor;
|
||||
minimapData[z++] = c.R;
|
||||
minimapData[z++] = c.G;
|
||||
minimapData[z++] = c.B;
|
||||
minimapData[z] = c.A;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var z = y * stride + pxStride * x;
|
||||
var z = y * stride + xOffset - pxStride;
|
||||
var c = actorColor.A == 0 ? terrainColor.Left : actorColor;
|
||||
minimapData[z++] = c.R;
|
||||
minimapData[z++] = c.G;
|
||||
minimapData[z++] = c.B;
|
||||
minimapData[z] = c.A;
|
||||
}
|
||||
|
||||
if (xOffset < stride)
|
||||
{
|
||||
var z = y * stride + xOffset;
|
||||
var c = actorColor.A == 0 ? terrainColor.Right : actorColor;
|
||||
minimapData[z++] = c.R;
|
||||
minimapData[z++] = c.G;
|
||||
minimapData[z++] = c.B;
|
||||
minimapData[z] = c.A;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var z = y * stride + pxStride * x;
|
||||
var c = actorColor.A == 0 ? terrainColor.Left : actorColor;
|
||||
minimapData[z++] = c.R;
|
||||
minimapData[z++] = c.G;
|
||||
minimapData[z++] = c.B;
|
||||
minimapData[z] = c.A;
|
||||
}
|
||||
}
|
||||
|
||||
var png = new Png(minimapData, bitmapWidth, height);
|
||||
return png.Save();
|
||||
}
|
||||
|
||||
var png = new Png(minimapData, bitmapWidth, height);
|
||||
return png.Save();
|
||||
}
|
||||
|
||||
public bool Contains(CPos cell)
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return Type.GetHashCode() ^ Index.GetHashCode(); }
|
||||
|
||||
public override string ToString() { return Type + "," + Index; }
|
||||
}
|
||||
|
||||
public struct ResourceTile
|
||||
|
||||
@@ -221,25 +221,30 @@ namespace OpenRA
|
||||
|
||||
public byte GetTerrainIndex(TerrainTile r)
|
||||
{
|
||||
if (!Templates.TryGetValue(r.Type, out var tpl))
|
||||
return defaultWalkableTerrainIndex;
|
||||
|
||||
if (tpl.Contains(r.Index))
|
||||
{
|
||||
var tile = tpl[r.Index];
|
||||
if (tile != null && tile.TerrainType != byte.MaxValue)
|
||||
return tile.TerrainType;
|
||||
}
|
||||
var tile = Templates[r.Type][r.Index];
|
||||
if (tile.TerrainType != byte.MaxValue)
|
||||
return tile.TerrainType;
|
||||
|
||||
return defaultWalkableTerrainIndex;
|
||||
}
|
||||
|
||||
public TerrainTileInfo GetTileInfo(TerrainTile r)
|
||||
{
|
||||
if (!Templates.TryGetValue(r.Type, out var tpl))
|
||||
return null;
|
||||
|
||||
return tpl.Contains(r.Index) ? tpl[r.Index] : null;
|
||||
return Templates[r.Type][r.Index];
|
||||
}
|
||||
|
||||
public bool TryGetTileInfo(TerrainTile r, out TerrainTileInfo info)
|
||||
{
|
||||
if (!Templates.TryGetValue(r.Type, out var tpl) || !tpl.Contains(r.Index))
|
||||
{
|
||||
info = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
info = tpl[r.Index];
|
||||
return info != null;
|
||||
}
|
||||
|
||||
public TerrainTile DefaultTerrainTile { get { return new TerrainTile(Templates.First().Key, 0); } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -41,26 +42,49 @@ namespace OpenRA
|
||||
var resolvedPath = FileSystem.FileSystem.ResolveAssemblyPath(path, manifest, mods);
|
||||
if (resolvedPath == null)
|
||||
throw new FileNotFoundException("Assembly `{0}` not found.".F(path));
|
||||
#if !MONO
|
||||
var loader = new AssemblyLoader(resolvedPath);
|
||||
var platformType = loader.LoadDefaultAssembly();
|
||||
assemblyList.Add(platformType);
|
||||
|
||||
// .NET doesn't provide any way of querying the metadata of an assembly without either:
|
||||
// (a) loading duplicate data into the application domain, breaking the world.
|
||||
// (b) crashing if the assembly has already been loaded.
|
||||
// We can't check the internal name of the assembly, so we'll work off the data instead
|
||||
var hash = CryptoUtil.SHA1Hash(File.ReadAllBytes(resolvedPath));
|
||||
|
||||
if (!ResolvedAssemblies.TryGetValue(hash, out var assembly))
|
||||
{
|
||||
assembly = Assembly.LoadFile(resolvedPath);
|
||||
ResolvedAssemblies.Add(hash, assembly);
|
||||
}
|
||||
|
||||
assemblyList.Add(assembly);
|
||||
#else
|
||||
LoadAssembly(assemblyList, resolvedPath);
|
||||
#endif
|
||||
}
|
||||
|
||||
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
|
||||
assemblies = assemblyList.SelectMany(asm => asm.GetNamespaces().Select(ns => (asm, ns))).ToArray();
|
||||
}
|
||||
|
||||
void LoadAssembly(List<Assembly> assemblyList, string resolvedPath)
|
||||
{
|
||||
// .NET doesn't provide any way of querying the metadata of an assembly without either:
|
||||
// (a) loading duplicate data into the application domain, breaking the world.
|
||||
// (b) crashing if the assembly has already been loaded.
|
||||
// We can't check the internal name of the assembly, so we'll work off the data instead
|
||||
var hash = CryptoUtil.SHA1Hash(File.ReadAllBytes(resolvedPath));
|
||||
|
||||
if (!ResolvedAssemblies.TryGetValue(hash, out var assembly))
|
||||
{
|
||||
assembly = Assembly.LoadFile(resolvedPath);
|
||||
ResolvedAssemblies.Add(hash, assembly);
|
||||
|
||||
// Allow mods to use libraries.
|
||||
var assemblyPath = Path.GetDirectoryName(resolvedPath);
|
||||
if (assemblyPath != null)
|
||||
{
|
||||
foreach (var referencedAssembly in assembly.GetReferencedAssemblies())
|
||||
{
|
||||
var depedencyPath = Path.Combine(assemblyPath, referencedAssembly.Name + ".dll");
|
||||
if (File.Exists(depedencyPath))
|
||||
LoadAssembly(assemblyList, depedencyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assemblyList.Add(assembly);
|
||||
}
|
||||
|
||||
Assembly ResolveAssembly(object sender, ResolveEventArgs e)
|
||||
{
|
||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
@@ -39,6 +39,11 @@
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
|
||||
<AdditionalFiles Include="../stylecop.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Mono)' == ''">
|
||||
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="5.0.0-preview.3-runtime.20214.6" />
|
||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
<Target Name="DisableAnalyzers" BeforeTargets="CoreCompile" Condition="'$(Configuration)'=='Release'">
|
||||
<!-- Disable code style analysis on Release builds to improve compile-time performance -->
|
||||
<ItemGroup Condition="'$(Configuration)'=='Release'">
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace OpenRA
|
||||
public readonly Shroud Shroud;
|
||||
public readonly FrozenActorLayer FrozenActorLayer;
|
||||
|
||||
/// <summary>The faction (including Random, etc) that was selected in the lobby.</summary>
|
||||
/// <summary>The faction (including Random, etc.) that was selected in the lobby.</summary>
|
||||
public readonly FactionInfo DisplayFaction;
|
||||
|
||||
/// <summary>The spawn point index that was assigned for client-based players.</summary>
|
||||
@@ -80,7 +80,8 @@ namespace OpenRA
|
||||
{
|
||||
get
|
||||
{
|
||||
return spectating || WinState != WinState.Undefined;
|
||||
// Players in mission maps must not leave the player view
|
||||
return !inMissionMap && (spectating || WinState != WinState.Undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
362
OpenRA.Game/Support/AssemblyLoader.cs
Normal file
362
OpenRA.Game/Support/AssemblyLoader.cs
Normal file
@@ -0,0 +1,362 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
// Not used/usable on Mono. Only used for Dotnet Core. Based on https://github.com/natemcmaster/DotNetCorePlugins
|
||||
#if !MONO
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
|
||||
namespace OpenRA.Support
|
||||
{
|
||||
public class AssemblyLoader
|
||||
{
|
||||
readonly string mainAssembly;
|
||||
readonly AssemblyLoadContext context;
|
||||
|
||||
public Assembly LoadDefaultAssembly() => context.LoadFromAssemblyPath(mainAssembly);
|
||||
|
||||
public AssemblyLoader(string assemblyFile)
|
||||
{
|
||||
mainAssembly = assemblyFile;
|
||||
var baseDir = Path.GetDirectoryName(assemblyFile);
|
||||
|
||||
context = CreateLoadContext(baseDir, assemblyFile);
|
||||
}
|
||||
|
||||
static AssemblyLoadContext CreateLoadContext(string baseDir, string assemblyFile)
|
||||
{
|
||||
var depsJsonFile = Path.Combine(baseDir, Path.GetFileNameWithoutExtension(assemblyFile) + ".deps.json");
|
||||
|
||||
var builder = new AssemblyLoadContextBuilder();
|
||||
|
||||
builder.TryAddDependencyContext(depsJsonFile, out _);
|
||||
builder.SetBaseDirectory(baseDir);
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
|
||||
public class AssemblyLoadContextBuilder
|
||||
{
|
||||
readonly Dictionary<string, ManagedLibrary> managedLibraries = new Dictionary<string, ManagedLibrary>(StringComparer.Ordinal);
|
||||
readonly Dictionary<string, NativeLibrary> nativeLibraries = new Dictionary<string, NativeLibrary>(StringComparer.Ordinal);
|
||||
string basePath;
|
||||
|
||||
public AssemblyLoadContext Build()
|
||||
{
|
||||
return new ManagedLoadContext(basePath, managedLibraries, nativeLibraries);
|
||||
}
|
||||
|
||||
public AssemblyLoadContextBuilder SetBaseDirectory(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("Argument must not be null or empty.", nameof(path));
|
||||
|
||||
if (!Path.IsPathRooted(path))
|
||||
throw new ArgumentException("Argument must be a full path.", nameof(path));
|
||||
|
||||
basePath = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AssemblyLoadContextBuilder AddManagedLibrary(ManagedLibrary library)
|
||||
{
|
||||
managedLibraries.Add(library.Name.Name, library);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AssemblyLoadContextBuilder AddNativeLibrary(NativeLibrary library)
|
||||
{
|
||||
ValidateRelativePath(library.AppLocalPath);
|
||||
nativeLibraries.Add(library.Name, library);
|
||||
return this;
|
||||
}
|
||||
|
||||
static void ValidateRelativePath(string probingPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(probingPath))
|
||||
throw new ArgumentException("Value must not be null or empty.", nameof(probingPath));
|
||||
|
||||
if (Path.IsPathRooted(probingPath))
|
||||
throw new ArgumentException("Argument must be a relative path.", nameof(probingPath));
|
||||
}
|
||||
}
|
||||
|
||||
class ManagedLoadContext : AssemblyLoadContext
|
||||
{
|
||||
readonly string basePath;
|
||||
readonly Dictionary<string, ManagedLibrary> managedAssemblies;
|
||||
readonly Dictionary<string, NativeLibrary> nativeLibraries;
|
||||
|
||||
static readonly string[] NativeLibraryExtensions;
|
||||
static readonly string[] NativeLibraryPrefixes;
|
||||
|
||||
static readonly string[] ManagedAssemblyExtensions =
|
||||
{
|
||||
".dll",
|
||||
".ni.dll",
|
||||
".exe",
|
||||
".ni.exe"
|
||||
};
|
||||
|
||||
static ManagedLoadContext()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
NativeLibraryPrefixes = new[] { "" };
|
||||
NativeLibraryExtensions = new[] { ".dll" };
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
NativeLibraryPrefixes = new[] { "", "lib", };
|
||||
NativeLibraryExtensions = new[] { ".dylib" };
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
NativeLibraryPrefixes = new[] { "", "lib" };
|
||||
NativeLibraryExtensions = new[] { ".so", ".so.1" };
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeLibraryPrefixes = Array.Empty<string>();
|
||||
NativeLibraryExtensions = Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
public ManagedLoadContext(string baseDirectory, Dictionary<string, ManagedLibrary> managedAssemblies, Dictionary<string, NativeLibrary> nativeLibraries)
|
||||
{
|
||||
basePath = baseDirectory ?? throw new ArgumentNullException(nameof(baseDirectory));
|
||||
this.managedAssemblies = managedAssemblies ?? throw new ArgumentNullException(nameof(managedAssemblies));
|
||||
this.nativeLibraries = nativeLibraries ?? throw new ArgumentNullException(nameof(nativeLibraries));
|
||||
}
|
||||
|
||||
protected override Assembly Load(AssemblyName assemblyName)
|
||||
{
|
||||
// If default context is preferred, check first for types in the default context unless the dependency has been declared as private
|
||||
try
|
||||
{
|
||||
var defaultAssembly = Default.LoadFromAssemblyName(assemblyName);
|
||||
if (defaultAssembly != null)
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Swallow errors in loading from the default context
|
||||
}
|
||||
|
||||
if (managedAssemblies.TryGetValue(assemblyName.Name, out var library) && SearchForLibrary(library, out var path))
|
||||
return LoadFromAssemblyPath(path);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
|
||||
{
|
||||
foreach (var prefix in NativeLibraryPrefixes)
|
||||
if (nativeLibraries.TryGetValue(prefix + unmanagedDllName, out var library) && SearchForLibrary(library, prefix, out var path))
|
||||
return LoadUnmanagedDllFromPath(path);
|
||||
|
||||
return base.LoadUnmanagedDll(unmanagedDllName);
|
||||
}
|
||||
|
||||
bool SearchForLibrary(ManagedLibrary library, out string path)
|
||||
{
|
||||
// 1. Search in base path
|
||||
foreach (var ext in ManagedAssemblyExtensions)
|
||||
{
|
||||
var local = Path.Combine(basePath, library.Name.Name + ext);
|
||||
if (File.Exists(local))
|
||||
{
|
||||
path = local;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
path = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SearchForLibrary(NativeLibrary library, string prefix, out string path)
|
||||
{
|
||||
// 1. Search in base path
|
||||
foreach (var ext in NativeLibraryExtensions)
|
||||
{
|
||||
var candidate = Path.Combine(basePath, $"{prefix}{library.Name}{ext}");
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
path = candidate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Search in base path + app local (for portable deployments of netcoreapp)
|
||||
var local = Path.Combine(basePath, library.AppLocalPath);
|
||||
if (File.Exists(local))
|
||||
{
|
||||
path = local;
|
||||
return true;
|
||||
}
|
||||
|
||||
path = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class ManagedLibrary
|
||||
{
|
||||
public AssemblyName Name { get; private set; }
|
||||
|
||||
public static ManagedLibrary CreateFromPackage(string assetPath)
|
||||
{
|
||||
return new ManagedLibrary
|
||||
{
|
||||
Name = new AssemblyName(Path.GetFileNameWithoutExtension(assetPath))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class NativeLibrary
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public string AppLocalPath { get; private set; }
|
||||
|
||||
public static NativeLibrary CreateFromPackage(string assetPath)
|
||||
{
|
||||
return new NativeLibrary
|
||||
{
|
||||
Name = Path.GetFileNameWithoutExtension(assetPath),
|
||||
AppLocalPath = assetPath
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class DependencyContextExtensions
|
||||
{
|
||||
public static AssemblyLoadContextBuilder TryAddDependencyContext(this AssemblyLoadContextBuilder builder, string depsFilePath, out Exception error)
|
||||
{
|
||||
error = null;
|
||||
try
|
||||
{
|
||||
builder.AddDependencyContext(depsFilePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex;
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static AssemblyLoadContextBuilder AddDependencyContext(this AssemblyLoadContextBuilder builder, string depsFilePath)
|
||||
{
|
||||
var reader = new DependencyContextJsonReader();
|
||||
using (var file = File.OpenRead(depsFilePath))
|
||||
{
|
||||
var deps = reader.Read(file);
|
||||
builder.SetBaseDirectory(Path.GetDirectoryName(depsFilePath));
|
||||
builder.AddDependencyContext(deps);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
static string GetFallbackRid()
|
||||
{
|
||||
string ridBase;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
ridBase = "win10";
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
ridBase = "linux";
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
ridBase = "osx.10.12";
|
||||
else
|
||||
return "any";
|
||||
|
||||
switch (RuntimeInformation.OSArchitecture)
|
||||
{
|
||||
case Architecture.X86:
|
||||
return ridBase + "-x86";
|
||||
case Architecture.X64:
|
||||
return ridBase + "-x64";
|
||||
case Architecture.Arm:
|
||||
return ridBase + "-arm";
|
||||
case Architecture.Arm64:
|
||||
return ridBase + "-arm64";
|
||||
}
|
||||
|
||||
return ridBase;
|
||||
}
|
||||
|
||||
public static AssemblyLoadContextBuilder AddDependencyContext(this AssemblyLoadContextBuilder builder, DependencyContext dependencyContext)
|
||||
{
|
||||
var ridGraph = dependencyContext.RuntimeGraph.Any()
|
||||
? dependencyContext.RuntimeGraph
|
||||
: DependencyContext.Default.RuntimeGraph;
|
||||
|
||||
var rid = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier();
|
||||
var fallbackRid = GetFallbackRid();
|
||||
var fallbackGraph = ridGraph.FirstOrDefault(g => g.Runtime == rid)
|
||||
?? ridGraph.FirstOrDefault(g => g.Runtime == fallbackRid)
|
||||
?? new RuntimeFallbacks("any");
|
||||
|
||||
foreach (var managed in dependencyContext.ResolveRuntimeAssemblies(fallbackGraph))
|
||||
builder.AddManagedLibrary(managed);
|
||||
|
||||
foreach (var native in dependencyContext.ResolveNativeAssets(fallbackGraph))
|
||||
builder.AddNativeLibrary(native);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
static IEnumerable<ManagedLibrary> ResolveRuntimeAssemblies(this DependencyContext depContext, RuntimeFallbacks runtimeGraph)
|
||||
{
|
||||
var rids = GetRids(runtimeGraph);
|
||||
return from library in depContext.RuntimeLibraries
|
||||
from assetPath in SelectAssets(rids, library.RuntimeAssemblyGroups)
|
||||
select ManagedLibrary.CreateFromPackage(assetPath);
|
||||
}
|
||||
|
||||
static IEnumerable<NativeLibrary> ResolveNativeAssets(this DependencyContext depContext, RuntimeFallbacks runtimeGraph)
|
||||
{
|
||||
var rids = GetRids(runtimeGraph);
|
||||
return from library in depContext.RuntimeLibraries
|
||||
from assetPath in SelectAssets(rids, library.NativeLibraryGroups)
|
||||
where !assetPath.EndsWith(".a", StringComparison.Ordinal)
|
||||
select NativeLibrary.CreateFromPackage(assetPath);
|
||||
}
|
||||
|
||||
static IEnumerable<string> GetRids(RuntimeFallbacks runtimeGraph)
|
||||
{
|
||||
return Enumerable.Concat(new[] { runtimeGraph.Runtime }, runtimeGraph?.Fallbacks ?? Enumerable.Empty<string>());
|
||||
}
|
||||
|
||||
static IEnumerable<string> SelectAssets(IEnumerable<string> rids, IEnumerable<RuntimeAssetGroup> groups)
|
||||
{
|
||||
foreach (var rid in rids)
|
||||
{
|
||||
var group = groups.FirstOrDefault(g => g.Runtime == rid);
|
||||
if (group != null)
|
||||
return group.AssetPaths;
|
||||
}
|
||||
|
||||
return groups.GetDefaultAssets();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework Condition="'$(Mono)' == ''">net5.0</TargetFramework>
|
||||
<TargetFramework Condition="'$(Mono)' != ''">netstandard2.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
@@ -17,6 +18,8 @@
|
||||
<CodeAnalysisRuleSet>..\OpenRA.ruleset</CodeAnalysisRuleSet>
|
||||
<Configurations>Release;Debug</Configurations>
|
||||
<AssemblyName>OpenRA</AssemblyName>
|
||||
<IsPublishable Condition="'$(CopyGenericLauncher)' == 'False'">false</IsPublishable>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetPlatform Condition="$([MSBuild]::IsOsPlatform('Windows'))">win-x64</TargetPlatform>
|
||||
@@ -62,4 +65,8 @@
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="netstandard" />
|
||||
<TrimmerRootAssembly Include="System.IO.Pipes" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -32,11 +32,6 @@ namespace OpenRA.Mods.Cnc.FileFormats
|
||||
|
||||
public static class AudReader
|
||||
{
|
||||
public static byte[] LoadSound(byte[] raw, ref int index)
|
||||
{
|
||||
return ImaAdpcmReader.LoadImaAdpcmSound(raw, ref index);
|
||||
}
|
||||
|
||||
public static float SoundLength(Stream s)
|
||||
{
|
||||
var sampleRate = s.ReadUInt16();
|
||||
|
||||
138
OpenRA.Mods.Cnc/FileSystem/MegFile.cs
Normal file
138
OpenRA.Mods.Cnc/FileSystem/MegFile.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Mods.Cnc.FileSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// This class supports loading unencrypted V3 .meg files using
|
||||
/// reference documentation from here https://modtools.petrolution.net/docs/MegFileFormat
|
||||
/// </summary>
|
||||
public class MegV3Loader : IPackageLoader
|
||||
{
|
||||
const uint UnencryptedMegID = 0xFFFFFFFF;
|
||||
|
||||
// Float value 0.99, but it is simpler to read and compare as an integer
|
||||
const uint MegVersion = 0x3F7D70A4;
|
||||
|
||||
public bool TryParsePackage(Stream s, string filename, OpenRA.FileSystem.FileSystem context, out IReadOnlyPackage package)
|
||||
{
|
||||
var position = s.Position;
|
||||
|
||||
var id = s.ReadUInt32();
|
||||
var version = s.ReadUInt32();
|
||||
|
||||
s.Position = position;
|
||||
|
||||
if (id != UnencryptedMegID || version != MegVersion)
|
||||
{
|
||||
package = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
package = new MegFile(s, filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
public sealed class MegFile : IReadOnlyPackage
|
||||
{
|
||||
readonly Stream s;
|
||||
|
||||
readonly Dictionary<string, (uint Offset, int Length)> contents = new Dictionary<string, (uint Offset, int Length)>();
|
||||
|
||||
public MegFile(Stream s, string filename)
|
||||
{
|
||||
Name = filename;
|
||||
this.s = s;
|
||||
|
||||
var id = s.ReadUInt32();
|
||||
var version = s.ReadUInt32();
|
||||
|
||||
if (id != UnencryptedMegID || version != MegVersion)
|
||||
throw new Exception("Invalid file signature for meg file");
|
||||
|
||||
var headerSize = s.ReadUInt32();
|
||||
var numStrings = s.ReadUInt32();
|
||||
var numFiles = s.ReadUInt32();
|
||||
var stringsSize = s.ReadUInt32();
|
||||
var stringsStart = s.Position;
|
||||
|
||||
var filenames = new List<string>();
|
||||
|
||||
// The file names are an indexed array of strings
|
||||
for (var i = 0; i < numStrings; i++)
|
||||
{
|
||||
var length = s.ReadUInt16();
|
||||
filenames.Add(s.ReadASCII(length));
|
||||
}
|
||||
|
||||
// The header indicates where we should be, so verify it
|
||||
if (s.Position != stringsSize + stringsStart)
|
||||
throw new Exception("File name table in .meg file inconsistent");
|
||||
|
||||
// Now we load each file entry and associated info
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
// Ignore flags, crc, index
|
||||
s.Position += 10;
|
||||
var size = s.ReadUInt32();
|
||||
var offset = s.ReadUInt32();
|
||||
var nameIndex = s.ReadUInt16();
|
||||
contents[filenames[nameIndex]] = (offset, (int)size);
|
||||
}
|
||||
|
||||
if (s.Position != headerSize)
|
||||
throw new Exception("Expected to be at data start offset");
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public IEnumerable<string> Contents => contents.Keys;
|
||||
|
||||
public bool Contains(string filename)
|
||||
{
|
||||
return contents.ContainsKey(filename);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
s.Dispose();
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
{
|
||||
// Look up the index of the filename
|
||||
if (!contents.TryGetValue(filename, out var index))
|
||||
return null;
|
||||
|
||||
return SegmentStream.CreateWithoutOwningStream(s, index.Offset, index.Length);
|
||||
}
|
||||
|
||||
public IReadOnlyPackage OpenPackage(string filename, OpenRA.FileSystem.FileSystem context)
|
||||
{
|
||||
var childStream = GetStream(filename);
|
||||
if (childStream == null)
|
||||
return null;
|
||||
|
||||
if (context.TryParsePackage(childStream, filename, out var package))
|
||||
return package;
|
||||
|
||||
childStream.Dispose();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
@@ -11,6 +11,7 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<CodeAnalysisRuleSet>..\OpenRA.ruleset</CodeAnalysisRuleSet>
|
||||
<IsPublishable Condition="'$(CopyCncDll)' == 'False'">false</IsPublishable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Work around an issue where Rider does not detect files in the project root using the default glob -->
|
||||
@@ -37,4 +38,4 @@
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -79,8 +79,8 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
[Desc("The condition to grant to self while disguised.")]
|
||||
public readonly string DisguisedCondition = null;
|
||||
|
||||
[Desc("What diplomatic stances can this actor disguise as.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Player relationships the owner of the disguise target needs.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Target types of actors that this actor disguise as.")]
|
||||
public readonly BitSet<TargetableType> TargetTypes = new BitSet<TargetableType>("Disguise");
|
||||
@@ -299,7 +299,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var stance = self.Owner.RelationshipWith(target.Owner);
|
||||
if (!info.ValidStances.HasStance(stance))
|
||||
if (!info.ValidRelationships.HasStance(stance))
|
||||
return false;
|
||||
|
||||
return info.TargetTypes.Overlaps(target.GetAllTargetTypes());
|
||||
@@ -308,7 +308,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var stance = self.Owner.RelationshipWith(target.Owner);
|
||||
if (!info.ValidStances.HasStance(stance))
|
||||
if (!info.ValidRelationships.HasStance(stance))
|
||||
return false;
|
||||
|
||||
return info.TargetTypes.Overlaps(target.Info.GetAllTargetTypes());
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
|
||||
protected override bool ShouldRender(Actor self)
|
||||
{
|
||||
return infiltrators.Any(i => Info.ValidStances.HasStance(i.RelationshipWith(self.World.RenderPlayer)));
|
||||
return infiltrators.Any(i => Info.ValidRelationships.HasStance(i.RelationshipWith(self.World.RenderPlayer)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
[Desc("Color to use for the target line.")]
|
||||
public readonly Color TargetLineColor = Color.Crimson;
|
||||
|
||||
[Desc("What diplomatic stances can be infiltrated by this actor.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Player relationships the owner of the infiltration target needs.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Behaviour when entering the target.",
|
||||
"Possible values are Exit, Suicide, Dispose.")]
|
||||
@@ -101,10 +101,10 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
{
|
||||
case TargetType.Actor:
|
||||
return Info.Types.Overlaps(target.Actor.GetEnabledTargetTypes()) &&
|
||||
Info.ValidStances.HasStance(self.Owner.RelationshipWith(target.Actor.Owner));
|
||||
Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(target.Actor.Owner));
|
||||
case TargetType.FrozenActor:
|
||||
return target.FrozenActor.IsValid && Info.Types.Overlaps(target.FrozenActor.TargetTypes) &&
|
||||
Info.ValidStances.HasStance(self.Owner.RelationshipWith(target.FrozenActor.Owner));
|
||||
Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(target.FrozenActor.Owner));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var stance = self.Owner.RelationshipWith(target.Owner);
|
||||
if (!info.ValidStances.HasStance(stance))
|
||||
if (!info.ValidRelationships.HasStance(stance))
|
||||
return false;
|
||||
|
||||
return info.Types.Overlaps(target.GetAllTargetTypes());
|
||||
@@ -145,7 +145,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var stance = self.Owner.RelationshipWith(target.Owner);
|
||||
if (!info.ValidStances.HasStance(stance))
|
||||
if (!info.ValidRelationships.HasStance(stance))
|
||||
return false;
|
||||
|
||||
return info.Types.Overlaps(target.Info.GetAllTargetTypes());
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
foreach (var t in enterActor.TraitsImplementing<INotifyCapture>())
|
||||
t.OnCapture(enterActor, self, oldOwner, self.Owner, captures.Info.CaptureTypes);
|
||||
|
||||
if (self.Owner.RelationshipWith(oldOwner).HasStance(captures.Info.PlayerExperienceStances))
|
||||
if (self.Owner.RelationshipWith(oldOwner).HasStance(captures.Info.PlayerExperienceRelationships))
|
||||
self.Owner.PlayerActor.TraitOrDefault<PlayerExperience>()?.GiveExperience(captures.Info.PlayerExperience);
|
||||
|
||||
if (captures.Info.ConsumedByCapture)
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
// Make sure we can still repair the target before entering
|
||||
// (but not before, because this may stop the actor in the middle of nowhere)
|
||||
var stance = self.Owner.RelationshipWith(enterActor.Owner);
|
||||
if (enterHealth == null || enterHealth.DamageState == DamageState.Undamaged || enterEngineerRepariable == null || enterEngineerRepariable.IsTraitDisabled || !info.ValidStances.HasStance(stance))
|
||||
if (enterHealth == null || enterHealth.DamageState == DamageState.Undamaged || enterEngineerRepariable == null || enterEngineerRepariable.IsTraitDisabled || !info.ValidRelationships.HasStance(stance))
|
||||
{
|
||||
Cancel(self, true);
|
||||
return false;
|
||||
@@ -61,7 +61,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return;
|
||||
|
||||
var stance = self.Owner.RelationshipWith(enterActor.Owner);
|
||||
if (!info.ValidStances.HasStance(stance))
|
||||
if (!info.ValidRelationships.HasStance(stance))
|
||||
return;
|
||||
|
||||
if (enterHealth.DamageState == DamageState.Undamaged)
|
||||
|
||||
@@ -89,9 +89,6 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
var tile = world.Map.Tiles[cell];
|
||||
var tileInfo = world.Map.Rules.TileSet.GetTileInfo(tile);
|
||||
if (tileInfo == null)
|
||||
return false;
|
||||
|
||||
var terrainType = world.Map.Rules.TileSet.TerrainInfo[tileInfo.TerrainType];
|
||||
|
||||
if (mapResources[cell].Type == ResourceType.ResourceType)
|
||||
|
||||
@@ -23,16 +23,14 @@ namespace OpenRA.Mods.Common.Effects
|
||||
readonly RallyPoint rp;
|
||||
readonly Animation flag;
|
||||
readonly Animation circles;
|
||||
readonly ExitInfo[] exits;
|
||||
|
||||
List<WPos> targetLineNodes = new List<WPos> { };
|
||||
List<CPos> cachedLocations;
|
||||
|
||||
public RallyPointIndicator(Actor building, RallyPoint rp, ExitInfo[] exits)
|
||||
public RallyPointIndicator(Actor building, RallyPoint rp)
|
||||
{
|
||||
this.building = building;
|
||||
this.rp = rp;
|
||||
this.exits = exits;
|
||||
|
||||
if (rp.Info.Image != null)
|
||||
{
|
||||
@@ -73,21 +71,8 @@ namespace OpenRA.Mods.Common.Effects
|
||||
if (targetLineNodes.Count == 0)
|
||||
return;
|
||||
|
||||
var exitPos = building.CenterPosition;
|
||||
|
||||
// Find closest exit
|
||||
var dist = int.MaxValue;
|
||||
foreach (var exit in exits)
|
||||
{
|
||||
var ep = building.CenterPosition + exit.SpawnOffset;
|
||||
var len = (targetLineNodes[0] - ep).Length;
|
||||
if (len < dist)
|
||||
{
|
||||
dist = len;
|
||||
exitPos = ep;
|
||||
}
|
||||
}
|
||||
|
||||
var exit = building.NearestExitOrDefault(targetLineNodes[0]);
|
||||
var exitPos = exit != null ? building.World.Map.CenterOfCell(building.Location + exit.Info.ExitCell) : building.CenterPosition;
|
||||
targetLineNodes.Insert(0, exitPos);
|
||||
}
|
||||
|
||||
|
||||
25
OpenRA.Mods.Common/Lint/CheckMapTiles.cs
Normal file
25
OpenRA.Mods.Common/Lint/CheckMapTiles.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Mods.Common.Lint
|
||||
{
|
||||
public class CheckMapTiles : ILintMapPass
|
||||
{
|
||||
public void Run(Action<string> emitError, Action<string> emitWarning, ModData modData, Map map)
|
||||
{
|
||||
foreach (var kv in map.ReplacedInvalidTerrainTiles)
|
||||
emitError("Cell {0} references invalid terrain tile {1}.".F(kv.Key, kv.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
@@ -11,6 +11,7 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<CodeAnalysisRuleSet>..\OpenRA.ruleset</CodeAnalysisRuleSet>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Work around an issue where Rider does not detect files in the project root using the default glob -->
|
||||
@@ -24,6 +25,7 @@
|
||||
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
|
||||
<PackageReference Include="OpenRA-FuzzyLogicLibrary" Version="1.0.1" />
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.150" />
|
||||
<PackageReference Include="rix0rrr.BeaconLib" Version="1.0.2" />
|
||||
|
||||
@@ -96,8 +96,8 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
[Desc("Terrain where the projectile explodes instead of bouncing.")]
|
||||
public readonly HashSet<string> InvalidBounceTerrain = new HashSet<string>();
|
||||
|
||||
[Desc("If projectile touches an actor with one of these stances during or after the first bounce, trigger explosion.")]
|
||||
public readonly PlayerRelationship ValidBounceBlockerStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
|
||||
[Desc("Trigger the explosion if the projectile touches an actor thats owner has these player relationships.")]
|
||||
public readonly PlayerRelationship ValidBounceBlockerRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
|
||||
|
||||
[Desc("Altitude above terrain below which to explode. Zero effectively deactivates airburst.")]
|
||||
public readonly WDist AirburstAltitude = WDist.Zero;
|
||||
@@ -319,7 +319,7 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
if (checkTargetType && !Target.FromActor(victim).IsValidFor(firedBy))
|
||||
continue;
|
||||
|
||||
if (!info.ValidBounceBlockerStances.HasStance(firedBy.Owner.RelationshipWith(victim.Owner)))
|
||||
if (!info.ValidBounceBlockerRelationships.HasStance(firedBy.Owner.RelationshipWith(victim.Owner)))
|
||||
continue;
|
||||
|
||||
// If the impact position is within any actor's HitShape, we have a direct hit
|
||||
|
||||
@@ -13,6 +13,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using BeaconLib;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Server;
|
||||
@@ -107,7 +108,7 @@ namespace OpenRA.Mods.Common.Server
|
||||
{
|
||||
isBusy = true;
|
||||
|
||||
Action a = () =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -160,9 +161,7 @@ namespace OpenRA.Mods.Common.Server
|
||||
}
|
||||
|
||||
isBusy = false;
|
||||
};
|
||||
|
||||
a.BeginInvoke(null, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Accepted `DeliversCash` types. Leave empty to accept all types.")]
|
||||
public readonly HashSet<string> ValidTypes = new HashSet<string>();
|
||||
|
||||
[Desc("Stance the delivering actor needs to enter.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
[Desc("Player relationships the owner of the delivering actor needs.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Play a randomly selected sound from this list when accepting cash.")]
|
||||
public readonly string[] Sounds = { };
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public class AcceptsDeliveredCash : INotifyCashTransfer
|
||||
{
|
||||
AcceptsDeliveredCashInfo info;
|
||||
readonly AcceptsDeliveredCashInfo info;
|
||||
|
||||
public AcceptsDeliveredCash(Actor self, AcceptsDeliveredCashInfo info)
|
||||
{
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Accepted `DeliversExperience` types. Leave empty to accept all types.")]
|
||||
public readonly HashSet<string> ValidTypes = new HashSet<string>();
|
||||
|
||||
[Desc("Stance the delivering actor needs to enter.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
[Desc("Player relationships the owner of the delivering actor needs.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new AcceptsDeliveredExperience(init.Self, this); }
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public WeaponInfo WeaponInfo { get; private set; }
|
||||
public WDist ModifiedRange { get; private set; }
|
||||
|
||||
public readonly PlayerRelationship TargetStances = PlayerRelationship.Enemy;
|
||||
public readonly PlayerRelationship ForceTargetStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally;
|
||||
public readonly PlayerRelationship TargetRelationships = PlayerRelationship.Enemy;
|
||||
public readonly PlayerRelationship ForceTargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally;
|
||||
|
||||
// TODO: instead of having multiple Armaments and unique AttackBase,
|
||||
// an actor should be able to have multiple AttackBases with
|
||||
|
||||
@@ -377,7 +377,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
return Armaments.Where(a =>
|
||||
!a.IsTraitDisabled
|
||||
&& (owner == null || (forceAttack ? a.Info.ForceTargetStances : a.Info.TargetStances).HasStance(self.Owner.RelationshipWith(owner)))
|
||||
&& (owner == null || (forceAttack ? a.Info.ForceTargetRelationships : a.Info.TargetRelationships).HasStance(self.Owner.RelationshipWith(owner)))
|
||||
&& a.Weapon.IsValidAgainst(t, self.World, self));
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
var stances = PlayerRelationship.None;
|
||||
foreach (var armament in Armaments)
|
||||
if (!armament.IsTraitDisabled)
|
||||
stances |= armament.Info.TargetStances;
|
||||
stances |= armament.Info.TargetRelationships;
|
||||
|
||||
return stances;
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return activeTargetPriorities.Any(ati =>
|
||||
{
|
||||
// Incompatible stances
|
||||
if (!ati.ValidStances.HasStance(self.Owner.RelationshipWith(owner)))
|
||||
if (!ati.ValidRelationships.HasStance(self.Owner.RelationshipWith(owner)))
|
||||
return false;
|
||||
|
||||
// Incompatible target types
|
||||
@@ -391,7 +391,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return false;
|
||||
|
||||
// Incompatible stances
|
||||
if (!ati.ValidStances.HasStance(self.Owner.RelationshipWith(owner)))
|
||||
if (!ati.ValidRelationships.HasStance(self.Owner.RelationshipWith(owner)))
|
||||
return false;
|
||||
|
||||
// Incompatible target types
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Target types that can't be AutoTargeted.", "Overrules ValidTargets.")]
|
||||
public readonly BitSet<TargetableType> InvalidTargets;
|
||||
|
||||
[Desc("Stances between actor's and target's owner which can be AutoTargeted.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Relationships between actor's and target's owner needed for AutoTargeting.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("ValidTargets with larger priorities will be AutoTargeted before lower priorities.")]
|
||||
public readonly int Priority = 1;
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Should visibility (Shroud, Fog, Cloak, etc) be considered when searching for capturable targets?")]
|
||||
public readonly bool CheckCaptureTargetsForVisibility = true;
|
||||
|
||||
[Desc("Player stances that capturers should attempt to target.")]
|
||||
public readonly PlayerRelationship CapturableStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
|
||||
[Desc("Player relationships that capturers should attempt to target.")]
|
||||
public readonly PlayerRelationship CapturableRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new CaptureManagerBotModule(init.Self, this); }
|
||||
}
|
||||
@@ -133,7 +133,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return;
|
||||
|
||||
var randPlayer = world.Players.Where(p => !p.Spectating
|
||||
&& Info.CapturableStances.HasStance(player.RelationshipWith(p))).Random(world.LocalRandom);
|
||||
&& Info.CapturableRelationships.HasStance(player.RelationshipWith(p))).Random(world.LocalRandom);
|
||||
|
||||
var targetOptions = Info.CheckCaptureTargetsForVisibility
|
||||
? GetVisibleActorsBelongingToPlayer(randPlayer)
|
||||
|
||||
@@ -75,13 +75,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
// Display only the first level of priority
|
||||
var priorityExits = self.Info.TraitInfos<ExitInfo>()
|
||||
.GroupBy(e => e.Priority)
|
||||
.FirstOrDefault();
|
||||
|
||||
var exits = priorityExits != null ? priorityExits.ToArray() : new ExitInfo[0];
|
||||
self.World.Add(new RallyPointIndicator(self, this, exits));
|
||||
self.World.Add(new RallyPointIndicator(self, this));
|
||||
}
|
||||
|
||||
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("CaptureTypes (from the Captures trait) that are able to capture this.")]
|
||||
public readonly BitSet<CaptureType> Types = default(BitSet<CaptureType>);
|
||||
|
||||
[Desc("What diplomatic stances can be captured by this actor.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("What player relationships the target's owner needs to be captured by this actor.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Cancel the actor's current activity when getting captured.")]
|
||||
public readonly bool CancelActivity = false;
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// Actors with FrozenUnderFog should therefore not disable the Capturable trait.
|
||||
var stance = captor.Owner.RelationshipWith(frozenActor.Owner);
|
||||
return frozenActor.Info.TraitInfos<CapturableInfo>()
|
||||
.Any(c => c.ValidStances.HasStance(stance) && captures.Info.CaptureTypes.Overlaps(c.Types));
|
||||
.Any(c => c.ValidRelationships.HasStance(stance) && captures.Info.CaptureTypes.Overlaps(c.Types));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,13 +108,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
allyCapturableTypes = neutralCapturableTypes = enemyCapturableTypes = default(BitSet<CaptureType>);
|
||||
foreach (var c in enabledCapturable)
|
||||
{
|
||||
if (c.Info.ValidStances.HasStance(PlayerRelationship.Ally))
|
||||
if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Ally))
|
||||
allyCapturableTypes = allyCapturableTypes.Union(c.Info.Types);
|
||||
|
||||
if (c.Info.ValidStances.HasStance(PlayerRelationship.Neutral))
|
||||
if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Neutral))
|
||||
neutralCapturableTypes = neutralCapturableTypes.Union(c.Info.Types);
|
||||
|
||||
if (c.Info.ValidStances.HasStance(PlayerRelationship.Enemy))
|
||||
if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Enemy))
|
||||
enemyCapturableTypes = enemyCapturableTypes.Union(c.Info.Types);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Experience granted to the capturing player.")]
|
||||
public readonly int PlayerExperience = 0;
|
||||
|
||||
[Desc("Stance that the structure's previous owner needs to have for the capturing player to receive Experience.")]
|
||||
public readonly PlayerRelationship PlayerExperienceStances = PlayerRelationship.Enemy;
|
||||
[Desc("Relationships that the structure's previous owner needs to have for the capturing player to receive Experience.")]
|
||||
public readonly PlayerRelationship PlayerExperienceRelationships = PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Cursor to display when the health of the target actor is above the sabotage threshold.")]
|
||||
public readonly string SabotageCursor = "capture";
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
"Ignored if 0 (actors are selected regardless of vertical distance).")]
|
||||
public readonly WDist MaximumVerticalOffset = WDist.Zero;
|
||||
|
||||
[Desc("What diplomatic stances are affected.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
[Desc("What player relationships are affected.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Condition is applied permanently to this actor.")]
|
||||
public readonly bool AffectsParent = false;
|
||||
@@ -111,7 +111,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return;
|
||||
|
||||
var stance = self.Owner.RelationshipWith(a.Owner);
|
||||
if (!Info.ValidStances.HasStance(stance))
|
||||
if (!Info.ValidRelationships.HasStance(stance))
|
||||
return;
|
||||
|
||||
var external = a.TraitsImplementing<ExternalCondition>()
|
||||
@@ -135,7 +135,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if ((produced.CenterPosition - self.CenterPosition).HorizontalLengthSquared <= Info.Range.LengthSquared)
|
||||
{
|
||||
var stance = self.Owner.RelationshipWith(produced.Owner);
|
||||
if (!Info.ValidStances.HasStance(stance))
|
||||
if (!Info.ValidRelationships.HasStance(stance))
|
||||
return;
|
||||
|
||||
var external = produced.TraitsImplementing<ExternalCondition>()
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class CreatesShroudInfo : AffectsShroudInfo
|
||||
{
|
||||
[Desc("Stance the watching player needs to see the generated shroud.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Relationship the watching player needs to see the generated shroud.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new CreatesShroud(init.Self, this); }
|
||||
}
|
||||
@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
protected override void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv)
|
||||
{
|
||||
if (!info.ValidStances.HasStance(self.Owner.RelationshipWith(p)))
|
||||
if (!info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)))
|
||||
return;
|
||||
|
||||
p.Shroud.AddSource(this, Shroud.SourceType.Shroud, uv);
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredCashInfo>();
|
||||
if (targetInfo == null || !targetInfo.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
return false;
|
||||
|
||||
if (targetInfo.ValidTypes.Count == 0)
|
||||
@@ -112,7 +112,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredCashInfo>();
|
||||
if (targetInfo == null || !targetInfo.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
return false;
|
||||
|
||||
if (targetInfo.ValidTypes.Count == 0)
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return false;
|
||||
|
||||
var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredExperienceInfo>();
|
||||
if (targetInfo == null || !targetInfo.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
return false;
|
||||
|
||||
if (targetInfo.ValidTypes.Count == 0)
|
||||
@@ -129,7 +129,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return false;
|
||||
|
||||
var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredExperienceInfo>();
|
||||
if (targetInfo == null || !targetInfo.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
return false;
|
||||
|
||||
if (targetInfo.ValidTypes.Count == 0)
|
||||
|
||||
@@ -47,8 +47,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Color to use for the target line.")]
|
||||
public readonly Color TargetLineColor = Color.Crimson;
|
||||
|
||||
public readonly PlayerRelationship TargetStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
|
||||
public readonly PlayerRelationship ForceTargetStances = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally;
|
||||
public readonly PlayerRelationship TargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral;
|
||||
public readonly PlayerRelationship ForceTargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Cursor to display when hovering over a demolishable target.")]
|
||||
public readonly string Cursor = "c4";
|
||||
@@ -118,10 +118,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return false;
|
||||
|
||||
var stance = target.Owner.RelationshipWith(self.Owner);
|
||||
if (!info.TargetStances.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||
if (!info.TargetRelationships.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||
return false;
|
||||
|
||||
if (!info.ForceTargetStances.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||
if (!info.ForceTargetRelationships.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||
return false;
|
||||
|
||||
return target.TraitsImplementing<IDemolishable>().Any(i => i.IsValidTarget(target, self));
|
||||
@@ -130,10 +130,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var stance = target.Owner.RelationshipWith(self.Owner);
|
||||
if (!info.TargetStances.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||
if (!info.TargetRelationships.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||
return false;
|
||||
|
||||
if (!info.ForceTargetStances.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||
if (!info.ForceTargetRelationships.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||
return false;
|
||||
|
||||
return target.Info.TraitInfos<IDemolishableInfo>().Any(i => i.IsValidTarget(target.Info, self));
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
"Possible values are Exit, Suicide, Dispose.")]
|
||||
public readonly EnterBehaviour EnterBehaviour = EnterBehaviour.Dispose;
|
||||
|
||||
[Desc("What diplomatic stances allow target to be repaired by this actor.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
[Desc("What player relationship the target's owner needs to be repaired by this actor.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Sound to play when repairing is done.")]
|
||||
public readonly string RepairSound = null;
|
||||
@@ -117,7 +117,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!engineerRepairable.Info.Types.IsEmpty && !engineerRepairable.Info.Types.Overlaps(info.Types))
|
||||
return false;
|
||||
|
||||
if (!info.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
if (!info.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
return false;
|
||||
|
||||
if (target.GetDamageState() == DamageState.Undamaged)
|
||||
@@ -139,7 +139,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!engineerRepairable.Types.IsEmpty && !engineerRepairable.Types.Overlaps(info.Types))
|
||||
return false;
|
||||
|
||||
if (!info.ValidStances.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
if (!info.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner)))
|
||||
return false;
|
||||
|
||||
if (target.DamageState == DamageState.Undamaged)
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Percentage of the killed actor's Cost or CustomSellValue to be given.")]
|
||||
public readonly int Percentage = 10;
|
||||
|
||||
[Desc("Stance the attacking player needs to receive the bounty.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Player relationships the attacking player needs to receive the bounty.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Whether to show a floating text announcing the won bounty.")]
|
||||
public readonly bool ShowBounty = true;
|
||||
@@ -64,7 +64,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (e.Attacker == null || e.Attacker.Disposed || IsTraitDisabled)
|
||||
return;
|
||||
|
||||
if (!Info.ValidStances.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner)))
|
||||
if (!Info.ValidRelationships.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner)))
|
||||
return;
|
||||
|
||||
if (!Info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(Info.DeathTypes))
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("If -1, use the value of the unit cost.")]
|
||||
public readonly int Experience = -1;
|
||||
|
||||
[Desc("Stance the attacking player needs to receive the experience.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Player relationships the attacking player needs to receive the experience.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Percentage of the `Experience` value that is being granted to the killing actor.")]
|
||||
public readonly int ActorExperienceModifier = 10000;
|
||||
@@ -59,7 +59,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (exp == 0 || e.Attacker == null || e.Attacker.Disposed)
|
||||
return;
|
||||
|
||||
if (!info.ValidStances.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner)))
|
||||
if (!info.ValidRelationships.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner)))
|
||||
return;
|
||||
|
||||
exp = Util.ApplyPercentageModifiers(exp, experienceModifiers);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -28,6 +30,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Chance (out of 100) the unit has to enter panic mode when attacking.")]
|
||||
public readonly int AttackPanicChance = 20;
|
||||
|
||||
[Desc("The terrain types that this actor should avoid running on to while panicking.")]
|
||||
public readonly HashSet<string> AvoidTerrainTypes = new HashSet<string>();
|
||||
|
||||
[SequenceReference(prefix: true)]
|
||||
public readonly string PanicSequencePrefix = "panic-";
|
||||
|
||||
@@ -39,6 +44,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
readonly ScaredyCatInfo info;
|
||||
readonly Mobile mobile;
|
||||
readonly Actor self;
|
||||
readonly Func<CPos, bool> avoidTerrainFilter;
|
||||
|
||||
[Sync]
|
||||
int panicStartedTick;
|
||||
@@ -52,6 +58,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
this.self = self;
|
||||
this.info = info;
|
||||
mobile = self.Trait<Mobile>();
|
||||
|
||||
if (info.AvoidTerrainTypes.Count > 0)
|
||||
avoidTerrainFilter = c => info.AvoidTerrainTypes.Contains(self.World.Map.GetTerrainInfo(c).Type);
|
||||
}
|
||||
|
||||
public void Panic()
|
||||
@@ -79,7 +88,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!Panicking)
|
||||
return;
|
||||
|
||||
mobile.Nudge(self);
|
||||
// Note: This is just a modified copy of Mobile.Nudge
|
||||
var cell = mobile.GetAdjacentCell(self.Location, avoidTerrainFilter);
|
||||
if (cell != null)
|
||||
self.QueueActivity(false, mobile.MoveTo(cell.Value, 0));
|
||||
}
|
||||
|
||||
void INotifyDamage.Damaged(Actor self, AttackInfo e)
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Range of the deflection.")]
|
||||
public readonly WDist Range = WDist.Zero;
|
||||
|
||||
[Desc("What diplomatic stances are affected.")]
|
||||
public readonly PlayerRelationship DeflectionStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("What player relationships are affected.")]
|
||||
public readonly PlayerRelationship DeflectionRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Chance of deflecting missiles.")]
|
||||
public readonly int Chance = 100;
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public class JamsMissiles : ConditionalTrait<JamsMissilesInfo>
|
||||
{
|
||||
public WDist Range { get { return IsTraitDisabled ? WDist.Zero : Info.Range; } }
|
||||
public PlayerRelationship DeflectionStances { get { return Info.DeflectionStances; } }
|
||||
public PlayerRelationship DeflectionStances { get { return Info.DeflectionRelationships; } }
|
||||
public int Chance { get { return Info.Chance; } }
|
||||
|
||||
public JamsMissiles(JamsMissilesInfo info)
|
||||
|
||||
@@ -364,14 +364,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
self.QueueActivity(false, MoveTo(cell.Value, 0));
|
||||
}
|
||||
|
||||
public CPos? GetAdjacentCell(CPos nextCell)
|
||||
public CPos? GetAdjacentCell(CPos nextCell, Func<CPos, bool> preferToAvoid = null)
|
||||
{
|
||||
var availCells = new List<CPos>();
|
||||
var notStupidCells = new List<CPos>();
|
||||
foreach (CVec direction in CVec.Directions)
|
||||
{
|
||||
var p = ToCell + direction;
|
||||
if (CanEnterCell(p) && CanStayInCell(p))
|
||||
if (CanEnterCell(p) && CanStayInCell(p) && (preferToAvoid == null || !preferToAvoid(p)))
|
||||
availCells.Add(p);
|
||||
else if (p != nextCell && p != ToCell)
|
||||
notStupidCells.Add(p);
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("This actor will remain visible (but not updated visually) under fog, once discovered.")]
|
||||
public class FrozenUnderFogInfo : TraitInfo, Requires<BuildingInfo>, IDefaultVisibilityInfo
|
||||
{
|
||||
[Desc("Players with these stances can always see the actor.")]
|
||||
public readonly PlayerRelationship AlwaysVisibleStances = PlayerRelationship.Ally;
|
||||
[Desc("Players with these relationships can always see the actor.")]
|
||||
public readonly PlayerRelationship AlwaysVisibleRelationships = PlayerRelationship.Ally;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); }
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return true;
|
||||
|
||||
var stance = self.Owner.RelationshipWith(byPlayer);
|
||||
return info.AlwaysVisibleStances.HasStance(stance) || IsVisibleInner(self, byPlayer);
|
||||
return info.AlwaysVisibleRelationships.HasStance(stance) || IsVisibleInner(self, byPlayer);
|
||||
}
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("The actor stays invisible under the shroud.")]
|
||||
public class HiddenUnderShroudInfo : TraitInfo, IDefaultVisibilityInfo
|
||||
{
|
||||
[Desc("Players with these stances can always see the actor.")]
|
||||
public readonly PlayerRelationship AlwaysVisibleStances = PlayerRelationship.Ally;
|
||||
[Desc("Players with these relationships can always see the actor.")]
|
||||
public readonly PlayerRelationship AlwaysVisibleRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Possible values are CenterPosition (reveal when the center is visible) and ",
|
||||
"Footprint (reveal when any footprint cell is visible).")]
|
||||
@@ -56,7 +56,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return true;
|
||||
|
||||
var stance = self.Owner.RelationshipWith(byPlayer);
|
||||
return Info.AlwaysVisibleStances.HasStance(stance) || IsVisibleInner(self, byPlayer);
|
||||
return Info.AlwaysVisibleRelationships.HasStance(stance) || IsVisibleInner(self, byPlayer);
|
||||
}
|
||||
|
||||
IEnumerable<IRenderable> IRenderModifier.ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -58,15 +59,19 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[NotificationReference("Speech")]
|
||||
public readonly string LeaveNotification = null;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new MissionObjectives(init.World, this); }
|
||||
public override object Create(ActorInitializer init) { return new MissionObjectives(init.Self.Owner, this); }
|
||||
}
|
||||
|
||||
public class MissionObjectives : INotifyWinStateChanged, ISync, IResolveOrder
|
||||
public class MissionObjectives : INotifyWinStateChanged, ISync, IResolveOrder, IWorldLoaded
|
||||
{
|
||||
public readonly MissionObjectivesInfo Info;
|
||||
readonly List<MissionObjective> objectives = new List<MissionObjective>();
|
||||
readonly Player player;
|
||||
public ReadOnlyList<MissionObjective> Objectives;
|
||||
|
||||
Player[] enemies;
|
||||
Player[] allies;
|
||||
|
||||
[Sync]
|
||||
public int ObjectivesHash
|
||||
{
|
||||
@@ -83,12 +88,21 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// The player's WinState is only updated when his allies have all completed their objective as well.
|
||||
public WinState WinStateCooperative { get; private set; }
|
||||
|
||||
public MissionObjectives(World world, MissionObjectivesInfo info)
|
||||
public MissionObjectives(Player player, MissionObjectivesInfo info)
|
||||
{
|
||||
Info = info;
|
||||
this.player = player;
|
||||
Objectives = new ReadOnlyList<MissionObjective>(objectives);
|
||||
}
|
||||
|
||||
void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr)
|
||||
{
|
||||
// Players and NonCombatants are fixed once the game starts, but the result of IsAlliedWith
|
||||
// may change once players are marked as spectators, so cache these
|
||||
allies = player.World.Players.Where(p => !p.NonCombatant && player.IsAlliedWith(p)).ToArray();
|
||||
enemies = player.World.Players.Where(p => !p.NonCombatant && player.RelationshipWith(p) == PlayerRelationship.Enemy).ToArray();
|
||||
}
|
||||
|
||||
public int Add(Player player, string description, string type, bool required = true, bool inhibitAnnouncement = false)
|
||||
{
|
||||
var newID = objectives.Count;
|
||||
@@ -140,10 +154,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
void CheckIfGameIsOver(Player player)
|
||||
{
|
||||
var players = player.World.Players.Where(p => !p.NonCombatant);
|
||||
|
||||
var gameOver = players.All(p => p.WinState != WinState.Undefined || !p.HasObjectives);
|
||||
var gameOver = player.World.Players.All(p => p.NonCombatant || p.WinState != WinState.Undefined || !p.HasObjectives);
|
||||
if (gameOver)
|
||||
{
|
||||
Game.RunAfterDelay(Info.GameOverDelay, () =>
|
||||
{
|
||||
if (!Game.IsCurrentWorld(player.World))
|
||||
@@ -153,17 +166,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
player.World.SetPauseState(true);
|
||||
player.World.PauseStateLocked = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void INotifyWinStateChanged.OnPlayerWon(Player player)
|
||||
{
|
||||
var players = player.World.Players.Where(p => !p.NonCombatant);
|
||||
var enemies = players.Where(p => !p.IsAlliedWith(player));
|
||||
|
||||
if (Info.Cooperative)
|
||||
{
|
||||
WinStateCooperative = WinState.Won;
|
||||
var allies = players.Where(p => p.IsAlliedWith(player));
|
||||
|
||||
if (allies.All(p => p.PlayerActor.Trait<MissionObjectives>().WinStateCooperative == WinState.Won))
|
||||
{
|
||||
@@ -193,13 +203,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
void INotifyWinStateChanged.OnPlayerLost(Player player)
|
||||
{
|
||||
var players = player.World.Players.Where(p => !p.NonCombatant);
|
||||
var enemies = players.Where(p => !p.IsAlliedWith(player));
|
||||
|
||||
if (Info.Cooperative)
|
||||
{
|
||||
WinStateCooperative = WinState.Lost;
|
||||
var allies = players.Where(p => p.IsAlliedWith(player));
|
||||
|
||||
if (allies.Any(p => p.PlayerActor.Trait<MissionObjectives>().WinStateCooperative == WinState.Lost))
|
||||
{
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits.Radar
|
||||
{
|
||||
public readonly bool UseLocation = false;
|
||||
|
||||
[Desc("Player stances who can view this actor on radar.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Player relationships who can view this actor on radar.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new AppearsOnRadar(this); }
|
||||
}
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits.Radar
|
||||
public void PopulateRadarSignatureCells(Actor self, List<(CPos Cell, Color Color)> destinationBuffer)
|
||||
{
|
||||
var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer;
|
||||
if (IsTraitDisabled || (viewer != null && !Info.ValidStances.HasStance(self.Owner.RelationshipWith(viewer))))
|
||||
if (IsTraitDisabled || (viewer != null && !Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(viewer))))
|
||||
return;
|
||||
|
||||
var color = Game.Settings.Game.UsePlayerStanceColors ? self.Owner.PlayerStanceColor(self) : self.Owner.Color;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
class CashTricklerBarInfo : TraitInfo, Requires<CashTricklerInfo>
|
||||
{
|
||||
[Desc("Defines to which players the bar is to be shown.")]
|
||||
public readonly PlayerRelationship DisplayStances = PlayerRelationship.Ally;
|
||||
public readonly PlayerRelationship DisplayRelationships = PlayerRelationship.Ally;
|
||||
|
||||
public readonly Color Color = Color.Magenta;
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
float ISelectionBar.GetValue()
|
||||
{
|
||||
var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer;
|
||||
if (viewer != null && !info.DisplayStances.HasStance(self.Owner.RelationshipWith(viewer)))
|
||||
if (viewer != null && !info.DisplayRelationships.HasStance(self.Owner.RelationshipWith(viewer)))
|
||||
return 0;
|
||||
|
||||
var complete = cashTricklers.Min(ct => (float)ct.Ticks / ct.Info.Interval);
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
class SupportPowerChargeBarInfo : ConditionalTraitInfo
|
||||
{
|
||||
[Desc("Defines to which players the bar is to be shown.")]
|
||||
public readonly PlayerRelationship DisplayStances = PlayerRelationship.Ally;
|
||||
public readonly PlayerRelationship DisplayRelationships = PlayerRelationship.Ally;
|
||||
|
||||
public readonly Color Color = Color.Magenta;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
return 0;
|
||||
|
||||
var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer;
|
||||
if (viewer != null && !Info.DisplayStances.HasStance(self.Owner.RelationshipWith(viewer)))
|
||||
if (viewer != null && !Info.DisplayRelationships.HasStance(self.Owner.RelationshipWith(viewer)))
|
||||
return 0;
|
||||
|
||||
return 1 - (float)power.RemainingTicks / power.TotalTicks;
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
[Desc("Position in the actor's selection box to draw the decoration.")]
|
||||
public readonly string Position = "TopLeft";
|
||||
|
||||
[Desc("Player stances who can view the decoration.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
[Desc("Player relationships who can view the decoration.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Should this be visible only when selected?")]
|
||||
public readonly bool RequiresSelection = false;
|
||||
@@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
if (self.World.RenderPlayer != null)
|
||||
{
|
||||
var stance = self.Owner.RelationshipWith(self.World.RenderPlayer);
|
||||
if (!Info.ValidStances.HasStance(stance))
|
||||
if (!Info.ValidRelationships.HasStance(stance))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,12 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
|
||||
void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel)
|
||||
{
|
||||
Attacking(self, target, a);
|
||||
// Lambdas can't use 'in' variables, so capture a copy for later
|
||||
var attackTarget = target;
|
||||
|
||||
// HACK: The FrameEndTask makes sure that this runs after Tick(), preventing that from
|
||||
// overriding the animation when an infantry unit stops to attack
|
||||
self.World.AddFrameEndTask(_ => Attacking(self, attackTarget, a));
|
||||
}
|
||||
|
||||
void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { }
|
||||
@@ -160,10 +165,6 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
|
||||
protected virtual void Tick(Actor self)
|
||||
{
|
||||
// Attacking takes care of reverting back to PlayStandAnimation
|
||||
if (state == AnimationState.Attacking)
|
||||
return;
|
||||
|
||||
if (rsm != null)
|
||||
{
|
||||
if (wasModifying != rsm.IsModifyingSequence)
|
||||
|
||||
@@ -40,9 +40,9 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
[Desc("If set, the color of the owning player will be used instead of `Color`.")]
|
||||
public readonly bool UsePlayerColor = false;
|
||||
|
||||
[Desc("Stances of players which will be able to see the circle.",
|
||||
[Desc("Player relationships which will be able to see the circle.",
|
||||
"Valid values are combinations of `None`, `Ally`, `Enemy` and `Neutral`.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("When to show the range circle. Valid values are `Always`, and `WhenSelected`")]
|
||||
public readonly RangeCircleVisibility Visible = RangeCircleVisibility.WhenSelected;
|
||||
@@ -91,7 +91,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
return false;
|
||||
|
||||
var p = self.World.RenderPlayer;
|
||||
return p == null || Info.ValidStances.HasStance(self.Owner.RelationshipWith(p)) || (p.Spectating && !p.NonCombatant);
|
||||
return p == null || Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)) || (p.Spectating && !p.NonCombatant);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Reveal this actor's last position when killed.")]
|
||||
public class RevealOnDeathInfo : ConditionalTraitInfo
|
||||
{
|
||||
[Desc("Stances relative to the actors' owner that shroud will be revealed for.")]
|
||||
public readonly PlayerRelationship RevealForStances = PlayerRelationship.Ally;
|
||||
[Desc("Relationships relative to the actors' owner that shroud will be revealed for.")]
|
||||
public readonly PlayerRelationship RevealForRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Duration of the reveal.")]
|
||||
public readonly int Duration = 25;
|
||||
@@ -66,7 +66,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
w.Add(new RevealShroudEffect(self.CenterPosition, info.Radius,
|
||||
info.RevealGeneratedShroud ? Shroud.SourceType.Visibility : Shroud.SourceType.PassiveVisibility,
|
||||
owner, info.RevealForStances, duration: info.Duration));
|
||||
owner, info.RevealForRelationships, duration: info.Duration));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("The armament types which trigger revealing.")]
|
||||
public readonly string[] ArmamentNames = { "primary", "secondary" };
|
||||
|
||||
[Desc("Stances relative to the target player this actor will be revealed to during firing.")]
|
||||
public readonly PlayerRelationship RevealForStancesRelativeToTarget = PlayerRelationship.Ally;
|
||||
[Desc("Player relationships relative to the target player this actor will be revealed to during firing.")]
|
||||
public readonly PlayerRelationship RevealForRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Duration of the reveal.")]
|
||||
public readonly int Duration = 25;
|
||||
@@ -60,7 +60,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(self.CenterPosition, info.Radius,
|
||||
info.RevealGeneratedShroud ? Shroud.SourceType.Visibility : Shroud.SourceType.PassiveVisibility,
|
||||
targetPlayer, info.RevealForStancesRelativeToTarget, duration: info.Duration)));
|
||||
targetPlayer, info.RevealForRelationships, duration: info.Duration)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Reveals shroud and fog across the whole map while active.")]
|
||||
public class RevealsMapInfo : ConditionalTraitInfo
|
||||
{
|
||||
[Desc("Stance the watching player needs to see the shroud removed.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
[Desc("Relationships the watching player needs to see the shroud removed.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Can this actor reveal shroud generated by the `GeneratesShroud` trait?")]
|
||||
public readonly bool RevealGeneratedShroud = true;
|
||||
@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
protected void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv)
|
||||
{
|
||||
if (!Info.ValidStances.HasStance(self.Owner.RelationshipWith(p)))
|
||||
if (!Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)))
|
||||
return;
|
||||
|
||||
p.Shroud.AddSource(this, type, uv);
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class RevealsShroudInfo : AffectsShroudInfo
|
||||
{
|
||||
[Desc("Stance the watching player needs to see the shroud removed.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
[Desc("Relationships the watching player needs to see the shroud removed.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Can this actor reveal shroud generated by the GeneratesShroud trait?")]
|
||||
public readonly bool RevealGeneratedShroud = true;
|
||||
@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
protected override void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv)
|
||||
{
|
||||
if (!info.ValidStances.HasStance(self.Owner.RelationshipWith(p)))
|
||||
if (!info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)))
|
||||
return;
|
||||
|
||||
p.Shroud.AddSource(this, type, uv);
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace OpenRA.Mods.Common.Traits.Sound
|
||||
[Desc("Voice to play.")]
|
||||
public readonly string Voice = null;
|
||||
|
||||
[Desc("Player stances who can hear this voice.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Player relationships who can hear this voice.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Play the voice to the owning player even if Stance.Ally is not included in ValidStances.")]
|
||||
public readonly bool PlayToOwner = true;
|
||||
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Traits.Sound
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
if (Info.ValidStances.HasStance(self.Owner.RelationshipWith(player)))
|
||||
if (Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(player)))
|
||||
self.PlayVoice(Info.Voice);
|
||||
else if (Info.PlayToOwner && self.Owner == player)
|
||||
self.PlayVoice(Info.Voice);
|
||||
|
||||
@@ -39,8 +39,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Sound to instantly play at the targeted area.")]
|
||||
public readonly string OnFireSound = null;
|
||||
|
||||
[Desc("Player stances which condition can be applied to.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally;
|
||||
[Desc("Player relationships which condition can be applied to.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[SequenceReference]
|
||||
[Desc("Sequence to play for granting actor when activated.",
|
||||
@@ -96,7 +96,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
return units.Distinct().Where(a =>
|
||||
{
|
||||
if (!info.ValidStances.HasStance(Self.Owner.RelationshipWith(a.Owner)))
|
||||
if (!info.ValidRelationships.HasStance(Self.Owner.RelationshipWith(a.Owner)))
|
||||
return false;
|
||||
|
||||
return a.TraitsImplementing<ExternalCondition>()
|
||||
|
||||
@@ -94,8 +94,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Can the camera reveal shroud generated by the GeneratesShroud trait?")]
|
||||
public readonly bool RevealGeneratedShroud = true;
|
||||
|
||||
[Desc("Reveal cells to players with these stances only.")]
|
||||
public readonly PlayerRelationship CameraStances = PlayerRelationship.Ally;
|
||||
[Desc("Reveal cells to players with these relationships only.")]
|
||||
public readonly PlayerRelationship CameraRelationships = PlayerRelationship.Ally;
|
||||
|
||||
[Desc("Amount of time before detonation to spawn the camera.")]
|
||||
public readonly int CameraSpawnAdvance = 25;
|
||||
@@ -180,7 +180,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
var type = info.RevealGeneratedShroud ? Shroud.SourceType.Visibility
|
||||
: Shroud.SourceType.PassiveVisibility;
|
||||
|
||||
self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, type, self.Owner, info.CameraStances,
|
||||
self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, type, self.Owner, info.CameraRelationships,
|
||||
info.FlightDelay - info.CameraSpawnAdvance, info.CameraSpawnAdvance + info.CameraRemoveDelay)));
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public readonly string IncomingSpeechNotification = null;
|
||||
|
||||
[Desc("Defines to which players the timer is shown.")]
|
||||
public readonly PlayerRelationship DisplayTimerStances = PlayerRelationship.None;
|
||||
public readonly PlayerRelationship DisplayTimerRelationships = PlayerRelationship.None;
|
||||
|
||||
[Desc("Beacons are only supported on the Airstrike, Paratroopers, and Nuke powers")]
|
||||
public readonly bool DisplayBeacon = false;
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Translate]
|
||||
public readonly string Description = "";
|
||||
|
||||
[Desc("Player stances who can view the description.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("Player relationships who can view the description.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new TooltipDescription(init.Self, this); }
|
||||
}
|
||||
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (Owner == null || forPlayer == null)
|
||||
return false;
|
||||
|
||||
return Info.ValidStances.HasStance(Owner.RelationshipWith(forPlayer));
|
||||
return Info.ValidRelationships.HasStance(Owner.RelationshipWith(forPlayer));
|
||||
}
|
||||
|
||||
public string TooltipText
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -27,6 +29,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Maximum amount of ticks the actor will sit idly before starting to wander.")]
|
||||
public readonly int MaxMoveDelay = 0;
|
||||
|
||||
[Desc("The terrain types that this actor should avoid wandering on to.")]
|
||||
public readonly HashSet<string> AvoidTerrainTypes = new HashSet<string>();
|
||||
|
||||
public override object Create(ActorInitializer init) { return new Wanders(init.Self, this); }
|
||||
}
|
||||
|
||||
@@ -75,8 +80,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return;
|
||||
|
||||
var targetCell = PickTargetLocation();
|
||||
if (targetCell != CPos.Zero)
|
||||
DoAction(self, targetCell);
|
||||
if (targetCell.HasValue)
|
||||
DoAction(self, targetCell.Value);
|
||||
}
|
||||
|
||||
void INotifyIdle.TickIdle(Actor self)
|
||||
@@ -84,7 +89,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
TickIdle(self);
|
||||
}
|
||||
|
||||
CPos PickTargetLocation()
|
||||
CPos? PickTargetLocation()
|
||||
{
|
||||
var target = self.CenterPosition + new WVec(0, -1024 * effectiveMoveRadius, 0).Rotate(WRot.FromFacing(self.World.SharedRandom.Next(255)));
|
||||
var targetCell = self.World.Map.CellContaining(target);
|
||||
@@ -95,7 +100,15 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (++ticksIdle % info.ReduceMoveRadiusDelay == 0)
|
||||
effectiveMoveRadius--;
|
||||
|
||||
return CPos.Zero; // We'll be back the next tick; better to sit idle for a few seconds than prolong this tick indefinitely with a loop
|
||||
// We'll be back the next tick; better to sit idle for a few seconds than prolong this tick indefinitely with a loop
|
||||
return null;
|
||||
}
|
||||
|
||||
if (info.AvoidTerrainTypes.Count > 0)
|
||||
{
|
||||
var terrainType = self.World.Map.GetTerrainInfo(targetCell).Type;
|
||||
if (Info.AvoidTerrainTypes.Contains(terrainType))
|
||||
return null;
|
||||
}
|
||||
|
||||
ticksIdle = 0;
|
||||
|
||||
@@ -60,6 +60,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
IsBot = client.Bot != null,
|
||||
FactionName = resolvedFaction.Name,
|
||||
FactionId = resolvedFaction.InternalName,
|
||||
DisplayFactionName = clientFaction.Name,
|
||||
DisplayFactionId = clientFaction.InternalName,
|
||||
Color = client.Color,
|
||||
Team = client.Team,
|
||||
SpawnPoint = resolvedSpawnPoint,
|
||||
|
||||
@@ -78,10 +78,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
for (var x = 0; x < TerrainTemplate.Size.X; x++)
|
||||
{
|
||||
var tile = new TerrainTile(TerrainTemplate.Id, (byte)i++);
|
||||
var tileInfo = world.Map.Rules.TileSet.GetTileInfo(tile);
|
||||
|
||||
// Empty tile
|
||||
if (tileInfo == null)
|
||||
if (!world.Map.Rules.TileSet.TryGetTileInfo(tile, out var tileInfo))
|
||||
continue;
|
||||
|
||||
var sprite = wr.Theater.TileSprite(tile, 0);
|
||||
|
||||
104
OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameStances.cs
Normal file
104
OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameStances.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Mods.Common.UpdateRules.Rules
|
||||
{
|
||||
public class RenameStances : UpdateRule
|
||||
{
|
||||
public override string Name { get { return "Renamed player 'Stances' to 'Relationships'."; } }
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return "'Stances' in regards to a player have been renamed to 'Relationships'.\n" +
|
||||
"The yaml values did not change.";
|
||||
}
|
||||
}
|
||||
|
||||
readonly (string TraitName, string OldName, string NewName)[] traits =
|
||||
{
|
||||
("Disguise", "ValidStances", "ValidRelationships"),
|
||||
("Infiltrates", "ValidStances", "ValidRelationships"),
|
||||
("AcceptsDeliveredCash", "ValidStances", "ValidRelationships"),
|
||||
("AcceptsDeliveredExperience", "ValidStances", "ValidRelationships"),
|
||||
("Armament", "TargetStances", "TargetRelationships"),
|
||||
("Armament", "ForceTargetStances", "ForceTargetRelationships"),
|
||||
("AutoTargetPriority", "ValidStances", "ValidRelationships"),
|
||||
("CaptureManagerBotModule", "CapturableStances", "CapturableRelationships"),
|
||||
("Capturable", "ValidStances", "ValidRelationships"),
|
||||
("Captures", "PlayerExperienceStances", "PlayerExperienceRelationships"),
|
||||
("ProximityExternalCondition", "ValidStances", "ValidRelationships"),
|
||||
("CreatesShroud", "ValidStances", "ValidRelationships"),
|
||||
("Demolition", "TargetStances", "TargetRelationships"),
|
||||
("Demolition", "ForceTargetStances", "ForceTargetRelationships"),
|
||||
("EngineerRepair", "ValidStances", "ValidRelationships"),
|
||||
("GivesBounty", "ValidStances", "ValidRelationships"),
|
||||
("GivesExperience", "ValidStances", "ValidRelationships"),
|
||||
("JamsMissiles", "DeflectionStances", "DeflectionRelationships"),
|
||||
("FrozenUnderFog", "AlwaysVisibleStances", "AlwaysVisibleRelationships"),
|
||||
("HiddenUnderShroud", "AlwaysVisibleStances", "AlwaysVisibleRelationships"),
|
||||
("HiddenUnderFog", "AlwaysVisibleStances", "AlwaysVisibleRelationships"),
|
||||
("AppearsOnRadar", "ValidStances", "ValidRelationships"),
|
||||
("CashTricklerBar", "DisplayStances", "DisplayRelationships"),
|
||||
("SupportPowerChargeBar", "DisplayStances", "DisplayRelationships"),
|
||||
("WithAmmoPipsDecoration", "ValidStances", "ValidRelationships"),
|
||||
("WithCargoPipsDecoration", "ValidStances", "ValidRelationships"),
|
||||
("WithDecoration", "ValidStances", "ValidRelationships"),
|
||||
("WithHarvesterPipsDecoration", "ValidStances", "ValidRelationships"),
|
||||
("WithNameTagDecoration", "ValidStances", "ValidRelationships"),
|
||||
("WithResourceStoragePipsDecoration", "ValidStances", "ValidRelationships"),
|
||||
("WithTextDecoration", "ValidStances", "ValidRelationships"),
|
||||
("WithRangeCircle", "ValidStances", "ValidRelationships"),
|
||||
("RevealOnDeath", "RevealForStances", "RevealForRelationships"),
|
||||
("RevealOnFire", "RevealForStancesRelativeToTarget", "RevealForRelationships"),
|
||||
("RevealsMap", "ValidStances", "ValidRelationships"),
|
||||
("RevealsShroud", "ValidStances", "ValidRelationships"),
|
||||
("VoiceAnnouncement", "ValidStances", "ValidRelationships"),
|
||||
("GrantExternalConditionPower", "ValidStances", "ValidRelationships"),
|
||||
("NukePower", "CameraStances", "CameraRelationships"),
|
||||
("NukePower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("AttackOrderPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("ChronoshiftPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("DropPodsPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("GpsPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("GrantPrerequisiteChargeDrainPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("IonCannonPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("AirstrikePower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("GrantExternalConditionPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("ParatroopersPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("ProduceActorPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("SpawnActorPower", "DisplayTimerStances", "DisplayTimerRelationships"),
|
||||
("TooltipDescription", "ValidStances", "ValidRelationships")
|
||||
};
|
||||
|
||||
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
|
||||
{
|
||||
foreach (var field in traits)
|
||||
foreach (var traitNode in actorNode.ChildrenMatching(field.TraitName))
|
||||
traitNode.RenameChildrenMatching(field.OldName, field.NewName);
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode)
|
||||
{
|
||||
foreach (var projectileNode in weaponNode.ChildrenMatching("Projectile"))
|
||||
projectileNode.RenameChildrenMatching("ValidBounceBlockerStances", "ValidBounceBlockerRelationships");
|
||||
|
||||
foreach (var warheadNode in weaponNode.ChildrenMatching("Warhead"))
|
||||
warheadNode.RenameChildrenMatching("ValidStances", "ValidRelationships");
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,7 @@ namespace OpenRA.Mods.Common.UpdateRules
|
||||
new RenameSelfHealing(),
|
||||
new ReplaceBurns(),
|
||||
new RemoveMuzzleSplitFacings(),
|
||||
new RenameStances(),
|
||||
new RemoveTurnToDock(),
|
||||
new RenameSmudgeSmokeFields(),
|
||||
new RenameCircleContrast(),
|
||||
|
||||
@@ -104,6 +104,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
" for (var j = 0; j < ctx.canvas.height / 4; j++)",
|
||||
" for (var i = j % 2; i < ctx.canvas.width / 4; i += 2)",
|
||||
" ctx.fillRect(4 * i, 4 * j, 4, 4);",
|
||||
" ctx.imageSmoothingEnabled = false;",
|
||||
" ctx.drawImage(image, 0, 0, c.width, c.height);",
|
||||
" ctx.strokeStyle = \"#ffff00\";",
|
||||
" ctx.lineWidth = 1;",
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Warheads
|
||||
public override bool IsValidAgainst(Actor victim, Actor firedBy)
|
||||
{
|
||||
var stance = firedBy.Owner.RelationshipWith(victim.Owner);
|
||||
if (!ValidStances.HasStance(stance))
|
||||
if (!ValidRelationships.HasStance(stance))
|
||||
return false;
|
||||
|
||||
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace OpenRA.Mods.Common.Warheads
|
||||
[Desc("What types of targets are unaffected.", "Overrules ValidTargets.")]
|
||||
public readonly BitSet<TargetableType> InvalidTargets;
|
||||
|
||||
[Desc("What diplomatic stances are affected.")]
|
||||
public readonly PlayerRelationship ValidStances = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
[Desc("What player relationships are affected.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Can this warhead affect the actor that fired it.")]
|
||||
public readonly bool AffectsParent = false;
|
||||
@@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Warheads
|
||||
return false;
|
||||
|
||||
var stance = firedBy.Owner.RelationshipWith(victim.Owner);
|
||||
if (!ValidStances.HasStance(stance))
|
||||
if (!ValidRelationships.HasStance(stance))
|
||||
return false;
|
||||
|
||||
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.
|
||||
@@ -81,7 +81,7 @@ namespace OpenRA.Mods.Common.Warheads
|
||||
|
||||
// AffectsParent checks do not make sense for FrozenActors, so skip to stance checks
|
||||
var stance = firedBy.Owner.RelationshipWith(victim.Owner);
|
||||
if (!ValidStances.HasStance(stance))
|
||||
if (!ValidRelationships.HasStance(stance))
|
||||
return false;
|
||||
|
||||
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
powers = world.ActorsWithTrait<SupportPowerManager>()
|
||||
.Where(p => !p.Actor.IsDead && !p.Actor.Owner.NonCombatant)
|
||||
.SelectMany(s => s.Trait.Powers.Values)
|
||||
.Where(p => p.Instances.Any() && p.Info.DisplayTimerStances != PlayerRelationship.None && !p.Disabled);
|
||||
.Where(p => p.Instances.Any() && p.Info.DisplayTimerRelationships != PlayerRelationship.None && !p.Disabled);
|
||||
|
||||
// Timers in replays should be synced to the effective game time, not the playback time.
|
||||
timestep = world.Timestep;
|
||||
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
var owner = p.Instances[0].Self.Owner;
|
||||
var viewer = owner.World.RenderPlayer ?? owner.World.LocalPlayer;
|
||||
return viewer == null || p.Info.DisplayTimerStances.HasStance(owner.RelationshipWith(viewer));
|
||||
return viewer == null || p.Info.DisplayTimerRelationships.HasStance(owner.RelationshipWith(viewer));
|
||||
});
|
||||
|
||||
texts = displayedPowers.Select(p =>
|
||||
|
||||
@@ -81,10 +81,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
for (var x = 0; x < Template.Size.X; x++)
|
||||
{
|
||||
var tile = new TerrainTile(Template.Id, (byte)(i++));
|
||||
var tileInfo = tileset.GetTileInfo(tile);
|
||||
|
||||
// Empty tile
|
||||
if (tileInfo == null)
|
||||
if (!tileset.TryGetTileInfo(tile, out var tileInfo))
|
||||
continue;
|
||||
|
||||
var sprite = worldRenderer.Theater.TileSprite(tile, 0);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
@@ -11,6 +11,7 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<CodeAnalysisRuleSet>..\OpenRA.ruleset</CodeAnalysisRuleSet>
|
||||
<IsPublishable Condition="'$(CopyD2kDll)' == 'False'">false</IsPublishable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Work around an issue where Rider does not detect files in the project root using the default glob -->
|
||||
@@ -37,4 +38,4 @@
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
@@ -11,6 +11,7 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<CodeAnalysisRuleSet>..\OpenRA.ruleset</CodeAnalysisRuleSet>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetPlatform Condition="$([MSBuild]::IsOsPlatform('Windows'))">win-x64</TargetPlatform>
|
||||
|
||||
@@ -59,7 +59,6 @@ namespace OpenRA.Platforms.Default
|
||||
Name = "ThreadedGraphicsContext RenderThread",
|
||||
IsBackground = true
|
||||
};
|
||||
renderThread.SetApartmentState(ApartmentState.STA);
|
||||
lock (syncObject)
|
||||
{
|
||||
// Start and wait for the rendering thread to have initialized before returning.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework Condition="'$(Mono)' == ''">net5.0</TargetFramework>
|
||||
<TargetFramework Condition="'$(Mono)' != ''">netstandard2.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
@@ -39,4 +40,8 @@
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="netstandard" />
|
||||
<TrimmerRootAssembly Include="System.IO.Pipes" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -10,6 +10,7 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<CodeAnalysisRuleSet>..\OpenRA.ruleset</CodeAnalysisRuleSet>
|
||||
<IsPublishable>false</IsPublishable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Work around an issue where Rider does not detect files in the project root using the default glob -->
|
||||
@@ -22,14 +23,12 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj" />
|
||||
<ProjectReference Include="..\OpenRA.Mods.Common\OpenRA.Mods.Common.csproj">
|
||||
<Private>False</Private>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit.Console" Version="3.11.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0-beta.1" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
|
||||
<AdditionalFiles Include="../stylecop.json" />
|
||||
@@ -40,4 +39,4 @@
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework Condition="'$(Mono)' == ''">net5.0</TargetFramework>
|
||||
<TargetFramework Condition="'$(Mono)' != ''">netstandard2.1</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
@@ -39,4 +40,8 @@
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="netstandard" />
|
||||
<TrimmerRootAssembly Include="System.IO.Pipes" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>winexe</OutputType>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<ApplicationIcon>$(LauncherIcon)</ApplicationIcon>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
@@ -10,14 +12,12 @@
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
|
||||
<OutputPath>../bin</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ExternalConsole>false</ExternalConsole>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<CodeAnalysisRuleSet>..\OpenRA.ruleset</CodeAnalysisRuleSet>
|
||||
<Configurations>Release;Debug</Configurations>
|
||||
<AssemblyName>$(LauncherName)</AssemblyName>
|
||||
<ApplicationIcon>$(LauncherIcon)</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Work around an issue where Rider does not detect files in the project root using the default glob -->
|
||||
@@ -58,4 +58,8 @@
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="netstandard" />
|
||||
<TrimmerRootAssembly Include="System.IO.Pipes" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -58,9 +58,7 @@ Global
|
||||
{FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -4,7 +4,7 @@ A Libre/Free Real Time Strategy game engine supporting early Westwood classics.
|
||||
|
||||
* Website: [http://www.openra.net](http://www.openra.net)
|
||||
* IRC: \#openra on irc.freenode.net
|
||||
* Repository: [https://github.com/OpenRA/OpenRA](https://github.com/OpenRA/OpenRA) [](https://travis-ci.org/OpenRA/OpenRA) [](https://ci.appveyor.com/project/OpenRA/openra)
|
||||
* Repository: [https://github.com/OpenRA/OpenRA](https://github.com/OpenRA/OpenRA) 
|
||||
|
||||
Please read the [FAQ](http://wiki.openra.net/FAQ) in our [Wiki](http://wiki.openra.net) and report problems at [http://bugs.openra.net](http://bugs.openra.net).
|
||||
|
||||
|
||||
28
appveyor.yml
28
appveyor.yml
@@ -1,28 +0,0 @@
|
||||
version: 1.0.{build}
|
||||
image: Visual Studio 2017
|
||||
|
||||
install:
|
||||
|
||||
build_script:
|
||||
- make all
|
||||
|
||||
test_script:
|
||||
- nunit3-console bin/OpenRA.Test.dll --result=myresults.xml;format=AppVeyor
|
||||
|
||||
after_test:
|
||||
- appveyor DownloadFile "https://github.com/OpenRA/GeoIP-Database/releases/download/monthly/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP" -FileName IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP
|
||||
- pip install Pillow
|
||||
- python -c "from PIL import Image; i = Image.open('packaging/artwork/ra_256x256.png'); i.save('ra.ico')"
|
||||
- python -c "from PIL import Image; i = Image.open('packaging/artwork/cnc_256x256.png'); i.save('cnc.ico')"
|
||||
- python -c "from PIL import Image; i = Image.open('packaging/artwork/d2k_256x256.png'); i.save('d2k.ico')"
|
||||
- msbuild -t:Build "OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -restore -p:Configuration=Release -p:TargetPlatform="win-x64" -p:LauncherName="RedAlert" -p:LauncherIcon="../ra.ico" -p:ModID="ra" -p:DisplayName="Red Alert" -p:FaqUrl="http://wiki.openra.net/FAQ"
|
||||
- msbuild -t:Build "OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -restore -p:Configuration=Release -p:TargetPlatform="win-x64" -p:LauncherName="TiberianDawn" -p:LauncherIcon="../cnc.ico" -p:ModID="cnc" -p:DisplayName="Tiberian Dawn" -p:FaqUrl="http://wiki.openra.net/FAQ"
|
||||
- msbuild -t:Build "OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -restore -p:Configuration=Release -p:TargetPlatform="win-x64" -p:LauncherName="Dune2000" -p:LauncherIcon="../d2k.ico" -p:ModID="d2k" -p:DisplayName="Dune 2000" -p:FaqUrl="http://wiki.openra.net/FAQ"
|
||||
- move /Y %APPVEYOR_BUILD_FOLDER%\bin\* %APPVEYOR_BUILD_FOLDER%
|
||||
- if defined APPVEYOR_REPO_TAG_NAME set VERSION=%APPVEYOR_REPO_TAG_NAME%
|
||||
- if not defined APPVEYOR_REPO_TAG_NAME set VERSION=%APPVEYOR_REPO_COMMIT:~0,7%
|
||||
- '"C:\Program Files (x86)\NSIS\makensis.exe" /DSRCDIR="%APPVEYOR_BUILD_FOLDER%" /DTAG="git-%VERSION%" /DSUFFIX=" (dev)" /V3 /DOUTFILE="OpenRA-$(VERSION).exe" packaging/windows/OpenRA.nsi'
|
||||
|
||||
artifacts:
|
||||
- path: OpenRA-$(VERSION).exe
|
||||
name: Installer
|
||||
@@ -25,7 +25,7 @@ ShareAnonymizedIPs="${ShareAnonymizedIPs:-"True"}"
|
||||
SupportDir="${SupportDir:-""}"
|
||||
|
||||
while true; do
|
||||
mono --debug bin/OpenRA.Server.exe Engine.EngineDir=".." Game.Mod="$Mod" \
|
||||
mono --debug bin/OpenRA.Server.dll Engine.EngineDir=".." Game.Mod="$Mod" \
|
||||
Server.Name="$Name" \
|
||||
Server.ListenPort="$ListenPort" \
|
||||
Server.AdvertiseOnline="$AdvertiseOnline" \
|
||||
|
||||
@@ -25,7 +25,7 @@ then
|
||||
fi
|
||||
|
||||
# Launch the engine with the appropriate arguments
|
||||
mono bin/OpenRA.exe Engine.EngineDir=".." Engine.LaunchPath="$MODLAUNCHER" $MODARG "$@"
|
||||
mono --debug bin/OpenRA.dll Engine.EngineDir=".." Engine.LaunchPath="$MODLAUNCHER" $MODARG "$@"
|
||||
|
||||
# Show a crash dialog if something went wrong
|
||||
if [ $? != 0 ] && [ $? != 1 ]; then
|
||||
|
||||
4
make.ps1
4
make.ps1
@@ -10,7 +10,7 @@ function All-Command
|
||||
return
|
||||
}
|
||||
|
||||
dotnet build /p:Configuration=Release /nologo
|
||||
dotnet build -c Release --nologo -p:TargetPlatform=win-x64
|
||||
if ($lastexitcode -ne 0)
|
||||
{
|
||||
Write-Host "Build failed. If just the development tools failed to build, try installing Visual Studio. You may also still be able to run the game." -ForegroundColor Red
|
||||
@@ -111,7 +111,7 @@ function Test-Command
|
||||
function Check-Command
|
||||
{
|
||||
Write-Host "Compiling in debug configuration..." -ForegroundColor Cyan
|
||||
dotnet build /p:Configuration=Debug /nologo
|
||||
dotnet build -c Debug --nologo -p:TargetPlatform=win-x64
|
||||
if ($lastexitcode -ne 0)
|
||||
{
|
||||
Write-Host "Build failed." -ForegroundColor Red
|
||||
|
||||
@@ -366,23 +366,18 @@ scrollpanel-decorations:
|
||||
Inherits: ^Chrome
|
||||
Regions:
|
||||
down: 836, 17, 16, 16
|
||||
down-pressed: 836, 17, 16, 16
|
||||
down-disabled: 853, 17, 16, 16
|
||||
up: 870, 17, 16, 16
|
||||
up-pressed: 870, 17, 16, 16
|
||||
up-disabled: 887, 17, 16, 16
|
||||
right: 904, 17, 16, 16
|
||||
right-pressed: 904, 17, 16, 16
|
||||
right-disabled: 921, 17, 16, 16
|
||||
left: 938, 17, 16, 16
|
||||
left-pressed: 938, 17, 16, 16
|
||||
left-disabled: 955, 17, 16, 16
|
||||
|
||||
dropdown-decorations:
|
||||
Inherits: ^Chrome
|
||||
Regions:
|
||||
marker: 836, 17, 16, 16
|
||||
marker-pressed: 836, 17, 16, 16
|
||||
marker-disabled: 853, 17, 16, 16
|
||||
|
||||
dropdown-separators:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user