mirror of
https://github.com/ihhub/fheroes2.git
synced 2026-10-12 02:16:11 +00:00
Add WASM version of the engine (#9406)
This commit is contained in:
@@ -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
|
||||
|
||||
+8
-1
@@ -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/*
|
||||
|
||||
@@ -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
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
@@ -0,0 +1,210 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>fheroes2</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/progress.js/0.1.0/progress.min.js" integrity="sha512-CklrzCqwODBOEJHJq73SZrgWC7xcxssgg5M1xokosfDDz2/nLTCuMDyc51gbJtb8DriV4EYjJSlklPH5Ejn9XA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/progress.js/0.1.0/progressjs.min.css" integrity="sha512-ovRFHsWpnYUBNZd/8CmbaWAKBDO8xb0l5Y8PdIae1O5RXO2QyU3CZGNzuYuE0CQHKazIzWMQpnTn26WpPjexfw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<style>
|
||||
body { margin: 0; height: 0; font-family: "Roboto", serif;}
|
||||
#canvas {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
background: url(./fheroes2.jpeg) center center;
|
||||
background-size: cover;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
#uploader, #launcher {
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
text-stroke: 1px #000;
|
||||
-webkit-text-stroke: 1px #000;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
#launcher {
|
||||
display: none;
|
||||
text-stroke: 1px #fff;
|
||||
-webkit-text-stroke: 1px #fff;
|
||||
}
|
||||
#uploader input[type=file] {
|
||||
display: none
|
||||
}
|
||||
#uploader label {
|
||||
text-align: center;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
position: absolute;
|
||||
}
|
||||
#uploader label span {
|
||||
padding: 10vh 0 0 0;
|
||||
display: block;
|
||||
}
|
||||
#launcher button {
|
||||
font-size: 30px;
|
||||
}
|
||||
#launcher .buttons {
|
||||
text-align: center;
|
||||
padding: 10vh 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas" width="640" height="400"></canvas>
|
||||
<div id="uploader">
|
||||
<label>
|
||||
<span>Click to select your Heroes 2 folder</span>
|
||||
<input
|
||||
type="file"
|
||||
directory="directory"
|
||||
multiple
|
||||
webkitdirectory="webkitdirectory"
|
||||
id="files"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div id="launcher">
|
||||
<div class="buttons">
|
||||
<button onclick="Module.startGame()">Start game</button>
|
||||
<button onclick="Module.deleteFiles()">Delete files</button>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const S_IFMT = 61440; /* 0x0170000 type of file */
|
||||
const S_IFDIR = 16384; /* 0x0040000 directory */
|
||||
const progressBar = progressJs("#canvas").setOptions({
|
||||
theme: 'blueOverlayRadiusWithPercentBar',
|
||||
overlayMode: true,
|
||||
considerTransition: true
|
||||
});
|
||||
const canvas = document.querySelector('canvas');
|
||||
canvas.oncontextmenu = event => event.preventDefault();
|
||||
Object.assign(window, { Module: {
|
||||
preRun: [
|
||||
() => Object.assign(window.ENV, {
|
||||
FHEROES2_DATA: `/fheroes2/data`,
|
||||
HOME: '/fheroes2'
|
||||
}),
|
||||
() => {
|
||||
addRunDependency('syncfs');
|
||||
FS.mkdir('/fheroes2');
|
||||
FS.mount(IDBFS, { root: '/' }, '/fheroes2');
|
||||
FS.syncfs(true, (err) => {
|
||||
if (err) throw err;
|
||||
try {
|
||||
if (Object.keys(FS.lookupPath(`${ENV.FHEROES2_DATA}`)).length === 0) return;
|
||||
document.querySelector('#uploader').style.display = 'none';
|
||||
document.querySelector('#launcher').style.display = 'block';
|
||||
}
|
||||
catch (ignore) {
|
||||
FS.mkdir(`${ENV.FHEROES2_DATA}`);
|
||||
}
|
||||
});
|
||||
},
|
||||
() => {
|
||||
document.querySelector('input[type=file]').addEventListener('input', e => {
|
||||
const files = [...e.target.files];
|
||||
const requiredFiles = ['data/HEROES2.AGG', 'data/HEROES2X.AGG']
|
||||
if (files.length === 1) return Module.clearInput('zip archives are not supported yet, sorry');
|
||||
if (files.length > 3000) return Module.clearInput('wrong directory, or your maps collection is really awesome.');
|
||||
const requiredResolved = files.filter(({ webkitRelativePath: path }) =>
|
||||
requiredFiles.some(rq => path.toLocaleLowerCase().endsWith(rq.toLocaleLowerCase()))).length === 2;
|
||||
if (!requiredResolved) return Module.clearInput('wrong directory');
|
||||
const whitListed = ['data', 'heroes2', 'maps', 'music'];
|
||||
files.filter(file => {
|
||||
const [fileName, ...path] = file.webkitRelativePath.split('/').reverse();
|
||||
if (fileName.startsWith('.')) return false;
|
||||
return path
|
||||
.map(folder => folder.toLocaleLowerCase())
|
||||
.some(folder => whitListed.includes(folder))
|
||||
}).reduce((uploaded, file, _ignore, queue) => {
|
||||
const [fileName, ...path] = file.webkitRelativePath.split('/').reverse();
|
||||
const [ignore, ...relativePath] = path.reverse();
|
||||
Module.mkdirWithParents(`${ENV.FHEROES2_DATA}/${relativePath.join('/')}`);
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('error', console.error);
|
||||
reader.addEventListener('loadend', ({ target: { result } }) => {
|
||||
FS.writeFile(`${ENV.FHEROES2_DATA}/${relativePath.join('/')}/${fileName}`, new Uint8Array(result), {
|
||||
encoding: 'binary'
|
||||
});
|
||||
uploaded.push(file);
|
||||
if (uploaded.length === queue.length) {
|
||||
FS.syncfs(false, err => {
|
||||
if (err) return Module.clearInput('Failed to sync FS');
|
||||
document.querySelector('#uploader').style.display = 'none';
|
||||
document.querySelector('#launcher').style.display = 'block';
|
||||
})
|
||||
}
|
||||
});
|
||||
reader.readAsArrayBuffer(file);
|
||||
return uploaded;
|
||||
}, []);
|
||||
})
|
||||
}
|
||||
],
|
||||
clearInput: (msg = '') => {
|
||||
document.querySelector('input[type=file]').value = null;
|
||||
msg && alert(msg);
|
||||
},
|
||||
mkdirWithParents: path => {
|
||||
const parts = path.split('/');
|
||||
try { FS.lookupPath(parts.join('/')) }
|
||||
catch (ignore) {
|
||||
parts.reduce((p, part) => {
|
||||
p = [...p, part];
|
||||
try { FS.lookupPath(p.join('/')) }
|
||||
catch (ignore) { FS.mkdir(p.join('/')) }
|
||||
return p;
|
||||
}, []);
|
||||
}
|
||||
},
|
||||
clearPath: path => {
|
||||
try {
|
||||
Object.keys(FS.lookupPath(path).node.contents).forEach(node =>
|
||||
(FS.stat(`${path}/${node}`).mode & S_IFMT) === S_IFDIR
|
||||
? Module.clearPath(`${path}/${node}`)
|
||||
: FS.unlink(`${path}/${node}`));
|
||||
FS.rmdir(`${path}`)
|
||||
} catch (ignore) {}
|
||||
},
|
||||
startGame: () => {
|
||||
removeRunDependency('syncfs');
|
||||
document.querySelector('#uploader').style.display = 'none';
|
||||
document.querySelector('#launcher').style.display = 'none';
|
||||
},
|
||||
deleteFiles: () => {
|
||||
if (false === confirm('Are you sure?')) return;
|
||||
Module.clearPath(ENV.FHEROES2_DATA);
|
||||
FS.syncfs(false, ignore => {});
|
||||
Module.clearInput();
|
||||
document.querySelector('#uploader').style.display = 'block';
|
||||
document.querySelector('#launcher').style.display = 'none';
|
||||
},
|
||||
setStatus: status => {
|
||||
const dlProgressRE = /(?<progress>\d+)\/(?<total>\d+)/ig;
|
||||
if (!status || !dlProgressRE.test(status)) {
|
||||
if ((status ?? '').startsWith('Downloading data')) progressBar.start();
|
||||
return;
|
||||
}
|
||||
dlProgressRE.lastIndex = 0;
|
||||
const {groups: {progress, total}} = [...status.matchAll(dlProgressRE)][0];
|
||||
const done = Math.round(progress / total * 100);
|
||||
progressBar.set(done);
|
||||
if (100 === done) progressBar.end();
|
||||
},
|
||||
canvas
|
||||
}
|
||||
});
|
||||
|
||||
document.head.append(Object.assign(document.createElement('script'), {src: './fheroes2.js'}));
|
||||
</script>
|
||||
</body>
|
||||
Vendored
+9
-1
@@ -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
|
||||
|
||||
Vendored
+43
@@ -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
|
||||
Vendored
+48
@@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user