diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index b61291a4ae7..f399ae28829 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -342,3 +342,44 @@ jobs: artifactErrorsFailBuild: true prerelease: true replacesArtifacts: true + make-emscripten: + name: Make (Emscripten) + runs-on: ubuntu-latest + container: emscripten/emsdk:3.1.74 + timeout-minutes: 30 + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get -y update + sudo apt-get -y install gettext p7zip-full + - name: Build + run: | + emmake make -f Makefile.emscripten -j "$(nproc)" + env: + FHEROES2_STRICT_COMPILATION: ON + - name: Create package + run: | + # Translations and H2D files are already included in fheroes2.data + 7z a -bb1 -tzip -- fheroes2_emscripten.zip LICENSE changelog.txt fheroes2.data fheroes2.js fheroes2.wasm ./docs/README.txt ./files/emscripten/* + - uses: actions/upload-artifact@v4 + if: ${{ github.event_name == 'pull_request' }} + with: + name: fheroes2_emscripten.zip + path: fheroes2_emscripten.zip + if-no-files-found: error + - uses: ncipollo/release-action@v1 + if: ${{ github.event_name == 'push' }} + with: + artifacts: fheroes2_emscripten.zip + body: ${{ github.event.head_commit.message }} + token: ${{ secrets.GITHUB_TOKEN }} + name: Emscripten build (latest commit) + tag: fheroes2-emscripten-sdl2_dev + allowUpdates: true + artifactErrorsFailBuild: true + prerelease: true + replacesArtifacts: true diff --git a/.gitignore b/.gitignore index af8057fc82b..3793277c993 100644 --- a/.gitignore +++ b/.gitignore @@ -92,7 +92,14 @@ android/.idea android/.gradle # Automatically created Android assets -android/app/src/main/assets/files/ +android/app/src/main/assets/ # Mac magic folders .DS_Store + +# Web build artifacts +*.wasm +*.wasm.map +fheroes2.js +fheroes2.data +src/dist/web/dist/* diff --git a/Makefile.emscripten b/Makefile.emscripten new file mode 100644 index 00000000000..07feece5450 --- /dev/null +++ b/Makefile.emscripten @@ -0,0 +1,43 @@ +########################################################################### +# fheroes2: https://github.com/ihhub/fheroes2 # +# Copyright (C) 2025 # +# # +# This program 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. # +# # +# This program 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 this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +########################################################################### + +# Options: +# +# FHEROES2_STRICT_COMPILATION: build in strict compilation mode (turns warnings into errors) +# FHEROES2_WITH_DEBUG: build in debug mode +# FHEROES2_DATA: set the built-in path to the fheroes2 data directory (e.g. /usr/share/fheroes2) + +.PHONY: all clean translations + +all: fheroes2.js + +fheroes2.js: translations + $(MAKE) -C src/dist PLATFORM=emscripten + cp src/dist/fheroes2-ems/fheroes2.data . + cp src/dist/fheroes2-ems/fheroes2.js . + cp src/dist/fheroes2-ems/fheroes2.wasm . + +translations: + $(MAKE) -C files/lang + +clean: + $(MAKE) -C src/dist clean + $(MAKE) -C files/lang clean + rm -f fheroes2.data fheroes2.js fheroes2.wasm diff --git a/Makefile.vita b/Makefile.vita index 18a547c6b23..956ec8d6694 100644 --- a/Makefile.vita +++ b/Makefile.vita @@ -1,6 +1,6 @@ ########################################################################### # fheroes2: https://github.com/ihhub/fheroes2 # -# Copyright (C) 2021 - 2024 # +# Copyright (C) 2021 - 2025 # # # # This program is free software; you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # @@ -40,7 +40,7 @@ fheroes2.vpk: eboot.bin param.sfo translations --add files/images/platform/psv/sce_sys/livearea/contents/template.xml=sce_sys/livearea/contents/template.xml \ --add files/data=files/data \ --add files/lang/vita_temp=files/lang \ - fheroes2.vpk + fheroes2.vpk rm -r files/lang/vita_temp translations: fheroes2.elf diff --git a/android/app/build.gradle b/android/app/build.gradle index 54991ba2fac..8167f0b5abc 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -99,6 +99,14 @@ tasks.register('copyH2D', Copy) { into 'src/main/assets/files/data' } +tasks.register('copyTimidity', Copy) { + from('../../files/timidity') { + include 'instruments/*.pat' + include 'timidity.cfg' + } + into 'src/main/assets' +} + tasks.register('copyTranslations', Copy) { from('../../files/lang') { include '*.mo' @@ -107,5 +115,5 @@ tasks.register('copyTranslations', Copy) { } preBuild { - dependsOn copyH2D, copyTranslations + dependsOn copyH2D, copyTimidity, copyTranslations } diff --git a/files/emscripten/fheroes2.jpeg b/files/emscripten/fheroes2.jpeg new file mode 100644 index 00000000000..d0d3f9f04e4 Binary files /dev/null and b/files/emscripten/fheroes2.jpeg differ diff --git a/files/emscripten/index.html b/files/emscripten/index.html new file mode 100644 index 00000000000..99352febb69 --- /dev/null +++ b/files/emscripten/index.html @@ -0,0 +1,210 @@ + + + fheroes2 + + + + + + + + + +
+ +
+
+
+ + +
+
+ + diff --git a/android/app/src/main/assets/instruments/README.txt b/files/timidity/instruments/README.txt similarity index 100% rename from android/app/src/main/assets/instruments/README.txt rename to files/timidity/instruments/README.txt diff --git a/android/app/src/main/assets/instruments/acpiano.pat b/files/timidity/instruments/acpiano.pat similarity index 100% rename from android/app/src/main/assets/instruments/acpiano.pat rename to files/timidity/instruments/acpiano.pat diff --git a/android/app/src/main/assets/instruments/agogohi.pat b/files/timidity/instruments/agogohi.pat similarity index 100% rename from android/app/src/main/assets/instruments/agogohi.pat rename to files/timidity/instruments/agogohi.pat diff --git a/android/app/src/main/assets/instruments/agogolo.pat b/files/timidity/instruments/agogolo.pat similarity index 100% rename from android/app/src/main/assets/instruments/agogolo.pat rename to files/timidity/instruments/agogolo.pat diff --git a/android/app/src/main/assets/instruments/bassoon.pat b/files/timidity/instruments/bassoon.pat similarity index 100% rename from android/app/src/main/assets/instruments/bassoon.pat rename to files/timidity/instruments/bassoon.pat diff --git a/android/app/src/main/assets/instruments/belltree.pat b/files/timidity/instruments/belltree.pat similarity index 100% rename from android/app/src/main/assets/instruments/belltree.pat rename to files/timidity/instruments/belltree.pat diff --git a/android/app/src/main/assets/instruments/bongohi.pat b/files/timidity/instruments/bongohi.pat similarity index 100% rename from android/app/src/main/assets/instruments/bongohi.pat rename to files/timidity/instruments/bongohi.pat diff --git a/android/app/src/main/assets/instruments/bongolo.pat b/files/timidity/instruments/bongolo.pat similarity index 100% rename from android/app/src/main/assets/instruments/bongolo.pat rename to files/timidity/instruments/bongolo.pat diff --git a/android/app/src/main/assets/instruments/bowglass.pat b/files/timidity/instruments/bowglass.pat similarity index 100% rename from android/app/src/main/assets/instruments/bowglass.pat rename to files/timidity/instruments/bowglass.pat diff --git a/android/app/src/main/assets/instruments/cabasa.pat b/files/timidity/instruments/cabasa.pat similarity index 100% rename from android/app/src/main/assets/instruments/cabasa.pat rename to files/timidity/instruments/cabasa.pat diff --git a/android/app/src/main/assets/instruments/castinet.pat b/files/timidity/instruments/castinet.pat similarity index 100% rename from android/app/src/main/assets/instruments/castinet.pat rename to files/timidity/instruments/castinet.pat diff --git a/android/app/src/main/assets/instruments/cello.pat b/files/timidity/instruments/cello.pat similarity index 100% rename from android/app/src/main/assets/instruments/cello.pat rename to files/timidity/instruments/cello.pat diff --git a/android/app/src/main/assets/instruments/choir.pat b/files/timidity/instruments/choir.pat similarity index 100% rename from android/app/src/main/assets/instruments/choir.pat rename to files/timidity/instruments/choir.pat diff --git a/android/app/src/main/assets/instruments/church.pat b/files/timidity/instruments/church.pat similarity index 100% rename from android/app/src/main/assets/instruments/church.pat rename to files/timidity/instruments/church.pat diff --git a/android/app/src/main/assets/instruments/claps.pat b/files/timidity/instruments/claps.pat similarity index 100% rename from android/app/src/main/assets/instruments/claps.pat rename to files/timidity/instruments/claps.pat diff --git a/android/app/src/main/assets/instruments/clarinet.pat b/files/timidity/instruments/clarinet.pat similarity index 100% rename from android/app/src/main/assets/instruments/clarinet.pat rename to files/timidity/instruments/clarinet.pat diff --git a/android/app/src/main/assets/instruments/clave.pat b/files/timidity/instruments/clave.pat similarity index 100% rename from android/app/src/main/assets/instruments/clave.pat rename to files/timidity/instruments/clave.pat diff --git a/android/app/src/main/assets/instruments/congahi1.pat b/files/timidity/instruments/congahi1.pat similarity index 100% rename from android/app/src/main/assets/instruments/congahi1.pat rename to files/timidity/instruments/congahi1.pat diff --git a/android/app/src/main/assets/instruments/congahi2.pat b/files/timidity/instruments/congahi2.pat similarity index 100% rename from android/app/src/main/assets/instruments/congahi2.pat rename to files/timidity/instruments/congahi2.pat diff --git a/android/app/src/main/assets/instruments/congalo.pat b/files/timidity/instruments/congalo.pat similarity index 100% rename from android/app/src/main/assets/instruments/congalo.pat rename to files/timidity/instruments/congalo.pat diff --git a/android/app/src/main/assets/instruments/contraba.pat b/files/timidity/instruments/contraba.pat similarity index 100% rename from android/app/src/main/assets/instruments/contraba.pat rename to files/timidity/instruments/contraba.pat diff --git a/android/app/src/main/assets/instruments/cowbell.pat b/files/timidity/instruments/cowbell.pat similarity index 100% rename from android/app/src/main/assets/instruments/cowbell.pat rename to files/timidity/instruments/cowbell.pat diff --git a/android/app/src/main/assets/instruments/cuica1.pat b/files/timidity/instruments/cuica1.pat similarity index 100% rename from android/app/src/main/assets/instruments/cuica1.pat rename to files/timidity/instruments/cuica1.pat diff --git a/android/app/src/main/assets/instruments/cuica2.pat b/files/timidity/instruments/cuica2.pat similarity index 100% rename from android/app/src/main/assets/instruments/cuica2.pat rename to files/timidity/instruments/cuica2.pat diff --git a/android/app/src/main/assets/instruments/cymbell.pat b/files/timidity/instruments/cymbell.pat similarity index 100% rename from android/app/src/main/assets/instruments/cymbell.pat rename to files/timidity/instruments/cymbell.pat diff --git a/android/app/src/main/assets/instruments/cymchina.pat b/files/timidity/instruments/cymchina.pat similarity index 100% rename from android/app/src/main/assets/instruments/cymchina.pat rename to files/timidity/instruments/cymchina.pat diff --git a/android/app/src/main/assets/instruments/cymcrsh1.pat b/files/timidity/instruments/cymcrsh1.pat similarity index 100% rename from android/app/src/main/assets/instruments/cymcrsh1.pat rename to files/timidity/instruments/cymcrsh1.pat diff --git a/android/app/src/main/assets/instruments/cymcrsh2.pat b/files/timidity/instruments/cymcrsh2.pat similarity index 100% rename from android/app/src/main/assets/instruments/cymcrsh2.pat rename to files/timidity/instruments/cymcrsh2.pat diff --git a/android/app/src/main/assets/instruments/cymride1.pat b/files/timidity/instruments/cymride1.pat similarity index 100% rename from android/app/src/main/assets/instruments/cymride1.pat rename to files/timidity/instruments/cymride1.pat diff --git a/android/app/src/main/assets/instruments/cymride2.pat b/files/timidity/instruments/cymride2.pat similarity index 100% rename from android/app/src/main/assets/instruments/cymride2.pat rename to files/timidity/instruments/cymride2.pat diff --git a/android/app/src/main/assets/instruments/cymsplsh.pat b/files/timidity/instruments/cymsplsh.pat similarity index 100% rename from android/app/src/main/assets/instruments/cymsplsh.pat rename to files/timidity/instruments/cymsplsh.pat diff --git a/android/app/src/main/assets/instruments/englhorn.pat b/files/timidity/instruments/englhorn.pat similarity index 100% rename from android/app/src/main/assets/instruments/englhorn.pat rename to files/timidity/instruments/englhorn.pat diff --git a/android/app/src/main/assets/instruments/flute.pat b/files/timidity/instruments/flute.pat similarity index 100% rename from android/app/src/main/assets/instruments/flute.pat rename to files/timidity/instruments/flute.pat diff --git a/android/app/src/main/assets/instruments/frenchrn.pat b/files/timidity/instruments/frenchrn.pat similarity index 100% rename from android/app/src/main/assets/instruments/frenchrn.pat rename to files/timidity/instruments/frenchrn.pat diff --git a/android/app/src/main/assets/instruments/guiro1.pat b/files/timidity/instruments/guiro1.pat similarity index 100% rename from android/app/src/main/assets/instruments/guiro1.pat rename to files/timidity/instruments/guiro1.pat diff --git a/android/app/src/main/assets/instruments/guiro2.pat b/files/timidity/instruments/guiro2.pat similarity index 100% rename from android/app/src/main/assets/instruments/guiro2.pat rename to files/timidity/instruments/guiro2.pat diff --git a/android/app/src/main/assets/instruments/harp.pat b/files/timidity/instruments/harp.pat similarity index 100% rename from android/app/src/main/assets/instruments/harp.pat rename to files/timidity/instruments/harp.pat diff --git a/android/app/src/main/assets/instruments/highq.pat b/files/timidity/instruments/highq.pat similarity index 100% rename from android/app/src/main/assets/instruments/highq.pat rename to files/timidity/instruments/highq.pat diff --git a/android/app/src/main/assets/instruments/hihatcl.pat b/files/timidity/instruments/hihatcl.pat similarity index 100% rename from android/app/src/main/assets/instruments/hihatcl.pat rename to files/timidity/instruments/hihatcl.pat diff --git a/android/app/src/main/assets/instruments/hihatop.pat b/files/timidity/instruments/hihatop.pat similarity index 100% rename from android/app/src/main/assets/instruments/hihatop.pat rename to files/timidity/instruments/hihatop.pat diff --git a/android/app/src/main/assets/instruments/hihatpd.pat b/files/timidity/instruments/hihatpd.pat similarity index 100% rename from android/app/src/main/assets/instruments/hihatpd.pat rename to files/timidity/instruments/hihatpd.pat diff --git a/android/app/src/main/assets/instruments/hrpschrd.pat b/files/timidity/instruments/hrpschrd.pat similarity index 100% rename from android/app/src/main/assets/instruments/hrpschrd.pat rename to files/timidity/instruments/hrpschrd.pat diff --git a/android/app/src/main/assets/instruments/jingles.pat b/files/timidity/instruments/jingles.pat similarity index 100% rename from android/app/src/main/assets/instruments/jingles.pat rename to files/timidity/instruments/jingles.pat diff --git a/android/app/src/main/assets/instruments/kick1.pat b/files/timidity/instruments/kick1.pat similarity index 100% rename from android/app/src/main/assets/instruments/kick1.pat rename to files/timidity/instruments/kick1.pat diff --git a/android/app/src/main/assets/instruments/kick2.pat b/files/timidity/instruments/kick2.pat similarity index 100% rename from android/app/src/main/assets/instruments/kick2.pat rename to files/timidity/instruments/kick2.pat diff --git a/android/app/src/main/assets/instruments/maracas.pat b/files/timidity/instruments/maracas.pat similarity index 100% rename from android/app/src/main/assets/instruments/maracas.pat rename to files/timidity/instruments/maracas.pat diff --git a/android/app/src/main/assets/instruments/marcato.pat b/files/timidity/instruments/marcato.pat similarity index 100% rename from android/app/src/main/assets/instruments/marcato.pat rename to files/timidity/instruments/marcato.pat diff --git a/android/app/src/main/assets/instruments/metbell.pat b/files/timidity/instruments/metbell.pat similarity index 100% rename from android/app/src/main/assets/instruments/metbell.pat rename to files/timidity/instruments/metbell.pat diff --git a/android/app/src/main/assets/instruments/metclick.pat b/files/timidity/instruments/metclick.pat similarity index 100% rename from android/app/src/main/assets/instruments/metclick.pat rename to files/timidity/instruments/metclick.pat diff --git a/android/app/src/main/assets/instruments/nyguitar.pat b/files/timidity/instruments/nyguitar.pat similarity index 100% rename from android/app/src/main/assets/instruments/nyguitar.pat rename to files/timidity/instruments/nyguitar.pat diff --git a/android/app/src/main/assets/instruments/oboe.pat b/files/timidity/instruments/oboe.pat similarity index 100% rename from android/app/src/main/assets/instruments/oboe.pat rename to files/timidity/instruments/oboe.pat diff --git a/android/app/src/main/assets/instruments/piccolo.pat b/files/timidity/instruments/piccolo.pat similarity index 100% rename from android/app/src/main/assets/instruments/piccolo.pat rename to files/timidity/instruments/piccolo.pat diff --git a/android/app/src/main/assets/instruments/pizzcato.pat b/files/timidity/instruments/pizzcato.pat similarity index 100% rename from android/app/src/main/assets/instruments/pizzcato.pat rename to files/timidity/instruments/pizzcato.pat diff --git a/android/app/src/main/assets/instruments/scratch1.pat b/files/timidity/instruments/scratch1.pat similarity index 100% rename from android/app/src/main/assets/instruments/scratch1.pat rename to files/timidity/instruments/scratch1.pat diff --git a/android/app/src/main/assets/instruments/scratch2.pat b/files/timidity/instruments/scratch2.pat similarity index 100% rename from android/app/src/main/assets/instruments/scratch2.pat rename to files/timidity/instruments/scratch2.pat diff --git a/android/app/src/main/assets/instruments/shaker.pat b/files/timidity/instruments/shaker.pat similarity index 100% rename from android/app/src/main/assets/instruments/shaker.pat rename to files/timidity/instruments/shaker.pat diff --git a/android/app/src/main/assets/instruments/slap.pat b/files/timidity/instruments/slap.pat similarity index 100% rename from android/app/src/main/assets/instruments/slap.pat rename to files/timidity/instruments/slap.pat diff --git a/android/app/src/main/assets/instruments/slowstr.pat b/files/timidity/instruments/slowstr.pat similarity index 100% rename from android/app/src/main/assets/instruments/slowstr.pat rename to files/timidity/instruments/slowstr.pat diff --git a/android/app/src/main/assets/instruments/snap.pat b/files/timidity/instruments/snap.pat similarity index 100% rename from android/app/src/main/assets/instruments/snap.pat rename to files/timidity/instruments/snap.pat diff --git a/android/app/src/main/assets/instruments/snare1.pat b/files/timidity/instruments/snare1.pat similarity index 100% rename from android/app/src/main/assets/instruments/snare1.pat rename to files/timidity/instruments/snare1.pat diff --git a/android/app/src/main/assets/instruments/snare2.pat b/files/timidity/instruments/snare2.pat similarity index 100% rename from android/app/src/main/assets/instruments/snare2.pat rename to files/timidity/instruments/snare2.pat diff --git a/android/app/src/main/assets/instruments/snarerol.pat b/files/timidity/instruments/snarerol.pat similarity index 100% rename from android/app/src/main/assets/instruments/snarerol.pat rename to files/timidity/instruments/snarerol.pat diff --git a/android/app/src/main/assets/instruments/sqrclick.pat b/files/timidity/instruments/sqrclick.pat similarity index 100% rename from android/app/src/main/assets/instruments/sqrclick.pat rename to files/timidity/instruments/sqrclick.pat diff --git a/android/app/src/main/assets/instruments/stickrim.pat b/files/timidity/instruments/stickrim.pat similarity index 100% rename from android/app/src/main/assets/instruments/stickrim.pat rename to files/timidity/instruments/stickrim.pat diff --git a/android/app/src/main/assets/instruments/sticks.pat b/files/timidity/instruments/sticks.pat similarity index 100% rename from android/app/src/main/assets/instruments/sticks.pat rename to files/timidity/instruments/sticks.pat diff --git a/android/app/src/main/assets/instruments/surdo1.pat b/files/timidity/instruments/surdo1.pat similarity index 100% rename from android/app/src/main/assets/instruments/surdo1.pat rename to files/timidity/instruments/surdo1.pat diff --git a/android/app/src/main/assets/instruments/surdo2.pat b/files/timidity/instruments/surdo2.pat similarity index 100% rename from android/app/src/main/assets/instruments/surdo2.pat rename to files/timidity/instruments/surdo2.pat diff --git a/android/app/src/main/assets/instruments/synstr2.pat b/files/timidity/instruments/synstr2.pat similarity index 100% rename from android/app/src/main/assets/instruments/synstr2.pat rename to files/timidity/instruments/synstr2.pat diff --git a/android/app/src/main/assets/instruments/taiko.pat b/files/timidity/instruments/taiko.pat similarity index 100% rename from android/app/src/main/assets/instruments/taiko.pat rename to files/timidity/instruments/taiko.pat diff --git a/android/app/src/main/assets/instruments/tamborin.pat b/files/timidity/instruments/tamborin.pat similarity index 100% rename from android/app/src/main/assets/instruments/tamborin.pat rename to files/timidity/instruments/tamborin.pat diff --git a/android/app/src/main/assets/instruments/timbaleh.pat b/files/timidity/instruments/timbaleh.pat similarity index 100% rename from android/app/src/main/assets/instruments/timbaleh.pat rename to files/timidity/instruments/timbaleh.pat diff --git a/android/app/src/main/assets/instruments/timbalel.pat b/files/timidity/instruments/timbalel.pat similarity index 100% rename from android/app/src/main/assets/instruments/timbalel.pat rename to files/timidity/instruments/timbalel.pat diff --git a/android/app/src/main/assets/instruments/timpani.pat b/files/timidity/instruments/timpani.pat similarity index 100% rename from android/app/src/main/assets/instruments/timpani.pat rename to files/timidity/instruments/timpani.pat diff --git a/android/app/src/main/assets/instruments/tomhi1.pat b/files/timidity/instruments/tomhi1.pat similarity index 100% rename from android/app/src/main/assets/instruments/tomhi1.pat rename to files/timidity/instruments/tomhi1.pat diff --git a/android/app/src/main/assets/instruments/tomhi2.pat b/files/timidity/instruments/tomhi2.pat similarity index 100% rename from android/app/src/main/assets/instruments/tomhi2.pat rename to files/timidity/instruments/tomhi2.pat diff --git a/android/app/src/main/assets/instruments/tomlo1.pat b/files/timidity/instruments/tomlo1.pat similarity index 100% rename from android/app/src/main/assets/instruments/tomlo1.pat rename to files/timidity/instruments/tomlo1.pat diff --git a/android/app/src/main/assets/instruments/tomlo2.pat b/files/timidity/instruments/tomlo2.pat similarity index 100% rename from android/app/src/main/assets/instruments/tomlo2.pat rename to files/timidity/instruments/tomlo2.pat diff --git a/android/app/src/main/assets/instruments/tommid1.pat b/files/timidity/instruments/tommid1.pat similarity index 100% rename from android/app/src/main/assets/instruments/tommid1.pat rename to files/timidity/instruments/tommid1.pat diff --git a/android/app/src/main/assets/instruments/tommid2.pat b/files/timidity/instruments/tommid2.pat similarity index 100% rename from android/app/src/main/assets/instruments/tommid2.pat rename to files/timidity/instruments/tommid2.pat diff --git a/android/app/src/main/assets/instruments/tremstr.pat b/files/timidity/instruments/tremstr.pat similarity index 100% rename from android/app/src/main/assets/instruments/tremstr.pat rename to files/timidity/instruments/tremstr.pat diff --git a/android/app/src/main/assets/instruments/triangl1.pat b/files/timidity/instruments/triangl1.pat similarity index 100% rename from android/app/src/main/assets/instruments/triangl1.pat rename to files/timidity/instruments/triangl1.pat diff --git a/android/app/src/main/assets/instruments/triangl2.pat b/files/timidity/instruments/triangl2.pat similarity index 100% rename from android/app/src/main/assets/instruments/triangl2.pat rename to files/timidity/instruments/triangl2.pat diff --git a/android/app/src/main/assets/instruments/trombone.pat b/files/timidity/instruments/trombone.pat similarity index 100% rename from android/app/src/main/assets/instruments/trombone.pat rename to files/timidity/instruments/trombone.pat diff --git a/android/app/src/main/assets/instruments/vibslap.pat b/files/timidity/instruments/vibslap.pat similarity index 100% rename from android/app/src/main/assets/instruments/vibslap.pat rename to files/timidity/instruments/vibslap.pat diff --git a/android/app/src/main/assets/instruments/viola.pat b/files/timidity/instruments/viola.pat similarity index 100% rename from android/app/src/main/assets/instruments/viola.pat rename to files/timidity/instruments/viola.pat diff --git a/android/app/src/main/assets/instruments/whistle1.pat b/files/timidity/instruments/whistle1.pat similarity index 100% rename from android/app/src/main/assets/instruments/whistle1.pat rename to files/timidity/instruments/whistle1.pat diff --git a/android/app/src/main/assets/instruments/whistle2.pat b/files/timidity/instruments/whistle2.pat similarity index 100% rename from android/app/src/main/assets/instruments/whistle2.pat rename to files/timidity/instruments/whistle2.pat diff --git a/android/app/src/main/assets/instruments/woodblk1.pat b/files/timidity/instruments/woodblk1.pat similarity index 100% rename from android/app/src/main/assets/instruments/woodblk1.pat rename to files/timidity/instruments/woodblk1.pat diff --git a/android/app/src/main/assets/instruments/woodblk2.pat b/files/timidity/instruments/woodblk2.pat similarity index 100% rename from android/app/src/main/assets/instruments/woodblk2.pat rename to files/timidity/instruments/woodblk2.pat diff --git a/android/app/src/main/assets/timidity.cfg b/files/timidity/timidity.cfg similarity index 100% rename from android/app/src/main/assets/timidity.cfg rename to files/timidity/timidity.cfg diff --git a/src/dist/Makefile b/src/dist/Makefile index 4e1c76db630..103f1a860cc 100644 --- a/src/dist/Makefile +++ b/src/dist/Makefile @@ -1,6 +1,6 @@ ########################################################################### # fheroes2: https://github.com/ihhub/fheroes2 # -# Copyright (C) 2021 - 2024 # +# Copyright (C) 2021 - 2025 # # # # This program is free software; you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # @@ -159,7 +159,11 @@ ifndef FHEROES2_WITH_SYSTEM_SMACKER $(MAKE) -C thirdparty/libsmacker CCFLAGS="$(CCFLAGS_TP)" CFLAGS="$(CFLAGS_TP)" CXXFLAGS="$(CXXFLAGS_TP)" CPPFLAGS="$(CPPFLAGS_TP)" endif $(MAKE) -C engine +ifeq ($(PLATFORM),emscripten) + $(MAKE) -C fheroes2-ems +else $(MAKE) -C fheroes2 +endif ifdef FHEROES2_WITH_TOOLS $(MAKE) -C tools endif @@ -169,5 +173,9 @@ ifndef FHEROES2_WITH_SYSTEM_SMACKER $(MAKE) -C thirdparty/libsmacker clean endif $(MAKE) -C engine clean +ifeq ($(PLATFORM),emscripten) + $(MAKE) -C fheroes2-ems clean +else $(MAKE) -C fheroes2 clean +endif $(MAKE) -C tools clean diff --git a/src/dist/Makefile.emscripten b/src/dist/Makefile.emscripten new file mode 100644 index 00000000000..98e74871f08 --- /dev/null +++ b/src/dist/Makefile.emscripten @@ -0,0 +1,43 @@ +########################################################################### +# fheroes2: https://github.com/ihhub/fheroes2 # +# Copyright (C) 2025 # +# # +# This program 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. # +# # +# This program 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 this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +########################################################################### + +CCFLAGS := $(filter-out -pthread,$(CCFLAGS)) \ + --use-port=sdl2 \ + --use-port=sdl2_mixer \ + --use-port=zlib \ + -Wno-variadic-macro-arguments-omitted + +LDFLAGS := $(filter-out -pthread,$(LDFLAGS)) \ + --preload-file ../../../files/data/resurrection.h2d@/files/data/resurrection.h2d \ + --preload-file ../../../files/lang/@/files/lang/ \ + --preload-file ../../../files/timidity/@/etc/ \ + -sASYNCIFY \ + -sASYNCIFY_STACK_SIZE=20480 \ + -sENVIRONMENT=web \ + -sINITIAL_MEMORY=128mb \ + -sNO_DISABLE_EXCEPTION_CATCHING \ + -sSDL2_MIXER_FORMATS=mid,mp3,ogg \ + -sSTACK_SIZE=262144 \ + -lidbfs.js + +ifdef FHEROES2_WITH_DEBUG +CCFLAGS := $(CCFLAGS) -gsource-map +LDFLAGS := $(LDFLAGS) -gsource-map +endif diff --git a/src/dist/fheroes2-ems/Makefile b/src/dist/fheroes2-ems/Makefile new file mode 100644 index 00000000000..200a2fe3c13 --- /dev/null +++ b/src/dist/fheroes2-ems/Makefile @@ -0,0 +1,48 @@ +########################################################################### +# fheroes2: https://github.com/ihhub/fheroes2 # +# Copyright (C) 2025 # +# # +# This program 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. # +# # +# This program 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 this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +########################################################################### + +DEPLIBS := ../engine/libengine.a +CCFLAGS := $(CCFLAGS) -I../../engine + +ifndef FHEROES2_WITH_SYSTEM_SMACKER +DEPLIBS := $(DEPLIBS) ../thirdparty/libsmacker/libsmacker.a +CCFLAGS := $(CCFLAGS) -I../../thirdparty/libsmacker +endif + +SOURCEROOT := ../../fheroes2 +SOURCEDIRS := $(filter %/,$(wildcard $(SOURCEROOT)/*/)) +SOURCES := $(wildcard $(SOURCEROOT)/*/*.cpp) + +VPATH := $(SOURCEDIRS) + +.PHONY: all clean + +all: fheroes2.js + +fheroes2.js: $(notdir $(patsubst %.cpp, %.o, $(SOURCES))) $(DEPLIBS) + $(CXX) -o $@ $^ $(LIBS) $(LDFLAGS) + +%.o: %.cpp + $(CXX) -c -MD $< $(addprefix -I, $(SOURCEDIRS)) $(CCFLAGS) $(CXXFLAGS) $(CPPFLAGS) + +include $(wildcard *.d) + +clean: + rm -f *.d *.o fheroes2.data fheroes2.js fheroes2.wasm diff --git a/src/engine/audio.cpp b/src/engine/audio.cpp index f152d36e63d..731954a1ca4 100644 --- a/src/engine/audio.cpp +++ b/src/engine/audio.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2008 by Andrey Afletdinov * @@ -540,6 +540,8 @@ namespace // Either there is no need to resume music playback, or the resumption failed. Let's try to // start the playback from the beginning. if ( returnCode != 0 ) { + track->setPosition( 0 ); + returnCode = Mix_FadeInMusic( mus.get(), loopCount, musicFadeInMs ); if ( returnCode != 0 ) { diff --git a/src/engine/serialize.cpp b/src/engine/serialize.cpp index d528e8b5f72..e05b777bd91 100644 --- a/src/engine/serialize.cpp +++ b/src/engine/serialize.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2012 by Andrey Afletdinov * @@ -29,6 +29,16 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include + +#include +#include +#include + +#include "tools.h" +#endif + #include "logging.h" namespace @@ -622,3 +632,41 @@ std::string StreamFile::getString( const size_t size /* = 0 */ ) return { buf.begin(), std::find( buf.begin(), buf.end(), 0 ) }; } + +int StreamFile::closeFile( std::FILE * f ) +{ +#ifdef __EMSCRIPTEN__ + const bool needSyncFS = [f]() { + static_assert( CountBits( O_WRONLY ) == 1 && CountBits( O_RDWR ) == 1 ); + + const int fn = fileno( f ); + if ( fn < 0 ) { + ERROR_LOG( "fileno() error: " << errno ) + return false; + } + + const int flags = fcntl( fn, F_GETFL ); + if ( flags < 0 ) { + ERROR_LOG( "fcntl() error: " << errno ) + return false; + } + + return ( flags & O_WRONLY ) || ( flags & O_RDWR ); + }(); +#endif + + const int res = std::fclose( f ); + +#ifdef __EMSCRIPTEN__ + if ( needSyncFS ) { + EM_ASM( + // The following code is not C++ code, but JavaScript code. + // clang-format off + FS.syncfs( err => err && console.warn( "FS.syncfs() error:", err ) ) + // clang-format on + ); + } +#endif + + return res; +} diff --git a/src/engine/serialize.h b/src/engine/serialize.h index efc71abfb30..05883448e55 100644 --- a/src/engine/serialize.h +++ b/src/engine/serialize.h @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2012 by Andrey Afletdinov * @@ -669,7 +669,9 @@ class StreamFile final : public IStreamBase, public OStreamBase } } - std::unique_ptr _file{ nullptr, []( std::FILE * f ) { return std::fclose( f ); } }; + static int closeFile( std::FILE * f ); + + std::unique_ptr _file{ nullptr, closeFile }; }; namespace fheroes2 diff --git a/src/engine/thread.cpp b/src/engine/thread.cpp index 10f86736900..e396ae026fa 100644 --- a/src/engine/thread.cpp +++ b/src/engine/thread.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2022 - 2023 * + * Copyright (C) 2022 - 2025 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -23,10 +23,39 @@ #include #include +namespace +{ +#ifdef __EMSCRIPTEN__ + class MutexUnlocker + { + public: + explicit MutexUnlocker( std::mutex & mutex ) + : _mutex( mutex ) + { + _mutex.unlock(); + } + + MutexUnlocker( const MutexUnlocker & ) = delete; + + ~MutexUnlocker() + { + _mutex.lock(); + } + + MutexUnlocker & operator=( const MutexUnlocker & ) = delete; + + private: + std::mutex & _mutex; + }; +#endif +} + namespace MultiThreading { void AsyncManager::createWorker() { + // Emscripten has no pthread support. The worker thread should not be started. +#ifndef __EMSCRIPTEN__ if ( !_worker ) { _runFlag = true; _worker = std::make_unique( AsyncManager::_workerThread, this ); @@ -37,10 +66,15 @@ namespace MultiThreading _masterNotification.wait( lock, [this] { return !_runFlag; } ); } } +#endif } void AsyncManager::stopWorker() { +#ifdef __EMSCRIPTEN__ + // Emscripten has no pthread support. The worker thread should not be running here. + assert( !_worker ); +#else if ( _worker ) { { const std::scoped_lock lock( _mutex ); @@ -54,13 +88,33 @@ namespace MultiThreading _worker->join(); _worker.reset(); } +#endif } void AsyncManager::notifyWorker() { _runFlag = true; + // Emscripten has no pthread support, so instead of passing tasks to the worker thread, we will process them immediately in the current thread. +#ifdef __EMSCRIPTEN__ + assert( !_exitFlag ); + + while ( _runFlag ) { + const bool moreTasks = prepareTask(); + if ( !moreTasks ) { + _runFlag = false; + } + + { + // In accordance with the contract, the _mutex should NOT be acquired while calling the executeTask(). + MutexUnlocker unlocker( _mutex ); + + executeTask(); + } + } +#else _workerNotification.notify_all(); +#endif } void AsyncManager::_workerThread( AsyncManager * manager ) diff --git a/src/engine/thread.h b/src/engine/thread.h index d3f9bb00ae2..4885dea2252 100644 --- a/src/engine/thread.h +++ b/src/engine/thread.h @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2022 * + * Copyright (C) 2022 - 2025 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -53,11 +53,10 @@ namespace MultiThreading // Notify the worker thread about a new task. The _mutex should be acquired while calling this method. void notifyWorker(); - // Prepare a task which requires mutex lock. Returns true if more tasks are available. + // Prepare the next task. The _mutex will be acquired while calling this method. Returns true if more tasks are available. virtual bool prepareTask() = 0; - // Task execution is done in non-thread safe mode! No mutex lock for any means of synchronizations are - // done for this call. + // Execute the next task. NOTE WELL: the _mutex will NOT be acquired while calling this method. virtual void executeTask() = 0; private: diff --git a/src/fheroes2/game/game_hotkeys.cpp b/src/fheroes2/game/game_hotkeys.cpp index be067217449..4df9820230e 100644 --- a/src/fheroes2/game/game_hotkeys.cpp +++ b/src/fheroes2/game/game_hotkeys.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2010 by Andrey Afletdinov * @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +42,7 @@ #include "localevent.h" #include "logging.h" #include "players.h" +#include "serialize.h" #include "settings.h" #include "system.h" #include "tinyconfig.h" @@ -452,17 +452,17 @@ void Game::HotKeysLoad( const std::string & filename ) void Game::HotKeySave() { - // Save the latest information into the file. const std::string filename = System::concatPath( System::GetConfigDirectory( "fheroes2" ), "fheroes2.key" ); - std::fstream file( filename.data(), std::fstream::out | std::fstream::trunc ); - if ( !file ) { - ERROR_LOG( "Unable to open hotkey settings file " << filename ) + StreamFile fileStream; + if ( !fileStream.open( filename, "w" ) ) { + ERROR_LOG( "Unable to open the hotkey settings file " << filename ) return; } - const std::string & data = getHotKeyFileContent(); - file.write( data.data(), data.size() ); + const std::string data = getHotKeyFileContent(); + + fileStream.putRaw( data.data(), data.size() ); } void Game::globalKeyDownEvent( const fheroes2::Key key, const int32_t modifier ) diff --git a/src/fheroes2/system/settings.cpp b/src/fheroes2/system/settings.cpp index 20d5e9636ed..2b822b6365a 100644 --- a/src/fheroes2/system/settings.cpp +++ b/src/fheroes2/system/settings.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2009 by Andrey Afletdinov * @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -348,16 +347,14 @@ bool Settings::Save( const std::string_view fileName ) const return false; } - const std::string cfgFilename = System::concatPath( System::GetConfigDirectory( "fheroes2" ), fileName ); - - std::fstream file; - file.open( cfgFilename.data(), std::fstream::out | std::fstream::trunc ); - if ( !file ) { + StreamFile fileStream; + if ( !fileStream.open( System::concatPath( System::GetConfigDirectory( "fheroes2" ), fileName ), "w" ) ) { return false; } - const std::string & data = String(); - file.write( data.data(), data.size() ); + const std::string data = String(); + + fileStream.putRaw( data.data(), data.size() ); return true; }