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 name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, minimum-scale=1, maximum-scale=1">
|
||||
<title>Techmino</title>
|
||||
|
||||
<!-- Load custom style sheet -->
|
||||
<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>
|
||||
@@ -61,7 +62,7 @@
|
||||
|
||||
var Module = {
|
||||
arguments: ["./game.love"],
|
||||
INITIAL_MEMORY: 536870912,
|
||||
INITIAL_MEMORY: 128000000,
|
||||
printErr: console.error.bind(console),
|
||||
canvas: (function() {
|
||||
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]
|
||||
|
||||
env:
|
||||
BUILD_ASSETS_FOLDER: ./.github/build
|
||||
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_PACKAGE_PATH: ./core.love
|
||||
|
||||
jobs:
|
||||
get-info:
|
||||
@@ -25,7 +27,7 @@ jobs:
|
||||
commit-hash: ${{ steps.git-info.outputs.commit-hash }}
|
||||
base-name: ${{ steps.assemble-base-name.outputs.base-name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install lua
|
||||
run: |
|
||||
sudo apt-get install lua5.3 -y
|
||||
@@ -73,7 +75,7 @@ jobs:
|
||||
OUTPUT_FOLDER: ./build
|
||||
RELEASE_FOLDER: ./release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Process app name
|
||||
@@ -95,13 +97,13 @@ jobs:
|
||||
build-list: ./media/ ./parts/ ./Zframework/ ./conf.lua ./main.lua ./version.lua ./legals.md ./license.txt
|
||||
package-path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||
- name: Upload core love package
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||
path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||
- name: Add icon to love package
|
||||
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
|
||||
rm media/image/icon.png
|
||||
- name: Rename love package
|
||||
@@ -109,7 +111,7 @@ jobs:
|
||||
mkdir -p ${{ env.OUTPUT_FOLDER }}
|
||||
mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ needs.get-info.outputs.base-name }}_Core_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') }}
|
||||
|
||||
auto-test:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build-core
|
||||
env:
|
||||
APPIMAGE_PATH: ./love.AppImage
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Love actions for testing
|
||||
@@ -141,16 +145,35 @@ jobs:
|
||||
with:
|
||||
font-path: ./parts/fonts/proportional.otf
|
||||
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:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [get-info, build-core, auto-test]
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
COLD_CLEAR_FOLDER: ./libAndroid
|
||||
OUTPUT_FOLDER: ./build
|
||||
RELEASE_FOLDER: ./release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Process app name
|
||||
@@ -159,6 +182,7 @@ jobs:
|
||||
run: |
|
||||
import os
|
||||
import re
|
||||
|
||||
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
|
||||
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')
|
||||
@@ -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('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
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||
- name: Download ColdClear
|
||||
uses: ./.github/actions/get-cc
|
||||
uses: ./.github/actions/get-unzip
|
||||
with:
|
||||
platform: Android
|
||||
dir: ./libAndroid
|
||||
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Android.zip
|
||||
dir: ${{ env.COLD_CLEAR_FOLDER }}
|
||||
- name: Build Android packages
|
||||
id: build-packages
|
||||
uses: love-actions/love-actions-android@main
|
||||
uses: love-actions/love-actions-android@v2
|
||||
with:
|
||||
app-name: ${{ needs.get-info.outputs.app-name }}
|
||||
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
||||
@@ -187,15 +211,15 @@ jobs:
|
||||
keystore-key-password: ${{ secrets.ANDROID_KEYSTORE_KEYPASSWORD }}
|
||||
keystore-store-password: ${{ secrets.ANDROID_KEYSTORE_STOREPASSWORD }}
|
||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||
resource-path: ./.github/build/android/${{ env.BUILD_TYPE }}/res
|
||||
extra-assets: ./libAndroid/
|
||||
resource-path: ${{ env.BUILD_ASSETS_FOLDER }}/android/${{ env.BUILD_TYPE }}/res
|
||||
extra-assets: ${{ env.COLD_CLEAR_FOLDER }}
|
||||
custom-scheme: studio26f://oauth
|
||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||
version-string: ${{ needs.get-info.outputs.version-string }}
|
||||
version-code: ${{ needs.get-info.outputs.version-code }}
|
||||
output-folder: ${{ env.OUTPUT_FOLDER }}
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ needs.get-info.outputs.base-name }}_Android_release
|
||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}-release.apk
|
||||
@@ -219,10 +243,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [get-info, build-core, auto-test]
|
||||
env:
|
||||
COLD_CLEAR_FOLDER: ./ColdClear
|
||||
OUTPUT_FOLDER: ./build
|
||||
RELEASE_FOLDER: ./release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Process app name
|
||||
@@ -237,45 +262,45 @@ jobs:
|
||||
f.write('bundle-id=org.26f-studio.' + product_name + '\n')
|
||||
f.write('product-name=' + product_name + '\n')
|
||||
- name: Download core love package
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||
- name: Add icon to love package
|
||||
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
|
||||
rm media/image/icon.png
|
||||
- name: Download ColdClear
|
||||
uses: ./.github/actions/get-cc
|
||||
uses: ./.github/actions/get-unzip
|
||||
with:
|
||||
platform: Linux
|
||||
dir: ./ColdClear
|
||||
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Linux.zip
|
||||
dir: ${{ env.COLD_CLEAR_FOLDER }}
|
||||
- name: Process ColdClear
|
||||
shell: bash
|
||||
run: |
|
||||
cd ./ColdClear
|
||||
cd ${{ env.COLD_CLEAR_FOLDER }}
|
||||
mkdir -p ./lib/lua/5.1
|
||||
mv ./x64/CCloader.so ./lib/lua/5.1
|
||||
- name: Build Linux packages
|
||||
id: build-packages
|
||||
uses: love-actions/love-actions-linux@v1
|
||||
uses: love-actions/love-actions-linux@v2
|
||||
with:
|
||||
app-name: ${{ needs.get-info.outputs.app-name }}
|
||||
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
||||
description: Techmino is fun!
|
||||
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 }}
|
||||
lib-path: ./ColdClear/lib
|
||||
lib-path: ${{ env.COLD_CLEAR_FOLDER }}/lib
|
||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||
output-folder: ${{ env.OUTPUT_FOLDER }}
|
||||
- name: Upload AppImage artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ needs.get-info.outputs.base-name }}_Linux_AppImage
|
||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.AppImage
|
||||
- name: Upload Debian artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ needs.get-info.outputs.base-name }}_Linux_Debian
|
||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.deb
|
||||
@@ -298,138 +323,58 @@ jobs:
|
||||
name: ${{ needs.get-info.outputs.update-title }}
|
||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||
|
||||
build-macos-portable:
|
||||
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:
|
||||
build-web-compat:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [get-info, build-core, auto-test]
|
||||
env:
|
||||
MEMORY_LIMIT: 128000000
|
||||
OUTPUT_FOLDER: ./build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Download core love package
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||
- name: Move core love package
|
||||
- name: Build web packages
|
||||
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
|
||||
uses: crazy-max/ghaction-github-pages@v3
|
||||
uses: crazy-max/ghaction-github-pages@v4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
build_dir: ./.github/build/web/
|
||||
build_dir: ${{ env.OUTPUT_FOLDER }}
|
||||
keep_history: false
|
||||
target_branch: web-dev
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ needs.get-info.outputs.base-name }}_Web_PWA
|
||||
path: ./.github/build/web/
|
||||
target_branch: gh-pages
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
needs: [get-info, build-core, auto-test]
|
||||
env:
|
||||
COLD_CLEAR_FOLDER: ./ColdClear
|
||||
OUTPUT_FOLDER: ./build
|
||||
RELEASE_FOLDER: ./release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Process app name
|
||||
@@ -441,20 +386,20 @@ jobs:
|
||||
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')
|
||||
- name: Download core love package
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||
- name: Download ColdClear
|
||||
uses: ./.github/actions/get-cc
|
||||
uses: ./.github/actions/get-unzip
|
||||
with:
|
||||
platform: Windows
|
||||
dir: ./ColdClear
|
||||
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Windows.zip
|
||||
dir: ${{ env.COLD_CLEAR_FOLDER }}
|
||||
- name: Update Windows template
|
||||
shell: python3 {0}
|
||||
run: |
|
||||
version_string = "${{ needs.get-info.outputs.version-string }}"
|
||||
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 = data\
|
||||
.replace("@Version", version_string)\
|
||||
@@ -464,30 +409,30 @@ jobs:
|
||||
file.write(data)
|
||||
- name: Build Windows packages
|
||||
id: build-packages
|
||||
uses: love-actions/love-actions-windows@v1
|
||||
uses: love-actions/love-actions-windows@v2
|
||||
with:
|
||||
icon-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/icon.ico
|
||||
rc-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/template.rc
|
||||
icon-path: ${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/icon.ico
|
||||
rc-path: ${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/template.rc
|
||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||
extra-assets-x86: ./ColdClear/x86/CCloader.dll ./ColdClear/x86/cold_clear.dll
|
||||
extra-assets-x64: ./ColdClear/x64/CCloader.dll ./ColdClear/x64/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: ${{ 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 }}
|
||||
app-id: ${{ secrets.WINDOWS_APP_ID }}
|
||||
project-website: https://www.studio26f.org/
|
||||
installer-languages: ChineseSimplified.isl ChineseTraditional.isl English.isl Spanish.isl French.isl Indonesian.isl Japanese.isl Portuguese.isl
|
||||
output-folder: ${{ env.OUTPUT_FOLDER }}
|
||||
- name: Upload 32-bit artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ needs.get-info.outputs.base-name }}_Windows_x86
|
||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x86.zip
|
||||
- name: Upload 64-bit artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ needs.get-info.outputs.base-name }}_Windows_x64
|
||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x64.zip
|
||||
- name: Upload installer artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ needs.get-info.outputs.base-name }}_Windows_installer
|
||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_installer.exe
|
||||
@@ -522,38 +467,58 @@ jobs:
|
||||
build-core,
|
||||
build-android,
|
||||
build-linux,
|
||||
build-macos-portable,
|
||||
build-web,
|
||||
build-web-compat,
|
||||
build-windows,
|
||||
]
|
||||
env:
|
||||
ACTION_TYPE: ${{ fromJSON('[["Development", "Pre-release"], ["Release", "Release"]]')[startsWith(github.ref, 'refs/tags/v')][startsWith(github.ref, 'refs/tags/pre')] }}
|
||||
steps:
|
||||
- name: Cleanup
|
||||
uses: geekyeggo/delete-artifact@v2
|
||||
uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||
- name: Send Discord message
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: Sniddl/discord-commits@v1.6
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
message: "Github Actions for **${{ github.repository }}**."
|
||||
embed: '{
|
||||
"author":{
|
||||
"name":"${{ needs.get-info.outputs.app-name }} [${{ env.ACTION_TYPE }}]",
|
||||
"url":"https://github.com/${{ github.repository }}"
|
||||
},
|
||||
"title":"${{ needs.get-info.outputs.app-name }} (${{ needs.get-info.outputs.version-name }}) Build Result",
|
||||
"description": "CI triggered at ${{ needs.get-info.outputs.commit-hash }}",
|
||||
"url":"https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
|
||||
"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**macOS portable:** ${{ needs.build-macos-portable.result }}\n**Windows:** ${{ needs.build-windows.result }}"}
|
||||
if: github.ref == 'refs/heads/main'
|
||||
shell: python
|
||||
run: |
|
||||
import requests
|
||||
import json
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
payload = json.dumps({
|
||||
"content": "Github Actions for **${{ github.repository }}**.",
|
||||
"embeds": [
|
||||
{
|
||||
"author": {
|
||||
"name": "${{ needs.get-info.outputs.app-name }} [${{ env.ACTION_TYPE }}]",
|
||||
"url": "https://github.com/${{ github.repository }}"
|
||||
},
|
||||
"title": "${{ needs.get-info.outputs.app-name }} (${{ needs.get-info.outputs.version-name }}) Build Result",
|
||||
"description": "CI triggered at ${{ needs.get-info.outputs.commit-hash }}",
|
||||
"url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
|
||||
"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
|
||||
libAndroid
|
||||
*.ini
|
||||
.DS_Store
|
||||
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 recvCHN=love.thread.getChannel('outputChannel')
|
||||
local sendCHN=love.thread.getChannel('HTTP_inputChannel')
|
||||
local recvCHN=love.thread.getChannel('HTTP_outputChannel')
|
||||
|
||||
local threads={}
|
||||
local threadCount=0
|
||||
@@ -9,11 +9,15 @@ local threadCode=[[
|
||||
local http=require'socket.http'
|
||||
local ltn12=require'ltn12'
|
||||
|
||||
local sendCHN=love.thread.getChannel('inputChannel')
|
||||
local recvCHN=love.thread.getChannel('outputChannel')
|
||||
local sendCHN=love.thread.getChannel('HTTP_inputChannel')
|
||||
local recvCHN=love.thread.getChannel('HTTP_outputChannel')
|
||||
local sleep=require'love.timer'.sleep
|
||||
|
||||
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
|
||||
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)
|
||||
EDITING=""
|
||||
LOADED=false
|
||||
|
||||
---@type 'Windows'|'Android'|'Linux'|'iOS'|'macOS'|'Web'
|
||||
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
|
||||
local success
|
||||
@@ -70,6 +80,7 @@ do
|
||||
end
|
||||
|
||||
-- Love-based modules (basic)
|
||||
CLIPBOARD= require'Zframework.clipboard'
|
||||
HTTP= require'Zframework.http'
|
||||
WS= require'Zframework.websocket'
|
||||
FILE= require'Zframework.file'
|
||||
@@ -92,6 +103,10 @@ IMG= require'Zframework.image'
|
||||
BGM= require'Zframework.bgm'
|
||||
VOC= require'Zframework.voice'
|
||||
|
||||
if SYSTEM=='Web' then
|
||||
JS=require'Zframework.js'
|
||||
end
|
||||
|
||||
local ms,kb=love.mouse,love.keyboard
|
||||
local KBisDown=kb.isDown
|
||||
|
||||
@@ -172,6 +187,7 @@ local function updatePowerInfo()
|
||||
gc_pop()
|
||||
gc.setCanvas()
|
||||
end
|
||||
|
||||
-------------------------------------------------------------
|
||||
local lastX,lastY=0,0-- Last click pos
|
||||
local function _updateMousePos(x,y,dx,dy)
|
||||
@@ -421,38 +437,38 @@ local dPadToKey={
|
||||
start='return',
|
||||
back='escape',
|
||||
}
|
||||
function love.joystickadded(JS)
|
||||
function love.joystickadded(joystick)
|
||||
table.insert(jsState,{
|
||||
_id=JS:getID(),
|
||||
_jsObj=JS,
|
||||
_id=joystick:getID(),
|
||||
_jsObj=joystick,
|
||||
leftx=0,lefty=0,
|
||||
rightx=0,righty=0,
|
||||
triggerleft=0,triggerright=0
|
||||
})
|
||||
MES.new('info',"Joystick added")
|
||||
end
|
||||
function love.joystickremoved(JS)
|
||||
function love.joystickremoved(joystick)
|
||||
for i=1,#jsState do
|
||||
if jsState[i]._jsObj==JS then
|
||||
if jsState[i]._jsObj==joystick then
|
||||
for j=1,#gamePadKeys do
|
||||
if JS:isGamepadDown(gamePadKeys[j]) then
|
||||
love.gamepadreleased(JS,gamePadKeys[j])
|
||||
if joystick:isGamepadDown(gamePadKeys[j]) then
|
||||
love.gamepadreleased(joystick,gamePadKeys[j])
|
||||
end
|
||||
end
|
||||
love.gamepadaxis(JS,'leftx',0)
|
||||
love.gamepadaxis(JS,'lefty',0)
|
||||
love.gamepadaxis(JS,'rightx',0)
|
||||
love.gamepadaxis(JS,'righty',0)
|
||||
love.gamepadaxis(JS,'triggerleft',-1)
|
||||
love.gamepadaxis(JS,'triggerright',-1)
|
||||
love.gamepadaxis(joystick,'leftx',0)
|
||||
love.gamepadaxis(joystick,'lefty',0)
|
||||
love.gamepadaxis(joystick,'rightx',0)
|
||||
love.gamepadaxis(joystick,'righty',0)
|
||||
love.gamepadaxis(joystick,'triggerleft',-1)
|
||||
love.gamepadaxis(joystick,'triggerright',-1)
|
||||
MES.new('info',"Joystick removed")
|
||||
table.remove(jsState,i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
function love.gamepadaxis(JS,axis,val)
|
||||
if jsState[1] and JS==jsState[1]._jsObj then
|
||||
function love.gamepadaxis(joystick,axis,val)
|
||||
if jsState[1] and joystick==jsState[1]._jsObj then
|
||||
local js=jsState[1]
|
||||
if axis=='leftx' or axis=='lefty' or axis=='rightx' or axis=='righty' then
|
||||
local newVal=-- range: [0,1]
|
||||
@@ -461,14 +477,14 @@ function love.gamepadaxis(JS,axis,val)
|
||||
0
|
||||
if newVal~=js[axis] then
|
||||
if js[axis]==-1 then
|
||||
love.gamepadreleased(JS,jsAxisEventName[axis][1])
|
||||
love.gamepadreleased(joystick,jsAxisEventName[axis][1])
|
||||
elseif js[axis]~=0 then
|
||||
love.gamepadreleased(JS,jsAxisEventName[axis][2])
|
||||
love.gamepadreleased(joystick,jsAxisEventName[axis][2])
|
||||
end
|
||||
if newVal==-1 then
|
||||
love.gamepadpressed(JS,jsAxisEventName[axis][1])
|
||||
love.gamepadpressed(joystick,jsAxisEventName[axis][1])
|
||||
elseif newVal==1 then
|
||||
love.gamepadpressed(JS,jsAxisEventName[axis][2])
|
||||
love.gamepadpressed(joystick,jsAxisEventName[axis][2])
|
||||
end
|
||||
js[axis]=newVal
|
||||
end
|
||||
@@ -476,9 +492,9 @@ function love.gamepadaxis(JS,axis,val)
|
||||
local newVal=val>.3 and 1 or 0-- range: [0,1]
|
||||
if newVal~=js[axis] then
|
||||
if newVal==1 then
|
||||
love.gamepadpressed(JS,jsAxisEventName[axis])
|
||||
love.gamepadpressed(joystick,jsAxisEventName[axis])
|
||||
else
|
||||
love.gamepadreleased(JS,jsAxisEventName[axis])
|
||||
love.gamepadreleased(joystick,jsAxisEventName[axis])
|
||||
end
|
||||
js[axis]=newVal
|
||||
end
|
||||
@@ -718,6 +734,10 @@ function love.run()
|
||||
|
||||
-- UPDATE
|
||||
STEP()
|
||||
if SYSTEM == 'Web' then
|
||||
JS.retrieveData(dt)
|
||||
CLIPBOARD._update(dt)
|
||||
end
|
||||
if mouseShow then mouse_update(dt) end
|
||||
if next(jsState) then gp_update(jsState[1],dt) end
|
||||
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
|
||||
if not switch then
|
||||
profile.stop()
|
||||
love.system.setClipboardText(profile.report())
|
||||
CLIPBOARD.set(profile.report())
|
||||
profile.reset()
|
||||
return false
|
||||
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<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
|
||||
timeUnits[#timeUnits]=floorint(timeUnits[#timeUnits])
|
||||
|
||||
local outputStr=''
|
||||
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]
|
||||
end
|
||||
end
|
||||
@@ -189,7 +189,7 @@ do-- functions to shorted big numbers
|
||||
function STRING.bigInt(t)
|
||||
if t<1000 then
|
||||
return tostring(t)
|
||||
elseif t~=1e999 then
|
||||
elseif t~=1/0 then
|
||||
local e=floorint(lg(t)/3)
|
||||
return(t/10^(e*3))..units[e+1]
|
||||
else
|
||||
|
||||
@@ -8,8 +8,6 @@ local path=''
|
||||
|
||||
local type=type
|
||||
local timer=love.timer.getTime
|
||||
local TRD=love.thread.newThread("\n")
|
||||
local TRD_isRunning=TRD.isRunning
|
||||
|
||||
local WS={}
|
||||
local wsList=setmetatable({},{
|
||||
@@ -151,7 +149,7 @@ function WS.update(dt)
|
||||
local time=timer()
|
||||
for name,ws in next,wsList do
|
||||
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
|
||||
ws.triggerCHN:push(0)
|
||||
end
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---@type love.Channel,love.Channel,love.Channel
|
||||
local triggerCHN,sendCHN,readCHN=...
|
||||
|
||||
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 JSON=require'Zframework.json'
|
||||
local sleep=require'love.timer'.sleep
|
||||
|
||||
do-- Connect
|
||||
local host=CHN_demand(sendCHN)
|
||||
local port=CHN_demand(sendCHN)
|
||||
local path=CHN_demand(sendCHN)
|
||||
local head=CHN_demand(sendCHN)
|
||||
local timeout=CHN_demand(sendCHN)
|
||||
-- Warning: workaround for love.js, used to use CHN_demand instead
|
||||
while CHN_getCount(sendCHN)<5 do sleep(.0626) end
|
||||
local host=CHN_pop(sendCHN)
|
||||
local port=CHN_pop(sendCHN)
|
||||
local path=CHN_pop(sendCHN)
|
||||
local head=CHN_pop(sendCHN)
|
||||
local timeout=CHN_pop(sendCHN)
|
||||
|
||||
SOCK:settimeout(timeout)
|
||||
local res,err=SOCK:connect(host,port)
|
||||
-- print('C0',res,err)
|
||||
assert(res,err)
|
||||
|
||||
-- WebSocket handshake
|
||||
@@ -31,6 +36,7 @@ do-- Connect
|
||||
|
||||
-- First line of HTTP
|
||||
res,err=SOCK:receive('*l')
|
||||
-- print('C',res,err)
|
||||
assert(res,err)
|
||||
local code,ctLen
|
||||
code=res:find(' ')
|
||||
@@ -39,22 +45,28 @@ do-- Connect
|
||||
-- Get body length from headers and remove headers
|
||||
repeat
|
||||
res,err=SOCK:receive('*l')
|
||||
-- print('H',res,err)
|
||||
assert(res,err)
|
||||
if not ctLen and res:find('length') then
|
||||
ctLen=tonumber(res:match('%d+'))
|
||||
if not ctLen and res:find('content-length') then
|
||||
ctLen=tonumber(res:match('%d+')) or 0
|
||||
end
|
||||
until res==''
|
||||
|
||||
-- Result
|
||||
if code=='101' then
|
||||
CHN_push(readCHN,'success')
|
||||
end
|
||||
|
||||
-- Content(?)
|
||||
if ctLen then
|
||||
if code=='101' then
|
||||
CHN_push(readCHN,'success')
|
||||
else
|
||||
res,err=SOCK:receive(ctLen)
|
||||
res,err=SOCK:receive(ctLen)
|
||||
-- print('R',res,err)
|
||||
if code~='101' then
|
||||
res=JSON.decode(assert(res,err))
|
||||
error((code or "XXX")..":"..(res and res.reason or "Server Error"))
|
||||
end
|
||||
end
|
||||
|
||||
SOCK:settimeout(0)
|
||||
end
|
||||
|
||||
@@ -136,10 +148,10 @@ local readThread=coroutine.wrap(function()
|
||||
assert(res,err)
|
||||
length=shl(byte(res,1),8)+byte(res,2)
|
||||
elseif length==127 then
|
||||
local lenData
|
||||
lenData,err=_receive(SOCK,8)
|
||||
-- 'res' is 'lenData' here
|
||||
res,err=_receive(SOCK,8)
|
||||
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
|
||||
end
|
||||
res,err=_receive(SOCK,length)
|
||||
@@ -158,12 +170,14 @@ local readThread=coroutine.wrap(function()
|
||||
lBuffer=lBuffer..res
|
||||
if fin then
|
||||
CHN_push(readCHN,lBuffer)
|
||||
-- print('M',lBuffer)
|
||||
lBuffer=""
|
||||
end
|
||||
else
|
||||
CHN_push(readCHN,op)
|
||||
if fin then
|
||||
CHN_push(readCHN,res)
|
||||
-- print('S',res)
|
||||
lBuffer=""
|
||||
else
|
||||
lBuffer=res
|
||||
@@ -176,7 +190,8 @@ end)
|
||||
local success,err
|
||||
|
||||
while true do-- Running
|
||||
CHN_demand(triggerCHN)
|
||||
while CHN_getCount(triggerCHN)==0 do sleep(.0626) end
|
||||
CHN_pop(triggerCHN)
|
||||
success,err=pcall(sendThread)
|
||||
if not success or err then break end
|
||||
success,err=pcall(readThread)
|
||||
|
||||
@@ -15,6 +15,7 @@ local timer=love.timer.getTime
|
||||
local next=next
|
||||
local floor,ceil=math.floor,math.ceil
|
||||
local max,min=math.max,math.min
|
||||
local match=string.match
|
||||
local sub,ins,rem=string.sub,table.insert,table.remove
|
||||
local xOy=SCR.xOy
|
||||
local FONT=FONT
|
||||
@@ -142,13 +143,21 @@ local button={
|
||||
type='button',
|
||||
mustHaveText=true,
|
||||
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()
|
||||
self.ATV=0
|
||||
end
|
||||
function button:setObject(obj)
|
||||
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
|
||||
self.obj=obj
|
||||
end
|
||||
@@ -194,16 +203,7 @@ function button:draw()
|
||||
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
||||
local y0=y+h*.5
|
||||
gc_setColor(1,1,1,.2+ATV*.05)
|
||||
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)
|
||||
elseif self.align=='L' then
|
||||
if self.align=='L' or self.textAlreadyWrapped then
|
||||
local edge=self.edge
|
||||
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_setColor(r*.55,g*.55,b*.55)
|
||||
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
|
||||
function button:getInfo()
|
||||
@@ -290,13 +299,21 @@ local key={
|
||||
type='key',
|
||||
mustHaveText=true,
|
||||
ATV=0,-- Activating time(0~4)
|
||||
textAlreadyWrapped=false,---See button.setObject (line 146)
|
||||
}
|
||||
function key:reset()
|
||||
self.ATV=0
|
||||
end
|
||||
function key:setObject(obj)
|
||||
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
|
||||
self.obj=obj
|
||||
end
|
||||
@@ -354,14 +371,15 @@ function key:draw()
|
||||
-- Drawable
|
||||
local obj=self.obj
|
||||
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
||||
|
||||
gc_setColor(r,g,b)
|
||||
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)
|
||||
elseif align=='L' then
|
||||
gc_draw(obj,x+self.edge,y-oy+h*.5)
|
||||
if align=='L' or self.textAlreadyWrapped then
|
||||
gc_draw(obj,x+self.edge,y+h*.5-oy)
|
||||
elseif align=='R' then
|
||||
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
|
||||
function key:getInfo()
|
||||
@@ -1382,10 +1400,13 @@ function WIDGET.setLang(widgetText)
|
||||
t=W.name or "##"
|
||||
W.color=COLOR.dV
|
||||
end
|
||||
if type(t)=='string' and W.font then
|
||||
t=gc.newText(FONT.get(W.font),t)
|
||||
if type(W.setObject)=='function' then
|
||||
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
|
||||
W.obj=t
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
13
conf.lua
@@ -1,9 +1,9 @@
|
||||
local OS=love._os
|
||||
if OS=='OS X' then OS='macOS' end
|
||||
MOBILE=OS=='Android' or OS=='iOS'
|
||||
FNNS=OS:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol
|
||||
local system=love._os
|
||||
if system=='OS X' then system='macOS' end
|
||||
MOBILE=system=='Android' or system=='iOS'
|
||||
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
|
||||
function love.filesystem.read(name,size)
|
||||
if love.filesystem.getInfo(name) then
|
||||
@@ -23,12 +23,13 @@ function love.conf(t)
|
||||
local fileData=fs.read('conf/settings')
|
||||
if fileData then
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
t.identity=identity -- Saving folder
|
||||
t.version="11.4"
|
||||
t.version="11.5"
|
||||
t.gammacorrect=false
|
||||
t.appendidentity=true -- Search files in source then in save directory
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
101
main.lua
@@ -23,7 +23,7 @@ TIME=love.timer.getTime
|
||||
|
||||
-- Global Vars & Settings
|
||||
SFXPACKS={'chiptune'}
|
||||
VOCPACKS={'miya','mono','xiaoya','flore','miku','zundamon'}
|
||||
VOCPACKS={'miya','mono','xiaoya','flore','neuro','miku','zundamon'}
|
||||
FIRSTLAUNCH=false
|
||||
DAILYLAUNCH=false
|
||||
|
||||
@@ -49,6 +49,10 @@ SCR.setSize(1280,720) -- Initialize Screen size
|
||||
BGM.setMaxSources(5)
|
||||
VOC.setDiversion(.62)
|
||||
|
||||
if SYSTEM == 'Web' and not WEB_COMPAT_MODE then
|
||||
CLIPBOARD.setFreshInterval(.5)
|
||||
end
|
||||
|
||||
WIDGET.setOnChange(function()
|
||||
if SCN.cur=='net_game' or SCN.cur=='custom_field' then return end
|
||||
local colorList=THEME.getThemeColor()
|
||||
@@ -271,6 +275,7 @@ IMG.init{
|
||||
floreCH='media/image/characters/flore.png',
|
||||
mikuCH='media/image/characters/miku.png',
|
||||
zundamonCH='media/image/characters/zundamon.png',
|
||||
neuroCH='media/image/characters/neuro.png',
|
||||
z={
|
||||
character='media/image/characters/z_character.png',
|
||||
screen1='media/image/characters/z_screen1.png',
|
||||
@@ -293,39 +298,41 @@ IMG.init{
|
||||
},
|
||||
}
|
||||
SKIN.load{
|
||||
{name="crystal_scf", path='media/image/skin/crystal_scf.png'},
|
||||
{name="matte_mrz", path='media/image/skin/matte_mrz.png'},
|
||||
{name="shiny_chno", path='media/image/skin/shiny_chno.png'},
|
||||
{name="contrast_mrz", path='media/image/skin/contrast_mrz.png'},
|
||||
{name="polkadots_scf", path='media/image/skin/polkadots_scf.png'},
|
||||
{name="toy_scf", path='media/image/skin/toy_scf.png'},
|
||||
{name="smooth_mrz", path='media/image/skin/smooth_mrz.png'},
|
||||
{name="simple_scf", path='media/image/skin/simple_scf.png'},
|
||||
{name="glass_scf", path='media/image/skin/glass_scf.png'},
|
||||
{name="penta_scf", path='media/image/skin/penta_scf.png'},
|
||||
{name="bubble_scf", path='media/image/skin/bubble_scf.png'},
|
||||
{name="minoes_scf", path='media/image/skin/minoes_scf.png'},
|
||||
{name="pure_mrz", path='media/image/skin/pure_mrz.png'},
|
||||
{name="bright_scf", path='media/image/skin/bright_scf.png'},
|
||||
{name="glow_mrz", path='media/image/skin/glow_mrz.png'},
|
||||
{name="plastic_mrz", path='media/image/skin/plastic_mrz.png'},
|
||||
{name="paper_mrz", path='media/image/skin/paper_mrz.png'},
|
||||
{name="yinyang_scf", path='media/image/skin/yinyang_scf.png'},
|
||||
{name="cartooncup_earety", path='media/image/skin/cartooncup_earety.png'},
|
||||
{name="jelly_miya", path='media/image/skin/jelly_miya.png'},
|
||||
{name="guidetris_xmiao_lusisi",path='media/image/skin/guidetris_xmiao_lusisi.png'},
|
||||
{name="brick_notypey", path='media/image/skin/brick_notypey.png'},
|
||||
{name="gem_notypey", path='media/image/skin/gem_notypey.png'},
|
||||
{name="classic", path='media/image/skin/classic_unknown.png'},
|
||||
{name="ball_shaw", path='media/image/skin/ball_shaw.png'},
|
||||
{name="retro_notypey", path='media/image/skin/retro_notypey.png'},
|
||||
{name="pixel_chno", path='media/image/skin/pixel_chno.png'},
|
||||
{name="pastel_chno", path='media/image/skin/pastel_chno.png'},
|
||||
{name="letters_chno", path='media/image/skin/letters_chno.png'},
|
||||
{name="kanji_chno", path='media/image/skin/kanji_chno.png'},
|
||||
{name="textbone_mrz", path='media/image/skin/textbone_mrz.png'},
|
||||
{name="coloredbone_mrz", path='media/image/skin/coloredbone_mrz.png'},
|
||||
{name="wtf", path='media/image/skin/wtf_mrz.png'},
|
||||
{name="Crystal (Scf)", path='media/image/skin/scf/crystal.png'},
|
||||
{name="Smooth (MrZ)", path='media/image/skin/mrz/smooth.png'},
|
||||
{name="Matte (MrZ)", path='media/image/skin/mrz/matte.png'},
|
||||
{name="Glass (Scf)", path='media/image/skin/scf/glass.png'},
|
||||
{name="Jelly (Miya)", path='media/image/skin/miya/jelly.png'},
|
||||
{name="Simple (Scf)", path='media/image/skin/scf/simple.png'},
|
||||
{name="Contrast (MrZ)", path='media/image/skin/mrz/contrast.png'},
|
||||
{name="Plastic (MrZ)", path='media/image/skin/mrz/plastic.png'},
|
||||
{name="Glow (MrZ)", path='media/image/skin/mrz/glow.png'},
|
||||
{name="Bright (Scf)", path='media/image/skin/scf/bright.png'},
|
||||
{name="Penta (Scf)", path='media/image/skin/scf/penta.png'},
|
||||
{name="Bubble (Scf)", path='media/image/skin/scf/bubble.png'},
|
||||
{name="Pure (MrZ)", path='media/image/skin/mrz/pure.png'},
|
||||
{name="Letters (CHNO)", path='media/image/skin/chno/letters.png'},
|
||||
{name="Kanji (CHNO)", path='media/image/skin/chno/kanji.png'},
|
||||
{name="Pastel (CHNO)", path='media/image/skin/chno/pastel.png'},
|
||||
{name="Classic", path='media/image/skin/unknown/classic.png'},
|
||||
{name="Arcade (Asriel)", path='media/image/skin/asriel/arcade.png'},
|
||||
{name="Shiny (CHNO)", path='media/image/skin/chno/shiny.png'},
|
||||
{name="Brick (Notypey)", path='media/image/skin/notypey/brick.png'},
|
||||
{name="Cartooncup (Earety)", path='media/image/skin/earety/cartooncup.png'},
|
||||
{name="Paper (MrZ)", path='media/image/skin/mrz/paper.png'},
|
||||
{name="Toy (Scf)", path='media/image/skin/scf/toy.png'},
|
||||
{name="Polkadots (Scf)", path='media/image/skin/scf/polkadots.png'},
|
||||
{name="Yinyang (Scf)", path='media/image/skin/scf/yinyang.png'},
|
||||
{name="Minoes (Scf)", path='media/image/skin/scf/minoes.png'},
|
||||
{name="Cardboard (Asriel, slimenergy)", path='media/image/skin/asriel/cardboard.png'},
|
||||
{name="Ball (Shaw)", path='media/image/skin/shaw/ball.png'},
|
||||
{name="Gem (Notypey)", path='media/image/skin/notypey/gem.png'},
|
||||
{name="Pixel (CHNO)", path='media/image/skin/chno/pixel.png'},
|
||||
{name="Retro (Notypey)", path='media/image/skin/notypey/retro.png'},
|
||||
{name="Guidetris (xmiao, lusisi)", path='media/image/skin/guidetris_xmiao_lusisi.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
|
||||
@@ -397,8 +404,12 @@ do
|
||||
RANKS.rhythm_h=nil; fs.remove('record/rhythm_h.rec')
|
||||
RANKS.rhythm_u=nil; fs.remove('record/rhythm_u.rec')
|
||||
end
|
||||
if RANKS.bigbang then fs.remove('record/bigbang.rec') end
|
||||
if RANKS.clearRush then fs.remove('record/clearRush.rec') end
|
||||
if RANKS.bigbang then RANKS.bigbang=nil; fs.remove('record/bigbang.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~=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
|
||||
if not RSlist[SETTING.RS] then SETTING.RS='TRS' 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 SETTING.cv then SETTING.vocPack,SETTING.cv=SETTING.cv 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.locale=='zh_full' then SETTING.locale='zh' 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_dig then RANKS.infinite_dig=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
|
||||
table.sort(REPLAY,function(a,b) return a.fileName>b.fileName end)
|
||||
|
||||
AUTHURL="https://studio26f.org/oauth?product=techmino"
|
||||
AUTHHOST="cafuuchino1.3322.org:8081"
|
||||
WS.switchHost('cafuuchino1.3322.org','10026','/techmino/ws/v1')
|
||||
HTTP.setHost("cafuuchino1.3322.org:10026")
|
||||
AUTHURL="https://www.studio26f.org/oauth?product=techmino"
|
||||
AUTHHOST="www.studio26f.org:8080"
|
||||
WS.switchHost('www.studio26f.org','8081','/techmino/ws/v1')
|
||||
HTTP.setHost("www.studio26f.org:8081")
|
||||
HTTP.setThreadCount(1)
|
||||
|
||||
-- Discord RPC
|
||||
DiscordRPC=require'parts.discordRPC'
|
||||
DiscordRPC.update()
|
||||
|
||||
table.insert(_LOADTIMELIST_,("Load Resources: %.3fs"):format(TIME()-_LOADTIME_))
|
||||
|
||||
for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i]) end
|
||||
|
||||
-- Launch testing task if launch param received
|
||||
if TABLE.find(arg,'-- test') then
|
||||
if TABLE.find(arg,'--test') then
|
||||
TASK.new(function()
|
||||
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 |