mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 14:24:43 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a576daa4b | |||
| 69461c90b7 | |||
| 6b763af4c8 | |||
| 0dbc1f604a | |||
| bf4eee555f | |||
| dae7a8c394 | |||
| 4633a2d522 | |||
| aa3767d2f9 | |||
| 7b3d6ce04e | |||
| c98ae10e39 | |||
| 655a444847 | |||
| 182b1e3ee6 | |||
| 60a44dfc26 | |||
| 38e4cdc755 | |||
| 68d99b3944 | |||
| 5ffddd0cc4 | |||
| 2721d642b8 | |||
| e1daff1869 | |||
| e5df3e1ad8 | |||
| 5ab58f82f0 | |||
| 520c489b68 | |||
| 0fdd6005b8 | |||
| 3fce9a37cc | |||
| e4b604982a | |||
| b78b666797 | |||
| 2fcce77ad4 | |||
| 83c8ec1b4a | |||
| a7694ef8b3 | |||
| 5012d1f1c0 | |||
| 73dec93113 | |||
| c4d10eedfd | |||
| 21ec2f0ab8 | |||
| 85cc968be0 | |||
| ef9ea478ec | |||
| 417af009ea | |||
| fa5f81ba6f | |||
| 30fe4f7fdc | |||
| 1ec2709236 | |||
| fa1f474d6e | |||
| e2d4ad6c40 | |||
| 851bbf07ac | |||
| 8a593904d5 | |||
| ef42efe1e1 | |||
| 8a31db1659 | |||
| 50127606b3 | |||
| 8053860a5b | |||
| 6746f380f7 |
@@ -66,6 +66,7 @@ Before moving on with Full Freeze, make sure that:
|
||||
|
||||
### Full Freeze
|
||||
|
||||
- [ ] [Update appdata.xml](wiki/ReleaseProcess#update-appdataxml)
|
||||
- [ ] [Freeze Jenkins](wiki/ReleaseProcess#freeze-jenkins)
|
||||
- [ ] [Confirm full freeze](wiki/ReleaseProcess#confirm-full-freeze)
|
||||
- [ ] [Package East Asian mods](wiki/ReleaseProcess#package-east-asian-mods)
|
||||
|
||||
@@ -9,6 +9,8 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Install lxml
|
||||
run: pip3 install lxml
|
||||
- name: Workaround for authentication problem with LFS
|
||||
|
||||
@@ -9,6 +9,8 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- id: restore-pip-cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
|
||||
@@ -98,14 +98,6 @@ var AccountSettingsPage = {
|
||||
if (Engine.GetGUIObjectByName("as_PasswordInputConfirm").caption !== newPass)
|
||||
throw new SetPasswordError(translate("Passwords do not match"));
|
||||
|
||||
let usn = Engine.LobbyGetJID();
|
||||
let atIndex = usn.indexOf("@");
|
||||
if (atIndex == -1)
|
||||
{
|
||||
// Probably can't happen too easily, so error out.
|
||||
error("Invalid JID");
|
||||
throw new SetPasswordError(translate("Invalid JID, cannot change password."));
|
||||
}
|
||||
return Engine.EncryptPassword(newPass, usn.substring(0, atIndex).toLowerCase());
|
||||
return Engine.EncryptPassword(newPass, Engine.LobbyGetUsername());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
FROM debian:bullseye-slim
|
||||
|
||||
RUN useradd -ms /bin/bash --uid 1006 builder
|
||||
|
||||
# 0 A.D. dependencies.
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG DEBCONF_NOWARNINGS="yes"
|
||||
@@ -45,9 +43,7 @@ RUN apt-get -qqy update && apt-get install -qqy --no-install-recommends git-lfs
|
||||
RUN git lfs install --system --skip-smudge
|
||||
|
||||
# Install rust and Cargo via rustup
|
||||
USER builder
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.66.0 -y
|
||||
ENV PATH="${PATH}:/home/builder/.cargo/bin"
|
||||
USER root
|
||||
ENV PATH="${PATH}:/root/.cargo/bin"
|
||||
|
||||
ENV SHELL=/bin/bash
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
FROM debian:buster-slim
|
||||
|
||||
RUN useradd -ms /bin/bash --uid 1006 builder
|
||||
|
||||
# 0 A.D. dependencies.
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG DEBCONF_NOWARNINGS="yes"
|
||||
@@ -47,10 +45,8 @@ RUN apt-get -qqy update && apt-get install -qqy --no-install-recommends git-lfs
|
||||
RUN git lfs install --system --skip-smudge
|
||||
|
||||
# Install rust and Cargo via rustup
|
||||
USER builder
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.66.0 -y
|
||||
ENV PATH="${PATH}:/home/builder/.cargo/bin"
|
||||
USER root
|
||||
ENV PATH="${PATH}:/root/.cargo/bin"
|
||||
|
||||
ENV SHELL=/bin/bash
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG DEBCONF_NOWARNINGS="yes"
|
||||
RUN apt-get update && apt-get install -qqy llvm-9 clang-9 lld-9 libclang-9-dev --no-install-recommends
|
||||
|
||||
USER builder
|
||||
|
||||
ENV CC=clang-9
|
||||
ENV CXX=clang++-9
|
||||
ENV LDFLAGS="-fuse-ld=lld-9"
|
||||
|
||||
@@ -4,8 +4,6 @@ ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG DEBCONF_NOWARNINGS="yes"
|
||||
RUN apt-get install -qqy gcc-8 g++-8 --no-install-recommends
|
||||
|
||||
USER builder
|
||||
|
||||
ENV LIBCC=gcc-8
|
||||
ENV LIBCXX=g++-8
|
||||
ENV CC=gcc-8
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -32,6 +32,8 @@ pipeline {
|
||||
|
||||
parameters {
|
||||
string(name: 'BUNDLE_VERSION', defaultValue: '0.27.0dev', description: 'Bundle Version')
|
||||
string(name: 'NIGHTLY_REVISION', defaultValue: 'HEAD', description: 'Nightly SVN revision from which to build the bundles')
|
||||
booleanParam(name: 'PATCH_BUILD', defaultValue: false, description: 'Apply patch generated from upstream job patch-release onto the nightly build')
|
||||
booleanParam(name: 'DO_GZIP', defaultValue: true, description: 'Create .gz unix tarballs as well as .xz')
|
||||
}
|
||||
|
||||
@@ -44,10 +46,20 @@ pipeline {
|
||||
steps {
|
||||
checkout changelog: false, poll: false, scm: [
|
||||
$class: 'SubversionSCM',
|
||||
locations: [[local: '.', remote: 'https://svn.wildfiregames.com/nightly-build/trunk']],
|
||||
locations: [[local: '.', remote: "https://svn.wildfiregames.com/nightly-build/trunk@${NIGHTLY_REVISION}"]],
|
||||
quietOperation: false,
|
||||
workspaceUpdater: [$class: 'UpdateWithCleanUpdater']]
|
||||
sh "svn cleanup"
|
||||
}
|
||||
}
|
||||
|
||||
stage("Patch Nightly Build") {
|
||||
when {
|
||||
expression { return params.PATCH_BUILD }
|
||||
}
|
||||
steps {
|
||||
copyArtifacts projectName: '0ad-patch-release', selector: upstream()
|
||||
sh "svn patch ${BUNDLE_VERSION}.patch"
|
||||
untar file: "${params.BUNDLE_VERSION}-nightly-patch.tar.gz", keepPermissions: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,12 +142,25 @@ pipeline {
|
||||
sh "BUNDLE_VERSION=${params.BUNDLE_VERSION} DO_GZIP=${params.DO_GZIP} source/tools/dist/build-unix-win32.sh"
|
||||
}
|
||||
}
|
||||
|
||||
stage("Generate Signatures and Checksums") {
|
||||
steps {
|
||||
withCredentials([sshUserPrivateKey(credentialsId: 'minisign-releases-key', keyFileVariable: 'MINISIGN_KEY', passphraseVariable: 'MINISIGN_PASS')]) {
|
||||
sh 'echo ${MINISIGN_PASS} | minisign -s ${MINISIGN_KEY} -Sm *.{dmg,exe,tar.gz,tar.xz}'
|
||||
}
|
||||
sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do md5sum "${file}" > "${file}".md5sum; done'
|
||||
sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do sha1sum "${file}" > "${file}".sha1sum; done'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts '*.dmg,*.exe,*.tar.gz,*.tar.xz'
|
||||
sh "shasum -a 1 *.{dmg,exe,tar.gz,tar.xz}"
|
||||
archiveArtifacts '*.dmg,*.exe,*.tar.gz,*.tar.xz,*.minisig,*.md5sum,*.sha1sum'
|
||||
}
|
||||
cleanup {
|
||||
sh 'svn revert -R .'
|
||||
sh 'svn cleanup --remove-unversioned'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -57,6 +57,9 @@ pipeline {
|
||||
customWorkspace "workspace/${JENKINS_COMPILER}-pch"
|
||||
dir 'build/jenkins/dockerfiles'
|
||||
filename "${JENKINS_COMPILER}.Dockerfile"
|
||||
// Prevent Jenkins from running commands with the UID of the host's jenkins user
|
||||
// https://stackoverflow.com/a/42822143
|
||||
args '-u root'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// This pipeline is used to generate patched releases, suitable to be bundled and distributed.
|
||||
|
||||
def visualStudioPath = '"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe"'
|
||||
def buildOptions = '/p:PlatformToolset=v141_xp /p:XPDeprecationWarning=false /t:pyrogenesis /t:AtlasUI %JOBS% /nologo -clp:Warningsonly -clp:ErrorsOnly'
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
node {
|
||||
label 'WindowsAgent'
|
||||
}
|
||||
}
|
||||
|
||||
parameters {
|
||||
string(name: 'BUNDLE_VERSION', description: 'Bundle Version')
|
||||
string(name: 'NIGHTLY_REVISION', description: 'Revision of the nightly build corresponding to the release')
|
||||
string(name: 'RELEASE_TAG', description: 'Git tag from which the point release originates')
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Generate Patch') {
|
||||
steps {
|
||||
checkout scmGit(branches: [[name: "${GIT_BRANCH}"]], extensions: [cleanAfterCheckout(), localBranch()])
|
||||
bat 'cd build\\build_version && build_version.bat'
|
||||
stash includes: 'build/build_version/build_version.txt', name: 'build_version'
|
||||
bat "git diff ${RELEASE_TAG}..HEAD > ${BUNDLE_VERSION}.patch"
|
||||
stash includes: "${params.BUNDLE_VERSION}.patch", name: 'patch'
|
||||
archiveArtifacts artifacts: "${params.BUNDLE_VERSION}.patch"
|
||||
}
|
||||
}
|
||||
|
||||
stage('Patch Windows Build') {
|
||||
steps {
|
||||
ws('workspace/patch-release-svn') {
|
||||
checkout changelog: false, poll: false, scm: [
|
||||
$class: 'SubversionSCM',
|
||||
locations: [[local: '.', remote: "https://svn.wildfiregames.com/nightly-build/trunk@${NIGHTLY_REVISION}"]],
|
||||
quietOperation: false,
|
||||
workspaceUpdater: [$class: 'UpdateWithCleanUpdater']]
|
||||
unstash 'patch'
|
||||
bat "svn patch ${params.BUNDLE_VERSION}.patch"
|
||||
|
||||
unstash 'build_version'
|
||||
bat 'cd libraries && get-windows-libs.bat'
|
||||
|
||||
bat '(robocopy E:\\wxWidgets-3.2.6\\lib libraries\\win32\\wxwidgets\\lib /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0'
|
||||
bat '(robocopy E:\\wxWidgets-3.2.6\\include libraries\\win32\\wxwidgets\\include /MIR /NDL /NJH /NJS /NP /NS /NC) ^& IF %ERRORLEVEL% LEQ 1 exit 0'
|
||||
bat 'cd build\\workspaces && update-workspaces.bat --without-pch --without-tests'
|
||||
bat "cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}"
|
||||
|
||||
script {
|
||||
def modifiedFiles = bat(script:'@svn status', returnStdout: true).split('\n').collect { l -> l.drop(8).trim() }.join(', ')
|
||||
tar archive: true, compress: true, exclude: '*.orig, binaries/system/*.exp, binaries/system/*.lib, build/workspaces/vs2017, libraries/win32/wxwidgets/**', file: "${params.BUNDLE_VERSION}-nightly-patch.tar.gz", glob: modifiedFiles
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
cleanup {
|
||||
ws('workspace/patch-release-svn') {
|
||||
bat 'svn revert -R .'
|
||||
bat 'svn cleanup --remove-unversioned'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Bundle Patched Release') {
|
||||
steps {
|
||||
build job: '0ad-patch-bundles', wait: false, waitForStart: true, parameters: [
|
||||
string(name: 'BUNDLE_VERSION', value: "${params.BUNDLE_VERSION}"),
|
||||
string(name: 'NIGHTLY_REVISION', value: "${params.NIGHTLY_REVISION}"),
|
||||
booleanParam(name: 'PATCH_BUILD', value: true)
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -21,9 +21,12 @@ pipeline {
|
||||
agent {
|
||||
dockerfile {
|
||||
label 'LinuxAgent'
|
||||
customWorkspace "workspace/technical-docs"
|
||||
customWorkspace 'workspace/technical-docs'
|
||||
dir 'build/jenkins/dockerfiles'
|
||||
filename "docs-tools.Dockerfile"
|
||||
filename 'docs-tools.Dockerfile'
|
||||
// Prevent Jenkins from running commands with the UID of the host's jenkins user
|
||||
// https://stackoverflow.com/a/42822143
|
||||
args '-u root'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -719,12 +719,6 @@ extern_lib_defs = {
|
||||
add_default_links({
|
||||
win_names = { "libvorbisfile" },
|
||||
})
|
||||
elseif os.getversion().description == "OpenBSD" then
|
||||
-- TODO: We need to force linking with these as currently
|
||||
-- they need to be loaded explicitly on execution
|
||||
add_default_links({
|
||||
unix_names = { "ogg", "vorbis" },
|
||||
})
|
||||
else
|
||||
pkgconfig.add_links("vorbisfile")
|
||||
end
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
local m = {}
|
||||
m._VERSION = "1.2.0-dev"
|
||||
m._VERSION = "1.3.0-dev"
|
||||
|
||||
m.additional_pc_path = nil
|
||||
m.static_link_libs = false
|
||||
|
||||
local pkg_config_command = "pkg-config"
|
||||
if os.getenv("PKG_CONFIG") then
|
||||
pkg_config_command = os.getenv("PKG_CONFIG")
|
||||
end
|
||||
|
||||
local function os_capture(cmd)
|
||||
return io.popen(cmd, 'r'):read('*a'):gsub("\n", " ")
|
||||
end
|
||||
@@ -12,7 +17,7 @@ local function parse_pkg_config_includes(lib, alternative_cmd, alternative_flags
|
||||
local result
|
||||
if not alternative_cmd then
|
||||
local pc_path = m.additional_pc_path and "PKG_CONFIG_PATH="..m.additional_pc_path or ""
|
||||
result = os_capture(pc_path.." pkg-config --cflags "..lib)
|
||||
result = os_capture(pc_path .. " " .. pkg_config_command .. " --cflags " .. lib)
|
||||
else
|
||||
if not alternative_flags then
|
||||
result = os_capture(alternative_cmd.." --cflags")
|
||||
@@ -81,7 +86,7 @@ function m.add_links(lib, alternative_cmd, alternative_flags)
|
||||
if not alternative_cmd then
|
||||
local pc_path = m.additional_pc_path and "PKG_CONFIG_PATH="..m.additional_pc_path or ""
|
||||
local static = m.static_link_libs and " --static " or ""
|
||||
result = os_capture(pc_path.." pkg-config --libs "..static..lib)
|
||||
result = os_capture(pc_path .. " " .. pkg_config_command .. " --libs " .. static .. lib)
|
||||
else
|
||||
if not alternative_flags then
|
||||
result = os_capture(alternative_cmd.." --libs")
|
||||
|
||||
@@ -5,6 +5,7 @@ newoption { trigger = "icc", description = "Use Intel C++ Compiler (Linux only;
|
||||
newoption { trigger = "jenkins-tests", description = "Configure CxxTest to use the XmlPrinter runner which produces Jenkins-compatible output" }
|
||||
newoption { trigger = "minimal-flags", description = "Only set compiler/linker flags that are really needed. Has no effect on Windows builds" }
|
||||
newoption { trigger = "outpath", description = "Location for generated project files", default="../workspaces/default" }
|
||||
newoption { trigger = "strip-binaries", description = "Strip created binaries" }
|
||||
newoption { trigger = "with-system-cxxtest", description = "Search standard paths for cxxtest, instead of using bundled copy" }
|
||||
newoption { trigger = "with-lto", description = "Enable Link Time Optimization (LTO)" }
|
||||
newoption { trigger = "with-system-mozjs", description = "Search standard paths for libmozjs115, instead of using bundled copy" }
|
||||
@@ -186,7 +187,9 @@ function project_set_build_flags()
|
||||
|
||||
editandcontinue "Off"
|
||||
|
||||
if not _OPTIONS["minimal-flags"] then
|
||||
if _OPTIONS['strip-binaries'] then
|
||||
symbols "Off"
|
||||
else
|
||||
symbols "On"
|
||||
end
|
||||
|
||||
@@ -209,7 +212,12 @@ function project_set_build_flags()
|
||||
optimize "Speed"
|
||||
end
|
||||
if _OPTIONS["with-lto"] then
|
||||
flags { "LinkTimeOptimization" }
|
||||
if linktimeoptimization then
|
||||
linktimeoptimization("On")
|
||||
else
|
||||
-- deprecated since v5.0.0-beta4
|
||||
flags { "LinkTimeOptimization" }
|
||||
end
|
||||
end
|
||||
defines { "NDEBUG", "CONFIG_FINAL=1" }
|
||||
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2018 Wildfire Games <webmaster@wildfiregames.com> -->
|
||||
<!-- Copyright 2025 Wildfire Games <webmaster@wildfiregames.com> -->
|
||||
<component type="desktop-application">
|
||||
<id>com.play0ad.zeroad</id>
|
||||
<developer id="com.wildfiregames">
|
||||
<name>Wildfire Games</name>
|
||||
</developer>
|
||||
<launchable type="desktop-id">0ad.desktop</launchable>
|
||||
<project_license>GPL-2.0+ and CC-BY-SA</project_license>
|
||||
<metadata_license>CC-BY-SA-3.0</metadata_license>
|
||||
<name>0 A.D.</name>
|
||||
<summary>Real-Time Strategy Game of Ancient Warfare</summary>
|
||||
<summary>Real-time strategy game</summary>
|
||||
<branding>
|
||||
<color type="primary" scheme_preference="light">#d6c49a</color>
|
||||
<color type="primary" scheme_preference="dark">#313131</color>
|
||||
</branding>
|
||||
<description>
|
||||
<p>
|
||||
0 A.D. is a real-time strategy (RTS) game of ancient warfare.
|
||||
@@ -15,10 +22,10 @@
|
||||
at their peak of economic growth and military prowess.
|
||||
</p>
|
||||
<p>
|
||||
The thirteen factions are: Three of the Hellenic States (Athens, Sparta and
|
||||
The fourteen factions are: Three of the Hellenic States (Athens, Sparta and
|
||||
Macedonia), two of the kingdoms of Alexander the Great's successors
|
||||
(Seleucids and Ptolemaic Egyptians), two Celtic tribes (Britons and
|
||||
Gauls), the Romans, the Persians, the Iberians, the Carthaginians, the
|
||||
Gauls), the Romans, the Persians, the Iberians, the Carthaginians, the Han, the
|
||||
Mauryas and the Kushites.
|
||||
Each civilization is complete with substantially unique artwork,
|
||||
technologies and civilization bonuses.
|
||||
@@ -32,15 +39,61 @@
|
||||
<url type="bugtracker">https://gitea.wildfiregames.com/0ad/0ad/issues/</url>
|
||||
<url type="translate">https://gitea.wildfiregames.com/0ad/0ad/wiki/Localization</url>
|
||||
<url type="donation">https://play0ad.com/community/donate/</url>
|
||||
<releases>
|
||||
<release version="0.27.1" date="2025-07-13">
|
||||
<url type="details">https://play0ad.com/patch-release-27-1-for-0-a-d/</url>
|
||||
<description>
|
||||
<p>Wildfire Games proudly announces the first "patch release" of 0 A.D., 0.27.1 for Alpha 27: "Agni".</p>
|
||||
<ul>
|
||||
<li>Critical performance fixes.</li>
|
||||
<li>Graphics fixes for GPU Skinning and Vulkan Renderer.</li>
|
||||
<li>Fix changing perspective in replays.</li>
|
||||
<li>Port Forwarding and Multiplayer Lobby password fixes.</li>
|
||||
<li>Various crash fixes, build fixes for Linux.</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.27.0" date="2025-01-30">
|
||||
<url type="details">https://play0ad.com/new-release-0-a-d-alpha-27-agni/</url>
|
||||
<description>
|
||||
<p>Wildfire Games proudly announces the release of 0 A.D. Alpha 27: "Agni", the last alpha version of the free, open-source real-time strategy game of ancient warfare.</p>
|
||||
<ul>
|
||||
<li>Vulkan Renderer for improved performance.</li>
|
||||
<li>Multiplayer Savegames support.</li>
|
||||
<li>New Tips & Tricks page for enhanced guidance.</li>
|
||||
<li>Naval overhaul with categorized warships.</li>
|
||||
<li>New and updated random and skirmish maps.</li>
|
||||
<li>Gameplay enhancements: Civilization differentiation, melee balance updates, and improved capture mechanics.</li>
|
||||
<li>Engine improvements: GPU Skinning, FSR upscaling, SpiderMonkey upgrades.</li>
|
||||
<li>Observer flares and improved anti-cheat measures.</li>
|
||||
<li>Migration to a git-based development environment.</li>
|
||||
<li>Various bug fixes, UI enhancements, and performance optimizations.</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
</releases>
|
||||
<screenshots>
|
||||
<screenshot type="default">https://play0ad.com/wp-content/gallery/screenshots/screenshot0072.jpg</screenshot>
|
||||
<screenshot>https://play0ad.com/wp-content/gallery/screenshots/water-specular.jpg</screenshot>
|
||||
<screenshot>https://play0ad.com/wp-content/gallery/screenshots/screenshot0050.jpg</screenshot>
|
||||
<screenshot>https://play0ad.com/wp-content/gallery/screenshots/cycladic_arcgipelago_6.jpg</screenshot>
|
||||
<screenshot type="default">
|
||||
<image>https://play0ad.com/wp-content/gallery/screenshots/screenshot0072.jpg</image>
|
||||
<caption>Maurya village with buildings and farms</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play0ad.com/wp-content/gallery/screenshots/water-specular.jpg</image>
|
||||
<caption>Carthaginian biremes in a tranquil cove</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play0ad.com/wp-content/gallery/screenshots/screenshot0050.jpg</image>
|
||||
<caption>Republican Roman village in a desert setting</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play0ad.com/wp-content/gallery/screenshots/cycladic_arcgipelago_6.jpg</image>
|
||||
<caption>Cycladic archipelago with six small islands</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<update_contact>webmaster@wildfiregames.com</update_contact>
|
||||
<keywords>
|
||||
<keyword>RTS</keyword>
|
||||
<keyword>0AD</keyword>
|
||||
<keyword>Realtime Strategy</keyword>
|
||||
<keyword>Economic Simulation Game</keyword>
|
||||
<keyword>History</keyword>
|
||||
@@ -55,6 +108,7 @@
|
||||
<keyword>Britons</keyword>
|
||||
<keyword>Carthaginians</keyword>
|
||||
<keyword>Gauls</keyword>
|
||||
<keyword>Han</keyword>
|
||||
<keyword>Iberians</keyword>
|
||||
<keyword>Kushites</keyword>
|
||||
<keyword>Macedonians</keyword>
|
||||
@@ -65,12 +119,23 @@
|
||||
<keyword>Seleucids</keyword>
|
||||
<keyword>Spartans</keyword>
|
||||
</keywords>
|
||||
<content_rating type="oars-1.0">
|
||||
<requires>
|
||||
<display_length compare="ge">1024</display_length>
|
||||
</requires>
|
||||
<supports>
|
||||
<control>pointing</control>
|
||||
<control>keyboard</control>
|
||||
<control>touch</control>
|
||||
<internet>offline-only</internet>
|
||||
</supports>
|
||||
<content_rating type="oars-1.1">
|
||||
<content_attribute id="violence-cartoon">none</content_attribute>
|
||||
<content_attribute id="violence-fantasy">none</content_attribute>
|
||||
<content_attribute id="violence-realistic">intense</content_attribute>
|
||||
<content_attribute id="violence-bloodshed">moderate</content_attribute>
|
||||
<content_attribute id="violence-sexual">none</content_attribute>
|
||||
<content_attribute id="violence-desecration">mild</content_attribute>
|
||||
<content_attribute id="violence-slavery">mild</content_attribute>
|
||||
<content_attribute id="drugs-alcohol">none</content_attribute>
|
||||
<content_attribute id="drugs-narcotics">none</content_attribute>
|
||||
<content_attribute id="drugs-tobacco">none</content_attribute>
|
||||
@@ -85,9 +150,11 @@
|
||||
<content_attribute id="social-location">none</content_attribute>
|
||||
<content_attribute id="social-contacts">none</content_attribute>
|
||||
<content_attribute id="money-purchasing">none</content_attribute>
|
||||
<content_attribute id="money-advertising">none</content_attribute>
|
||||
<content_attribute id="money-gambling">none</content_attribute>
|
||||
</content_rating>
|
||||
<mimetypes>
|
||||
<mimetype>application/x-pyromod+zip</mimetype>
|
||||
</mimetypes>
|
||||
<provides>
|
||||
<mediatype>application/x-pyromod+zip</mediatype>
|
||||
<binary>pyrogenesis</binary>
|
||||
</provides>
|
||||
</component>
|
||||
|
||||
@@ -3,6 +3,7 @@ Version=1.4
|
||||
Name=0 A.D.
|
||||
Exec=0ad %F
|
||||
Icon=0ad
|
||||
StartupWMClass=pyrogenesis
|
||||
Terminal=false
|
||||
MimeType=application/x-pyromod+zip;
|
||||
Type=Application
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
echo "Running as root will mess up file permissions. Aborting ..." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
die()
|
||||
{
|
||||
echo ERROR: "$*"
|
||||
@@ -47,8 +42,6 @@ fi
|
||||
|
||||
echo
|
||||
|
||||
# If we're in bash then make HOSTTYPE available to Premake, for primitive arch-detection
|
||||
export HOSTTYPE="$HOSTTYPE"
|
||||
# Now run Premake to create the makefiles
|
||||
echo "Premake args: ${premake_args}"
|
||||
if [ "$OS" != "Darwin" ]; then
|
||||
|
||||
@@ -62,7 +62,7 @@ while [ "$#" -gt 0 ]; do
|
||||
--with-system-cxxtest) with_system_cxxtest=true ;;
|
||||
--with-system-nvtt) with_system_nvtt=true ;;
|
||||
--with-system-mozjs) with_system_mozjs=true ;;
|
||||
--with-system-premake) with_system_mozjs=true ;;
|
||||
--with-system-premake) with_system_premake=true ;;
|
||||
--with-spirv-reflect) with_spirv_reflect=true ;;
|
||||
-j*) JOBS="$1" ;;
|
||||
*)
|
||||
|
||||
@@ -2,9 +2,17 @@ rem **Download sources and binaries of libraries**
|
||||
|
||||
rem **SVN revision to checkout for windows-libs**
|
||||
rem **Update this line when you commit an update to windows-libs**
|
||||
set "svnrev=28243"
|
||||
set "svnrev=28256"
|
||||
|
||||
svn co https://svn.wildfiregames.com/public/windows-libs/trunk@%svnrev% win32
|
||||
svn co https://svn.wildfiregames.com/public/windows-libs/trunk@%svnrev% win32 || ^
|
||||
svn export --force https://svn.wildfiregames.com/public/windows-libs/trunk@%svnrev% win32
|
||||
|
||||
rem **Fixup SpiderMonkey for Windows 7 on Win32**
|
||||
rem This change is performed separately to allow backporting to A27
|
||||
set "smrev=28263"
|
||||
svn up -r %smrev% win32/spidermonkey/bin || ^
|
||||
svn export --force https://svn.wildfiregames.com/public/windows-libs/trunk/spidermonkey/bin@%smrev% win32/spidermonkey/bin || ^
|
||||
exit /b 1
|
||||
|
||||
rem **Copy dependencies' binaries to binaries/system/**
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
: "${TAR:=tar}"
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PV=4.4
|
||||
@@ -40,7 +42,7 @@ fi
|
||||
|
||||
# unpack
|
||||
rm -Rf "cxxtest-${PV}"
|
||||
tar -xf "cxxtest-${PV}.tar.gz"
|
||||
"${TAR}" -xf "cxxtest-${PV}.tar.gz"
|
||||
|
||||
# patch
|
||||
patch -d "cxxtest-${PV}" -p1 <patches/0001-Add-Debian-python3-patch.patch
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
: "${TAR:=tar}"
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PV=28209
|
||||
@@ -10,7 +12,7 @@ fetch()
|
||||
{
|
||||
rm -Rf fcollada-${PV}
|
||||
svn export https://svn.wildfiregames.com/public/source-libs/trunk/fcollada@${PV} fcollada-${PV}
|
||||
tar cJf fcollada-${PV}.tar.xz fcollada-${PV}
|
||||
"${TAR}" cJf fcollada-${PV}.tar.xz fcollada-${PV}
|
||||
rm -R fcollada-${PV}
|
||||
}
|
||||
|
||||
@@ -42,7 +44,7 @@ fi
|
||||
|
||||
# unpack
|
||||
rm -Rf fcollada-${PV}
|
||||
tar xf fcollada-${PV}.tar.xz
|
||||
"${TAR}" xf fcollada-${PV}.tar.xz
|
||||
|
||||
# build
|
||||
(
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
: "${TAR:=tar}"
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PV=28209
|
||||
LIB_VERSION=${PV}
|
||||
LIB_VERSION=${PV}+wfg1
|
||||
|
||||
fetch()
|
||||
{
|
||||
rm -Rf nvtt-${PV}
|
||||
svn export https://svn.wildfiregames.com/public/source-libs/trunk/nvtt@${PV} nvtt-${PV}
|
||||
tar cJf nvtt-${PV}.tar.xz nvtt-${PV}
|
||||
"${TAR}" cJf nvtt-${PV}.tar.xz nvtt-${PV}
|
||||
rm -R nvtt-${PV}
|
||||
}
|
||||
|
||||
@@ -42,7 +44,12 @@ fi
|
||||
|
||||
# unpack
|
||||
rm -Rf nvtt-${PV}
|
||||
tar xf nvtt-${PV}.tar.xz
|
||||
"${TAR}" xf nvtt-${PV}.tar.xz
|
||||
|
||||
# patch
|
||||
patch -d nvtt-${PV} -p1 <patches/0001-Don-t-overspecify-flags.patch
|
||||
patch -d nvtt-${PV} -p1 <patches/0002-Bump-cmake-min-version-to-3.10.patch
|
||||
patch -d nvtt-${PV} -p1 <patches/0003-Use-execute_process-insted-of-exec_program.patch
|
||||
|
||||
# build
|
||||
(
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
From fee966a8d44afc26005df9b539b16a5ee7f99107 Mon Sep 17 00:00:00 2001
|
||||
From: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
Date: Sun, 27 Apr 2025 07:53:42 +0200
|
||||
Subject: [PATCH] Don't overspecify flags
|
||||
|
||||
Cmake picks flags like CFALGS CXXFLAGS and LDFLAGS from environment. The
|
||||
use of CMAKE_LINK_FLAGS even triggers a warning.
|
||||
|
||||
Fixes: #7538
|
||||
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
---
|
||||
build.sh | 6 ------
|
||||
1 file changed, 6 deletions(-)
|
||||
|
||||
diff --git a/build.sh b/build.sh
|
||||
index dae3bcf..935c6ff 100755
|
||||
--- a/build.sh
|
||||
+++ b/build.sh
|
||||
@@ -29,9 +29,6 @@ if [ "$(uname -s)" = "Darwin" ]; then
|
||||
# but they're not as flexible for cross-compiling
|
||||
# Disable png support (avoids some conflicts with MacPorts)
|
||||
cmake .. \
|
||||
- -DCMAKE_LINK_FLAGS="$LDFLAGS" \
|
||||
- -DCMAKE_C_FLAGS="$CFLAGS" \
|
||||
- -DCMAKE_CXX_FLAGS="$CXXFLAGS" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
$CMAKE_FLAGS \
|
||||
-DBINDIR=bin \
|
||||
@@ -40,9 +37,6 @@ if [ "$(uname -s)" = "Darwin" ]; then
|
||||
-G "Unix Makefiles"
|
||||
else
|
||||
cmake .. \
|
||||
- -DCMAKE_LINK_FLAGS="$LDFLAGS" \
|
||||
- -DCMAKE_C_FLAGS="$CFLAGS" \
|
||||
- -DCMAKE_CXX_FLAGS="$CXXFLAGS" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
$CMAKE_FLAGS \
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
From cc07839eff9be49e2c3df4e68ce18f3134caafd2 Mon Sep 17 00:00:00 2001
|
||||
From: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
Date: Sun, 27 Apr 2025 07:57:10 +0200
|
||||
Subject: [PATCH] Bump cmake min version to 3.10
|
||||
|
||||
Cmake-4 removes support for cmake < cmake-3.5 and deprecates cmake <
|
||||
cmake-3.10
|
||||
|
||||
Fixes: #7764
|
||||
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
---
|
||||
src/CMakeLists.txt | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
|
||||
index b18b791..b517b52 100644
|
||||
--- a/src/CMakeLists.txt
|
||||
+++ b/src/CMakeLists.txt
|
||||
@@ -1,4 +1,4 @@
|
||||
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)
|
||||
+CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
|
||||
PROJECT(NV)
|
||||
ENABLE_TESTING()
|
||||
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
From 324f50d1ccf5ca38e0f3817c8d18208bd72e01f2 Mon Sep 17 00:00:00 2001
|
||||
From: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
Date: Sun, 27 Apr 2025 08:05:59 +0200
|
||||
Subject: [PATCH] Use execute_process insted of exec_program
|
||||
|
||||
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
---
|
||||
src/cmake/DetermineProcessor.cmake | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/cmake/DetermineProcessor.cmake b/src/cmake/DetermineProcessor.cmake
|
||||
index 7db7a95..13d39de 100644
|
||||
--- a/src/cmake/DetermineProcessor.cmake
|
||||
+++ b/src/cmake/DetermineProcessor.cmake
|
||||
@@ -8,7 +8,7 @@ IF(UNIX)
|
||||
#EXEC_PROGRAM(uname ARGS -p OUTPUT_VARIABLE NV_SYSTEM_PROCESSOR RETURN_VALUE val)
|
||||
|
||||
#IF("${val}" GREATER 0 OR NV_SYSTEM_PROCESSOR STREQUAL "unknown")
|
||||
- EXEC_PROGRAM(uname ARGS -m OUTPUT_VARIABLE NV_SYSTEM_PROCESSOR RETURN_VALUE val)
|
||||
+ execute_process(COMMAND uname -m OUTPUT_VARIABLE NV_SYSTEM_PROCESSOR ERROR_VARIABLE val)
|
||||
#ENDIF("${val}" GREATER 0 OR NV_SYSTEM_PROCESSOR STREQUAL "unknown")
|
||||
|
||||
IF(NV_SYSTEM_PROCESSOR STREQUAL "Power Macintosh")
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@@ -4,11 +4,12 @@ set -e
|
||||
: "${OS:=$(uname -s || true)}"
|
||||
: "${MAKE:=make}"
|
||||
: "${JOBS:=-j1}"
|
||||
: "${TAR:=tar}"
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PV=5.0.0-beta3
|
||||
LIB_VERSION=${PV}+wfg1
|
||||
PV=5.0.0-beta4
|
||||
LIB_VERSION=${PV}+wfg0
|
||||
|
||||
fetch()
|
||||
{
|
||||
@@ -44,19 +45,11 @@ fi
|
||||
|
||||
# unpack
|
||||
rm -Rf "premake-core-${PV}"
|
||||
tar -xf "premake-core-${PV}.tar.gz"
|
||||
"${TAR}" -xf "premake-core-${PV}.tar.gz"
|
||||
|
||||
# patch
|
||||
# ffcb7790f013bdceacc14ba5fda1c5cd107aac08
|
||||
patch -d "premake-core-${PV}" -p1 <patches/0001-Use-_SC_NPROCESSORS_ONLN-for-CPU-detection-in-BSDs.-.patch
|
||||
# https://github.com/premake/premake-core/issues/2338
|
||||
patch -d "premake-core-${PV}" -p1 <patches/0002-Make-clang-default-toolset-for-BSD.patch
|
||||
# 82c9d90495940e2d0d574e1c7849e9698f23b090
|
||||
patch -d "premake-core-${PV}" -p1 <patches/0003-Add-support-for-riscv64-2356.patch
|
||||
# 928397f72c00979d57ec4688cb1fb26ec7f2449b
|
||||
patch -d "premake-core-${PV}" -p1 <patches/0004-Add-support-for-loongarch64-2363.patch
|
||||
# 5c524b6d53307bcb4ba7b02c9dba20100df68943
|
||||
patch -d "premake-core-${PV}" -p1 <patches/0005-premake.h-added-e2k-definition-2349.patch
|
||||
patch -d "premake-core-${PV}" -p1 <patches/0001-Make-clang-default-toolset-for-BSD.patch
|
||||
|
||||
#build
|
||||
(
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
From 0641fc981d664d1fd7202f145a9c846ee0089b20 Mon Sep 17 00:00:00 2001
|
||||
From 4f02eba3f7279de3693aa2405e1c0700fcade23a Mon Sep 17 00:00:00 2001
|
||||
From: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
Date: Mon, 25 Nov 2024 15:57:10 +0100
|
||||
Subject: [PATCH] Make clang default toolset for *BSD
|
||||
@@ -11,10 +11,10 @@ Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/_premake_init.lua b/src/_premake_init.lua
|
||||
index a1043e25..ca901ffc 100644
|
||||
index 69f05fc9..c42c514f 100644
|
||||
--- a/src/_premake_init.lua
|
||||
+++ b/src/_premake_init.lua
|
||||
@@ -1597,7 +1597,7 @@
|
||||
@@ -1441,7 +1441,7 @@
|
||||
filter { "kind:SharedLib", "system:not Windows" }
|
||||
pic "On"
|
||||
|
||||
@@ -22,7 +22,7 @@ index a1043e25..ca901ffc 100644
|
||||
+ filter { "system:darwin or bsd" }
|
||||
toolset "clang"
|
||||
|
||||
filter { "platforms:Win32" }
|
||||
filter { "system:emscripten" }
|
||||
--
|
||||
2.45.2
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
From 6b52a675b7ec13619a64836a7d50ebcb7e0a09d4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jo=C3=A3o=20Matos?= <joao@tritao.eu>
|
||||
Date: Thu, 14 Nov 2024 13:42:21 +0000
|
||||
Subject: [PATCH] Use `_SC_NPROCESSORS_ONLN` for CPU detection in BSDs. (#2329)
|
||||
|
||||
Fixes https://github.com/premake/premake-core/issues/2328.
|
||||
---
|
||||
src/host/os_getnumcpus.c | 23 +----------------------
|
||||
1 file changed, 1 insertion(+), 22 deletions(-)
|
||||
|
||||
diff --git a/src/host/os_getnumcpus.c b/src/host/os_getnumcpus.c
|
||||
index f9b2fa93..57c478d5 100644
|
||||
--- a/src/host/os_getnumcpus.c
|
||||
+++ b/src/host/os_getnumcpus.c
|
||||
@@ -46,29 +46,8 @@ int do_getnumcpus()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
-#elif PLATFORM_SOLARIS | PLATFORM_AIX | PLATFORM_MACOSX
|
||||
+#elif PLATFORM_SOLARIS | PLATFORM_AIX | PLATFORM_MACOSX | PLATFORM_BSD
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
-#elif PLATFORM_BSD
|
||||
- int mib[4];
|
||||
- int numCPU;
|
||||
- size_t len = sizeof(numCPU);
|
||||
-
|
||||
- /* set the mib for hw.ncpu */
|
||||
- mib[0] = CTL_HW;
|
||||
- mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
|
||||
-
|
||||
- /* get the number of CPUs from the system */
|
||||
- sysctl(mib, 2, &numCPU, &len, NULL, 0);
|
||||
-
|
||||
- if (numCPU < 1)
|
||||
- {
|
||||
- mib[1] = HW_NCPU;
|
||||
- sysctl(mib, 2, &numCPU, &len, NULL, 0);
|
||||
- if (numCPU < 1)
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- return numCPU;
|
||||
#else
|
||||
#warning do_getnumcpus is not implemented for your platform yet
|
||||
return 0;
|
||||
--
|
||||
2.45.2
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
From 4a4491c96feb182d219759de0d9e7655d4ab39ec Mon Sep 17 00:00:00 2001
|
||||
From: Levi Zim <rsworktech@outlook.com>
|
||||
Date: Thu, 5 Dec 2024 23:52:42 +0800
|
||||
Subject: [PATCH] Add support for riscv64 (#2356)
|
||||
|
||||
* Add support for riscv64
|
||||
* Make error message clear when architecture is unknown
|
||||
---
|
||||
src/_premake_init.lua | 1 +
|
||||
src/base/_foundation.lua | 1 +
|
||||
src/host/premake.h | 4 ++++
|
||||
website/docs/architecture.md | 1 +
|
||||
4 files changed, 7 insertions(+)
|
||||
|
||||
diff --git a/src/_premake_init.lua b/src/_premake_init.lua
|
||||
index ca901ffc..184f0c43 100644
|
||||
--- a/src/_premake_init.lua
|
||||
+++ b/src/_premake_init.lua
|
||||
@@ -28,6 +28,7 @@
|
||||
p.X86_64,
|
||||
p.ARM,
|
||||
p.ARM64,
|
||||
+ p.RISCV64,
|
||||
},
|
||||
aliases = {
|
||||
i386 = p.X86,
|
||||
diff --git a/src/base/_foundation.lua b/src/base/_foundation.lua
|
||||
index 0c19a861..411eb536 100644
|
||||
--- a/src/base/_foundation.lua
|
||||
+++ b/src/base/_foundation.lua
|
||||
@@ -61,6 +61,7 @@
|
||||
premake.X86_64 = "x86_64"
|
||||
premake.ARM = "ARM"
|
||||
premake.ARM64 = "ARM64"
|
||||
+ premake.RISCV64 = "RISCV64"
|
||||
|
||||
|
||||
|
||||
diff --git a/src/host/premake.h b/src/host/premake.h
|
||||
index 9bf20380..788f8a38 100644
|
||||
--- a/src/host/premake.h
|
||||
+++ b/src/host/premake.h
|
||||
@@ -60,6 +60,10 @@
|
||||
#elif defined(__arm__) || defined(__thumb__) || defined(__TARGET_ARCH_ARM) || defined(__TARGET_ARCH_THUMB) || \
|
||||
defined(__ARM) || defined(_M_ARM) || defined(_M_ARM_T) || defined(__ARM_ARCH)
|
||||
#define PLATFORM_ARCHITECTURE "ARM"
|
||||
+#elif defined(_M_RISCV64) || (defined(__riscv) && __riscv_xlen == 64)
|
||||
+#define PLATFORM_ARCHITECTURE "RISCV64"
|
||||
+#elif !defined(RC_INVOKED)
|
||||
+#error Unknown architecture detected
|
||||
#endif
|
||||
|
||||
/* Pull in platform-specific headers required by built-in functions */
|
||||
diff --git a/website/docs/architecture.md b/website/docs/architecture.md
|
||||
index fb530453..0dbe352e 100644
|
||||
--- a/website/docs/architecture.md
|
||||
+++ b/website/docs/architecture.md
|
||||
@@ -13,6 +13,7 @@ architecture ("value")
|
||||
* `x86_64`
|
||||
* `ARM`
|
||||
* `ARM64`
|
||||
+* `RISCV64`
|
||||
* `armv5`: Only supported in VSAndroid projects
|
||||
* `armv7`: Only supported in VSAndroid projects
|
||||
* `aarch64`: Only supported in VSAndroid projects
|
||||
--
|
||||
2.45.2
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
From 64a8e8ae350a734b2b8512c4bcbba6e56a8e814e Mon Sep 17 00:00:00 2001
|
||||
From: Leo <114008189+Leoforever123@users.noreply.github.com>
|
||||
Date: Sat, 7 Dec 2024 11:21:24 +0800
|
||||
Subject: [PATCH] Add support for loongarch64 (#2363)
|
||||
|
||||
---
|
||||
src/_premake_init.lua | 1 +
|
||||
src/base/_foundation.lua | 1 +
|
||||
src/host/premake.h | 2 ++
|
||||
website/docs/architecture.md | 1 +
|
||||
4 files changed, 5 insertions(+)
|
||||
|
||||
diff --git a/src/_premake_init.lua b/src/_premake_init.lua
|
||||
index 184f0c43..d40558df 100644
|
||||
--- a/src/_premake_init.lua
|
||||
+++ b/src/_premake_init.lua
|
||||
@@ -29,6 +29,7 @@
|
||||
p.ARM,
|
||||
p.ARM64,
|
||||
p.RISCV64,
|
||||
+ p.LOONGARCH64
|
||||
},
|
||||
aliases = {
|
||||
i386 = p.X86,
|
||||
diff --git a/src/base/_foundation.lua b/src/base/_foundation.lua
|
||||
index 411eb536..4581d2c0 100644
|
||||
--- a/src/base/_foundation.lua
|
||||
+++ b/src/base/_foundation.lua
|
||||
@@ -62,6 +62,7 @@
|
||||
premake.ARM = "ARM"
|
||||
premake.ARM64 = "ARM64"
|
||||
premake.RISCV64 = "RISCV64"
|
||||
+ premake.LOONGARCH64 = "loongarch64"
|
||||
|
||||
|
||||
|
||||
diff --git a/src/host/premake.h b/src/host/premake.h
|
||||
index 788f8a38..4e15b863 100644
|
||||
--- a/src/host/premake.h
|
||||
+++ b/src/host/premake.h
|
||||
@@ -62,6 +62,8 @@
|
||||
#define PLATFORM_ARCHITECTURE "ARM"
|
||||
#elif defined(_M_RISCV64) || (defined(__riscv) && __riscv_xlen == 64)
|
||||
#define PLATFORM_ARCHITECTURE "RISCV64"
|
||||
+#elif (defined(__loongarch__) && __loongarch_grlen == 64) || defined(__loongarch64)
|
||||
+#define PLATFORM_ARCHITECTURE "loongarch64"
|
||||
#elif !defined(RC_INVOKED)
|
||||
#error Unknown architecture detected
|
||||
#endif
|
||||
diff --git a/website/docs/architecture.md b/website/docs/architecture.md
|
||||
index 0dbe352e..e7f4283f 100644
|
||||
--- a/website/docs/architecture.md
|
||||
+++ b/website/docs/architecture.md
|
||||
@@ -14,6 +14,7 @@ architecture ("value")
|
||||
* `ARM`
|
||||
* `ARM64`
|
||||
* `RISCV64`
|
||||
+* `loongarch64`
|
||||
* `armv5`: Only supported in VSAndroid projects
|
||||
* `armv7`: Only supported in VSAndroid projects
|
||||
* `aarch64`: Only supported in VSAndroid projects
|
||||
--
|
||||
2.45.2
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
From a4fa1da72cc969bb85e575be25acd5aaef2edc49 Mon Sep 17 00:00:00 2001
|
||||
From: r-a-sattarov <51679282+r-a-sattarov@users.noreply.github.com>
|
||||
Date: Sun, 8 Dec 2024 22:39:47 +0300
|
||||
Subject: [PATCH] premake.h - added e2k definition (#2349)
|
||||
|
||||
---
|
||||
src/host/premake.h | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/host/premake.h b/src/host/premake.h
|
||||
index 4e15b863..25ccf33a 100644
|
||||
--- a/src/host/premake.h
|
||||
+++ b/src/host/premake.h
|
||||
@@ -64,6 +64,8 @@
|
||||
#define PLATFORM_ARCHITECTURE "RISCV64"
|
||||
#elif (defined(__loongarch__) && __loongarch_grlen == 64) || defined(__loongarch64)
|
||||
#define PLATFORM_ARCHITECTURE "loongarch64"
|
||||
+#elif defined(__e2k__)
|
||||
+#define PLATFORM_ARCHITECTURE "e2k"
|
||||
#elif !defined(RC_INVOKED)
|
||||
#error Unknown architecture detected
|
||||
#endif
|
||||
--
|
||||
2.45.2
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
: "${TAR:=tar}"
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# This should match the version in config/milestone.txt
|
||||
FOLDER="mozjs-115.16.1"
|
||||
# If same-version changes are needed, increment this.
|
||||
LIB_VERSION="115.16.1+1"
|
||||
LIB_VERSION="115.16.1+a27.1"
|
||||
LIB_NAME="mozjs115"
|
||||
|
||||
fetch()
|
||||
@@ -47,7 +49,7 @@ fi
|
||||
|
||||
# unpack
|
||||
rm -Rf "${FOLDER}"
|
||||
tar xfJ "${FOLDER}.tar.xz"
|
||||
"${TAR}" xfJ "${FOLDER}.tar.xz"
|
||||
|
||||
# patch
|
||||
(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/modules/fdlibm/src/math_private.h
|
||||
+++ b/modules/fdlibm/src/math_private.h
|
||||
@@ -30,8 +30,13 @@
|
||||
@@ -30,7 +30,11 @@
|
||||
* Adapted from https://github.com/freebsd/freebsd-src/search?q=__double_t
|
||||
*/
|
||||
|
||||
@@ -10,10 +10,9 @@
|
||||
typedef double __double_t;
|
||||
+#endif
|
||||
typedef __double_t double_t;
|
||||
+typedef float __float_t;
|
||||
typedef float __float_t;
|
||||
|
||||
/*
|
||||
* The original fdlibm code used statements like:
|
||||
|
||||
@@ -630,6 +634,53 @@
|
||||
return ((double)(x + 0x1.8p52) - 0x1.8p52);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
: "${TAR:=tar}"
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PV=1.3.290.0
|
||||
@@ -40,7 +42,7 @@ fi
|
||||
|
||||
# unpack
|
||||
rm -Rf "SPIRV-Reflect-vulkan-sdk-${PV}"
|
||||
tar xf "vulkan-sdk-${PV}.tar.gz"
|
||||
"${TAR}" xf "vulkan-sdk-${PV}.tar.gz"
|
||||
|
||||
# configure
|
||||
cmake -B build -S "SPIRV-Reflect-vulkan-sdk-${PV}" \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -236,12 +236,10 @@ void CModel::ValidatePosition()
|
||||
// For CPU skinning, we precompute as much as possible so that the only
|
||||
// per-vertex work is a single matrix*vec multiplication.
|
||||
// For GPU skinning, we try to minimise CPU work by doing most computation
|
||||
// in the vertex shader instead.
|
||||
// Using g_RenderingOptions to detect CPU vs GPU is a bit hacky,
|
||||
// and this doesn't allow the setting to change at runtime, but there isn't
|
||||
// an obvious cleaner way to determine what data needs to be computed.
|
||||
bool worldSpaceBoneMatrices = !g_RenderingOptions.GetGPUSkinning();
|
||||
bool computeBlendMatrices = !g_RenderingOptions.GetGPUSkinning();
|
||||
// in the compute shader instead.
|
||||
const bool isGPUSkinningEnabled{g_RenderingOptions.GetGPUSkinning()};
|
||||
const bool worldSpaceBoneMatrices{!isGPUSkinningEnabled};
|
||||
const bool computeBlendMatrices{!isGPUSkinningEnabled};
|
||||
|
||||
if (m_BoneMatrices && worldSpaceBoneMatrices)
|
||||
{
|
||||
|
||||
@@ -370,7 +370,7 @@ void CGUIManager::TickObjects()
|
||||
|
||||
// We share the script context with everything else that runs in the same thread.
|
||||
// This call makes sure we trigger GC regularly even if the simulation is not running.
|
||||
m_ScriptContext.MaybeIncrementalGC(1.0f);
|
||||
m_ScriptContext.MaybeIncrementalGC();
|
||||
|
||||
// Save an immutable copy so iterators aren't invalidated by tick handlers
|
||||
PageStackType pageStack = m_PageStack;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@@ -20,6 +20,6 @@
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define PYROGENESIS_VERSION "0.27.0"
|
||||
#define PYROGENESIS_VERSION_WORD 0,27,0,0
|
||||
#define PYROGENESIS_VERSION "0.27.1"
|
||||
#define PYROGENESIS_VERSION_WORD 0,27,1,0
|
||||
extern wchar_t build_version[];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
virtual void SetNick(const std::string& nick) = 0;
|
||||
virtual std::string GetNick() const = 0;
|
||||
virtual std::string GetJID() const = 0;
|
||||
virtual std::string GetUsername() const = 0;
|
||||
virtual void ChangePassword(const std::string& newPassword) = 0;
|
||||
virtual void kick(const std::string& nick, const std::string& reason) = 0;
|
||||
virtual void ban(const std::string& nick, const std::string& reason) = 0;
|
||||
|
||||
@@ -169,6 +169,8 @@ XmppClient::XmppClient(const ScriptInterface* scriptInterface, const std::string
|
||||
*/
|
||||
XmppClient::~XmppClient()
|
||||
{
|
||||
this->disconnect();
|
||||
|
||||
DbgXMPP("XmppClient destroyed");
|
||||
delete m_registration;
|
||||
delete m_mucRoom;
|
||||
@@ -1183,9 +1185,9 @@ const std::wstring& XmppClient::GetSubject()
|
||||
}
|
||||
|
||||
/**
|
||||
* Request nick change, real change via mucRoomHandler.
|
||||
* Request MUC nick change, real change via mucRoomHandler.
|
||||
*
|
||||
* @param nick Desired nickname
|
||||
* @param nick Desired MUC nickname
|
||||
*/
|
||||
void XmppClient::SetNick(const std::string& nick)
|
||||
{
|
||||
@@ -1193,7 +1195,7 @@ void XmppClient::SetNick(const std::string& nick)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current nickname.
|
||||
* Get current MUC nickname.
|
||||
*/
|
||||
std::string XmppClient::GetNick() const
|
||||
{
|
||||
@@ -1205,6 +1207,17 @@ std::string XmppClient::GetJID() const
|
||||
return m_client->jid().full();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the XMPP username.
|
||||
*
|
||||
* @return current XMPP username
|
||||
*/
|
||||
std::string XmppClient::GetUsername() const
|
||||
{
|
||||
return m_username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change password for authenticated user.
|
||||
*
|
||||
@@ -1212,7 +1225,7 @@ std::string XmppClient::GetJID() const
|
||||
*/
|
||||
void XmppClient::ChangePassword(const std::string& newPassword)
|
||||
{
|
||||
m_registration->changePassword(m_username, newPassword);
|
||||
m_registration->changePassword(m_client->jid().username(), newPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
void SetNick(const std::string& nick) override;
|
||||
std::string GetNick() const override;
|
||||
std::string GetJID() const override;
|
||||
std::string GetUsername() const override;
|
||||
void ChangePassword(const std::string& newPassword) override;
|
||||
void kick(const std::string& nick, const std::string& reason) override;
|
||||
void ban(const std::string& nick, const std::string& reason) override;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -218,6 +218,7 @@ void RegisterScriptFunctions(const ScriptRequest& rq)
|
||||
REGISTER_XMPP(SetNick, "LobbySetNick");
|
||||
REGISTER_XMPP(GetNick, "LobbyGetNick");
|
||||
REGISTER_XMPP(GetJID, "LobbyGetJID");
|
||||
REGISTER_XMPP(GetUsername, "LobbyGetUsername");
|
||||
REGISTER_XMPP(ChangePassword, "LobbyChangePassword");
|
||||
REGISTER_XMPP(kick, "LobbyKick");
|
||||
REGISTER_XMPP(ban, "LobbyBan");
|
||||
|
||||
@@ -193,20 +193,20 @@ bool CNetServerWorker::SetupConnection(const u16 port)
|
||||
|
||||
#if CONFIG2_MINIUPNPC
|
||||
// Launch the UPnP thread
|
||||
m_UPnPThread = std::thread(Threading::HandleExceptions<SetupUPnP>::Wrapper);
|
||||
m_UPnPThread = std::thread(Threading::HandleExceptions<SetupUPnP>::Wrapper, port);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if CONFIG2_MINIUPNPC
|
||||
void CNetServerWorker::SetupUPnP()
|
||||
void CNetServerWorker::SetupUPnP(const u16 port)
|
||||
{
|
||||
debug_SetThreadName("UPnP");
|
||||
|
||||
// Values we want to set.
|
||||
char psPort[6];
|
||||
sprintf_s(psPort, ARRAY_SIZE(psPort), "%d", PS_DEFAULT_PORT);
|
||||
sprintf_s(psPort, ARRAY_SIZE(psPort), "%d", port);
|
||||
const char* leaseDuration = "0"; // Indefinite/permanent lease duration.
|
||||
const char* description = "0AD Multiplayer";
|
||||
const char* protocall = "UDP";
|
||||
@@ -242,7 +242,7 @@ void CNetServerWorker::SetupUPnP()
|
||||
int ret = 0;
|
||||
|
||||
// Try a cached URL first
|
||||
if (!rootDescURL.empty() && UPNP_GetIGDFromUrl(rootDescURL.c_str(), &urls, &data, internalIPAddress, sizeof(internalIPAddress)))
|
||||
if (!rootDescURL.empty() && UPNP_GetIGDFromUrl(rootDescURL.c_str(), &urls, &data, internalIPAddress, sizeof(internalIPAddress)) && strlen(data.first.controlurl) != 0)
|
||||
{
|
||||
LOGMESSAGE("Net server: using cached IGD = %s", urls.controlURL);
|
||||
ret = 1;
|
||||
@@ -339,9 +339,9 @@ void CNetServerWorker::SetupUPnP()
|
||||
externalIPAddress, psPort, protocall, intClient, intPort, duration);
|
||||
|
||||
// Cache root descriptor URL to try to avoid discovery next time.
|
||||
g_ConfigDB.SetValueString(CFG_USER, "network.upnprootdescurl", urls.controlURL);
|
||||
g_ConfigDB.WriteValueToFile(CFG_USER, "network.upnprootdescurl", urls.controlURL);
|
||||
LOGMESSAGE("Net server: cached UPnP root descriptor URL as %s", urls.controlURL);
|
||||
g_ConfigDB.SetValueString(CFG_USER, "network.upnprootdescurl", urls.rootdescURL);
|
||||
g_ConfigDB.WriteValueToFile(CFG_USER, "network.upnprootdescurl", urls.rootdescURL);
|
||||
LOGMESSAGE("Net server: cached UPnP root descriptor URL as %s", urls.rootdescURL);
|
||||
|
||||
freeUPnP();
|
||||
}
|
||||
@@ -424,7 +424,7 @@ bool CNetServerWorker::RunStep()
|
||||
// (Do as little work as possible while the mutex is held open,
|
||||
// to avoid performance problems and deadlocks.)
|
||||
|
||||
m_ScriptInterface->GetContext().MaybeIncrementalGC(0.5f);
|
||||
m_ScriptInterface->GetContext().MaybeIncrementalGC();
|
||||
|
||||
ScriptRequest rq(m_ScriptInterface);
|
||||
|
||||
|
||||
@@ -436,7 +436,7 @@ private:
|
||||
/**
|
||||
* Try to find a UPnP root on the network and setup port forwarding.
|
||||
*/
|
||||
static void SetupUPnP();
|
||||
static void SetupUPnP(const u16 port);
|
||||
std::thread m_UPnPThread;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "renderer/TimeManager.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
#include "scriptinterface/FunctionWrapper.h"
|
||||
#include "scriptinterface/ScriptContext.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "scriptinterface/JSON.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
@@ -331,6 +332,11 @@ PSRETURN CGame::ReallyStartGame()
|
||||
// all be invisible)
|
||||
Interpolate(0, 0);
|
||||
|
||||
// Run a shrinking GC to reset the memory before starting the game proper.
|
||||
// This also clears JIT code, which seems like a good idea as the game init
|
||||
// might have different patterns to the game itself.
|
||||
m_Simulation2->GetScriptInterface().GetContext().ShrinkingGC();
|
||||
|
||||
m_GameStarted = true;
|
||||
|
||||
// Preload resources to avoid blinking on a first game frame.
|
||||
|
||||
@@ -348,7 +348,7 @@ void ShutdownNetworkAndUI()
|
||||
if (hasRenderer)
|
||||
{
|
||||
TIMER_BEGIN(L"shutdown Renderer");
|
||||
g_Renderer.~CRenderer();
|
||||
delete &g_Renderer;
|
||||
TIMER_END(L"shutdown Renderer");
|
||||
}
|
||||
|
||||
@@ -535,7 +535,7 @@ bool Init(const CmdLineArgs& args, int flags)
|
||||
// Using a global object for the context is a workaround until Simulation and AI use
|
||||
// their own threads and also their own contexts.
|
||||
const int contextSize = 384 * 1024 * 1024;
|
||||
const int heapGrowthBytesGCTrigger = 20 * 1024 * 1024;
|
||||
const int heapGrowthBytesGCTrigger = 12 * 1024 * 1024;
|
||||
g_ScriptContext = ScriptContext::CreateContext(contextSize, heapGrowthBytesGCTrigger);
|
||||
|
||||
// On the first Init (INIT_MODS), check for command-line arguments
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -71,7 +71,6 @@ namespace {
|
||||
|
||||
static_assert(std::is_integral<std::underlying_type<SDL_Scancode>::type>::value, "SDL_Scancode is not an integral enum.");
|
||||
static_assert(SDL_USEREVENT_ == SDL_USEREVENT, "SDL_USEREVENT_ is not the same type as the real SDL_USEREVENT");
|
||||
static_assert(UNUSED_HOTKEY_CODE == SDL_SCANCODE_UNKNOWN);
|
||||
|
||||
// Look up each key binding in the config file and set the mappings for
|
||||
// all key combinations that trigger it.
|
||||
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -49,7 +49,8 @@ const uint SDL_HOTKEYUP = SDL_USEREVENT_ + 2;
|
||||
const uint SDL_HOTKEYPRESS_SILENT = SDL_USEREVENT_ + 3;
|
||||
const uint SDL_HOTKEYUP_SILENT = SDL_USEREVENT_ + 4;
|
||||
|
||||
constexpr SDL_Scancode_ UNUSED_HOTKEY_CODE = 0; // == SDL_SCANCODE_UNKNOWN
|
||||
// Value not mapping to any valid SDL_SCANCODE_*
|
||||
constexpr SDL_Scancode_ UNUSED_HOTKEY_CODE{-1};
|
||||
|
||||
struct SKey
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "ps/CStr.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ void CReplayPlayer::Replay(const bool serializationtest, const int rejointesttur
|
||||
g_ProfileViewer.AddRootTable(g_ScriptStatsTable);
|
||||
|
||||
const int contextSize = 384 * 1024 * 1024;
|
||||
const int heapGrowthBytesGCTrigger = 20 * 1024 * 1024;
|
||||
const int heapGrowthBytesGCTrigger = 12 * 1024 * 1024;
|
||||
g_ScriptContext = ScriptContext::CreateContext(contextSize, heapGrowthBytesGCTrigger);
|
||||
|
||||
std::vector<SimulationCommand> commands;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -76,7 +76,7 @@ void SetPlayerID(const ScriptRequest& rq, int id)
|
||||
if (currentID == id)
|
||||
return;
|
||||
|
||||
if (g_Game->CheatsEnabled())
|
||||
if (g_Game->CheatsEnabled() || g_Game->IsVisualReplay())
|
||||
g_Game->SetPlayerID(id);
|
||||
else
|
||||
ScriptException::Raise(rq, "Changing player ID with cheats disabled is prohibited");
|
||||
@@ -89,7 +89,7 @@ void SetViewedPlayer(const ScriptRequest& rq, int id)
|
||||
|
||||
int playerID = g_Game->GetPlayerID();
|
||||
// Forbid active players to reveal the map by changing perspective, unless cheats are allowed.
|
||||
if (playerID == -1 || g_Game->CheatsEnabled() || g_Game->PlayerFinished(playerID))
|
||||
if (playerID == -1 || g_Game->CheatsEnabled() || g_Game->PlayerFinished(playerID) || g_Game->IsVisualReplay())
|
||||
g_Game->SetViewedPlayerID(id);
|
||||
else
|
||||
ScriptException::Raise(rq, "Changing the perspective with cheats disabled is prohibited");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -219,6 +219,7 @@ void ShaderModelRenderer::Submit(int cullGroup, CModel* model)
|
||||
const void* key = m->vertexRenderer.get();
|
||||
if (!rdata || rdata->GetKey() != key)
|
||||
{
|
||||
model->InvalidatePosition();
|
||||
rdata = m->vertexRenderer->CreateModelData(key, model);
|
||||
model->SetRenderData(rdata);
|
||||
model->SetDirty(~0u);
|
||||
|
||||
@@ -262,6 +262,9 @@ void CRenderingOptions::ReadConfigAndSetupHooks()
|
||||
m_GPUSkinning = true;
|
||||
else
|
||||
LOGMESSAGE("GPU skinning isn't supported on the current hardware.");
|
||||
|
||||
if (CRenderer::IsInitialised())
|
||||
g_Renderer.MakeShadersDirty();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -362,8 +362,7 @@ std::unique_ptr<IDevice> CDevice::Create(SDL_Window* window, const bool arb)
|
||||
capabilities.ARBShaders = !ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", nullptr);
|
||||
if (capabilities.ARBShaders)
|
||||
capabilities.ARBShadersShadow = ogl_HaveExtension("GL_ARB_fragment_program_shadow");
|
||||
capabilities.computeShaders = !device->m_ARB &&
|
||||
(ogl_HaveVersion(4, 3) || (ogl_HaveVersion(4, 2) && ogl_HaveExtension("GL_ARB_compute_shader") && ogl_HaveExtension("GL_ARB_shader_image_load_store")));
|
||||
capabilities.computeShaders = !device->m_ARB && ogl_HaveVersion(4, 3);
|
||||
#if CONFIG2_GLES
|
||||
// Some GLES implementations have GL_EXT_texture_compression_dxt1
|
||||
// but that only supports DXT1 so we can't use it.
|
||||
|
||||
@@ -246,6 +246,9 @@ CDeviceCommandContext::CDeviceCommandContext(CDevice* device)
|
||||
for (size_t index = 0; index < m_BoundBuffers.size(); ++index)
|
||||
{
|
||||
const CBuffer::Type type = static_cast<CBuffer::Type>(index);
|
||||
// Currently we don't support upload buffers for GL.
|
||||
if (type == CBuffer::Type::UPLOAD)
|
||||
continue;
|
||||
const GLenum target = BufferTypeToGLTarget(type);
|
||||
const GLuint handle = 0;
|
||||
m_BoundBuffers[index].first = target;
|
||||
@@ -1456,6 +1459,7 @@ CDeviceCommandContext::ScopedBufferBind::ScopedBufferBind(
|
||||
{
|
||||
ENSURE(buffer);
|
||||
m_CacheIndex = static_cast<size_t>(buffer->GetType());
|
||||
ENSURE(m_CacheIndex < m_DeviceCommandContext->m_BoundBuffers.size());
|
||||
const GLenum target = BufferTypeToGLTarget(buffer->GetType());
|
||||
const GLuint handle = buffer->GetHandle();
|
||||
if (m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].first == target &&
|
||||
|
||||
@@ -221,7 +221,7 @@ private:
|
||||
};
|
||||
|
||||
using BoundBuffer = std::pair<GLenum, GLuint>;
|
||||
std::array<BoundBuffer, 2> m_BoundBuffers;
|
||||
std::array<BoundBuffer, 4> m_BoundBuffers;
|
||||
class ScopedBufferBind
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -135,7 +135,7 @@ template<typename T>
|
||||
inline bool GetObjectClassName(const ScriptRequest& rq, JS::HandleObject obj, T& name)
|
||||
{
|
||||
JS::RootedValue constructor(rq.cx, JS::ObjectOrNullValue(JS_GetConstructor(rq.cx, obj)));
|
||||
return constructor.isObject() && Script::HasProperty(rq, constructor, "name") && Script::GetProperty(rq, constructor, "name", name);
|
||||
return constructor.isObject() && Script::GetProperty(rq, constructor, "name", name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "scriptinterface/ScriptEngine.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
|
||||
#include "js/friend/PerformanceHint.h"
|
||||
|
||||
void GCSliceCallbackHook(JSContext* UNUSED(cx), JS::GCProgress progress, const JS::GCDescription& UNUSED(desc))
|
||||
{
|
||||
/**
|
||||
@@ -57,7 +59,8 @@ void GCSliceCallbackHook(JSContext* UNUSED(cx), JS::GCProgress progress, const J
|
||||
if (progress == JS::GCProgress::GC_CYCLE_BEGIN)
|
||||
printf("starting cycle ===========================================\n");
|
||||
|
||||
const char16_t* str = desc.formatMessage(cx);
|
||||
//const char16_t* str = desc.formatMessage(cx);
|
||||
const char16_t* str = desc.formatSliceMessage(cx);
|
||||
int len = 0;
|
||||
|
||||
for(int i = 0; i < 10000; i++)
|
||||
@@ -75,15 +78,22 @@ void GCSliceCallbackHook(JSContext* UNUSED(cx), JS::GCProgress progress, const J
|
||||
}
|
||||
|
||||
printf("---------------------------------------\n: %ls \n---------------------------------------\n", outstring);
|
||||
|
||||
const uint32_t gcBytes = JS_GetGCParameter(cx, JSGC_BYTES);
|
||||
|
||||
printf("gcBytes: %i KB\n", gcBytes / 1024);
|
||||
|
||||
if (progress == JS::GCProgress::GC_SLICE_END)
|
||||
printf("ending cycle ===========================================\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::shared_ptr<ScriptContext> ScriptContext::CreateContext(int contextSize, int heapGrowthBytesGCTrigger)
|
||||
std::shared_ptr<ScriptContext> ScriptContext::CreateContext(int contextSize, uint32_t heapGrowthBytesGCTrigger)
|
||||
{
|
||||
return std::make_shared<ScriptContext>(contextSize, heapGrowthBytesGCTrigger);
|
||||
}
|
||||
|
||||
ScriptContext::ScriptContext(int contextSize, int heapGrowthBytesGCTrigger):
|
||||
ScriptContext::ScriptContext(int contextSize, uint32_t heapGrowthBytesGCTrigger):
|
||||
m_JobQueue{std::make_unique<Script::JobQueue>()},
|
||||
m_ContextSize{contextSize},
|
||||
m_HeapGrowthBytesGCTrigger{heapGrowthBytesGCTrigger}
|
||||
@@ -110,6 +120,12 @@ ScriptContext::ScriptContext(int contextSize, int heapGrowthBytesGCTrigger):
|
||||
JS_SetGCParameter(m_cx, JSGC_INCREMENTAL_GC_ENABLED, true);
|
||||
JS_SetGCParameter(m_cx, JSGC_PER_ZONE_GC_ENABLED, false);
|
||||
|
||||
// Set a low time budget to avoid lag spikes, but allow any number of last ditch GCs
|
||||
// to avoid OOM errors.
|
||||
JS_SetGCParameter(m_cx, JSGC_SLICE_TIME_BUDGET_MS, 10);
|
||||
JS_SetGCParameter(m_cx, JSGC_MIN_LAST_DITCH_GC_PERIOD, 0);
|
||||
|
||||
|
||||
JS_SetOffthreadIonCompilationEnabled(m_cx, true);
|
||||
|
||||
// For GC debugging:
|
||||
@@ -129,6 +145,10 @@ ScriptContext::ScriptContext(int contextSize, int heapGrowthBytesGCTrigger):
|
||||
|
||||
JS::ContextOptionsRef(m_cx).setStrictMode(true);
|
||||
|
||||
// Workaround to turn off nursery size heuristic.
|
||||
// See https://gitea.wildfiregames.com/0ad/0ad/issues/7714 for details.
|
||||
js::gc::SetPerformanceHint(m_cx, js::gc::PerformanceHint::InPageLoad);
|
||||
|
||||
ScriptEngine::GetSingleton().RegisterContext(m_cx);
|
||||
|
||||
JS::SetJobQueue(m_cx, m_JobQueue.get());
|
||||
@@ -139,6 +159,9 @@ ScriptContext::~ScriptContext()
|
||||
{
|
||||
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be active (initialized and not yet shut down) when destroying a ScriptContext!");
|
||||
|
||||
// Switch back to normal performance mode to avoid assertion in debug mode.
|
||||
js::gc::SetPerformanceHint(m_cx, js::gc::PerformanceHint::Normal);
|
||||
|
||||
JS_DestroyContext(m_cx);
|
||||
ScriptEngine::GetSingleton().UnRegisterContext(m_cx);
|
||||
}
|
||||
@@ -159,105 +182,71 @@ void ScriptContext::UnRegisterRealm(JS::Realm* realm)
|
||||
}
|
||||
|
||||
#define GC_DEBUG_PRINT 0
|
||||
void ScriptContext::MaybeIncrementalGC(double delay)
|
||||
void ScriptContext::MaybeIncrementalGC()
|
||||
{
|
||||
PROFILE2("MaybeIncrementalGC");
|
||||
|
||||
if (JS::IsIncrementalGCEnabled(m_cx))
|
||||
if (!JS::IsIncrementalGCEnabled(m_cx))
|
||||
return;
|
||||
|
||||
// The idea is to get the heap size after a completed GC and trigger the next GC
|
||||
// when the heap size has reached m_LastGCBytes + X.
|
||||
// Spidermonkey allocates memory arenas of 4KB for JS heap data.
|
||||
// At the end of a GC, any such arena that became empty is freed.
|
||||
// On shrinking GCs, spidermonkey further defragments the arenas, which effectively frees more memory but costs time.
|
||||
// In practice, shrinking GCs also dump JITted code and the defragmentation is not worth it for 0 A.D.
|
||||
// The regular GCs also free quite a bit of memory anyways, and non-full arenas get used for new objects.
|
||||
|
||||
const uint32_t gcBytes = JS_GetGCParameter(m_cx, JSGC_BYTES);
|
||||
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("gcBytes: %i KB, last of %i KB\n", gcBytes / 1024, m_LastGCBytes / 1024);
|
||||
#endif
|
||||
|
||||
// The memory freeing happens mostly in the background, so we can't rely on the value on the last incremental slice.
|
||||
// To fix that, just remember a 'minimum' value.
|
||||
if (m_LastGCBytes > gcBytes || m_LastGCBytes == 0)
|
||||
{
|
||||
// The idea is to get the heap size after a completed GC and trigger the next GC when the heap size has
|
||||
// reached m_LastGCBytes + X.
|
||||
// In practice it doesn't quite work like that. When the incremental marking is completed, the sweeping kicks in.
|
||||
// The sweeping actually frees memory and it does this in a background thread (if JS_USE_HELPER_THREADS is set).
|
||||
// While the sweeping is happening we already run scripts again and produce new garbage.
|
||||
|
||||
const js::SliceBudget GCSliceTimeBudget = js::SliceBudget(js::TimeBudget(30)); // Milliseconds an incremental slice is allowed to run
|
||||
|
||||
// Have a minimum time in seconds to wait between GC slices and before starting a new GC to distribute the GC
|
||||
// load and to hopefully make it unnoticeable for the player. This value should be high enough to distribute
|
||||
// the load well enough and low enough to make sure we don't run out of memory before we can start with the
|
||||
// sweeping.
|
||||
if (timer_Time() - m_LastGCCheck < delay)
|
||||
return;
|
||||
|
||||
m_LastGCCheck = timer_Time();
|
||||
|
||||
int gcBytes = JS_GetGCParameter(m_cx, JSGC_BYTES);
|
||||
|
||||
#if GC_DEBUG_PRINT
|
||||
std::cout << "gcBytes: " << gcBytes / 1024 << " KB" << std::endl;
|
||||
printf("Setting m_LastGCBytes: %d KB \n", gcBytes / 1024);
|
||||
#endif
|
||||
m_LastGCBytes = gcBytes;
|
||||
}
|
||||
|
||||
// Run an additional incremental GC slice if the currently running incremental GC isn't over yet
|
||||
// ... or
|
||||
// start a new incremental GC if the JS heap size has grown enough for a GC to make sense
|
||||
if (JS::IsIncrementalGCInProgress(m_cx) || (gcBytes - m_LastGCBytes > m_HeapGrowthBytesGCTrigger))
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
if (JS::IsIncrementalGCInProgress(m_cx))
|
||||
printf("An incremental GC cycle is in progress. \n");
|
||||
else
|
||||
printf("GC needed because JSGC_BYTES - m_LastGCBytes > m_HeapGrowthBytesGCTrigger \n"
|
||||
" JSGC_BYTES: %d KB \n m_LastGCBytes: %d KB \n m_HeapGrowthBytesGCTrigger: %d KB \n",
|
||||
gcBytes / 1024,
|
||||
m_LastGCBytes / 1024,
|
||||
m_HeapGrowthBytesGCTrigger / 1024);
|
||||
#endif
|
||||
|
||||
if (m_LastGCBytes > gcBytes || m_LastGCBytes == 0)
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Setting m_LastGCBytes: %d KB \n", gcBytes / 1024);
|
||||
#endif
|
||||
m_LastGCBytes = gcBytes;
|
||||
}
|
||||
|
||||
// Run an additional incremental GC slice if the currently running incremental GC isn't over yet
|
||||
// ... or
|
||||
// start a new incremental GC if the JS heap size has grown enough for a GC to make sense
|
||||
if (JS::IsIncrementalGCInProgress(m_cx) || (gcBytes - m_LastGCBytes > m_HeapGrowthBytesGCTrigger))
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
if (JS::IsIncrementalGCInProgress(m_cx))
|
||||
printf("An incremental GC cycle is in progress. \n");
|
||||
else
|
||||
printf("GC needed because JSGC_BYTES - m_LastGCBytes > m_HeapGrowthBytesGCTrigger \n"
|
||||
" JSGC_BYTES: %d KB \n m_LastGCBytes: %d KB \n m_HeapGrowthBytesGCTrigger: %d KB \n",
|
||||
gcBytes / 1024,
|
||||
m_LastGCBytes / 1024,
|
||||
m_HeapGrowthBytesGCTrigger / 1024);
|
||||
if (!JS::IsIncrementalGCInProgress(m_cx))
|
||||
printf("Starting incremental GC \n");
|
||||
else
|
||||
printf("Running incremental GC slice \n");
|
||||
#endif
|
||||
|
||||
// A hack to make sure we never exceed the context size because we can't collect the memory
|
||||
// fast enough.
|
||||
if (gcBytes > m_ContextSize / 2)
|
||||
{
|
||||
if (JS::IsIncrementalGCInProgress(m_cx))
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Finishing incremental GC because gcBytes > m_ContextSize / 2. \n");
|
||||
#endif
|
||||
PrepareZonesForIncrementalGC();
|
||||
JS::FinishIncrementalGC(m_cx, JS::GCReason::API);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gcBytes > m_ContextSize * 0.75)
|
||||
{
|
||||
ShrinkingGC();
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Running shrinking GC because gcBytes > m_ContextSize * 0.75. \n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Running full GC because gcBytes > m_ContextSize / 2. \n");
|
||||
#endif
|
||||
JS_GC(m_cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
if (!JS::IsIncrementalGCInProgress(m_cx))
|
||||
printf("Starting incremental GC \n");
|
||||
else
|
||||
printf("Running incremental GC slice \n");
|
||||
#endif
|
||||
PrepareZonesForIncrementalGC();
|
||||
if (!JS::IsIncrementalGCInProgress(m_cx))
|
||||
JS::StartIncrementalGC(m_cx, JS::GCOptions::Normal, JS::GCReason::API, GCSliceTimeBudget);
|
||||
else
|
||||
JS::IncrementalGCSlice(m_cx, JS::GCReason::API, GCSliceTimeBudget);
|
||||
}
|
||||
m_LastGCBytes = gcBytes;
|
||||
}
|
||||
// There is a tradeoff between this time and the number of frames we must run GCs on, but overall we should prioritize smooth framerates.
|
||||
const js::SliceBudget GCSliceTimeBudget = js::SliceBudget(js::TimeBudget(6)); // Milliseconds an incremental slice is allowed to run. SM respects this fairly well.
|
||||
|
||||
PrepareZonesForIncrementalGC();
|
||||
if (!JS::IsIncrementalGCInProgress(m_cx))
|
||||
JS::StartIncrementalGC(m_cx, JS::GCOptions::Normal, JS::GCReason::API, GCSliceTimeBudget);
|
||||
else
|
||||
JS::IncrementalGCSlice(m_cx, JS::GCReason::API, GCSliceTimeBudget);
|
||||
|
||||
// Reset this here so that the minimum gets cleared.
|
||||
m_LastGCBytes = gcBytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
// Those are minimal defaults. The runtime for the main game is larger and GCs upon a larger growth.
|
||||
constexpr int DEFAULT_CONTEXT_SIZE = 16 * 1024 * 1024;
|
||||
constexpr int DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER = 2 * 1024 * 1024;
|
||||
constexpr uint32_t DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER = 2 * 1024 * 1024;
|
||||
|
||||
namespace Script
|
||||
{
|
||||
@@ -45,7 +45,7 @@ class JobQueue;
|
||||
class ScriptContext
|
||||
{
|
||||
public:
|
||||
ScriptContext(int contextSize, int heapGrowthBytesGCTrigger);
|
||||
ScriptContext(int contextSize, uint32_t heapGrowthBytesGCTrigger);
|
||||
~ScriptContext();
|
||||
|
||||
/**
|
||||
@@ -57,20 +57,26 @@ public:
|
||||
*/
|
||||
static std::shared_ptr<ScriptContext> CreateContext(
|
||||
int contextSize = DEFAULT_CONTEXT_SIZE,
|
||||
int heapGrowthBytesGCTrigger = DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER);
|
||||
uint32_t heapGrowthBytesGCTrigger = DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER);
|
||||
|
||||
|
||||
/**
|
||||
* MaybeIncrementalGC tries to determine whether a context-wide garbage collection would free up enough memory to
|
||||
* be worth the amount of time it would take. It does this with our own logic and NOT some predefined JSAPI logic because
|
||||
* such functionality currently isn't available out of the box.
|
||||
* It does incremental GC which means it will collect one slice each time it's called until the garbage collection is done.
|
||||
* This can and should be called quite regularly. The delay parameter allows you to specify a minimum time since the last GC
|
||||
* in seconds (the delay should be a fraction of a second in most cases though).
|
||||
* It will only start a new incremental GC or another GC slice if this time is exceeded. The user of this function is
|
||||
* responsible for ensuring that GC can run with a small enough delay to get done with the work.
|
||||
* MaybeIncrementalGC checks if running a GC is worth the time that will take.
|
||||
* The logic is custom as Spidermonkey tends to assume 'idle time' will exist,
|
||||
* which is a thing in websites but not really in 0 A.D.
|
||||
* This can have a few behaviours:
|
||||
* - doing nothing
|
||||
* - starting a new incremental GC
|
||||
* - running a GC slice
|
||||
* - finishing the incremental GC
|
||||
* For details, check the SM doc in e.g. GC.cpp and GCapi.cpp
|
||||
*/
|
||||
void MaybeIncrementalGC();
|
||||
|
||||
/**
|
||||
* Does a non-incremental, shrinking GC.
|
||||
* A shrinking GC dumps JIT code and tries to defragment memory.
|
||||
*/
|
||||
void MaybeIncrementalGC(double delay);
|
||||
void ShrinkingGC();
|
||||
|
||||
/**
|
||||
@@ -105,9 +111,8 @@ private:
|
||||
std::list<JS::Realm*> m_Realms;
|
||||
|
||||
int m_ContextSize;
|
||||
int m_HeapGrowthBytesGCTrigger;
|
||||
int m_LastGCBytes{0};
|
||||
double m_LastGCCheck{0.0};
|
||||
uint32_t m_HeapGrowthBytesGCTrigger;
|
||||
uint32_t m_LastGCBytes{0};
|
||||
};
|
||||
|
||||
// Using a global object for the context is a workaround until Simulation, AI, etc,
|
||||
|
||||
@@ -489,20 +489,9 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
|
||||
}
|
||||
}
|
||||
|
||||
// Run the GC occasionally
|
||||
// No delay because a lot of garbage accumulates in one turn and in non-visual replays there are
|
||||
// much more turns in the same time than in normal games.
|
||||
// Every 500 turns we run a shrinking GC, which decommits unused memory and frees all JIT code.
|
||||
// Based on testing, this seems to be a good compromise between memory usage and performance.
|
||||
// Also check the comment about gcPreserveCode in the ScriptInterface code and this forum topic:
|
||||
// http://www.wildfiregames.com/forum/index.php?showtopic=18466&p=300323
|
||||
//
|
||||
// (TODO: we ought to schedule this for a frame where we're not
|
||||
// running the sim update, to spread the load)
|
||||
if (m_TurnNumber % 500 == 0)
|
||||
scriptInterface.GetContext().ShrinkingGC();
|
||||
else
|
||||
scriptInterface.GetContext().MaybeIncrementalGC(0.0f);
|
||||
scriptInterface.GetContext().MaybeIncrementalGC();
|
||||
|
||||
if (m_EnableOOSLog)
|
||||
DumpState();
|
||||
|
||||
@@ -62,6 +62,8 @@ CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(const ScriptInterface&
|
||||
{
|
||||
ScriptRequest rq(m_ScriptInterface);
|
||||
JS_AddExtraGCRootsTracer(rq.cx, Trace, this);
|
||||
m_SerializePropId = JS::PropertyKey::fromPinnedString(JS_AtomizeAndPinString(rq.cx, "Serialize"));
|
||||
m_DeserializePropId = JS::PropertyKey::fromPinnedString(JS_AtomizeAndPinString(rq.cx, "Deserialize"));
|
||||
}
|
||||
|
||||
CBinarySerializerScriptImpl::~CBinarySerializerScriptImpl()
|
||||
@@ -70,10 +72,13 @@ CBinarySerializerScriptImpl::~CBinarySerializerScriptImpl()
|
||||
JS_RemoveExtraGCRootsTracer(rq.cx, Trace, this);
|
||||
}
|
||||
|
||||
void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
void CBinarySerializerScriptImpl::PutScriptVal(JS::HandleValue val)
|
||||
{
|
||||
ScriptRequest rq(m_ScriptInterface);
|
||||
HandleScriptVal(ScriptRequest(m_ScriptInterface), val);
|
||||
}
|
||||
|
||||
void CBinarySerializerScriptImpl::HandleScriptVal(const ScriptRequest& rq, JS::HandleValue val)
|
||||
{
|
||||
switch (JS_TypeOfValue(rq.cx, val))
|
||||
{
|
||||
case JSTYPE_UNDEFINED:
|
||||
@@ -92,7 +97,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
JS::RootedObject obj(rq.cx, &val.toObject());
|
||||
|
||||
// If we've already serialized this object, just output a reference to it
|
||||
u32 tag = GetScriptBackrefTag(obj);
|
||||
u32 tag = GetScriptBackrefTag(rq, obj);
|
||||
if (tag != 0)
|
||||
{
|
||||
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BACKREF);
|
||||
@@ -129,7 +134,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
// Now handle its array buffer
|
||||
// this may be a backref, since ArrayBuffers can be shared by multiple views
|
||||
JS::RootedValue bufferVal(rq.cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(rq.cx, obj, &sharedMemory)));
|
||||
HandleScriptVal(bufferVal);
|
||||
HandleScriptVal(rq, bufferVal);
|
||||
break;
|
||||
}
|
||||
else if (JS::IsArrayBufferObject(obj))
|
||||
@@ -177,8 +182,8 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
ENSURE(JS_GetElement(rq.cx, keyValuePairObj, 0, &key));
|
||||
ENSURE(JS_GetElement(rq.cx, keyValuePairObj, 1, &value));
|
||||
|
||||
HandleScriptVal(key);
|
||||
HandleScriptVal(value);
|
||||
HandleScriptVal(rq, key);
|
||||
HandleScriptVal(rq, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -206,7 +211,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
if (done)
|
||||
break;
|
||||
|
||||
HandleScriptVal(value);
|
||||
HandleScriptVal(rq, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -227,14 +232,14 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
if (!JS_GetPrototype(rq.cx, obj, &proto))
|
||||
throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed");
|
||||
|
||||
SPrototypeSerialization protoInfo = GetPrototypeInfo(rq, proto);
|
||||
SPrototypeSerialization protoInfo = GetPrototypeInfo(rq, proto, m_SerializePropId, m_DeserializePropId);
|
||||
|
||||
if (protoInfo.name == "Object")
|
||||
if (protoInfo.name == L"Object")
|
||||
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT);
|
||||
else
|
||||
{
|
||||
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_PROTOTYPE);
|
||||
m_Serializer.String("proto", wstring_from_utf8(protoInfo.name), 0, 256);
|
||||
m_Serializer.String("proto", protoInfo.name, 0, 256);
|
||||
|
||||
// Does it have custom Serialize function?
|
||||
// if so, we serialize the data it returns, rather than the object's properties directly
|
||||
@@ -281,7 +286,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
JS::RootedString str(rq.cx, JS::ToString(rq.cx, val));
|
||||
if (!str)
|
||||
throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");
|
||||
ScriptString("value", str);
|
||||
ScriptString(rq, "value", str);
|
||||
break;
|
||||
}
|
||||
else if (protokey == JSProto_Boolean)
|
||||
@@ -330,12 +335,12 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
if (!idstr)
|
||||
throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");
|
||||
|
||||
ScriptString("prop name", idstr);
|
||||
ScriptString(rq, "prop name", idstr);
|
||||
|
||||
if (!JS_GetPropertyById(rq.cx, obj, id, &propval))
|
||||
throw PSERROR_Serialize_ScriptError("JS_GetPropertyById failed");
|
||||
|
||||
HandleScriptVal(propval);
|
||||
HandleScriptVal(rq, propval);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -376,7 +381,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
{
|
||||
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_STRING);
|
||||
JS::RootedString stringVal(rq.cx, val.toString());
|
||||
ScriptString("string", stringVal);
|
||||
ScriptString(rq, "string", stringVal);
|
||||
break;
|
||||
}
|
||||
case JSTYPE_NUMBER:
|
||||
@@ -425,10 +430,8 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
|
||||
}
|
||||
}
|
||||
|
||||
void CBinarySerializerScriptImpl::ScriptString(const char* name, JS::HandleString string)
|
||||
void CBinarySerializerScriptImpl::ScriptString(const ScriptRequest& rq, const char* name, JS::HandleString string)
|
||||
{
|
||||
ScriptRequest rq(m_ScriptInterface);
|
||||
|
||||
#if BYTE_ORDER != LITTLE_ENDIAN
|
||||
#error TODO: probably need to convert JS strings to little-endian
|
||||
#endif
|
||||
@@ -436,8 +439,8 @@ void CBinarySerializerScriptImpl::ScriptString(const char* name, JS::HandleStrin
|
||||
size_t length;
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
// Serialize strings directly as UTF-16 or Latin1, to avoid expensive encoding conversions
|
||||
bool isLatin1 = JS::StringHasLatin1Chars(string);
|
||||
m_Serializer.Bool("isLatin1", isLatin1);
|
||||
u8 isLatin1 = JS::StringHasLatin1Chars(string);
|
||||
m_Serializer.NumberU8_Unbounded("isLatin1", isLatin1);
|
||||
if (isLatin1)
|
||||
{
|
||||
const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(rq.cx, nogc, string, &length);
|
||||
@@ -463,15 +466,13 @@ void CBinarySerializerScriptImpl::Trace(JSTracer *trc, void *data)
|
||||
serializer->m_ScriptBackrefTags.trace(trc);
|
||||
}
|
||||
|
||||
u32 CBinarySerializerScriptImpl::GetScriptBackrefTag(JS::HandleObject obj)
|
||||
u32 CBinarySerializerScriptImpl::GetScriptBackrefTag(const ScriptRequest& rq, JS::HandleObject obj)
|
||||
{
|
||||
// To support non-tree structures (e.g. "var x = []; var y = [x, x];"), we need a way
|
||||
// to indicate multiple references to one object(/array). So every time we serialize a
|
||||
// new object, we give it a new tag; when we serialize it a second time we just refer
|
||||
// to that tag.
|
||||
|
||||
ScriptRequest rq(m_ScriptInterface);
|
||||
|
||||
ObjectTagMap::Ptr ptr = m_ScriptBackrefTags.lookup(JS::Heap<JSObject*>(obj.get()));
|
||||
if (!ptr.found())
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "lib/byte_order.h"
|
||||
|
||||
#include "scriptinterface/ScriptExtraHeaders.h"
|
||||
#include "scriptinterface/ScriptForward.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
@@ -86,9 +87,10 @@ public:
|
||||
CBinarySerializerScriptImpl(const ScriptInterface& scriptInterface, ISerializer& serializer);
|
||||
~CBinarySerializerScriptImpl();
|
||||
|
||||
void ScriptString(const char* name, JS::HandleString string);
|
||||
void HandleScriptVal(JS::HandleValue val);
|
||||
void PutScriptVal(JS::HandleValue val);
|
||||
private:
|
||||
void ScriptString(const ScriptRequest& rq, const char* name, JS::HandleString string);
|
||||
void HandleScriptVal(const ScriptRequest& rq, JS::HandleValue val);
|
||||
static void Trace(JSTracer* trc, void* data);
|
||||
|
||||
const ScriptInterface& m_ScriptInterface;
|
||||
@@ -97,7 +99,11 @@ private:
|
||||
using ObjectTagMap = JS::GCHashMap<JS::Heap<JSObject*>, u32, js::StableCellHasher<JSObject*>, js::SystemAllocPolicy>;
|
||||
ObjectTagMap m_ScriptBackrefTags;
|
||||
u32 m_ScriptBackrefsNext;
|
||||
u32 GetScriptBackrefTag(JS::HandleObject obj);
|
||||
u32 GetScriptBackrefTag(const ScriptRequest& rq, JS::HandleObject obj);
|
||||
|
||||
JS::PropertyKey m_SerializePropId;
|
||||
JS::PropertyKey m_DeserializePropId;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -201,7 +207,7 @@ protected:
|
||||
|
||||
virtual void PutScriptVal(const char* UNUSED(name), JS::MutableHandleValue value)
|
||||
{
|
||||
m_ScriptImpl->HandleScriptVal(value);
|
||||
m_ScriptImpl->PutScriptVal(value);
|
||||
}
|
||||
|
||||
virtual void PutRaw(const char* name, const u8* data, size_t len)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -57,13 +57,13 @@ enum
|
||||
|
||||
struct SPrototypeSerialization
|
||||
{
|
||||
std::string name = "";
|
||||
std::wstring name;
|
||||
bool hasCustomSerialize = false;
|
||||
bool hasCustomDeserialize = false;
|
||||
bool hasNullSerialize = false;
|
||||
};
|
||||
|
||||
inline SPrototypeSerialization GetPrototypeInfo(const ScriptRequest& rq, JS::HandleObject prototype)
|
||||
inline SPrototypeSerialization GetPrototypeInfo(const ScriptRequest& rq, JS::HandleObject prototype, JS::PropertyKey ser, JS::PropertyKey deser)
|
||||
{
|
||||
SPrototypeSerialization ret;
|
||||
|
||||
@@ -71,27 +71,26 @@ inline SPrototypeSerialization GetPrototypeInfo(const ScriptRequest& rq, JS::Han
|
||||
throw PSERROR_Serialize_ScriptError("Could not get constructor name.");
|
||||
|
||||
// Nothing to do for basic Object objects.
|
||||
if (ret.name == "Object")
|
||||
if (ret.name == L"Object")
|
||||
return ret;
|
||||
|
||||
if (!JS_HasProperty(rq.cx, prototype, "Serialize", &ret.hasCustomSerialize) ||
|
||||
!JS_HasProperty(rq.cx, prototype, "Deserialize", &ret.hasCustomDeserialize))
|
||||
throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");
|
||||
JS::RootedValue serialize(rq.cx);
|
||||
if (!JS_GetPropertyById(rq.cx, prototype, JS::Handle<jsid>::fromMarkedLocation(&ser), &serialize))
|
||||
throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");
|
||||
|
||||
if (ret.hasCustomSerialize)
|
||||
if (serialize.isUndefined())
|
||||
return ret;
|
||||
|
||||
ret.hasCustomSerialize = true;
|
||||
if (serialize.isNull())
|
||||
ret.hasNullSerialize = true;
|
||||
if (!JS_HasPropertyById(rq.cx, prototype, JS::Handle<jsid>::fromMarkedLocation(&deser), &ret.hasCustomDeserialize) ||
|
||||
(!ret.hasNullSerialize && !ret.hasCustomDeserialize))
|
||||
{
|
||||
JS::RootedValue serialize(rq.cx);
|
||||
if (!JS_GetProperty(rq.cx, prototype, "Serialize", &serialize))
|
||||
throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");
|
||||
|
||||
if (serialize.isNull())
|
||||
ret.hasNullSerialize = true;
|
||||
else if (!ret.hasCustomDeserialize)
|
||||
{
|
||||
// Don't throw for this error: mods might need updating and this crashes as exceptions are not correctly handled.
|
||||
LOGERROR("Error serializing object '%s': non-null Serialize() but no matching Deserialize().", ret.name);
|
||||
}
|
||||
// Don't throw for this error: mods might need updating and this crashes as exceptions are not correctly handled.
|
||||
LOGERROR("Error serializing object '%s': non-null Serialize() but no matching Deserialize().", utf8_from_wstring(ret.name));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -35,7 +35,11 @@
|
||||
CStdDeserializer::CStdDeserializer(const ScriptInterface& scriptInterface, std::istream& stream) :
|
||||
m_ScriptInterface(scriptInterface), m_Stream(stream)
|
||||
{
|
||||
JS_AddExtraGCRootsTracer(ScriptRequest(scriptInterface).cx, CStdDeserializer::Trace, this);
|
||||
ScriptRequest rq(m_ScriptInterface);
|
||||
JS_AddExtraGCRootsTracer(rq.cx, CStdDeserializer::Trace, this);
|
||||
m_SerializePropId = JS::PropertyKey::fromPinnedString(JS_AtomizeAndPinString(rq.cx, "Serialize"));
|
||||
m_DeserializePropId = JS::PropertyKey::fromPinnedString(JS_AtomizeAndPinString(rq.cx, "Deserialize"));
|
||||
|
||||
// Insert a dummy object in front, as valid tags start at 1.
|
||||
m_ScriptBackrefs.emplace_back(nullptr);
|
||||
}
|
||||
@@ -168,9 +172,9 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
|
||||
|
||||
JS::RootedObject prototype(rq.cx);
|
||||
JS_GetPrototype(rq.cx, obj, &prototype);
|
||||
SPrototypeSerialization info = GetPrototypeInfo(rq, prototype);
|
||||
SPrototypeSerialization info = GetPrototypeInfo(rq, prototype, m_SerializePropId, m_DeserializePropId);
|
||||
|
||||
if (preexistingObject != nullptr && prototypeName != wstring_from_utf8(info.name))
|
||||
if (preexistingObject != nullptr && prototypeName != info.name)
|
||||
throw PSERROR_Deserialize_ScriptError("Deserializer failed: incorrect pre-existing object");
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -52,6 +52,8 @@ private:
|
||||
virtual void AddScriptBackref(JS::HandleObject obj);
|
||||
virtual void GetScriptBackref(size_t tag, JS::MutableHandleObject ret);
|
||||
std::vector<JS::Heap<JSObject*> > m_ScriptBackrefs;
|
||||
JS::PropertyKey m_SerializePropId;
|
||||
JS::PropertyKey m_DeserializePropId;
|
||||
|
||||
const ScriptInterface& m_ScriptInterface;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Profiler2.h"
|
||||
|
||||
std::string SerializeRNG(const boost::random::rand48& rng)
|
||||
{
|
||||
@@ -97,6 +98,7 @@ bool CComponentManager::DumpDebugState(std::ostream& stream, bool includeDebugIn
|
||||
|
||||
bool CComponentManager::ComputeStateHash(std::string& outHash, bool quick) const
|
||||
{
|
||||
PROFILE2("ComputeStateHash");
|
||||
// Hash serialization: this includes the minimal data necessary to detect
|
||||
// differences in the state, and ignores things like counts and names
|
||||
|
||||
@@ -117,27 +119,17 @@ bool CComponentManager::ComputeStateHash(std::string& outHash, bool quick) const
|
||||
continue;
|
||||
|
||||
// Only emit component types if they have a component that will be serialized
|
||||
bool needsSerialization = false;
|
||||
for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)
|
||||
{
|
||||
// Don't serialize local entities
|
||||
if (ENTITY_IS_LOCAL(eit->first))
|
||||
continue;
|
||||
|
||||
needsSerialization = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!needsSerialization)
|
||||
continue;
|
||||
|
||||
serializer.NumberI32_Unbounded("component type id", cit->first);
|
||||
|
||||
bool hasEmittedComponent = false;
|
||||
for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)
|
||||
{
|
||||
// Don't serialize local entities
|
||||
if (ENTITY_IS_LOCAL(eit->first))
|
||||
continue;
|
||||
if (!hasEmittedComponent)
|
||||
{
|
||||
serializer.NumberI32_Unbounded("component type id", cit->first);
|
||||
hasEmittedComponent = true;
|
||||
}
|
||||
|
||||
serializer.NumberU32_Unbounded("entity id", eit->first);
|
||||
eit->second->Serialize(serializer);
|
||||
|
||||
@@ -127,7 +127,7 @@ QUERYHANDLER(GenerateMap)
|
||||
|
||||
msg->status = 0;
|
||||
}
|
||||
catch (PSERROR_Game_World_MapLoadFailed&)
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Cancel loading
|
||||
LDR_Cancel();
|
||||
|
||||
Reference in New Issue
Block a user