Compare commits
170 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2226aa2e6b | ||
|
|
12ae789239 | ||
|
|
2d7d02d5c9 | ||
|
|
64ddb09060 | ||
|
|
0203bfa805 | ||
|
|
c974db8c1c | ||
|
|
8559b5e565 | ||
|
|
201ec079d6 | ||
|
|
f6e7e993f5 | ||
|
|
ff6a99999b | ||
|
|
35aacc1a3e | ||
|
|
59903397a7 | ||
|
|
ca39c0ddf3 | ||
|
|
6e6e1034b4 | ||
|
|
01efc218bf | ||
|
|
b4b602ae9d | ||
|
|
bd395b2775 | ||
|
|
bf36bfb02b | ||
|
|
4bbf77b217 | ||
|
|
486e88e7bc | ||
|
|
46396efd09 | ||
|
|
57d42a84a4 | ||
|
|
eb7e20d157 | ||
|
|
725e8b35bd | ||
|
|
17a8181822 | ||
|
|
6c40fb098f | ||
|
|
785935d26f | ||
|
|
f2e064e900 | ||
|
|
2e537807a7 | ||
|
|
f4e04b32dd | ||
|
|
d38ff06262 | ||
|
|
e1255e6124 | ||
|
|
37993c1669 | ||
|
|
2fa653fffe | ||
|
|
77fd519b43 | ||
|
|
017f874f38 | ||
|
|
c642bd3857 | ||
|
|
bc831220b4 | ||
|
|
b50147cace | ||
|
|
45a4b10d11 | ||
|
|
fe12f397cc | ||
|
|
801f67b194 | ||
|
|
e331c8f446 | ||
|
|
51897584a7 | ||
|
|
1cf3d101aa | ||
|
|
eb3b8c9e9d | ||
|
|
9ddab37232 | ||
|
|
cec7914c8f | ||
|
|
b19a83ac23 | ||
|
|
1905960b51 | ||
|
|
68a806aa3e | ||
|
|
b555c44b8b | ||
|
|
d0c503e096 | ||
|
|
9ec2182252 | ||
|
|
881d43c56d | ||
|
|
8a663e29a6 | ||
|
|
7ae19b6431 | ||
|
|
081b77f0e1 | ||
|
|
b4a9766d14 | ||
|
|
c33614a9cc | ||
|
|
ae37fde4b9 | ||
|
|
64a86b260a | ||
|
|
59cd9347c2 | ||
|
|
0281d28a72 | ||
|
|
e517e6c65b | ||
|
|
95283b6fc7 | ||
|
|
1ed2cd468e | ||
|
|
eaba1cd0ab | ||
|
|
421e74e357 | ||
|
|
6eba788236 | ||
|
|
d041461f0a | ||
|
|
13b277b35a | ||
|
|
fc703f241c | ||
|
|
1830e849d8 | ||
|
|
e3f246aa00 | ||
|
|
1eb679cf24 | ||
|
|
1963dc9fb9 | ||
|
|
396293c8af | ||
|
|
fbf6e910a3 | ||
|
|
9e4e861c32 | ||
|
|
d0b99a16c9 | ||
|
|
347e81c11c | ||
|
|
6b2a376dfe | ||
|
|
51e0ab7c48 | ||
|
|
87fd26ab89 | ||
|
|
0b1cee99bd | ||
|
|
4768df6867 | ||
|
|
423d502aa4 | ||
|
|
a74e9033b3 | ||
|
|
dc6b7de15f | ||
|
|
74f67d0216 | ||
|
|
d47f073d53 | ||
|
|
7407911914 | ||
|
|
9672a4fe57 | ||
|
|
6c6ff26586 | ||
|
|
ca6f701084 | ||
|
|
5793b7ca38 | ||
|
|
dee6ba95f2 | ||
|
|
67aef1dbe3 | ||
|
|
90f41a20a3 | ||
|
|
5f5dd48ee8 | ||
|
|
a8e0574f44 | ||
|
|
40f148b6b3 | ||
|
|
0eb37666f8 | ||
|
|
b73a653332 | ||
|
|
49f1b747b2 | ||
|
|
2c75f0bc9c | ||
|
|
97e17edfae | ||
|
|
f7e4e47466 | ||
|
|
8779abef9a | ||
|
|
4d1caa7fe0 | ||
|
|
78f3c31db1 | ||
|
|
3c852f17a0 | ||
|
|
8737a00b44 | ||
|
|
fff2c49f2e | ||
|
|
35c19a4d50 | ||
|
|
137e707c63 | ||
|
|
d2e9439e38 | ||
|
|
39cd7e4c1a | ||
|
|
57f2b9541d | ||
|
|
9d4065a05a | ||
|
|
424a3b3bee | ||
|
|
de3e1fcdc7 | ||
|
|
59f390de93 | ||
|
|
26287c8f35 | ||
|
|
24d552ba2b | ||
|
|
f1a08ca325 | ||
|
|
28ec031afa | ||
|
|
d9f606c56f | ||
|
|
de4b73cf83 | ||
|
|
beff0c9d99 | ||
|
|
4a76a929f5 | ||
|
|
aa981160e8 | ||
|
|
24a95a36d0 | ||
|
|
583819e8c4 | ||
|
|
4c193efd41 | ||
|
|
8208e7b132 | ||
|
|
7e2bd7b08d | ||
|
|
29258e2a35 | ||
|
|
9e028bc907 | ||
|
|
75ae05ffc9 | ||
|
|
aec0b91039 | ||
|
|
34df33c9b0 | ||
|
|
1674902727 | ||
|
|
4fd497fe9f | ||
|
|
f01594b4d1 | ||
|
|
6f74693811 | ||
|
|
94d2af685c | ||
|
|
0b7c2fa59b | ||
|
|
137f9a0d55 | ||
|
|
23d8a34991 | ||
|
|
3f0d4d3cdf | ||
|
|
ac8f62de03 | ||
|
|
e518d91237 | ||
|
|
c054a76504 | ||
|
|
d3406c4a48 | ||
|
|
3c0266ec02 | ||
|
|
4f4683d06c | ||
|
|
3441002758 | ||
|
|
c2bf291029 | ||
|
|
d70b04e7fb | ||
|
|
a979b6dbe6 | ||
|
|
523b7ce443 | ||
|
|
4e74c9456f | ||
|
|
7719b74b09 | ||
|
|
9d3aeeb50b | ||
|
|
0459248556 | ||
|
|
288a6ba80a | ||
|
|
97eee39266 | ||
|
|
8c4446edac |
16
.github/500stars/README.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Techmino - 500-star Banner
|
||||||
|
Created by NOT_A_ROBOT
|
||||||
|
13 September, 2024
|
||||||
|
|
||||||
|
**Don't forget to attribute me when using this.**
|
||||||
|
The image already includes sufficient attribution, so if you just don't crop that out, you shouldn't need to explicitly mention them.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
Created by NOT_A_ROBOT
|
||||||
|
GitHub logo (on Z-character's screen) by GitHub
|
||||||
|
Background (space stars) originally by MrZ, ported to JS by NOT_A_ROBOT for rendering
|
||||||
|
Block skin (featured in the background) by Scf, slightly modified to make it darker
|
||||||
|
Z-character drawn by 葉枭, designed by MrZ
|
||||||
|
Techmino by MrZ and many contributors
|
||||||
|
|
||||||
|
Techmino is fun! https://github.com/26F-Studio/Techmino
|
||||||
BIN
.github/500stars/exported.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
32
.github/actions/get-cc/action.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: 'get cc'
|
|
||||||
description: 'download cc into specific dir'
|
|
||||||
inputs:
|
|
||||||
tag:
|
|
||||||
required: false
|
|
||||||
default: "11.4.2"
|
|
||||||
platform:
|
|
||||||
required: true
|
|
||||||
dir:
|
|
||||||
required: false
|
|
||||||
default: '.'
|
|
||||||
repo:
|
|
||||||
required: false
|
|
||||||
default: 26F-Studio/cold_clear_ai_love2d_wrapper
|
|
||||||
temp-file:
|
|
||||||
required: false
|
|
||||||
default: temp.zip
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- run: |
|
|
||||||
echo "tag="$(if [ -z "${{ inputs.tag }}" ]
|
|
||||||
then curl -w '%{url_effective}' -I -L -s -S https://github.com/${{ inputs.repo }}/releases/latest -o /dev/null | grep -o '\<[^/]*$'
|
|
||||||
else echo ${{ inputs.tag }}
|
|
||||||
fi) >> $GITHUB_OUTPUT
|
|
||||||
id: get-tag
|
|
||||||
shell: bash
|
|
||||||
- uses: ./.github/actions/get-unzip
|
|
||||||
with:
|
|
||||||
url: https://github.com/${{ inputs.repo }}/releases/download/${{ steps.get-tag.outputs.tag }}/${{ inputs.platform }}.zip
|
|
||||||
dir: ${{ inputs.dir }}
|
|
||||||
temp-file: ${{ inputs.temp-file }}
|
|
||||||
BIN
.github/build/extraLibs/Windows_x64/discord-rpc.dll
vendored
Normal file
BIN
.github/build/extraLibs/Windows_x86/discord-rpc.dll
vendored
Normal file
BIN
.github/build/web/dev/favicon.ico
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
112
.github/build/web/dev/index.html
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en-us">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, minimum-scale=1, maximum-scale=1">
|
||||||
|
<title>Techmino Development</title>
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
<link rel="stylesheet" type="text/css" href="theme/love.css">
|
||||||
|
<script src="consolewrapper.js"></script>
|
||||||
|
<script src="webdb.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<center>
|
||||||
|
<div>
|
||||||
|
<h1>Techmino</h1>
|
||||||
|
<canvas id="loadingCanvas" oncontextmenu="event.preventDefault()" width="800" height="600"></canvas>
|
||||||
|
<canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||||
|
</div>
|
||||||
|
</center>
|
||||||
|
|
||||||
|
<script type='text/javascript'>
|
||||||
|
function goFullScreen(){
|
||||||
|
var canvas = document.getElementById("canvas");
|
||||||
|
if(canvas.requestFullScreen)
|
||||||
|
canvas.requestFullScreen();
|
||||||
|
else if(canvas.webkitRequestFullScreen)
|
||||||
|
canvas.webkitRequestFullScreen();
|
||||||
|
else if(canvas.mozRequestFullScreen)
|
||||||
|
canvas.mozRequestFullScreen();
|
||||||
|
}
|
||||||
|
function FullScreenHook(){
|
||||||
|
var canvas = document.getElementById("canvas");
|
||||||
|
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
|
canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
|
||||||
|
}
|
||||||
|
var loadingContext = document.getElementById('loadingCanvas').getContext('2d');
|
||||||
|
function drawLoadingText(text) {
|
||||||
|
var canvas = loadingContext.canvas;
|
||||||
|
|
||||||
|
loadingContext.fillStyle = "rgb(142, 195, 227)";
|
||||||
|
loadingContext.fillRect(0, 0, canvas.scrollWidth, canvas.scrollHeight);
|
||||||
|
|
||||||
|
loadingContext.font = '2em arial';
|
||||||
|
loadingContext.textAlign = 'center'
|
||||||
|
loadingContext.fillStyle = "rgb( 11, 86, 117 )";
|
||||||
|
loadingContext.fillText(text, canvas.scrollWidth / 2, canvas.scrollHeight / 2);
|
||||||
|
|
||||||
|
loadingContext.fillText("Powered By Emscripten.", canvas.scrollWidth / 2, canvas.scrollHeight / 4);
|
||||||
|
loadingContext.fillText("Powered By LÖVE.", canvas.scrollWidth / 2, canvas.scrollHeight / 4 * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function () { window.focus(); };
|
||||||
|
window.onclick = function () { window.focus(); };
|
||||||
|
|
||||||
|
window.addEventListener("keydown", function(e) {
|
||||||
|
// space and arrow keys
|
||||||
|
if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
var Module = {
|
||||||
|
arguments: ["./game.love"],
|
||||||
|
INITIAL_MEMORY: 128000000,
|
||||||
|
printErr: console.error.bind(console),
|
||||||
|
canvas: (function() {
|
||||||
|
var canvas = document.getElementById('canvas');
|
||||||
|
|
||||||
|
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
|
||||||
|
// application robust, you may want to override this behavior before shipping!
|
||||||
|
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
|
||||||
|
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
})(),
|
||||||
|
setStatus: function(text) {
|
||||||
|
if (text) {
|
||||||
|
drawLoadingText(text);
|
||||||
|
} else if (Module.remainingDependencies === 0) {
|
||||||
|
document.getElementById('loadingCanvas').style.display = 'none';
|
||||||
|
document.getElementById('canvas').style.visibility = 'visible';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
totalDependencies: 0,
|
||||||
|
remainingDependencies: 0,
|
||||||
|
monitorRunDependencies: function(left) {
|
||||||
|
this.remainingDependencies = left;
|
||||||
|
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||||
|
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Module.setStatus('Downloading...');
|
||||||
|
window.onerror = function(event) {
|
||||||
|
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
|
||||||
|
Module.setStatus('Exception thrown, see JavaScript console');
|
||||||
|
Module.setStatus = function(text) {
|
||||||
|
if (text) Module.printErr('[post-exception status] ' + text);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var applicationLoad = function(e) {
|
||||||
|
Love(Module);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="game.js"></script>
|
||||||
|
<script async type="text/javascript" src="love.js" onload="applicationLoad(this)"></script>
|
||||||
|
<footer>
|
||||||
|
<p>Built with <a href="https://github.com/Davidobot/love.js">love.js</a> <button onclick="goFullScreen();">Go Fullscreen</button><br>Hint: Reload the page if screen is blank</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
288
.github/build/web/game.js
vendored
@@ -1,288 +0,0 @@
|
|||||||
|
|
||||||
var Module;
|
|
||||||
|
|
||||||
if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
|
|
||||||
|
|
||||||
if (!Module.expectedDataFileDownloads) {
|
|
||||||
Module.expectedDataFileDownloads = 0;
|
|
||||||
Module.finishedDataFileDownloads = 0;
|
|
||||||
}
|
|
||||||
Module.expectedDataFileDownloads++;
|
|
||||||
(function() {
|
|
||||||
var loadPackage = function(metadata) {
|
|
||||||
|
|
||||||
var PACKAGE_PATH;
|
|
||||||
if (typeof window === 'object') {
|
|
||||||
PACKAGE_PATH = window['encodeURIComponent'](window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/');
|
|
||||||
} else if (typeof location !== 'undefined') {
|
|
||||||
// worker
|
|
||||||
PACKAGE_PATH = encodeURIComponent(location.pathname.toString().substring(0, location.pathname.toString().lastIndexOf('/')) + '/');
|
|
||||||
} else {
|
|
||||||
throw 'using preloaded data can only be done on a web page or in a web worker';
|
|
||||||
}
|
|
||||||
var PACKAGE_NAME = 'game.data';
|
|
||||||
var REMOTE_PACKAGE_BASE = 'game.data';
|
|
||||||
if (typeof Module['locateFilePackage'] === 'function' && !Module['locateFile']) {
|
|
||||||
Module['locateFile'] = Module['locateFilePackage'];
|
|
||||||
Module.printErr('warning: you defined Module.locateFilePackage, that has been renamed to Module.locateFile (using your locateFilePackage for now)');
|
|
||||||
}
|
|
||||||
var REMOTE_PACKAGE_NAME = typeof Module['locateFile'] === 'function' ?
|
|
||||||
Module['locateFile'](REMOTE_PACKAGE_BASE) :
|
|
||||||
((Module['filePackagePrefixURL'] || '') + REMOTE_PACKAGE_BASE);
|
|
||||||
|
|
||||||
var REMOTE_PACKAGE_SIZE = metadata.remote_package_size;
|
|
||||||
var PACKAGE_UUID = metadata.package_uuid;
|
|
||||||
|
|
||||||
function fetchRemotePackage(packageName, packageSize, callback, errback) {
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.open('GET', packageName, true);
|
|
||||||
xhr.responseType = 'arraybuffer';
|
|
||||||
xhr.onprogress = function(event) {
|
|
||||||
var url = packageName;
|
|
||||||
var size = packageSize;
|
|
||||||
if (event.total) size = event.total;
|
|
||||||
if (event.loaded) {
|
|
||||||
if (!xhr.addedTotal) {
|
|
||||||
xhr.addedTotal = true;
|
|
||||||
if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
|
|
||||||
Module.dataFileDownloads[url] = {
|
|
||||||
loaded: event.loaded,
|
|
||||||
total: size
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
Module.dataFileDownloads[url].loaded = event.loaded;
|
|
||||||
}
|
|
||||||
var total = 0;
|
|
||||||
var loaded = 0;
|
|
||||||
var num = 0;
|
|
||||||
for (var download in Module.dataFileDownloads) {
|
|
||||||
var data = Module.dataFileDownloads[download];
|
|
||||||
total += data.total;
|
|
||||||
loaded += data.loaded;
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
total = Math.ceil(total * Module.expectedDataFileDownloads/num);
|
|
||||||
if (Module['setStatus']) Module['setStatus']('Downloading data... (' + loaded + '/' + total + ')');
|
|
||||||
} else if (!Module.dataFileDownloads) {
|
|
||||||
if (Module['setStatus']) Module['setStatus']('Downloading data...');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.onerror = function(event) {
|
|
||||||
throw new Error("NetworkError for: " + packageName);
|
|
||||||
}
|
|
||||||
xhr.onload = function(event) {
|
|
||||||
if (xhr.status == 200 || xhr.status == 304 || xhr.status == 206 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
|
|
||||||
var packageData = xhr.response;
|
|
||||||
callback(packageData);
|
|
||||||
} else {
|
|
||||||
throw new Error(xhr.statusText + " : " + xhr.responseURL);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.send(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
function handleError(error) {
|
|
||||||
console.error('package error:', error);
|
|
||||||
};
|
|
||||||
|
|
||||||
function runWithFS() {
|
|
||||||
|
|
||||||
function assert(check, msg) {
|
|
||||||
if (!check) throw msg + new Error().stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
function DataRequest(start, end, crunched, audio) {
|
|
||||||
this.start = start;
|
|
||||||
this.end = end;
|
|
||||||
this.crunched = crunched;
|
|
||||||
this.audio = audio;
|
|
||||||
}
|
|
||||||
DataRequest.prototype = {
|
|
||||||
requests: {},
|
|
||||||
open: function(mode, name) {
|
|
||||||
this.name = name;
|
|
||||||
this.requests[name] = this;
|
|
||||||
Module['addRunDependency']('fp ' + this.name);
|
|
||||||
},
|
|
||||||
send: function() {},
|
|
||||||
onload: function() {
|
|
||||||
var byteArray = this.byteArray.subarray(this.start, this.end);
|
|
||||||
|
|
||||||
this.finish(byteArray);
|
|
||||||
|
|
||||||
},
|
|
||||||
finish: function(byteArray) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
Module['FS_createDataFile'](this.name, null, byteArray, true, true, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change
|
|
||||||
Module['removeRunDependency']('fp ' + that.name);
|
|
||||||
|
|
||||||
this.requests[this.name] = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var files = metadata.files;
|
|
||||||
for (i = 0; i < files.length; ++i) {
|
|
||||||
new DataRequest(files[i].start, files[i].end, files[i].crunched, files[i].audio).open('GET', files[i].filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
|
|
||||||
var IDB_RO = "readonly";
|
|
||||||
var IDB_RW = "readwrite";
|
|
||||||
var DB_NAME = "EM_PRELOAD_CACHE";
|
|
||||||
var DB_VERSION = 1;
|
|
||||||
var METADATA_STORE_NAME = 'METADATA';
|
|
||||||
var PACKAGE_STORE_NAME = 'PACKAGES';
|
|
||||||
function openDatabase(callback, errback) {
|
|
||||||
try {
|
|
||||||
var openRequest = indexedDB.open(DB_NAME, DB_VERSION);
|
|
||||||
} catch (e) {
|
|
||||||
return errback(e);
|
|
||||||
}
|
|
||||||
openRequest.onupgradeneeded = function(event) {
|
|
||||||
var db = event.target.result;
|
|
||||||
|
|
||||||
if(db.objectStoreNames.contains(PACKAGE_STORE_NAME)) {
|
|
||||||
db.deleteObjectStore(PACKAGE_STORE_NAME);
|
|
||||||
}
|
|
||||||
var packages = db.createObjectStore(PACKAGE_STORE_NAME);
|
|
||||||
|
|
||||||
if(db.objectStoreNames.contains(METADATA_STORE_NAME)) {
|
|
||||||
db.deleteObjectStore(METADATA_STORE_NAME);
|
|
||||||
}
|
|
||||||
var metadata = db.createObjectStore(METADATA_STORE_NAME);
|
|
||||||
};
|
|
||||||
openRequest.onsuccess = function(event) {
|
|
||||||
var db = event.target.result;
|
|
||||||
callback(db);
|
|
||||||
};
|
|
||||||
openRequest.onerror = function(error) {
|
|
||||||
errback(error);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Check if there's a cached package, and if so whether it's the latest available */
|
|
||||||
function checkCachedPackage(db, packageName, callback, errback) {
|
|
||||||
var transaction = db.transaction([METADATA_STORE_NAME], IDB_RO);
|
|
||||||
var metadata = transaction.objectStore(METADATA_STORE_NAME);
|
|
||||||
|
|
||||||
var getRequest = metadata.get("metadata/" + packageName);
|
|
||||||
getRequest.onsuccess = function(event) {
|
|
||||||
var result = event.target.result;
|
|
||||||
if (!result) {
|
|
||||||
return callback(false);
|
|
||||||
} else {
|
|
||||||
return callback(PACKAGE_UUID === result.uuid);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
getRequest.onerror = function(error) {
|
|
||||||
errback(error);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function fetchCachedPackage(db, packageName, callback, errback) {
|
|
||||||
var transaction = db.transaction([PACKAGE_STORE_NAME], IDB_RO);
|
|
||||||
var packages = transaction.objectStore(PACKAGE_STORE_NAME);
|
|
||||||
|
|
||||||
var getRequest = packages.get("package/" + packageName);
|
|
||||||
getRequest.onsuccess = function(event) {
|
|
||||||
var result = event.target.result;
|
|
||||||
callback(result);
|
|
||||||
};
|
|
||||||
getRequest.onerror = function(error) {
|
|
||||||
errback(error);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function cacheRemotePackage(db, packageName, packageData, packageMeta, callback, errback) {
|
|
||||||
var transaction_packages = db.transaction([PACKAGE_STORE_NAME], IDB_RW);
|
|
||||||
var packages = transaction_packages.objectStore(PACKAGE_STORE_NAME);
|
|
||||||
|
|
||||||
var putPackageRequest = packages.put(packageData, "package/" + packageName);
|
|
||||||
putPackageRequest.onsuccess = function(event) {
|
|
||||||
var transaction_metadata = db.transaction([METADATA_STORE_NAME], IDB_RW);
|
|
||||||
var metadata = transaction_metadata.objectStore(METADATA_STORE_NAME);
|
|
||||||
var putMetadataRequest = metadata.put(packageMeta, "metadata/" + packageName);
|
|
||||||
putMetadataRequest.onsuccess = function(event) {
|
|
||||||
callback(packageData);
|
|
||||||
};
|
|
||||||
putMetadataRequest.onerror = function(error) {
|
|
||||||
errback(error);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
putPackageRequest.onerror = function(error) {
|
|
||||||
errback(error);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function processPackageData(arrayBuffer) {
|
|
||||||
Module.finishedDataFileDownloads++;
|
|
||||||
assert(arrayBuffer, 'Loading data file failed.');
|
|
||||||
assert(arrayBuffer instanceof ArrayBuffer, 'bad input to processPackageData');
|
|
||||||
var byteArray = new Uint8Array(arrayBuffer);
|
|
||||||
var curr;
|
|
||||||
|
|
||||||
// copy the entire loaded file into a spot in the heap. Files will refer to slices in that. They cannot be freed though
|
|
||||||
// (we may be allocating before malloc is ready, during startup).
|
|
||||||
if (Module['SPLIT_MEMORY']) Module.printErr('warning: you should run the file packager with --no-heap-copy when SPLIT_MEMORY is used, otherwise copying into the heap may fail due to the splitting');
|
|
||||||
var ptr = Module['getMemory'](byteArray.length);
|
|
||||||
Module['HEAPU8'].set(byteArray, ptr);
|
|
||||||
DataRequest.prototype.byteArray = Module['HEAPU8'].subarray(ptr, ptr+byteArray.length);
|
|
||||||
|
|
||||||
var files = metadata.files;
|
|
||||||
for (i = 0; i < files.length; ++i) {
|
|
||||||
DataRequest.prototype.requests[files[i].filename].onload();
|
|
||||||
}
|
|
||||||
Module['removeRunDependency']('datafile_game.data');
|
|
||||||
|
|
||||||
};
|
|
||||||
Module['addRunDependency']('datafile_game.data');
|
|
||||||
|
|
||||||
if (!Module.preloadResults) Module.preloadResults = {};
|
|
||||||
|
|
||||||
function preloadFallback(error) {
|
|
||||||
console.error(error);
|
|
||||||
console.error('falling back to default preload behavior');
|
|
||||||
fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, processPackageData, handleError);
|
|
||||||
};
|
|
||||||
|
|
||||||
openDatabase(
|
|
||||||
function(db) {
|
|
||||||
checkCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME,
|
|
||||||
function(useCached) {
|
|
||||||
Module.preloadResults[PACKAGE_NAME] = {fromCache: useCached};
|
|
||||||
if (useCached) {
|
|
||||||
console.info('loading ' + PACKAGE_NAME + ' from cache');
|
|
||||||
fetchCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME, processPackageData, preloadFallback);
|
|
||||||
} else {
|
|
||||||
console.info('loading ' + PACKAGE_NAME + ' from remote');
|
|
||||||
fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE,
|
|
||||||
function(packageData) {
|
|
||||||
cacheRemotePackage(db, PACKAGE_PATH + PACKAGE_NAME, packageData, {uuid:PACKAGE_UUID}, processPackageData,
|
|
||||||
function(error) {
|
|
||||||
console.error(error);
|
|
||||||
processPackageData(packageData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
, preloadFallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
, preloadFallback);
|
|
||||||
}
|
|
||||||
, preloadFallback);
|
|
||||||
|
|
||||||
if (Module['setStatus']) Module['setStatus']('Downloading...');
|
|
||||||
|
|
||||||
}
|
|
||||||
if (Module['calledRun']) {
|
|
||||||
runWithFS();
|
|
||||||
} else {
|
|
||||||
if (!Module['preRun']) Module['preRun'] = [];
|
|
||||||
Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
loadPackage({"package_uuid":"80826f15-f924-4428-a8c4-e984743417c6","remote_package_size":62246034,"files":[{"filename":"/game.love","crunched":0,"start":0,"end":62246034,"audio":false}]});
|
|
||||||
|
|
||||||
})();
|
|
||||||
22
.github/build/web/love.js
vendored
BIN
.github/build/web/love.wasm
vendored
|
Before Width: | Height: | Size: 305 KiB After Width: | Height: | Size: 305 KiB |
@@ -5,9 +5,10 @@
|
|||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, minimum-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, minimum-scale=1, maximum-scale=1">
|
||||||
<title>Techmino</title>
|
<title>Techmino</title>
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
<!-- Load custom style sheet -->
|
|
||||||
<link rel="stylesheet" type="text/css" href="theme/love.css">
|
<link rel="stylesheet" type="text/css" href="theme/love.css">
|
||||||
|
<script src="consolewrapper.js"></script>
|
||||||
|
<script src="webdb.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<center>
|
<center>
|
||||||
@@ -61,7 +62,7 @@
|
|||||||
|
|
||||||
var Module = {
|
var Module = {
|
||||||
arguments: ["./game.love"],
|
arguments: ["./game.love"],
|
||||||
INITIAL_MEMORY: 536870912,
|
INITIAL_MEMORY: 128000000,
|
||||||
printErr: console.error.bind(console),
|
printErr: console.error.bind(console),
|
||||||
canvas: (function() {
|
canvas: (function() {
|
||||||
var canvas = document.getElementById('canvas');
|
var canvas = document.getElementById('canvas');
|
||||||
BIN
.github/build/web/theme/bg.png
vendored
|
Before Width: | Height: | Size: 7.0 KiB |
49
.github/build/web/theme/love.css
vendored
@@ -1,49 +0,0 @@
|
|||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-family: arial;
|
|
||||||
color: rgb( 11, 86, 117 );
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-image: url(bg.png);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
font-family: arial;
|
|
||||||
margin: 0;
|
|
||||||
padding: none;
|
|
||||||
background-color: rgb( 154, 205, 237 );
|
|
||||||
color: rgb( 28, 78, 104 );
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
font-family: arial;
|
|
||||||
font-size: 12px;
|
|
||||||
padding-left: 10px;
|
|
||||||
position:absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Links */
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
a:link {
|
|
||||||
color: rgb( 233, 73, 154 );
|
|
||||||
}
|
|
||||||
a:visited {
|
|
||||||
color: rgb( 110, 30, 71 );
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: rgb( 252, 207, 230 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
|
|
||||||
#canvas {
|
|
||||||
padding-right: 0;
|
|
||||||
display: block;
|
|
||||||
border: 0px none;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
BIN
.github/donate/donate.png
vendored
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
319
.github/workflows/main.yml
vendored
@@ -8,9 +8,11 @@ on:
|
|||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
BUILD_ASSETS_FOLDER: ./.github/build
|
||||||
BUILD_TYPE: ${{ fromJSON('["dev", "release"]')[startsWith(github.ref, 'refs/tags/v')] }}
|
BUILD_TYPE: ${{ fromJSON('["dev", "release"]')[startsWith(github.ref, 'refs/tags/v')] }}
|
||||||
CORE_LOVE_PACKAGE_PATH: ./core.love
|
COLD_CLEAR_DOWNLOAD_URL: https://github.com/26F-Studio/cold_clear_ai_love2d_wrapper/releases/download/11.5
|
||||||
CORE_LOVE_ARTIFACT_NAME: core_love_package
|
CORE_LOVE_ARTIFACT_NAME: core_love_package
|
||||||
|
CORE_LOVE_PACKAGE_PATH: ./core.love
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
get-info:
|
get-info:
|
||||||
@@ -25,7 +27,7 @@ jobs:
|
|||||||
commit-hash: ${{ steps.git-info.outputs.commit-hash }}
|
commit-hash: ${{ steps.git-info.outputs.commit-hash }}
|
||||||
base-name: ${{ steps.assemble-base-name.outputs.base-name }}
|
base-name: ${{ steps.assemble-base-name.outputs.base-name }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install lua
|
- name: Install lua
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install lua5.3 -y
|
sudo apt-get install lua5.3 -y
|
||||||
@@ -73,7 +75,7 @@ jobs:
|
|||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Process app name
|
- name: Process app name
|
||||||
@@ -95,13 +97,13 @@ jobs:
|
|||||||
build-list: ./media/ ./parts/ ./Zframework/ ./conf.lua ./main.lua ./version.lua ./legals.md ./license.txt
|
build-list: ./media/ ./parts/ ./Zframework/ ./conf.lua ./main.lua ./version.lua ./legals.md ./license.txt
|
||||||
package-path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
package-path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
- name: Upload core love package
|
- name: Upload core love package
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
- name: Add icon to love package
|
- name: Add icon to love package
|
||||||
run: |
|
run: |
|
||||||
cp ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png
|
cp ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png
|
||||||
zip -u ${{ env.CORE_LOVE_PACKAGE_PATH }} media/image/icon.png
|
zip -u ${{ env.CORE_LOVE_PACKAGE_PATH }} media/image/icon.png
|
||||||
rm media/image/icon.png
|
rm media/image/icon.png
|
||||||
- name: Rename love package
|
- name: Rename love package
|
||||||
@@ -109,7 +111,7 @@ jobs:
|
|||||||
mkdir -p ${{ env.OUTPUT_FOLDER }}
|
mkdir -p ${{ env.OUTPUT_FOLDER }}
|
||||||
mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love
|
mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Core_love
|
name: ${{ needs.get-info.outputs.base-name }}_Core_love
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love
|
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love
|
||||||
@@ -130,10 +132,12 @@ jobs:
|
|||||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||||
|
|
||||||
auto-test:
|
auto-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
needs: build-core
|
needs: build-core
|
||||||
|
env:
|
||||||
|
APPIMAGE_PATH: ./love.AppImage
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Love actions for testing
|
- name: Love actions for testing
|
||||||
@@ -141,16 +145,35 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
font-path: ./parts/fonts/proportional.otf
|
font-path: ./parts/fonts/proportional.otf
|
||||||
language-folder: ./parts/language
|
language-folder: ./parts/language
|
||||||
|
- name: Download core love package
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
|
- name: Download love
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
curl --retry 5 https://github.com/love2d/love/releases/download/11.5/love-11.5-x86_64.AppImage -o ${{ env.APPIMAGE_PATH }}
|
||||||
|
chmod +x ${{ env.APPIMAGE_PATH }}
|
||||||
|
- name: Install dependencies
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install alsa-oss alsa-utils libfuse2 pavucontrol pulseaudio pulseaudio-utils x11-xserver-utils xvfb -y
|
||||||
|
- name: Run automated test
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
xvfb-run --auto-servernum ${{ env.APPIMAGE_PATH }} ${{ env.CORE_LOVE_PACKAGE_PATH }} --test
|
||||||
|
|
||||||
build-android:
|
build-android:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [get-info, build-core, auto-test]
|
needs: [get-info, build-core, auto-test]
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
env:
|
env:
|
||||||
|
COLD_CLEAR_FOLDER: ./libAndroid
|
||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Process app name
|
- name: Process app name
|
||||||
@@ -159,6 +182,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
|
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
|
||||||
if "${{ env.BUILD_TYPE }}" == "dev":
|
if "${{ env.BUILD_TYPE }}" == "dev":
|
||||||
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '.snapshot\n')
|
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '.snapshot\n')
|
||||||
@@ -167,17 +191,17 @@ jobs:
|
|||||||
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
||||||
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
||||||
- name: Download core love package
|
- name: Download core love package
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
- name: Download ColdClear
|
- name: Download ColdClear
|
||||||
uses: ./.github/actions/get-cc
|
uses: ./.github/actions/get-unzip
|
||||||
with:
|
with:
|
||||||
platform: Android
|
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Android.zip
|
||||||
dir: ./libAndroid
|
dir: ${{ env.COLD_CLEAR_FOLDER }}
|
||||||
- name: Build Android packages
|
- name: Build Android packages
|
||||||
id: build-packages
|
id: build-packages
|
||||||
uses: love-actions/love-actions-android@main
|
uses: love-actions/love-actions-android@v2
|
||||||
with:
|
with:
|
||||||
app-name: ${{ needs.get-info.outputs.app-name }}
|
app-name: ${{ needs.get-info.outputs.app-name }}
|
||||||
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
||||||
@@ -187,15 +211,15 @@ jobs:
|
|||||||
keystore-key-password: ${{ secrets.ANDROID_KEYSTORE_KEYPASSWORD }}
|
keystore-key-password: ${{ secrets.ANDROID_KEYSTORE_KEYPASSWORD }}
|
||||||
keystore-store-password: ${{ secrets.ANDROID_KEYSTORE_STOREPASSWORD }}
|
keystore-store-password: ${{ secrets.ANDROID_KEYSTORE_STOREPASSWORD }}
|
||||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
resource-path: ./.github/build/android/${{ env.BUILD_TYPE }}/res
|
resource-path: ${{ env.BUILD_ASSETS_FOLDER }}/android/${{ env.BUILD_TYPE }}/res
|
||||||
extra-assets: ./libAndroid/
|
extra-assets: ${{ env.COLD_CLEAR_FOLDER }}
|
||||||
custom-scheme: studio26f://oauth
|
custom-scheme: studio26f://oauth
|
||||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||||
version-string: ${{ needs.get-info.outputs.version-string }}
|
version-string: ${{ needs.get-info.outputs.version-string }}
|
||||||
version-code: ${{ needs.get-info.outputs.version-code }}
|
version-code: ${{ needs.get-info.outputs.version-code }}
|
||||||
output-folder: ${{ env.OUTPUT_FOLDER }}
|
output-folder: ${{ env.OUTPUT_FOLDER }}
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Android_release
|
name: ${{ needs.get-info.outputs.base-name }}_Android_release
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}-release.apk
|
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}-release.apk
|
||||||
@@ -219,10 +243,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [get-info, build-core, auto-test]
|
needs: [get-info, build-core, auto-test]
|
||||||
env:
|
env:
|
||||||
|
COLD_CLEAR_FOLDER: ./ColdClear
|
||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Process app name
|
- name: Process app name
|
||||||
@@ -237,45 +262,45 @@ jobs:
|
|||||||
f.write('bundle-id=org.26f-studio.' + product_name + '\n')
|
f.write('bundle-id=org.26f-studio.' + product_name + '\n')
|
||||||
f.write('product-name=' + product_name + '\n')
|
f.write('product-name=' + product_name + '\n')
|
||||||
- name: Download core love package
|
- name: Download core love package
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
- name: Add icon to love package
|
- name: Add icon to love package
|
||||||
run: |
|
run: |
|
||||||
cp ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png
|
cp ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png
|
||||||
zip -u ${{ env.CORE_LOVE_PACKAGE_PATH }} media/image/icon.png
|
zip -u ${{ env.CORE_LOVE_PACKAGE_PATH }} media/image/icon.png
|
||||||
rm media/image/icon.png
|
rm media/image/icon.png
|
||||||
- name: Download ColdClear
|
- name: Download ColdClear
|
||||||
uses: ./.github/actions/get-cc
|
uses: ./.github/actions/get-unzip
|
||||||
with:
|
with:
|
||||||
platform: Linux
|
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Linux.zip
|
||||||
dir: ./ColdClear
|
dir: ${{ env.COLD_CLEAR_FOLDER }}
|
||||||
- name: Process ColdClear
|
- name: Process ColdClear
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cd ./ColdClear
|
cd ${{ env.COLD_CLEAR_FOLDER }}
|
||||||
mkdir -p ./lib/lua/5.1
|
mkdir -p ./lib/lua/5.1
|
||||||
mv ./x64/CCloader.so ./lib/lua/5.1
|
mv ./x64/CCloader.so ./lib/lua/5.1
|
||||||
- name: Build Linux packages
|
- name: Build Linux packages
|
||||||
id: build-packages
|
id: build-packages
|
||||||
uses: love-actions/love-actions-linux@v1
|
uses: love-actions/love-actions-linux@v2
|
||||||
with:
|
with:
|
||||||
app-name: ${{ needs.get-info.outputs.app-name }}
|
app-name: ${{ needs.get-info.outputs.app-name }}
|
||||||
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
||||||
description: Techmino is fun!
|
description: Techmino is fun!
|
||||||
version-string: ${{ needs.get-info.outputs.version-string }}
|
version-string: ${{ needs.get-info.outputs.version-string }}
|
||||||
icon-path: ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png
|
icon-path: ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png
|
||||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
lib-path: ./ColdClear/lib
|
lib-path: ${{ env.COLD_CLEAR_FOLDER }}/lib
|
||||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||||
output-folder: ${{ env.OUTPUT_FOLDER }}
|
output-folder: ${{ env.OUTPUT_FOLDER }}
|
||||||
- name: Upload AppImage artifact
|
- name: Upload AppImage artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Linux_AppImage
|
name: ${{ needs.get-info.outputs.base-name }}_Linux_AppImage
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.AppImage
|
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.AppImage
|
||||||
- name: Upload Debian artifact
|
- name: Upload Debian artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Linux_Debian
|
name: ${{ needs.get-info.outputs.base-name }}_Linux_Debian
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.deb
|
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.deb
|
||||||
@@ -298,138 +323,58 @@ jobs:
|
|||||||
name: ${{ needs.get-info.outputs.update-title }}
|
name: ${{ needs.get-info.outputs.update-title }}
|
||||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||||
|
|
||||||
build-macos-portable:
|
build-web-compat:
|
||||||
runs-on: macos-latest
|
|
||||||
needs: [get-info, build-core, auto-test]
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
env:
|
|
||||||
OUTPUT_FOLDER: ./build
|
|
||||||
RELEASE_FOLDER: ./release
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
- name: Process app name
|
|
||||||
id: process-app-name
|
|
||||||
shell: python3 {0}
|
|
||||||
run: |
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
|
|
||||||
f.write('bundle-id=org.26f-studio.techmino\n')
|
|
||||||
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
|
||||||
- name: Download core love package
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
|
||||||
- name: Download ColdClear
|
|
||||||
uses: ./.github/actions/get-cc
|
|
||||||
with:
|
|
||||||
platform: macOS
|
|
||||||
dir: ./ColdClear
|
|
||||||
- name: Process ColdClear
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
rm ./ColdClear/universal/libcold_clear.a
|
|
||||||
- name: Build macOS packages
|
|
||||||
id: build-packages
|
|
||||||
uses: love-actions/love-actions-macos-portable@v1
|
|
||||||
with:
|
|
||||||
app-name: ${{ needs.get-info.outputs.app-name }}
|
|
||||||
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
|
||||||
copyright: "Copyright © 2019-2023 26F-Studio. Some Rights Reserved."
|
|
||||||
icon-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/icon.icns
|
|
||||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
|
||||||
libs-path: ./ColdClear/universal/
|
|
||||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
|
||||||
version-string: ${{ needs.get-info.outputs.version-string }}
|
|
||||||
output-folder: ${{ env.OUTPUT_FOLDER }}
|
|
||||||
account-username: ${{ secrets.APPLE_ACCOUNT_USERNAME }}
|
|
||||||
account-password: ${{ secrets.APPLE_ACCOUNT_PASSWORD }}
|
|
||||||
team-id: "${{ secrets.APPLE_DEVELOPER_TEAM_ID }}"
|
|
||||||
developer-id-application-base64: ${{ secrets.APPLE_CERT_DEVELOPER_ID_APPLICATION }}
|
|
||||||
developer-id-application-password: ${{ secrets.APPLE_CERT_DEVELOPER_ID_APPLICATION_PWD }}
|
|
||||||
developer-id-installer-base64: ${{ secrets.APPLE_CERT_DEVELOPER_ID_INSTALLER }}
|
|
||||||
developer-id-installer-password: ${{ secrets.APPLE_CERT_DEVELOPER_ID_INSTALLER_PWD }}
|
|
||||||
dmg-background-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/dmg.png
|
|
||||||
dmg-icon-position: "239 203"
|
|
||||||
dmg-icon-size: "100"
|
|
||||||
dmg-link-position: "565 203"
|
|
||||||
dmg-text-size: "12"
|
|
||||||
dmg-volume-icon-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/dmg.icns
|
|
||||||
dmg-volume-name: ${{ steps.process-app-name.outputs.product-name }}
|
|
||||||
dmg-window-position: "200 120"
|
|
||||||
dmg-window-size: "800 500"
|
|
||||||
- name: Upload pkg artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_macOS_portable_pkg
|
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.pkg
|
|
||||||
- name: Upload dmg artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_macOS_portable_dmg
|
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.dmg
|
|
||||||
- name: Upload bare artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_macOS_portable_bare
|
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.zip
|
|
||||||
- name: Prepare for release
|
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ env.RELEASE_FOLDER }}
|
|
||||||
cp ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.pkg ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_macOS_portable.pkg
|
|
||||||
cp ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.dmg ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_macOS_portable.dmg
|
|
||||||
- name: Upload release
|
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
|
||||||
uses: ncipollo/release-action@v1
|
|
||||||
with:
|
|
||||||
allowUpdates: true
|
|
||||||
artifacts: |
|
|
||||||
${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_macOS_portable.pkg
|
|
||||||
${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_macOS_portable.dmg
|
|
||||||
body: ${{ needs.get-info.outputs.update-note }}
|
|
||||||
name: ${{ needs.get-info.outputs.update-title }}
|
|
||||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
|
||||||
|
|
||||||
build-web:
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [get-info, build-core, auto-test]
|
needs: [get-info, build-core, auto-test]
|
||||||
|
env:
|
||||||
|
MEMORY_LIMIT: 128000000
|
||||||
|
OUTPUT_FOLDER: ./build
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Download core love package
|
- name: Download core love package
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
- name: Move core love package
|
- name: Build web packages
|
||||||
run: |
|
run: |
|
||||||
mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ./.github/build/web/game.data
|
npx love.js ${{ env.CORE_LOVE_PACKAGE_PATH }} ${{ env.OUTPUT_FOLDER }} -t "${{ needs.get-info.outputs.app-name }}" -m ${{ env.MEMORY_LIMIT }} -c
|
||||||
|
- name: Move assets
|
||||||
|
run: |
|
||||||
|
mv ${{ env.BUILD_ASSETS_FOLDER }}/web/${{ env.BUILD_TYPE }}/* ${{ env.OUTPUT_FOLDER }}
|
||||||
|
- name: Initialize Love.js Api Player
|
||||||
|
run: |
|
||||||
|
pushd ${{ env.OUTPUT_FOLDER }}
|
||||||
|
wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/consolewrapper.js
|
||||||
|
wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/globalizeFS.js
|
||||||
|
wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/webdb.js
|
||||||
|
node globalizeFS.js
|
||||||
|
rm globalizeFS.js
|
||||||
|
popd
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ needs.get-info.outputs.base-name }}_Web
|
||||||
|
path: ${{ env.OUTPUT_FOLDER }}
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
uses: crazy-max/ghaction-github-pages@v3
|
uses: crazy-max/ghaction-github-pages@v4
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
build_dir: ./.github/build/web/
|
build_dir: ${{ env.OUTPUT_FOLDER }}
|
||||||
keep_history: false
|
keep_history: false
|
||||||
target_branch: web-dev
|
target_branch: gh-pages
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Web_PWA
|
|
||||||
path: ./.github/build/web/
|
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
needs: [get-info, build-core, auto-test]
|
needs: [get-info, build-core, auto-test]
|
||||||
env:
|
env:
|
||||||
|
COLD_CLEAR_FOLDER: ./ColdClear
|
||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Process app name
|
- name: Process app name
|
||||||
@@ -441,20 +386,20 @@ jobs:
|
|||||||
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
|
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
|
||||||
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
||||||
- name: Download core love package
|
- name: Download core love package
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
- name: Download ColdClear
|
- name: Download ColdClear
|
||||||
uses: ./.github/actions/get-cc
|
uses: ./.github/actions/get-unzip
|
||||||
with:
|
with:
|
||||||
platform: Windows
|
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Windows.zip
|
||||||
dir: ./ColdClear
|
dir: ${{ env.COLD_CLEAR_FOLDER }}
|
||||||
- name: Update Windows template
|
- name: Update Windows template
|
||||||
shell: python3 {0}
|
shell: python3 {0}
|
||||||
run: |
|
run: |
|
||||||
version_string = "${{ needs.get-info.outputs.version-string }}"
|
version_string = "${{ needs.get-info.outputs.version-string }}"
|
||||||
file_version = (f"{version_string.replace('.', ',')},0")
|
file_version = (f"{version_string.replace('.', ',')},0")
|
||||||
with open("./.github/build/windows/${{ env.BUILD_TYPE }}/template.rc", "r+", encoding="utf8") as file:
|
with open("${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/template.rc", "r+", encoding="utf8") as file:
|
||||||
data = file.read()
|
data = file.read()
|
||||||
data = data\
|
data = data\
|
||||||
.replace("@Version", version_string)\
|
.replace("@Version", version_string)\
|
||||||
@@ -464,30 +409,30 @@ jobs:
|
|||||||
file.write(data)
|
file.write(data)
|
||||||
- name: Build Windows packages
|
- name: Build Windows packages
|
||||||
id: build-packages
|
id: build-packages
|
||||||
uses: love-actions/love-actions-windows@v1
|
uses: love-actions/love-actions-windows@v2
|
||||||
with:
|
with:
|
||||||
icon-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/icon.ico
|
icon-path: ${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/icon.ico
|
||||||
rc-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/template.rc
|
rc-path: ${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/template.rc
|
||||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
extra-assets-x86: ./ColdClear/x86/CCloader.dll ./ColdClear/x86/cold_clear.dll
|
extra-assets-x86: ${{ env.COLD_CLEAR_FOLDER }}/x86/CCloader.dll ${{ env.COLD_CLEAR_FOLDER }}/x86/cold_clear.dll ${{ env.BUILD_ASSETS_FOLDER }}/extraLibs/Windows_x64/discord-rpc.dll
|
||||||
extra-assets-x64: ./ColdClear/x64/CCloader.dll ./ColdClear/x64/cold_clear.dll
|
extra-assets-x64: ${{ env.COLD_CLEAR_FOLDER }}/x64/CCloader.dll ${{ env.COLD_CLEAR_FOLDER }}/x64/cold_clear.dll ${{ env.BUILD_ASSETS_FOLDER }}/extraLibs/Windows_x86/discord-rpc.dll
|
||||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||||
app-id: ${{ secrets.WINDOWS_APP_ID }}
|
app-id: ${{ secrets.WINDOWS_APP_ID }}
|
||||||
project-website: https://www.studio26f.org/
|
project-website: https://www.studio26f.org/
|
||||||
installer-languages: ChineseSimplified.isl ChineseTraditional.isl English.isl Spanish.isl French.isl Indonesian.isl Japanese.isl Portuguese.isl
|
installer-languages: ChineseSimplified.isl ChineseTraditional.isl English.isl Spanish.isl French.isl Indonesian.isl Japanese.isl Portuguese.isl
|
||||||
output-folder: ${{ env.OUTPUT_FOLDER }}
|
output-folder: ${{ env.OUTPUT_FOLDER }}
|
||||||
- name: Upload 32-bit artifact
|
- name: Upload 32-bit artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Windows_x86
|
name: ${{ needs.get-info.outputs.base-name }}_Windows_x86
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x86.zip
|
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x86.zip
|
||||||
- name: Upload 64-bit artifact
|
- name: Upload 64-bit artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Windows_x64
|
name: ${{ needs.get-info.outputs.base-name }}_Windows_x64
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x64.zip
|
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x64.zip
|
||||||
- name: Upload installer artifact
|
- name: Upload installer artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Windows_installer
|
name: ${{ needs.get-info.outputs.base-name }}_Windows_installer
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_installer.exe
|
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_installer.exe
|
||||||
@@ -522,38 +467,58 @@ jobs:
|
|||||||
build-core,
|
build-core,
|
||||||
build-android,
|
build-android,
|
||||||
build-linux,
|
build-linux,
|
||||||
build-macos-portable,
|
build-web-compat,
|
||||||
build-web,
|
|
||||||
build-windows,
|
build-windows,
|
||||||
]
|
]
|
||||||
env:
|
env:
|
||||||
ACTION_TYPE: ${{ fromJSON('[["Development", "Pre-release"], ["Release", "Release"]]')[startsWith(github.ref, 'refs/tags/v')][startsWith(github.ref, 'refs/tags/pre')] }}
|
ACTION_TYPE: ${{ fromJSON('[["Development", "Pre-release"], ["Release", "Release"]]')[startsWith(github.ref, 'refs/tags/v')][startsWith(github.ref, 'refs/tags/pre')] }}
|
||||||
steps:
|
steps:
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
uses: geekyeggo/delete-artifact@v2
|
uses: geekyeggo/delete-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
- name: Send Discord message
|
- name: Send Discord message
|
||||||
if: github.event_name != 'pull_request'
|
if: github.ref == 'refs/heads/main'
|
||||||
uses: Sniddl/discord-commits@v1.6
|
shell: python
|
||||||
with:
|
run: |
|
||||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
import requests
|
||||||
message: "Github Actions for **${{ github.repository }}**."
|
import json
|
||||||
embed: '{
|
|
||||||
"author":{
|
headers = {
|
||||||
"name":"${{ needs.get-info.outputs.app-name }} [${{ env.ACTION_TYPE }}]",
|
'Content-Type': 'application/json',
|
||||||
"url":"https://github.com/${{ github.repository }}"
|
}
|
||||||
},
|
payload = json.dumps({
|
||||||
"title":"${{ needs.get-info.outputs.app-name }} (${{ needs.get-info.outputs.version-name }}) Build Result",
|
"content": "Github Actions for **${{ github.repository }}**.",
|
||||||
"description": "CI triggered at ${{ needs.get-info.outputs.commit-hash }}",
|
"embeds": [
|
||||||
"url":"https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
|
{
|
||||||
"thumbnail":{
|
"author": {
|
||||||
"url":"https://raw.githubusercontent.com/${{ github.repository }}/main/.github/build/linux/${{ env.BUILD_TYPE }}/icon.png"
|
"name": "${{ needs.get-info.outputs.app-name }} [${{ env.ACTION_TYPE }}]",
|
||||||
},
|
"url": "https://github.com/${{ github.repository }}"
|
||||||
"color":36863,
|
},
|
||||||
"fields":[
|
"title": "${{ needs.get-info.outputs.app-name }} (${{ needs.get-info.outputs.version-name }}) Build Result",
|
||||||
{"name":"Version","value":"${{ needs.get-info.outputs.version-string }}","inline": true},
|
"description": "CI triggered at ${{ needs.get-info.outputs.commit-hash }}",
|
||||||
{"name":"Package Name","value":"${{ needs.get-info.outputs.base-name }}","inline": true},
|
"url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
|
||||||
{"name":"Status","value":"**Automatic Test:** ${{ needs.auto-test.result }}\n**Core:** ${{ needs.build-core.result }}\n**Android:** ${{ needs.build-android.result }}\n**Linux:** ${{ needs.build-linux.result }}\n**macOS portable:** ${{ needs.build-macos-portable.result }}\n**Windows:** ${{ needs.build-windows.result }}"}
|
"thumbnail": {
|
||||||
|
"url": "https://raw.githubusercontent.com/${{ github.repository }}/main/.github/build/linux/${{ env.BUILD_TYPE }}/icon.png"
|
||||||
|
},
|
||||||
|
"color": 36863,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "Version",
|
||||||
|
"value": "${{ needs.get-info.outputs.version-string }}",
|
||||||
|
"inline": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Package Name",
|
||||||
|
"value": "${{ needs.get-info.outputs.base-name }}",
|
||||||
|
"inline": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Status",
|
||||||
|
"value": "**Automatic Test:** ${{ needs.auto-test.result }}\n**Core:** ${{ needs.build-core.result }}\n**Android:** ${{ needs.build-android.result }}\n**Linux:** ${{ needs.build-linux.result }}\n**Web compatible:** ${{ needs.build-web-compat.result }}\n**Windows:** ${{ needs.build-windows.result }}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}'
|
})
|
||||||
|
requests.request("POST", "${{ secrets.DISCORD_WEBHOOK }}", headers=headers, data=payload)
|
||||||
|
|||||||
1
.gitignore
vendored
@@ -1,5 +1,4 @@
|
|||||||
.vscode
|
.vscode
|
||||||
libAndroid
|
|
||||||
*.ini
|
*.ini
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
103
Zframework/clipboard.lua
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
local function _sanitize(content)
|
||||||
|
if type(content)=='boolean' then
|
||||||
|
content=content and 'true' or 'false'
|
||||||
|
end
|
||||||
|
if type(content)=='nil' then
|
||||||
|
content=''
|
||||||
|
end
|
||||||
|
if type(content)=='number' then
|
||||||
|
content=tostring(content)
|
||||||
|
end
|
||||||
|
if type(content)~='string' then
|
||||||
|
MES.new('error',"Invalid content type!")
|
||||||
|
MES.traceback()
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
return content
|
||||||
|
end
|
||||||
|
|
||||||
|
if SYSTEM~='Web' then
|
||||||
|
local get=love.system.getClipboardText
|
||||||
|
local set=love.system.setClipboardText
|
||||||
|
return {
|
||||||
|
get=function() return get() or '' end,
|
||||||
|
set=function(content) set(_sanitize(content)) end,
|
||||||
|
setFreshInterval=NULL,
|
||||||
|
_update=NULL,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
if WEB_COMPAT_MODE then
|
||||||
|
local _clipboardBuffer=''
|
||||||
|
return {
|
||||||
|
get=function()
|
||||||
|
JS.newPromiseRequest(
|
||||||
|
JS.stringFunc(
|
||||||
|
[[
|
||||||
|
window.navigator.clipboard
|
||||||
|
.readText()
|
||||||
|
.then((text) => _$_(text))
|
||||||
|
.catch((e) => {
|
||||||
|
console.warn(e);
|
||||||
|
_$_('');
|
||||||
|
});
|
||||||
|
]]
|
||||||
|
),
|
||||||
|
function(data) _clipboardBuffer=data end,
|
||||||
|
function() _clipboardBuffer='' end,
|
||||||
|
3,
|
||||||
|
'getClipboardText'
|
||||||
|
)
|
||||||
|
if TASK.lock('clipboard_compat_interval',2.6) then
|
||||||
|
_clipboardBuffer=''
|
||||||
|
MES.new('warn',"Web-Compat mode, paste again to confirm",2.6)
|
||||||
|
end
|
||||||
|
return _clipboardBuffer
|
||||||
|
end,
|
||||||
|
set=function(str)
|
||||||
|
JS.callJS(JS.stringFunc(
|
||||||
|
[[
|
||||||
|
window.navigator.clipboard
|
||||||
|
.writeText('%s')
|
||||||
|
.then(() => console.log('Copied to clipboard'))
|
||||||
|
.catch((e) => console.warn(e));
|
||||||
|
]],
|
||||||
|
_sanitize(str)
|
||||||
|
))
|
||||||
|
end,
|
||||||
|
setFreshInterval=NULL,
|
||||||
|
_update=NULL,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local getCHN=love.thread.getChannel('CLIP_get')
|
||||||
|
local setCHN=love.thread.getChannel('CLIP_set')
|
||||||
|
local trigCHN=love.thread.getChannel('CLIP_trig')
|
||||||
|
|
||||||
|
local clipboard_thread=love.thread.newThread('Zframework/clipboard_thread.lua')
|
||||||
|
local isStarted,errorMessage=clipboard_thread:start()
|
||||||
|
|
||||||
|
if not isStarted then
|
||||||
|
MES.new("error",errorMessage,26)
|
||||||
|
end
|
||||||
|
|
||||||
|
local freshInterval=1
|
||||||
|
local timer=-.626
|
||||||
|
return {
|
||||||
|
get=function() return getCHN:peek() or '' end,
|
||||||
|
set=function(content) setCHN:push(_sanitize(content)) end,
|
||||||
|
setFreshInterval=function(val)
|
||||||
|
freshInterval=val
|
||||||
|
end,
|
||||||
|
_update=function(dt)
|
||||||
|
timer=timer+dt
|
||||||
|
if timer>freshInterval then
|
||||||
|
if isStarted and not clipboard_thread:isRunning() then
|
||||||
|
MES.new("warn",clipboard_thread:getError(),26)
|
||||||
|
isStarted=false
|
||||||
|
end
|
||||||
|
trigCHN:push(timer)
|
||||||
|
timer=0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
48
Zframework/clipboard_thread.lua
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
local getCHN=love.thread.getChannel('CLIP_get')
|
||||||
|
local setCHN=love.thread.getChannel('CLIP_set')
|
||||||
|
local trigCHN=love.thread.getChannel('CLIP_trig')
|
||||||
|
|
||||||
|
JS=require'Zframework.js'
|
||||||
|
local sleep=require'love.timer'.sleep
|
||||||
|
|
||||||
|
local retrieving=false
|
||||||
|
while true do
|
||||||
|
if trigCHN:getCount()>0 then
|
||||||
|
local dt=trigCHN:pop()
|
||||||
|
if setCHN:getCount()>0 then
|
||||||
|
while setCHN:getCount()>1 do setCHN:pop() end
|
||||||
|
-- Set Clipboard
|
||||||
|
JS.callJS(JS.stringFunc(
|
||||||
|
[[
|
||||||
|
window.navigator.clipboard
|
||||||
|
.writeText('%s')
|
||||||
|
.then(() => console.log('Copied to clipboard'))
|
||||||
|
.catch((e) => console.warn(e));
|
||||||
|
]],
|
||||||
|
setCHN:pop()
|
||||||
|
))
|
||||||
|
end
|
||||||
|
-- Get Clipboard
|
||||||
|
if not retrieving then
|
||||||
|
JS.newPromiseRequest(
|
||||||
|
JS.stringFunc[[
|
||||||
|
window.navigator.clipboard
|
||||||
|
.readText()
|
||||||
|
.then((text) => _$_(text))
|
||||||
|
.catch((e)=>{});
|
||||||
|
]],
|
||||||
|
function(data)
|
||||||
|
while getCHN:getCount()>0 do getCHN:pop() end
|
||||||
|
getCHN:push(data)
|
||||||
|
retrieving=false
|
||||||
|
end,
|
||||||
|
function() retrieving=false end,
|
||||||
|
1,
|
||||||
|
'getClipboardText'
|
||||||
|
)
|
||||||
|
retrieving=true
|
||||||
|
end
|
||||||
|
JS.retrieveData(dt)
|
||||||
|
end
|
||||||
|
sleep(.001)
|
||||||
|
end
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local sendCHN=love.thread.getChannel('inputChannel')
|
local sendCHN=love.thread.getChannel('HTTP_inputChannel')
|
||||||
local recvCHN=love.thread.getChannel('outputChannel')
|
local recvCHN=love.thread.getChannel('HTTP_outputChannel')
|
||||||
|
|
||||||
local threads={}
|
local threads={}
|
||||||
local threadCount=0
|
local threadCount=0
|
||||||
@@ -9,11 +9,15 @@ local threadCode=[[
|
|||||||
local http=require'socket.http'
|
local http=require'socket.http'
|
||||||
local ltn12=require'ltn12'
|
local ltn12=require'ltn12'
|
||||||
|
|
||||||
local sendCHN=love.thread.getChannel('inputChannel')
|
local sendCHN=love.thread.getChannel('HTTP_inputChannel')
|
||||||
local recvCHN=love.thread.getChannel('outputChannel')
|
local recvCHN=love.thread.getChannel('HTTP_outputChannel')
|
||||||
|
local sleep=require'love.timer'.sleep
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local arg=sendCHN:demand()
|
-- local arg=sendCHN:demand()
|
||||||
|
-- Warning: workaround for love.js
|
||||||
|
while sendCHN:getCount()==0 do sleep(.0626) end
|
||||||
|
local arg=sendCHN:pop()
|
||||||
|
|
||||||
if arg._destroy then
|
if arg._destroy then
|
||||||
recvCHN:push{
|
recvCHN:push{
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
|
-- WARNING: This framework has been remade and renamed to Zenitha. Do not use this deprecated framework for your project
|
||||||
|
|
||||||
NONE={}function NULL() end PAPER=love.graphics.newCanvas(1,1)
|
NONE={}function NULL() end PAPER=love.graphics.newCanvas(1,1)
|
||||||
EDITING=""
|
EDITING=""
|
||||||
LOADED=false
|
LOADED=false
|
||||||
|
|
||||||
|
---@type 'Windows'|'Android'|'Linux'|'iOS'|'macOS'|'Web'
|
||||||
SYSTEM=love.system.getOS()
|
SYSTEM=love.system.getOS()
|
||||||
if SYSTEM=='OS X' then SYSTEM='macOS' end
|
WEB_COMPAT_MODE=false
|
||||||
|
if SYSTEM=='OS X' then
|
||||||
|
SYSTEM='macOS'
|
||||||
|
elseif SYSTEM=='Web' then
|
||||||
|
WEB_COMPAT_MODE=not love.thread.newThread('\n'):start()
|
||||||
|
print('Web compatible mode: ', WEB_COMPAT_MODE)
|
||||||
|
end
|
||||||
|
|
||||||
-- Bit module
|
-- Bit module
|
||||||
local success
|
local success
|
||||||
@@ -70,6 +80,7 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Love-based modules (basic)
|
-- Love-based modules (basic)
|
||||||
|
CLIPBOARD= require'Zframework.clipboard'
|
||||||
HTTP= require'Zframework.http'
|
HTTP= require'Zframework.http'
|
||||||
WS= require'Zframework.websocket'
|
WS= require'Zframework.websocket'
|
||||||
FILE= require'Zframework.file'
|
FILE= require'Zframework.file'
|
||||||
@@ -92,6 +103,10 @@ IMG= require'Zframework.image'
|
|||||||
BGM= require'Zframework.bgm'
|
BGM= require'Zframework.bgm'
|
||||||
VOC= require'Zframework.voice'
|
VOC= require'Zframework.voice'
|
||||||
|
|
||||||
|
if SYSTEM=='Web' then
|
||||||
|
JS=require'Zframework.js'
|
||||||
|
end
|
||||||
|
|
||||||
local ms,kb=love.mouse,love.keyboard
|
local ms,kb=love.mouse,love.keyboard
|
||||||
local KBisDown=kb.isDown
|
local KBisDown=kb.isDown
|
||||||
|
|
||||||
@@ -172,6 +187,7 @@ local function updatePowerInfo()
|
|||||||
gc_pop()
|
gc_pop()
|
||||||
gc.setCanvas()
|
gc.setCanvas()
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------
|
-------------------------------------------------------------
|
||||||
local lastX,lastY=0,0-- Last click pos
|
local lastX,lastY=0,0-- Last click pos
|
||||||
local function _updateMousePos(x,y,dx,dy)
|
local function _updateMousePos(x,y,dx,dy)
|
||||||
@@ -421,38 +437,38 @@ local dPadToKey={
|
|||||||
start='return',
|
start='return',
|
||||||
back='escape',
|
back='escape',
|
||||||
}
|
}
|
||||||
function love.joystickadded(JS)
|
function love.joystickadded(joystick)
|
||||||
table.insert(jsState,{
|
table.insert(jsState,{
|
||||||
_id=JS:getID(),
|
_id=joystick:getID(),
|
||||||
_jsObj=JS,
|
_jsObj=joystick,
|
||||||
leftx=0,lefty=0,
|
leftx=0,lefty=0,
|
||||||
rightx=0,righty=0,
|
rightx=0,righty=0,
|
||||||
triggerleft=0,triggerright=0
|
triggerleft=0,triggerright=0
|
||||||
})
|
})
|
||||||
MES.new('info',"Joystick added")
|
MES.new('info',"Joystick added")
|
||||||
end
|
end
|
||||||
function love.joystickremoved(JS)
|
function love.joystickremoved(joystick)
|
||||||
for i=1,#jsState do
|
for i=1,#jsState do
|
||||||
if jsState[i]._jsObj==JS then
|
if jsState[i]._jsObj==joystick then
|
||||||
for j=1,#gamePadKeys do
|
for j=1,#gamePadKeys do
|
||||||
if JS:isGamepadDown(gamePadKeys[j]) then
|
if joystick:isGamepadDown(gamePadKeys[j]) then
|
||||||
love.gamepadreleased(JS,gamePadKeys[j])
|
love.gamepadreleased(joystick,gamePadKeys[j])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
love.gamepadaxis(JS,'leftx',0)
|
love.gamepadaxis(joystick,'leftx',0)
|
||||||
love.gamepadaxis(JS,'lefty',0)
|
love.gamepadaxis(joystick,'lefty',0)
|
||||||
love.gamepadaxis(JS,'rightx',0)
|
love.gamepadaxis(joystick,'rightx',0)
|
||||||
love.gamepadaxis(JS,'righty',0)
|
love.gamepadaxis(joystick,'righty',0)
|
||||||
love.gamepadaxis(JS,'triggerleft',-1)
|
love.gamepadaxis(joystick,'triggerleft',-1)
|
||||||
love.gamepadaxis(JS,'triggerright',-1)
|
love.gamepadaxis(joystick,'triggerright',-1)
|
||||||
MES.new('info',"Joystick removed")
|
MES.new('info',"Joystick removed")
|
||||||
table.remove(jsState,i)
|
table.remove(jsState,i)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function love.gamepadaxis(JS,axis,val)
|
function love.gamepadaxis(joystick,axis,val)
|
||||||
if jsState[1] and JS==jsState[1]._jsObj then
|
if jsState[1] and joystick==jsState[1]._jsObj then
|
||||||
local js=jsState[1]
|
local js=jsState[1]
|
||||||
if axis=='leftx' or axis=='lefty' or axis=='rightx' or axis=='righty' then
|
if axis=='leftx' or axis=='lefty' or axis=='rightx' or axis=='righty' then
|
||||||
local newVal=-- range: [0,1]
|
local newVal=-- range: [0,1]
|
||||||
@@ -461,14 +477,14 @@ function love.gamepadaxis(JS,axis,val)
|
|||||||
0
|
0
|
||||||
if newVal~=js[axis] then
|
if newVal~=js[axis] then
|
||||||
if js[axis]==-1 then
|
if js[axis]==-1 then
|
||||||
love.gamepadreleased(JS,jsAxisEventName[axis][1])
|
love.gamepadreleased(joystick,jsAxisEventName[axis][1])
|
||||||
elseif js[axis]~=0 then
|
elseif js[axis]~=0 then
|
||||||
love.gamepadreleased(JS,jsAxisEventName[axis][2])
|
love.gamepadreleased(joystick,jsAxisEventName[axis][2])
|
||||||
end
|
end
|
||||||
if newVal==-1 then
|
if newVal==-1 then
|
||||||
love.gamepadpressed(JS,jsAxisEventName[axis][1])
|
love.gamepadpressed(joystick,jsAxisEventName[axis][1])
|
||||||
elseif newVal==1 then
|
elseif newVal==1 then
|
||||||
love.gamepadpressed(JS,jsAxisEventName[axis][2])
|
love.gamepadpressed(joystick,jsAxisEventName[axis][2])
|
||||||
end
|
end
|
||||||
js[axis]=newVal
|
js[axis]=newVal
|
||||||
end
|
end
|
||||||
@@ -476,9 +492,9 @@ function love.gamepadaxis(JS,axis,val)
|
|||||||
local newVal=val>.3 and 1 or 0-- range: [0,1]
|
local newVal=val>.3 and 1 or 0-- range: [0,1]
|
||||||
if newVal~=js[axis] then
|
if newVal~=js[axis] then
|
||||||
if newVal==1 then
|
if newVal==1 then
|
||||||
love.gamepadpressed(JS,jsAxisEventName[axis])
|
love.gamepadpressed(joystick,jsAxisEventName[axis])
|
||||||
else
|
else
|
||||||
love.gamepadreleased(JS,jsAxisEventName[axis])
|
love.gamepadreleased(joystick,jsAxisEventName[axis])
|
||||||
end
|
end
|
||||||
js[axis]=newVal
|
js[axis]=newVal
|
||||||
end
|
end
|
||||||
@@ -718,6 +734,10 @@ function love.run()
|
|||||||
|
|
||||||
-- UPDATE
|
-- UPDATE
|
||||||
STEP()
|
STEP()
|
||||||
|
if SYSTEM == 'Web' then
|
||||||
|
JS.retrieveData(dt)
|
||||||
|
CLIPBOARD._update(dt)
|
||||||
|
end
|
||||||
if mouseShow then mouse_update(dt) end
|
if mouseShow then mouse_update(dt) end
|
||||||
if next(jsState) then gp_update(jsState[1],dt) end
|
if next(jsState) then gp_update(jsState[1],dt) end
|
||||||
VOC.update()
|
VOC.update()
|
||||||
|
|||||||
142
Zframework/js.lua
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
local __requestQueue={}
|
||||||
|
local _requestCount=0
|
||||||
|
local _Request={
|
||||||
|
command="",
|
||||||
|
currentTime=0,
|
||||||
|
timeOut=2,
|
||||||
|
id='0',
|
||||||
|
}
|
||||||
|
local __defaultErrorFunction=nil
|
||||||
|
local isDebugActive=false
|
||||||
|
|
||||||
|
local JS={}
|
||||||
|
|
||||||
|
function JS.callJS(funcToCall)
|
||||||
|
print("callJavascriptFunction "..funcToCall)
|
||||||
|
end
|
||||||
|
|
||||||
|
--You can pass a set of commands here and, it is a syntactic sugar for executing many commands inside callJS, as it only calls a function
|
||||||
|
--If you pass arguments to the func beyond the string, it will perform automatically string.format
|
||||||
|
--Return statement is possible inside this structure
|
||||||
|
--This will return a string containing a function to be called by JS.callJS
|
||||||
|
function JS.stringFunc(str,...)
|
||||||
|
str="(function(){"..str.."})()"
|
||||||
|
if (#arg>0) then
|
||||||
|
str=str:format(unpack(arg))
|
||||||
|
end
|
||||||
|
str=str:gsub("[\n\t]","")
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
||||||
|
--The call will store in the webDB the return value from the function passed it timeouts
|
||||||
|
local function retrieveJS(funcToCall,filename)
|
||||||
|
--Used for retrieveData function
|
||||||
|
JS.callJS(("FS.writeFile('%s/%s',%s);"):format(love.filesystem.getSaveDirectory(),filename,funcToCall))
|
||||||
|
end
|
||||||
|
|
||||||
|
--Call JS.newRequest instead
|
||||||
|
function _Request:new(isPromise,command,onDataLoaded,onError,timeout,id)
|
||||||
|
local obj={}
|
||||||
|
setmetatable(obj,self)
|
||||||
|
obj.command=command
|
||||||
|
obj.onError=onError or __defaultErrorFunction
|
||||||
|
if not isPromise then
|
||||||
|
retrieveJS(command,self.filename)
|
||||||
|
else
|
||||||
|
JS.callJS(command)
|
||||||
|
end
|
||||||
|
obj.onDataLoaded=onDataLoaded
|
||||||
|
obj.timeOut=(timeout==nil) and obj.timeOut or timeout
|
||||||
|
obj.id=id
|
||||||
|
obj.filename="__temp"..id
|
||||||
|
|
||||||
|
|
||||||
|
function obj:getData()
|
||||||
|
--Try to read from webdb
|
||||||
|
if love.filesystem.getInfo(self.filename) then
|
||||||
|
return love.filesystem.read(self.filename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function obj:purgeData()
|
||||||
|
--Data must be purged for not allowing old data to be retrieved
|
||||||
|
love.filesystem.remove(self.filename)
|
||||||
|
end
|
||||||
|
|
||||||
|
function obj:update(dt)
|
||||||
|
self.timeOut=self.timeOut-dt
|
||||||
|
local retData=self:getData()
|
||||||
|
|
||||||
|
if ((retData~=nil and retData~="nil") or self.timeOut<=0) then
|
||||||
|
if (retData~=nil and retData:match("ERROR")==nil) then
|
||||||
|
if isDebugActive then
|
||||||
|
print("Data has been retrieved "..retData)
|
||||||
|
end
|
||||||
|
self.onDataLoaded(retData)
|
||||||
|
else
|
||||||
|
self.onError(self.id,retData)
|
||||||
|
end
|
||||||
|
self:purgeData()
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
|
||||||
|
--Place this function on love.update and set it to return if it returns false (This API is synchronous)
|
||||||
|
function JS.retrieveData(dt)
|
||||||
|
local isRetrieving=#__requestQueue~=0
|
||||||
|
local deadRequests={}
|
||||||
|
for i=1,#__requestQueue do
|
||||||
|
local isUpdating=__requestQueue[i]:update(dt)
|
||||||
|
if not isUpdating then
|
||||||
|
table.insert(deadRequests,i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i=1,#deadRequests do
|
||||||
|
if (isDebugActive) then
|
||||||
|
print("Request died: "..deadRequests[i])
|
||||||
|
end
|
||||||
|
table.remove(__requestQueue,deadRequests[i])
|
||||||
|
end
|
||||||
|
return isRetrieving
|
||||||
|
end
|
||||||
|
|
||||||
|
--May only be used for functions that don't return a promise
|
||||||
|
function JS.newRequest(funcToCall,onDataLoaded,onError,timeout,optionalId)
|
||||||
|
table.insert(__requestQueue,_Request:new(false,funcToCall,onDataLoaded,onError,timeout or 5,optionalId or _requestCount))
|
||||||
|
end
|
||||||
|
|
||||||
|
--This function can be handled manually (in JS code)
|
||||||
|
--How to: add the function call when your events resolve: FS.writeFile("Put love.filesystem.getSaveDirectory here", "Pass a string here (NUMBER DONT WORK"))
|
||||||
|
--Or it can be handled by Lua, it auto sets your data if you write the following command:
|
||||||
|
-- _$_(yourStringOrFunctionHere)
|
||||||
|
function JS.newPromiseRequest(funcToCall,onDataLoaded,onError,timeout,optionalId)
|
||||||
|
optionalId=optionalId or _requestCount
|
||||||
|
funcToCall=funcToCall:gsub("_$_%(","FS.writeFile('"..love.filesystem.getSaveDirectory().."/__temp"..optionalId.."', ")
|
||||||
|
table.insert(__requestQueue,_Request:new(true,funcToCall,onDataLoaded,onError,timeout or 5,optionalId))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--It receives the ID from ther request
|
||||||
|
--Don't try printing the request.command, as it will execute the javascript command
|
||||||
|
function JS.setDefaultErrorFunction(func)
|
||||||
|
__defaultErrorFunction=func
|
||||||
|
end
|
||||||
|
|
||||||
|
JS.setDefaultErrorFunction(function(id,error)
|
||||||
|
if (isDebugActive) then
|
||||||
|
local msg="Data could not be loaded for id:'"..id.."'"
|
||||||
|
if (error) then
|
||||||
|
msg=msg.."\nError: "..error
|
||||||
|
end
|
||||||
|
print(msg)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
JS.callJS(JS.stringFunc("__getWebDB('%s');","__LuaJSDB"))
|
||||||
|
|
||||||
|
return JS
|
||||||
@@ -140,7 +140,7 @@ function profile.switch()
|
|||||||
switch=not switch
|
switch=not switch
|
||||||
if not switch then
|
if not switch then
|
||||||
profile.stop()
|
profile.stop()
|
||||||
love.system.setClipboardText(profile.report())
|
CLIPBOARD.set(profile.report())
|
||||||
profile.reset()
|
profile.reset()
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -125,14 +125,14 @@ function STRING.time_short(t)
|
|||||||
if t<1 then return math.floor(t*1000)..timeLetters[6] end -- 123 ms
|
if t<1 then return math.floor(t*1000)..timeLetters[6] end -- 123 ms
|
||||||
if t<MINUTE then return math.floor(t)..timeLetters[5]..' '..math.floor((t%1)*1000)..timeLetters[6] end -- 12s 345ms
|
if t<MINUTE then return math.floor(t)..timeLetters[5]..' '..math.floor((t%1)*1000)..timeLetters[6] end -- 12s 345ms
|
||||||
|
|
||||||
local timeUnits=TABLE.reverse({convertSecondsToUnits(t)})
|
local timeUnits={convertSecondsToUnits(t)}
|
||||||
|
TABLE.reverse(timeUnits)
|
||||||
|
|
||||||
-- floor seconds
|
-- floor seconds
|
||||||
timeUnits[#timeUnits]=floorint(timeUnits[#timeUnits])
|
timeUnits[#timeUnits]=floorint(timeUnits[#timeUnits])
|
||||||
|
|
||||||
local outputStr=''
|
|
||||||
for i=1,#timeUnits do
|
for i=1,#timeUnits do
|
||||||
if timeUnits>0 then
|
if timeUnits[i]>0 then
|
||||||
return timeUnits[i]..timeLetters[i]..' '..timeUnits[i+1]..timeLetters[i+1]
|
return timeUnits[i]..timeLetters[i]..' '..timeUnits[i+1]..timeLetters[i+1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -189,7 +189,7 @@ do-- functions to shorted big numbers
|
|||||||
function STRING.bigInt(t)
|
function STRING.bigInt(t)
|
||||||
if t<1000 then
|
if t<1000 then
|
||||||
return tostring(t)
|
return tostring(t)
|
||||||
elseif t~=1e999 then
|
elseif t~=1/0 then
|
||||||
local e=floorint(lg(t)/3)
|
local e=floorint(lg(t)/3)
|
||||||
return(t/10^(e*3))..units[e+1]
|
return(t/10^(e*3))..units[e+1]
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ local path=''
|
|||||||
|
|
||||||
local type=type
|
local type=type
|
||||||
local timer=love.timer.getTime
|
local timer=love.timer.getTime
|
||||||
local TRD=love.thread.newThread("\n")
|
|
||||||
local TRD_isRunning=TRD.isRunning
|
|
||||||
|
|
||||||
local WS={}
|
local WS={}
|
||||||
local wsList=setmetatable({},{
|
local wsList=setmetatable({},{
|
||||||
@@ -151,7 +149,7 @@ function WS.update(dt)
|
|||||||
local time=timer()
|
local time=timer()
|
||||||
for name,ws in next,wsList do
|
for name,ws in next,wsList do
|
||||||
if ws.real and ws.status~='dead' then
|
if ws.real and ws.status~='dead' then
|
||||||
if TRD_isRunning(ws.thread) then
|
if ws.thread:isRunning() then
|
||||||
if ws.triggerCHN:getCount()==0 then
|
if ws.triggerCHN:getCount()==0 then
|
||||||
ws.triggerCHN:push(0)
|
ws.triggerCHN:push(0)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
---@type love.Channel,love.Channel,love.Channel
|
||||||
local triggerCHN,sendCHN,readCHN=...
|
local triggerCHN,sendCHN,readCHN=...
|
||||||
|
|
||||||
local CHN_demand,CHN_getCount=triggerCHN.demand,triggerCHN.getCount
|
local CHN_demand,CHN_getCount=triggerCHN.demand,triggerCHN.getCount
|
||||||
@@ -5,16 +6,20 @@ local CHN_push,CHN_pop=triggerCHN.push,triggerCHN.pop
|
|||||||
|
|
||||||
local SOCK=require'socket'.tcp()
|
local SOCK=require'socket'.tcp()
|
||||||
local JSON=require'Zframework.json'
|
local JSON=require'Zframework.json'
|
||||||
|
local sleep=require'love.timer'.sleep
|
||||||
|
|
||||||
do-- Connect
|
do-- Connect
|
||||||
local host=CHN_demand(sendCHN)
|
-- Warning: workaround for love.js, used to use CHN_demand instead
|
||||||
local port=CHN_demand(sendCHN)
|
while CHN_getCount(sendCHN)<5 do sleep(.0626) end
|
||||||
local path=CHN_demand(sendCHN)
|
local host=CHN_pop(sendCHN)
|
||||||
local head=CHN_demand(sendCHN)
|
local port=CHN_pop(sendCHN)
|
||||||
local timeout=CHN_demand(sendCHN)
|
local path=CHN_pop(sendCHN)
|
||||||
|
local head=CHN_pop(sendCHN)
|
||||||
|
local timeout=CHN_pop(sendCHN)
|
||||||
|
|
||||||
SOCK:settimeout(timeout)
|
SOCK:settimeout(timeout)
|
||||||
local res,err=SOCK:connect(host,port)
|
local res,err=SOCK:connect(host,port)
|
||||||
|
-- print('C0',res,err)
|
||||||
assert(res,err)
|
assert(res,err)
|
||||||
|
|
||||||
-- WebSocket handshake
|
-- WebSocket handshake
|
||||||
@@ -31,6 +36,7 @@ do-- Connect
|
|||||||
|
|
||||||
-- First line of HTTP
|
-- First line of HTTP
|
||||||
res,err=SOCK:receive('*l')
|
res,err=SOCK:receive('*l')
|
||||||
|
-- print('C',res,err)
|
||||||
assert(res,err)
|
assert(res,err)
|
||||||
local code,ctLen
|
local code,ctLen
|
||||||
code=res:find(' ')
|
code=res:find(' ')
|
||||||
@@ -39,22 +45,28 @@ do-- Connect
|
|||||||
-- Get body length from headers and remove headers
|
-- Get body length from headers and remove headers
|
||||||
repeat
|
repeat
|
||||||
res,err=SOCK:receive('*l')
|
res,err=SOCK:receive('*l')
|
||||||
|
-- print('H',res,err)
|
||||||
assert(res,err)
|
assert(res,err)
|
||||||
if not ctLen and res:find('length') then
|
if not ctLen and res:find('content-length') then
|
||||||
ctLen=tonumber(res:match('%d+'))
|
ctLen=tonumber(res:match('%d+')) or 0
|
||||||
end
|
end
|
||||||
until res==''
|
until res==''
|
||||||
|
|
||||||
-- Result
|
-- Result
|
||||||
|
if code=='101' then
|
||||||
|
CHN_push(readCHN,'success')
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Content(?)
|
||||||
if ctLen then
|
if ctLen then
|
||||||
if code=='101' then
|
res,err=SOCK:receive(ctLen)
|
||||||
CHN_push(readCHN,'success')
|
-- print('R',res,err)
|
||||||
else
|
if code~='101' then
|
||||||
res,err=SOCK:receive(ctLen)
|
|
||||||
res=JSON.decode(assert(res,err))
|
res=JSON.decode(assert(res,err))
|
||||||
error((code or "XXX")..":"..(res and res.reason or "Server Error"))
|
error((code or "XXX")..":"..(res and res.reason or "Server Error"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
SOCK:settimeout(0)
|
SOCK:settimeout(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -136,10 +148,10 @@ local readThread=coroutine.wrap(function()
|
|||||||
assert(res,err)
|
assert(res,err)
|
||||||
length=shl(byte(res,1),8)+byte(res,2)
|
length=shl(byte(res,1),8)+byte(res,2)
|
||||||
elseif length==127 then
|
elseif length==127 then
|
||||||
local lenData
|
-- 'res' is 'lenData' here
|
||||||
lenData,err=_receive(SOCK,8)
|
res,err=_receive(SOCK,8)
|
||||||
assert(res,err)
|
assert(res,err)
|
||||||
local _,_,_,_,_5,_6,_7,_8=byte(lenData,1,8)
|
local _,_,_,_,_5,_6,_7,_8=byte(res,1,8)
|
||||||
length=shl(_5,24)+shl(_6,16)+shl(_7,8)+_8
|
length=shl(_5,24)+shl(_6,16)+shl(_7,8)+_8
|
||||||
end
|
end
|
||||||
res,err=_receive(SOCK,length)
|
res,err=_receive(SOCK,length)
|
||||||
@@ -158,12 +170,14 @@ local readThread=coroutine.wrap(function()
|
|||||||
lBuffer=lBuffer..res
|
lBuffer=lBuffer..res
|
||||||
if fin then
|
if fin then
|
||||||
CHN_push(readCHN,lBuffer)
|
CHN_push(readCHN,lBuffer)
|
||||||
|
-- print('M',lBuffer)
|
||||||
lBuffer=""
|
lBuffer=""
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
CHN_push(readCHN,op)
|
CHN_push(readCHN,op)
|
||||||
if fin then
|
if fin then
|
||||||
CHN_push(readCHN,res)
|
CHN_push(readCHN,res)
|
||||||
|
-- print('S',res)
|
||||||
lBuffer=""
|
lBuffer=""
|
||||||
else
|
else
|
||||||
lBuffer=res
|
lBuffer=res
|
||||||
@@ -176,7 +190,8 @@ end)
|
|||||||
local success,err
|
local success,err
|
||||||
|
|
||||||
while true do-- Running
|
while true do-- Running
|
||||||
CHN_demand(triggerCHN)
|
while CHN_getCount(triggerCHN)==0 do sleep(.0626) end
|
||||||
|
CHN_pop(triggerCHN)
|
||||||
success,err=pcall(sendThread)
|
success,err=pcall(sendThread)
|
||||||
if not success or err then break end
|
if not success or err then break end
|
||||||
success,err=pcall(readThread)
|
success,err=pcall(readThread)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ local timer=love.timer.getTime
|
|||||||
local next=next
|
local next=next
|
||||||
local floor,ceil=math.floor,math.ceil
|
local floor,ceil=math.floor,math.ceil
|
||||||
local max,min=math.max,math.min
|
local max,min=math.max,math.min
|
||||||
|
local match=string.match
|
||||||
local sub,ins,rem=string.sub,table.insert,table.remove
|
local sub,ins,rem=string.sub,table.insert,table.remove
|
||||||
local xOy=SCR.xOy
|
local xOy=SCR.xOy
|
||||||
local FONT=FONT
|
local FONT=FONT
|
||||||
@@ -142,13 +143,21 @@ local button={
|
|||||||
type='button',
|
type='button',
|
||||||
mustHaveText=true,
|
mustHaveText=true,
|
||||||
ATV=0,-- Activating time(0~8)
|
ATV=0,-- Activating time(0~8)
|
||||||
|
textAlreadyWrapped=false,-- Text already wrapped? (Managed by :setObject, can be override, this will be true if obj has a '\n')
|
||||||
}
|
}
|
||||||
function button:reset()
|
function button:reset()
|
||||||
self.ATV=0
|
self.ATV=0
|
||||||
end
|
end
|
||||||
function button:setObject(obj)
|
function button:setObject(obj)
|
||||||
if type(obj)=='string' or type(obj)=='number' then
|
if type(obj)=='string' or type(obj)=='number' then
|
||||||
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
|
if match(obj,"\n") then
|
||||||
|
self.textAlreadyWrapped=true
|
||||||
|
self.obj=gc.newText(FONT.get(self.font,self.fType))
|
||||||
|
self.obj:addf(obj,self.w-self.edge*2,(self.align=='L' and 'left') or (self.align=='R' and 'right') or 'center')
|
||||||
|
else
|
||||||
|
self.textAlreadyWrapped=false
|
||||||
|
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
|
||||||
|
end
|
||||||
elseif obj then
|
elseif obj then
|
||||||
self.obj=obj
|
self.obj=obj
|
||||||
end
|
end
|
||||||
@@ -194,16 +203,7 @@ function button:draw()
|
|||||||
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
||||||
local y0=y+h*.5
|
local y0=y+h*.5
|
||||||
gc_setColor(1,1,1,.2+ATV*.05)
|
gc_setColor(1,1,1,.2+ATV*.05)
|
||||||
if self.align=='M' then
|
if self.align=='L' or self.textAlreadyWrapped then
|
||||||
local x0=x+w*.5
|
|
||||||
local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
|
|
||||||
gc_draw(obj,x0-1,y0-1,nil,kx,1,ox,oy)
|
|
||||||
gc_draw(obj,x0-1,y0+1,nil,kx,1,ox,oy)
|
|
||||||
gc_draw(obj,x0+1,y0-1,nil,kx,1,ox,oy)
|
|
||||||
gc_draw(obj,x0+1,y0+1,nil,kx,1,ox,oy)
|
|
||||||
gc_setColor(r*.55,g*.55,b*.55)
|
|
||||||
gc_draw(obj,x0,y0,nil,kx,1,ox,oy)
|
|
||||||
elseif self.align=='L' then
|
|
||||||
local edge=self.edge
|
local edge=self.edge
|
||||||
gc_draw(obj,x+edge-1,y0-1-oy)
|
gc_draw(obj,x+edge-1,y0-1-oy)
|
||||||
gc_draw(obj,x+edge-1,y0+1-oy)
|
gc_draw(obj,x+edge-1,y0+1-oy)
|
||||||
@@ -219,6 +219,15 @@ function button:draw()
|
|||||||
gc_draw(obj,x0+1,y0+1-oy)
|
gc_draw(obj,x0+1,y0+1-oy)
|
||||||
gc_setColor(r*.55,g*.55,b*.55)
|
gc_setColor(r*.55,g*.55,b*.55)
|
||||||
gc_draw(obj,x0,y0-oy)
|
gc_draw(obj,x0,y0-oy)
|
||||||
|
else--if self.align=='M' then
|
||||||
|
local x0=x+w*.5
|
||||||
|
local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
|
||||||
|
gc_draw(obj,x0-1,y0-1,nil,kx,1,ox,oy)
|
||||||
|
gc_draw(obj,x0-1,y0+1,nil,kx,1,ox,oy)
|
||||||
|
gc_draw(obj,x0+1,y0-1,nil,kx,1,ox,oy)
|
||||||
|
gc_draw(obj,x0+1,y0+1,nil,kx,1,ox,oy)
|
||||||
|
gc_setColor(r*.55,g*.55,b*.55)
|
||||||
|
gc_draw(obj,x0,y0,nil,kx,1,ox,oy)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function button:getInfo()
|
function button:getInfo()
|
||||||
@@ -290,13 +299,21 @@ local key={
|
|||||||
type='key',
|
type='key',
|
||||||
mustHaveText=true,
|
mustHaveText=true,
|
||||||
ATV=0,-- Activating time(0~4)
|
ATV=0,-- Activating time(0~4)
|
||||||
|
textAlreadyWrapped=false,---See button.setObject (line 146)
|
||||||
}
|
}
|
||||||
function key:reset()
|
function key:reset()
|
||||||
self.ATV=0
|
self.ATV=0
|
||||||
end
|
end
|
||||||
function key:setObject(obj)
|
function key:setObject(obj)
|
||||||
if type(obj)=='string' or type(obj)=='number' then
|
if type(obj)=='string' or type(obj)=='number' then
|
||||||
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
|
if match(obj,"\n") then
|
||||||
|
self.textAlreadyWrapped=true
|
||||||
|
self.obj=gc.newText(FONT.get(self.font,self.fType))
|
||||||
|
self.obj:addf(obj,self.w-self.edge*2,(self.align=='L' and 'left') or (self.align=='R' and 'right') or 'center')
|
||||||
|
else
|
||||||
|
self.textAlreadyWrapped=false
|
||||||
|
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
|
||||||
|
end
|
||||||
elseif obj then
|
elseif obj then
|
||||||
self.obj=obj
|
self.obj=obj
|
||||||
end
|
end
|
||||||
@@ -354,14 +371,15 @@ function key:draw()
|
|||||||
-- Drawable
|
-- Drawable
|
||||||
local obj=self.obj
|
local obj=self.obj
|
||||||
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
||||||
|
|
||||||
gc_setColor(r,g,b)
|
gc_setColor(r,g,b)
|
||||||
if align=='M' then
|
if align=='L' or self.textAlreadyWrapped then
|
||||||
local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
|
gc_draw(obj,x+self.edge,y+h*.5-oy)
|
||||||
gc_draw(obj,x+w*.5,y+h*.5,nil,kx,1,ox,oy)
|
|
||||||
elseif align=='L' then
|
|
||||||
gc_draw(obj,x+self.edge,y-oy+h*.5)
|
|
||||||
elseif align=='R' then
|
elseif align=='R' then
|
||||||
gc_draw(obj,x+w-self.edge-ox*2,y-oy+h*.5)
|
gc_draw(obj,x+w-self.edge-ox*2,y-oy+h*.5)
|
||||||
|
else--if align=='M' then
|
||||||
|
local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
|
||||||
|
gc_draw(obj,x+w*.5,y+h*.5,nil,kx,1,ox,oy)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function key:getInfo()
|
function key:getInfo()
|
||||||
@@ -1382,10 +1400,13 @@ function WIDGET.setLang(widgetText)
|
|||||||
t=W.name or "##"
|
t=W.name or "##"
|
||||||
W.color=COLOR.dV
|
W.color=COLOR.dV
|
||||||
end
|
end
|
||||||
if type(t)=='string' and W.font then
|
if type(W.setObject)=='function' then
|
||||||
t=gc.newText(FONT.get(W.font),t)
|
W:setObject(t)
|
||||||
|
elseif type(t)=='string' and W.font then
|
||||||
|
W.obj=gc.newText(FONT.get(W.font or 30),t)
|
||||||
|
else
|
||||||
|
W.obj=t
|
||||||
end
|
end
|
||||||
W.obj=t
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
13
conf.lua
@@ -1,9 +1,9 @@
|
|||||||
local OS=love._os
|
local system=love._os
|
||||||
if OS=='OS X' then OS='macOS' end
|
if system=='OS X' then system='macOS' end
|
||||||
MOBILE=OS=='Android' or OS=='iOS'
|
MOBILE=system=='Android' or system=='iOS'
|
||||||
FNNS=OS:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol
|
FNNS=system:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol
|
||||||
|
|
||||||
if OS=='Web' then
|
if system=='Web' then
|
||||||
local oldRead=love.filesystem.read
|
local oldRead=love.filesystem.read
|
||||||
function love.filesystem.read(name,size)
|
function love.filesystem.read(name,size)
|
||||||
if love.filesystem.getInfo(name) then
|
if love.filesystem.getInfo(name) then
|
||||||
@@ -23,12 +23,13 @@ function love.conf(t)
|
|||||||
local fileData=fs.read('conf/settings')
|
local fileData=fs.read('conf/settings')
|
||||||
if fileData then
|
if fileData then
|
||||||
msaa=tonumber(fileData:match('"msaa":(%d+)')) or 0;
|
msaa=tonumber(fileData:match('"msaa":(%d+)')) or 0;
|
||||||
|
msaa=msaa==0 and 0 or 2*msaa
|
||||||
portrait=MOBILE and fileData:find('"portrait":true') and true
|
portrait=MOBILE and fileData:find('"portrait":true') and true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
t.identity=identity -- Saving folder
|
t.identity=identity -- Saving folder
|
||||||
t.version="11.4"
|
t.version="11.5"
|
||||||
t.gammacorrect=false
|
t.gammacorrect=false
|
||||||
t.appendidentity=true -- Search files in source then in save directory
|
t.appendidentity=true -- Search files in source then in save directory
|
||||||
t.accelerometerjoystick=false -- Accelerometer=joystick on ios/android
|
t.accelerometerjoystick=false -- Accelerometer=joystick on ios/android
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ Lua is free software distributed under the terms of the MIT license. Copyright
|
|||||||
|
|
||||||
json.lua is copyrighted by rxi. © 2022 rxi.
|
json.lua is copyrighted by rxi. © 2022 rxi.
|
||||||
|
|
||||||
|
discord-rpc.dll is copyrighted by Discord, Inc. © 2017 Discord, Inc.
|
||||||
|
|
||||||
IBM Plex is copyrighted by the International Business Machines Corporation. IBM and IBM Plex are trademarks of IBM Corp, registered in many jurisdictions worldwide. IBM Plex is licensed under the SIL Open Font License, Version 1.1.
|
IBM Plex is copyrighted by the International Business Machines Corporation. IBM and IBM Plex are trademarks of IBM Corp, registered in many jurisdictions worldwide. IBM Plex is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
101
main.lua
@@ -23,7 +23,7 @@ TIME=love.timer.getTime
|
|||||||
|
|
||||||
-- Global Vars & Settings
|
-- Global Vars & Settings
|
||||||
SFXPACKS={'chiptune'}
|
SFXPACKS={'chiptune'}
|
||||||
VOCPACKS={'miya','mono','xiaoya','flore','miku','zundamon'}
|
VOCPACKS={'miya','mono','xiaoya','flore','neuro','miku','zundamon'}
|
||||||
FIRSTLAUNCH=false
|
FIRSTLAUNCH=false
|
||||||
DAILYLAUNCH=false
|
DAILYLAUNCH=false
|
||||||
|
|
||||||
@@ -49,6 +49,10 @@ SCR.setSize(1280,720) -- Initialize Screen size
|
|||||||
BGM.setMaxSources(5)
|
BGM.setMaxSources(5)
|
||||||
VOC.setDiversion(.62)
|
VOC.setDiversion(.62)
|
||||||
|
|
||||||
|
if SYSTEM == 'Web' and not WEB_COMPAT_MODE then
|
||||||
|
CLIPBOARD.setFreshInterval(.5)
|
||||||
|
end
|
||||||
|
|
||||||
WIDGET.setOnChange(function()
|
WIDGET.setOnChange(function()
|
||||||
if SCN.cur=='net_game' or SCN.cur=='custom_field' then return end
|
if SCN.cur=='net_game' or SCN.cur=='custom_field' then return end
|
||||||
local colorList=THEME.getThemeColor()
|
local colorList=THEME.getThemeColor()
|
||||||
@@ -271,6 +275,7 @@ IMG.init{
|
|||||||
floreCH='media/image/characters/flore.png',
|
floreCH='media/image/characters/flore.png',
|
||||||
mikuCH='media/image/characters/miku.png',
|
mikuCH='media/image/characters/miku.png',
|
||||||
zundamonCH='media/image/characters/zundamon.png',
|
zundamonCH='media/image/characters/zundamon.png',
|
||||||
|
neuroCH='media/image/characters/neuro.png',
|
||||||
z={
|
z={
|
||||||
character='media/image/characters/z_character.png',
|
character='media/image/characters/z_character.png',
|
||||||
screen1='media/image/characters/z_screen1.png',
|
screen1='media/image/characters/z_screen1.png',
|
||||||
@@ -293,39 +298,41 @@ IMG.init{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
SKIN.load{
|
SKIN.load{
|
||||||
{name="crystal_scf", path='media/image/skin/crystal_scf.png'},
|
{name="Crystal (Scf)", path='media/image/skin/scf/crystal.png'},
|
||||||
{name="matte_mrz", path='media/image/skin/matte_mrz.png'},
|
{name="Smooth (MrZ)", path='media/image/skin/mrz/smooth.png'},
|
||||||
{name="shiny_chno", path='media/image/skin/shiny_chno.png'},
|
{name="Matte (MrZ)", path='media/image/skin/mrz/matte.png'},
|
||||||
{name="contrast_mrz", path='media/image/skin/contrast_mrz.png'},
|
{name="Glass (Scf)", path='media/image/skin/scf/glass.png'},
|
||||||
{name="polkadots_scf", path='media/image/skin/polkadots_scf.png'},
|
{name="Jelly (Miya)", path='media/image/skin/miya/jelly.png'},
|
||||||
{name="toy_scf", path='media/image/skin/toy_scf.png'},
|
{name="Simple (Scf)", path='media/image/skin/scf/simple.png'},
|
||||||
{name="smooth_mrz", path='media/image/skin/smooth_mrz.png'},
|
{name="Contrast (MrZ)", path='media/image/skin/mrz/contrast.png'},
|
||||||
{name="simple_scf", path='media/image/skin/simple_scf.png'},
|
{name="Plastic (MrZ)", path='media/image/skin/mrz/plastic.png'},
|
||||||
{name="glass_scf", path='media/image/skin/glass_scf.png'},
|
{name="Glow (MrZ)", path='media/image/skin/mrz/glow.png'},
|
||||||
{name="penta_scf", path='media/image/skin/penta_scf.png'},
|
{name="Bright (Scf)", path='media/image/skin/scf/bright.png'},
|
||||||
{name="bubble_scf", path='media/image/skin/bubble_scf.png'},
|
{name="Penta (Scf)", path='media/image/skin/scf/penta.png'},
|
||||||
{name="minoes_scf", path='media/image/skin/minoes_scf.png'},
|
{name="Bubble (Scf)", path='media/image/skin/scf/bubble.png'},
|
||||||
{name="pure_mrz", path='media/image/skin/pure_mrz.png'},
|
{name="Pure (MrZ)", path='media/image/skin/mrz/pure.png'},
|
||||||
{name="bright_scf", path='media/image/skin/bright_scf.png'},
|
{name="Letters (CHNO)", path='media/image/skin/chno/letters.png'},
|
||||||
{name="glow_mrz", path='media/image/skin/glow_mrz.png'},
|
{name="Kanji (CHNO)", path='media/image/skin/chno/kanji.png'},
|
||||||
{name="plastic_mrz", path='media/image/skin/plastic_mrz.png'},
|
{name="Pastel (CHNO)", path='media/image/skin/chno/pastel.png'},
|
||||||
{name="paper_mrz", path='media/image/skin/paper_mrz.png'},
|
{name="Classic", path='media/image/skin/unknown/classic.png'},
|
||||||
{name="yinyang_scf", path='media/image/skin/yinyang_scf.png'},
|
{name="Arcade (Asriel)", path='media/image/skin/asriel/arcade.png'},
|
||||||
{name="cartooncup_earety", path='media/image/skin/cartooncup_earety.png'},
|
{name="Shiny (CHNO)", path='media/image/skin/chno/shiny.png'},
|
||||||
{name="jelly_miya", path='media/image/skin/jelly_miya.png'},
|
{name="Brick (Notypey)", path='media/image/skin/notypey/brick.png'},
|
||||||
{name="guidetris_xmiao_lusisi",path='media/image/skin/guidetris_xmiao_lusisi.png'},
|
{name="Cartooncup (Earety)", path='media/image/skin/earety/cartooncup.png'},
|
||||||
{name="brick_notypey", path='media/image/skin/brick_notypey.png'},
|
{name="Paper (MrZ)", path='media/image/skin/mrz/paper.png'},
|
||||||
{name="gem_notypey", path='media/image/skin/gem_notypey.png'},
|
{name="Toy (Scf)", path='media/image/skin/scf/toy.png'},
|
||||||
{name="classic", path='media/image/skin/classic_unknown.png'},
|
{name="Polkadots (Scf)", path='media/image/skin/scf/polkadots.png'},
|
||||||
{name="ball_shaw", path='media/image/skin/ball_shaw.png'},
|
{name="Yinyang (Scf)", path='media/image/skin/scf/yinyang.png'},
|
||||||
{name="retro_notypey", path='media/image/skin/retro_notypey.png'},
|
{name="Minoes (Scf)", path='media/image/skin/scf/minoes.png'},
|
||||||
{name="pixel_chno", path='media/image/skin/pixel_chno.png'},
|
{name="Cardboard (Asriel, slimenergy)", path='media/image/skin/asriel/cardboard.png'},
|
||||||
{name="pastel_chno", path='media/image/skin/pastel_chno.png'},
|
{name="Ball (Shaw)", path='media/image/skin/shaw/ball.png'},
|
||||||
{name="letters_chno", path='media/image/skin/letters_chno.png'},
|
{name="Gem (Notypey)", path='media/image/skin/notypey/gem.png'},
|
||||||
{name="kanji_chno", path='media/image/skin/kanji_chno.png'},
|
{name="Pixel (CHNO)", path='media/image/skin/chno/pixel.png'},
|
||||||
{name="textbone_mrz", path='media/image/skin/textbone_mrz.png'},
|
{name="Retro (Notypey)", path='media/image/skin/notypey/retro.png'},
|
||||||
{name="coloredbone_mrz", path='media/image/skin/coloredbone_mrz.png'},
|
{name="Guidetris (xmiao, lusisi)", path='media/image/skin/guidetris_xmiao_lusisi.png'},
|
||||||
{name="wtf", path='media/image/skin/wtf_mrz.png'},
|
{name="Textbone (MrZ)", path='media/image/skin/mrz/textbone.png'},
|
||||||
|
{name="Coloredbone (MrZ)", path='media/image/skin/mrz/coloredbone.png'},
|
||||||
|
{name="WTF (MrZ)", path='media/image/skin/mrz/wtf.png'},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Initialize sound libs
|
-- Initialize sound libs
|
||||||
@@ -397,8 +404,12 @@ do
|
|||||||
RANKS.rhythm_h=nil; fs.remove('record/rhythm_h.rec')
|
RANKS.rhythm_h=nil; fs.remove('record/rhythm_h.rec')
|
||||||
RANKS.rhythm_u=nil; fs.remove('record/rhythm_u.rec')
|
RANKS.rhythm_u=nil; fs.remove('record/rhythm_u.rec')
|
||||||
end
|
end
|
||||||
if RANKS.bigbang then fs.remove('record/bigbang.rec') end
|
if RANKS.bigbang then RANKS.bigbang=nil; fs.remove('record/bigbang.rec') end
|
||||||
if RANKS.clearRush then fs.remove('record/clearRush.rec') end
|
if RANKS.clearRush then RANKS.clearRush=nil; fs.remove('record/clearRush.rec') end
|
||||||
|
if RANKS.strategy_e then RANKS.strategy_e=nil; fs.remove('record/strategy_e.rec') end
|
||||||
|
if RANKS.strategy_h_plus then RANKS.strategy_h_plus=nil; fs.remove('record/strategy_h_plus.rec') end
|
||||||
|
if RANKS.strategy_u_plus then RANKS.strategy_u_plus=nil; fs.remove('record/strategy_u_plus.rec') end
|
||||||
|
|
||||||
if STAT.version<1715 then fs.remove('record/dig_quad_10l.rec') end
|
if STAT.version<1715 then fs.remove('record/dig_quad_10l.rec') end
|
||||||
|
|
||||||
if STAT.version~=VERSION.code then
|
if STAT.version~=VERSION.code then
|
||||||
@@ -424,7 +435,8 @@ do
|
|||||||
for _,v in next,SETTING.skin do if v<1 or v>17 then v=17 end end
|
for _,v in next,SETTING.skin do if v<1 or v>17 then v=17 end end
|
||||||
if not RSlist[SETTING.RS] then SETTING.RS='TRS' end
|
if not RSlist[SETTING.RS] then SETTING.RS='TRS' end
|
||||||
if SETTING.ghostType=='greyCell' then SETTING.ghostType='grayCell' end
|
if SETTING.ghostType=='greyCell' then SETTING.ghostType='grayCell' end
|
||||||
if type(SETTING.skinSet)=='number' then SETTING.skinSet='crystal_scf' end
|
if type(SETTING.skinSet)=='number' then SETTING.skinSet='Crystal (Scf)' end
|
||||||
|
if string.find(SETTING.skinSet,"_") then SETTING.skinSet='Crystal (Scf)' end
|
||||||
if not TABLE.find({8,10,13,17,22,29,37,47,62,80,100},SETTING.frameMul) then SETTING.frameMul=100 end
|
if not TABLE.find({8,10,13,17,22,29,37,47,62,80,100},SETTING.frameMul) then SETTING.frameMul=100 end
|
||||||
if SETTING.cv then SETTING.vocPack,SETTING.cv=SETTING.cv end
|
if SETTING.cv then SETTING.vocPack,SETTING.cv=SETTING.cv end
|
||||||
if type(SETTING.bg)~='string' then SETTING.bg='on' end
|
if type(SETTING.bg)~='string' then SETTING.bg='on' end
|
||||||
@@ -432,6 +444,7 @@ do
|
|||||||
if SETTING.reTime>3 or SETTING.reTime<.5 then SETTING.reTime=2 end
|
if SETTING.reTime>3 or SETTING.reTime<.5 then SETTING.reTime=2 end
|
||||||
if SETTING.locale=='zh_full' then SETTING.locale='zh' end
|
if SETTING.locale=='zh_full' then SETTING.locale='zh' end
|
||||||
if SETTING.vocPack=='rin' then SETTING.vocPack='miku' end
|
if SETTING.vocPack=='rin' then SETTING.vocPack='miku' end
|
||||||
|
if SETTING.msaa>4 then SETTING.msaa=4 end
|
||||||
if RANKS.infinite then RANKS.infinite=0 end
|
if RANKS.infinite then RANKS.infinite=0 end
|
||||||
if RANKS.infinite_dig then RANKS.infinite_dig=0 end
|
if RANKS.infinite_dig then RANKS.infinite_dig=0 end
|
||||||
if not RANKS.sprint_10l then RANKS.sprint_10l=0 end
|
if not RANKS.sprint_10l then RANKS.sprint_10l=0 end
|
||||||
@@ -590,18 +603,22 @@ for _,fileName in next,fs.getDirectoryItems('replay') do
|
|||||||
end
|
end
|
||||||
table.sort(REPLAY,function(a,b) return a.fileName>b.fileName end)
|
table.sort(REPLAY,function(a,b) return a.fileName>b.fileName end)
|
||||||
|
|
||||||
AUTHURL="https://studio26f.org/oauth?product=techmino"
|
AUTHURL="https://www.studio26f.org/oauth?product=techmino"
|
||||||
AUTHHOST="cafuuchino1.3322.org:8081"
|
AUTHHOST="www.studio26f.org:8080"
|
||||||
WS.switchHost('cafuuchino1.3322.org','10026','/techmino/ws/v1')
|
WS.switchHost('www.studio26f.org','8081','/techmino/ws/v1')
|
||||||
HTTP.setHost("cafuuchino1.3322.org:10026")
|
HTTP.setHost("www.studio26f.org:8081")
|
||||||
HTTP.setThreadCount(1)
|
HTTP.setThreadCount(1)
|
||||||
|
|
||||||
|
-- Discord RPC
|
||||||
|
DiscordRPC=require'parts.discordRPC'
|
||||||
|
DiscordRPC.update()
|
||||||
|
|
||||||
table.insert(_LOADTIMELIST_,("Load Resources: %.3fs"):format(TIME()-_LOADTIME_))
|
table.insert(_LOADTIMELIST_,("Load Resources: %.3fs"):format(TIME()-_LOADTIME_))
|
||||||
|
|
||||||
for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i]) end
|
for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i]) end
|
||||||
|
|
||||||
-- Launch testing task if launch param received
|
-- Launch testing task if launch param received
|
||||||
if TABLE.find(arg,'-- test') then
|
if TABLE.find(arg,'--test') then
|
||||||
TASK.new(function()
|
TASK.new(function()
|
||||||
while not LOADED do coroutine.yield() end
|
while not LOADED do coroutine.yield() end
|
||||||
|
|
||||||
|
|||||||
BIN
media/image/characters/neuro.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
media/image/skin/asriel/arcade.png
Executable file
|
After Width: | Height: | Size: 20 KiB |
BIN
media/image/skin/asriel/cardboard.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 613 B After Width: | Height: | Size: 613 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 91 B After Width: | Height: | Size: 91 B |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 837 B After Width: | Height: | Size: 837 B |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |