Compare commits

..

6 Commits

Author SHA1 Message Date
C29H25N3O5
0e8ddee6c5 Update Monospaced font
Redesigned the monospaced font based on the main UI font of the game (Exo 2).
2024-01-15 17:40:22 -06:00
C₂₉H₂₅N₃O₅
bf0bb1d47b Merge branch '26F-Studio:main' into main 2024-01-15 16:20:37 -06:00
C29H25N3O5
06dc22544f Symbol and font fixes
- Added some more symbols
- Fixed some missing characters
2023-08-29 11:35:49 +08:00
C₂₉H₂₅N₃O₅
70c1b04bf6 Merge branch '26F-Studio:main' into main 2023-08-28 22:27:54 -05:00
C29H25N3O5
41c957cd8f Updated in-game font
- Adjusted the alignment of font
- Added missing glyphs in some languages
- Redesigned grade letters to increase legibility
2023-08-18 01:24:49 +08:00
C29H25N3O5
e3a0eacf1d Updated two block skins 2023-08-17 02:10:46 +08:00
260 changed files with 1558 additions and 2741 deletions

View File

@@ -1,16 +0,0 @@
# 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

32
.github/actions/get-cc/action.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
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 }}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,112 +0,0 @@
<!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>

View File

Before

Width:  |  Height:  |  Size: 305 KiB

After

Width:  |  Height:  |  Size: 305 KiB

288
.github/build/web/game.js vendored Normal file
View File

@@ -0,0 +1,288 @@
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}]});
})();

View File

@@ -5,10 +5,9 @@
<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>
@@ -62,7 +61,7 @@
var Module = { var Module = {
arguments: ["./game.love"], arguments: ["./game.love"],
INITIAL_MEMORY: 128000000, INITIAL_MEMORY: 536870912,
printErr: console.error.bind(console), printErr: console.error.bind(console),
canvas: (function() { canvas: (function() {
var canvas = document.getElementById('canvas'); var canvas = document.getElementById('canvas');

22
.github/build/web/love.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
.github/build/web/love.wasm vendored Normal file

Binary file not shown.

BIN
.github/build/web/theme/bg.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

49
.github/build/web/theme/love.css vendored Normal file
View File

@@ -0,0 +1,49 @@
* {
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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -8,11 +8,9 @@ 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')] }}
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 CORE_LOVE_PACKAGE_PATH: ./core.love
CORE_LOVE_ARTIFACT_NAME: core_love_package
jobs: jobs:
get-info: get-info:
@@ -27,7 +25,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@v4 - uses: actions/checkout@v3
- name: Install lua - name: Install lua
run: | run: |
sudo apt-get install lua5.3 -y sudo apt-get install lua5.3 -y
@@ -75,7 +73,7 @@ jobs:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Process app name - name: Process app name
@@ -97,13 +95,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@v4 uses: actions/upload-artifact@v3
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 ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png cp ./.github/build/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
@@ -111,7 +109,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@v4 uses: actions/upload-artifact@v3
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
@@ -132,12 +130,10 @@ jobs:
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }} prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
auto-test: auto-test:
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
needs: build-core needs: build-core
env:
APPIMAGE_PATH: ./love.AppImage
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Love actions for testing - name: Love actions for testing
@@ -145,35 +141,16 @@ 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@v4 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Process app name - name: Process app name
@@ -182,7 +159,6 @@ 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')
@@ -191,17 +167,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@v4 uses: actions/download-artifact@v3
with: with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }} name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Download ColdClear - name: Download ColdClear
uses: ./.github/actions/get-unzip uses: ./.github/actions/get-cc
with: with:
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Android.zip platform: Android
dir: ${{ env.COLD_CLEAR_FOLDER }} dir: ./libAndroid
- name: Build Android packages - name: Build Android packages
id: build-packages id: build-packages
uses: love-actions/love-actions-android@v2 uses: love-actions/love-actions-android@main
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 }}
@@ -211,15 +187,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: ${{ env.BUILD_ASSETS_FOLDER }}/android/${{ env.BUILD_TYPE }}/res resource-path: ./.github/build/android/${{ env.BUILD_TYPE }}/res
extra-assets: ${{ env.COLD_CLEAR_FOLDER }} extra-assets: ./libAndroid/
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@v4 uses: actions/upload-artifact@v3
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
@@ -243,11 +219,10 @@ 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@v4 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Process app name - name: Process app name
@@ -262,45 +237,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@v4 uses: actions/download-artifact@v3
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 ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png media/image/icon.png cp ./.github/build/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-unzip uses: ./.github/actions/get-cc
with: with:
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Linux.zip platform: Linux
dir: ${{ env.COLD_CLEAR_FOLDER }} dir: ./ColdClear
- name: Process ColdClear - name: Process ColdClear
shell: bash shell: bash
run: | run: |
cd ${{ env.COLD_CLEAR_FOLDER }} cd ./ColdClear
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@v2 uses: love-actions/love-actions-linux@v1
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: ${{ env.BUILD_ASSETS_FOLDER }}/linux/${{ env.BUILD_TYPE }}/icon.png icon-path: ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }} love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
lib-path: ${{ env.COLD_CLEAR_FOLDER }}/lib lib-path: ./ColdClear/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@v4 uses: actions/upload-artifact@v3
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@v4 uses: actions/upload-artifact@v3
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
@@ -323,58 +298,138 @@ 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-web-compat: 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:
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@v4 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Download core love package - name: Download core love package
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }} name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Build web packages - name: Move core love package
run: | run: |
npx love.js ${{ env.CORE_LOVE_PACKAGE_PATH }} ${{ env.OUTPUT_FOLDER }} -t "${{ needs.get-info.outputs.app-name }}" -m ${{ env.MEMORY_LIMIT }} -c mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ./.github/build/web/game.data
- 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@v4 uses: crazy-max/ghaction-github-pages@v3
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
build_dir: ${{ env.OUTPUT_FOLDER }} build_dir: ./.github/build/web/
keep_history: false keep_history: false
target_branch: gh-pages 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/
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@v4 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Process app name - name: Process app name
@@ -386,20 +441,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@v4 uses: actions/download-artifact@v3
with: with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }} name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Download ColdClear - name: Download ColdClear
uses: ./.github/actions/get-unzip uses: ./.github/actions/get-cc
with: with:
url: ${{ env.COLD_CLEAR_DOWNLOAD_URL }}/Windows.zip platform: Windows
dir: ${{ env.COLD_CLEAR_FOLDER }} dir: ./ColdClear
- 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("${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/template.rc", "r+", encoding="utf8") as file: with open("./.github/build/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)\
@@ -409,30 +464,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@v2 uses: love-actions/love-actions-windows@v1
with: with:
icon-path: ${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/icon.ico icon-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/icon.ico
rc-path: ${{ env.BUILD_ASSETS_FOLDER }}/windows/${{ env.BUILD_TYPE }}/template.rc rc-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/template.rc
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }} love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
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-x86: ./ColdClear/x86/CCloader.dll ./ColdClear/x86/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 extra-assets-x64: ./ColdClear/x64/CCloader.dll ./ColdClear/x64/cold_clear.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@v4 uses: actions/upload-artifact@v3
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@v4 uses: actions/upload-artifact@v3
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@v4 uses: actions/upload-artifact@v3
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
@@ -467,58 +522,38 @@ jobs:
build-core, build-core,
build-android, build-android,
build-linux, build-linux,
build-web-compat, build-macos-portable,
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@v5 uses: geekyeggo/delete-artifact@v2
with: with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }} name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Send Discord message - name: Send Discord message
if: github.ref == 'refs/heads/main' if: github.event_name != 'pull_request'
shell: python uses: Sniddl/discord-commits@v1.6
run: | with:
import requests webhook: ${{ secrets.DISCORD_WEBHOOK }}
import json message: "Github Actions for **${{ github.repository }}**."
embed: '{
headers = { "author":{
'Content-Type': 'application/json', "name":"${{ needs.get-info.outputs.app-name }} [${{ env.ACTION_TYPE }}]",
} "url":"https://github.com/${{ github.repository }}"
payload = json.dumps({ },
"content": "Github Actions for **${{ github.repository }}**.", "title":"${{ needs.get-info.outputs.app-name }} (${{ needs.get-info.outputs.version-name }}) Build Result",
"embeds": [ "description": "CI triggered at ${{ needs.get-info.outputs.commit-hash }}",
{ "url":"https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"author": { "thumbnail":{
"name": "${{ needs.get-info.outputs.app-name }} [${{ env.ACTION_TYPE }}]", "url":"https://raw.githubusercontent.com/${{ github.repository }}/main/.github/build/linux/${{ env.BUILD_TYPE }}/icon.png"
"url": "https://github.com/${{ github.repository }}" },
}, "color":36863,
"title": "${{ needs.get-info.outputs.app-name }} (${{ needs.get-info.outputs.version-name }}) Build Result", "fields":[
"description": "CI triggered at ${{ needs.get-info.outputs.commit-hash }}", {"name":"Version","value":"${{ needs.get-info.outputs.version-string }}","inline": true},
"url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}", {"name":"Package Name","value":"${{ needs.get-info.outputs.base-name }}","inline": true},
"thumbnail": { {"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 }}"}
"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
View File

@@ -1,4 +1,5 @@
.vscode .vscode
libAndroid
*.ini *.ini
.DS_Store .DS_Store
Thumbs.db Thumbs.db

View File

@@ -1,103 +0,0 @@
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,
}

View File

@@ -1,48 +0,0 @@
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

View File

@@ -1,5 +1,5 @@
local sendCHN=love.thread.getChannel('HTTP_inputChannel') local sendCHN=love.thread.getChannel('inputChannel')
local recvCHN=love.thread.getChannel('HTTP_outputChannel') local recvCHN=love.thread.getChannel('outputChannel')
local threads={} local threads={}
local threadCount=0 local threadCount=0
@@ -9,15 +9,11 @@ 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('HTTP_inputChannel') local sendCHN=love.thread.getChannel('inputChannel')
local recvCHN=love.thread.getChannel('HTTP_outputChannel') local recvCHN=love.thread.getChannel('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{

View File

@@ -1,18 +1,8 @@
-- 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()
WEB_COMPAT_MODE=false if SYSTEM=='OS X' then SYSTEM='macOS' end
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
@@ -80,7 +70,6 @@ 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'
@@ -103,10 +92,6 @@ 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
@@ -187,7 +172,6 @@ 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)
@@ -437,38 +421,38 @@ local dPadToKey={
start='return', start='return',
back='escape', back='escape',
} }
function love.joystickadded(joystick) function love.joystickadded(JS)
table.insert(jsState,{ table.insert(jsState,{
_id=joystick:getID(), _id=JS:getID(),
_jsObj=joystick, _jsObj=JS,
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(joystick) function love.joystickremoved(JS)
for i=1,#jsState do for i=1,#jsState do
if jsState[i]._jsObj==joystick then if jsState[i]._jsObj==JS then
for j=1,#gamePadKeys do for j=1,#gamePadKeys do
if joystick:isGamepadDown(gamePadKeys[j]) then if JS:isGamepadDown(gamePadKeys[j]) then
love.gamepadreleased(joystick,gamePadKeys[j]) love.gamepadreleased(JS,gamePadKeys[j])
end end
end end
love.gamepadaxis(joystick,'leftx',0) love.gamepadaxis(JS,'leftx',0)
love.gamepadaxis(joystick,'lefty',0) love.gamepadaxis(JS,'lefty',0)
love.gamepadaxis(joystick,'rightx',0) love.gamepadaxis(JS,'rightx',0)
love.gamepadaxis(joystick,'righty',0) love.gamepadaxis(JS,'righty',0)
love.gamepadaxis(joystick,'triggerleft',-1) love.gamepadaxis(JS,'triggerleft',-1)
love.gamepadaxis(joystick,'triggerright',-1) love.gamepadaxis(JS,'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(joystick,axis,val) function love.gamepadaxis(JS,axis,val)
if jsState[1] and joystick==jsState[1]._jsObj then if jsState[1] and JS==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]
@@ -477,14 +461,14 @@ function love.gamepadaxis(joystick,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(joystick,jsAxisEventName[axis][1]) love.gamepadreleased(JS,jsAxisEventName[axis][1])
elseif js[axis]~=0 then elseif js[axis]~=0 then
love.gamepadreleased(joystick,jsAxisEventName[axis][2]) love.gamepadreleased(JS,jsAxisEventName[axis][2])
end end
if newVal==-1 then if newVal==-1 then
love.gamepadpressed(joystick,jsAxisEventName[axis][1]) love.gamepadpressed(JS,jsAxisEventName[axis][1])
elseif newVal==1 then elseif newVal==1 then
love.gamepadpressed(joystick,jsAxisEventName[axis][2]) love.gamepadpressed(JS,jsAxisEventName[axis][2])
end end
js[axis]=newVal js[axis]=newVal
end end
@@ -492,9 +476,9 @@ function love.gamepadaxis(joystick,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(joystick,jsAxisEventName[axis]) love.gamepadpressed(JS,jsAxisEventName[axis])
else else
love.gamepadreleased(joystick,jsAxisEventName[axis]) love.gamepadreleased(JS,jsAxisEventName[axis])
end end
js[axis]=newVal js[axis]=newVal
end end
@@ -734,10 +718,6 @@ 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()

View File

@@ -1,142 +0,0 @@
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

View File

@@ -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()
CLIPBOARD.set(profile.report()) love.system.setClipboardText(profile.report())
profile.reset() profile.reset()
return false return false
else else

View File

@@ -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={convertSecondsToUnits(t)} local timeUnits=TABLE.reverse({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[i]>0 then if timeUnits>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~=1/0 then elseif t~=1e999 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

View File

@@ -8,6 +8,8 @@ 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({},{
@@ -149,7 +151,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 ws.thread:isRunning() then if TRD_isRunning(ws.thread) then
if ws.triggerCHN:getCount()==0 then if ws.triggerCHN:getCount()==0 then
ws.triggerCHN:push(0) ws.triggerCHN:push(0)
end end

View File

@@ -1,4 +1,3 @@
---@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
@@ -6,20 +5,16 @@ 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
-- Warning: workaround for love.js, used to use CHN_demand instead local host=CHN_demand(sendCHN)
while CHN_getCount(sendCHN)<5 do sleep(.0626) end local port=CHN_demand(sendCHN)
local host=CHN_pop(sendCHN) local path=CHN_demand(sendCHN)
local port=CHN_pop(sendCHN) local head=CHN_demand(sendCHN)
local path=CHN_pop(sendCHN) local timeout=CHN_demand(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
@@ -36,7 +31,6 @@ 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(' ')
@@ -45,28 +39,22 @@ 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('content-length') then if not ctLen and res:find('length') then
ctLen=tonumber(res:match('%d+')) or 0 ctLen=tonumber(res:match('%d+'))
end end
until res=='' until res==''
-- Result -- Result
if code=='101' then
CHN_push(readCHN,'success')
end
-- Content(?)
if ctLen then if ctLen then
res,err=SOCK:receive(ctLen) if code=='101' then
-- print('R',res,err) CHN_push(readCHN,'success')
if code~='101' then else
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
@@ -148,10 +136,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
-- 'res' is 'lenData' here local lenData
res,err=_receive(SOCK,8) lenData,err=_receive(SOCK,8)
assert(res,err) assert(res,err)
local _,_,_,_,_5,_6,_7,_8=byte(res,1,8) local _,_,_,_,_5,_6,_7,_8=byte(lenData,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)
@@ -170,14 +158,12 @@ 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
@@ -190,8 +176,7 @@ end)
local success,err local success,err
while true do-- Running while true do-- Running
while CHN_getCount(triggerCHN)==0 do sleep(.0626) end CHN_demand(triggerCHN)
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)

View File

@@ -15,7 +15,6 @@ 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
@@ -143,21 +142,13 @@ 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
if match(obj,"\n") then self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
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
@@ -203,7 +194,16 @@ 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=='L' or self.textAlreadyWrapped then 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
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,15 +219,6 @@ 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()
@@ -299,21 +290,13 @@ 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
if match(obj,"\n") then self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
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
@@ -371,15 +354,14 @@ 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=='L' or self.textAlreadyWrapped then if align=='M' 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 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) 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
gc_draw(obj,x+w-self.edge-ox*2,y-oy+h*.5)
end end
end end
function key:getInfo() function key:getInfo()
@@ -821,7 +803,7 @@ function selector:press(x)
end end
end end
if self.select~=s then if self.select~=s then
self.code(self.list[s],s) self.code(self.list[s])
self.select=s self.select=s
self.selText=self.list[s] self.selText=self.list[s]
if self.sound then if self.sound then
@@ -1400,13 +1382,10 @@ function WIDGET.setLang(widgetText)
t=W.name or "##" t=W.name or "##"
W.color=COLOR.dV W.color=COLOR.dV
end end
if type(W.setObject)=='function' then if type(t)=='string' and W.font then
W:setObject(t) t=gc.newText(FONT.get(W.font),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

View File

@@ -1,9 +1,9 @@
local system=love._os local OS=love._os
if system=='OS X' then system='macOS' end if OS=='OS X' then OS='macOS' end
MOBILE=system=='Android' or system=='iOS' MOBILE=OS=='Android' or OS=='iOS'
FNNS=system:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol FNNS=OS:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol
if system=='Web' then if OS=='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,13 +23,12 @@ 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.5" t.version="11.4"
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

View File

@@ -12,8 +12,6 @@ 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
View File

@@ -23,7 +23,7 @@ TIME=love.timer.getTime
-- Global Vars & Settings -- Global Vars & Settings
SFXPACKS={'chiptune'} SFXPACKS={'chiptune'}
VOCPACKS={'miya','mono','xiaoya','flore','neuro','miku','zundamon'} VOCPACKS={'miya','mono','xiaoya','flore','miku','zundamon'}
FIRSTLAUNCH=false FIRSTLAUNCH=false
DAILYLAUNCH=false DAILYLAUNCH=false
@@ -49,10 +49,6 @@ 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()
@@ -275,7 +271,6 @@ 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',
@@ -298,41 +293,39 @@ IMG.init{
}, },
} }
SKIN.load{ SKIN.load{
{name="Crystal (Scf)", path='media/image/skin/scf/crystal.png'}, {name="crystal_scf", path='media/image/skin/crystal_scf.png'},
{name="Smooth (MrZ)", path='media/image/skin/mrz/smooth.png'}, {name="matte_mrz", path='media/image/skin/matte_mrz.png'},
{name="Matte (MrZ)", path='media/image/skin/mrz/matte.png'}, {name="shiny_chno", path='media/image/skin/shiny_chno.png'},
{name="Glass (Scf)", path='media/image/skin/scf/glass.png'}, {name="contrast_mrz", path='media/image/skin/contrast_mrz.png'},
{name="Jelly (Miya)", path='media/image/skin/miya/jelly.png'}, {name="polkadots_scf", path='media/image/skin/polkadots_scf.png'},
{name="Simple (Scf)", path='media/image/skin/scf/simple.png'}, {name="toy_scf", path='media/image/skin/toy_scf.png'},
{name="Contrast (MrZ)", path='media/image/skin/mrz/contrast.png'}, {name="smooth_mrz", path='media/image/skin/smooth_mrz.png'},
{name="Plastic (MrZ)", path='media/image/skin/mrz/plastic.png'}, {name="simple_scf", path='media/image/skin/simple_scf.png'},
{name="Glow (MrZ)", path='media/image/skin/mrz/glow.png'}, {name="glass_scf", path='media/image/skin/glass_scf.png'},
{name="Bright (Scf)", path='media/image/skin/scf/bright.png'}, {name="penta_scf", path='media/image/skin/penta_scf.png'},
{name="Penta (Scf)", path='media/image/skin/scf/penta.png'}, {name="bubble_scf", path='media/image/skin/bubble_scf.png'},
{name="Bubble (Scf)", path='media/image/skin/scf/bubble.png'}, {name="minoes_scf", path='media/image/skin/minoes_scf.png'},
{name="Pure (MrZ)", path='media/image/skin/mrz/pure.png'}, {name="pure_mrz", path='media/image/skin/pure_mrz.png'},
{name="Letters (CHNO)", path='media/image/skin/chno/letters.png'}, {name="bright_scf", path='media/image/skin/bright_scf.png'},
{name="Kanji (CHNO)", path='media/image/skin/chno/kanji.png'}, {name="glow_mrz", path='media/image/skin/glow_mrz.png'},
{name="Pastel (CHNO)", path='media/image/skin/chno/pastel.png'}, {name="plastic_mrz", path='media/image/skin/plastic_mrz.png'},
{name="Classic", path='media/image/skin/unknown/classic.png'}, {name="paper_mrz", path='media/image/skin/paper_mrz.png'},
{name="Arcade (Asriel)", path='media/image/skin/asriel/arcade.png'}, {name="yinyang_scf", path='media/image/skin/yinyang_scf.png'},
{name="Shiny (CHNO)", path='media/image/skin/chno/shiny.png'}, {name="cartooncup_earety", path='media/image/skin/cartooncup_earety.png'},
{name="Brick (Notypey)", path='media/image/skin/notypey/brick.png'}, {name="jelly_miya", path='media/image/skin/jelly_miya.png'},
{name="Cartooncup (Earety)", path='media/image/skin/earety/cartooncup.png'}, {name="guidetris_xmiao_lusisi",path='media/image/skin/guidetris_xmiao_lusisi.png'},
{name="Paper (MrZ)", path='media/image/skin/mrz/paper.png'}, {name="brick_notypey", path='media/image/skin/brick_notypey.png'},
{name="Toy (Scf)", path='media/image/skin/scf/toy.png'}, {name="gem_notypey", path='media/image/skin/gem_notypey.png'},
{name="Polkadots (Scf)", path='media/image/skin/scf/polkadots.png'}, {name="classic", path='media/image/skin/classic_unknown.png'},
{name="Yinyang (Scf)", path='media/image/skin/scf/yinyang.png'}, {name="ball_shaw", path='media/image/skin/ball_shaw.png'},
{name="Minoes (Scf)", path='media/image/skin/scf/minoes.png'}, {name="retro_notypey", path='media/image/skin/retro_notypey.png'},
{name="Cardboard (Asriel, slimenergy)", path='media/image/skin/asriel/cardboard.png'}, {name="pixel_chno", path='media/image/skin/pixel_chno.png'},
{name="Ball (Shaw)", path='media/image/skin/shaw/ball.png'}, {name="pastel_chno", path='media/image/skin/pastel_chno.png'},
{name="Gem (Notypey)", path='media/image/skin/notypey/gem.png'}, {name="letters_chno", path='media/image/skin/letters_chno.png'},
{name="Pixel (CHNO)", path='media/image/skin/chno/pixel.png'}, {name="kanji_chno", path='media/image/skin/kanji_chno.png'},
{name="Retro (Notypey)", path='media/image/skin/notypey/retro.png'}, {name="textbone_mrz", path='media/image/skin/textbone_mrz.png'},
{name="Guidetris (xmiao, lusisi)", path='media/image/skin/guidetris_xmiao_lusisi.png'}, {name="coloredbone_mrz", path='media/image/skin/coloredbone_mrz.png'},
{name="Textbone (MrZ)", path='media/image/skin/mrz/textbone.png'}, {name="wtf", path='media/image/skin/wtf_mrz.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
@@ -404,12 +397,8 @@ 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 RANKS.bigbang=nil; fs.remove('record/bigbang.rec') end if RANKS.bigbang then fs.remove('record/bigbang.rec') end
if RANKS.clearRush then RANKS.clearRush=nil; fs.remove('record/clearRush.rec') end if RANKS.clearRush then 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
@@ -435,8 +424,7 @@ 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
@@ -444,7 +432,6 @@ 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
@@ -603,22 +590,18 @@ 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://www.studio26f.org/oauth?product=techmino" AUTHURL="https://studio26f.org/oauth?product=techmino"
AUTHHOST="www.studio26f.org:8080" AUTHHOST="cafuuchino1.3322.org:8081"
WS.switchHost('www.studio26f.org','8081','/techmino/ws/v1') WS.switchHost('cafuuchino1.3322.org','10026','/techmino/ws/v1')
HTTP.setHost("www.studio26f.org:8081") HTTP.setHost("cafuuchino1.3322.org:10026")
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 613 B

After

Width:  |  Height:  |  Size: 613 B

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 837 B

After

Width:  |  Height:  |  Size: 837 B

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Before

Width:  |  Height:  |  Size: 91 B

After

Width:  |  Height:  |  Size: 91 B

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More