From 6c94909367b118738a0e1798855361929021ea13 Mon Sep 17 00:00:00 2001 From: sprunk Date: Wed, 11 Oct 2023 17:50:46 +0200 Subject: [PATCH] Changelogs. --- .gitignore | 5 + 404.html | 25 + Gemfile | 48 + Gemfile.lock | 281 +++ README.md | 26 + _authors/badosu.markdown | 4 + _authors/lhog.markdown | 4 + _authors/p2004a.markdown | 4 + _authors/sprunk.markdown | 4 + _authors/verybadsoldier.markdown | 4 + _config.yml | 175 ++ _data/configs.json | 2082 +++++++++++++++++++++ _data/glossary.yml | 38 + _data/latest_release.json | 244 +++ _data/non_coder_contributors.yml | 3 + _data/synced_commands.json | 116 ++ _data/unsynced_commands.json | 1164 ++++++++++++ _data/weapondefs.json | 819 ++++++++ _includes/head.html | 52 + _includes/header_custom.html | 34 + _layouts/post.html | 21 + _sass/content-nocharset.scss | 237 +++ _sass/custom/custom.scss | 226 +++ _sass/modules-nocharset.scss | 16 + _scripts/get_engine_data.sh | 36 + _scripts/get_release_data.sh | 10 + about.markdown | 10 + articles.markdown | 10 + articles/ceg-operators.markdown | 190 ++ articles/modrules-and-others.markdown | 39 + articles/pathfinding.markdown | 7 + articles/select-command.markdown | 210 +++ articles/team-terminology.markdown | 89 + articles/unit-defs.markdown | 178 ++ articles/units-of-measurement.markdown | 55 + articles/vfs-basics.markdown | 63 + assets/css/just-the-docs-themes.scss | 83 + assets/github-mark-white.svg | 1 + assets/github-mark.svg | 1 + assets/guides/lua-vbo-vao-1.png | Bin 0 -> 59905 bytes assets/guides/lua-vbo-vao-2.png | Bin 0 -> 85689 bytes assets/guides/lua-vbo-vao-3.png | Bin 0 -> 137537 bytes assets/guides/lua-vbo-vao-4.png | Bin 0 -> 89526 bytes assets/js/theme-switcher.js | 58 + assets/matrix-logo-white.svg | 18 + assets/matrix-logo.svg | 5 + changelogs.markdown | 10 + changelogs/changelog-105-1214.markdown | 88 + changelogs/changelog-105-1354.markdown | 54 + changelogs/changelog-105-1544.markdown | 90 + changelogs/changelog-105-1775.markdown | 100 + changelogs/changelog-105-861.markdown | 143 ++ changelogs/changelog-105-902.markdown | 41 + changelogs/changelog-105-941.markdown | 25 + changelogs/changelog-105-966.markdown | 58 + changelogs/running-changelog.markdown | 268 +++ development.markdown | 10 + development/build-with-docker.markdown | 139 ++ development/build-without-docker.markdown | 229 +++ guides.markdown | 10 + guides/choose-recoil.markdown | 43 + guides/configuration-variables.markdown | 49 + guides/glossary.markdown | 15 + guides/headless-and-dedi.markdown | 32 + guides/lua-vbo-vao.markdown | 155 ++ guides/synced-commands.markdown | 47 + guides/unsynced-commands.markdown | 48 + guides/weapondefs.markdown | 40 + guides/widgets.markdown | 7 + index.markdown | 88 + ldoc/.gitkeep | 0 lua-api.md | 20 + migrating-from-spring.markdown | 222 +++ 73 files changed, 8726 insertions(+) create mode 100644 .gitignore create mode 100644 404.html create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 README.md create mode 100644 _authors/badosu.markdown create mode 100644 _authors/lhog.markdown create mode 100644 _authors/p2004a.markdown create mode 100644 _authors/sprunk.markdown create mode 100644 _authors/verybadsoldier.markdown create mode 100644 _config.yml create mode 100644 _data/configs.json create mode 100644 _data/glossary.yml create mode 100644 _data/latest_release.json create mode 100644 _data/non_coder_contributors.yml create mode 100644 _data/synced_commands.json create mode 100644 _data/unsynced_commands.json create mode 100644 _data/weapondefs.json create mode 100644 _includes/head.html create mode 100644 _includes/header_custom.html create mode 100644 _layouts/post.html create mode 100644 _sass/content-nocharset.scss create mode 100644 _sass/custom/custom.scss create mode 100644 _sass/modules-nocharset.scss create mode 100755 _scripts/get_engine_data.sh create mode 100755 _scripts/get_release_data.sh create mode 100644 about.markdown create mode 100644 articles.markdown create mode 100644 articles/ceg-operators.markdown create mode 100644 articles/modrules-and-others.markdown create mode 100644 articles/pathfinding.markdown create mode 100644 articles/select-command.markdown create mode 100644 articles/team-terminology.markdown create mode 100644 articles/unit-defs.markdown create mode 100644 articles/units-of-measurement.markdown create mode 100644 articles/vfs-basics.markdown create mode 100644 assets/css/just-the-docs-themes.scss create mode 100644 assets/github-mark-white.svg create mode 100644 assets/github-mark.svg create mode 100644 assets/guides/lua-vbo-vao-1.png create mode 100644 assets/guides/lua-vbo-vao-2.png create mode 100644 assets/guides/lua-vbo-vao-3.png create mode 100644 assets/guides/lua-vbo-vao-4.png create mode 100644 assets/js/theme-switcher.js create mode 100644 assets/matrix-logo-white.svg create mode 100644 assets/matrix-logo.svg create mode 100644 changelogs.markdown create mode 100644 changelogs/changelog-105-1214.markdown create mode 100644 changelogs/changelog-105-1354.markdown create mode 100644 changelogs/changelog-105-1544.markdown create mode 100644 changelogs/changelog-105-1775.markdown create mode 100644 changelogs/changelog-105-861.markdown create mode 100644 changelogs/changelog-105-902.markdown create mode 100644 changelogs/changelog-105-941.markdown create mode 100644 changelogs/changelog-105-966.markdown create mode 100644 changelogs/running-changelog.markdown create mode 100644 development.markdown create mode 100644 development/build-with-docker.markdown create mode 100644 development/build-without-docker.markdown create mode 100644 guides.markdown create mode 100644 guides/choose-recoil.markdown create mode 100644 guides/configuration-variables.markdown create mode 100644 guides/glossary.markdown create mode 100644 guides/headless-and-dedi.markdown create mode 100644 guides/lua-vbo-vao.markdown create mode 100644 guides/synced-commands.markdown create mode 100644 guides/unsynced-commands.markdown create mode 100644 guides/weapondefs.markdown create mode 100644 guides/widgets.markdown create mode 100644 index.markdown create mode 100644 ldoc/.gitkeep create mode 100644 lua-api.md create mode 100644 migrating-from-spring.markdown diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..f40fbd8ba5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +_site +.sass-cache +.jekyll-cache +.jekyll-metadata +vendor diff --git a/404.html b/404.html new file mode 100644 index 0000000000..086a5c9ea9 --- /dev/null +++ b/404.html @@ -0,0 +1,25 @@ +--- +permalink: /404.html +layout: default +--- + + + +
+

404

+ +

Page not found :(

+

The requested page could not be found.

+
diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..fb80b448fb --- /dev/null +++ b/Gemfile @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' +# Hello! This is where you manage which Jekyll version is used to run. +# When you want to use a different version, change it below, save the +# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: +# +# bundle exec jekyll serve +# +# This will help ensure the proper Jekyll version is running. +# Happy Jekylling! +# This is the default theme for new Jekyll sites. You may change this to anything you like. +gem 'just-the-docs' +# If you want to use GitHub Pages, remove the 'gem 'jekyll'' above and +# uncomment the line below. To upgrade, run `bundle update github-pages`. + +# Already included with github-pages gem +# gem 'jekyll' + +# If you have any plugins, put them here! +group :jekyll_plugins do + gem 'github-pages' + gem 'jekyll-feed' + # Already included with github-pages gem + # gem 'jekyll-github-metadata' + gem 'jekyll-glossary_tooltip' + gem 'jekyll-liquify' + gem 'jekyll-remote-theme' + gem 'jekyll-sitemap' +end + +# Can't serve locally without webrick +# https://github.com/github/pages-gem/issues/752 +gem 'webrick' + +# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem +# and associated library. +platforms :mingw, :x64_mingw, :mswin, :jruby do + gem 'tzinfo', '>= 1', '< 3' + gem 'tzinfo-data' +end + +# Performance-booster for watching directories on Windows +gem 'wdm', '~> 0.1.1', platforms: %i[mingw x64_mingw mswin] + +# Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem +# do not have a Java counterpart. +gem 'http_parser.rb', '~> 0.6.0', platforms: %i[jruby] diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..f78bcafe66 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,281 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (7.0.4.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.11.1) + colorator (1.1.0) + commonmarker (0.23.8) + concurrent-ruby (1.2.2) + dnsruby (1.61.9) + simpleidn (~> 0.1) + em-websocket (0.5.3) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0) + ethon (0.16.0) + ffi (>= 1.15.0) + eventmachine (1.2.7) + execjs (2.8.1) + faraday (2.7.4) + faraday-net_http (>= 2.0, < 3.1) + ruby2_keywords (>= 0.0.4) + faraday-net_http (3.0.2) + ffi (1.15.5) + forwardable-extended (2.6.0) + gemoji (3.0.1) + github-pages (228) + github-pages-health-check (= 1.17.9) + jekyll (= 3.9.3) + jekyll-avatar (= 0.7.0) + jekyll-coffeescript (= 1.1.1) + jekyll-commonmark-ghpages (= 0.4.0) + jekyll-default-layout (= 0.1.4) + jekyll-feed (= 0.15.1) + jekyll-gist (= 1.5.0) + jekyll-github-metadata (= 2.13.0) + jekyll-include-cache (= 0.2.1) + jekyll-mentions (= 1.6.0) + jekyll-optional-front-matter (= 0.3.2) + jekyll-paginate (= 1.1.0) + jekyll-readme-index (= 0.3.0) + jekyll-redirect-from (= 0.16.0) + jekyll-relative-links (= 0.6.1) + jekyll-remote-theme (= 0.4.3) + jekyll-sass-converter (= 1.5.2) + jekyll-seo-tag (= 2.8.0) + jekyll-sitemap (= 1.4.0) + jekyll-swiss (= 1.0.0) + jekyll-theme-architect (= 0.2.0) + jekyll-theme-cayman (= 0.2.0) + jekyll-theme-dinky (= 0.2.0) + jekyll-theme-hacker (= 0.2.0) + jekyll-theme-leap-day (= 0.2.0) + jekyll-theme-merlot (= 0.2.0) + jekyll-theme-midnight (= 0.2.0) + jekyll-theme-minimal (= 0.2.0) + jekyll-theme-modernist (= 0.2.0) + jekyll-theme-primer (= 0.6.0) + jekyll-theme-slate (= 0.2.0) + jekyll-theme-tactile (= 0.2.0) + jekyll-theme-time-machine (= 0.2.0) + jekyll-titles-from-headings (= 0.5.3) + jemoji (= 0.12.0) + kramdown (= 2.3.2) + kramdown-parser-gfm (= 1.1.0) + liquid (= 4.0.4) + mercenary (~> 0.3) + minima (= 2.5.1) + nokogiri (>= 1.13.6, < 2.0) + rouge (= 3.26.0) + terminal-table (~> 1.4) + github-pages-health-check (1.17.9) + addressable (~> 2.3) + dnsruby (~> 1.60) + octokit (~> 4.0) + public_suffix (>= 3.0, < 5.0) + typhoeus (~> 1.3) + html-pipeline (2.14.3) + activesupport (>= 2) + nokogiri (>= 1.4) + http_parser.rb (0.8.0) + i18n (1.12.0) + concurrent-ruby (~> 1.0) + jekyll (3.9.3) + addressable (~> 2.4) + colorator (~> 1.0) + em-websocket (~> 0.5) + i18n (>= 0.7, < 2) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (>= 1.17, < 3) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + jekyll-avatar (0.7.0) + jekyll (>= 3.0, < 5.0) + jekyll-coffeescript (1.1.1) + coffee-script (~> 2.2) + coffee-script-source (~> 1.11.1) + jekyll-commonmark (1.4.0) + commonmarker (~> 0.22) + jekyll-commonmark-ghpages (0.4.0) + commonmarker (~> 0.23.7) + jekyll (~> 3.9.0) + jekyll-commonmark (~> 1.4.0) + rouge (>= 2.0, < 5.0) + jekyll-default-layout (0.1.4) + jekyll (~> 3.0) + jekyll-feed (0.15.1) + jekyll (>= 3.7, < 5.0) + jekyll-gist (1.5.0) + octokit (~> 4.2) + jekyll-github-metadata (2.13.0) + jekyll (>= 3.4, < 5.0) + octokit (~> 4.0, != 4.4.0) + jekyll-glossary_tooltip (1.5.0) + jekyll (>= 3.7, < 5.0) + jekyll-include-cache (0.2.1) + jekyll (>= 3.7, < 5.0) + jekyll-liquify (0.0.2) + liquid (>= 2.5, < 5.0) + redcarpet (~> 3.1) + jekyll-mentions (1.6.0) + html-pipeline (~> 2.3) + jekyll (>= 3.7, < 5.0) + jekyll-optional-front-matter (0.3.2) + jekyll (>= 3.0, < 5.0) + jekyll-paginate (1.1.0) + jekyll-readme-index (0.3.0) + jekyll (>= 3.0, < 5.0) + jekyll-redirect-from (0.16.0) + jekyll (>= 3.3, < 5.0) + jekyll-relative-links (0.6.1) + jekyll (>= 3.3, < 5.0) + jekyll-remote-theme (0.4.3) + addressable (~> 2.0) + jekyll (>= 3.5, < 5.0) + jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) + rubyzip (>= 1.3.0, < 3.0) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-seo-tag (2.8.0) + jekyll (>= 3.8, < 5.0) + jekyll-sitemap (1.4.0) + jekyll (>= 3.7, < 5.0) + jekyll-swiss (1.0.0) + jekyll-theme-architect (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-cayman (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-dinky (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-hacker (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-leap-day (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-merlot (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-midnight (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-minimal (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-modernist (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-primer (0.6.0) + jekyll (> 3.5, < 5.0) + jekyll-github-metadata (~> 2.9) + jekyll-seo-tag (~> 2.0) + jekyll-theme-slate (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-tactile (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-time-machine (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-titles-from-headings (0.5.3) + jekyll (>= 3.3, < 5.0) + jekyll-watch (2.2.1) + listen (~> 3.0) + jemoji (0.12.0) + gemoji (~> 3.0) + html-pipeline (~> 2.2) + jekyll (>= 3.0, < 5.0) + just-the-docs (0.4.1) + jekyll (>= 3.8.5) + jekyll-seo-tag (>= 2.0) + rake (>= 12.3.1) + kramdown (2.3.2) + rexml + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + liquid (4.0.4) + listen (3.8.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + mercenary (0.3.6) + minima (2.5.1) + jekyll (>= 3.5, < 5.0) + jekyll-feed (~> 0.9) + jekyll-seo-tag (~> 2.1) + minitest (5.17.0) + nokogiri (1.14.2-x86_64-linux) + racc (~> 1.4) + octokit (4.25.1) + faraday (>= 1, < 3) + sawyer (~> 0.9) + pathutil (0.16.2) + forwardable-extended (~> 2.6) + public_suffix (4.0.7) + racc (1.6.2) + rake (13.0.6) + rb-fsevent (0.11.2) + rb-inotify (0.10.1) + ffi (~> 1.0) + redcarpet (3.6.0) + rexml (3.2.5) + rouge (3.26.0) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + safe_yaml (1.0.5) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sawyer (0.9.2) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) + simpleidn (0.2.1) + unf (~> 0.1.4) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + typhoeus (1.4.0) + ethon (>= 0.9.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.8.1) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + github-pages + http_parser.rb (~> 0.6.0) + jekyll-feed + jekyll-glossary_tooltip + jekyll-liquify + jekyll-remote-theme + jekyll-sitemap + just-the-docs + tzinfo (>= 1, < 3) + tzinfo-data + wdm (~> 0.1.1) + webrick + +BUNDLED WITH + 2.3.25 diff --git a/README.md b/README.md new file mode 100644 index 0000000000..2fa9462992 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Recoil Site + +The recoil site is a jekyll application, usually hosted on github pages. + +## Testing locally + +Have a reasonably recent version of Ruby. Inside `doc/site` run: + +```bash +bundle +bundle exec jekyll build && bundle exec jekyll serve +``` + +Navigate to http://localhost:4000/spring + +## Generating LDoc + +Have [LDoc](https://github.com/lunarmodules/LDoc) installed or available at your `$PATH`. + +Inside `doc/LDoc` run: + +```bash +ldoc -c config.ld . +``` + +Keep in mind to see changes on the site you might have to restart jekyll. diff --git a/_authors/badosu.markdown b/_authors/badosu.markdown new file mode 100644 index 0000000000..308fb4cd38 --- /dev/null +++ b/_authors/badosu.markdown @@ -0,0 +1,4 @@ +--- +short_name: badosu +github: badosu +--- diff --git a/_authors/lhog.markdown b/_authors/lhog.markdown new file mode 100644 index 0000000000..7a96955e35 --- /dev/null +++ b/_authors/lhog.markdown @@ -0,0 +1,4 @@ +--- +short_name: lhog +github: lhog +--- diff --git a/_authors/p2004a.markdown b/_authors/p2004a.markdown new file mode 100644 index 0000000000..3d31064b8e --- /dev/null +++ b/_authors/p2004a.markdown @@ -0,0 +1,4 @@ +--- +short_name: p2004a +github: p2004a +--- diff --git a/_authors/sprunk.markdown b/_authors/sprunk.markdown new file mode 100644 index 0000000000..8002876154 --- /dev/null +++ b/_authors/sprunk.markdown @@ -0,0 +1,4 @@ +--- +short_name: sprunk +github: sprunk +--- diff --git a/_authors/verybadsoldier.markdown b/_authors/verybadsoldier.markdown new file mode 100644 index 0000000000..eb91f72af1 --- /dev/null +++ b/_authors/verybadsoldier.markdown @@ -0,0 +1,4 @@ +--- +short_name: verybadsoldier +github: verybadsoldier +--- diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000000..2d90a13e69 --- /dev/null +++ b/_config.yml @@ -0,0 +1,175 @@ +# Welcome to Jekyll! +# +# This config file is meant for settings that affect your whole blog, values +# which you are expected to set up once and rarely edit after that. If you find +# yourself editing this file very often, consider using Jekyll's data files +# feature for the data you need to update frequently. +# +# For technical reasons, this file is *NOT* reloaded automatically when you use +# 'bundle exec jekyll serve'. If you change this file, please restart the server process. +# +# If you need help with YAML syntax, here are some quick references for you: +# https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml +# https://learnxinyminutes.com/docs/yaml/ +# +# Site settings +# These are used to personalize your new site. If you look in the HTML files, +# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. +# You can create any custom variable you would like, and they will be accessible +# in the templates via {{ site.myvariable }}. + +title: Recoil +email: amadeusfolego@gmail.com +description: >- # this means to ignore newlines until "baseurl:" + Recoil RTS Engine +baseurl: "/spring" # the subpath of your site, e.g. /blog +url: "https://beyond-all-reason.github.io" # the base hostname & protocol for your site, e.g. http://example.com +#twitter_username: jekyllrb +github_username: beyond-all-reason +permalink: pretty +repository: beyond-all-reason/spring # for github-metadata + +# Build settings +#theme: minima +#theme: just-the-docs +remote_theme: just-the-docs/just-the-docs +plugins: + - jekyll-feed + - jekyll-github-metadata + - jekyll-glossary_tooltip + - jekyll-remote-theme + - jekyll-sitemap + - jekyll-seo-tag + +search: + # Split pages into sections that can be searched individually + # Supports 1 - 6, default: 2 + heading_level: 3 + # Maximum amount of previews per search result + # Default: 3 + previews: 3 + # Maximum amount of words to display before a matched word in the preview + # Default: 5 + preview_words_before: 5 + # Maximum amount of words to display after a matched word in the preview + # Default: 10 + preview_words_after: 10 + # Set the search token separator + # Default: /[\s\-/]+/ + # Example: enable support for hyphenated search words + tokenizer_separator: /[\s/]+/ + # Display the relative url in search results + # Supports true (default) or false + rel_url: true + # Enable or disable the search button that appears in the bottom right corner of every page + # Supports true or false (default) + button: false + +# External navigation links +#nav_external_links: +# - title: Just the Docs on GitHub +# url: https://github.com/just-the-docs/just-the-docs + +# Makes Aux links open in a new tab. Default is false +aux_links_new_tab: true + +# For copy button on code +enable_copy_code_button: true + +# Footer content +# appears at the bottom of every page's main content + +# Back to top link +back_to_top: true +back_to_top_text: "Back to top" + +footer_content: "Copyright © 2022 Recoil team. Distributed by an GPL2 license." + +# Footer last edited timestamp +last_edit_timestamp: true # show or hide edit time - page must have `last_modified_date` defined in the frontmatter +last_edit_time_format: "%b %e %Y at %I:%M %p" # uses ruby's time format: https://ruby-doc.org/stdlib-2.7.0/libdoc/time/rdoc/Time.html + + + +# Footer "Edit this page on GitHub" link text +gh_edit_link: true # show or hide edit this page link +gh_edit_link_text: "Edit this page on GitHub" +gh_edit_repository: "https://github.com/beyond-all-reason/spring" # the github URL for your repo +gh_edit_branch: "BAR105" # the branch that your docs is served from +gh_edit_source: doc/site # the source that your files originate from +gh_edit_view_mode: "tree" # "tree" or "edit" if you want the user to jump into the editor immediately + +# Color scheme currently only supports "dark", "light"/nil (default), or a custom scheme that you define +color_scheme: nil + +callouts_level: quiet # or loud +callouts: + highlight: + color: yellow + important: + title: Important + color: blue + new: + title: New + color: green + note: + title: Note + color: purple + warning: + title: Warning + color: red + +# Google Analytics Tracking (optional) +# Supports a CSV of tracking ID strings (eg. "UA-1234567-89,G-1AB234CDE5") +# Note: the main Just the Docs site does *not* use Google Analytics. +# ga_tracking: UA-2709176-10,G-5FG1HLH3XQ +# ga_tracking_anonymize_ip: true # Use GDPR compliant Google Analytics settings (true/nil by default) + +kramdown: + syntax_highlighter_opts: + block: + line_numbers: false + +compress_html: + clippings: all + comments: all + endings: all + startings: [] + blanklines: false + profile: false + # ignore: + # envs: all + +collections: + authors: + +# Exclude from processing. +# The following items will not be processed, by default. +# Any item listed under the `exclude:` key here will be automatically added to +# the internal "default list". +# +# Excluded items can be processed by explicitly listing the directories or +# their entries' file path in the `include:` list. +# +exclude: + # from https://github.com/jekyll/jekyll/blob/master/lib/site_template/_config.yml: + - .sass-cache/ + - .jekyll-cache/ + - gemfiles/ + - Gemfile + - Gemfile.lock + - node_modules/ + - vendor/bundle/ + - vendor/cache/ + - vendor/gems/ + - vendor/ruby/ + # specific to the theme website: + - bin/ + - lib/ + - "*.gemspec" + - "*.gem" + - LICENSE.txt + - package.json + - package-lock.json + - Rakefile + - README.md diff --git a/_data/configs.json b/_data/configs.json new file mode 100644 index 0000000000..3b8dc3bac7 --- /dev/null +++ b/_data/configs.json @@ -0,0 +1,2082 @@ +{ + "AdvMapShading": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 43, + "description": "Enable shaders for terrain rendering.", + "defaultValue": 1, + "safemodeValue": 0, + "type": "bool" + }, + "AdvSky": { + "declarationFile": "/spring/rts/Rendering/Env/ISky.cpp", + "declarationLine": 19, + "deprecated": 1, + "type": "bool" + }, + "AdvUnitShading": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 67, + "description": "Determines whether specular highlights and other lighting effects are rendered for units.", + "defaultValue": 1, + "safemodeValue": 0, + "headlessValue": 0, + "type": "bool" + }, + "AllowDeferredMapRendering": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 44, + "defaultValue": 0, + "safemodeValue": 0, + "type": "bool" + }, + "AllowDeferredModelBufferClear": { + "declarationFile": "/spring/rts/Rendering/LuaObjectDrawer.cpp", + "declarationLine": 32, + "defaultValue": 0, + "safemodeValue": 0, + "type": "bool" + }, + "AllowDeferredModelRendering": { + "declarationFile": "/spring/rts/Rendering/LuaObjectDrawer.cpp", + "declarationLine": 31, + "defaultValue": 0, + "safemodeValue": 0, + "type": "bool" + }, + "AllowDrawMapDeferredEvents": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 46, + "defaultValue": 0, + "type": "bool" + }, + "AllowDrawMapPostDeferredEvents": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 45, + "defaultValue": 0, + "type": "bool" + }, + "AllowDrawModelPostDeferredEvents": { + "declarationFile": "/spring/rts/Rendering/LuaObjectDrawer.cpp", + "declarationLine": 33, + "defaultValue": 1, + "type": "bool" + }, + "AllowMultiSampledFrameBuffers": { + "declarationFile": "/spring/rts/Rendering/LuaObjectDrawer.cpp", + "declarationLine": 34, + "defaultValue": 0, + "type": "bool" + }, + "AllowSpectatorJoin": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 73, + "description": "allow any unauthenticated clients to join as spectator with any name, name will be prefixed with ~", + "defaultValue": 1, + "dedicatedValue": 0, + "type": "bool" + }, + "AlwaysSendDrawGroundEvents": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 55, + "description": "Always send DrawGround{Pre,Post}{Forward,Deferred} events", + "defaultValue": 0, + "type": "bool" + }, + "AtiHacks": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 57, + "description": "Enables graphics drivers workarounds for users with AMD proprietary drivers.\n -1:=runtime detect, 0:=off, 1:=on", + "defaultValue": -1, + "minimumValue": -1, + "maximumValue": 1, + "headlessValue": 0, + "type": "int" + }, + "AtiSwapRBFix": { + "declarationFile": "/spring/rts/Rendering/GL/FBO.cpp", + "declarationLine": 16, + "defaultValue": 0, + "type": "bool" + }, + "AutoAddBuiltUnitsToFactoryGroup": { + "declarationFile": "/spring/rts/Game/SelectedUnitsHandler.cpp", + "declarationLine": 49, + "description": "Controls whether or not units built by factories will inherit that factory's unit group.", + "defaultValue": 0, + "type": "bool" + }, + "AutoAddBuiltUnitsToSelectedGroup": { + "declarationFile": "/spring/rts/Game/SelectedUnitsHandler.cpp", + "declarationLine": 50, + "defaultValue": 0, + "type": "bool" + }, + "AutohostIP": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 78, + "defaultValue": "127.0.0.1", + "type": "std::string" + }, + "AutohostPort": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 69, + "defaultValue": 0, + "type": "int" + }, + "BlockCompositing": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 69, + "description": "Disables kwin compositing to fix tearing, possible fixes low FPS in windowed mode, too.", + "defaultValue": 0, + "safemodeValue": 1, + "type": "bool" + }, + "BuildIconsFirst": { + "declarationFile": "/spring/rts/Game/SelectedUnitsHandler.cpp", + "declarationLine": 48, + "defaultValue": 0, + "type": "bool" + }, + "BumpWaterAnisotropy": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 45, + "defaultValue": 0, + "minimumValue": 0, + "type": "float" + }, + "BumpWaterBlurReflection": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 48, + "defaultValue": 0, + "type": "bool" + }, + "BumpWaterDepthBits": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 47, + "defaultValue": 24, + "minimumValue": 16, + "maximumValue": 32, + "type": "int" + }, + "BumpWaterDynamicWaves": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 51, + "defaultValue": 1, + "type": "bool" + }, + "BumpWaterEndlessOcean": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 50, + "description": "Sets whether Bumpmapped water will be drawn beyond the map edge.", + "defaultValue": 1, + "type": "bool" + }, + "BumpWaterOcclusionQuery": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 53, + "deprecated": 1, + "type": "bool" + }, + "BumpWaterReflection": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 43, + "description": "Determines the amount of objects reflected in Bumpmapped water.\n0:=off, 1:=fast (skip terrain), 2:=full", + "defaultValue": 1, + "minimumValue": 0, + "maximumValue": 2, + "headlessValue": 0, + "type": "int" + }, + "BumpWaterRefraction": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 44, + "description": "Determines the method of refraction with Bumpmapped water.\n0:=off, 1:=screencopy, 2:=own rendering cycle (disabled)", + "defaultValue": 1, + "minimumValue": 0, + "maximumValue": 1, + "headlessValue": 0, + "type": "int" + }, + "BumpWaterShoreWaves": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 49, + "description": "Enables rendering of shorewaves.", + "defaultValue": 1, + "safemodeValue": 0, + "headlessValue": 0, + "type": "bool" + }, + "BumpWaterTexSizeReflection": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 42, + "description": "Sets the size of the framebuffer texture used to store the reflection in Bumpmapped water.", + "defaultValue": 512, + "minimumValue": 32, + "headlessValue": 32, + "type": "int" + }, + "BumpWaterUseDepthTexture": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 46, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "BumpWaterUseUniforms": { + "declarationFile": "/spring/rts/Rendering/Env/BumpWater.cpp", + "declarationLine": 52, + "deprecated": 1, + "type": "bool" + }, + "CamFrameTimeCorrection": { + "declarationFile": "/spring/rts/Game/Camera.cpp", + "declarationLine": 33, + "description": "Sets wether the camera interpolation factor should be the inverse of fps or last draw frame time (0 = lastdrawframetime, 1 = fpsinv)", + "defaultValue": 0, + "minimumValue": 0, + "type": "int" + }, + "CamFreeAngVelTime": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 29, + "defaultValue": 1, + "type": "float" + }, + "CamFreeAutoTilt": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 27, + "description": "When free camera is locked, AutoTilt will point the camera in the direction of the ground's slope", + "defaultValue": 150, + "type": "float" + }, + "CamFreeEnabled": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 18, + "defaultValue": 0, + "type": "bool" + }, + "CamFreeFOV": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 21, + "defaultValue": 45, + "type": "float" + }, + "CamFreeGoForward": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 20, + "defaultValue": 0, + "type": "bool" + }, + "CamFreeGravity": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 23, + "description": "When free camera is locked, Gravity will be used if you jump off of a ground ramp.", + "defaultValue": -500, + "type": "float" + }, + "CamFreeGroundOffset": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 25, + "description": "Determines ground handling for the free camera.\n0 - the camera can move anywhere,\n< 0 - the camera is always offset from the ground height by -CamFreeGroundOffset\n> 0 - the camera can be \"locked\" to the ground by using SHIFT UP_ARROW. (and will use CamFreeGroundOffset as the offset). To release the lock, simply press SHIFT DOWN_ARROW.", + "defaultValue": 16, + "type": "float" + }, + "CamFreeInvertAlt": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 19, + "defaultValue": 0, + "type": "bool" + }, + "CamFreeScrollSpeed": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 22, + "defaultValue": 500, + "type": "float" + }, + "CamFreeSlide": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 24, + "defaultValue": 0.5, + "type": "float" + }, + "CamFreeTiltSpeed": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 26, + "defaultValue": 150, + "type": "float" + }, + "CamFreeVelTime": { + "declarationFile": "/spring/rts/Game/Camera/FreeController.cpp", + "declarationLine": 28, + "defaultValue": 1.5, + "type": "float" + }, + "CamMode": { + "declarationFile": "/spring/rts/Game/CameraHandler.cpp", + "declarationLine": 41, + "description": "Defines the used camera. Options are:\n0 = FPS\n1 = Overhead\n2 = Spring\n3 = RotOverhead\n4 = Free\n5 = Overview", + "defaultValue": 2, + "minimumValue": 0, + "maximumValue": 5, + "type": "int" + }, + "CamModeName": { + "declarationFile": "/spring/rts/Game/CameraHandler.cpp", + "declarationLine": 39, + "defaultValue": "", + "type": "std::string" + }, + "CamOverheadFastScale": { + "declarationFile": "/spring/rts/Game/Camera/OverheadController.cpp", + "declarationLine": 24, + "description": "Scaling for CameraMoveFastMult.", + "defaultValue": 0.3, + "type": "float" + }, + "CamSpringEdgeRotate": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 24, + "description": "Rotate camera when cursor touches screen borders.", + "defaultValue": 0, + "type": "bool" + }, + "CamSpringEnabled": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 18, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "CamSpringFOV": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 20, + "defaultValue": 45, + "type": "float" + }, + "CamSpringFastScaleMouseMove": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 25, + "description": "Scaling for CameraMoveFastMult in spring camera mode while moving mouse.", + "defaultValue": 0.3, + "type": "float" + }, + "CamSpringFastScaleMousewheelMove": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 26, + "description": "Scaling for CameraMoveFastMult in spring camera mode while scrolling with mouse.", + "defaultValue": 0.2, + "type": "float" + }, + "CamSpringLockCardinalDirections": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 21, + "description": "Whether cardinal directions should be `locked` for a short time when rotating.", + "defaultValue": 1, + "type": "bool" + }, + "CamSpringScrollSpeed": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 19, + "defaultValue": 10, + "type": "int" + }, + "CamSpringZoomInToMousePos": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 22, + "defaultValue": 1, + "type": "bool" + }, + "CamSpringZoomOutFromMousePos": { + "declarationFile": "/spring/rts/Game/Camera/SpringController.cpp", + "declarationLine": 23, + "defaultValue": 0, + "type": "bool" + }, + "CamTimeExponent": { + "declarationFile": "/spring/rts/Game/CameraHandler.cpp", + "declarationLine": 59, + "description": "Camera transitions happen at lerp(old, new, timeNorm ^ CamTimeExponent).", + "defaultValue": 4, + "minimumValue": 0, + "type": "float" + }, + "CamTimeFactor": { + "declarationFile": "/spring/rts/Game/CameraHandler.cpp", + "declarationLine": 54, + "description": "Scales the speed of camera transitions, e.g. zooming or position change.", + "defaultValue": 1, + "minimumValue": 0, + "type": "float" + }, + "CameraMoveFastMult": { + "declarationFile": "/spring/rts/Game/Camera.cpp", + "declarationLine": 25, + "description": "The multiplier applied to speed when camera is in movefast state.", + "defaultValue": 10, + "minimumValue": 1, + "type": "float" + }, + "CameraMoveSlowMult": { + "declarationFile": "/spring/rts/Game/Camera.cpp", + "declarationLine": 29, + "description": "The multiplier applied to speed when camera is in moveslow state.", + "defaultValue": 0.1, + "maximumValue": 1, + "type": "float" + }, + "ColorElev": { + "declarationFile": "/spring/rts/Map/HeightLinePalette.cpp", + "declarationLine": 8, + "description": "If heightmap (default hotkey [F1]) should be colored or not.", + "defaultValue": 1, + "type": "bool" + }, + "CompressTextures": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 60, + "description": "Runtime compress most textures to save VideoRAM.", + "defaultValue": 0, + "safemodeValue": 1, + "type": "bool" + }, + "CrossAlpha": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 56, + "defaultValue": 0.5, + "type": "float" + }, + "CrossMoveScale": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 57, + "defaultValue": 1, + "type": "float" + }, + "CrossSize": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 55, + "defaultValue": 12, + "type": "float" + }, + "CubeTexGenerateMipMaps": { + "declarationFile": "/spring/rts/Rendering/Env/CubeMapHandler.cpp", + "declarationLine": 21, + "defaultValue": 0, + "type": "bool" + }, + "CubeTexSizeReflection": { + "declarationFile": "/spring/rts/Rendering/Env/CubeMapHandler.cpp", + "declarationLine": 20, + "defaultValue": 128, + "minimumValue": 1, + "type": "int" + }, + "CubeTexSizeSpecular": { + "declarationFile": "/spring/rts/Rendering/Env/CubeMapHandler.cpp", + "declarationLine": 19, + "defaultValue": 128, + "minimumValue": 1, + "type": "int" + }, + "DebugGL": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 42, + "description": "Enables GL debug-context and output. (see GL_ARB_debug_output)", + "defaultValue": 0, + "type": "bool" + }, + "DebugGLStacktraces": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 43, + "description": "Create a stacktrace when an OpenGL error occurs", + "defaultValue": 0, + "type": "bool" + }, + "DefaultLuaMenu": { + "declarationFile": "/spring/rts/Menu/LuaMenuController.cpp", + "declarationLine": 18, + "description": "Sets the default menu to be used when spring is started.", + "defaultValue": "", + "type": "std::string" + }, + "DefaultStartScript": { + "declarationFile": "/spring/rts/System/SpringApp.cpp", + "declarationLine": 112, + "description": "filename of script.txt to use when no command line parameters are specified.", + "defaultValue": "", + "type": "std::string" + }, + "DemoFromDemo": { + "declarationFile": "/spring/rts/Game/PreGame.cpp", + "declarationLine": 60, + "defaultValue": 0, + "type": "bool" + }, + "DeprecatedGLWarnLevel": { + "declarationFile": "/spring/rts/Lua/LuaOpenGL.cpp", + "declarationLine": 83, + "defaultValue": 0, + "safemodeValue": 0, + "headlessValue": 0, + "type": "int" + }, + "DisableDemoVersionCheck": { + "declarationFile": "/spring/rts/System/LoadSave/DemoReader.cpp", + "declarationLine": 10, + "description": "Allow to play every replay file (may crash / cause undefined behaviour in replays)", + "defaultValue": 0, + "type": "bool" + }, + "DoubleClickTime": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 59, + "description": "Double click time in milliseconds.", + "defaultValue": 200, + "type": "float" + }, + "DualScreenMiniMapAspectRatio": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 71, + "description": "Whether minimap preserves aspect ratio on dual screen mode.", + "defaultValue": 1, + "type": "bool" + }, + "DualScreenMiniMapOnLeft": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 62, + "description": "When set, will make the left half of the screen the minimap when DualScreenMode is set.", + "defaultValue": 0, + "type": "bool" + }, + "DualScreenMode": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 61, + "description": "Sets whether to split the screen in half, with one half for minimap and one for main screen. Right side is for minimap unless DualScreenMiniMapOnLeft is set.", + "defaultValue": 0, + "type": "bool" + }, + "DumpGameStateOnDesync": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 63, + "defaultValue": 0, + "type": "bool" + }, + "EdgeMoveDynamic": { + "declarationFile": "/spring/rts/Game/Camera.cpp", + "declarationLine": 22, + "description": "If EdgeMove scrolling speed should fade with edge distance.", + "defaultValue": 1, + "type": "bool" + }, + "EdgeMoveWidth": { + "declarationFile": "/spring/rts/Game/Camera.cpp", + "declarationLine": 18, + "description": "The width (in percent of screen size) of the EdgeMove scrolling area.", + "defaultValue": 0.02, + "minimumValue": 0, + "type": "float" + }, + "ExtraTextureUpdateRate": { + "declarationFile": "/spring/rts/Rendering/Map/InfoTexture/Legacy/LegacyInfoTextureHandler.cpp", + "declarationLine": 22, + "description": "EXTREME CPU-HEAVY ON MEDIUM/BIG MAPS! DON'T CHANGE DEFAULT!", + "defaultValue": 45, + "type": "int" + }, + "FPSClampPos": { + "declarationFile": "/spring/rts/Game/Camera/FPSController.cpp", + "declarationLine": 18, + "defaultValue": 1, + "type": "bool" + }, + "FPSEnabled": { + "declarationFile": "/spring/rts/Game/Camera/FPSController.cpp", + "declarationLine": 16, + "defaultValue": 1, + "type": "bool" + }, + "FPSFOV": { + "declarationFile": "/spring/rts/Game/Camera/FPSController.cpp", + "declarationLine": 17, + "defaultValue": 45, + "type": "float" + }, + "FPSMouseScale": { + "declarationFile": "/spring/rts/Game/Camera/FPSController.cpp", + "declarationLine": 15, + "defaultValue": 0.01, + "type": "float" + }, + "FPSScrollSpeed": { + "declarationFile": "/spring/rts/Game/Camera/FPSController.cpp", + "declarationLine": 14, + "defaultValue": 10, + "type": "int" + }, + "FSAA": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 80, + "deprecated": 1, + "type": "bool" + }, + "FSAALevel": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 81, + "deprecated": 1, + "type": "int" + }, + "FeatureDrawDistance": { + "declarationFile": "/spring/rts/Rendering/Features/FeatureDrawerData.cpp", + "declarationLine": 14, + "description": "Maximum distance at which features will be drawn.", + "defaultValue": 6000, + "minimumValue": 0, + "type": "float" + }, + "FeatureFadeDistance": { + "declarationFile": "/spring/rts/Rendering/Features/FeatureDrawerData.cpp", + "declarationLine": 19, + "description": "Distance at which features will begin to fade from view.", + "defaultValue": 4500, + "minimumValue": 0, + "type": "float" + }, + "FontFile": { + "declarationFile": "/spring/rts/Rendering/Fonts/glFont.cpp", + "declarationLine": 22, + "description": "Sets the font of Spring engine text.", + "defaultValue": "fonts/FreeSansBold.otf", + "type": "std::string" + }, + "FontOutlineWeight": { + "declarationFile": "/spring/rts/Rendering/Fonts/glFont.cpp", + "declarationLine": 29, + "description": "Sets the opacity of Spring engine text, such as the title screen version number, clock, and basic UI. Does not affect LuaUI elements.", + "defaultValue": 25, + "type": "float" + }, + "FontOutlineWidth": { + "declarationFile": "/spring/rts/Rendering/Fonts/glFont.cpp", + "declarationLine": 27, + "description": "Sets the width of the black outline around Spring engine text, such as the title screen version number, clock, and basic UI. Does not affect LuaUI elements.", + "defaultValue": 3, + "type": "int" + }, + "FontSize": { + "declarationFile": "/spring/rts/Rendering/Fonts/glFont.cpp", + "declarationLine": 25, + "description": "Sets the font size (in pixels) of the MainMenu and more.", + "defaultValue": 23, + "type": "int" + }, + "ForceCoreContext": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 55, + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 1, + "type": "int" + }, + "ForceDisableClipCtrl": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 51, + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 1, + "type": "int" + }, + "ForceDisableExplicitAttribLocs": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 50, + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 1, + "type": "int" + }, + "ForceDisableGL4": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 53, + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 1, + "safemodeValue": 1, + "type": "int" + }, + "ForceDisablePersistentMapping": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 49, + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 1, + "type": "int" + }, + "ForceDisableShaders": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 82, + "deprecated": 1, + "type": "bool" + }, + "ForceSwapBuffers": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 56, + "defaultValue": 1, + "minimumValue": 0, + "maximumValue": 1, + "type": "int" + }, + "Fullscreen": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 67, + "description": "Sets whether the game will run in fullscreen, as opposed to a window. For Windowed Fullscreen of Borderless Window, set this to 0, WindowBorderless to 1, and WindowPosX and WindowPosY to 0.", + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "FullscreenEdgeMove": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 136, + "description": "see WindowedEdgeMove, just for fullscreen mode", + "defaultValue": 1, + "type": "bool" + }, + "GLContextMajorVersion": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 45, + "defaultValue": 3, + "minimumValue": 3, + "maximumValue": 4, + "type": "int" + }, + "GLContextMinorVersion": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 46, + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 5, + "type": "int" + }, + "GameEndOnConnectionLoss": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 132, + "defaultValue": 1, + "type": "bool" + }, + "GrassDetail": { + "declarationFile": "/spring/rts/Rendering/Env/GrassDrawer.cpp", + "declarationLine": 35, + "description": "Sets how detailed the engine rendered grass will be on any given map.", + "defaultValue": 7, + "minimumValue": 0, + "headlessValue": 0, + "type": "int" + }, + "GroundDecals": { + "declarationFile": "/spring/rts/Rendering/Env/IGroundDecalDrawer.cpp", + "declarationLine": 12, + "description": "Controls whether ground decals underneath buildings and ground scars from explosions will be rendered. Values >1 define how long such decals will stay.", + "defaultValue": 3, + "headlessValue": 0, + "type": "int" + }, + "GroundDecalsParallaxMapping": { + "declarationFile": "/spring/rts/Rendering/Env/Decals/DecalsDrawerGL4.cpp", + "declarationLine": 47, + "defaultValue": 1, + "type": "bool" + }, + "GroundDetail": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 30, + "description": "Controls how detailed the map geometry will be. On lowered settings, cliffs may appear to be jagged or \"melting\".", + "defaultValue": 60, + "minimumValue": 4, + "maximumValue": 200, + "headlessValue": 0, + "type": "int" + }, + "GroundLODScaleReflection": { + "declarationFile": "/spring/rts/Map/BaseGroundDrawer.cpp", + "declarationLine": 7, + "defaultValue": 1, + "headlessValue": 0, + "type": "float" + }, + "GroundLODScaleRefraction": { + "declarationFile": "/spring/rts/Map/BaseGroundDrawer.cpp", + "declarationLine": 8, + "defaultValue": 1, + "headlessValue": 0, + "type": "float" + }, + "GroundLODScaleTerrainReflection": { + "declarationFile": "/spring/rts/Map/BaseGroundDrawer.cpp", + "declarationLine": 9, + "defaultValue": 1, + "type": "float" + }, + "GroundNormalTextureHighPrecision": { + "declarationFile": "/spring/rts/Map/SMF/SMFReadMap.cpp", + "declarationLine": 35, + "defaultValue": 0, + "type": "bool" + }, + "GroundScarAlphaFade": { + "declarationFile": "/spring/rts/Rendering/Env/Decals/GroundDecalHandler.cpp", + "declarationLine": 55, + "defaultValue": 0, + "type": "int" + }, + "GuiOpacity": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 142, + "description": "Sets the opacity of the built-in Spring UI. Generally has no effect on LuaUI widgets. Can be set in-game using shift+, to decrease and shift+. to increase.", + "defaultValue": 0.8, + "minimumValue": 0, + "maximumValue": 1, + "type": "float" + }, + "HangTimeout": { + "declarationFile": "/spring/rts/System/Platform/Watchdog.cpp", + "declarationLine": 24, + "description": "Number of seconds that, if spent in the same code segment, indicate a hang; -1 to disable.", + "defaultValue": 60, + "minimumValue": -1, + "maximumValue": 600, + "type": "int" + }, + "HardwareCursor": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 50, + "description": "Sets hardware mouse cursor rendering. If you have a low framerate, your mouse cursor will seem \"laggy\". Setting hardware cursor will render the mouse cursor separately from spring and the mouse will behave normally. Note, not all GPU drivers support it in fullscreen mode!", + "defaultValue": 0, + "type": "bool" + }, + "HighResInfoTexture": { + "declarationFile": "/spring/rts/Rendering/Map/InfoTexture/Modern/Combiner.cpp", + "declarationLine": 14, + "defaultValue": 1, + "type": "bool" + }, + "HighResLos": { + "declarationFile": "/spring/rts/Rendering/Map/InfoTexture/Legacy/LegacyInfoTextureHandler.cpp", + "declarationLine": 21, + "description": "Controls whether LOS (\"L view\") edges are rendered in high resolution. Resource heavy!", + "defaultValue": 0, + "type": "bool" + }, + "HostIPDefault": { + "declarationFile": "/spring/rts/Game/ClientSetup.cpp", + "declarationLine": 16, + "description": "Default IP to use for hosting if not specified in script.txt", + "defaultValue": "localhost", + "dedicatedValue": "", + "type": "std::string" + }, + "HostPortDefault": { + "declarationFile": "/spring/rts/Game/ClientSetup.cpp", + "declarationLine": 17, + "description": "Default Port to use for hosting if not specified in script.txt", + "defaultValue": 8452, + "minimumValue": 0, + "maximumValue": 65535, + "type": "int" + }, + "InfoConsoleGeometry": { + "declarationFile": "/spring/rts/Game/UI/InfoConsole.cpp", + "declarationLine": 14, + "defaultValue": "0.26 0.96 0.41 0.205", + "type": "std::string" + }, + "InfoMessageTime": { + "declarationFile": "/spring/rts/Game/UI/InfoConsole.cpp", + "declarationLine": 13, + "description": "Time until old messages disappear from the ingame console.", + "defaultValue": 10, + "type": "int" + }, + "InitialNetworkTimeout": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 15, + "defaultValue": 30, + "minimumValue": 10, + "type": "int" + }, + "InputTextGeo": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 143, + "defaultValue": "", + "type": "std::string" + }, + "InvertMouse": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 51, + "defaultValue": 0, + "type": "bool" + }, + "InvertQueueKey": { + "declarationFile": "/spring/rts/Game/UI/GuiHandler.cpp", + "declarationLine": 60, + "defaultValue": 0, + "type": "bool" + }, + "KeyChainTimeout": { + "declarationFile": "/spring/rts/Game/UI/KeyBindings.cpp", + "declarationLine": 29, + "description": "Timeout in milliseconds waiting for a key chain shortcut.", + "defaultValue": 750, + "minimumValue": 0, + "type": "int" + }, + "LODScale": { + "declarationFile": "/spring/rts/Rendering/LuaObjectDrawer.cpp", + "declarationLine": 36, + "defaultValue": 1, + "type": "float" + }, + "LODScaleReflection": { + "declarationFile": "/spring/rts/Rendering/LuaObjectDrawer.cpp", + "declarationLine": 38, + "defaultValue": 1, + "type": "float" + }, + "LODScaleRefraction": { + "declarationFile": "/spring/rts/Rendering/LuaObjectDrawer.cpp", + "declarationLine": 39, + "defaultValue": 1, + "type": "float" + }, + "LODScaleShadow": { + "declarationFile": "/spring/rts/Rendering/LuaObjectDrawer.cpp", + "declarationLine": 37, + "defaultValue": 1, + "type": "float" + }, + "LastSelectedMap": { + "declarationFile": "/spring/rts/Menu/SelectionWidget.cpp", + "declarationLine": 29, + "description": "Stores the previously played map.", + "defaultValue": "No map selected", + "type": "std::string" + }, + "LastSelectedMod": { + "declarationFile": "/spring/rts/Menu/SelectionWidget.cpp", + "declarationLine": 28, + "description": "Stores the previously played game.", + "defaultValue": "No game selected", + "type": "std::string" + }, + "LastSelectedScript": { + "declarationFile": "/spring/rts/Menu/SelectionWidget.cpp", + "declarationLine": 30, + "description": "Stores the previously played AI.", + "defaultValue": "No script selected", + "type": "std::string" + }, + "LastSelectedSetting": { + "declarationFile": "/spring/rts/Menu/SelectMenu.cpp", + "declarationLine": 46, + "description": "Stores the previously selected setting, when editing settings within the Spring main menu.", + "defaultValue": "", + "type": "std::string" + }, + "LinkIncomingMaxPacketRate": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 43, + "defaultValue": 64, + "minimumValue": 0, + "type": "int" + }, + "LinkIncomingMaxWaitingPackets": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 49, + "defaultValue": 512, + "minimumValue": 0, + "type": "int" + }, + "LinkIncomingPeakBandwidth": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 39, + "defaultValue": 32768, + "minimumValue": 0, + "type": "int" + }, + "LinkIncomingSustainedBandwidth": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 35, + "defaultValue": 2048, + "minimumValue": 0, + "type": "int" + }, + "LinkOutgoingBandwidth": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 31, + "defaultValue": 65536, + "minimumValue": 0, + "type": "int" + }, + "LoadBadSaves": { + "declarationFile": "/spring/rts/Game/PreGame.cpp", + "declarationLine": 61, + "defaultValue": 0, + "type": "bool" + }, + "LoadingMT": { + "declarationFile": "/spring/rts/Game/LoadScreen.cpp", + "declarationLine": 46, + "description": "Experimental option to load the game in separate thread. Expect visual glitches, crashes and deadlocks", + "defaultValue": 0, + "safemodeValue": 0, + "type": "int" + }, + "LogClientData": { + "declarationFile": "/spring/rts/Net/NetCommands.cpp", + "declarationLine": 43, + "defaultValue": 0, + "type": "bool" + }, + "LogFlushLevel": { + "declarationFile": "/spring/rts/System/LogOutput.cpp", + "declarationLine": 38, + "description": "Flush the logfile when a message's level exceeds this value. ERROR is flushed by default, WARNING is not.", + "defaultValue": 50, + "type": "int" + }, + "LogRepeatLimit": { + "declarationFile": "/spring/rts/System/LogOutput.cpp", + "declarationLine": 42, + "description": "Allow at most this many consecutive identical messages to be logged.", + "defaultValue": 10, + "type": "int" + }, + "LogSections": { + "declarationFile": "/spring/rts/System/LogOutput.cpp", + "declarationLine": 33, + "description": "Comma-separated list of enabled logsections, see infolog.txt / console output for possible values.", + "defaultValue": "", + "type": "std::string" + }, + "LuaGarbageCollectionMemLoadMult": { + "declarationFile": "/spring/rts/Lua/LuaHandle.cpp", + "declarationLine": 59, + "defaultValue": 1.33, + "minimumValue": 1, + "maximumValue": 100, + "type": "float" + }, + "LuaGarbageCollectionRunTimeMult": { + "declarationFile": "/spring/rts/Lua/LuaHandle.cpp", + "declarationLine": 60, + "description": "in milliseconds", + "defaultValue": 5, + "minimumValue": 1, + "type": "float" + }, + "LuaShaders": { + "declarationFile": "/spring/rts/Lua/LuaOpenGL.cpp", + "declarationLine": 82, + "defaultValue": 1, + "safemodeValue": 0, + "headlessValue": 0, + "type": "bool" + }, + "LuaSocketEnabled": { + "declarationFile": "/spring/rts/Lua/LuaUI.cpp", + "declarationLine": 47, + "description": "Enable LuaSocket support, allows Lua widgets to make TCP/UDP connections", + "readOnly": 1, + "defaultValue": 1, + "type": "bool" + }, + "LuaWritableConfigFile": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 60, + "defaultValue": 1, + "type": "bool" + }, + "MSAALevel": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 47, + "description": "Enables multisample anti-aliasing; 'level' is the number of samples used.", + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 32, + "type": "int" + }, + "MapBorder": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 36, + "description": "Draws a solid border at the edges of the map.", + "defaultValue": 1, + "type": "bool" + }, + "MaxDynamicMapLights": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 39, + "defaultValue": 1, + "minimumValue": 0, + "type": "int" + }, + "MaxDynamicModelLights": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 63, + "defaultValue": 1, + "minimumValue": 0, + "type": "int" + }, + "MaxNanoParticles": { + "declarationFile": "/spring/rts/Sim/Projectiles/ProjectileHandler.cpp", + "declarationLine": 42, + "defaultValue": 2000, + "minimumValue": 0, + "headlessValue": 0, + "type": "int" + }, + "MaxParticles": { + "declarationFile": "/spring/rts/Sim/Projectiles/ProjectileHandler.cpp", + "declarationLine": 41, + "defaultValue": 10000, + "minimumValue": 0, + "headlessValue": 0, + "type": "int" + }, + "MaxSounds": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 30, + "description": "Maximum sounds played in parallel.", + "defaultValue": 128, + "minimumValue": 1, + "headlessValue": 1, + "type": "int" + }, + "MaxTextureAtlasSizeX": { + "declarationFile": "/spring/rts/Rendering/Textures/TextureAtlas.cpp", + "declarationLine": 22, + "defaultValue": 2048, + "minimumValue": 512, + "maximumValue": 32768, + "type": "int" + }, + "MaxTextureAtlasSizeY": { + "declarationFile": "/spring/rts/Rendering/Textures/TextureAtlas.cpp", + "declarationLine": 23, + "defaultValue": 2048, + "minimumValue": 512, + "maximumValue": 32768, + "type": "int" + }, + "MaximumTransmissionUnit": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 27, + "defaultValue": 1400, + "minimumValue": 400, + "type": "int" + }, + "MenuArchive": { + "declarationFile": "/spring/rts/Menu/SelectMenu.cpp", + "declarationLine": 47, + "description": "Archive name for the default Menu.", + "defaultValue": "Spring Bitmaps", + "type": "std::string" + }, + "MiddleClickScrollSpeed": { + "declarationFile": "/spring/rts/Game/Camera/OverheadController.cpp", + "declarationLine": 18, + "defaultValue": 0.01, + "type": "float" + }, + "MiniMapButtonSize": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 53, + "defaultValue": 16, + "type": "int" + }, + "MiniMapCanDraw": { + "declarationFile": "/spring/rts/Game/InMapDraw.cpp", + "declarationLine": 28, + "description": "Enables drawing with cursor over MiniMap.", + "defaultValue": 0, + "type": "bool" + }, + "MiniMapCanFlip": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 73, + "description": "Whether minimap inverts coordinates when camera Y rotation is between 90 and 270 degrees.", + "defaultValue": 0, + "type": "bool" + }, + "MiniMapCursorScale": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 60, + "defaultValue": -0.5, + "type": "float" + }, + "MiniMapDrawCommands": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 63, + "defaultValue": 1, + "minimumValue": 0, + "headlessValue": 0, + "type": "int" + }, + "MiniMapDrawProjectiles": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 65, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "MiniMapFullProxy": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 52, + "defaultValue": 1, + "type": "bool" + }, + "MiniMapGeometry": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 51, + "defaultValue": "2 2 200 200", + "type": "std::string" + }, + "MiniMapIcons": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 61, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "MiniMapMarker": { + "declarationFile": "/spring/rts/Game/UI/GuiHandler.cpp", + "declarationLine": 59, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "MiniMapMouseWheel": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 53, + "description": "Whether MiniMap responds to MouseWheel events", + "defaultValue": 0, + "type": "bool" + }, + "MiniMapRefreshRate": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 69, + "description": "The refresh rate of the async MiniMap texture. Needs MiniMapRenderToTexture to be true. Value of \"0\" autoselects between 10-60FPS.", + "defaultValue": 0, + "minimumValue": 0, + "type": "int" + }, + "MiniMapRenderToTexture": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 68, + "description": "Asynchronous render MiniMap to a texture independent of screen FPS.", + "defaultValue": 1, + "safemodeValue": 0, + "type": "bool" + }, + "MiniMapUnitExp": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 59, + "defaultValue": 0.25, + "type": "float" + }, + "MiniMapUnitSize": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 55, + "defaultValue": 2.5, + "minimumValue": 0, + "type": "float" + }, + "MinimizeOnFocusLoss": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 65, + "description": "When set to 1 minimize Window if it loses key focus when in fullscreen mode.", + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 1, + "type": "int" + }, + "MouseDragBoxCommandThreshold": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 65, + "description": "Distance in pixels which the mouse must be dragged to trigger a rectangular area command.", + "defaultValue": 16, + "type": "int" + }, + "MouseDragCircleCommandThreshold": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 64, + "description": "Distance in pixels which the mouse must be dragged to trigger a circular area command.", + "defaultValue": 4, + "type": "int" + }, + "MouseDragFrontCommandThreshold": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 66, + "description": "Distance in pixels which the mouse must be dragged to trigger a formation front command.", + "defaultValue": 30, + "type": "int" + }, + "MouseDragScrollThreshold": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 62, + "defaultValue": 0.3, + "type": "float" + }, + "MouseDragSelectionThreshold": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 63, + "description": "Distance in pixels which the mouse must be dragged to trigger a selection box.", + "defaultValue": 4, + "type": "int" + }, + "MouseRelativeModeWarp": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 52, + "defaultValue": 1, + "type": "bool" + }, + "NetworkLossFactor": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 10, + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 2, + "type": "int" + }, + "NetworkTimeout": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 19, + "defaultValue": 120, + "minimumValue": 0, + "type": "int" + }, + "NoHelperAIs": { + "declarationFile": "/spring/rts/System/StartScriptGen.cpp", + "declarationLine": 12, + "defaultValue": 0, + "type": "bool" + }, + "OverheadEnabled": { + "declarationFile": "/spring/rts/Game/Camera/OverheadController.cpp", + "declarationLine": 21, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "OverheadFOV": { + "declarationFile": "/spring/rts/Game/Camera/OverheadController.cpp", + "declarationLine": 22, + "defaultValue": 45, + "type": "float" + }, + "OverheadMaxHeightFactor": { + "declarationFile": "/spring/rts/Game/Camera/OverheadController.cpp", + "declarationLine": 23, + "description": "float multiplier for maximum overhead camera height", + "defaultValue": 1, + "type": "float" + }, + "OverheadScrollSpeed": { + "declarationFile": "/spring/rts/Game/Camera/OverheadController.cpp", + "declarationLine": 19, + "defaultValue": 10, + "type": "int" + }, + "OverheadTiltSpeed": { + "declarationFile": "/spring/rts/Game/Camera/OverheadController.cpp", + "declarationLine": 20, + "defaultValue": 1, + "type": "float" + }, + "PathingThreadCount": { + "declarationFile": "/spring/rts/Sim/Path/QTPFS/PathManager.cpp", + "declarationLine": 38, + "defaultValue": 0, + "minimumValue": 0, + "safemodeValue": 1, + "type": "int" + }, + "PitchAdjust": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 31, + "description": "Adjusts sound pitch proportional to [if set to 1, the square root of] game speed. Set to 2 for linear scaling.", + "defaultValue": 0, + "type": "int" + }, + "PreloadModels": { + "declarationFile": "/spring/rts/Rendering/WorldDrawer.cpp", + "declarationLine": 53, + "description": "The engine will preload all models", + "defaultValue": 1, + "type": "bool" + }, + "ROAM": { + "declarationFile": "/spring/rts/Map/SMF/SMFGroundDrawer.cpp", + "declarationLine": 49, + "description": "Use ROAM for terrain mesh rendering: 0 to disable, 1=VBO mode to enable.", + "defaultValue": 1, + "minimumValue": 0, + "maximumValue": 1, + "type": "int" + }, + "RapidTagResolutionOrder": { + "declarationFile": "/spring/rts/System/FileSystem/RapidHandler.cpp", + "declarationLine": 91, + "description": "';' separated list of domains, preference order for resolving package from rapid tags", + "defaultValue": "", + "type": "std::string" + }, + "ReconnectTimeout": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 23, + "defaultValue": 15, + "minimumValue": 0, + "type": "int" + }, + "RendererHash": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 79, + "deprecated": 1, + "type": "int" + }, + "RotOverheadClampMap": { + "declarationFile": "/spring/rts/Game/Camera/RotOverheadController.cpp", + "declarationLine": 19, + "defaultValue": 1, + "headlessValue": 1, + "type": "bool" + }, + "RotOverheadEnabled": { + "declarationFile": "/spring/rts/Game/Camera/RotOverheadController.cpp", + "declarationLine": 17, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "RotOverheadFOV": { + "declarationFile": "/spring/rts/Game/Camera/RotOverheadController.cpp", + "declarationLine": 18, + "defaultValue": 45, + "type": "float" + }, + "RotOverheadMouseScale": { + "declarationFile": "/spring/rts/Game/Camera/RotOverheadController.cpp", + "declarationLine": 15, + "defaultValue": 0.01, + "type": "float" + }, + "RotOverheadScrollSpeed": { + "declarationFile": "/spring/rts/Game/Camera/RotOverheadController.cpp", + "declarationLine": 16, + "defaultValue": 10, + "type": "int" + }, + "RotateLogFiles": { + "declarationFile": "/spring/rts/System/LogOutput.cpp", + "declarationLine": 29, + "description": "Rotate logfiles, old logfiles will be moved into the subfolder \"log\".", + "defaultValue": 0, + "type": "bool" + }, + "SMFTexAniso": { + "declarationFile": "/spring/rts/Map/SMF/SMFReadMap.cpp", + "declarationLine": 36, + "defaultValue": 4, + "minimumValue": 0, + "type": "float" + }, + "SSMFTexAniso": { + "declarationFile": "/spring/rts/Map/SMF/SMFReadMap.cpp", + "declarationLine": 37, + "defaultValue": 4, + "minimumValue": 0, + "type": "float" + }, + "ScreenshotCounter": { + "declarationFile": "/spring/rts/Rendering/Screenshot.cpp", + "declarationLine": 19, + "defaultValue": 0, + "type": "int" + }, + "ScrollWheelSpeed": { + "declarationFile": "/spring/rts/Game/UI/MouseHandler.cpp", + "declarationLine": 60, + "defaultValue": -25, + "minimumValue": -255, + "maximumValue": 255, + "type": "float" + }, + "ServerLogDebugMessages": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 77, + "defaultValue": 0, + "type": "bool" + }, + "ServerLogInfoMessages": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 76, + "defaultValue": 0, + "type": "bool" + }, + "ServerRecordDemos": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 75, + "defaultValue": 0, + "dedicatedValue": 1, + "type": "bool" + }, + "ServerSleepTime": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 70, + "description": "number of milliseconds to sleep per tick", + "defaultValue": 5, + "type": "int" + }, + "SetCoreAffinity": { + "declarationFile": "/spring/rts/System/SpringApp.cpp", + "declarationLine": 105, + "description": "Defines a bitmask indicating which CPU cores the main-thread should use.", + "defaultValue": "0", + "safemodeValue": "1", + "type": "unsigned" + }, + "ShadowColorMode": { + "declarationFile": "/spring/rts/Rendering/ShadowHandler.cpp", + "declarationLine": 34, + "description": "Whether the colorbuffer of shadowmap FBO is RGB vs greyscale(to conserve some VRAM)", + "defaultValue": 1, + "type": "bool" + }, + "ShadowMapSize": { + "declarationFile": "/spring/rts/Rendering/ShadowHandler.cpp", + "declarationLine": 32, + "description": "Sets the resolution of shadows. Higher numbers increase quality at the cost of performance.", + "defaultValue": 2048, + "minimumValue": 32, + "type": "int" + }, + "ShadowProjectionMode": { + "declarationFile": "/spring/rts/Rendering/ShadowHandler.cpp", + "declarationLine": 33, + "defaultValue": 1, + "type": "int" + }, + "Shadows": { + "declarationFile": "/spring/rts/Rendering/ShadowHandler.cpp", + "declarationLine": 31, + "description": "Sets whether shadows are rendered.\n-1:=forceoff, 0:=off, 1:=full, 2:=fast (skip terrain)", + "defaultValue": 2, + "minimumValue": -1, + "safemodeValue": -1, + "headlessValue": -1, + "type": "int" + }, + "ShowClock": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 139, + "description": "Displays a clock on the top-right corner of the screen showing the elapsed time of the current game.", + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "ShowFPS": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 138, + "description": "Displays current framerate.", + "defaultValue": 0, + "type": "bool" + }, + "ShowPlayerInfo": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 141, + "defaultValue": 1, + "headlessValue": 0, + "type": "int" + }, + "ShowSpeed": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 140, + "description": "Displays current game speed.", + "defaultValue": 0, + "type": "bool" + }, + "SimpleMiniMapColors": { + "declarationFile": "/spring/rts/Game/UI/MiniMap.cpp", + "declarationLine": 66, + "defaultValue": 0, + "type": "bool" + }, + "SmallFontFile": { + "declarationFile": "/spring/rts/Rendering/Fonts/glFont.cpp", + "declarationLine": 23, + "description": "Sets the font of Spring engine small text.", + "defaultValue": "fonts/FreeSansBold.otf", + "type": "std::string" + }, + "SmallFontOutlineWeight": { + "declarationFile": "/spring/rts/Rendering/Fonts/glFont.cpp", + "declarationLine": 30, + "description": "see FontOutlineWeight", + "defaultValue": 10, + "type": "float" + }, + "SmallFontOutlineWidth": { + "declarationFile": "/spring/rts/Rendering/Fonts/glFont.cpp", + "declarationLine": 28, + "description": "see FontOutlineWidth", + "defaultValue": 2, + "type": "int" + }, + "SmallFontSize": { + "declarationFile": "/spring/rts/Rendering/Fonts/glFont.cpp", + "declarationLine": 26, + "description": "Sets the font size (in pixels) of the engine GUIs and more.", + "defaultValue": 14, + "type": "int" + }, + "SmoothTimeOffset": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 145, + "description": "Enables frametimeoffset smoothing, 0 = off (old version), -1 = forced 0.5, 1-20 smooth, recommended = 2-3", + "defaultValue": 0, + "headlessValue": 0, + "type": "int" + }, + "SoftParticles": { + "declarationFile": "/spring/rts/Rendering/Env/Particles/ProjectileDrawer.cpp", + "declarationLine": 44, + "description": "Soften up CEG particles on clipping edges", + "defaultValue": 1, + "safemodeValue": 0, + "type": "int" + }, + "Sound": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 24, + "description": "Enables (OpenAL) or disables sound.", + "defaultValue": 1, + "type": "bool" + }, + "SourcePort": { + "declarationFile": "/spring/rts/Net/Protocol/NetProtocol.cpp", + "declarationLine": 21, + "defaultValue": 0, + "type": "int" + }, + "SpeedControl": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 71, + "description": "Sets how server adjusts speed according to player's load (CPU), 1: use average, 2: use highest", + "defaultValue": 1, + "minimumValue": 1, + "maximumValue": 2, + "type": "int" + }, + "SplashScreenDir": { + "declarationFile": "/spring/rts/System/SpringApp.cpp", + "declarationLine": 113, + "defaultValue": ".", + "type": "std::string" + }, + "SpringData": { + "declarationFile": "/spring/rts/System/FileSystem/DataDirLocater.cpp", + "declarationLine": 34, + "description": "List of additional data-directories, separated by ';' on Windows and ':' on other OSs", + "readOnly": 1, + "defaultValue": "", + "type": "std::string" + }, + "SpringDataRoot": { + "declarationFile": "/spring/rts/System/FileSystem/DataDirLocater.cpp", + "declarationLine": 39, + "description": "Optional custom data-directory content root ('base', 'maps', ...) to scan for archives", + "readOnly": 1, + "defaultValue": "", + "type": "std::string" + }, + "TCPAllowConnect": { + "declarationFile": "/spring/rts/lib/luasocket/src/restrictions.cpp", + "declarationLine": 24, + "readOnly": 1, + "defaultValue": "*", + "type": "std::string" + }, + "TCPAllowListen": { + "declarationFile": "/spring/rts/lib/luasocket/src/restrictions.cpp", + "declarationLine": 25, + "readOnly": 1, + "defaultValue": "*", + "type": "std::string" + }, + "TeamHighlight": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 53, + "defaultValue": 1, + "minimumValue": 0, + "maximumValue": 2, + "type": "int" + }, + "TeamNanoSpray": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 63, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "TextureMemPoolSize": { + "declarationFile": "/spring/rts/System/SpringApp.cpp", + "declarationLine": 106, + "description": "Set to 0 to disable, otherwise specify a predefined memory to serve Bitmap allocation requests", + "defaultValue": "512", + "minimumValue": "0", + "type": "unsigned" + }, + "TooltipGeometry": { + "declarationFile": "/spring/rts/Game/UI/TooltipConsole.cpp", + "declarationLine": 28, + "defaultValue": "0.0 0.0 0.41 0.1", + "type": "std::string" + }, + "TooltipOutlineFont": { + "declarationFile": "/spring/rts/Game/UI/TooltipConsole.cpp", + "declarationLine": 29, + "defaultValue": 1, + "headlessValue": 0, + "type": "bool" + }, + "UDPAllowConnect": { + "declarationFile": "/spring/rts/lib/luasocket/src/restrictions.cpp", + "declarationLine": 26, + "readOnly": 1, + "defaultValue": "", + "type": "std::string" + }, + "UDPAllowListen": { + "declarationFile": "/spring/rts/lib/luasocket/src/restrictions.cpp", + "declarationLine": 27, + "readOnly": 1, + "defaultValue": "*", + "type": "std::string" + }, + "UDPConnectionLogDebugMessages": { + "declarationFile": "/spring/rts/System/Net/UDPConnection.cpp", + "declarationLine": 20, + "defaultValue": 0, + "type": "bool" + }, + "UnitIconDist": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 55, + "defaultValue": 200, + "headlessValue": 0, + "type": "int" + }, + "UnitIconFadeStart": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 57, + "defaultValue": 3000, + "minimumValue": 1, + "maximumValue": 10000, + "type": "float" + }, + "UnitIconFadeVanish": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 58, + "defaultValue": 1000, + "minimumValue": 1, + "maximumValue": 10000, + "type": "float" + }, + "UnitIconScaleUI": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 56, + "defaultValue": 1, + "minimumValue": 0.1, + "maximumValue": 10, + "type": "float" + }, + "UnitIconsAsUI": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 60, + "description": "Draw unit icons like it is an UI element and not like unit's LOD.", + "defaultValue": 0, + "type": "bool" + }, + "UnitIconsHideWithUI": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 61, + "description": "Hide unit icons when UI is hidden.", + "defaultValue": 0, + "type": "bool" + }, + "UnitLodDist": { + "declarationFile": "/spring/rts/Rendering/Common/ModelDrawerData.cpp", + "declarationLine": 3, + "deprecated": 1, + "defaultValue": 1000, + "headlessValue": 0, + "type": "int" + }, + "UnitTransparency": { + "declarationFile": "/spring/rts/Rendering/Units/UnitDrawer.cpp", + "declarationLine": 59, + "defaultValue": 0.7, + "type": "float" + }, + "UseDistToGroundForIcons": { + "declarationFile": "/spring/rts/Game/Camera/CameraController.cpp", + "declarationLine": 11, + "defaultValue": 0.95, + "type": "float" + }, + "UseEFX": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 26, + "defaultValue": 1, + "safemodeValue": 0, + "type": "bool" + }, + "UseFontConfigLib": { + "declarationFile": "/spring/rts/System/SpringApp.cpp", + "declarationLine": 109, + "description": "Whether the system fontconfig library (if present and enabled at compile-time) should be used for handling fonts.", + "defaultValue": 1, + "type": "bool" + }, + "UseHighResTimer": { + "declarationFile": "/spring/rts/System/SpringApp.cpp", + "declarationLine": 108, + "description": "On Windows, sets whether Spring will use low- or high-resolution timer functions for tasks like graphical interpolation between game frames.", + "defaultValue": 0, + "type": "bool" + }, + "UseLuaMemPools": { + "declarationFile": "/spring/rts/System/SpringApp.cpp", + "declarationLine": 107, + "description": "Whether Lua VM memory allocations are made from pools.", + "defaultValue": 1, + "type": "bool" + }, + "UseNetMessageSmoothingBuffer": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 58, + "defaultValue": 1, + "type": "bool" + }, + "UsePBO": { + "declarationFile": "/spring/rts/Rendering/GL/VBO.cpp", + "declarationLine": 21, + "defaultValue": 1, + "safemodeValue": 0, + "headlessValue": 0, + "type": "bool" + }, + "UseSDLAudio": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 27, + "description": "If enabled, OpenAL-soft only renders audio into a SDL buffer and playback is done by the SDL audio layer, i.e. SDL handles the hardware", + "defaultValue": 1, + "safemodeValue": 0, + "headlessValue": 0, + "type": "bool" + }, + "UseShaderCache": { + "declarationFile": "/spring/rts/Rendering/Shaders/Shader.cpp", + "declarationLine": 37, + "description": "If already compiled shaders should be shared via a cache, reducing compiles of already compiled shaders.", + "defaultValue": 1, + "type": "bool" + }, + "UseVBO": { + "declarationFile": "/spring/rts/Rendering/GL/VBO.cpp", + "declarationLine": 20, + "deprecated": 1, + "type": "bool" + }, + "VFSCacheArchiveFiles": { + "declarationFile": "/spring/rts/System/GlobalConfig.cpp", + "declarationLine": 61, + "defaultValue": 1, + "type": "bool" + }, + "VSync": { + "declarationFile": "/spring/rts/Rendering/VerticalSync.cpp", + "declarationLine": 19, + "description": "Synchronize buffer swaps with vertical blanking interval. Modes are -N (adaptive), +N (standard), or 0 (disabled).", + "defaultValue": -1, + "minimumValue": -6, + "maximumValue": 6, + "type": "int" + }, + "Water": { + "declarationFile": "/spring/rts/Rendering/Env/IWater.cpp", + "declarationLine": 24, + "description": "Defines the type of water rendering. Can be set in game. Options are: 0 = Basic water, 1 = Reflective water, 2 = Reflective and Refractive water, 3 = Dynamic water, 4 = Bumpmapped water", + "defaultValue": 1, + "minimumValue": 0, + "maximumValue": 4, + "safemodeValue": 0, + "headlessValue": 0, + "type": "int" + }, + "WhiteListAdditionalPlayers": { + "declarationFile": "/spring/rts/Net/GameServer.cpp", + "declarationLine": 74, + "defaultValue": 1, + "type": "bool" + }, + "WindowBorderless": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 68, + "description": "When set and Fullscreen is 0, will put the game in Borderless Window mode, also known as Windowed Fullscreen. When using this, it is generally best to also set WindowPosX and WindowPosY to 0", + "defaultValue": 0, + "type": "bool" + }, + "WindowPosX": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 75, + "description": "Sets the horizontal position of the game window, if Fullscreen is 0. When WindowBorderless is set, this should usually be 0.", + "defaultValue": 0, + "type": "int" + }, + "WindowPosY": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 76, + "description": "Sets the vertical position of the game window, if Fullscreen is 0. When WindowBorderless is set, this should usually be 0.", + "defaultValue": 32, + "type": "int" + }, + "WindowedEdgeMove": { + "declarationFile": "/spring/rts/Game/Game.cpp", + "declarationLine": 135, + "description": "Sets whether moving the mouse cursor to the screen edge will move the camera across the map.", + "defaultValue": 1, + "type": "bool" + }, + "WorkerThreadCount": { + "declarationFile": "/spring/rts/System/Threading/ThreadPool.cpp", + "declarationLine": 43, + "description": "Number of workers (including the main thread!) used by ThreadPool.", + "defaultValue": -1, + "minimumValue": -1, + "safemodeValue": 0, + "type": "int" + }, + "XResolution": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 71, + "description": "Sets the width of the game screen. If set to 0 Spring will autodetect the current resolution of your desktop.", + "defaultValue": 0, + "minimumValue": 0, + "headlessValue": 8, + "type": "int" + }, + "XResolutionWindowed": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 73, + "description": "See XResolution, just for windowed.", + "defaultValue": 0, + "minimumValue": 0, + "headlessValue": 8, + "type": "int" + }, + "YResolution": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 72, + "description": "Sets the height of the game screen. If set to 0 Spring will autodetect the current resolution of your desktop.", + "defaultValue": 0, + "minimumValue": 0, + "headlessValue": 8, + "type": "int" + }, + "YResolutionWindowed": { + "declarationFile": "/spring/rts/Rendering/GlobalRendering.cpp", + "declarationLine": 74, + "description": "See YResolution, just for windowed.", + "defaultValue": 0, + "minimumValue": 0, + "headlessValue": 8, + "type": "int" + }, + "address": { + "declarationFile": "/spring/rts/Menu/SelectMenu.cpp", + "declarationLine": 45, + "description": "Last Ip/hostname used as direct connect in the menu.", + "defaultValue": "", + "type": "std::string" + }, + "name": { + "declarationFile": "/spring/rts/System/SpringApp.cpp", + "declarationLine": 111, + "description": "Sets your name in the game. Since this is overridden by lobbies with your lobby username when playing, it usually only comes up when viewing replays or starting the engine directly for testing purposes.", + "defaultValue": "UnnamedPlayer", + "type": "std::string" + }, + "snd_airAbsorption": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 39, + "defaultValue": 0.1, + "type": "float" + }, + "snd_device": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 41, + "description": "Sets the used output device. See \"Available Devices\" section in infolog.txt.", + "defaultValue": "", + "type": "std::string" + }, + "snd_volbattle": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 36, + "description": "Volume for \"battle\" sound channel.", + "defaultValue": 100, + "minimumValue": 0, + "maximumValue": 200, + "type": "int" + }, + "snd_volgeneral": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 34, + "description": "Volume for \"general\" sound channel.", + "defaultValue": 100, + "minimumValue": 0, + "maximumValue": 200, + "type": "int" + }, + "snd_volmaster": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 33, + "description": "Master sound volume.", + "defaultValue": 60, + "minimumValue": 0, + "maximumValue": 200, + "type": "int" + }, + "snd_volmusic": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 38, + "description": "Volume for \"music\" sound channel.", + "defaultValue": 100, + "minimumValue": 0, + "maximumValue": 200, + "type": "int" + }, + "snd_volui": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 37, + "description": "Volume for \"ui\" sound channel.", + "defaultValue": 100, + "minimumValue": 0, + "maximumValue": 200, + "type": "int" + }, + "snd_volunitreply": { + "declarationFile": "/spring/rts/System/Sound/ISound.cpp", + "declarationLine": 35, + "description": "Volume for \"unit reply\" sound channel.", + "defaultValue": 100, + "minimumValue": 0, + "maximumValue": 200, + "type": "int" + } +} diff --git a/_data/glossary.yml b/_data/glossary.yml new file mode 100644 index 0000000000..3ca222a6ad --- /dev/null +++ b/_data/glossary.yml @@ -0,0 +1,38 @@ +- term: Allyteam + definition: > + What most people would naturally call a team is called an “allyteam” in + Recoil terminology. + url: > + {% link articles/team-terminology.markdown %}#allyteam-vs-team +- term: Team + definition: A team is generally controlled by a player or an AI. + url: > + {% link articles/team-terminology.markdown %}#team-vs-player +- term: Spectator + definition: Spectators are players not controlling any team. + url: > + {% link articles/team-terminology.markdown %}#regular-player-vs-spectator +- term: AI + definition: > + An AI fulfils a similar role to a player, being there to control a team. + url: > + {% link articles/team-terminology.markdown %}#player-vs-ai +- term: Lua AI + definition: > + A Lua AI generally has two components: a piece of game mechanics, and the + AI instance itself which is just a handle to tell game mechanics which teams + are legal to control. + url: > + {% link articles/team-terminology.markdown %}#lua-ai-vs-skirmish-ai +- term: Skirmish AI + definition: > + A “skirmish” AI is hosted by one of the players and generally acts very + similar to a player. + url: > + {% link articles/team-terminology.markdown %}#lua-ai-vs-skirmish-ai +- term: Gaia + definition: > + Gaia is a special team that is always present, uncontrolled, and is always + in its own allyteam. + url: > + {% link articles/team-terminology.markdown %}#gaia diff --git a/_data/latest_release.json b/_data/latest_release.json new file mode 100644 index 0000000000..53209deac8 --- /dev/null +++ b/_data/latest_release.json @@ -0,0 +1,244 @@ +{ + "url": "https://api.github.com/repos/beyond-all-reason/spring/releases/92924750", + "assets_url": "https://api.github.com/repos/beyond-all-reason/spring/releases/92924750/assets", + "upload_url": "https://uploads.github.com/repos/beyond-all-reason/spring/releases/92924750/assets{?name,label}", + "html_url": "https://github.com/beyond-all-reason/spring/releases/tag/spring_bar_%7BBAR105%7D105.1.1-1544-g058c8ea", + "id": 92924750, + "author": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "site_admin": false + }, + "node_id": "RE_kwDOEgT4Wc4FietO", + "tag_name": "spring_bar_{BAR105}105.1.1-1544-g058c8ea", + "target_commitish": "BAR105", + "name": "spring_bar_{BAR105}105.1.1-1544-g058c8ea", + "draft": false, + "prerelease": false, + "created_at": "2023-02-18T18:40:26Z", + "published_at": "2023-02-18T20:36:43Z", + "assets": [ + { + "url": "https://api.github.com/repos/beyond-all-reason/spring/releases/assets/96209637", + "id": 96209637, + "node_id": "RA_kwDOEgT4Wc4FvArl", + "name": "buildoptions_linux-64.txt", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "site_admin": false + }, + "content_type": "binary/octet-stream", + "state": "uploaded", + "size": 662, + "download_count": 3, + "created_at": "2023-02-18T20:36:44Z", + "updated_at": "2023-02-18T20:36:44Z", + "browser_download_url": "https://github.com/beyond-all-reason/spring/releases/download/spring_bar_%7BBAR105%7D105.1.1-1544-g058c8ea/buildoptions_linux-64.txt" + }, + { + "url": "https://api.github.com/repos/beyond-all-reason/spring/releases/assets/96209638", + "id": 96209638, + "node_id": "RA_kwDOEgT4Wc4FvArm", + "name": "buildoptions_windows-64.txt", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "site_admin": false + }, + "content_type": "binary/octet-stream", + "state": "uploaded", + "size": 551, + "download_count": 3, + "created_at": "2023-02-18T20:36:44Z", + "updated_at": "2023-02-18T20:36:45Z", + "browser_download_url": "https://github.com/beyond-all-reason/spring/releases/download/spring_bar_%7BBAR105%7D105.1.1-1544-g058c8ea/buildoptions_windows-64.txt" + }, + { + "url": "https://api.github.com/repos/beyond-all-reason/spring/releases/assets/96209640", + "id": 96209640, + "node_id": "RA_kwDOEgT4Wc4FvAro", + "name": "spring_bar_.BAR105.105.1.1-1544-g058c8ea_linux-64-minimal-portable.7z", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "site_admin": false + }, + "content_type": "binary/octet-stream", + "state": "uploaded", + "size": 16976427, + "download_count": 830, + "created_at": "2023-02-18T20:36:45Z", + "updated_at": "2023-02-18T20:36:46Z", + "browser_download_url": "https://github.com/beyond-all-reason/spring/releases/download/spring_bar_%7BBAR105%7D105.1.1-1544-g058c8ea/spring_bar_.BAR105.105.1.1-1544-g058c8ea_linux-64-minimal-portable.7z" + }, + { + "url": "https://api.github.com/repos/beyond-all-reason/spring/releases/assets/96209642", + "id": 96209642, + "node_id": "RA_kwDOEgT4Wc4FvArq", + "name": "spring_bar_.BAR105.105.1.1-1544-g058c8ea_linux-64-minimal-symbols.tgz", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "site_admin": false + }, + "content_type": "binary/octet-stream", + "state": "uploaded", + "size": 407813530, + "download_count": 3, + "created_at": "2023-02-18T20:36:46Z", + "updated_at": "2023-02-18T20:36:54Z", + "browser_download_url": "https://github.com/beyond-all-reason/spring/releases/download/spring_bar_%7BBAR105%7D105.1.1-1544-g058c8ea/spring_bar_.BAR105.105.1.1-1544-g058c8ea_linux-64-minimal-symbols.tgz" + }, + { + "url": "https://api.github.com/repos/beyond-all-reason/spring/releases/assets/96209648", + "id": 96209648, + "node_id": "RA_kwDOEgT4Wc4FvArw", + "name": "spring_bar_.BAR105.105.1.1-1544-g058c8ea_windows-64-minimal-portable.7z", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "site_admin": false + }, + "content_type": "binary/octet-stream", + "state": "uploaded", + "size": 16499276, + "download_count": 6563, + "created_at": "2023-02-18T20:36:54Z", + "updated_at": "2023-02-18T20:36:55Z", + "browser_download_url": "https://github.com/beyond-all-reason/spring/releases/download/spring_bar_%7BBAR105%7D105.1.1-1544-g058c8ea/spring_bar_.BAR105.105.1.1-1544-g058c8ea_windows-64-minimal-portable.7z" + }, + { + "url": "https://api.github.com/repos/beyond-all-reason/spring/releases/assets/96209651", + "id": 96209651, + "node_id": "RA_kwDOEgT4Wc4FvArz", + "name": "spring_bar_.BAR105.105.1.1-1544-g058c8ea_windows-64-minimal-symbols.tgz", + "label": "", + "uploader": { + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", + "site_admin": false + }, + "content_type": "binary/octet-stream", + "state": "uploaded", + "size": 435054551, + "download_count": 2, + "created_at": "2023-02-18T20:36:55Z", + "updated_at": "2023-02-18T20:37:04Z", + "browser_download_url": "https://github.com/beyond-all-reason/spring/releases/download/spring_bar_%7BBAR105%7D105.1.1-1544-g058c8ea/spring_bar_.BAR105.105.1.1-1544-g058c8ea_windows-64-minimal-symbols.tgz" + } + ], + "tarball_url": "https://api.github.com/repos/beyond-all-reason/spring/tarball/spring_bar_{BAR105}105.1.1-1544-g058c8ea", + "zipball_url": "https://api.github.com/repos/beyond-all-reason/spring/zipball/spring_bar_{BAR105}105.1.1-1544-g058c8ea", + "body": "Github Action Upload" +} diff --git a/_data/non_coder_contributors.yml b/_data/non_coder_contributors.yml new file mode 100644 index 0000000000..7ce1157c10 --- /dev/null +++ b/_data/non_coder_contributors.yml @@ -0,0 +1,3 @@ +- login: 6AKU66 + html_url: https://github.com/6AKU66 + avatar_url: https://avatars.githubusercontent.com/u/89547444?v=4 diff --git a/_data/synced_commands.json b/_data/synced_commands.json new file mode 100644 index 0000000000..7bb678e76e --- /dev/null +++ b/_data/synced_commands.json @@ -0,0 +1,116 @@ +{ + "atm" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Atm", + "description" : "Gives 1000 metal and 1000 energy to the issuing player's team" + }, + "cheat" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Cheat", + "description" : "Enables/Disables cheating, which is required for a lot of other commands to be usable" + }, + "destroy" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Destroy", + "description" : "Destroys one or multiple units by unit-ID, instantly" + }, + "desync" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Desync", + "description" : "Allows creating an artificial desync of the local client with the rest of the participating hosts" + }, + "devlua" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "DevLua", + "description" : "Enables/Disables Lua dev-mode (can cause desyncs if enabled)" + }, + "editdefs" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "EditDefs", + "description" : "Allows/Disallows editing of unit-, feature- and weapon-defs through Lua" + }, + "give" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Give", + "description" : "Places one or multiple units of a single or multiple types on the map, instantly; by default belonging to your own team" + }, + "globallos" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "GlobalLOS", + "description" : "Enables/Disables global line-of-sight, which makes the whole map permanently visible to everyone or to a specific allyteam" + }, + "godmode" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "GodMode", + "description" : "Enables/Disables god-mode, which allows all players (even spectators) to control all units (even during replays, which will DESYNC them)" + }, + "luagaia" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LuaGaia", + "description" : "Allows reloading or disabling LuaGaia, and to send a chat message to LuaGaia scripts" + }, + "luarules" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LuaRules", + "description" : "Allows reloading or disabling LuaRules, and to send a chat message to LuaRules scripts" + }, + "nocost" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "NoCost", + "description" : "Enables/Disables everything-for-free, which allows everyone to build everything for zero resource costs" + }, + "nohelp" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "NoHelp", + "description" : "Enables/Disables widgets (LuaUI control)" + }, + "nospecdraw" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "NoSpecDraw", + "description" : "Allows/Disallows spectators to draw on the map" + }, + "nospectatorchat" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "NoSpectatorChat", + "description" : "Enables/Disables spectators to use the chat" + }, + "reloadcegs" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "ReloadCEGs", + "description" : "Reloads CEG scripts" + }, + "reloadcob" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "ReloadCOB", + "description" : "Reloads COB scripts" + }, + "skip" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Skip", + "description" : "Fast-forwards to a given frame, or stops fast-forwarding" + }, + "take" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Take", + "description" : "Transfers all units of allied teams without any active players to the team of the issuing player" + } +} diff --git a/_data/unsynced_commands.json b/_data/unsynced_commands.json new file mode 100644 index 0000000000..ae59b8b3ed --- /dev/null +++ b/_data/unsynced_commands.json @@ -0,0 +1,1164 @@ +{ + "advmapshading" : { + "arguments" : { + "" : "Toggles advanced map shading mode", + "" : "Set advanced map shading mode " + }, + "cheatRequired" : false, + "command" : "AdvMapShading", + "description" : "Control advanced map shading mode" + }, + "advmodelshading" : { + "arguments" : { + "" : "Toggles advanced model shading mode", + "" : "Set advanced model shading mode " + }, + "cheatRequired" : false, + "command" : "AdvModelShading", + "description" : "Control advanced model shading mode" + }, + "aicontrol" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "AIControl", + "description" : "Creates a new instance of a Skirmish AI, to let it control a specific team" + }, + "aikill" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "AIKill", + "description" : "Kills the Skirmish AI controlling a specified team" + }, + "ailist" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "AIList", + "description" : "Prints a list of all currently active Skirmish AIs" + }, + "aireload" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "AIReload", + "description" : "Reloads the Skirmish AI controlling a specified team" + }, + "airmesh" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "airmesh", + "description" : "Show/Hide the smooth air-mesh map overlay" + }, + "allmapmarks" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "AllMapMarks", + "description" : "Show/Hide all map marks drawn so far" + }, + "ally" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Ally", + "description" : "Starts/Ends alliance of the local player's ally-team with another ally-team" + }, + "atm" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ATM", + "description" : "Redirects command /ATM to its synced processor" + }, + "buffertext" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "BufferText", + "description" : "Write the argument string(s) directly to the console history" + }, + "chat" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Chat", + "description" : "Starts waiting for intput to be sent to " + }, + "chatall" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ChatAll", + "description" : "Starts waiting for intput to be sent to All" + }, + "chatally" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ChatAlly", + "description" : "Starts waiting for intput to be sent to Ally" + }, + "chatspec" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ChatSpec", + "description" : "Starts waiting for intput to be sent to Spec" + }, + "clearmapmarks" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ClearMapMarks", + "description" : "Remove all map marks drawn so far" + }, + "clock" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Clock", + "description" : "Shows a small digital clock indicating the local time" + }, + "cmdcolors" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "CmdColors", + "description" : "Reloads cmdcolors.txt" + }, + "commandhelp" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "CommandHelp", + "description" : "Prints info about a specific chat command" + }, + "commandlist" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "CommandList", + "description" : "Prints all the available chat commands with description (if available) to the console" + }, + "console" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Console", + "description" : "Enables/Disables the in-game console" + }, + "controlunit" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ControlUnit", + "description" : "Start to first-person-control a unit" + }, + "crash" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Crash", + "description" : "Invoke an artificial crash through a NULL-pointer dereference (SIGSEGV)" + }, + "createvideo" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "CreateVideo", + "description" : "Start/Stop capturing a video of the game in progress" + }, + "cross" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Cross", + "description" : "Allows one to exchange and modify the appearance of the cross/mouse-pointer in first-person-control view" + }, + "ctrlpanel" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "CtrlPanel", + "description" : "Reloads GUI config" + }, + "debug" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Debug", + "description" : "Enable/Disable debug rendering mode" + }, + "debugcolvol" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DebugColVol", + "description" : "Enable/Disable drawing of collision volumes" + }, + "debugcubemap" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DebugCubeMap", + "description" : "Use debug cubemap texture instead of the sky" + }, + "debugdrawai" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DebugDrawAI", + "description" : "Enables/Disables debug drawing for AIs" + }, + "debuggl" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DebugGL", + "description" : "Enable/Disable OpenGL debug-context output" + }, + "debugglerrors" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DebugGLErrors", + "description" : "Enable/Disable OpenGL debug-errors" + }, + "debuginfo" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DebugInfo", + "description" : "Print debug info to the chat/log-file about either sound, profiling, or command-descriptions" + }, + "debugpath" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DebugPath", + "description" : "Enable/Disable drawing of pathfinder debug-data" + }, + "debugtraceray" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DebugTraceRay", + "description" : "Enable/Disable drawing of traceray debug-data" + }, + "decguiopacity" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DecGUIOpacity", + "description" : "Decreases the the opacity(see-through-ness) of GUI elements" + }, + "decreaseviewradius" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DecreaseViewRadius", + "description" : "Decrease the view radius (higher performance, uglier view)" + }, + "deselect" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Deselect", + "description" : "Deselects all currently selected units" + }, + "destroy" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Destroy", + "description" : "Destroys one or multiple units by unit-ID, instantly" + }, + "desync" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Desync", + "description" : "Redirects command /Desync to its synced processor" + }, + "disticon" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DistIcon", + "description" : "Set the distance between units and camera, at which they turn into icons (Graphic setting)" + }, + "distsortprojectiles" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DistSortProjectiles", + "description" : "Enable/Disable sorting drawn projectiles by camera distance" + }, + "divbyzero" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "DivByZero", + "description" : "Invoke an artificial crash by performing a division-by-zero" + }, + "drawinmap" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DrawInMap", + "description" : "Enables drawing on the map" + }, + "drawlabel" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DrawLabel", + "description" : "Draws a label on the map at the current mouse-pointer position" + }, + "draworderparticles" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DrawOrderParticles", + "description" : "Enable/Disable particles draw order: 0=disabled, 1=enabled" + }, + "drawsky" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DrawSky", + "description" : "Whether to actually draw sky" + }, + "dumpatlas" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DumpAtlas", + "description" : "Save Some Atlases" + }, + "dumprng" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DumpRNG", + "description" : "dump SyncedRNG-state to file" + }, + "dumpshadows" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DumpShadows", + "description" : "Save shadow map textures to files" + }, + "dumpstate" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "DumpState", + "description" : "dump game-state to file" + }, + "echo" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Echo", + "description" : "Write a string to the log file" + }, + "endgraph" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "EndGraph", + "description" : "Enables/Disables the statistics graphs shown at the end of the game" + }, + "exception" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Exception", + "description" : "Invoke an artificial crash by throwing an std::runtime_error" + }, + "featuredrawdistance" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "FeatureDrawDistance", + "description" : "" + }, + "featuredrawer" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "FeatureDrawer", + "description" : "Forces particular Feature drawer type" + }, + "featurefadedistance" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "FeatureFadeDistance", + "description" : "" + }, + "font" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Font", + "description" : "Reloads default or custom fonts" + }, + "fps" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "FPS", + "description" : "Shows/Hides the frames-per-second indicator" + }, + "fpshud" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "FPSHud", + "description" : "Enables/Disables HUD (GUI interface) shown in first-person-control mode" + }, + "fullscreen" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Fullscreen", + "description" : "Switches fullscreen mode" + }, + "gameinfo" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "GameInfo", + "description" : "Enables/Disables game-info panel rendering" + }, + "gathermode" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "GatherMode", + "description" : "Enter/Leave gather-wait command mode" + }, + "give" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Give", + "description" : "Places one or multiple units of a single or multiple types on the map, instantly; by default to your own team" + }, + "grabinput" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "GrabInput", + "description" : "Prevents/Enables the mouse from leaving the game window (windowed mode only)" + }, + "grounddecals" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "GroundDecals", + "description" : "Enable/Disable ground-decal rendering." + }, + "grounddetail" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "GroundDetail", + "description" : "Set the level of ground detail" + }, + "group" : { + "arguments" : { + "" : "Select group ", + "add " : "Add current selected units to group ", + "selectadd " : "Add members from group to currently selected units", + "selectclear " : "Remove members from group from currently selected units", + "selecttoggle " : "Toggle members from group from currently selected units", + "set " : "Set current selected units as group ", + "unset" : "Deassign control group for currently selected units" + }, + "cheatRequired" : false, + "command" : "Group", + "description" : "Manage control groups" + }, + "group0" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group0", + "description" : "Allows modifying the members of group 0" + }, + "group1" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group1", + "description" : "Allows modifying the members of group 1" + }, + "group2" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group2", + "description" : "Allows modifying the members of group 2" + }, + "group3" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group3", + "description" : "Allows modifying the members of group 3" + }, + "group4" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group4", + "description" : "Allows modifying the members of group 4" + }, + "group5" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group5", + "description" : "Allows modifying the members of group 5" + }, + "group6" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group6", + "description" : "Allows modifying the members of group 6" + }, + "group7" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group7", + "description" : "Allows modifying the members of group 7" + }, + "group8" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group8", + "description" : "Allows modifying the members of group 8" + }, + "group9" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Group9", + "description" : "Allows modifying the members of group 9" + }, + "hang" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Hang", + "description" : "Invoke an artificial hang" + }, + "hardwarecursor" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "HardwareCursor", + "description" : "Enables/Disables hardware mouse-cursor support" + }, + "hideinterface" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "HideInterface", + "description" : "Hide/Show the GUI controlls" + }, + "iconfadestart" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "IconFadeStart", + "description" : "Set the distance where unit icons became completely opaque at" + }, + "iconfadevanish" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "IconFadeVanish", + "description" : "Set the distance where unit icons fade out at" + }, + "iconsasui" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "IconsAsUI", + "description" : "Set whether unit icons are drawn as an UI element (true) or old LOD-like style (false, default)." + }, + "iconscaleui" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "IconScaleUI", + "description" : "Set the multiplier for the size of the UI unit icons" + }, + "iconshidewithui" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "IconsHideWithUI", + "description" : "Set whether unit icons are hidden when UI is hidden." + }, + "incguiopacity" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "IncGUIOpacity", + "description" : "Increases the the opacity(see-through-ness) of GUI elements" + }, + "increaseviewradius" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "IncreaseViewRadius", + "description" : "Increase terrain tessellation level" + }, + "info" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Info", + "description" : "Shows/Hides the player roster" + }, + "inputtextgeo" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "InputTextGeo", + "description" : "Move and/or resize the input-text field (the \"Say: \" thing)" + }, + "lastmsgpos" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LastMsgPos", + "description" : "Moves the camera to show the position of the last message" + }, + "lodscale" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LODScale", + "description" : "Set the scale for either of: LOD (level-of-detail), shadow-LOD, reflection-LOD, refraction-LOD" + }, + "luagaia" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LuaGaia", + "description" : "Redirects command /LuaGaia to its synced processor" + }, + "luagccontrol" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LuaGCControl", + "description" : "Toggle between 1/f and 30/s Lua garbage collection rate" + }, + "luamenu" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LuaMenu", + "description" : "Allows one to reload or disable LuaMenu, or alternatively to send a chat message to LuaMenu" + }, + "luarules" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LuaRules", + "description" : "Redirects command /LuaRules to its synced processor" + }, + "luasave" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LuaSave", + "description" : "Save the game state to a specific file, add -y to overwrite when file is already present" + }, + "luaui" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "LuaUI", + "description" : "Allows one to reload or disable LuaUI, or alternatively to send a chat message to LuaUI" + }, + "mapborder" : { + "arguments" : { + "" : "Toggles map-border rendering", + "" : "Set map-border rendering " + }, + "cheatRequired" : false, + "command" : "MapBorder", + "description" : "Control map-border rendering" + }, + "mapmarks" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MapMarks", + "description" : "Enables/Disables map marks rendering" + }, + "mapmeshdrawer" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "mapmeshdrawer", + "description" : "Switch map-mesh rendering modes: 0=GCM, 1=HLOD, 2=ROAM" + }, + "mapshadowpolyoffset" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MapShadowPolyOffset", + "description" : "" + }, + "maxnanoparticles" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MaxNanoParticles", + "description" : "Set the maximum number of nano-particles (Graphic setting)" + }, + "maxparticles" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MaxParticles", + "description" : "Set the maximum number of particles (Graphics setting)" + }, + "maxviewrange" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MaxViewRange", + "description" : "Set maximum view-distance" + }, + "minimap" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MiniMap", + "description" : "FIXME document subcommands" + }, + "minviewrange" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MinViewRange", + "description" : "Set minimum view-distance" + }, + "mouse1" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Mouse1", + "description" : "Simulates a press of mouse-button 1" + }, + "mouse2" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Mouse2", + "description" : "Simulates a press of mouse-button 2" + }, + "mouse3" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Mouse3", + "description" : "Simulates a press of mouse-button 3" + }, + "mouse4" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Mouse4", + "description" : "Simulates a press of mouse-button 4" + }, + "mouse5" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Mouse5", + "description" : "Simulates a press of mouse-button 5" + }, + "mousecancelselectionrectangle" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MouseCancelSelectionRectangle", + "description" : "" + }, + "moveback" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveBack", + "description" : "Moves the camera Back a bit" + }, + "movedown" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveDown", + "description" : "Moves the camera Down a bit" + }, + "movefast" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveFast", + "description" : "Moves the camera Fast a bit" + }, + "moveforward" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveForward", + "description" : "Moves the camera Forward a bit" + }, + "moveleft" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveLeft", + "description" : "Moves the camera Left a bit" + }, + "movereset" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveReset", + "description" : "Moves the camera Reset a bit" + }, + "moveright" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveRight", + "description" : "Moves the camera Right a bit" + }, + "moverotate" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveRotate", + "description" : "Moves the camera Rotate a bit" + }, + "moveslow" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveSlow", + "description" : "Moves the camera Slow a bit" + }, + "movetilt" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveTilt", + "description" : "Moves the camera Tilt a bit" + }, + "moveup" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MoveUp", + "description" : "Moves the camera Up a bit" + }, + "mutesound" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "MuteSound", + "description" : "Mute/Unmute the current sound system" + }, + "netmsgsmoothing" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "NetMsgSmoothing", + "description" : "Toggles whether client will use net-message smoothing; better for unstable connections" + }, + "netping" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "NetPing", + "description" : "Send a ping request to the server" + }, + "noluadraw" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "NoLuaDraw", + "description" : "Allow/Disallow Lua to draw on the map" + }, + "pastetext" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "PasteText", + "description" : "Paste either the argument string(s) or the content of the clip-board to chat input" + }, + "pause" : { + "arguments" : { + "" : "Toggles tracking", + "" : "Set tracking " + }, + "cheatRequired" : false, + "command" : "Pause", + "description" : "Pause/Unpause the game" + }, + "quitforce" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "QuitForce", + "description" : "Exits game to system" + }, + "quitmenu" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "QuitMenu", + "description" : "Opens the quit-menu, if it is not already open" + }, + "quitmessage" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "QuitMessage", + "description" : "Deprecated, see /Quit instead (was used to quit the game immediately)" + }, + "reloadforce" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ReloadForce", + "description" : "Exits game to menu" + }, + "reloadshaders" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ReloadShaders", + "description" : "Reloads all engine shaders" + }, + "reloadtextures" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ReloadTextures", + "description" : "Reloads textures" + }, + "resbar" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ResBar", + "description" : "Shows/Hides team resource storage indicator bar" + }, + "resync" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Resync", + "description" : "Redirects command /Resync to its synced processor" + }, + "safegl" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SafeGL", + "description" : "Enables/Disables OpenGL safe-mode" + }, + "save" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Save", + "description" : "Save the game state to a specific file, add -y to overwrite when file is already present" + }, + "say" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Say", + "description" : "Say something in (public) chat" + }, + "screenshot" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ScreenShot", + "description" : "Take a screen-shot of the current view" + }, + "select" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Select", + "description" : "" + }, + "selectcycle" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SelectCycle", + "description" : "" + }, + "selectunits" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SelectUnits", + "description" : "" + }, + "send" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Send", + "description" : "Send a string as raw network message to the game host (for debugging only)" + }, + "set" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Set", + "description" : "Set a config key=value pair" + }, + "setspeed" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SetSpeed", + "description" : "Set the simulation speed to any positive value, bounded by the minimum and maximum game speed settings." + }, + "shadows" : { + "arguments" : { + "-1" : "Disabled", + "0" : "Off", + "1" : "Full shadows", + "2" : "Skip terrain shadows" + }, + "cheatRequired" : false, + "command" : "Shadows", + "description" : "Control shadow rendering" + }, + "sharedialog" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ShareDialog", + "description" : "Opens the share dialog for sending units and resources to other players" + }, + "showelevation" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ShowElevation", + "description" : "Enable rendering of the auxiliary height-map overlay" + }, + "showmetalmap" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ShowMetalMap", + "description" : "Enable rendering of the auxiliary metal-map overlay" + }, + "showpathcost" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "ShowPathCost", + "description" : "Enable rendering of the path cost-map overlay" + }, + "showpathflow" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "ShowPathFlow", + "description" : "Enable/Disable rendering of the path flow-map overlay" + }, + "showpathheat" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "ShowPathHeat", + "description" : "Enable/Disable rendering of the path heat-map overlay" + }, + "showpathtraversability" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ShowPathTraversability", + "description" : "Enable rendering of the path traversability-map overlay" + }, + "showpathtype" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ShowPathType", + "description" : "Shows path traversability for a given MoveDefName, MoveDefID or UnitDefName" + }, + "showstandard" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ShowStandard", + "description" : "Disable rendering of all auxiliary map overlays" + }, + "slowdown" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SlowDown", + "description" : "Decreases the simulation speed. The engine will try to simulate less frames per second" + }, + "softparticles" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SoftParticles", + "description" : "Enable/Disable particles softening: 0=disabled, 1=enabled" + }, + "soundchannelenable" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SoundChannelEnable", + "description" : "Enable/Disable specific sound channels: UnitReply, General, Battle, UserInterface, Music" + }, + "sounddevice" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SoundDevice", + "description" : "Switch the sound output system (currently only OpenAL / NullAudio)" + }, + "specfullview" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SpecFullView", + "description" : "Sets or toggles between full LOS or ally-team LOS if the local user is a spectator" + }, + "spectator" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Spectator", + "description" : "Lets the local user give up control over a team and start spectating" + }, + "specteam" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SpecTeam", + "description" : "Lets the local user specify the team to follow if he is a spectator" + }, + "speed" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Speed", + "description" : "Shows/Hides the simulation speed indicator" + }, + "speedcontrol" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SpeedControl", + "description" : "Sets how server adjusts speed according to player's CPU load, 1: use average, 0: use highest" + }, + "speedup" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "SpeedUp", + "description" : "Increases the simulation speed. The engine will try to simulate more frames per second" + }, + "take" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "Take", + "description" : "Redirects command /Take to its synced processor" + }, + "team" : { + "arguments" : {}, + "cheatRequired" : true, + "command" : "Team", + "description" : "Lets the local user change to another team" + }, + "teamhighlight" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "TeamHighlight", + "description" : "Enables/Disables uncontrolled team blinking" + }, + "toggleinfo" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ToggleInfo", + "description" : "Toggles current info texture view" + }, + "togglelos" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ToggleLOS", + "description" : "Enable rendering of the auxiliary LOS-map overlay" + }, + "tooltip" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ToolTip", + "description" : "Enables/Disables the general tool-tips, displayed when hovering over units. features or the map" + }, + "track" : { + "arguments" : { + "" : "Toggles tracking", + "" : "Set tracking " + }, + "cheatRequired" : false, + "command" : "Track", + "description" : "Start/stop following the selected unit(s) with the camera" + }, + "trackmode" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "TrackMode", + "description" : "Shift through different ways of following selected unit(s)" + }, + "tset" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "TSet", + "description" : "Set a config key=value pair in the overlay, meaning it will not be persisted for future games" + }, + "unitdrawer" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "UnitDrawer", + "description" : "Forces particular Unit drawer type" + }, + "viewselection" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "ViewSelection", + "description" : "Moves the camera to the center of the currently selected units" + }, + "vsync" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "VSync", + "description" : "Enables/Disables vertical-sync (Graphics setting)" + }, + "w" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "W", + "description" : "Say something in private to a specific player, by player-name" + }, + "water" : { + "arguments" : { + "0" : "Basic", + "1" : "Reflective", + "2" : "Dynamic", + "3" : "Reflective & Refractive", + "4" : "Bump-mapped" + }, + "cheatRequired" : false, + "command" : "Water", + "description" : "Set water rendering mode" + }, + "wbynum" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "WByNum", + "description" : "Say something in private to a specific player, by player-ID" + }, + "windowborderless" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "WindowBorderless", + "description" : "Switches borderless/decorated mode" + }, + "wiremap" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "WireMap", + "description" : "Toggle wireframe-mode drawing of map geometry" + }, + "wiremodel" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "WireModel", + "description" : "Toggle wireframe-mode drawing of model geometry" + }, + "wiresky" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "WireSky", + "description" : "Toggle wireframe-mode drawing of skydome geometry" + }, + "wirewater" : { + "arguments" : {}, + "cheatRequired" : false, + "command" : "WireWater", + "description" : "Toggle wireframe-mode drawing of water geometry" + } +} diff --git a/_data/weapondefs.json b/_data/weapondefs.json new file mode 100644 index 0000000000..f9851ed553 --- /dev/null +++ b/_data/weapondefs.json @@ -0,0 +1,819 @@ +{ + "WeaponDefs": { + "name": { + "internalName": "description", + "description": "The descriptive name of the weapon as listed in FPS mode.", + "defaultValue": Weapon, + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "weaponType": { + "internalName": "type", + "defaultValue": Cannon, + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "id": { + "internalName": "tdfId", + "defaultValue": 0, + "type": "int" + }, + "customParams": { + "type": "table" + }, + "avoidFriendly": { + "defaultValue": 1, + "type": "bool" + }, + "avoidFeature": { + "defaultValue": 1, + "type": "bool" + }, + "avoidNeutral": { + "defaultValue": 0, + "type": "bool" + }, + "avoidGround": { + "defaultValue": 1, + "type": "bool" + }, + "avoidCloaked": { + "defaultValue": 0, + "type": "bool" + }, + "collideEnemy": { + "defaultValue": 1, + "type": "bool" + }, + "collideFriendly": { + "defaultValue": 1, + "type": "bool" + }, + "collideFeature": { + "defaultValue": 1, + "type": "bool" + }, + "collideNeutral": { + "defaultValue": 1, + "type": "bool" + }, + "collideGround": { + "defaultValue": 1, + "type": "bool" + }, + "damage": { + "type": "table" + }, + "damage.default": { + "defaultValue": 1, + "type": "float" + }, + "size": { + "type": "float" + }, + "explosionSpeed": { + "type": "float" + }, + "impactOnly": { + "defaultValue": 0, + "type": "bool" + }, + "noSelfDamage": { + "defaultValue": 0, + "type": "bool" + }, + "noExplode": { + "defaultValue": 0, + "type": "bool" + }, + "burnblow": { + "internalName": "selfExplode", + "defaultValue": 0, + "type": "bool" + }, + "damageAreaOfEffect": { + "fallbackName": "areaOfEffect", + "defaultValue": 8, + "scaleValue": 0.5, + "scaleValueString": "0.5f", + "type": "float" + }, + "edgeEffectiveness": { + "defaultValue": 0, + "maximumValue": 1, + "type": "float" + }, + "collisionSize": { + "defaultValue": 0.05, + "type": "float" + }, + "weaponVelocity": { + "internalName": "projectilespeed", + "fallbackName": "maxVelocity", + "defaultValue": 0, + "minimumValue": 0.01, + "scaleValue": 0.0333333, + "scaleValueString": "1.0f / GAME_SPEED", + "type": "float" + }, + "startvelocity": { + "defaultValue": 0, + "minimumValue": 0.01, + "scaleValue": 0.0333333, + "scaleValueString": "1.0f / GAME_SPEED", + "type": "float" + }, + "weaponacceleration": { + "fallbackName": "acceleration", + "defaultValue": 0, + "scaleValue": 0.00111111, + "scaleValueString": "1.0f / (GAME_SPEED * GAME_SPEED)", + "type": "float" + }, + "reloadTime": { + "internalName": "reload", + "defaultValue": 1, + "type": "float" + }, + "burstRate": { + "internalName": "salvodelay", + "defaultValue": 0.1, + "type": "float" + }, + "burst": { + "internalName": "salvosize", + "defaultValue": 1, + "type": "int" + }, + "projectiles": { + "internalName": "projectilespershot", + "defaultValue": 1, + "type": "int" + }, + "waterBounce": { + "defaultValue": 0, + "type": "bool" + }, + "groundBounce": { + "defaultValue": 0, + "type": "bool" + }, + "bounceSlip": { + "defaultValue": 1, + "type": "float" + }, + "bounceRebound": { + "defaultValue": 1, + "type": "float" + }, + "numBounce": { + "defaultValue": -1, + "type": "int" + }, + "impulseFactor": { + "defaultValue": 1, + "type": "float" + }, + "impulseBoost": { + "defaultValue": 0, + "type": "float" + }, + "craterMult": { + "fallbackName": "impulseFactor", + "defaultValue": 1, + "type": "float" + }, + "craterBoost": { + "defaultValue": 0, + "type": "float" + }, + "craterAreaOfEffect": { + "fallbackName": "areaOfEffect", + "defaultValue": 8, + "scaleValue": 0.5, + "scaleValueString": "0.5f", + "type": "float" + }, + "waterweapon": { + "defaultValue": 0, + "type": "bool" + }, + "submissile": { + "defaultValue": 0, + "type": "bool" + }, + "fireSubmersed": { + "fallbackName": "waterweapon", + "defaultValue": 0, + "type": "bool" + }, + "commandfire": { + "internalName": "manualfire", + "defaultValue": 0, + "type": "bool" + }, + "range": { + "defaultValue": 10, + "type": "float" + }, + "heightmod": { + "defaultValue": 0.2, + "type": "float" + }, + "targetBorder": { + "defaultValue": 0, + "minimumValue": -1, + "maximumValue": 1, + "type": "float" + }, + "cylinderTargeting": { + "fallbackName": "cylinderTargetting", + "defaultValue": 0, + "minimumValue": 0, + "maximumValue": 128, + "type": "float" + }, + "turret": { + "description": "Does the unit aim within an arc (up-to and including full 360° turret traverse) or always aim along the owner's heading?", + "defaultValue": 0, + "type": "bool" + }, + "fixedLauncher": { + "defaultValue": 0, + "type": "bool" + }, + "tolerance": { + "internalName": "maxAngle", + "defaultValue": 3000, + "scaleValue": 9.58738e-05, + "scaleValueString": "TAANG2RAD", + "type": "float" + }, + "firetolerance": { + "internalName": "maxFireAngle", + "defaultValue": 3640, + "scaleValue": 9.58738e-05, + "scaleValueString": "TAANG2RAD", + "type": "float" + }, + "highTrajectory": { + "defaultValue": 2, + "type": "int" + }, + "trajectoryHeight": { + "defaultValue": 0, + "type": "float" + }, + "tracks": { + "defaultValue": 0, + "type": "bool" + }, + "wobble": { + "defaultValue": 0, + "scaleValue": 3.19579e-06, + "scaleValueString": "float(TAANG2RAD) / GAME_SPEED", + "type": "float" + }, + "dance": { + "defaultValue": 0, + "scaleValue": 0.0333333, + "scaleValueString": "1.0f / GAME_SPEED", + "type": "float" + }, + "gravityAffected": { + "defaultValue": 0, + "type": "bool" + }, + "myGravity": { + "defaultValue": 0, + "type": "float" + }, + "canAttackGround": { + "defaultValue": 1, + "type": "bool" + }, + "weaponTimer": { + "internalName": "uptime", + "defaultValue": 0, + "type": "float" + }, + "flighttime": { + "description": "Flighttime of missiles in seconds.", + "defaultValue": 0, + "scaleValue": 30, + "scaleValueString": "GAME_SPEED", + "type": "float" + }, + "turnrate": { + "defaultValue": 0, + "scaleValue": 3.19579e-06, + "scaleValueString": "float(TAANG2RAD) / GAME_SPEED", + "type": "float" + }, + "heightBoostFactor": { + "defaultValue": -1, + "type": "float" + }, + "proximityPriority": { + "defaultValue": 1, + "type": "float" + }, + "allowNonBlockingAim": { + "description": "When false, the weapon is blocked from firing until AimWeapon() returns.", + "defaultValue": 0, + "type": "bool" + }, + "accuracy": { + "defaultValue": 0, + "tagFunction": "math::sin(x * math::PI / 0xafff)", + "type": "float" + }, + "sprayAngle": { + "defaultValue": 0, + "tagFunction": "math::sin(x * math::PI / 0xafff)", + "type": "float" + }, + "movingAccuracy": { + "fallbackName": "accuracy", + "defaultValue": 0, + "tagFunction": "math::sin(x * math::PI / 0xafff)", + "type": "float" + }, + "targetMoveError": { + "defaultValue": 0, + "type": "float" + }, + "leadLimit": { + "defaultValue": -1, + "type": "float" + }, + "leadBonus": { + "defaultValue": 0, + "type": "float" + }, + "predictBoost": { + "defaultValue": 0, + "type": "float" + }, + "ownerExpAccWeight": { + "type": "float" + }, + "minIntensity": { + "description": "The minimum percentage the weapon's damage can fall-off to over its range. Setting to 1.0 will disable fall off entirely. Unrelated to the visual-only intensity tag.", + "defaultValue": 0, + "type": "float" + }, + "duration": { + "defaultValue": 0.05, + "type": "float" + }, + "beamtime": { + "defaultValue": 1, + "type": "float" + }, + "beamburst": { + "defaultValue": 0, + "type": "bool" + }, + "beamTTL": { + "internalName": "beamLaserTTL", + "defaultValue": 0, + "type": "int" + }, + "sweepFire": { + "description": "Makes BeamLasers continue firing while aiming for a new target, 'sweeping' across the terrain.", + "defaultValue": 0, + "type": "bool" + }, + "largeBeamLaser": { + "defaultValue": 0, + "type": "bool" + }, + "sizeGrowth": { + "defaultValue": 0.5, + "type": "float" + }, + "flameGfxTime": { + "type": "float" + }, + "metalPerShot": { + "internalName": "metalcost", + "defaultValue": 0, + "type": "float" + }, + "energyPerShot": { + "internalName": "energycost", + "defaultValue": 0, + "type": "float" + }, + "fireStarter": { + "description": "The percentage chance of the weapon setting fire to static map features on impact.", + "defaultValue": 0, + "minimumValue": 0, + "scaleValue": 0.01, + "scaleValueString": "0.01f", + "type": "float" + }, + "paralyzer": { + "description": "Is the weapon a paralyzer? If true the weapon only stuns enemy units and does not cause damage in the form of lost hit-points.", + "defaultValue": 0, + "type": "bool" + }, + "paralyzeTime": { + "description": "Determines the maximum length of time in seconds that the target will be paralyzed. The timer is restarted every time the target is hit by the weapon. Cannot be less than 0.", + "defaultValue": 10, + "minimumValue": 0, + "type": "int" + }, + "stockpile": { + "description": "Does each round of the weapon have to be built and stockpiled by the player? Will only correctly function for the first of each stockpiled weapons a unit has.", + "defaultValue": 0, + "type": "bool" + }, + "stockpileTime": { + "fallbackName": "reload", + "description": "The time in seconds taken to stockpile one round of the weapon.", + "defaultValue": 1, + "scaleValue": 30, + "scaleValueString": "GAME_SPEED", + "type": "float" + }, + "targetable": { + "description": "Bitmask representing the types of weapon that can intercept this weapon. Each digit of binary that is set to one means that a weapon with the corresponding digit in its interceptor tag will intercept this weapon. Instant-hitting weapons such as [#BeamLaser], [#LightningCannon] and [#Rifle] cannot be targeted.", + "defaultValue": 0, + "type": "int" + }, + "interceptor": { + "description": "Bitmask representing the types of weapons that this weapon can intercept. Each digit of binary that is set to one means that a weapon with the corresponding digit in its targetable tag will be intercepted by this weapon.", + "defaultValue": 0, + "type": "int" + }, + "interceptedByShieldType": { + "description": "", + "type": "unsigned int" + }, + "coverage": { + "internalName": "coverageRange", + "description": "The radius in elmos within which an interceptor weapon will fire on targetable weapons.", + "defaultValue": 0, + "type": "float" + }, + "interceptSolo": { + "description": "If true no other interceptors may target the same projectile.", + "defaultValue": 1, + "type": "bool" + }, + "dynDamageInverted": { + "description": "If true the damage curve is inverted i.e. the weapon does more damage at greater ranges as opposed to less.", + "defaultValue": 0, + "type": "bool" + }, + "dynDamageExp": { + "description": "Exponent of the range-dependent damage formula, the default of 0.0 disables dynamic damage, 1.0 means linear scaling, 2.0 quadratic and so on.", + "defaultValue": 0, + "type": "float" + }, + "dynDamageMin": { + "description": "The minimum floor value that range-dependent damage can drop to.", + "defaultValue": 0, + "type": "float" + }, + "dynDamageRange": { + "description": "If set to non-zero values the weapon will use this value in the range-dependant damage formula instead of the actual range.", + "defaultValue": 0, + "type": "float" + }, + "shield.repulser": { + "internalName": "shieldRepulser", + "fallbackName": "shieldRepulser", + "description": "Does the shield repulse (deflect) projectiles or absorb them?", + "defaultValue": 0, + "type": "bool" + }, + "shield.smart": { + "internalName": "smartShield", + "fallbackName": "smartShield", + "description": "Determines whether or not projectiles fired by allied units can pass through the shield (true) or are intercepted as enemy weapons are (false).", + "defaultValue": 0, + "type": "bool" + }, + "shield.exterior": { + "internalName": "exteriorShield", + "fallbackName": "exteriorShield", + "description": "Determines whether or not projectiles fired within the shield's radius can pass through the shield (true) or are intercepted (false).", + "defaultValue": 0, + "type": "bool" + }, + "shield.maxSpeed": { + "internalName": "shieldMaxSpeed", + "fallbackName": "shieldMaxSpeed", + "description": "The maximum speed the repulsor will impart to deflected projectiles.", + "defaultValue": 0, + "type": "float" + }, + "shield.force": { + "internalName": "shieldForce", + "fallbackName": "shieldForce", + "description": "The force applied by the repulsor to the weapon - higher values will deflect weapons away at higher velocities.", + "defaultValue": 0, + "type": "float" + }, + "shield.radius": { + "internalName": "shieldRadius", + "fallbackName": "shieldRadius", + "description": "The radius of the circular area the shield covers.", + "defaultValue": 0, + "type": "float" + }, + "shield.power": { + "internalName": "shieldPower", + "fallbackName": "shieldPower", + "description": "Essentially the maximum allowed hit-points of the shield - reduced by the damage of a weapon upon impact.", + "defaultValue": 0, + "type": "float" + }, + "shield.startingPower": { + "internalName": "shieldStartingPower", + "fallbackName": "shieldStartingPower", + "description": "How many hit-points the shield starts with - otherwise the shield must regenerate from 0 until it reaches maximum power.", + "defaultValue": 0, + "type": "float" + }, + "shield.powerRegen": { + "internalName": "shieldPowerRegen", + "fallbackName": "shieldPowerRegen", + "description": "How many hit-points the shield regenerates each second.", + "defaultValue": 0, + "type": "float" + }, + "shield.powerRegenEnergy": { + "internalName": "shieldPowerRegenEnergy", + "fallbackName": "shieldPowerRegenEnergy", + "description": "How much energy resource is consumed to regenerate each hit-point.", + "defaultValue": 0, + "type": "float" + }, + "shield.energyUse": { + "internalName": "shieldEnergyUse", + "fallbackName": "shieldEnergyUse", + "description": "The amount of the energy resource consumed by the shield to absorb or repulse weapons, continually drained by a repulsor as long as the projectile is in range.", + "defaultValue": 0, + "type": "float" + }, + "rechargeDelay": { + "internalName": "shieldRechargeDelay", + "fallbackName": "shieldRechargeDelay", + "description": "The delay in seconds before a shield begins to regenerate after it is hit.", + "defaultValue": 0, + "scaleValue": 30, + "scaleValueString": "GAME_SPEED", + "type": "float" + }, + "shield.interceptType": { + "internalName": "shieldInterceptType", + "fallbackName": "shieldInterceptType", + "description": "Bitmask representing the types of weapons that this shield can intercept. Each digit of binary that is set to one means that a weapon with the corresponding digit in its interceptedByShieldType will be intercepted by this shield (See [[Shield Interception Tag]] Use).", + "defaultValue": 0, + "type": "unsigned int" + }, + "shield.visible": { + "internalName": "visibleShield", + "fallbackName": "visibleShield", + "description": "Is the shield visible or not?", + "defaultValue": 0, + "type": "bool" + }, + "shield.visibleRepulse": { + "internalName": "visibleShieldRepulse", + "fallbackName": "visibleShieldRepulse", + "description": "Is the (hard-coded) repulse effect rendered or not?", + "defaultValue": 0, + "type": "bool" + }, + "shield.visibleHitFrames": { + "internalName": "visibleShieldHitFrames", + "fallbackName": "visibleShieldHitFrames", + "description": "The number of frames a shield becomes visible for when hit.", + "defaultValue": 0, + "type": "int" + }, + "shield.badColor": { + "internalName": "shieldBadColor", + "fallbackName": "shieldBadColor", + "description": "The RGBA colour the shield transitions to as its hit-points are reduced towards 0.", + "defaultValue": [ 1, 0.5, 0.5 ], + "type": "float4" + }, + "shield.goodColor": { + "internalName": "shieldGoodColor", + "fallbackName": "shieldGoodColor", + "description": "The RGBA colour the shield transitions to as its hit-points are regenerated towards its maximum power.", + "defaultValue": [ 0.5, 0.5, 1 ], + "type": "float4" + }, + "shield.alpha": { + "internalName": "shieldAlpha", + "fallbackName": "shieldAlpha", + "description": "The alpha transparency of the shield whilst it is visible.", + "defaultValue": 0.2, + "type": "float" + }, + "shield.armorType": { + "internalName": "shieldArmorTypeName", + "fallbackName": "shieldArmorType", + "description": "Specifies the armorclass of the shield; you can input either an armorclass name OR a unitdef name to share that unit's armorclass", + "defaultValue": default, + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "model": { + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "explosionScar": { + "defaultValue": 1, + "type": "bool" + }, + "alwaysVisible": { + "defaultValue": 0, + "type": "bool" + }, + "cameraShake": { + "fallbackName": "damage.default", + "defaultValue": 0, + "minimumValue": 0, + "type": "float" + }, + "smokeTrail": { + "defaultValue": 0, + "type": "bool" + }, + "smokeTrailCastShadow": { + "defaultValue": 1, + "type": "bool" + }, + "smokePeriod": { + "defaultValue": 8, + "type": "int" + }, + "smokeTime": { + "defaultValue": 60, + "type": "int" + }, + "smokeSize": { + "defaultValue": 7, + "type": "float" + }, + "smokeColor": { + "defaultValue": 0.65, + "type": "float" + }, + "castShadow": { + "defaultValue": 1, + "type": "bool" + }, + "sizeDecay": { + "defaultValue": 0, + "type": "float" + }, + "alphaDecay": { + "defaultValue": 1, + "type": "float" + }, + "separation": { + "defaultValue": 1, + "type": "float" + }, + "noGap": { + "defaultValue": 1, + "type": "bool" + }, + "stages": { + "defaultValue": 5, + "type": "int" + }, + "lodDistance": { + "defaultValue": 1000, + "type": "int" + }, + "thickness": { + "defaultValue": 2, + "type": "float" + }, + "coreThickness": { + "defaultValue": 0.25, + "type": "float" + }, + "laserFlareSize": { + "defaultValue": 15, + "type": "float" + }, + "tileLength": { + "defaultValue": 200, + "type": "float" + }, + "scrollSpeed": { + "defaultValue": 5, + "type": "float" + }, + "pulseSpeed": { + "defaultValue": 1, + "type": "float" + }, + "beamDecay": { + "defaultValue": 1, + "type": "float" + }, + "falloffRate": { + "defaultValue": 0.5, + "type": "float" + }, + "hardstop": { + "internalName": "laserHardStop", + "defaultValue": 0, + "type": "bool" + }, + "rgbColor": { + "defaultValue": [ 1, 0.5, 0 ], + "type": "float3" + }, + "rgbColor2": { + "defaultValue": [ 1, 1, 1 ], + "type": "float3" + }, + "intensity": { + "description": "Alpha transparency for non-model projectiles. Lower values are more opaque, but 0.0 will cause the projectile to disappear entirely.", + "defaultValue": 0.9, + "type": "float" + }, + "colormap": { + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "textures.1": { + "internalName": "textures1", + "fallbackName": "texture1", + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "textures.2": { + "internalName": "textures2", + "fallbackName": "texture2", + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "textures.3": { + "internalName": "textures3", + "fallbackName": "texture3", + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "textures.4": { + "internalName": "textures4", + "fallbackName": "texture4", + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "cegTag": { + "description": "The name, without prefixes, of a CEG to be emitted by the projectile each frame.", + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "explosionGenerator": { + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "bounceExplosionGenerator": { + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "soundTrigger": { + "type": "bool" + }, + "soundStart": { + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "soundHitDry": { + "fallbackName": "soundHit", + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "soundHitWet": { + "fallbackName": "soundHit", + "defaultValue": , + "type": "std::__cxx11::basic_string, std::allocator >" + }, + "soundStartVolume": { + "defaultValue": -1, + "type": "float" + }, + "soundHitDryVolume": { + "fallbackName": "soundHitVolume", + "defaultValue": -1, + "type": "float" + }, + "soundHitWetVolume": { + "fallbackName": "soundHitVolume", + "defaultValue": -1, + "type": "float" + } + } +} diff --git a/_includes/head.html b/_includes/head.html new file mode 100644 index 0000000000..ca82cb0807 --- /dev/null +++ b/_includes/head.html @@ -0,0 +1,52 @@ + + + + + + + + + {% if site.ga_tracking != nil %} + {% assign ga_tracking_ids = site.ga_tracking | split: "," %} + + + {% endif %} + + {% if site.search_enabled != false %} + + {% endif %} + + {% if site.mermaid %} + {% if site.mermaid.path %} + + {% else %} + + {% endif %} + {% endif %} + + + + + + {% for file in site.static_files %} + {% if file.path == site.favicon_ico or file.path == '/favicon.ico' %} + {% assign favicon = true %} + {% endif %} + {% endfor %} + {% if favicon %} + + {% endif %} + + {% seo %} + + {% include head_custom.html %} + + diff --git a/_includes/header_custom.html b/_includes/header_custom.html new file mode 100644 index 0000000000..bf38de64c9 --- /dev/null +++ b/_includes/header_custom.html @@ -0,0 +1,34 @@ + + + diff --git a/_layouts/post.html b/_layouts/post.html new file mode 100644 index 0000000000..93bd81d917 --- /dev/null +++ b/_layouts/post.html @@ -0,0 +1,21 @@ +--- +layout: default +--- + +{{ content }} + +{% assign author = site.authors | where: 'short_name', page.author | first %} + +{% if author != nil %} +{% assign contributor = site.github.contributors | where: 'login', author.github | first %} +
+

+Written by: {{author.short_name}} + +{% if contributor != nil and contributor != false %} +

+{{ contributor.login }} +

+{% endif %} +

+{% endif %} diff --git a/_sass/content-nocharset.scss b/_sass/content-nocharset.scss new file mode 100644 index 0000000000..032f8ef159 --- /dev/null +++ b/_sass/content-nocharset.scss @@ -0,0 +1,237 @@ +// Styles for rendered markdown in the .main-content container +// stylelint-disable selector-no-type, max-nesting-depth, selector-max-compound-selectors, selector-max-type, selector-max-specificity, selector-max-id + +.main-content { + line-height: $content-line-height; + + ol, + ul, + dl, + pre, + address, + blockquote, + .table-wrapper { + margin-top: 0.5em; + } + + a { + overflow: hidden; + text-overflow: ellipsis; + } + + ul, + ol { + padding-left: 1.5em; + } + + li { + .highlight { + margin-top: $sp-1; + } + } + + ol { + list-style-type: none; + counter-reset: step-counter; + + > li { + position: relative; + + &::before { + position: absolute; + top: 0.2em; + left: -1.6em; + color: $grey-dk-000; + content: counter(step-counter); + counter-increment: step-counter; + @include fs-3; + + @include mq(sm) { + top: 0.11em; + } + } + + ol { + counter-reset: sub-counter; + + > li { + &::before { + content: counter(sub-counter, lower-alpha); + counter-increment: sub-counter; + } + } + } + } + } + + ul { + list-style: none; + + > li { + &::before { + position: absolute; + margin-left: -1.4em; + color: $grey-dk-000; + content: "•"; + } + } + } + + .task-list-item { + &::before { + content: ""; + } + } + + .task-list-item-checkbox { + margin-right: 0.6em; + margin-left: -1.4em; + + // The same margin-left is used above for ul > li::before + } + + hr + * { + margin-top: 0; + } + + h1:first-of-type { + margin-top: 0.5em; + } + + dl { + display: grid; + grid-template: auto / 10em 1fr; + } + + dt, + dd { + margin: 0.25em 0; + } + + dt { + grid-column: 1; + font-weight: 500; + text-align: right; + + &::after { + content: ":"; + } + } + + dd { + grid-column: 2; + margin-bottom: 0; + margin-left: 1em; + + blockquote, + div, + dl, + dt, + h1, + h2, + h3, + h4, + h5, + h6, + li, + ol, + p, + pre, + table, + ul, + .table-wrapper { + &:first-child { + margin-top: 0; + } + } + } + + dd, + ol, + ul { + dl:first-child { + dt:first-child, + dd:nth-child(2) { + margin-top: 0; + } + } + } + + .anchor-heading { + position: absolute; + right: -$sp-4; + width: $sp-5; + height: 100%; + padding-right: $sp-1; + padding-left: $sp-1; + overflow: visible; + + @include mq(md) { + right: auto; + left: -$sp-5; + } + + svg { + display: inline-block; + width: 100%; + height: 100%; + color: $link-color; + visibility: hidden; + } + } + + .anchor-heading:hover, + .anchor-heading:focus, + h1:hover > .anchor-heading, + h2:hover > .anchor-heading, + h3:hover > .anchor-heading, + h4:hover > .anchor-heading, + h5:hover > .anchor-heading, + h6:hover > .anchor-heading { + svg { + visibility: visible; + } + } + + summary { + cursor: pointer; + } + + h1, + h2, + h3, + h4, + h5, + h6, + #toctitle { + position: relative; + margin-top: 1.5em; + margin-bottom: 0.25em; + + + table, + + .table-wrapper, + + .code-example, + + .highlighter-rouge, + + .sectionbody .listingblock { + margin-top: 1em; + } + + + p:not(.label) { + margin-top: 0; + } + } + + > h1:first-child, + > h2:first-child, + > h3:first-child, + > h4:first-child, + > h5:first-child, + > h6:first-child, + > .sect1:first-child > h2, + > .sect2:first-child > h3, + > .sect3:first-child > h4, + > .sect4:first-child > h5, + > .sect5:first-child > h6 { + margin-top: $sp-2; + } +} diff --git a/_sass/custom/custom.scss b/_sass/custom/custom.scss new file mode 100644 index 0000000000..51766ac182 --- /dev/null +++ b/_sass/custom/custom.scss @@ -0,0 +1,226 @@ +/****************************/ +/***** Jekyll Glossary ******/ +/****************************/ + +/* vendored from https://raw.githubusercontent.com/erikw/jekyll-glossary_tooltip/main/lib/jekyll-glossary_tooltip/jekyll-glossary_tooltip.css */ + +.jekyll-glossary { + position: relative; + display: inline-block; + border-bottom: 2px dotted #0074bd; + cursor: help; +} + +.jekyll-glossary .jekyll-glossary-tooltip { + visibility: hidden; + width: 120px; + background-color: black; + color: #fff; + text-align: center; + font-size: 0.5em; + padding: 5px; + border-radius: 6px; + + /* Position the tooltip text - see examples below! */ + position: absolute; + z-index: 1; + + width: 160px; + bottom: 100%; + left: 50%; + margin-left: -80px; /* Use half of the width to center the tooltip */ + +} + +/* Show the tooltip text when you mouse over the tooltip container */ +.jekyll-glossary:hover .jekyll-glossary-tooltip { + visibility: visible; +} + +/* Style the source link (if there is one provided in the glossary entry). */ +.jekyll-glossary-source-link:before { + content: "[source]"; // "(reference)", "" or whatever you want. +} + +/* Arrow created with borders. */ +.jekyll-glossary .jekyll-glossary-tooltip::after { + content: " "; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: black transparent transparent transparent; +} + +/* Animation from invisible to visible on hover. */ +.jekyll-glossary .jekyll-glossary-tooltip { + opacity: 0; + transition: opacity 1s; +} +.jekyll-glossary:hover .jekyll-glossary-tooltip { + opacity: 1; +} + +/***************************/ +/***** Theme switcher ******/ +/***************************/ + +// vendored from https://github.com/argyleink/gui-challenges/blob/main/theme-switch + +@import"https://unpkg.com/open-props/easings.min.css"; + +.sun-and-moon>:is(.moon,.sun,.sun-beams) { + transform-origin:center center +} +.sun-and-moon>:is(.moon, +.sun) { + fill:var(--icon-fill) +} +.theme-toggle:is(:hover, +:focus-visible)>.sun-and-moon>:is(.moon, +.sun) { + fill:var(--icon-fill-hover) +} +.sun-and-moon>.sun-beams { + stroke:var(--icon-fill); + stroke-width:2px +} +.theme-toggle:is(:hover, +:focus-visible) .sun-and-moon>.sun-beams { + stroke:var(--icon-fill-hover) +} +[data-theme=dark] .sun-and-moon>.sun { + transform:scale(1.75) +} +[data-theme=dark] .sun-and-moon>.sun-beams { + opacity:0 +} +[data-theme=dark] .sun-and-moon>.moon>circle { + transform:translate(-7px) +} +@supports (cx: 1) { + [data-theme=dark] .sun-and-moon>.moon>circle { + transform:translate(0); + cx:17 + } +} +@media (prefers-reduced-motion: no-preference) { + .sun-and-moon>.sun { + transition:transform .5s var(--ease-elastic-3) + } + .sun-and-moon>.sun-beams { + transition:transform .5s var(--ease-elastic-4),opacity .5s var(--ease-3) + } + .sun-and-moon .moon>circle { + transition:transform .25s var(--ease-out-5) + } + @supports (cx: 1) { + .sun-and-moon .moon>circle { + transition:cx .25s var(--ease-out-5) + } + } + [data-theme=dark] .sun-and-moon>.sun { + transform:scale(1.75); + transition-timing-function:var(--ease-3); + transition-duration:.25s + } + [data-theme=dark] .sun-and-moon>.sun-beams { + transform:rotate(-25deg); + transition-duration:.15s + } + [data-theme=dark] .sun-and-moon>.moon>circle { + transition-delay:.25s; + transition-duration:.5s + } +} +.theme-toggle { + --size: 2rem; + --icon-fill: hsl(210 10% 30%); + --icon-fill-hover: hsl(210 10% 15%); + background:none; + border:none; + padding:0; + inline-size:var(--size); + block-size:var(--size); + aspect-ratio:1; + border-radius:50%; + cursor:pointer; + touch-action:manipulation; + -webkit-tap-highlight-color:transparent; + outline-offset:5px +} +.theme-toggle>svg { + inline-size:100%; + block-size:100%; + stroke-linecap:round +} +[data-theme=dark] .theme-toggle { + --icon-fill: hsl(210 10% 70%); + --icon-fill-hover: hsl(210 15% 90%) +} +@media (hover: none) { + .theme-toggle { + --size: 48px + } +} + +/***************************/ +/***** Custom Stuff ********/ +/***************************/ + +// unvendored do not remove +html[data-theme="dark"] button.theme-toggle, button.theme-toggle { + height: 100%; + margin: 0 0 0 1rem; +} + +/* Enlarged dt */ +.main-content dl.big-dt, html[data-theme="dark"] dl.big-dt { + grid-template: auto / fit-content(20em) 1fr; +} + +/* dt allowed to expand/contract */ +.main-content dl.dl-auto, html[data-theme="dark"] dl.dl-auto { + grid-template: auto / auto 1fr; +} + +.aux-nav, html[data-theme="dark"] .aux-nav { + padding-right: 0; +} + +.aux-nav-img img { + filter: invert(27%) sepia(14%) saturate(463%) hue-rotate(166deg) brightness(93%) contrast(85%); +} + +.aux-nav-list-item:hover .aux-nav-img img { + filter: invert(13%) sepia(6%) saturate(958%) hue-rotate(169deg) brightness(96%) contrast(95%); +} + +html:not(data-theme) .aux-nav-matrix img, html[data-theme="light"] .aux-nav-matrix img { + background-image: url("/spring/assets/matrix-logo.svg"); +} + +html[data-theme="dark"] .aux-nav-matrix img { + background-image: url("/spring/assets/matrix-logo-white.svg"); +} + +html:not(data-theme) .aux-nav-github img, html[data-theme="light"] .aux-nav-github img { + background-image: url("/spring/assets/github-mark.svg"); +} + +html[data-theme="dark"] .aux-nav-github img { + background-image: url("/spring/assets/github-mark-white.svg"); +} + +html .aux-nav-img img { + display: block; + -moz-box-sizing: border-box; + box-sizing: border-box; + + background-repeat: no-repeat; + background-size: cover; + height: 32px; + padding-left: 100%; /* Equal to width of new image */ +} diff --git a/_sass/modules-nocharset.scss b/_sass/modules-nocharset.scss new file mode 100644 index 0000000000..cdf9509b4d --- /dev/null +++ b/_sass/modules-nocharset.scss @@ -0,0 +1,16 @@ +// Import external dependencies +@import "./vendor/normalize.scss/normalize"; + +// Modules +@import "./base"; +@import "./layout"; +@import "./content-nocharset"; +@import "./navigation"; +@import "./typography"; +@import "./labels"; +@import "./buttons"; +@import "./search"; +@import "./tables"; +@import "./code"; +@import "./utilities/utilities"; +@import "./print"; diff --git a/_scripts/get_engine_data.sh b/_scripts/get_engine_data.sh new file mode 100755 index 0000000000..dc0b16d74f --- /dev/null +++ b/_scripts/get_engine_data.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +DATA_DIR="$SCRIPT_DIR/../_data" +DATA_FILE="$DATA_DIR/latest_release.json" +WORK_DIR="$SCRIPT_DIR/tmp" +CONFIG_FILE="$DATA_DIR/configs.json" +WDEFS_FILE="$DATA_DIR/weapondefs.json" +COMMANDS_FILE="$DATA_DIR/unsynced_commands.json" +SYNCED_COMMANDS_FILE="$DATA_DIR/synced_commands.json" + +DOWNLOAD_URL=$(jq -r '.assets[] | select(.name | contains("_linux-64-minimal-portable")).browser_download_url' $DATA_FILE) + +echo "> downloading latest engine release from $DOWNLOAD_URL" + +mkdir $WORK_DIR +cd $WORK_DIR + +curl -L $DOWNLOAD_URL -o engine.7z +7z -y e engine.7z spring + +echo "> writing $CONFIG_FILE" +rm -f $CONFIG_FILE +./spring --list-config-vars | grep -v "^\[t=" > $CONFIG_FILE + +echo "> writing $WDEFS_FILE" +rm -f $WDEFS_FILE +./spring --list-def-tags | grep -v "^\[t=" > $WDEFS_FILE + +echo "> writing $COMMANDS_FILE" +rm -f $COMMANDS_FILE +./spring --list-unsynced-commands | grep -v "^\[t=" > $COMMANDS_FILE + +echo "> writing $SYNCED_COMMANDS_FILE" +rm -f $SYNCED_COMMANDS_FILE +./spring --list-synced-commands | grep -v "^\[t=" > $SYNCED_COMMANDS_FILE diff --git a/_scripts/get_release_data.sh b/_scripts/get_release_data.sh new file mode 100755 index 0000000000..6199cd88c2 --- /dev/null +++ b/_scripts/get_release_data.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +DATA_FILE="$SCRIPT_DIR/../_data/latest_release.json" + +echo "> writing $DATA_FILE" + +rm $DATA_FILE +curl -s https://api.github.com/repos/beyond-all-reason/spring/releases/latest \ + > $DATA_FILE diff --git a/about.markdown b/about.markdown new file mode 100644 index 0000000000..b6ac31f041 --- /dev/null +++ b/about.markdown @@ -0,0 +1,10 @@ +--- +layout: default +title: About +permalink: /about/ +--- + +Recoil is an RTS engine. + +You can find the source code for Recoil at GitHub: +[spring](https://github.com/beyond-all-reason/spring) diff --git a/articles.markdown b/articles.markdown new file mode 100644 index 0000000000..972cf8783e --- /dev/null +++ b/articles.markdown @@ -0,0 +1,10 @@ +--- +layout: default +title: Articles +nav_order: 2 +has_children: true +permalink: articles +--- + +# Articles +{: .no_toc } diff --git a/articles/ceg-operators.markdown b/articles/ceg-operators.markdown new file mode 100644 index 0000000000..59284d39ef --- /dev/null +++ b/articles/ceg-operators.markdown @@ -0,0 +1,190 @@ +--- +layout: post +title: CEG operators +parent: Articles +permalink: articles/ceg-operators +author: sprunk +--- + +## Basics + +You can customize some CEG entries by specifying a series of operators instead of just a number. +This lets you apply limited logic to customize explosions. +Each operation is specified by a single string. + +### Raw numbers + +A single number means just that number. So for example: +```lua +sizeGrowth = "3", +``` +This sets `sizeGrowth` to 3. So far so simple. + +Some parameters, especially 3D vectors, accept multiple values. In that case, we separate then with the `,` (comma) operator. +For example: +```lua +pos = "1, 2, 3", +``` +This sets the position to x=1, y=2, and z=3. + +### Running value + +There is an implicit running value, which starts at 0 and on which all the operators work. +A raw number is actually an "operatorless" operator that performs simple addition to that running value. +So, one could think of the examples above as really being `0 +3` for `sizeGrowth` and `0 +1`, `0 +2`, and `0 +3` as the components of the `pos` vector respectively. + + +To illustrate how this matters, consider this example. Note that there is no `,` between these! +```lua +sizeGrowth = "1 2 3", +``` +The result of this is 6. This is because each of these is addition: `0 +1 +2 +3`, which nets 6. + +Similarly: +```lua +pos = "1 2, 3 4, 5 6", +``` +This sets the components to 3 (0 +1 +2), 7 (0 +3 +4) and 11 (0 +5 +6) respectively. + + +Putting a bunch of raw numbers next to each other doesn't make much sense, since we could have just written the sum directly, but the principle starts to matter when you mix operators. + +### Random (`r`) + +The `r` operator also works on the running value, but adds a random value between 0 and the operand. +So, for example, `r4` gives a random value between 0 and 4. Practical hints: + * very useful to make explosions look less artificial. + * if you don't want to roll from 0, then just add the offset (remember a raw operatorless number performs addition). +So, `3 r4` gives a value between 3 and 7. + * a common desire is to roll negative values, for example so that a directional particle can go either way. +In that case, also use the offset. A common idiom is to use, for example, `-15 r30` to roll ±15. + * the value is distributed uniformly, but with some knowledge of statistics you could tweak it by stacking rolls. +For example `r6` produces a flat uniform distribution, `r3 r3` a sort of triangle, and `r2 r2 r2` something smoother still. +In practice this seems very underused though, and you can't make the distribution asymmetrical via this basic method, +though you can via the more advanced ones below. + +### Index (`i`) + +The `i` operator multiplies its operand by the index of the particle, and adds this to the running value. +When a generator spawns multiple particles of the same kind, each one is assigned an increasing index: 0, 1, 2, etc. + +For example, if an explosion spawns 4 particles and `size = "3 i2"`, then they will have sizes of 3, 5, 7 and 9 respectively. + + * useful for spawning stuff in something resembling a line or cone. + * useful for scaling explosions via particle count, since the low-index particles will behave the same as before. + * remember this doesn't multiply the running value, or anything other than the operand. + +### Damage (`d`) + +The `d` operator multiplies its operand by the "damage" of an explosion. +For example `d0.1` will net 10 for a 100-damage explosion, and 50 for a 500-damage explosion. + +Some practical remarks: + * for regular weapons, this is the "default" damage. Beware if you treat it as the "features" armor class (since they can't have a real armor class)! + * for CEG trails, damage is the TTL of the projectile. So you can for example make missile trails burn out. + * for explosions spawned by unit scripts, this defaults to 0 but you can set it to an arbitrary value. + * existing games prefer to have a separate effect for each similar weapon, so this is quite an uncommon operator, but if made to work could work wonders for consistency. + +## Advanced + +In addition to the running value, you have an access to a buffer with 16 "slots" whither you can save values for later use. +Other than allowing complex math, these let you reuse a value for multiple components of a vector (across the `,` boundary which normally resets the running value). +There are also some operators that involve more complex values than just addition. + +### Yank (`y`), add (`a`), and multiply (`x`) + +The `y` operator saves ("yanks") the current running value to the buffer under given index, and resets the running value to 0. +The `a` operator adds to the current running value from given buffer. +The `x` operator multiplies the running value by the value of given buffer. + +Examples: + * `10 r20 y7 5 r10 x7`. Rolls a random value 10-30 (see earlier lesson), saves it to buffer #7 (which resets running value to 0), rolls a different one 5-15, then multiplies it by the value of the contents of buffer #7 (i.e. the previous roll). The `foo yN bar xN` pattern is how you multiply things in general. + * `r10 y0 a0, 0, a0`. Rolls a value, saves it, loads it right back because of the reset. Reuses the value for the third component of the vector. This is how you can get diagonal values. + +### Sinus (`s`) + +The `s` operator treats its operand as an amplitude and the current running value as the phase, and _replaces_ the current running value with the result. +For example `3 s2` is about 0.28, because that's `2 * sin(3 radians)`. + + * only really makes sense with sources of unpredictability such as `r`, `i`, or `d`. + * there is no separate cosinus operator, but you can make a ghetto cosinus via `cos(x) = sin(π/2 + x)`, i.e. just do `1.57 sX` instead of just `sX`. + * good for making circular or spherical volumetric effects (for non-volumetric there's basic spread parameters like `emitRot`). + +### Sawtooth/modulo (`m`) and discretize (`k`) + +The `m` operator applies the modulo operator to the running value. The `k` operator truncates the running value to a multiple of the operand. So: + * `1 k7` is 0, `1 m7` is 1 + * `6 k7` is 0, `6 m7` is 6 + * `7 k7` is 7, `7 m7` is 0 + * `8 k7` is 7, `8 m7` is 1 + * `13 k7` is 7, `13 m7` is 6 + * `14 k7` is 14, `14 m7` is 0 + +### Power (`p`) and power buffer (`q`) + +The `p` operator raises the running value to the operandth power. The `q` operator is similar but takes the power from given buffer. The main use case is probably for getting x² or √x. Examples: + * `3p4` is 81, since that's 3⁴. + * `4y7 3q7` is also 81 (and leaves the 7th buffer slot with the value of 4). + +## Table + +Notation: V is the running value, X is the operand, and B denotes the buffer. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
operatoreffect
(none)V += X
rV += random(0; X)
iV += X * index
dV += X * damage
yB[X] = V
V = 0
aV += B[X]
xV *= B[X]
sV = X * sin(V)
mV = V % X
kV = floor(V / X) * X
pV = VX
qV = VB[X]
,result = V
V = 0
diff --git a/articles/modrules-and-others.markdown b/articles/modrules-and-others.markdown new file mode 100644 index 0000000000..44334f25a8 --- /dev/null +++ b/articles/modrules-and-others.markdown @@ -0,0 +1,39 @@ +--- +layout: post +title: Modrules and (un)related concepts +parent: Articles +permalink: articles/modrules-and-others +author: sprunk +--- + +### Mod options, mod info, mod rules, rules params +These concepts have similar names (which stems from how Recoil games used to be called "mods", even original/standalone ones) +and all deal with customizability in some way, so often get confused with each other. But they are not directly related. +This article will briefly describe all of them in a way that hopefully prevents any ambiguity. + +### Mod info +* metadata about the game's archive. Things like name and version. +* lives in `./modinfo.lua`, hence the name. +* many mature games put `"$VERSION"` as the version. This is a magic value replaced by the Rapid distribution system with the actual version string. Check out Rapid's documentation for specifics. +* this file is both necessary and sufficient for a Recoil game, and its contents can consist of just the `name` entry as well. +* for engine devs: note that in engine internals, modinfo is **not** represented by the `CModInfo` class, that one is actually _mod rules_! Modinfo is a "class 1 meta file" only really referred to in the archive scanner. + +### Mod rules +* a hardcoded set of knobs for tweaking engine behaviour. +* some technical (like the choice of pathfinding system or allocation limits) and some gameplay related (like the resource cost scaling for repairing). +* everything is a single constant global value. No per-unit rules, no changing at runtime, no rules outside the limited set exposed by the engine. +* read from `./gamedata/modrules.lua`, hence the name. Internal engine C++ code stores them in the `CModInfo` class. +* can depend on modoptions. + +### Mod options +* per-match game setup. +* a set of arbitrary key-value pairs supplied by the host; interpretation is solely up to the game. +* usually live in `./modoptions.lua`, but this is just a convention for lobbies (this is where `unitsync` looks). The engine doesn't read this, nor enforce defaults etc. +* usually used for things like enabling custom modes and game setups (add lava, disable units etc.), but also is the technical means for supplying singleplayer mission data. +* maps can suggest and interpret modoptions too, these are often called mapoptions. + +### Rules params +* dynamic per-unit/team or gamewide values. +* arbitrary key-value pairs set and interpreted by the game. +* usually used for storing attributes like "is burning" or "slowdown %" or such. +* can depend on both modoptions and modrules. diff --git a/articles/pathfinding.markdown b/articles/pathfinding.markdown new file mode 100644 index 0000000000..4ee2abc927 --- /dev/null +++ b/articles/pathfinding.markdown @@ -0,0 +1,7 @@ +--- +layout: default +title: Pathfinding +parent: Articles +permalink: articles/pathfinding +published: false +--- diff --git a/articles/select-command.markdown b/articles/select-command.markdown new file mode 100644 index 0000000000..3dc366ca59 --- /dev/null +++ b/articles/select-command.markdown @@ -0,0 +1,210 @@ +--- +layout: default +title: The select command +parent: Articles +permalink: /articles/select-command/ +--- + +# The `select` command + +You can bind the command `select` to a key, in order to define custom selection commands. After select, you can specify a **selector**, that defines *which* units will be selected. + +This selector consists of three parts: `SOURCE+FILTER+CONCLUSION+` + +- *SOURCE*: Which units to choose from. +- *FILTER*: Narrow down the list of units. +- *CONCLUSION*: What to do exactly with the units that were chosen and filtered. + +These three parts are all succeeded by a literal plus sign (`+`), so there is one `+` between *SOURCE* and *FILTER*, one between *FILTER* and *CONCLUSION*, and one after *CONCLUSION*. Do **not** use a space (` `) anywhere in the entire expression. + +For example, `AllMap+_Builder+_SelectAll+` is a valid selector, where: + +- `AllMap` is the *SOURCE* +- `_Builder` is the *FILTER* and +- `_SelectAll` is the *CONCLUSION*. + +Note that there is an **underscore** (`_`) between each element, even if there is already a plus sign (`+`), for hysterical raisins... + +## Source + +The *SOURCE* describes the set of units that you want to filter and pick a selection from. For players, these are restricted your team. It can be one of + +- `AllMap`: All active units on the entire map. +- `Visible`: All active units that are currently visible. +- `PrevSelection`: All units present in previous selection; that is, the one active before you hit the selection key. +- `FromMouse_`: All units that are at most a distance of `` away from the mouse cursor. +- `FromMouseC_`: Same as above, but using a vertical cylinder instead of a sphere. This is good for selecting airplanes or ships on deep water. + +## Filter + +The *FILTER* is an arbitrarily long list of filters. + +Here are the filters. Note that "units" generally means both buildings and mobile units. Typing both got old real quick. + +### `Not` + + Every filter can be preceded by `Not` to negate it. You have to use a `_` to separate the `Not` from the filter, as in `Not_Builder`. + +### `AbsoluteHealth_` + + Keep only units that have an absolute health greater than `` points. + + - `AbsoluteHealth_100`: Keep only units that have **more** than 100 health points left. + - `Not_AbsoluteHealth_100`: Keep only units that have **less** than 101 health points left. + +### `Aircraft` + + Keep only units that can fly. + +### `Builder` + + Keep only units and buildings that can construct. This means Factories, Construction Turrets, Constructors, but not Rezzers. + +### `Buildoptions` + + Keep only units that can build other units or buildings. + +### `Building` + + Keep only buildings, not mobile units. + +### `Category_` + + Keep only units of category `` + +### `Cloak` + + Keep only units that can cloak. + +### `Cloaked` + + Keep only units that are currently cloaked. + +### `Guarding` + + Keep only units that currently have a **Guard** order. + +### `IdMatches_` + + Keep only units whose internal name (unitDef name) matches `` **exactly**. + + - `IdMatches_armcom`: keep only Armada Commanders (internally named `armcom`). + +### `Idle` + + Keep only units that are currently idle, i.e. do not have any active order. + +### `InGroup_` + Keep only units that are in control group ``. + + - `Not_InGroup_`: keep all units that are **not** currently in control group ``. + +### `InHotkeyGroup` + + Keep only units that are in any control group. + + - `Not_InHotkeyGroup`: keep all units that are **not** currently in any control group. + +### `InPrevSel` + + Keep only units of the same type (unitDefID) as any unit in the selection before this `select` command was run. + +### `Jammer` + + Keep only units that have a jammer radius greater than 0. + +### `ManualFireUnit`: + + Keep only units that have a weapon that requires manual firing (currently only the commanders and Armada Thor). + +### `NameContain_` + + Keep only units whose name contains the ``. + +### `Radar` + + Keep only units that have a radar or sonar radius greater than 0. + +### `Resurrect` + + Keep only units that can resurrect other units. + +### `RelativeHealth_` + + Keep only units that have health greater than `` percent. + + Example: + - `Not_RelativeHealth_10`: Keep only units that have less than 10% health. + +### `RulesParamEquals__` + + Keep only units where the `` rules parameter has the exact value ``. + +### `Stealth` + + Keep only units that are stealthy. + +### `Transport` + + Keep only units that can transport other units. + +### `Waiting` + + Keep only units that currently have a **Wait** order. + +### `WeaponRange_` + + Keep only units that have a maximum weapon range greater than ``. + +### `Weapons` + + Keep only units that have any weapons. + + +## Conclusion + +The *CONCLUSION* specifies what to do with the units that are left from the source after running through all the filters. + +If the *CONCLUSION* starts with `_ClearSelection`, your new selection will replace the old one; otherwise, it will just add to it. It must be followed by exactly one of: + +- `SelectAll`: all units +- `SelectOne`: one unit, will also center the camera on that unit. This command remembers which unit was selected, on repeating the selection command, the **next** unit will be selected, so you can cycle through all matching units. +- `SelectClosestToCursor`: one unit, the one closest to the mouse cursor. +- `SelectNum_`: `` units. Repeating this command adds `` more units. +- `SelectPart_`: `` percent of the units. + + +# Examples +Recall that between every two tokens, there must be an underscore `_`, even if there is also a `+`. Another way to put it is that before every word in your selector except the *SOURCE*, there must be an underscore. + +Some examples. Again, "unit" also includes buildings. + +- `AllMap++_ClearSelection_SelectAll+` + + Selects everything on the entire map. + +- `AllMap+_Builder_Idle+_ClearSelection_SelectOne+` + + Selects any (one) idle builder (unit or building) on entire map. Repeatedly running this command will cycle through all idle builders. + +- `AllMap+_Radar+_ClearSelection_SelectAll+` + + Selects all units with radar/sonar/jammer. + +- `AllMap+_Not_Aircraft_Weapons+_ClearSelection_SelectAll+` + + Selects all non-aircraft armed units + +- `AllMap+_InPrevSel+_ClearSelection_SelectAll+` + + Selects all units of any type that was in your previous selection. + + Note that up to now, all keys said `ClearSelection`, hence they replaced your old selection. + +- `AllMap+_InPrevSel_Not_InHotkeyGroup+_SelectAll+` + + Selects all units of any type that was in your previous selection, unless they are already in a hotkey group. + +- `PrevSelection+_Not_Building_Not_RelativeHealth_30+_ClearSelection_SelectAll+` + + From your previous selection, leaves everything that is below 30% health, and not a building. (Use this to quickly retreat damaged units.) diff --git a/articles/team-terminology.markdown b/articles/team-terminology.markdown new file mode 100644 index 0000000000..f2225763f6 --- /dev/null +++ b/articles/team-terminology.markdown @@ -0,0 +1,89 @@ +--- +layout: post +title: Team terminology +parent: Articles +permalink: articles/team-terminology +author: sprunk +--- + +## Overview + +Often players want to play as a team, or conduct diplomacy with each other. +This article aims to explain Recoil's somewhat confusing terminology behind the various team-related entities and how they relate to each other. + +### Allyteam vs team + +What most people would naturally call a team is called an *"allyteam"* in Recoil terminology. +A *"team"* is a single element of an *"allyteam"*. *Teams* are permanently bound to an *allyteam*. + +For example, NATO would be an *allyteam* while USA and UK would be *teams*, because they are separate entities but are in the same alliance, sharing goals and intel. +For modders coming from Supreme Commander, the *team* is what SupCom calls an "army". + +*Teams* each have their own: + * units + * resources + * colour + * starting point + * faction (aka side) + * any other custom extra traits you add. + +*Teams* in the same *allyteam* always share some traits (meaning that, these operate on the level of *allyteams*): + * visibility (this includes sight, other sensors such as radar, but also reading of various unit traits that aren't readable by enemies even in sight, for example mana if a game wants to implement that) + * diplomacy towards other *allyteams* (in particular, all *teams* in an *allyteam* are never hostile to each other) + * victory goals + +### Team vs player + +A *team* is generally controlled by a *player* or an AI. +An AI is not considered a *player* and the interfaces for dealing with AIs are separate to those for dealing with players, +but generally they fill the same role of controlling a *team*. + +Control of a *team* is not exclusive. +In particular, a *team* can be controlled by two or more *players* (or AIs, or a mix thereof) simultaneously (think SC2 Archon Mode). +This is sometimes referred to as "comsharing" in the community for historical reasons. +In that case all of them can exercise control over the team equally. + +Control of a *team* is also not permanent. +*Players* can start controlling a different team (losing control of the previous *team*). +In particular *players* can also control no team at all, in which case they're just spectators. +It is up to the game to let *players* change their *team* to a different one (they cannot do so at will), though they can always become a spectator. + +To go with the analogy above, if the US Army is a *team* then Patton and Eisenhower are *players*: they both have control over the army (simultaneously with each other), and the army itself is generally unaffected by personal changes in the command staff: it is not bound to its generals, but the generals are bound to the army. + +A *team* can also have no controllers. +This usually happens when somebody disconnects, but you can have teams that are uncontrolled by design (for example to have a perspective change in a singleplayer mission, or to have rescuable units). + +### Regular player vs spectator + +Spectators are *players* not controlling any *team*. +They have two modes of spectating, one is a full-view mode where they can see everything, and the other is to spectate as if they were on a particular *team* (meaning their UI will display that team's resources, they will only see what that team sees, etc). +Spectators can change what team they are spectating, and to and from the full-view mode, at will. +The engine also has an option to allow new players to join mid-game (as opposed to regular players reconnecting); such added people always end up as spectators (in particular, this means they will have seen the full state of the game while simulating). + +### Player vs AI + +An AI fulfils a similar role to a *player*, being there to control a *team*. +One difference is that an AI is permanently bound to a *team* and cannot spectate. +The API to deal with AIs is also separate to *players* (so, for example, the function to get all *players* will not return them, and a *team* may look uncontrolled if care is not taken to handle both of its *player* and AI controllers). +There are two main types of AI: Lua AI and Skirmish AI. + +### Lua AI vs Skirmish AI + +A "skirmish" AI is hosted by one of the players and generally acts very similar to a *player*. +It can read the game state via AI interface and works by giving units commands. +Strictly speaking, it is their hosting player relaying commands - this means that this type of AI is subject to lag and will drop if the hosting player quits. +On the other hand, only the host player is taking on the burden of simulating the AI. +There are currently Skirmish AI bindings for C and Java (though distributing the Java runtime environment for a Java skirmish AI is up to the game). +A game does not need explicit support for this kind of AI (meaning for example, somebody can homebrew one), though it will likely want to handle distribution and infrastructure issues (for example to block homebrew AI). + +A Lua AI generally has two components: a piece of game mechanics, and the AI instance itself which is just a handle to tell game mechanics which teams are legal to control. +Since game mechanics have full control over the game state, this type of AI can do things like spawn units on its own (for a sort of PvE experience) . +It can also control teams that aren't explicitly marked for control by the LuaAI handle (for example a LuaAI can be made to automatically control AFK players' teams, or Gaia units - see below). +This type of AI is written in Lua (like all game code), has to be included in the game itself, and the code runs for every player in the game. + +### Gaia + +Gaia is a special *team* that is always present, uncontrolled, and is always in its own *allyteam*. +It is generally meant for ownership of map features such as trees and rocks, but it also can have resources and own units. +This can be used for example for PvE enemies - note that game mechanics still have control an uncontrolled *team* so it is not necessary to have an explicit AI for it. +At the moment there is only one Gaia. diff --git a/articles/unit-defs.markdown b/articles/unit-defs.markdown new file mode 100644 index 0000000000..c23d4248cc --- /dev/null +++ b/articles/unit-defs.markdown @@ -0,0 +1,178 @@ +--- +layout: post +title: Unit defs +parent: Articles +permalink: articles/unit-defs +author: sprunk +--- + +# Unit types basics + +**Each unit in Spring/Recoil belongs to a single type**. +By default, all units of a type are the same as far as most traits (for example health) go. +Units don't necessarily need to fully conform to their type - **most traits can be changed per-unit**. + +This is **similar to other RTS engines**. +For example, a default Starcraft2 marine has 45 health. +Specific marines can actually have 55 health (after an upgrade), or 22 health (with 50% difficulty handicap), or 200 health (if they're the special campaign marine Jim Raynor). +But marines, as a generalized type, have 45 health. +It works **essentially the same way in Recoil**. +Note that the **type itself cannot be modified at runtime**, though you can still easily apply a modified value to every unit of a type. + +The **set of unit types is static**. +You **cannot dynamically add new types**, though you **can generate them beforehand**, including via code. + +The information about a unit type is usually called a **unit def** (from "definition"), and sometimes the type itself is referred to by "unit def" as well. +This article will talk about and compare the two ways that unit defs are often dealt with that are often confused. + +As a general remark, the same notes apply not just to unit types, but also feature types and weapon types and can be applied there directly. + +## Unit def files + +At their simplest, games can provide **a set of simple Lua files with unit defs in the `./units` subfolder**, which **return a table** like this: +```lua +-- ./units/light_tank.lua +return { + light_tank = { + health = 100, + maxVelocity = 1, + requiresSuperSecretResearch = false, + customParams = { flammable = 1, }, + ... + }, +} +``` +The above defines a unit def named "light_tank" with the appropriate stats. +Note that each def **must have a unique name**. + +Note also the keys used inside: `health` and `maxVelocity` are standard and interpreted by the engine, you can find their meanings in the documentation. +**The `customParams` table is somewhat special as it is itself standard but its contents are not**: anything inside (in this case `customParams.flammable`) needs to be handled by the game. +Lastly, `requiresSuperSecretResearch` is non-standard. +We will get back to the non-standard ones later. + +In the example above, the filename matches the single def inside and is basically just a static set of values. +This **is generally the convention** for various reasons (for example it makes it easier for a mod to replace units one by one, and the files can get fairly long), but it **doesn't have to** be the case. +In particular, you **can put multiple units there and have Lua code inside** to generate values, for example: +```lua +-- ./units/various_tanks.lua +local base_tank_health = Shared.base_tank_health +return { + light_tank = { + health = base_tank_health * 1, + maxVelocity = 1, + requiresSuperSecretResearch = false, + customParams = { flammable = 1, }, + ... + }, + heavy_tank = { + health = base_tank_health * 2.5, + maxVelocity = 0.3, + requiresSuperSecretResearch = true, + customParams = { flammable = 0, }, + ... + } +} +``` + +At some point you **might want to post-process** these values. +For example you'd like to try out a sweeping design change, or maybe the match at hand is a custom scenario with different rules. +For those cases, **default engine content lets you supply a file, `./gamedata/unitdefs_post.lua`**, which has access to a `UnitDefs` table with all the defs. +For example, let's say you want to make all units slightly faster, but the healthiest ones more fragile using some arbitrary formula: +```lua +-- ./gamedata/unitdefs_post.lua +for unitDefName, unitDef in pairs(UnitDefs) do + UnitDefs[unitDefName] = lowerkeys(unitDef) +end + +for unitDefName, unitDef in pairs(UnitDefs) do + if unitDef.maxvelocity then + unitDef.maxvelocity = unitDef.maxvelocity * 1.2 + end + + if unitDef.health and unitDef.health > 300 then + unitDef.health = 300 + math.sqrt(unitDef.health - 300) + end + + if unitDef.requiressupersecretresearch then + unitDef.customparams.tech_level_required = 4 + end +end +``` + +First, the `lowerkeys` function. +Maybe some def files defined "maxVelocity" with an uppercase 'V' and some "maxvelocity" with a lowercase 'v', maybe even some used "MAXVELOCITY". +In Lua, these are all different keys. +Calling lowerkeys **makes sure that handling those in post-processing does not become a hassle**. +Some games put the lowerkeys call inside the individual def files as a convention; you also **don't have to do this at all** if you pay attention and don't expect this to be a problem. + +Note that **there are checks** so that calculation only happens if the value is defined, **even for the standard ones** (i.e. `if unitDef.health and...`). +This is because **while the engine does fill in defaults** (so you don't need to define velocity for buildings, for instance) **it does so at a later point**: so far everything is still **just a regular Lua table**. +In particular, you can make use of the fact that an entry is not defined and/or fill it with some default calculated by you. + +Another thing going on here is the handling non-standard entries in the table. +Anything which is not a standard key **is going to be discarded by the engine after this point unless it's inside the `customparams` table**. +This can be useful if you just want to define a helper for post-processing - in particular this can even be something like a function. +`customParams` let you keep non-standard values, but **only allows strings as keys, and strings and numbers as values**. + +There is also a **pre-processing file, `./gamedata/unitdefs_pre.lua`**, which can prepare data **before any def files are read**. +It exposes **a global `Shared` table**, which can be populated there and which can be seen used in one of the examples above. +Use it to propagate reference values to multiple defs without having to redefine them. + +## The `UnitDefs` table inside wupgets + +This is where things get somewhat messy. The engine exposes a table also called `UnitDefs` to wupgets. +However, **this is NOT the same table as the one above**. +The table above gets parsed into internal engine structures and is gone. +The engine exposes a new table with those parsed values. This means that, compared to unit def files: + + * the overall table is **indexed by numerical IDs, not the name**. +So it's (say) `UnitDefs[123]` instead of `UnitDefs["light_tank"]`. +Default engine content provides **a `UnitDefNames` table indexed by the name** though. +The internal name is also **provided in the table under the key `"name"`**. +The majority of **wupget interfaces use the numerical ID**. + + * keys are **not the same**. +For example, metal cost is read as `buildCostMetal` from unit def files, but exposed as `metalCost` in `UnitDefs`. +In particular, they often **have "proper" uppercase even if the post-processing file is all lowercase**. +This may well be **the most common misconception** and mistake when it comes to defs! +Remember, **don't copy-paste keys between unit def files and wupgets** or vice versa. + + * unused values are discarded. +In the example above, `UnitDefs[x].requireSuperSecretTech` (and the lowercase spelling) is `nil`. + + * **values are not the same**. +For example, speed is read as elmos/frame from unit def files, but exposed as elmos/second. +Some values have caps or offsets applied. See the documentation for specifics. + +## Advanced technicalities + +Here's some looser remarks around these topics. + +### Unit def files + +In truth, the engine **only directly reads one file for all def file processing, which is `./gamedata/defs.lua`**. +This file is **provided in basecontent** and for all the various def types (unit, weapon, etc) it loads a pre-processing file, individual legacy def files (TDF, FBI and other Total Annihilation formats), the individual Lua def files under `./units/`, and then the post-processing file. +The practical effect is that you can **customize the loading process somewhat** (load things in a different order, or from elsewhere than `./units/`, etc.) if you don't like the default one. + +A limited number of **wupget interfaces are available** during def loading. +This includes **getters involving the match** in general (map, player roster etc), of which most importantly **mod-options**. +You can use them to customise a match (for example, maybe aircraft fly higher on maps with lava or something like that). + +VFS is also available, **as a game dev you can expose interfaces for modders** or mappers by attempting to load specific files. + +### UnitDefs + +A unitDef is a proxy table with the `__index` meta-method. +**According to measurements** this makes it somewhat **slower than a plain Lua table**, so it might be worth **caching if a wupget mostly uses a single field** from it. + +There is a **defs-editing dev mode where you can edit defs**, toggled via `/editdefs` (requires cheats). +In this mode, changes are done by just **assigning to a unitDef in Lua code**, which **isn't normally possible**. +Keep in mind that there is **no standard widget** yet to allow easy editing, and that **editing the def files will do nothing** +(of course unless you make your editing widget read them, but remember the caveat where the keys and values differ between +unit defs and `UnitDefs`). This mode is **not usable for game logic** and will desync if used in multiplayer. + +There's three **minor differences between `WeaponDefs` and `UnitDefs`/`FeatureDefs`**: + * `WeaponDefs` are 0-indexed while the others are 1-indexed. Beware of `for i = 1, #WeaponDefs do`, this is incorrect! + * **negative weaponDefIDs are valid and mean things like lava or collisions**. Check the `Game.envDamageTypes` table. + * it is possible to iterate over all keys of a unitDef via `for key, value in unitDef:pairs() do`, but this is currently not possible for either weapon or feature defs. + diff --git a/articles/units-of-measurement.markdown b/articles/units-of-measurement.markdown new file mode 100644 index 0000000000..5d8eea376c --- /dev/null +++ b/articles/units-of-measurement.markdown @@ -0,0 +1,55 @@ +--- +layout: post +title: Units of measurement +parent: Articles +permalink: articles/units-of-measurement +author: sprunk +--- + +## Units of measurement + +In addition to standard units of measurement such as seconds or radians, Recoil uses some in-house units that warrant a bit of explanation. + +### Base + + * **frames**. These represent the discrete, fundamental unit of time for simulation purposes. +Everything in a simulation happens between two frames. +Currently, a simulation at x1 speed runs frames at a constant 30 Hz (so a frame is 0.033s). +On the other hand, it can run slower or faster depending on gamespeed (including at thousands Hz when catching up or skipping over a replay). +Therefore, do not use frames to measure time for things that should use wall-clock time (for example interface animations), i.e. use `widget:Update(dt)` over `widget:GameFrame(f)`. +The base frequency value in Hz is available to Lua as `Game.gameSpeed`. +It is currently hardcoded by the engine and not configurable by games (despite being in the `Game` table and not `Engine`). + +* **elmos**. "Elmo" is the name for Recoil's arbitrary unit of distance. It is purposefully underdefined so that each game can have its own sense of scale. +For example, maybe one game is some sort of galactic war and 1 elmo represents 1 parsec, while another game is about a war between bacteria and viruses and 1 elmo is 1 μm. +Most existing content seems to assume it's 1 m or 12.5 cm, or within this order of magnitude, but there is nothing to enforce consistency. +Almost all length/distance values are given in elmos (or derived values such as elmo/s for speed), unless otherwise noted. + +* **arbitrary**: many values, such as mass, are also in arbitrary units that a game could define on its own if it wanted to for world-building reasons. +Unlike the elmo these aren't even named, so they're typically referred to as just, for example, "100 mass", "100 energy", or "100 map hardness". + +### Derived + +* **game square**. The map is divided into a grid of squares. +The high-resolution yardmap grid is in squares, as is the heightmap (height is an interpolation between the corners of a square). +The length of the edge of a game square in elmo is available as `Game.squareSize` to Lua. +It is not configurable by games and is currently hard-coded to 8 (so a 1x1 square is 8x8 elmos). +Note that for map creation, the supplied heightmap represents corners of squares (which is why its size has to be N/8 + 1). +* **footprint square**. Footprints in unit defs are defined in squares of game squares (for historical reasons). +Regular-resolution yardmap is defined per footprint square. +The length of the edge of the footprint square in game squares is available to Lua as `Game.footprintScale` and is currently hard-coded to 2 (so a 1x1 footprint is 2x2 game squares). +* **build square**. The grid to which construction of buildings is aligned. +Similarly to footprints, it's in multiples of a regular game square. +The length of the edge of a build square in elmos is available as `Game.buildSquareSize` to Lua and is currently hard-coded to 16 (which is the same as a footprint square, meaning that except for high-resolution yardmaps you can always fit buildings next to each other tightly). +* **metalmap square**. The metal-map is divided into a grid which covers multiple game squares. +Interfaces such as `Spring.GetMetalAmount` accept the co-ordinates in this unit. +It is available to Lua as `Game.metalMapSquareSize` and its value is currently 16. +Note that for map creation, the supplied metalmap represents the insides of metalmap squares (which is why its size has to be N/16). +* **lobby map size**. This is the size of maps typically shown in lobbies and other such places. +A 1x1 map is 512x512 elmos. +This is merely a convention (though a strong one for historical reasons) and thus is not directly available to Lua (you can derive it via `Game.mapSizeX / Game.mapX` if you have a map loaded, though there isn't much point because `Game.mapX` is already about the only useful value in this unit). +* **slow update**. Some performance-heavy things only happen to units once per slow-update. +A slow-update happens once per 15 frames. +It is a bit of an implementation detail, so it's not directly exposed, though some def entries related to allowing things to run more often are usually capped at the slow-update rate. +* **TA angular unit**. A full circle is 65536 TA angular units. +Used in some unit and weapon def entries - consult defs documentation for specifics. diff --git a/articles/vfs-basics.markdown b/articles/vfs-basics.markdown new file mode 100644 index 0000000000..d4dfd746ae --- /dev/null +++ b/articles/vfs-basics.markdown @@ -0,0 +1,63 @@ +--- +layout: post +title: VFS Basics +parent: Articles +permalink: articles/vfs-basics +author: sprunk +--- + +## VFS basics + +### What is loaded? + +Recoil Engine **loads content from three main places** into its Virtual Filesystem (VFS): the game, the map, and the user's local files. +The game and the map **are specified by the lobby** when launching an instance of Recoil. +**Game content is primary** and it usually decides whether to even load content from the other two, with some exceptions (for example map layout is always taken from the map archive). + +### Archives + +Games and maps **typically come as archives** (a single compressed file). +For development purposes, they can also be **regular folders as long as their name ends with ".SDD"**, though this is **not recommended for production** (for performance reasons). +Archives **can specify dependency** upon other archives, so **if you want to build upon an existing game you don't need to copy-paste its whole contents** (and probably shouldn't). +By default, games live in the `./games/` subfolder of your Recoil folder and maps live in `./maps/`, but a **lobby can specify arbitrary archives**. + +{: .warning } +> At the moment, **files in dependencies are completely overridden** in the VFS and are not accessible. + +The user can also **specify local content folders** which are then loaded from, **if the game allows** that. +By default, the Recoil folder is the read directory. +In this case, there is usually **no archive - loose files are seen by the VFS**. +Of course **an archive can be such loose file** and there are interfaces to load its contents. + +### Sync + +The **game and map are synced**, meaning their contents can be used as **authoritative data related to the simulation**. +Local files are unsynced, so they **cannot even be accessed from synced contexts**. +For example, the game can define that a tank has 100 health. +The game **can give the map an opportunity to modify this**, so for example the map can say the tank has 200 health instead. +But there is no way for local files to modify that further, unit health is part of the game mechanics simulation so the game cannot defer to local files here even if it wants to. +What this means is that **local files are largely for local content like the UI**, and it is generally **safe to assume the VFS is under a game dev's control even if you don't pay attention**, as far as mechanics are concerned. + +### How do I defer to the other content? + +VFS interfaces tend to **expect a _mode_ parameter**, which lets you specify **where to look for and in what order**. +The values are strings so **you can combine them** using the `..` operator. +For example, if you want to include a file from the map but also have a game-side backup, you'd pass `VFS.MAP .. VFS.GAME` to `VFS.Include`. +Since `VFS.RAW` was not passed, any existing loose file with the appropriate name among the user's local files is ignored. + +By paying attention to the VFS mode, you can **prevent loading unwanted content**. +As mentioned above, requesting unsynced modes in synced contexts is also ignored. + +### Loose remarks + +There is a fourth place where content is loaded from, the **basecontent** archive. +The engine **always loads** it and it contains various **bare necessities** for a functional game, such as default water texture or the basic wupget frameworks. +Its content is **entirely optional** and can be avoided via the usual VFS mode interface, though even mature games will usually want to make use of its facilities. + +The engine **can also write files** in addition to reading them. +Unlike multiple read-folders, there is **only a single write-folder** (defaults to the Recoil folder). +Writing is done by general Lua interfaces such as `io` and `os`, not `VFS`. + +A somewhat unorthodox way to pass (synced) content is **via modoptions**. +Modoptions can **contain data** that gameside code can act upon, and if you're brave enough you can even **pass Lua code** as a modoption to be excuted. +This is one of the ways to let people **run their local files in a synced way**, by just forwarding them as modoptions. diff --git a/assets/css/just-the-docs-themes.scss b/assets/css/just-the-docs-themes.scss new file mode 100644 index 0000000000..b6fd209f28 --- /dev/null +++ b/assets/css/just-the-docs-themes.scss @@ -0,0 +1,83 @@ +--- +--- + +{% if site.logo %} +$logo: "{{ site.logo | relative_url }}"; +{% endif %} +@import "./support/support"; +@import "./custom/setup"; + +@import "./color_schemes/light"; +@import "./modules"; +{% include css/callouts.scss.liquid color_scheme = "light" %} + +html[data-theme="dark"] { +@import "./color_schemes/dark"; +@import "./modules-nocharset"; +{% include css/callouts.scss.liquid color_scheme = "dark" %} +} + +// fix for search using class in html tag +html[data-theme="dark"].search-active { + .search { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 0; + } + + .search-input-wrap { + height: $sp-10; + border-radius: 0; + + @include mq(md) { + width: $search-results-width; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + } + } + + .search-input { + background-color: $grey-dk-250; + + @include mq(md) { + padding-left: 2.3rem; + } + } + + .search-label { + @include mq(md) { + padding-left: 0.6rem; + } + } + + .search-results { + display: block; + } + + .search-overlay { + width: 100%; + height: 100%; + opacity: 1; + transition: opacity ease $transition-duration, width 0s, height 0s; + } + + @include mq(md) { + .main { + position: fixed; + right: 0; + left: 0; + } + } + + .main-header { + padding-top: $sp-10; + + @include mq(md) { + padding-top: 0; + } + } +} + +{% include css/custom.scss.liquid %} diff --git a/assets/github-mark-white.svg b/assets/github-mark-white.svg new file mode 100644 index 0000000000..d5e6491854 --- /dev/null +++ b/assets/github-mark-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/github-mark.svg b/assets/github-mark.svg new file mode 100644 index 0000000000..37fa923df3 --- /dev/null +++ b/assets/github-mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/guides/lua-vbo-vao-1.png b/assets/guides/lua-vbo-vao-1.png new file mode 100644 index 0000000000000000000000000000000000000000..981aece9cb3734c8fdf4b5621704a25edaae6df6 GIT binary patch literal 59905 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 literal 0 HcmV?d00001 diff --git a/assets/guides/lua-vbo-vao-2.png b/assets/guides/lua-vbo-vao-2.png new file mode 100644 index 0000000000000000000000000000000000000000..f57b111c6726b16828b9940872f731c9ed21a150 GIT binary patch literal 85689 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%0A-yg9#A|+UR%543pZ1SgYKhia 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 Gm;MEf=jy!x literal 0 HcmV?d00001 diff --git a/assets/guides/lua-vbo-vao-3.png b/assets/guides/lua-vbo-vao-3.png new file mode 100644 index 0000000000000000000000000000000000000000..10933e847503971caa6c826169f6102b8ecd5288 GIT binary patch literal 137537 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 z z$J8$N09v3va5-7+jP)Yme4ALhD)Ldvq`J&bcXvh$01^xZS`o;{w9hes&|3mml4an7 zdgV?6sZ5HxJkWRHA80&a*o#nf<@6M7Ud2T{;

~QKGAt(Tv)yN$on!``|h)FLG0So1Kp4=-=Do`s`ODj< zuW|w2B9KNs#8Gy8z|(6B=Jl~=8xr4ik4wRZSJ|Gv$s0lB=CAD5Vg8nvmz&HxWZA1F zyDuOgG(~j1BY$DuqKy)+VT9jRBN#FL^a7yi@4dPdhGJH&*=~gE#O3Vl4wo^2uM-nM zs$LImpEuBa+kBe6^o^p#{T7BbPb_Lwy8H0ccPM}bGggD+%CW9~N{h`I=TPUr7nij( zr&VgTvj+8ve9*C>*F+Nc!70PqZU7#QpRr**7yQ5pi&q%r9JF@ZiKSRnSGsI_@H)Fa zzc}BJQ@s*Do`g6hBsM1>;$oVkeAwfZl#3_yZB@+`Y7owJ7TIrHuFraPat%*^40j~P z@99No5?R~iT>RP+-_oMh+G6}#1@d;!yWy}ay`i_~UFHXkIa+$-nI86Rn8-(a;VV*0 z_ufYB)8yv(eXZv@P^J!vxyaWu>13Gh{JvS)@^Yw?WGi^#64N^LAZz|sZ_x7jG?KKk zd~rHAt77j%9X7t#Lm*k$KF}W#=^eF@5mLjjq1UdZgM5w*H#!g59&)jx-}Sz=K#jYG z3Or|1%4j!2G+mk|{-PbA<{HX$kuYX}ra$o7-rO}9{L#>b4p0y}G$@4JR@ zb$p1;EuJd*`0;~n+iT9FpJ5_v8R$Tnt<^8j6`K90Y&3E47--BG)Wom`$m<*k2O!_$ z1`-?zRW;%I2pw)tpTHe~?Opug;ZCi>TEC$+WriPcNJoRoZb*)^r-mW7obO8XqV?>X zi!C=;BP4aBtn`+}J-o#=>lBH)Qw@Ik_n%0DN!$1$APFF!^Q~h&bp;9Z?%r|5!Cu#a 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 literal 0 HcmV?d00001 diff --git a/assets/guides/lua-vbo-vao-4.png b/assets/guides/lua-vbo-vao-4.png new file mode 100644 index 0000000000000000000000000000000000000000..b4d2b6d914d62cdc9f46f1b219d28a026c73ca5c GIT binary patch literal 89526 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

Cohdes*(%r2g*zbbf? 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 a-~Sb|w*S04S*Dl)2s~Z=T-G@yGywox1T9qn literal 0 HcmV?d00001 diff --git a/assets/js/theme-switcher.js b/assets/js/theme-switcher.js new file mode 100644 index 0000000000..88354f197d --- /dev/null +++ b/assets/js/theme-switcher.js @@ -0,0 +1,58 @@ +const storageKey = 'theme-preference' + +const onClick = () => { + // flip current value + theme.value = theme.value === 'light' + ? 'dark' + : 'light' + + setPreference() +} + +const getColorPreference = () => { + if (localStorage.getItem(storageKey)) + return localStorage.getItem(storageKey) + else + return window.matchMedia('(prefers-color-scheme: dark)').matches + ? 'dark' + : 'light' +} + +const setPreference = () => { + localStorage.setItem(storageKey, theme.value) + reflectPreference() +} + +const reflectPreference = () => { + document.firstElementChild + .setAttribute('data-theme', theme.value) + + document + .querySelector('#theme-toggle') + ?.setAttribute('aria-label', theme.value) +} + +const theme = { + value: getColorPreference(), +} + +// set early so no page flashes / CSS is made aware +reflectPreference() + +window.onload = () => { + // set on load so screen readers can see latest value on the button + reflectPreference() + + // now this script can find and listen for clicks on the control + document + .querySelector('#theme-toggle') + .addEventListener('click', onClick) +} + +// sync with system changes +window + .matchMedia('(prefers-color-scheme: dark)') + .addEventListener('change', ({matches:isDark}) => { + theme.value = isDark ? 'dark' : 'light' + setPreference() + }) diff --git a/assets/matrix-logo-white.svg b/assets/matrix-logo-white.svg new file mode 100644 index 0000000000..900a5aa0ed --- /dev/null +++ b/assets/matrix-logo-white.svg @@ -0,0 +1,18 @@ + + + + matrix logo white + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/matrix-logo.svg b/assets/matrix-logo.svg new file mode 100644 index 0000000000..e458d1d5d6 --- /dev/null +++ b/assets/matrix-logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/changelogs.markdown b/changelogs.markdown new file mode 100644 index 0000000000..467a670b25 --- /dev/null +++ b/changelogs.markdown @@ -0,0 +1,10 @@ +--- +layout: default +title: Changelogs +nav_order: 6 +has_children: true +permalink: changelogs +--- + +# Changelogs +{: .no_toc } diff --git a/changelogs/changelog-105-1214.markdown b/changelogs/changelog-105-1214.markdown new file mode 100644 index 0000000000..f7a3e5ee20 --- /dev/null +++ b/changelogs/changelog-105-1214.markdown @@ -0,0 +1,88 @@ +--- +layout: post +title: Release 105-1214 +parent: Changelogs +permalink: changelogs/changelog-105-1214 +author: sprunk +--- + +The changelog since release 105-966 **until release 105-1214**, which happened in October 2022. + +## Caveats +* there is now only one `UnitUnitCollision` event for each unit pair, and return values from UnitUnitCollision are now ignored! +* `vsync` springsettng now defaults to -1 +* ships now obey `upright = false` when pulled out of water (still always upright when floating). +* killed most of ARB shader fallbacks + +## Features and fixes + +### Unit collisions +* multi-threaded unit steering and collisions. +* there is now only one `UnitUnitCollision` event for each unit pair, and return values from UnitUnitCollision are now ignored! +* added modrule, `movement.groundUnitCollisionAvoidanceUpdateRate`, for controlling steering performance vs quality tradeoff load. Reduce to get better quality at the cost of perf. Default value is 3 for cycling through all units over 3 sim frames. +* added modrule, `movement.unitQuadPositionUpdateRate`. Similar perf tradeoff to the above, but affects collision accuracy (incl. with projectiles). In particular, if this value isn't 1 then sometimes beamlasers/lightning can visibly ghost through units. Defaults to 3. +* added modrule, `movement.maxCollisionPushMultiplier`, limits the speed (as a multiplier relative to their base speed) units can push each other at. Defaults to infinity/unlimited. + +### Particles +* add animated "flipbook" CEGs: `animParams = "numX, numY, animLength"`. Enabled for BitmapMuzzleFlame, HeatCloudProjectile, SimpleParticleSystem and GroundFlash. +* some semi-transparent objects can cast colored shadows +* fixed smoke-trails with a non-standard smoke period +* `/dumpatlas` for now only works with `proj` argument to dump projectiles atlases to disk + +### Units on slopes +* ships now obey `upright = false` when pulled out of water (still always upright when floating). +* added `upDirSmoothing` to unit def so units could update their upward vector smoother than by default +* floating mobiles can be built over seafloor slopes + +### Bugger off! +* add `Spring.SetFactoryBuggerOff(unitID, bool? active, number? distanceFromFactoryCenter, number? radius, number? relativeHeading, bool? spherical, bool? forced) → bool active`. Forced means it also asks push-resistant units to move. Everything is optional. +* add `Spring.GetFactoryBuggerOff(unitID) → active, distance, radius, relativeHeading, spherical, forced`, same units as above. +* add `Spring.BuggerOff(x, y = groundHeight, z, radius, teamID, spherical = true, forced = true, excludeUnitID = nil, excludeUnitDefIDArray = nil) → nil`, for standalone bugger-off in-world (like happens when units stand on a construction site). +* `/debugcolvol` now shows factory bugger off, in cyan. Standalone bugger off not shown. + +### Key press scan codes +* add `Spring.GetPressedScans() → {[scanCode] = true, [scanName] = true, ...}`, similar to `Spring.GetPressedKeys` but with scancodes +* add `Spring.GetKeyFromScanSymbol(scanSymbol) → string keyName` that receives a scancode and returns the user's correspondent key in the current keyboard layout +* add `wupget:KeyMapChanged() → nil` callin for when the user switches keyboard layouts, for example switching input method language. + +### Selection box +* add `Spring.SetBoxSelectionByEngine(bool) → nil`. If set to false, engine won't apply selection when you release the selection box. +* add `Spring.GetSelectionBox() → minX, maxY, maxX, minY` (sic) returning the screen coordinates of the selection box. Nil if not dragging a box. + +### Rendering internals +* lots of engine internals (in particular, fonts) use modern approaches to rendering. Expect speed-ups. +* applied more robust algorithm of culling shadow projection matrix. The net result is that shadows should not disappear any longer on small maps, at oblique camera angles, etc. +* allow skipping the use of Texture Memory Pool to save ~512 MB (by default) of statically allocated memory. Note this might be detrimental due to possible memory fragmentation. See `TextureMemPoolSize` springsettings +* removed most of the sanity checks from window positioning code (reverted back to 105.0 like code). Now the engine won't resist to resizing the window as the user/widget wants. There are still some rules in place, but they shouldn't be too restrictive. +* FontConfig should be more robust upon failure and don't crash that often on FC errors +* fix multiple camera issues. +* fix the hardware cursor on Linux/Wayland. +* fixed incorrect cubemap texture mapping + +### Rendering API +* add `DrawGroundDeferred` callin such that bound g-buffers could be updated from say game side decals renderer. +* projectiles transformation matrices are now available through LuaVBO + +Added the following `GL.` constants: +* `TEXTURE_{1,2,3}D` +* `TEXTURE_CUBE_MAP` +* `TEXTURE_2D_MULTISAMPLE` +* `COLOR_ATTACHMENT{0...15}{,_EXT}` +* `DEPTH_ATTACHMENT{,_EXT}` +* `STENCIL_ATTACHMENT{,_EXT}` + +### Miscellaneous +* add `Spring.GetSyncedGCInfo(bool forceCollectionBeforeReturning = false) → number usage in KiB`. Use from unsynced to query the status of synced memory occupation and force garbage collection +* introduced `RapidTagResolutionOrder` option to control priority of domains when resolving rapid tags in case multiple Rapid mirrors are used at the same time. +* `/dumprng` switch to tap out the state of synced RNG, works similar to `/dumpstate` +* skirmish AI interface: add FeatureDef_isAutoreclaimable +* fix the 1 second pause/freeze players experience when a player or spectator disconnects from the match. +* fix SaveLoad hang in case when AllyTeams > 2 and one or more teams died. +* fix SaveLoad memory leaks. + +## pr-downloader +* add options to override rapid and springfiles url. +* add option to download from Rapid without using `streamer.cgi`, but files directly. See https://github.com/beyond-all-reason/pr-downloader/pull/9 +* improve file IO performance by multithreading it (big performance boost on Windows) +* fix handling of unicode paths on Windows +* fix finding and loading of SSL certificates on multiple Linux distributions (on Windows also switches to system certificate storage) diff --git a/changelogs/changelog-105-1354.markdown b/changelogs/changelog-105-1354.markdown new file mode 100644 index 0000000000..4524f2f50b --- /dev/null +++ b/changelogs/changelog-105-1354.markdown @@ -0,0 +1,54 @@ +--- +layout: post +title: Release 105-1354 +parent: Changelogs +permalink: changelogs/changelog-105-1354 +author: sprunk +--- + +The changelog since release 105-1214 **until release 105-1354**, which happened in November 2022. + +## Caveats +* Ctrl and Alt as camera movement modifiers were unhardcoded and turned into bindings. The engine binds them same as before by default, but if you wipe bindings and handle them on your own then you may want to handle rebinding them. +* `/dynamicSky` command and `AdvSky` springsetting were removed. +* resurrection no longer sets health to 5%. See the "migrating from Spring" guide for a replacement. Note that the Lua function to do this 100% correctly only got added in a further release. +* respect `gl.Color()` in `gl.Text()`. May require taking care that the appropriate colour is set, possibly via inline color codes. + +## Features and fixes + +### Minimap +* new boolean springsetting `MiniMapCanFlip`, default 0. If enabled, flips minimap coordinates when camera rotation is between 90 and 270 degrees (with rotating cameras, or when flipping via `/viewtaflip` with the default non-rotating camera). +* add `Spring.GetMiniMapRotation() → rot`, currently only 0, or π if flipped. +* minimap now allows making labels when cursor is inside, transposed to map location +* new boolean springsetting: `MiniMapCanDraw`, defaults to 0. Enable the other draw events (line/erase) to happen via minimap + +### Camera control +* add `Spring.GetCameraRotation() → rotX, rotY, rotZ`. Also useful for minimap flipping detection. +* Ctrl and Alt as camera movement modifiers were unhardcoded and turned into bindings. The engine binds them same as before by default, but if you wipe bindings and handle them on your own then you may want to handle rebinding them. +* add `movetilt`, `movereset` and `moverotate` actions for previously hardcoded behavior, engine defaults to `Any+ctrl` and `Any+alt` respectively (i.e. previous behaviour). +* make the `InvertMouse` springsetting respected when inverting the "hold middle mouse button to pan camera" functionality + * add configurability of movefast and moveslow speed via added config values (`CameraMoveFastMult`, `CameraMoveSlowMult`) and scaling factors for specific cameras (`CamSpringFastScaleMouseMove`, `CamSpringFastScaleMousewheelMove`, `CamOverheadFastScale`) +* fix `movefast` and `moveslow` actions not being respected in some circumstances. + +### Keys +* accept `keyreload` and `keyload` commands in uikeys +* add `/keydefaults` command, loads the defaults +* accept filename arguments for `keyload`, `keyreload` and `keysave` + +### Skybox +* allow loading skybox from equirectangular 2D texture +* deprecate `AdvSky` springsetting +* remove the obsolete `/dynamicsky` option + +### Miscellaneous +* add `Platform.cpuLogicalCores` and `Platform.cpuPhysicalCores` constants +* new action: `group unset`, removes any group assignment to selected units +* add `Spring.GetTeamAllyTeamID(teamID) → allyTeamID` +* add `Spring.GetProjectileAllyTeamID(projectileID) → allyTeamID` +* add `Spring.SetWindow{Min,Max}imized() → bool success` (also in LuaIntro) +* add `Spring.LoadModelTextures(string modelName) -> bool success` to preload model textures. Returns false if model not found or is 3do. +* add `damage.debris` modrule for debris damage, default 50 (same as previous). +* add `reclaim.unitDrainHealth` modrule, whether reclaim drains health. Mostly for the reverse wireframe method +* add 5th and 6th params to `Spring.MarkerErasePosition`, onlyLocal and playerID. Makes the erase happen locally, optionally as if done by given player, same as the existing interface for MarkerAddPoint and MarkerAddLine. NOTE: 4th arg is currently unused (reserved for radius)! +* fix functionality for `DualScreenMode` setting, it draws on the window area of the left or rightmost display depending on `DualScreenMiniMapOnLeft` setting. Fix engine related issues with view positioning and adds `DualScreenMiniMapAspectRatio` to draw minimap with preserved aspect ratio. +* fixed a crash caused by kicking a player diff --git a/changelogs/changelog-105-1544.markdown b/changelogs/changelog-105-1544.markdown new file mode 100644 index 0000000000..b71dc5339b --- /dev/null +++ b/changelogs/changelog-105-1544.markdown @@ -0,0 +1,90 @@ +--- +layout: post +title: Release 105-1544 +parent: Changelogs +permalink: changelogs/changelog-105-1544 +author: sprunk +--- + +The changelog since release 105-1354 **until release 105-1544**, which happened in February 2023. + +## Caveats +* rebranded the fork to Recoil. Everything where a rename would have technical consequences (`spring.exe` filename, `Spring.Foo` Lua API etc) has been kept as-is. +* `Spring.GetConfig{Int,Float,String}` second parameter can now be `nil`, which means it will return `nil` if the requested setting is not set. Formerly returned `0`, `0`, or `""` respectively. Note that for settings used by the engine the value is never nil (so this is only for custom ones). To get back previous behaviour: +```lua +local originalGetConfigInt = Spring.GetConfigInt +Spring.GetConfigInt = function (key, def) + return originalGetConfigInt(key, def) or 0 +end +-- ditto for Float and String +``` + +## Features and fixes + +### General multi-threading improvements +* main thread is now allowed to move between cores when hyperthreading is unavailable. This helps when a server is running multiple headless or opengl instances. +* `LoadingMT` springsetting no longer accepts -1 for autodetect (which meant 0 for Intel/Mesa graphics drivers and 1 for others) +* add `Spring.Yield() → bool hintShouldKeepCallingYield` to give back OpenGL context from game-loading thread back to main thread to process events and draw with LuaIntro. It's safe to call this regardless of LoadingMT. In practice this means it should be called from unsynced wupget initializers periodically as long as the returned hint value is true, the common implementation is to call it after a wupget is loaded like so: +```lua +local wantYield = true +for wupget in wupgetsToLoad do + loadWupget(wupget) + wantYield = wantYield and Spring.Yield() +end +``` + +### Multi-threading modrules +Note from the future, these were removed after release 1775. +* added `system.pfForceSingleThreaded` to force pathing requests to be sent single threaded. +* added `system.pfForceUpdateSingleThreaded` to force pathing vertex updates to be processed single threaded. +* added `movement.forceCollisionsSingleThreaded` to force collisions system to use only a single thread. +* added `movement.forceCollisionAvoidanceSingleThreaded` to force collision avoidance system to use only a single thread. + +### Debugging improvements +* added boolean springsetting `DumpGameStateOnDesync`. When set to true on the server, it will request all clients to produce a local copy of the current game state (effectively calling `/dumpstate`). Doesn't do anything if set client-side. +* add `/debug reset` to reset the collected debug stats +* added the `/desync` command for non-debug builds +* fixed issue where desyncs could not be detected before the 300th sim frame (10 seconds) + +### Standalone model piece getters +Unlike similar existing functions these don't require a unit/feature instance to exist. +* `Spring.GetModelPieceMap(string modelName) → { body = 0, turret = 1, ... }` +* `Spring.GetModelPieceList(string modelName) → { "body", "turret", ... }` + +### New selectkeys filters +* `Buildoptions` - for units that have a non-zero number of build options (meaning constructors and factories) +* `Resurrect` - for units that can resurrect +* `Cloaked` - for units that are currently cloaked +* `Cloak` - for units of a type that can cloak (regardless of current cloak state) +* `Stealth` - for units of a type that is stealth by default (regardless of current stealth state) +* (note that there is no filter for "currently stealthed" like there is for cloak) + +### Drawing related changes +* add `wupget:DrawPreDecals()` callin +* add `AlwaysSendDrawGroundEvents` boolean springsetting (default false) to always send `DrawGround{Pre,Post}{Forward,Deferred}` events, otherwise/previously they are skipped when non-Lua rendering pipeline was in use. +* add `/drawSky` which toggles drawing of the sky (mostly for performance measurements now) +* Maps with missing/invalid details texture no longer get tint with red. Improved reporting of missing map textures. +* Shadows color buffer can be made greyscale with springsettings `ShadowColorMode = 0` or `/shadows` switches. +* fix Bumpwater rendering on non-NVIDIA drivers + +### Miscellaneous features +* add `Game.metalMapSquareSize` for use with API like `Spring.GetMetalAmount` etc +* add mirrored looping of animated CEG sprites (animates backwards until it reaches the start and then bounces again), enabled by making the animation speed parameter negative (e.g. `animParams = "4,4,-30"`) +* add `Spring.GiveOrderArrayToUnit`, accepts a single unitID and an order array and otherwise works the same as the existing `GiveOrderXYZ` family of functions + +### Miscellaneous fixes +* fix `Spring.GetSelectionBox` not returning nil when there's an active mouse owner (activeReceiver) +* fix multiple issues with movement and pathing quality and performance +* fix a crash on loading a game with Circuit/Barbarian AI. +* when scanning archives (at early loading), the window should no longer be considered frozen/unresponsive by the OS +* `PreloadModels = 0` (non-default) should work correctly now, though it comes with its own set of compromises. + +## pr-downloader +* implement concurrent fetching of multiple mods and maps with single tool invocation +* replace potentially racy `If-Modified-Since` caching with ETags. +* harden downloading rapid packages by saving sdp file only after full successful download +* implement writing `md5sum` files for assets downloaded from springfiles to allow future full game +files validation +* drop lsl from the repo and separate RapidTools into separate repo +* fix resolving of dependent rapid archives +* fix compilation issues under MSVC making some parts of codebase more platform agnostic diff --git a/changelogs/changelog-105-1775.markdown b/changelogs/changelog-105-1775.markdown new file mode 100644 index 0000000000..3a790150fe --- /dev/null +++ b/changelogs/changelog-105-1775.markdown @@ -0,0 +1,100 @@ +--- +layout: post +title: Release 105-1775 +parent: Changelogs +permalink: changelogs/changelog-105-1775 +author: sprunk +--- + +The changelog since release 105-1544 **until release 105-1775**, which happened in June 2023. + +## Caveats +* `Spring.GetSelectedUnits{Sorted,Counts}` no longer returns the `n` inside the table, it's now the 2nd return value from the function +* LuaUI can receive attacker info in `UnitDamaged` and similar, when appropriate. Set them to `nil` in the widget handler (or just don't pass them to widgets) if you don't want this behaviour. +* remove the deprecated `Game.allowTeamColors` entry that was always `true`. +* PNG is now the default `/screenshot` format. +* new Recoil icons and loadscreens. +* Due to the introduction of skinning/bones (see below), the maximum number of pieces per model is limited by 254 pieces +* unit shader changes required related to skinning and bones. This requires updates of code that calls `vbo:ModelsVBO()` such that you'd replace: + ``` + layout (location = 5) in uint pieceIndex; + ``` + with + ``` +layout (location = 5) in uvec2 bonesInfo; // boneIDs, boneWeights +#define pieceIndex (bonesInfo.x & 0x000000FFu) +``` + +## Features and fixes + +### Catching up performance +* CPU usage reserved for drawing and minimum frames draw by second are now configurable via springsettings: `MinSimDrawBalance` which controls the minimum CPU fraction dedicated to drawing; more means more FPS but slower catch-up (defaults to 0.15) and `MinDrawFPS` which controls the minimum desired FPS below which it won't go (defaults to 2). +* fixed how this drawing/simulating proportion interacts with the "slow the game for laggers" feature. + +### Modelling +* added skinning and bones. Not supported for `.s3o` or `.3do`, supported by `.dae` (the other formats supported by the engine are fairly uncommon and untested, but those that can carry bone information should work as well). No extra work needed, bones created by an industry standard tool (for example Blender) should work out of the box. +* shader change is needed, see above in the caveats section. +* allow instanced rendering without instance VBO attached. `gl_InstanceID` can be used to index into an SSBO or used to produce instance attributes algorithmically. +* bump model pool from 2560 to 3840 and log when it gets exhausted +* bump up 3do atlas size (4k^2) +* change default `MaxTextureAtlasSize{X,Y}` springsettings from 2048 to 4096. +* fix 3do shattered pieces rendering (no texture) +* fix AMD / Windows issues with invalid "under-construction" model rendering +* fix invalid asset checksum calculations + +### Terrain rendering +* add the `wupget:DrawShadowPassTransparent() → nil` and `wupget:DrawWaterPost() → nil` callins +* infotexture shaders (F1, F2 etc) are more tolerant to potato drivers +* improved terrain shadow quality and visibility checks. +* add `/debugVisibility` for debugging the visible quadfield quads (for engine devs, mostly useless otherwise) +* add `/debugShadowFrustum` to draw the shadow frustum on the minimap (ditto; also beware, doesn't exactly correspond to the actual camera frustum so probably doesn't have much use outside shadows specifically due to minor bugs) +* fix the overview camera not being centered in 2nd and subsequent games if the terrain is different +* fix bump water and terrain rendering on Intel + +### Selecting units + * add `InGroup_N` filter for selections, to select given control group. For example: `Visible+_InGroup_1+_ClearSelection_SelectAll` + * add `group select` and `group focus` group subactions. Note that the previous `bind X group N` is equivalent to `bind X group select N` + `bind X,X group focus N`. The old `group N` still works. + +### Unit defs: weapon + * add `weaponAimAdjustPriority` numerical tag to weapon (note, NOT weapon def! This is the table inside a unit def, where e.g. target categories are). This is a multiplier for the importance of picking targets in the direction the weapon is already aiming at. Defaults to 1. + * and `fastAutoRetargeting` boolean tag to weapon. Makes the unit acquire a new target if its current ones dies (the tradeoff is the perf cost, and a buff if applies to existing units). Defaults to false (target acquisition check every 0.5s). + +### Unit heading + * changed how unit rotation works. This should make cases like spiders pathing across near-vertical peaks preserve heading better + * add `Spring.Set{Unit,Feature}HeadingAndUpDir(thingID, heading, x, y, z) → nil`, note that the previously existing `Spring.SetUnitDirection` only receives one vector so does not allow setting an object's rotation unambiguously. + +### Pathing +* TKPFS merged into the default HAPFS. +* add a new modrule, `system.pathFinderUpdateRateScale` (default 1.0), to control pathfinder update rate. Note that it gets removed sometime after 1775. +* the pathing overlay (F2) update rate increased x4. +* engine line-move now tries to maintain relative unit position to some extent (so equivalent units don't cross each other). +* fix various pathing quality issues and improve performance. + +### Miscellaneous API changes +* allow shallow recursion in `Spring.TransferUnit` (16 levels deep, same as for other callouts) +* add `Game.footprintScale`, the footprint multiplier compared to defs +* add `Game.buildSquareSize`, the building alignment grid size +* add `system.LuaAllocLimit` modrule to control global Lua alloc limit, default 1536 (in megabytes) +* `Spring.GetPlayerInfo` returns a 12th value, boolean isDesynced. Keep in mind the 11th will be `nil` if you opt out of the customkeys table (i.e. the new 12th value does NOT get "pushed back" to fill the "missing" spot) +* add `Spring.GetFeaturesInScreenRectangle(x1, y1, x2, z2) → {featureID, featureID, ...}`, similar to the existing one for units +* `Spring.SetProjectileCEG` now accepts numerical cegID in addition to CEG name +* add `Game.demoPlayName` to get the filename of the running replay. +* add 7th boolean param to `Spring.MarkerErasePosition`, which makes the command erase any marker when `localOnly` and the current player is spectating. This allows spectators to erase players markers which otherwise they can't do outside of `/clearmapmarks`. +* `Spring.SetActiveCommand(nil)` now cancels the command (previous method of `-1` still works) +* add `StoreDefaultSettings` springsetting, default false. If enabled, settings equal to their defaults will still be saved. This means that `Spring.GetConfigInt` et al does not need to do a nil check for the defaults, but also the defaults won't get automatically updated if they change since they already have a concrete value. +* reimplement Lua mem pools, controlled by the `UseLuaMemPools` springsettings. + +### Miscellaneous +* added Tracy support for debugging. +* default minimum sim speed changed from 0.3 to 0.1 +* add `--list-[un]synced-commands` flag to dump the command list when running the exe directly +* fixed `/iconsAsUI 1` leaking information about dead ghosted buildings. +* fixed piece projectiles (debris flying off from exploding units), and weapon projectiles with `collideFireBase` set to true and no other `collisionX` set to false, failing to collide with units. + +## pr-downloader +* improved performance of verifying if there is an update needed: it now takes ~0.25s on all OSes +* introduce custom X-Prd-Retry-Num to inform server at which retry are we when fetching files +* fixed sdp downloading behavior when all files are already present +* fixed progress bar in presence of redirects and when total download size is >2GiB +* fixed `--disable-all-logging` to actually do that +* fixed the handling of Unicode env vars on Windows diff --git a/changelogs/changelog-105-861.markdown b/changelogs/changelog-105-861.markdown new file mode 100644 index 0000000000..0b99e0bc40 --- /dev/null +++ b/changelogs/changelog-105-861.markdown @@ -0,0 +1,143 @@ +--- +layout: post +title: Release 105-861 +parent: Changelogs +permalink: changelogs/changelog-105-861 +author: sprunk +--- + +The changelog since the fork **until release 105-861**, which happened in February 2022. + +## Caveats +* `wupget:GameProgress` interval 10 → 5 seconds +* basecontent now provides the `treetype0` to `treetype15` features with a model and some customparams +* buildings can be placed inside other buildings' open yardmap gaps +* demos are saved with UTC clock filename (could break filename parsing etc) + +## Features and fixes + +### Icons as UI +* new springsetting `UnitIconsAsUI` and an ingame `/iconsAsUI` command (all below have a `/command` variant without the "Unit"). Set to 1 to make radar icons behave like UI elements instead of in-world objects (e.g. no obscuring by terrain, distance fog, blurring or reflection in the water etc. +* new springsetting `UnitIconScaleUI`. Size scaling for icons when drawn as UI. +* new springsetting `UnitIconsHideWithUI`. Whether icons get hidden via F5. +* new springsettings `UnitIconFadeStart` and `UnitIconFadeVanish`, for making icons fade smoothly + +### Grass +* `Spring.{Add,Get,Remove}Grass` now works even if grass rendering is disabled (also fixes desync) +* `Spring.AddGrass` now has a 3rd param, grass intensity (returned by `Get`; putting 0 equivalent to using `Remove`) + +### Recursion +Allow shallow recursion (up to 16 calls deep) for the following callouts/callins: +* `Spring.{Create,Destroy}{Unit,Feature}` +* `Spring.GiveOrder{,Array}ToUnit{,Array,Map}` + +Additionally: +* `Spring.SpawnExplosion` works inside `Projectile{Created,Destroyed}` + +### Texture Atlases +* add `gl.CreateTextureAtlas(number x, number y, number? allocType, string? atlasName) → string texName`. +`x` and `y` have to be between 256 and the value of the springsetting `MaxTextureAtlasSizeX` (Y respectively). +`allocType` defaults to 0 if not specified. `atlasName` is an optional name for the atlas. +* add `gl.FinalizeTextureAtlas(string id) → bool success`. +* add `gl.DeleteTextureAtlas(string id) → bool success`. +* add `gl.AddAtlasTexture(string id, string luaTex, string? subAtlasTexName)`. Adds texture `luaTexStr` to sub-atlas `subAtlasTextureName` (defaulting to same name as `luaTex` if not specified) of atlas `id`. The lua tex has to be a regular 2D RGBA/UNORM texture. DDS textures can also be put into the atlas. +* add `gl.GetAtlasTexture(string texName, string luaTex) → number s, p, t, q`. Query an atlas texture for the UV coordinates (minU, maxU, minV, maxV) of a texture saved earlier with `Spring.AddAtlasTexture`. + +### Particles +* CEGs from allied projectiles now visible in the fog +* add `/softParticles` toggle and `SoftParticles` springsetting to make particles (esp. groundflashes) clipping into the ground fade a bit instead of having a jagged edge +* add `Spring.SetNanoProjectileParams(r, v, a, randR, randV, randA) → nil`. All params are numbers, and default to 0 when not given. The first three are starting rotation in °, rotation speed in °/s, and rotation acceleration in °/s². The other three are the same but multiplied with a random (-1; +1) before being added to the former, rolled once per particle at the start of its lifetime. +* add `Spring.GetNanoProjectileParams() → r, v, a, randR, randV, randA`, returns the parameters as above. +* add `/drawOrderParticles` command which makes particles obey draw order, supplied in CEG definition under the `drawOrder` key +* add `rotParams` key to `CSimpleParticleSystem` and `CBitmapMuzzleFlame` CEGs, a vector of 3 floats: rotation speed °/s, rotation acceleration °/s², starting rotation in ° + +### Advanced GL4 (shaders, VAO, etc) +* add `gl.GetVAO` which returns an object with a bunch of methods. +* add `gl.GetVBO`. +* add `Spring.GetSelectedUnitsCount` to the shader container (use case: F2 pathmap replacement, can show a general slope map if 0 units selected) +* add `gl.{Unit,Feature}{,Shape}GL4` temporary functions +* added a ton of uniforms for shaders +* add LuaShaders::Set{Unit,Feature}BufferUniforms for GPU side per unit/feature "uniforms" (SSBO in fact) +* gl.Uniform/gl.UniformInt/etc don't require location as a first param, name is fine too. + +### Lua constants for rendering +* add `Platform.glHave{AMD,NVidia,Intel,GLSL,GL4}` bools +* remove `Platform.glSupport24bitDepthBuffer` and add `Platform.glSupportDepthBufferBitDepth` instead +* add the following constants to `GL`: `LINE_STRIP_ADJACENCY`, `LINES_ADJACENCY`, `TRIANGLE_STRIP_ADJACENCY`, `TRIANGLES_ADJACENCY`, `PATCHES` +* add the following constants to `GL`: `[UNSINGED_]BYTE`, `[UNSINGED_]SHORT`, `[UNSINGED_]INT[_VEC4]`, `FLOAT[_VEC4]`, `FLOAT_MAT4` +* add the following constants to `GL`: `ELEMENT_ARRAY_BUFFER`, `ARRAY_BUFFER`, `UNIFORM_BUFFER`, `SHADER_STORAGE_BUFFER` +* add the following constants to `GL`: `READ_ONLY`, `WRITE_ONLY`, `READ_WRITE` +* add a ton of image type specifiers (`RGBA32` etc) to `GL` +* add a ton of barrier bit constants to `GL` + +### Other rendering-adjacent stuff +* most CEGs and weapon visuals are tested for texture validity such that sprites with invalid textures are not displayed. No more need for 1x1 empty texture +* fix skybox stretching and seams (in case it's represented by a cubemap) +* smoother area-command circle, vertices 20 → 100 +* add `Spring.{Set,Get}{Unit,Feature}AlwaysUpdateMatrix` which makes the unit "always update matrix" +* add `/reloadTextures [lua, smf, s3o, ceg]` to reload textures, all groups if none specified. +* filling the nano wireframe works on the current model heights (meaning units with pieces hidden high above but moved downward work correctly) +* add `globalRenderingInfo.availableVideoModes ` +* add `gl.GetFixedState` that returns a bunch of various GL constants and tables, it does a lot depending on args. +* `DeprecatedGLWarnLevel` springsetting default value 2 → 0 (to reduce spam) +* add `gl.AlphaToCoverage(bool enable, bool? force) → nil`, defined only if `GLEW_ARB_multisample` is supported by the platform, and otherwise the func itself is nil; `force` makes it apply even if MSAA level is under 4 +* improve AMD gfx card detection (looks for more strings, eg. "radeon", and in more places) +* add `gl.ClipDistance(number clipID, bool enabled) → nil`, `clipID` is 1 or 2. +* change `TextureMemPoolSize` springsetting default value 256 → 512 MB +* expose `windSpeed` to `Spring.{Get,Set}WaterParams` +* new bumpwater params (defaults): waveOffsetFactor (0.0), waveLength (0.15), waveFoamDistortion (0.05), waveFoamIntensity (0.5), causticsResolution (75.0), causticsStrength (0.08) +* fix sky reflections on the ground (`skyReflectModTex`) + +### Missile smoke trails +* weapon defs: add bool `smokeTrailCastShadow`, number `smokePeriod` (default 8), number `smokeTime` (default 60), number `smokeSize` (default 7), and number `smokeColor` (default 0.7, single value for all three RGB channels tint) to things with smoke trails +* weapon defs: add bool `castShadow`, for the projectile itself + +### Camera tweaks +* add integer springsetting `SmoothTimeOffset`. This attempts to smooth out the TimeOffset parameter that is used to calculated the tweened draw frames. Default 0, old behaviour. Recommended value of 2, this attempts to keep the actualy timeoffset within 90% of the true time. Best with vsync on. +* add boolean springsetting `CamFrameTimeCorrection`. Default false is the current behaviour, use true to get better interpolation during high load. + +### Builders +* new yardmap options for "stacked" buildings +* add `Spring.{Set,Get}UnitBuildParams(unitID, "buildDistance"/"buildRange3D", value) → nil` about unit build range (number) and whether it's spherical (bool) +* add `Spring.GetUnitInBuildStance(unitID) → bool` +* add the `gadget:AllowUnitCaptureStep(capturerID, capturerTeamID, victimID, victimTeamID, progressDiff) → bool` callin +* fix seaplanes being unbuildable on water if they were set to float rather than submerge + +### Other additions to Lua API +* `math.random()` now correctly accepts arguments when parsing defs +* allow `nil` as the first arg to `Spring.SetCameraState` +* `Spring.SetWMIcon` new 2nd arg, bool `force`: ignores the 32x32 icon restriction on Windows +* allow empty argument for `Spring.GetKeyBindings` to return all keybindings +* add `Spring.GetUnitsInScreenRectangle` +* added `Spring.SetWindowGeometry` for easy window positioning. +* add `Spring.ForceTesselationUpdate(bool normalMesh = true, bool shadowMesh = false) → bool isROAM` for ROAM +* parameterless `Spring.GetUnitFlanking()` now has an 8th return value, collected flanking bonus mobility + +### Misc features +* selection keys: add an `IdMatches` filter to use the internal name +* the default pathfinder (set via 0 in modrules) is now multi-threaded. In release 861, the old single-threaded pathfinder is temporarily accessible by setting the modrule to 2, but this gets removed later on in release 1544 when MT issues are fixed. +* add `/setSpeed x` to set game speed directly, still obeys min/max +* add `/endGraph 2` to bring the player back to the menu (1 still quits) +* keybinds: same action with different arguments now differentiated +* added a Load Game button to the raw spring.exe menu +* command cache increased 1024 → 2048 +* native AI interface: add `Feature_getResurrectDef` and `Feature_getBuildingFacing` +* native AI interface: add `spherical` param to `Get{Friendly,Enemy,Neutral,}{Units,Features}{In,}` + +### Misc fixes +* fix CEGs from allied projectiles: now visible in the fog +* fix disk read failures (files that get read failure errors are retried multiple times before giving up) +* fix enabling globallos not revealing unseen terrain changes immediately +* fix height bounds calculation, it now reflects the actual heights rather than the historical min/max (for example if the highest point went 100 → 90 → 110 → 100, previously `Spring.GetGroundExtremes` would return 100 → 100 → 110 → 110) +* fix `Spring.SpawnExplosion` crashing on some valid data +* fixed aircraft using smoothmesh to update if terrain was modified pre-game +* multiple fixes to save/load +* fix spring-dedicated not correctly showing output on Windows when not redirected (spring-headless already worked correctly) +* fix a crash when trying to add enemy units to a control group (e.g. selected via /godmode) +* fix a desync caused by locale-dependent string sorting +* fix a crash trying to load a save done on a map with LuaGaia when currently playing on a map without it +* fix resources sometimes getting into the negative (on the order of 1e-15) due to float inaccuracies; in particular this caused units that cost 0 resources to shoot to be unable to fire due to insufficient resources +* fix "zombie torpedoes" bouncing under the map +* fix projectiles going through units sometimes +* fix the "unload dead unit" synced crash +* probably works on Linux Wayland (implementation doesn't support hardware cursor yet; added in a later release) \ No newline at end of file diff --git a/changelogs/changelog-105-902.markdown b/changelogs/changelog-105-902.markdown new file mode 100644 index 0000000000..a71f970027 --- /dev/null +++ b/changelogs/changelog-105-902.markdown @@ -0,0 +1,41 @@ +--- +layout: post +title: Release 105-902 +parent: Changelogs +permalink: changelogs/changelog-105-902 +author: sprunk +--- + +The changelog since release 105-861 **until minor release 105-902**, which happened in April 2022. + +## Caveats +* Default trees are now provided by basecontent. Chopped engine trees (removed engine tree generators and renderers). Trees have models/textures donated by 0 A.D. so these have outlived their utility. + +## Features and fixes + +### GLDB queries +Add `Spring.MakeGLDBQuery(bool forced) → bool ok` to create a query to the OpenGL drivers database. There's generally only one query at a time allowed, forcing rewrites it. + +Add `Spring.GetGLDBQuery(bool blocking)` to receive the results of the query made with the call above. +Blocking means it will wait for the answer so probably only use it in the lobby and not the game. +Possible returns: +* `nil` if there was no query or the query failed completely +* `false` if it's not ready yet and call isn't blocking +* `true, false` if it finished and drivers don't have issues +* `true, true, number glMajor, number glMinor, string URL, string driver`. + +### Texturing +* engine can load HDR textures (`.hdr` format/extension) with automatic upcasting to FLOAT internal storage format (takes 4x more memory). No user side changes are needed +* LegacyAtlas now produces mipmaps. Previously it never did. +* s3o textures reload fix for Assimp models + +### Defs +* fix unitdef.useFootPrintCollisionVolume. Now the `useFootPrintCollisionVolume` tag takes precedence over the default sphere that appears when `collisionVolumeScales` are zero. +* basecontent `setupdefs.lua` fills `UnitDefs[x].hasShield` correctly +* added modrules to set default flanking min/max damages, though this was already possible (and is better done) via unitdefs_post. + +### Miscellaneous +* add boolean springsetting `RotOverheadClampMap`, default true, disabling it allows the rotatable overhead camera to move outside of map boundaries. +* selection keys: add new filter `Guarding` (first command in the queue is guard) and new count `SelectClosestToCursor` (always a single unit, doesn't work with `SelectNum_X` and doesn't pick the second-closest if appending, etc). +* area-reclaim: always ignore wrecks being rezzed (now the CTRL modifier is only for features with `autoreclaimable = false` in their def; use single-target reclaim for things being rezzed) +* fixed `Spring.TraceScreenRay()` failing to hit terrain diff --git a/changelogs/changelog-105-941.markdown b/changelogs/changelog-105-941.markdown new file mode 100644 index 0000000000..d97c8b5dff --- /dev/null +++ b/changelogs/changelog-105-941.markdown @@ -0,0 +1,25 @@ +--- +layout: post +title: Release 105-941 +parent: Changelogs +permalink: changelogs/changelog-105-941 +author: sprunk +--- + +The changelog since release 105-902 **until minor release 105-941**, which happened in May 2022. + +### Drawing +* enable 3D and cubemaps for luatextures +* `Spring.GetRender{Units,Features}` now support GL4 CUS. +* add `Spring.Clear{Units,Features}PreviousDrawFlag() → nil` +* add `Spring.GetRender{Units,Features}DrawFlagChanged(bool returnMasks = false) → changedIDs[, changedMasks]` + +### Timers + * Add new `Spring.GetTimerMicros() → number`, which gets timers in usec precision + * `Spring.DiffTimers` now takes a fourth arg, if you want usec precision in millisecond numbers, and passed in microsec level timers + +### Miscellaneous +* added a new 'b' designator for yardmaps to declare an area that is buildable, but is not walkable. This allows for the current method of upgradable buildings to create a locking pattern that won't break pathing. +* add `group [subcommand] N` action handlers where subcommand is one of `add`, `set`, `selecttoggle`, `selectadd`, or `selectclear`. This allows for more granular group binding control than `groupN` (which checks for keyboard modifiers in the action). When subcommand is not present, select group N. +* Skirmish AI: call `PostLoad()` after load event and only if `loadSupported != yes` +* accept an integer quality argument in `screenshot` action, as in `screenshot [format] [quality]`. diff --git a/changelogs/changelog-105-966.markdown b/changelogs/changelog-105-966.markdown new file mode 100644 index 0000000000..0ff4549337 --- /dev/null +++ b/changelogs/changelog-105-966.markdown @@ -0,0 +1,58 @@ +--- +layout: post +title: Release 105-966 +parent: Changelogs +permalink: changelogs/changelog-105-966 +author: sprunk +--- + +The changelog since release 105-941 **until minor release 105-966**, which happened in June 2022. + +## Caveats +* removed LOD unit rendering (far 2d sprites) including `/distdraw` command and `UnitLodDist` springconfig entry +* hovercraft are no longer forced to be upright regardless on the terrain slope they are travelling over, they now obey the `upright` unit def. +* the `Up+` modifier in keybinds is now deprecated, a warning is displayed if attempted to bind. No change in behaviour though. + +## Features and fixes + +### Keybinds +* `wupget:KeyPress` and `wupget:KeyRelease` callins receive an additional scanCode parameter. +* `sc_foo` keysets are introduced for scancodes and handled in conjunction with keycode bindings preserving the order on which the actions where bound. `Any+` order is preserved (`Any+` bindings are at the bottom) +* `/keysave` and `/keyprint` now preserve the binding order, providing a better output +* extend `Spring.GetKeyBindings` to receive an additional keyset string to retrieve scancode actions +* add `Spring.GetScanSymbol` callout in a similar fashion to `Spring.GetKeySymbol` +* basecontent wupget handlers are modified to support scancodes. Games that wish to support lua actions via scancodes are recommended to adopt these changes, otherwise behavior should be identical to before. +* fix issue where keysets could be bound to duplicate actions when the action line contained different comments +* fix issue where name retrieval for keycodes would never return a non hex value, this affected the label parameter of KeyPress and KeyRelease callins +* fix issue where `Spring.GetKeyBindings` would return incorrect actions when keychains were bound, e.g. if actions bound to m,n and b,n both would be returned on GetKeyBindings('n') regardless of the previous pressed key + +### Rendering +* add `gl.GetEngineAtlasTextures("$explosions" | "$groundfx") → { texName = {x1, y1, x2, y2}, texName = {...}, ... }`. +* atlasses now have a deterministic order given an identical alphabetical ordering of identically sized textures. This allows Lua construction of pairs of atlasses, e.g. pairs of diffuse and normal maps for multiple decals. + +### Aircraft smooth mesh +* The Smooth Height Mesh will now respond to changes in the height map and recalculate itself over the impacted area. This means aircraft using the smooth mesh will continue to be able to navigate appropriately after extended battles have modified the terrain significantly. +* smooth mesh can now be disabled with the boolean modrule `system.enableSmoothMesh`. + +### Original heightmap +Lua can now change what is considered the "original" heightmap, mostly for random map generators. These new interfaces work the same as the existing ones for the current heightmap. +* `Spring.AdjustOriginalHeightMap(x1, z1[, x2, z2], height) → nil`, adds height. +* Spring.LevelOriginalHeightMap(x1, z1[, x2, z2], height) → nil`, sets height. +* `Spring.RevertOriginalHeightMap(x1, z1[, x2, z2], factor) → nil`, reverts to the "original original" heightmap as defined in the map file; `factor` is a 0-1 value that interpolates between the current and the map file height. +* `Spring.SetOriginalHeightMapFunc(func, arg1, arg2, ...) → number totalChange`, calls a function that can call one of the two functions below. +* `Spring.AddOriginalHeightMap(x, z, height) → newHeight`, can only be called from `Spring.SetOriginalHeightMapFunc` and adds height at given co-ordinates. +* `Spring.SetOriginalHeightMap(x, z, height[, factor= 1]) → heightChange`, can only be called from `Spring.SetOriginalHeightMapFunc` and interpolates height at given co-ordinates towards the given value with given factor. + +Usage example: +```lua +Spring.SetOriginalHeightMapFunc(function(amplitude, period) + for z = 0, Game.mapSizeZ, Game.squareSize do + for x = 0, Game.mapSizeX, Game.squareSize do + Spring.SetOriginalHeightMap(x, z, 100 + amplitude * math.cos((x + z) / period)) + end end +end, 123, 456) -- args to pass (in this case amplitude and period) +``` + +### Miscellaneous +* add `Spring.AddUnitExperience(unitID, delta_xp)`. Can subtract, but the result will be clamped to 0 if negative. +* fixed the `/crash` command to crash properly. diff --git a/changelogs/running-changelog.markdown b/changelogs/running-changelog.markdown new file mode 100644 index 0000000000..b1fe4c5971 --- /dev/null +++ b/changelogs/running-changelog.markdown @@ -0,0 +1,268 @@ +--- +layout: post +title: Running changelog +parent: Changelogs +permalink: changelogs/running-changelog +author: sprunk +--- + +This is the changelog **since version 1775**. + +# Caveats +These are the entries which may require special attention when migrating: + +### Removals +* removed `gl.GetMatrix` and the interface accessible from the returned matrix object. Apparently these were unused, so we offer no replacement guide at the moment. +* removed `spairs`, `sipairs` and `snext`. These have been equivalent to the regular `pairs`, `ipairs` and `next` for years now, use the regular versions instead. +You can replace these functions before migrating, and known existing games have already received patches to do so. +* removed `VFS.MapArchive` and `VFS.UnmapArchive`. They were very sync-unsafe. Hopefully they will be back at some point, but no timeline is available yet. Use `VFS.UseArchive` in the meantime. + +### Behaviour changes +* failure to load a model now results in a crash. This avoids a potential desync down the road. +* QTPFS had a major overhaul, with multiple modrule changes and behaviour changes. See the section below. +* many invalid def entries now cause the unit to be rejected; on the other hand, many (in particular, metal cost and weapon damage) can now be 0. Watch out for division by 0! +Check the "def validity checks" section below for details. +* nanoturret (immobile builder) build-range now only needs to reach the edge of the buildee's radius instead of its center. Mobile builders already worked this way. +* screenshots are postfixed with UTC timestamp instead of number. +* add `SMFTextureStreaming` boolean springsetting, defaults to false. If true, dynamically load and unload SMF Diffuse textures, which saves VRAM, but worse performance and image quality. +Previous behaviour was equivalent to `true`, so if you get VRAM issues try changing it. +* it's now possible to play fixed and random start positions with more teams than the map specifies. +The extras are considered to start in the (0, 0) corner and it is now up to the game to handle this case correctly. +* the `movement.allowGroundUnitGravity` mod rule now defaults to `false`. All known games have an explicit value set, so this should only affect new games. +* `/ally` no longer announces this to unrelated players via a console message. The affected players still see one. +Use the `TeamChanged` call-in to make a replacement if you want it to be public. +* manually shared units no longer receive the Stop command. Use the `UnitGiven` callin to get back the previous behaviour. + +### Deprecation +No changes yet, but these will happen in the future and possibly break things. + +* the `acceleration` and `brakeRate` unit def entries are scheduled for a unit change from elmo/frame to elmo/second. There is no change yet, +but if you prefer not to have to add processing later you might want to change to `maxAcc` and `maxDec` respectively (which will stay elmo/frame). +* the `CSphereParticleSpawner` (alias `simpleparticlespawner`) CEG class is scheduled for removal. It can be entirely drop-in replaced with `CSimpleParticleSystem` (alias `simpleparticlesystem`) +since it has always had the same behaviour, just different internal implementation. Known games using the class will receive PRs before this happens. + +# QTPFS + +The QTPFS pathfinder has received a large overhaul. There are major improvements in both quality (fewer cases of units getting stuck, cutting corners etc.) +and performance (processing speed, memory use, even disk usage). Every facet of QTPFS should generally work better. Try it out! + +* debug path drawer now draws into the minimap, showing the map damage updates waiting to be processed. The more intense the colour, the more layers (MoveTypes) that still need to process the change. +* added modrule, `system.pfRepathDelayInFrames`, which controls how many frames at least must pass between checks for whether a unit is making enough progress to its current waypoint +or whether a new path should be requested. Defaults to 60 (2 seconds). Adjust to find the right balance between how quickly units can get unstuck and how much CPU power is used. +Smaller intervals increase the chance of slow units triggering unnecessary re-pathing requests, but reduces the chance that players may believe a unit is getting stuck and is not handling itself well. +* added modrule, `system.pfRepathMaxRateInFrames`, which controls the minimum amount of frames that must pass before a unit is allowed to request a new path. By default, it is 150 frames (5 seconds). +This is mostly for rate limiting and prevent excessive CPU wastage, because processing path requests are not cheap. +* added modrule, `system.pfUpdateRateScale`. This is a multiplier for the update rate and defaults to 1. Increase to get faster updates but more CPU usage. +* added modrule, `system.pfRawMoveSpeedThreshold`. Controls the speed modifier (which includes typemap boosts and up/down hill modifiers) under which units will never do raw move, +regardless of distance etc. Defaults to 0, which means units will not try to raw-move into unpathable terrain (e.g. typemapped lava, cliffs, water). You can set it to some positive +value to make them avoid pathable but very slow terrain (for example if you set it to 0.2 then they will not raw-move across terrain where they move at 20% speed or less, and will use +normal pathing instead - which may still end up taking them through that path). +* added modrule, `system.pfHcostMult`, a float value between 0 and 2, defaults to 0.2. Controls how aggressively the pathing search prioritizes nodes going in the direction of the goal. +Higher values mean pathing is cheaper, but can start producing degenerate paths where the unit goes straight at the goal and then has to hug a wall. +* removed modrules: `system.pfForceUpdateSingleThreaded` and `system.pfForceSingleThreaded`. Multithreading has shown itself stable. +* removed modrule: `system.pathFinderUpdateRate`, since `system.pfUpdateRateScale` now serves the same general role but has different units. + +# Defs unification + +Unit defs (i.e. `/units/*.lua`) and `UnitDefs` (in wupgets) referring to the same thing under different names and sometimes even different units of measurement has always been a point of confusion. +Some of this has been alleviated, with a unified name being available for many mismatched keys. Usually it's one already existing on either "side" of the divide. + +## New def keys +The following unit def keys now accept the same spelling as the ones exposed via `UnitDefs`. +The old spelling still works (old → new). +* metalUse → metalUpkeep +* energyUse → energyUpkeep +* buildCostMetal → metalCost +* buildCostEnergy → energyCost +* unitRestricted → maxThisUnit +* name → humanName + +These two also accept a new spelling, and both the old and new spellings are in elmo/frame. +However, consider migrating to the new spellings ASAP because the original spellings will be +changed to use elmo/s sometime in the future. +* acceleration → maxAcc +* brakeRate → maxDec + +The following unit def keys now accept a spelling and measurement unit +as the one exposed via `UnitDefs` (old → new). The old spelling still works, +and is still in the old measurement unit. +* maxVelocity (elmo/frame) → speed (elmo/second) +* maxReverseVelocity (elmo/frame) → rSpeed (elmo/second) + +The following unit def keys now accept a new spelling, which hasn't been previously +available in `UnitDefs`, but which has also been added there in this update. +Old spelling still works. +* losEmitHeight → sightEmitHeight +* cruiseAlt → cruiseAltitude + +Added `fastQueryPointUpdate` to weapon (note, this is the entry inside a unit def that also sets target categories and direction; NOT weapon def!). +When enabled, the `QueryWeapon` family of functions in the script is called every frame (instead of every 15 in slow update). This fixes friendly fire for rapid-fire multi-barrel weapons. + +## New `UnitDefs` members +The following `UnitDefs` keys now accept the same spelling as the ones +accepted for unit def files. The old spelling still works (old → new). +* tooltip → description +* wreckName → corpse +* buildpicname → buildPic +* canSelfD → canSelfDestruct +* selfDCountdown → selfDestructCountdown +* losRadius → sightDistance +* airLosRadius → airSightDistance +* radarRadius → radarDistance +* jammerRadius → radarDistanceJam +* sonarRadius → sonarDistance +* sonarJamRadius → sonarDistanceJam +* seismicRadius → seismicDistance +* kamikazeDist → kamikazeDistance +* targfac → isTargetingUpgrade + +The following keys receive a new spelling which hasn't previously been +available for unit defs, but which has also been added in this update. +Old spellings still work. +* losHeight → sightEmitHeight +* wantedHeight → cruiseAltitude + +Added the missing `radarEmitHeight` to UnitDefs. The unit def file key was also already `radarEmitHeight`. + +## Def validity checks + +Some invalid and/or missing defs are now handled differently. + +* negative values for health, (reverse) speed, and metal/energy/buildtime +now cause the unit def to be rejected; previously each was clamped to 0.1 +* negative values for acceleration and brake rate now cause the unit def to +be rejected; previously the absolute value was taken +* values (0; 0.1) now allowed for health and buildtime (0 still prohibited) +* values [0; 0.1) now allowed for metal cost (0 now allowed) +* undefined metal cost now defaults to 0 instead of 1 +* undefined health and buildtime now each default to 100 instead of 0.1 +* weapon `edgeEffectiveness` can now be 1 (previously capped at 0.999) +* unit armor multiplier (aka `damageModifier`) can now be 0 (previously capped at 0.0001) +* damage in weapon defs can now be 0 (previously capped at 0.0001) +* damage and armor can also be negative again (so that the target is healed), +but keep in mind weapons will still always target enemies and never allies, +so avoid using it outside of manually-triggered contexts, death explosions, and such + +### Deprecated UnitDefs removal + +All deprecated UnitDefs keys (who returned zero and produced a warning) have been removed, listed below: +* techLevel +* harvestStorage +* extractSquare +* canHover +* drag +* isAirBase +* cloakTimeout +* minx +* miny +* minz +* maxx +* maxy +* maxz +* midx +* midy +* midz + +# Features and fixes + +### Builder behaviour +* nanoturret (immobile builder) build-range now only needs to reach the edge of the buildee's radius instead of its center. Mobile builders already worked this way. +* fixed builders not placing nanoframes from their maximum range. +* units vacating a build area (aka "bugger off") will now try to use the fastest route out. +* added `Spring.GetUnitWorkerTask(unitID) → cmdID, targetID`. Similar to `Spring.GetUnitCurrentCommand`, but shows what the unit is actually doing, +so will differ when the unit is guarding or out of range. Also resolves Build vs Repair. Only shows worker tasks (i.e. things related to nanolathing). +* `gadget:AllowUnitCreation` now has two return values. The first one is still a boolean on whether to allow creating the unit (no change here). +The new second value is a boolean, if the creation was not allowed, whether to drop the order (defaults to true, which is the previous behaviour). +If set to false, the builder or factory will keep retrying. +* added `Spring.GetUnitEffectiveBuildRange(unitID[, buildeeDefID]) → number`. Returns the effective build range for given builder towards the center of the prospective buildee, +i.e. the same way engine measures build distance. Useful for setting the goal radius for raw move orders. +This doesn't solve all known cases yet (doesn't handle features, or terraform) which are pending a solution; for now, the function returns just the build range if `buildeeDefID` is nil. +* added `Spring.GetUnitIsBeingBuilt(unitID) → bool beingBuilt, number buildProgress`. Note that this doesn't bring new _capability_ because `buildProgress` was already available +from the 5th return of `Spring.GetUnitHealth`, and `beingBuilt` from the 3rd return of `Spring.GetUnitIsStunned`, but it wasn't terribly convenient or intuitive. + +### Rules params +* added player rules params. Controlled by the new interfaces: `Spring.SetPlayerRulesParam`, `GetPlayerRulesParam` and `GetPlayerRulesParams`, +similar to other existing rules params. There's currently two visibility levels, public and private. A notable difference is that the private level +is only visible to that player, not his allyteam, and not even his (comsharing) team; this is partially for technical reasons and can be changed if need be. +Synced and specs see everything. Not yet available to the Skirmish AI interface. +* added boolean value support to rules params, including the new player rules params. +Skirmish AI and the unit rules param selection filter can read them via existing numerical interface as 0 and 1. + +### Map textures +* added `SMFTextureStreaming` boolean springsetting, defaults to false. If true, dynamically load and unload SMF Diffuse textures, which saves VRAM, but worse performance and image quality. +Previous behaviour was equivalent to `true`, so if you get VRAM issues try changing it. +* added `SMFTextureLodBias` numerical springsetting, defaults to 0. In case `SMFTextureStreaming = false`, this parameter controls the sampling lod bias applied to diffuse texture. +* added a 5th integer param to `Spring.GetMapSquareTexture(x, y, lodMin, texName[, lodMax = lodMin])`. It controls the max lod and defaults to the 3rd parameter, +which is now the minimum (instead of being the final value). + +### FFA support +* it's now possible to play fixed and random start positions with more teams than the map specifies. +The extras are considered to start in the (0, 0) corner and it is now up to the game to handle this case correctly. +* `/ally` no longer announces this to unrelated players via a console message. The affected players still see one. +Use the `TeamChanged` call-in to make a replacement if you want it to be public. +* added `system.allowEnginePlayerlist`, defaults to true. If false, the built-in `/info` playerlist won't display. +Use for "anonymous players" modes in conjunction with `Spring.GetPlayerInfo` poisoning, or just to prevent ugliness. +* added `Spring.SetAllyTeamStartBox(allyTeamID, xMin, zMin, xMax, zMax) → nil`, sets that allyteam's startbox edges, in elmos. + +### VFS +* added a 4th boolean parameter to `VFS.DirList` and `VFS.SubDirs`, defaults to false. If set to true, the search is recursive. +* fixed `VFS.SubDirs` applying the passed pattern to the whole paths instead of just the individual folder names in `VFS.RAW` mode. + +### Unit selection +* added `Spring.DeselectUnit(unitID) → nil`. +* added `Spring.SelectUnit(unitID[, bool append]]) → nil`, a single-unit version of `Spring.SelectUnit{Array,Map}` that doesn't require a table. +The unitID can be nil. +* added `Spring.DeselectUnitArray({[any] = unitID, [any] = unitID, ...}) → nil` and `Spring.DeselectUnitMap({[unitID] = any, [unitID] = any, ...}) → nil`. +These are the counterparts to the existing `Spring.SelectUnitArray` and `Spring.SelectUnitMap`. +* the table in `Spring.SelectUnitArray` can now have arbitrary keys. Previously they had to be numbers, but the table did not actually have to be an array. + +### Root pieces +* added `Spring.GetModelRootPiece(modelName) → number pieceID` which returns the root piece. +* added `Spring.GetUnitRootPiece(unitID) → number pieceID` and `Spring.GetFeatureRootPiece(featureID) → number pieceID`, likewise. + +### Colored text +* added an inline colour code `\254`, followed by 8 bytes: RGBARGBA, where the first four describe the following text colour and the next four the text's outline. +* added the `Game.textColorCodes` table, containing the constants `Color` (`\255`), `ColorAndOutline` (the newly added `\254`), and `Reset` (`\008`). + +### Miscellaneous additions +* add `Spring.IsPosInMap(x, z) → bool inPlayArea, bool inMap`. Currently, both of the returned values are the same and just check whether the position +is in the map's rectangle. Perhaps in the future, or if a game overrides the function, there will be cases of limited play area (think SupCom singleplayer +map extension; 0 A.D. circular maps; or just an external decoration area). +* add `Spring.GetFacingFromHeading(number heading) → number facing` and `Spring.GetHeadingFromFacing(number facing) → number heading` for unit conversion. +* added `wupget:Unit{Entered,Left}Underwater(unitID, unitDefID, teamID) → nil`, similar to existing UnitEnteredWater. +Note that EnteredWater happens when the unit dips its toes into the water while EnteredUnderwater is when it becomes completely submerged. +* add new `/remove` cheat-only command, it removes selected units similar to `/destroy` except the units are just removed (no wreck, no death explosion). +* added new startscript entry: `FixedRNGSeed`. Defaults to 0 which means to generate a random seed for synced RNG (current behaviour). +Otherwise, given value is used as the seed. Use for reproducible runs (benchmarks, mission cutscenes...). +* added `Script.DelayByFrames(frameDelay, function, args...)`. **Beware**, it's `Script`, not `Spring`! Runs `function(args...)` after a delay of the specified number of frames (at least 1). +Multiple functions can be queued onto the same frame and run in the order they were added, just before that frame's `GameFrame` call-in. Use to avoid manual tracking in GameFrame. +* added `Spring.GetUnitSeismicSignature(unitID) → number` and `Spring.SetUnitSeismicSignature(unitID, number newSignature) → nil`. +* added `Spring.SetUnitShieldRechargeDelay(unitID, [weaponNum], [seconds]) → nil`. Resets a unit's shield regeneration delay. +The weapon number is optional if the unit has a single shield. The timer value is also optional: if you leave it nil it will emulate a weapon hit. +Note that a weapon hit (both via `nil` here, and "real" hits) will never decrease the remaining timer, though it can increase it. +An explicit numerical value always sets the timer to that many seconds. +* added `GL.DEPTH_COMPONENT{16,24,32,32F}` constants. +* added the following `GL` constants for use in `gl.BlendEquation`: `FUNC_ADD`, `FUNC_SUBTRACT`, `FUNC_REVERSE_SUBTRACT`, `MIN` and `MAX`. +* added `Spring.GetWindowDisplayMode() → number width, number height, number bitsPerPixel, number refreshRateHz, string pixelFormatName`. +The pixel format name is something like, for example, "SDL_PIXELFORMAT_RGB565". + +### Weapon fixes +* fix `Cannon` type weapons aiming at the (0, 0) corner of the world if they can't find a physical firing solution due to target leading +* fix `Cannon` type weapons being too lenient in friendly-fire avoidance when firing over allies +* fix `MissileLauncher` weapons with high `trajectoryHeight` not performing ground and ally avoidance correctly +* fix `MissileLauncher` weapons with high `trajectoryHeight`, zero `turnRate` and high `wobble` having an unstable trajectory and prematurely falling down when firing onto higher elevations +* fix `DGun` weapon type projectile direction (previously shot at an angle that would be valid from the `AimFromWeapon` piece and not the `QueryWeapon` piece) + +### Basecontent fixes +* moved the `cursornormal` cursor from the "Spring cursors" archive to basecontent. The significance +of this is that `modinfo.lua` is now sufficient for an archive to be a valid Recoil game that doesn't crash. +* fixed the initial spawn gadget. +* fixed action handler key press/release events. + +### Miscellaneous fixes +* fixed skirmish AI API getTeamResourcePull (used to return max storage instead). +* `Spring.SetSunDirection` no longer causes broken shadows if you pass an unnormalized vector. +* fixed being unable to drag-select units with `/specfullview 0`. +* fixed weirdly-boned Assimp (`.dae`) models being loaded incorrectly. +* fixed COB `SetMaxReloadTime` receiving a value 10% smaller than it was supposed to. +* fix screenshots saved as PNG having an inflated file size via a redundant fully-opaque alpha channel. diff --git a/development.markdown b/development.markdown new file mode 100644 index 0000000000..96ac79495f --- /dev/null +++ b/development.markdown @@ -0,0 +1,10 @@ +--- +layout: default +title: Development +nav_order: 4 +has_children: true +permalink: development +--- + +# Development +{: .no_toc } diff --git a/development/build-with-docker.markdown b/development/build-with-docker.markdown new file mode 100644 index 0000000000..82e3faafc0 --- /dev/null +++ b/development/build-with-docker.markdown @@ -0,0 +1,139 @@ +--- +layout: post +title: Building with Docker +parent: Development +permalink: development/build-with-docker +author: verybadsoldier +--- + +# Building with Docker + +## Introduction + +There is a docker image available that is based on Ubuntu being able to compile the engine. + +The image can be used as a one-shot command to compile the engine and provide the artifacts by a docker volume but it can also be used as a development environment. + +### Docker Image +There are two ways to obtain the docker image. + +1. Checkout the repository, change into the directory `docker-build` and build the image yourself using the command: `docker build -t springrts-build .`. Additional arguments can be passed to configure the image creation process (see below). + +2. The image is also available on [Docker Hub](https://hub.docker.com/repository/docker/verybadsoldier/springrts-build). It will be auto-downloaded if you use it in regular docker commands like `docker run verybadsoldier/springrts-build:latest build`. So you can replace the image name with `verybadsoldier/springrts-build:latest` in all docker commands described below. +The image on Docker Hub might not be updated at all times but we try to keep it up-to-date as good as possible. + +When building the image the following arguments are available: + +| Parameter| Default | Description | +|:----------:|:-------------:|:------| +| mxe_version | 02852a7b690aa411ce2a2089deea25a7292a33d6 | Version of MXE to use. This can be a commit hash but also a tag or branch name | +| mxe_gcc | gcc11 | Defines which gcc plugin to use in MXE | +| cmake_version | 3.16.* | Defines a CMake version string to be used when installing CMake via `pip` | +| ccache_version | v4.5.1 | Version of ccache to use. This can be a commit hash but also a tag or branch name | + +## Quickstart + +### Building + +To build branch `BAR105` from `https://github.com/beyond-all-reason/spring` (default values) run this command: +```bash +docker run -it springrts-build build +``` + +The output artifacts can be found in a volume linked to the container. Accessible e.g. via the Docker Desktop application. + +### Develop +To start a development environment: +```bash +docker run -it springrts-build dev +``` + +You will get a bash shell with the spring source code checked out ready to make modifications and compile by typing `make` or `cmake --build .`: +``` +---------------------------------------------- +SpringRTS development environment has been set up successfully +Source code directory: /spring +Build directory: /spring/build +---------------------------------------------- + root@e0d3fbe4fffd:/spring/build$ _ +``` + +## General +The image is based on Ubuntu 18.04 so created Linux binaries are runnable on that version and later. Windows binaries are build using a MXE cross-compile environment. + +The image utilizes `ccache` to speedup consecutive compilation processes. It is recommended to reuse the cache data in different containers by configuring the ccache volume accordingly. + +The image can be used with different commands that are described below: +1. `build` +2. `dev` +3. `shell` (just open a bash shell) + +The build process consists of multiple steps. Each step is represented by a shell script and they are run consecutively: + +1. `00_setup.sh` +2. `01_clone.sh` +3. `02_configure.sh` +4. `04_fill_portable_dir_linux-64.sh`and `04_fill_portable_dir_windows-64.sh` +5. `05_fill_debugsymbol_dir.sh` +6. `06_fill_build_options_file.sh` +7. `07_pack_build_artifacts.sh` +8. `08_copy_to_publish_dir.sh` + +## Parameters +Both commands can be configured with these arguments: + +| Parameter| Default | Description | +|:----------:|:-------------:|:------| +| -b | BAR105 | The branch to build from the spring project | +| -u | https://github.com/beyond-all-reason/spring | URL to a Spring Git repository | +| -a | https://github.com/beyond-all-reason | Prefix for the URLs used to clone auxiliary repos. The following URL will e.g. be cloned: https://github.com/beyond-all-reason/BARbarIAn | +| -d | 0 | Dummy mode: to not actually clone or compile but just produce zero-size artifacts +| -e | 1 | Enable ccache +| -c | \ | Configures gcc's `-march` and `-mtune`flag +| -r | -O3 -g -DNDEBUG | CXX flags for RELWITHDEBINFO config +| -f | \ | CXXFLAGS and CFLAGS flags for gcc +| -s | 1 | Enable stripping of symbols from artifacts +| -z | | Enable generation ccache debug data in /ccache_dbg +| -p | windows-64 | Which target platform to setup build for (use "linux-64" or "windows-64") + +### Building (command `run`) + +The container can be started by passing `run` as the first parameter to run the compilation process for one target platform and produce an archive package that will contain the runnable engine with all library dependencies. + +The following directories contain output data and can be used as a volume to access the files: +1. `/publish` - This is the directory the build process will copy all produced artifacts into +2. `/ccache` - The image is using `ccache` to speed up the build process. To make use of the cache you have to run different build runs using the same cache data directory. +2. `/ccache_dbg` - Directory where ccache debug data will be placed + +```bash +docker run -v D:\myspringbuild:/publish -it springrts-build +``` + +### Building from another GitHub Repository + +```bash +Build branch `gl4` from repository at `https://github.com/beyond-all-reason/spring`: +docker run -it springrts-build build -u https://github.com/beyond-all-reason/spring -b gl4 -p linux-64 +``` + +## Development + +The image can also be used as a development environment. When starting the development mode then only the first three steps are executed: +1. `00_setup.sh` +2. `01_clone.sh` +3. `02_configure.sh` + +So the source code will be cloned into the container and the build will be configured using CMake. You will find yourself inside the development shell ready to start the compilation process. +In you started the container with a raw `/bin/bash` shell (didn't use `build` or `dev` command) you can start the dev shell manually by running `dev.sh` with the usual arguments. + +When working in the development shell you can always start the step scripts manually if needed. But be aware that running e.g. `01_clone.sh` will wipe the `/spring` directory completely and create a clean checkout. So make sure to not lose your changes! +As some of the steps will modify shell variables all scripts should be sourced (instead of started regularly), e.g. `. /scripts/01.clone.sh`. + +### Reconfiguring +In case you want to switch the configuration inside the development shell you you can run `00_setup.sh `. + +For example: + +```bash +. /scripts/00_setup.sh -p linux-64 +``` diff --git a/development/build-without-docker.markdown b/development/build-without-docker.markdown new file mode 100644 index 0000000000..413322692f --- /dev/null +++ b/development/build-without-docker.markdown @@ -0,0 +1,229 @@ +--- +layout: post +title: Building without Docker +parent: Development +permalink: development/build-without-docker +author: p2004a +--- + +# Building without Docker + +The [https://github.com/beyond-all-reason/spring/tree/BAR105/docker-build/scripts](scripts) folder is the source of truth and best reference to figure out how to invoke and configure things. + +## Compilation + +It's arguable that compilation of spring for both Linux and Windows is just easier from Linux. So, we will only describe compilation on Linux. +- Windows: There is [WSL](https://docs.microsoft.com/en-us/windows/wsl/) and it works great. +- Linux: To not have to install all the dev dependencies, compilers etc directly in the base system, and for compatibility, you can use [distrobox](https://github.com/89luca89/distrobox) and develop there. It's fine to do it without that, but it's just very convenient. + +This instruction was tested on Debian based system and Arch, but it should also work on all other Linux distributions once you figure out the list of packages to install. + +### Install system dependencies + +#### Debian based systems + +Compilers, basic utilities, and helpful for developing: + +```bash +sudo apt-get install -y cmake g++ ccache ninja-build clang lld git clangd socat \ + python3-pip g++-mingw-w64-x86-64-posix +sudo pip install compdb +``` + +Spring engine dependencies + +```bash +sudo apt-get install -y doxygen libsdl2-dev libdevil-dev libcurl4-openssl-dev \ + p7zip-full libopenal-dev libogg-dev libvorbis-dev libunwind-dev libfreetype-dev \ + libglew-dev libminizip-dev libfontconfig-dev libjsoncpp-dev +``` + +#### Arch + +Compilers, basic utilities, and helpful for developing (except for mingw cross compiler that is instelled for Debian based distros): + +```bash +sudo pacman -S base-devel cmake ccache git openssh ninja lld socat clang python-pip +sudo pip install compdb +``` + +Recoil engine dependencies + +```bash +sudo pacman -S curl sdl2 devil p7zip openal libogg libvorbis libunwind freetype2 glew \ + minizip fontconfig jsoncpp +``` + +And to make sure that openal has some functioning sound backend: + +```bash +sudo pacman -S libpulse +``` + +### Fetch source + +```bash +git clone https://github.com/beyond-all-reason/spring.git +cd spring +git submodule update --init --recursive +# for windows compilation +git clone https://github.com/beyond-all-reason/mingwlibs64.git mingwlibs64 +``` + +### Compilation + +This part is the most annoying: configuring build is done using cmake, and the command lines are quite large. + +#### Toolchains + +First, you should have a few toolchains configured. Toolchains select the compiler and target operating system. You can store them in the `toolchain` directory in the spring repo. Linux toolchains use `lld` linker as it's much faster. + +`toolchain/clang_x86_64-pc-linux-gnu.cmake`: +```cmake +SET(CMAKE_SYSTEM_NAME Linux) +SET(CMAKE_C_COMPILER "clang") +SET(CMAKE_CXX_COMPILER "clang++") +SET(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld") +SET(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld") +SET(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld") +``` + +`toolchain/gcc_x86_64-pc-linux-gnu.cmake`: +```cmake +SET(CMAKE_SYSTEM_NAME Linux) +SET(CMAKE_C_COMPILER "gcc") +SET(CMAKE_CXX_COMPILER "g++") +SET(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld") +SET(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld") +SET(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld") +``` + +`toolchain/gcc_x86_64-pc-windows-gnu.cmake`: +```cmake +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_C_COMPILER "x86_64-w64-mingw32-gcc-posix") +SET(CMAKE_CXX_COMPILER "x86_64-w64-mingw32-g++-posix") +SET(CMAKE_RC_COMPILER "x86_64-w64-mingw32-windres") +SET(WINDRES_BIN "x86_64-w64-mingw32-windres") +SET(CMAKE_DLLTOOL "x86_64-w64-mingw32-dlltool") +SET(DLLTOOL "x86_64-w64-mingw32-dlltool") +``` + +#### CMake command lines + +With cmake we are building outside of the source, so create directory like `builddir-win`, or `builddir-dbg` and inside them we can run cmake invocations. There are plenty of possible configuration so we will just list a bunch that can be used as a starting point. + +In all of them: +- We use Ninja generator, as Ninja is the quickest to actually execute the build process, scan for changes etc. +- Using ccache to make next compilation quicker +- Install dir is simply `install`, so that after configuing build with cmake, you can just run `ninja && ninja install` and get all the files ready for usage in the `install` directory in builddir. + +---- +Basic release with debug info, shared libraries Linux build with GCC: + +```bash +cmake \ + -DCMAKE_TOOLCHAIN_FILE="../toolchain/gcc_x86_64-pc-linux-gnu.cmake" \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O3 -g -DNDEBUG -fdiagnostics-color=always" \ + -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O3 -g -DNDEBUG -fdiagnostics-color=always" \ + -DCMAKE_BUILD_TYPE=RELWITHDEBINFO \ + -DAI_TYPES=NATIVE \ + -DINSTALL_PORTABLE=ON \ + -DCMAKE_USE_RELATIVE_PATHS:BOOL=1 + -DBINDIR:PATH=./ \ + -DLIBDIR:PATH=./ \ + -DDATADIR:PATH=./ \ + -DCMAKE_INSTALL_PREFIX=install \ + -G Ninja \ + .. +``` + +Fast unoptimized debug Linux shared libraries build with Clang and generation of [`compile_commands.json`](https://clang.llvm.org/docs/JSONCompilationDatabase.html) file. +```bash +cmake \ + -DCMAKE_TOOLCHAIN_FILE="../toolchain/clang_x86_64-pc-linux-gnu.cmake" \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_FLAGS_DEBUG="-O1 -g -fcolor-diagnostics" \ + -DCMAKE_C_FLAGS_DEBUG="-O1 -g -fcolor-diagnostics" \ + -DCMAKE_BUILD_TYPE=DEBUG \ + -DDEBUG_MAX_WARNINGS=OFF \ + -DAI_TYPES=NATIVE \ + -DINSTALL_PORTABLE=ON \ + -DCMAKE_USE_RELATIVE_PATHS:BOOL=1 \ + -DBINDIR:PATH=./ \ + -DLIBDIR:PATH=./ \ + -DDATADIR:PATH=./ \ + -DCMAKE_INSTALL_PREFIX=install \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -G Ninja \ + .. +``` + +Windows release with minimal line debug info static cross compilation with mingw64: +```bash +cmake \ + -DCMAKE_TOOLCHAIN_FILE="../toolchain/gcc_x86_64-pc-windows-gnu.cmake" \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_BUILD_TYPE=RELWITHDEBINFO \ + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O3 -g1 -DNDEBUG -fdiagnostics-color=always" \ + -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O3 -g1 -DNDEBUG -fdiagnostics-color=always" \ + -DAI_TYPES=NATIVE \ + -DINSTALL_PORTABLE=ON \ + -DCMAKE_INSTALL_PREFIX:PATH=install \ + -GNinja .. +``` + +---- + +### Source code completion + +In the clang debug above, we also enabled creation of `compile_commands.json` file that can be then used by IMHO the best C++ language server [clangd](https://clangd.llvm.org/). The main problem with cmake generated compilation databases is that it doesn't contain entries for header files. That can be fixed with [compdb](https://github.com/Sarcasm/compdb) utility installed in the beggining. Running from top repo directory: + +```bash +compdb -p builddir-clang/ list > compile_commands.json +``` + +Clangd will then just pick it up. + +If running in distrobox, and with clangd in distrobox, you might need to override clangd invocation in the LSP supporting editor to something like: `distrobox enter --no-tty {container_name} spring -- socat tcp-listen:{port},reuseaddr exec:clangd` + +When developing on Windows, with clangd on Linux, and WSL container mapped to `L:` drive, the invocation might looks like this: `wsl.exe socat tcp-listen:${port},reuseaddr exec:'clangd --path-mappings=L:/home=/home,L:/usr=/usr'`. Only drawback is that ofc `#ifdef _WIN32` blocks won't have completion in such setup. + +Example `spring.sublime-project` for Sublime Text on Linux with [LSP](https://lsp.sublimetext.io/) server pckages: + +```json +{ + "folders": + [ + { + "path": "." + } + ], + "settings": { + "tab_size": 4, + "LSP": { + "clangd": { + "enabled": true, + "command": [ + "distrobox", + "enter", + "--no-tty", + "spring", + "--", + "socat", + "tcp-listen:{port},reuseaddr", + "exec:clangd" + ], + "tcp_port": 0, + "scopes": ["source.c", "source.c++"], + "syntaxes": [ + "Packages/C++/C.sublime-syntax", + "Packages/C++/C++.sublime-syntax", + ], + "languageId": "cpp", + } + } + } +} +``` diff --git a/guides.markdown b/guides.markdown new file mode 100644 index 0000000000..b06af0f4f5 --- /dev/null +++ b/guides.markdown @@ -0,0 +1,10 @@ +--- +layout: default +title: Guides +nav_order: 3 +has_children: true +permalink: guides +--- + +# Guides +{: .no_toc } diff --git a/guides/choose-recoil.markdown b/guides/choose-recoil.markdown new file mode 100644 index 0000000000..9730220f2b --- /dev/null +++ b/guides/choose-recoil.markdown @@ -0,0 +1,43 @@ +--- +layout: post +title: Choose Recoil +parent: Guides +permalink: guides/choose-recoil +author: sprunk +--- + +## Choose Recoil! + +Picking the engine for your game is a very important decision to make. +Here's how Recoil compares to other choices. + +### Why shouldn't I pick a general engine (Unity, Godot, etc)? + * Recoil has **built-in multiplayer RTS facilities**. +This means systems such as pathfinding, targeting, the concept of unit commands, projectile physics, resource system, networking and synchronisation, replays, and many others. +With general engines you'd need to bother integrating these yourself. + * Recoil **embraces open-source**. +The engine is both free and welcoming to modification. +The GPL license means that Recoil games can always share code with each other, though you can still make a successful commercial game: content/assets such as models and maps, or access to your servers, can remain proprietary. + * Recoil **is a platform**. +There's a community of veteran RTS enthusiasts around the project that will gladly help you start out. +Host your budding game on existing servers, reuse existing content, don't worry about issues such as distribution and marketing until your game is mature enough to take them on. + +### My game is heavily inspired by some existing game XYZ, why shouldn't I just mod it? + * Recoil **is an open-source platform**, see above. + * Recoil is **built with modding in mind**. +Most commercial games require you to put in some effort to replace content, and often it is not possible to replace some deeper mechanics without major hackery. +Meanwhile Recoil exposes interfaces for you to do everything you want. + +### I'm making a little Starcraft style mod. Why shouldn't I just use SC2 Arcade? It's also a platform for mods. + * well, perhaps you should! Recoil is oriented towards Total Annihilation style games, and SC2 is still a great platform for modding. **However:** + * Recoil is **constantly being developed**. +Improvements and features are being added over time. +If your game finds a feature missing you can talk to engine developers who will be glad to try and accomodate your needs. + * Recoil doesn't interfere with your **ownership of content**. +Code has to be open-sourced, but full ownership of content is still yours, not Blizzard's. + +### Recoil is just a fork of Spring, why shouldn't I use the original? + * **active and easy to reach maintainers** who are happy to accomodate your game's needs. + * the API (incl. documentation), the feature set, and engine performance have **all improved and keep improving**, check out the changelog. + * most **major Spring games made the move** and are happy with it. + * if you still want to pick Spring, that's fine because **Recoil is very back-compatible so you can easily switch later**. diff --git a/guides/configuration-variables.markdown b/guides/configuration-variables.markdown new file mode 100644 index 0000000000..a8d45355f8 --- /dev/null +++ b/guides/configuration-variables.markdown @@ -0,0 +1,49 @@ +--- +layout: default +title: Configuration Variables +parent: Guides +permalink: /guides/configuration-variables/ +--- + +# Configuration Variables + +Recoil supports configuration variables that can be set during runtime +(with +[`Spring.{Set,Get}Config*`]({{ site.baseurl }}/ldoc/modules/UnsyncedCtrl.html#Engine_Config) +) or via `springsettings.cfg`. + +Here we provide a list of them: + + + + + + + + {% for row in site.data.configs %} + {% assign row_data = row[1] %} + + + + + + {% endfor %} +
NameDescriptionValues
+ + {{ row[0] }} + + {% if row_data["deprecated"] %}

Deprecated

{% endif %} +
+ {{ row_data["type"] | replace: "std::", "" }} {{ row_data["description"] }} + + + (source) + + + + {% if row_data["defaultValue"] %} Default: {{ row_data["defaultValue"] }}
{% endif %} + {% if row_data["minimumValue"] %} Min: {{ row_data["minimumValue"] }}
{% endif %} + {% if row_data["maximumValue"] %} Max: {{ row_data["maximumValue"] }}
{% endif %} + {% if row_data["safemodeValue"] %} Safe Mode: {{ row_data["safemodeValue"] }}
{% endif %} + {% if row_data["headlessValue"] %} Headless: {{ row_data["safemodeValue"] }} {% endif %} +
diff --git a/guides/glossary.markdown b/guides/glossary.markdown new file mode 100644 index 0000000000..41fc917d59 --- /dev/null +++ b/guides/glossary.markdown @@ -0,0 +1,15 @@ +--- +layout: default +title: Glossary +parent: Guides +permalink: /guides/glossary/ +--- + +{% assign ordered_items = site.data.glossary | sort: 'term' %} + +

diff --git a/guides/headless-and-dedi.markdown b/guides/headless-and-dedi.markdown new file mode 100644 index 0000000000..0907d59ea3 --- /dev/null +++ b/guides/headless-and-dedi.markdown @@ -0,0 +1,32 @@ +--- +layout: post +title: Headless and dedicated +parent: Guides +permalink: guides/headless-and-dedi +author: sprunk +--- + +## Overview + +Recoil builds some **extra binaries** that **behave differently** to the primary 'spring.exe' one. +This guide briefly describes what they do and when to use them. + +### Headless + +The headless build **only does the simulation** and does **not do any rendering**. +**Widgets still work** and are the main way to provide input, all rendering-related call-ins and call-outs just do nothing. + +It is **great for automated tasks** such as: + * gathering **data from replays, general analysis**. Spectate a replay, use a widget to gather data. + * simulating **AI vs AI** games (either for AI development, or just to produce something analyzable in conjunction with the above). + * simulate games played on a dedicated binary, to **verify results**. See below. + * be a game server for a multiplayer game, though only **on limited scale** (perhaps for important games like tournaments). See below. + +### Dedicated (aka dedi) + +Simulating games can get fairly heavy, such that a game server would **struggle to simulate more than a handful**. +However, players simulate the game anyway, so **a server technically doesn't need to** - this is the idea behind the dedicated binary. +It only collects and **relays network traffic without running the simulation**. + +Typically, dedicated servers are used for **automated hosting in large games** since they are quite lightweight. +In theory this leaves games without a single source of truth, but **replays are still produced** which can be ran for verification **later, as needed**. diff --git a/guides/lua-vbo-vao.markdown b/guides/lua-vbo-vao.markdown new file mode 100644 index 0000000000..38e71de96d --- /dev/null +++ b/guides/lua-vbo-vao.markdown @@ -0,0 +1,155 @@ +--- +layout: post +title: Lua VBO and VAO +parent: Guides +permalink: guides/lua-vbo-vao +author: lhog +--- + +# Lua VBO and VAO + +## Crash course + +### What is VBO/VAO + +Read excellent intro here: [Hello-Triangle](https://learnopengl.com/Getting-started/Hello-Triangle) + +{: .note-title } +> TLDR +> +> It's a modern and most performant way of loading geometry attributes like position, color, normal vector, texture coordinates and generally any attribute you need to GPU for rendering. + +### What is VBO? + +VBO is simply an array of interleaved data. + +Interleaved means that data of different types go one after another forming an element. + +After the first element comes second element structured in the same way, etc. See: + +![image]({{ site.baseurl }}/assets/guides/lua-vbo-vao-1.png) + +### What types of VBO exist: + +Two main types of VBO are vertex buffer and index buffer. + +Vertex buffer holds vertex data, index buffer holds indices used to index into vertex buffer. + +One canonical example of the use of index buffer is drawing of rectangle. + +Rectangles have 4 vertices, but since GPU draws with triangles, rectangle needs to broken down into triangles. In this case triangles are specified as list of indices referencing vertex buffer to render the rectangle: + +![image]({{ site.baseurl }}/assets/guides/lua-vbo-vao-2.png) + +{: .note } +Use of index buffer is optional, you can skip it, but you will have to duplicate vertex data instead to produce the same two triangles, which is often not desired, especially if you have big geometry. + +One additional more advanced type of VBO is instance buffer. + +Unlike vertex VBO, which defines per-vertex data, instance VBO defines per instance (per shape) data. + +For example you might want to draw exactly the same complex shape N times in N different places, this is where instancing makes sense. You can read more [here](https://learnopengl.com/Advanced-OpenGL/Instancing) + +As said, in Recoil instancing is done by means of instance buffer (alternative implementations are possible by out of scope of this basic tutorial): + +![image]({{ site.baseurl }}/assets/guides/lua-vbo-vao-3.png) + +Here in the example we use instance buffer to offset instances of rectangle in screen space, other possibilities exist too: rotate, re-color, etc. + +### What is VAO + +VAO serves as glue to tie together various VBOs above, description of their type, description of what each individual attribute inside each VBO means: name, size, type, etc. VAO allows one to define attributes completely flexible. + +Usually you want something like position, color, texture coordinates, but you can absolutely skip each one and supply whatever information you need. + +Below the schematic of what VAO is to VBOs: + +![image]({{ site.baseurl }}/assets/guides/lua-vbo-vao-4.png) + +There can be up to 16 input attributes, this number is shared between vertex attributes (mandatory most of the time) and instance attributes (optional). + +## VBO and VAO creation + +```lua +local someVAO = gl.GetVAO() --get empty VAO + +local vertVBO = gl.GetVBO(GL.ARRAY_BUFFER, true) --empty VBO, "GL.ARRAY_BUFFER" means it's either vertex or instance buffer, "true" means this buffer will be optimized by GL driver for frequent updates. Here by the variable name you can guess it's supposed to be vertex buffer + +local instVBO = gl.GetVBO(GL.ARRAY_BUFFER, true) --empty VBO, "GL.ARRAY_BUFFER" means it's either vertex or instance buffer, "true" means this buffer will be optimized by GL driver for frequent updates. Here by the variable name you can guess it's supposed to be instance buffer + +local indxVBO = gl.GetVBO(GL.ELEMENT_ARRAY_BUFFER, false) -- empty index buffer, not going to be frequently updated ("false"). + +vertVBO:Define(1000, { --someVBO is created to hold 1000 "elements", see pics above what element is. If suddenly the number of elements exceeds 1000, the buffer will not accept new data, "someVBO" will need to be remand and rebound to VAO + {id = 0, name = "pos", size = 4}, -- "pos" attribute will hold 4 floats (float is the default type, if "type" is not specified). "id" in the shader must be 0 + {id = 1, name = "color", type=GL.UNSIGNED_BYTE, normalized = true, size = 3}, -- "color" is represented by 3 unsigned bytes (values from 0 to 255), values are normalized (in this case divided by 255 to get float inside shader). "id" in the shader must be 1. This can be useful to hold RGB data. +}) + +instVBO:Define(2, { --reserve space for 2 elements of the type described below + {id = 2, name = "posBias", size = 4}, -- posBias is 4 floats attribute of id = 2, note that ids here and ids of vertVBO cannot duplicate. We will use it to offset instances in space +}) + +indxVBO:Define(2000, GL.UNSIGNED_INT) --defines index buffer with capacity of 2000 elements of type unsigned integer (32 bit integer), other possibilities for type are GL.UNSIGNED_SHORT and GL.UNSIGNED_BYTE, representing 16 bit and 8 bit unsigned integers respectively. If no type is given GL.UNSIGNED_SHORT is the default) - it makes sense as it allows to index 65534 vertices and occupies only 2 bytes per one index. + +--here we attach (glue) VBOs into VAO. Note in theory you can use (and I use sometimes) completely empty VAO (no attached buffers), but most often you will want to attach (and create before) at least vertex buffer. +someVAO:AttachVertexBuffer(vertVBO) --note vertVBO and instVBO were created with the same command (except for definition), the only way to tell apart instance buffer from vertex buffer is to see what command was used to attach the VBO to the VAO. +someVAO:AttachInstanceBuffer(instVBO) +someVAO:AttachIndexBuffer(indxVBO) +-- only one attachment of certain type can be made. E.g. you can't attach two vertex buffers. +``` + +## Uploading VBO data to VBOs +Now we have VBOs structure defined. Time to upload some useful data, that will later be used to draw stuff. +```lua +local vertexData = { + -- element #1 + 0, 0, 0, 1, --this goes into "pos" + 127, 0, 0, --this goes into "color" + -- element #2 + 1, 1, 1, 1, --this goes into "pos" + 127, 127, 0, --this goes into "color" + -- element #3 + 1, 0, 0, 1, --this goes into "pos" + 127, 127, 127, --this goes into "color" + -- etc +} +vertVBO:Upload(vertexData) + +local instanceData = { + -- element #1 + 100, 100, 0, 1, --this goes into "posBias" + -- element #2 + 100, 200, 0, 1, --this goes into "posBias" + -- element #3 + 200, 100, 0, 1, --this goes into "posBias" + -- etc +} +instVBO:Upload(instanceData) + +local indexData = { + 0, 1, 2, --one triangle + 1, 2, 3, --second triangle + -- etc +} +indxVBO:Upload(indexData) +``` +Here I'm showing very basic upload use. All data is uploaded in one go. This is recommended on initial upload or in case your data is static. +Upload() has tons of options to upload only selected attribute, do partial upload, etc: +Upload(tableData, optionalAttribIdx, optionalElementOffset, optionalLuaStartIndex, optionalLuaFinishIndex). +Ask for extended description when you master basic upload! + + +### Drawing with VAOs +```lua +---somewhere in widget:Draw...() + +-- draw WITHOUT index buffer (index buffer is not needed and won't be used if attached) +gl.UseShader(someShader) --yes, you need a shader. No, without shader you won't see a pixel +someVAO:DrawArrays(GL.TRIANGLES, numberOfElements, firstElementIndex, numberOfInstances, firstInstanceIndex) --GL.TRIANGLES means every 3 element in vertex buffer are used to output a triangle. Besides GL.TRIANGLES you can draw with points, lines, stripes, and tons of other stuff. See https://docs.gl/gl4/glDrawArrays , the rest of options are optional and self descriptive +gl.UseShader(0) + + +-- draw WITH index buffer (index buffer must be attached to VAO) +gl.UseShader(someShader) --yes, you need a shader. No, without shader you won't see a pixel +someVAO:DrawElements(GL.TRIANGLES, numberOfIndices, indexOfFirstIndex, numberOfInstances, baseVertex) --GL.TRIANGLES means every 3 element in index buffer are used to index into vertex buffer to output a triangle. Besides GL.TRIANGLES you can draw with points, lines, stripes, and tons of other stuff. See https://docs.gl/gl4/glDrawElements , the rest of options are optional and mostly self descriptive +gl.UseShader(0) +``` diff --git a/guides/synced-commands.markdown b/guides/synced-commands.markdown new file mode 100644 index 0000000000..ac2e1ef432 --- /dev/null +++ b/guides/synced-commands.markdown @@ -0,0 +1,47 @@ +--- +layout: default +title: Synced Commands +parent: Guides +permalink: /guides/synced-commands/ +--- + +# Synced Commands + +Game developers and players can issue synced commands from chat, e.g. +("/give unit"), or `Spring.SendCommands`: + +Here we provide a list of them, some commands require cheats enabled ("/cheat"): + + + + + + + + {% for row in site.data.synced_commands %} + {% assign row_data = row[1] %} + + + + + + {% endfor %} +
NameDescriptionArguments
+ + {{ row[0] }} + {% if row_data["cheatRequired"] %}

Cheat

{% endif %} +
+
+ {{ row_data["description"] | xml_escape | textilize }} + +
+ {% for arg in args %} +
+ {{ arg[0] | xml_escape | textilize }} +
+
+ {{ arg[1] | xml_escape | textilize }} +
+ {% endfor %} +
+
diff --git a/guides/unsynced-commands.markdown b/guides/unsynced-commands.markdown new file mode 100644 index 0000000000..1cd38c93c4 --- /dev/null +++ b/guides/unsynced-commands.markdown @@ -0,0 +1,48 @@ +--- +layout: default +title: Unsynced Commands +parent: Guides +permalink: /guides/unsynced-commands/ +--- + +# Unsynced Commands + +Game developers and players can issue unsynced commands from chat, e.g. +("/showmetalmap") or `Spring.SendCommands`. + +Here we provide a list of them, some commands require cheats enabled ("/cheat"): + + + + + + + + {% for row in site.data.unsynced_commands %} + {% assign row_data = row[1] %} + {% assign args = row_data["arguments"] %} + + + + + + {% endfor %} +
NameDescriptionArguments
+ + {{ row[0] | xml_escape | textilize }} + {% if row_data["cheatRequired"] %}

Cheat

{% endif %} +
+
+ {{ row_data["description"] | xml_escape | textilize }} + +
+ {% for arg in args %} +
+ {{ arg[0] | xml_escape | textilize }} +
+
+ {{ arg[1] | xml_escape | textilize }} +
+ {% endfor %} +
+
diff --git a/guides/weapondefs.markdown b/guides/weapondefs.markdown new file mode 100644 index 0000000000..13ad803fb7 --- /dev/null +++ b/guides/weapondefs.markdown @@ -0,0 +1,40 @@ +--- +layout: default +title: Weapon Defs +parent: Guides +permalink: /guides/weapon-defs/ +--- + +# Weapon Defs + +Here we provide a list of engine defined weapondefs: + + + + + + + + {% for row in site.data.weapondefs["WeaponDefs"] %} + {% assign row_data = row[1] %} + + + + + + {% endfor %} +
NameDescriptionValues
+ + {{ row[0] }} + + {% if row_data["deprecated"] %}

Deprecated

{% endif %} +
+ {{ row_data["type"] | replace: "std::__cxx11::basic_string, std::allocator >", "string" | xml_escape | textilize }} {{ row_data["description"] }} + + {% if row_data["fallbackName"] %} Fallback: {{ row_data["fallbackName"] }}
{% endif %} + {% if row_data["defaultValue"] %} Default: {{ row_data["defaultValue"] | join: ", " }}
{% endif %} + {% if row_data["minimumValue"] %} Min: {{ row_data["minimumValue"] }}
{% endif %} + {% if row_data["maximumValue"] %} Max: {{ row_data["maximumValue"] }}
{% endif %} + {% if row_data["scaleValue"] %} Scale Value: {{ row_data["scaleValue"] }}
{% endif %} + {% if row_data["scaleValueString"] %} Scale String: {{ row_data["scaleValueString"] }}
{% endif %} +
diff --git a/guides/widgets.markdown b/guides/widgets.markdown new file mode 100644 index 0000000000..8f1e71d225 --- /dev/null +++ b/guides/widgets.markdown @@ -0,0 +1,7 @@ +--- +layout: default +title: Widgets +parent: Guides +permalink: guides/widgets +published: false +--- diff --git a/index.markdown b/index.markdown new file mode 100644 index 0000000000..ef4208673a --- /dev/null +++ b/index.markdown @@ -0,0 +1,88 @@ +--- +layout: default +title: Home +nav_order: 1 +description: "Recoil is an RTS engine designed for game flexibility and large scale." +permalink: / +--- + +# Design large scale RTS games +{: .fs-9 } + +Recoil is a battle tested open-source RTS engine that, allied with a flexible +Lua API, allows you to implement the perfect UI and mechanics for your game +with the ability to support thousands of complex units simultaneously. + +Some of the games powered by Recoil: [Beyond All Reason], [ZeroK], [TA Prime] +and [Metal Factions]. + +{: .fs-6 .fw-300 } + +[Get started now](#getting-started){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } +[View it on GitHub][Recoil repo]{: .btn .fs-5 .mb-4 .mb-md-0 } + +--- + +{: .warning } +> Recoil is a recent hard fork of [Spring] from the [105 tree], many references +to it might and will be present. Overall most documented Spring API and +tutorials are compatible with Recoil since they are based on the [105 tree]. + +## Getting started + +{: .note } +This site is an early work-in-progress so content will mostly be references to +Spring documentation until its own guides are written. + +References: + +- [Spring Wiki] +- [Recoil Lua API] +- [Recoil Github Wiki] + +### Download + +The latest stable release is `{{site.data.latest_release.name}}` available at: + +{% assign releases = site.data.latest_release.assets | where_exp: "asset", "asset.browser_download_url contains 'minimal-portable'" %} + +{% for rel in releases %} +- [`{{rel.name}}`]({{rel.browser_download_url}}) +{% endfor %} + +See the [release page]({{site.data.latest_release.html_url}}) for more options. + +## Contributing + +See [Development](development.markdown) for guides on how to build and +develop Recoil. + +When contributing to this repository, please first discuss the change you wish +to make via [GitHub issues], our [Matrix Room] or any other method with the +owners of this repository before making a change. + +### Thank you to the contributors of Recoil! + +
    +{% assign contributors = site.data.non_coder_contributors | concat: site.github.contributors %} +{% assign contributors_size = contributors | size %} +{% assign shuffled_contributors = contributors | sample: contributors_size %} +{% for contributor in shuffled_contributors %} +
  • + {{ contributor.login }} +
  • +{% endfor %} +
+ +[Recoil repo]: {{site.gh_edit_repository}} +[GitHub issues]: {{site.gh_edit_repository}}/issues +[Beyond All Reason]: https://beyondallreason.info +[ZeroK]: https://zero-k.info +[Spring]: https://github.com/spring/spring +[Metal Factions]: https://metalfactions.pt +[TA Prime]: https://www.fluidplay.co/tap.html +[105 tree]: https://github.com/spring/spring/releases/tag/105.0.1 +[Matrix Room]: https://matrix.to/#/#recoil-rts:matrix.org +[Spring Wiki]: https://springrts.com/wiki/Main_Page +[Recoil Lua API]: {{site.baseurl}}{% link lua-api.md %} +[Recoil Github Wiki]: {{site.gh_edit_repository}}/issues diff --git a/ldoc/.gitkeep b/ldoc/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lua-api.md b/lua-api.md new file mode 100644 index 0000000000..bf947310d8 --- /dev/null +++ b/lua-api.md @@ -0,0 +1,20 @@ +--- +layout: default +title: Lua API +nav_order: 5 +has_children: true +has_toc: false +permalink: lua-api +--- + +# Lua API +
+{% for pagey in site.pages %} +{% if pagey.parent == 'Lua API' %} +
+{{ pagey.title }} +
+
{{ pagey.description }}
+{% endif %} +{% endfor %} +
diff --git a/migrating-from-spring.markdown b/migrating-from-spring.markdown new file mode 100644 index 0000000000..7efb997ac2 --- /dev/null +++ b/migrating-from-spring.markdown @@ -0,0 +1,222 @@ +--- +layout: default +title: Migrating from Spring +permalink: /migrating-from-spring/ +nav_order: 5 +--- + +# Migrating from Spring +{: .no_toc } + +While Recoil is mostly compatible with Spring 105 some divergences naturally +developed over time. + +Here we list the most relevant breaking changes and how to fix them when +migrating from Spring. + +
+ + Table of contents + + {: .text-delta } +- TOC +{:toc} +
+ +## Callouts + +### Font rendering + +Rendering fonts now obeys GL color state. This means that sometimes text will +not be the same color as previously. To get back previous behaviour, you might +need to add +[`gl.Color`](https://beyond-all-reason.github.io/spring/ldoc/modules/OpenGL.html#gl.Text) +in front of +[`gl.Text`](https://beyond-all-reason.github.io/spring/ldoc/modules/OpenGL.html#gl.Color) +calls. Alternatively, you can add inline colour codes (`\255\rrr\ggg\bbb`). + +### Spring.Marker usage + +All three [Spring.Marker] functions (Point, Line, Erase) no longer accept +numerical 0 as false for `onlyLocal` (now follows regular Lua language rules +where 0 is true). To get back old behaviour, change `0` to `false`, e.g.: + +```diff +-Spring.MarkerAddPoint(x, y, z, text, 0) ++Spring.MarkerAddPoint(x, y, z, text, false) +``` + +```diff +-Spring.MarkerAddLine(x1, y1, z1, x2, y2, z2, 0, playerId) ++Spring.MarkerAddLine(x1, y1, z1, x2, y2, z2, false, playerId) +``` + +```diff +-Spring.MarkerErasePosition(x, y, z, noop, 0, playerId) ++Spring.MarkerErasePosition(x, y, z, noop, false, playerId) +``` + +### Spring.GetConfig usage + +[`Spring.GetConfigInt`](https://beyond-all-reason.github.io/spring/ldoc/modules/UnsyncedRead.html#Spring.GetConfigInt), +[`Spring.GetConfigFloat`](https://beyond-all-reason.github.io/spring/ldoc/modules/UnsyncedRead.html#Spring.GetConfigFloat) and +[`Spring.GetConfigString`](https://beyond-all-reason.github.io/spring/ldoc/modules/UnsyncedRead.html#Spring.GetConfigString) +now accept nil as the second argument (what to return by default if not set). +Previously it was treated as 0 (Int and Float) or "" (String). +To get back previous behaviour: + +```lua +local originalGetConfigInt = Spring.GetConfigInt +Spring.GetConfigInt = function(key, def) + return originalGetConfigInt(key, def) or 0 +end +``` + +### Spring.GetSelectedUnits{Sorted,Counts} + +The tables returned by +[`Spring.GetSelectedUnitsSorted`](https://beyond-all-reason.github.io/spring/ldoc/modules/UnsyncedRead.html#Spring.GetSelectedUnitsSorted) and +[`Spring.GetSelectedUnitsCounts`](https://beyond-all-reason.github.io/spring/ldoc/modules/UnsyncedRead.html#Spring.GetSelectedUnitsCounts) +no longer have an additional `n` key with corresponding value containining the +number of unitdefs. + +Instead use the second return value, e.g.: + +```diff +- local counts = Spring.GetSelectedUnitsCounts() +- local unitDefsCount = counts.n +- counts.n = nil ++ local counts, unitDefsCount = Spring.GetSelectedUnitsCounts() +``` + +## Stop command on manual share +Manually shared units no longer receive the Stop command. +Replicate the previous behaviour via the `UnitGiven` callin: +```lua +function wupget:UnitGiven(unitID, unitDefID, newTeam) + if newTeam == Spring.GetMyTeamID() then -- if doing in unsynced + Spring.GiveOrderToUnit(unitID, CMD.STOP, 0, 0) + end +end +``` + +## Defs + +- Hovercraft and ships brought out of water no longer forced to be upright. +To get back previous behaviour, put the `upright = true` tag in all unit defs +whose move def is of the hovercraft or ship type. +- Units with `useFootPrintCollisionVolume` but no `collisionVolumeScales` set +will now use the footprint volume (previously mistakenly used the model's sphere). + + To keep the old hitvolume, set `useFootPrintCollisionVolume` to false for units + with no `collisionVolumeScales`. Assuming you apply `lowerkeys` to unit defs, + this can also be achieved by putting the following in unit defs post-processing: + + ```lua + for unitDefID, unitDef in pairs(UnitDefs) do + if not unitDef.collisionvolumescales then + unitDef.usefootprintcollisionvolume = nil + end + end + ``` +- Tree feature defs `treetype0` through `treetype16` are now provided by the +basecontent archive instead of the engine. + + No known games ship their own basecontent and they would know what to do if so. + +- The `firestarter` weapon tag no longer capped at 10000 in defs (which +becomes 100 in Lua WeaponDefs after rescale), now uncapped. + + To get back previous behaviour, put the following in weapon defs + post-processing: + + ```lua + for weaponDefID, weaponDef in pairs(WeaponDefs) do + if weaponDef.firestarter then + weaponDef.firestarter = math.min(weaponDef.firestarter, 10000) + end + end + ``` + +- It is heavily recommended to replace `acceleration` and `brakeRate` +with `maxAcc` and `maxDec` respectively (possibly in post-processing). +While the old spelling still works the way it always did, at some point +in the future it will be changed from elmo/frame to elmo/second. + +## Camera modifiers + +The following keyboard modifiers were unhardcoded from engine: + +- On spring camera: rotating on the x (pitch) or y (yaw) axis with ALT and +middle mouse button pressed while moving the cursor. +- Resetting camera settings on ALT pressed and mousewheelscroll down. +- Rotating on the x axis (pitch) with CTRL pressed and mousewheelscroll. + +If games and players do not change engine defaults, no action is needed, +however to enable these modifiers as previously the following keybindings must +be set: + +``` +bind Any+ctrl movetilt // rotates the camera over the x axis on mousewheel move +bind Any+alt movereset // resets camera state to maxzoom/minzoom on mousewheel move, additionally resets tilt on Overhead cam +bind Any+alt moverotate // rotates the camera in x and y axis on mmb move (Spring cam) +``` + +## Resurrecting units + +Resurrecting units no longer overrides their health to 5%. +To get back the old behaviour define a gadget with the following callin: + +```lua +function gadget:UnitCreated(unitID, unitDefID, teamID, builderID) + if builderID and Spring.GetUnitWorkerTask(builderID) == CMD.RESURRECT then + Spring.SetUnitHealth(unitID, Spring.GetUnitHealth(unitID) * 0.05) + end +end +``` + +## VFS mapping API + +`Spring.MapArchive` and `Spring.UnmapArchive` have been temporarily removed due to sync unsafety. +In the meantime, use `Spring.UseArchive`. These functions are going to come back at some point, +but there is no concrete timeline for that yet. + +## Iterating synced proxy tables + +Functions for iterating synced proxy tables: `snext`, `spairs` and `sipairs` have been removed. +These have been able to be replaced by the regular `next`, `pairs` and `ipairs` for some time +already (so the change can be done before migrating): +```diff + local syncedProxyTable = SYNCED.foo +-for key, value in spairs(syncedProxyTable) do ++for key, value in pairs(syncedProxyTable) do +``` + +## General + +- Paletted image files are no longer accepted. Convert your images not to be paletted. +- The return value from the +[`UnitUnitCollision`](https://beyond-all-reason.github.io/spring/ldoc/modules/LuaHandle.html#UnitUnitCollision) +callin is now ignored and there is only one event for each collision. +There is no way to get back the old behaviour for now, +but if someone needs it it could be arranged. +- Removed the following constants: + - `Platform.glSupport16bitDepthBuffer` + - `Platform.glSupport24bitDepthBuffer` + - `Platform.glSupport32bitDepthBuffer` + + To get back previous behaviour, replace with + ```lua + Platform.glSupportDepthBufferBitDepth >= 16 -- or 24, or 32, respectively + ``` +- Removed LOD rendering (2D unit billboards when zoomed out far), including the +`/distdraw` command and the `UnitLodDist` springsettings entry +- Removed the `AdvSky` springsetting and the `/dynamicsky` command, +which made clouds move across the sky. You cannot easily get back +previous behaviour, though you can probably achieve something similar +by rendering moving clouds yourself. +- The deprecated `Game.allowTeamColors`, whose value was always `true`, has been removed. Note that this inverts logic if you used it like a bool. +- The default `/screenshot` format was changed to PNG. Check any automated processing you do on these. +- Screenshots and replay demo files now have a different filename format, with an UTC timestamp. Check any automated file parsing you might have. + +[Spring.Marker]: https://beyond-all-reason.github.io/spring/ldoc/modules/UnsyncedCtrl.html#Markers
+{% for item in ordered_items %} +
{{item.term}}
+
{{item.definition}}
+{% endfor %} +