This commit is contained in:
Dante
2026-05-21 23:40:20 -07:00
parent 3e2915dff7
commit 877a69d844
5737 changed files with 29796 additions and 1589684 deletions

1
Kha/Tools/khamake/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* -text

2
Kha/Tools/khamake/.github/funding.yml vendored Normal file
View File

@ -0,0 +1,2 @@
github: RobDangerous
patreon: RobDangerous

View File

@ -0,0 +1,23 @@
name: Build
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Install tslint
run: sudo npm install -g tslint
- name: Lint
run: tslint -c tslint.json src/*.ts src/Exporters/*.ts
- name: Compile
run: tsc

9
Kha/Tools/khamake/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
*.js.map
/.vscode/.BROWSE.VC.DB
/.vscode/.BROWSE.VC.DB-shm
/.vscode/.BROWSE.VC.DB-wal
/node_modules/typescript
/node_modules/.bin/tsserver.cmd
/node_modules/.bin/tsc
/node_modules/.bin/tsc.cmd
/node_modules/.bin/tsserver

View File

@ -6,7 +6,11 @@
"tsconfig": "tsconfig.json",
"problemMatcher": [
"$tsc"
]
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Linter",
@ -21,4 +25,4 @@
"problemMatcher": []
}
]
}
}

View File

@ -59,6 +59,27 @@ class AssetConverter {
}
return { name: nameValue, destination: destination };
}
canDecodeFormat(ext) {
var _a, _b, _c, _d, _e, _f;
// without ffmpeg we need to encode mp3 and ogg files
const hasFFmpeg = !!this.options.ffmpeg;
const hasFFmpegOgg = (_b = (_a = this.options.ogg) === null || _a === void 0 ? void 0 : _a.includes('ffmpeg')) !== null && _b !== void 0 ? _b : false;
const hasFFmpegMp3 = (_d = (_c = this.options.mp3) === null || _c === void 0 ? void 0 : _c.includes('ffmpeg')) !== null && _d !== void 0 ? _d : false;
const hasFFmpegAac = (_f = (_e = this.options.aac) === null || _e === void 0 ? void 0 : _e.includes('ffmpeg')) !== null && _f !== void 0 ? _f : false;
switch (ext) {
case '.wav':
return true;
case '.ogg':
return hasFFmpeg || (hasFFmpegOgg && (hasFFmpegMp3 || hasFFmpegAac));
case '.mp3':
// lame can decode mp3, so we only need ogg ffmpeg encoder
return hasFFmpeg || (hasFFmpegOgg && !!this.options.mp3);
case '.flac':
return hasFFmpeg;
default:
return false;
}
}
watch(watch, match, temp, options) {
return new Promise((resolve, reject) => {
let ready = false;
@ -69,11 +90,15 @@ class AssetConverter {
let outPath = fileinfo.name;
// with subfolders
if (options.destination) {
const from = path.resolve(options.baseDir, '..');
// remove trailing slash
const nameBaseDir = options.nameBaseDir.replace(/\/$/, '');
const lastIndex = options.baseDir.lastIndexOf(nameBaseDir);
const from = path.resolve(options.baseDir.substring(0, lastIndex));
outPath = AssetConverter.replacePattern(options.destination, fileinfo.name, fileinfo, options, from);
}
log.info('Reexporting ' + outPath + fileinfo.ext);
switch (fileinfo.ext) {
const ext = fileinfo.ext.toLowerCase();
log.info('Reexporting ' + outPath + ext);
switch (ext) {
case '.png':
case '.jpg':
case '.jpeg':
@ -85,6 +110,9 @@ class AssetConverter {
case '.mp3':
case '.flac':
case '.wav': {
if (!this.canDecodeFormat(ext)) {
log.error(`Error: ${fileinfo.base} should be in wav format, or use \`--ffmpeg path/to/ffmpeg\` option to convert ogg/mp3/flac files`);
}
await this.exporter.copySound(this.platform, file, outPath, {});
break;
}
@ -100,10 +128,10 @@ class AssetConverter {
await this.exporter.copyFont(this.platform, file, outPath, {});
break;
default:
await this.exporter.copyBlob(this.platform, file, outPath + fileinfo.ext, {});
await this.exporter.copyBlob(this.platform, file, outPath + ext, {});
}
for (let callback of ProjectFile_1.Callbacks.postAssetReexporting) {
callback(outPath + fileinfo.ext);
callback(outPath + ext);
}
};
this.watcher.on('add', (file) => {
@ -129,8 +157,7 @@ class AssetConverter {
if (fs.existsSync(cachePath)) {
cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
}
const self = this;
async function convertAsset(file, index) {
const convertAsset = async (file, index) => {
let fileinfo = path.parse(file);
log.info('Exporting asset ' + (index + 1) + ' of ' + files.length + ' (' + fileinfo.base + ').');
const ext = fileinfo.ext.toLowerCase();
@ -139,13 +166,13 @@ class AssetConverter {
case '.jpg':
case '.jpeg':
case '.hdr': {
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, self.exporter.options.from);
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
let images;
if (options.noprocessing) {
images = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
images = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
}
else {
images = await self.exporter.copyImage(self.platform, file, exportInfo.destination, options, cache);
images = await this.exporter.copyImage(this.platform, file, exportInfo.destination, options, cache);
}
if (!options.notinlist) {
parsedFiles.push({ name: exportInfo.name, from: file, type: 'image', files: images.files, file_sizes: images.sizes, original_width: options.original_width, original_height: options.original_height, readable: options.readable });
@ -156,13 +183,17 @@ class AssetConverter {
case '.mp3':
case '.flac':
case '.wav': {
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, self.exporter.options.from);
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
let sounds;
if (options.noprocessing) {
sounds = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
sounds = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
}
else {
sounds = await self.exporter.copySound(self.platform, file, exportInfo.destination, options);
if (!this.canDecodeFormat(ext)) {
log.error(`Error: ${fileinfo.base} should be in wav format, or use \`--ffmpeg\` option to convert ogg/mp3/flac files`);
process.exit(1);
}
sounds = await this.exporter.copySound(this.platform, file, exportInfo.destination, options);
}
if (sounds.files.length === 0) {
throw 'Audio file ' + file + ' could not be exported, you have to specify a path to ffmpeg.';
@ -173,13 +204,13 @@ class AssetConverter {
break;
}
case '.ttf': {
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, self.exporter.options.from);
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
let fonts;
if (options.noprocessing) {
fonts = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
fonts = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
}
else {
fonts = await self.exporter.copyFont(self.platform, file, exportInfo.destination, options);
fonts = await this.exporter.copyFont(this.platform, file, exportInfo.destination, options);
}
if (!options.notinlist) {
parsedFiles.push({ name: exportInfo.name, from: file, type: 'font', files: fonts.files, file_sizes: fonts.sizes, original_width: undefined, original_height: undefined, readable: undefined });
@ -191,13 +222,13 @@ class AssetConverter {
case '.mov':
case '.wmv':
case '.avi': {
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, self.exporter.options.from);
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
let videos;
if (options.noprocessing) {
videos = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
videos = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
}
else {
videos = await self.exporter.copyVideo(self.platform, file, exportInfo.destination, options);
videos = await this.exporter.copyVideo(this.platform, file, exportInfo.destination, options);
}
if (videos.files.length === 0) {
log.error('Video file ' + file + ' could not be exported, you have to specify a path to ffmpeg.');
@ -208,15 +239,15 @@ class AssetConverter {
break;
}
default: {
let exportInfo = AssetConverter.createExportInfo(fileinfo, true, options, self.exporter.options.from);
let blobs = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
let exportInfo = AssetConverter.createExportInfo(fileinfo, true, options, this.exporter.options.from);
let blobs = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
if (!options.notinlist) {
parsedFiles.push({ name: exportInfo.name, from: file, type: 'blob', files: blobs.files, file_sizes: blobs.sizes, original_width: undefined, original_height: undefined, readable: undefined });
}
break;
}
}
}
};
if (this.options.parallelAssetConversion !== 0) {
let todo = files.map((file, index) => {
return async () => {

View File

@ -38,6 +38,9 @@ function convert(inFilename, outFilename, encoder, args = null) {
else
options.push(parts[i]);
}
if (fs.existsSync(outFilename.toString())) {
fs.unlinkSync(outFilename.toString());
}
// About stdio ignore: https://stackoverflow.com/a/20792428
let process = child_process.spawn(exe, options, { stdio: 'ignore' });
process.on('close', (code) => {

View File

@ -1,137 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KincExporter = void 0;
const fs = require("fs-extra");
const path = require("path");
const defaults = require("../defaults");
const KhaExporter_1 = require("./KhaExporter");
const Converter_1 = require("../Converter");
const GraphicsApi_1 = require("../GraphicsApi");
const Platform_1 = require("../Platform");
const ImageTool_1 = require("../ImageTool");
class KincExporter extends KhaExporter_1.KhaExporter {
constructor(options) {
super(options);
this.slowgc = options.slowgc;
// Files.removeDirectory(this.directory.resolve(Paths.get(this.sysdir() + "-build", "Sources")));
}
backend() {
return 'Kinc-hxcpp';
}
haxeOptions(name, targetOptions, defines) {
defines.push('no-compilation');
defines.push('include-prefix=hxinc');
if (!this.slowgc) {
defines.push('HXCPP_GC_GENERATIONAL');
}
defines.push('sys_' + this.options.target);
defines.push('sys_kore');
defines.push('sys_g1');
defines.push('sys_g2');
defines.push('sys_g3');
defines.push('sys_g4');
defines.push('sys_a1');
defines.push('sys_a2');
defines.push('kha_cpp');
defines.push('kha_' + this.options.target);
defines.push('kha_' + this.options.target + '_native');
defines.push('kha_' + this.options.target + '_cpp');
let graphics = this.options.graphics;
if (graphics === GraphicsApi_1.GraphicsApi.Default) {
graphics = defaults.graphicsApi(this.options.target);
}
defines.push('kha_' + graphics);
defines.push('kha_kore');
defines.push('kha_g1');
defines.push('kha_g2');
defines.push('kha_g3');
defines.push('kha_g4');
defines.push('kha_a1');
defines.push('kha_a2');
if (this.options.vr === 'gearvr') {
defines.push('vr_gearvr');
}
else if (this.options.vr === 'cardboard') {
defines.push('vr_cardboard');
}
else if (this.options.vr === 'rift') {
defines.push('vr_rift');
}
if (this.options.raytrace === 'dxr') {
defines.push('kha_dxr');
}
return {
from: this.options.from,
to: path.join(this.sysdir() + '-build', 'Sources'),
sources: this.sources,
libraries: this.libraries,
defines: defines,
parameters: this.parameters,
haxeDirectory: this.options.haxe,
system: this.sysdir(),
language: 'cpp',
width: this.width,
height: this.height,
name: name,
main: this.options.main,
};
}
async export(name, targetOptions, haxeOptions) {
}
async copySound(platform, from, to, options) {
if (options.quality < 1) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
return { files: [to + '.ogg'], sizes: [1] };
}
else {
if (from.endsWith('.wav')) {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
}
else {
throw 'Can not convert ' + from + ' to wav format.';
}
return { files: [to + '.wav'], sizes: [1] };
}
}
async copyImage(platform, from, to, options, cache) {
if (platform === Platform_1.Platform.iOS && options.quality < 1) {
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'pvr', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
else if (platform === Platform_1.Platform.Windows && options.quality < 1 && (this.options.graphics === GraphicsApi_1.GraphicsApi.OpenGL || this.options.graphics === GraphicsApi_1.GraphicsApi.Vulkan)) {
// let format = await exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'ASTC', true, false, cache);
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'DXT5', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
else {
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'lz4', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
}
async copyBlob(platform, from, to) {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to), { overwrite: true });
return { files: [to], sizes: [1] };
}
async copyVideo(platform, from, to) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
if (platform === Platform_1.Platform.Windows) {
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.avi'), this.options.h264);
return { files: [to + '.avi'], sizes: [1] };
}
else if (platform === Platform_1.Platform.iOS || platform === Platform_1.Platform.OSX) {
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.mp4'), this.options.h264);
return { files: [to + '.mp4'], sizes: [1] };
}
else if (platform === Platform_1.Platform.Android) {
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ts'), this.options.h264);
return { files: [to + '.ts'], sizes: [1] };
}
else {
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ogv'), this.options.theora);
return { files: [to + '.ogv'], sizes: [1] };
}
}
}
exports.KincExporter = KincExporter;
//# sourceMappingURL=KincExporter.js.map

View File

@ -1,124 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KincHLExporter = void 0;
const fs = require("fs-extra");
const path = require("path");
const defaults = require("../defaults");
const KhaExporter_1 = require("./KhaExporter");
const Converter_1 = require("../Converter");
const GraphicsApi_1 = require("../GraphicsApi");
const Platform_1 = require("../Platform");
const ImageTool_1 = require("../ImageTool");
class KincHLExporter extends KhaExporter_1.KhaExporter {
constructor(options) {
super(options);
// Files.removeDirectory(this.directory.resolve(Paths.get(this.sysdir() + "-build", "Sources")));
}
backend() {
return 'Kinc-HL';
}
haxeOptions(name, targetOptions, defines) {
defines.push('no-compilation');
defines.push('sys_' + this.options.target);
defines.push('sys_g1');
defines.push('sys_g2');
defines.push('sys_g3');
defines.push('sys_g4');
defines.push('sys_a1');
defines.push('sys_a2');
defines.push('kha_hl');
defines.push('kha_' + this.options.target);
defines.push('kha_' + this.options.target + '_hl');
let graphics = this.options.graphics;
if (graphics === GraphicsApi_1.GraphicsApi.Default) {
graphics = defaults.graphicsApi(this.options.target);
}
defines.push('kha_' + graphics);
defines.push('kha_g1');
defines.push('kha_g2');
defines.push('kha_g3');
defines.push('kha_g4');
defines.push('kha_a1');
defines.push('kha_a2');
if (this.options.vr === 'gearvr') {
defines.push('vr_gearvr');
}
else if (this.options.vr === 'cardboard') {
defines.push('vr_cardboard');
}
else if (this.options.vr === 'rift') {
defines.push('vr_rift');
}
if (this.options.raytrace === 'dxr') {
defines.push('kha_dxr');
}
return {
from: this.options.from,
to: path.join(this.sysdir() + '-build', 'sources.c'),
sources: this.sources,
libraries: this.libraries,
defines: defines,
parameters: this.parameters,
haxeDirectory: this.options.haxe,
system: this.sysdir(),
language: 'hl',
width: this.width,
height: this.height,
name: name,
main: this.options.main,
};
}
async export(name, targetOptions, haxeOptions) {
}
async copySound(platform, from, to, options) {
if (options.quality < 1) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
let ogg = await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
return { files: [to + '.ogg'], sizes: [1] };
}
else {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
return { files: [to + '.wav'], sizes: [1] };
}
}
async copyImage(platform, from, to, options, cache) {
if (platform === Platform_1.Platform.iOS && options.quality < 1) {
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'pvr', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
else if (platform === Platform_1.Platform.Windows && options.quality < 1 && (this.options.graphics === GraphicsApi_1.GraphicsApi.OpenGL || this.options.graphics === GraphicsApi_1.GraphicsApi.Vulkan)) {
// let format = await exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'ASTC', true, false, cache);
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'DXT5', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
else {
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'lz4', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
}
async copyBlob(platform, from, to) {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to).toString(), { overwrite: true });
return { files: [to], sizes: [1] };
}
async copyVideo(platform, from, to) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
if (platform === Platform_1.Platform.Windows) {
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.avi'), this.options.h264);
return { files: [to + '.avi'], sizes: [1] };
}
else if (platform === Platform_1.Platform.iOS || platform === Platform_1.Platform.OSX) {
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.mp4'), this.options.h264);
return { files: [to + '.mp4'], sizes: [1] };
}
else if (platform === Platform_1.Platform.Android) {
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ts'), this.options.h264);
return { files: [to + '.ts'], sizes: [1] };
}
else {
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ogv'), this.options.theora);
return { files: [to + '.ogv'], sizes: [1] };
}
}
}
exports.KincHLExporter = KincHLExporter;
//# sourceMappingURL=KincHLExporter.js.map

View File

@ -1,5 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KoreExporter = void 0;
const fs = require("fs-extra");
const path = require("path");
const defaults = require("../defaults");
@ -8,6 +9,7 @@ const Converter_1 = require("../Converter");
const GraphicsApi_1 = require("../GraphicsApi");
const Platform_1 = require("../Platform");
const ImageTool_1 = require("../ImageTool");
const log = require("../log");
class KoreExporter extends KhaExporter_1.KhaExporter {
constructor(options) {
super(options);
@ -15,7 +17,7 @@ class KoreExporter extends KhaExporter_1.KhaExporter {
// Files.removeDirectory(this.directory.resolve(Paths.get(this.sysdir() + "-build", "Sources")));
}
backend() {
return 'Kore';
return 'Kore-hxcpp';
}
haxeOptions(name, targetOptions, defines) {
defines.push('no-compilation');
@ -80,7 +82,7 @@ class KoreExporter extends KhaExporter_1.KhaExporter {
async copySound(platform, from, to, options) {
if (options.quality < 1) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
return { files: [to + '.ogg'], sizes: [1] };
}
else {
@ -88,23 +90,24 @@ class KoreExporter extends KhaExporter_1.KhaExporter {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
}
else {
throw 'Can not convert ' + from + ' to wav format.';
log.error('Can not convert ' + from + ' to wav format.\nSet `{quality: 0.99}` in `project.addAssets` if you want to convert your files to `ogg`.');
process.exit(1);
}
return { files: [to + '.wav'], sizes: [1] };
}
}
async copyImage(platform, from, to, options, cache) {
if (platform === Platform_1.Platform.iOS && options.quality < 1) {
let format = await ImageTool_1.exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'pvr', true, false, cache);
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'pvr', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
else if (platform === Platform_1.Platform.Windows && options.quality < 1 && (this.options.graphics === GraphicsApi_1.GraphicsApi.OpenGL || this.options.graphics === GraphicsApi_1.GraphicsApi.Vulkan)) {
// let format = await exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'ASTC', true, false, cache);
let format = await ImageTool_1.exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'DXT5', true, false, cache);
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'DXT5', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
else {
let format = await ImageTool_1.exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'lz4', true, false, cache);
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'lz4', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
}
@ -115,19 +118,19 @@ class KoreExporter extends KhaExporter_1.KhaExporter {
async copyVideo(platform, from, to) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
if (platform === Platform_1.Platform.Windows) {
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.avi'), this.options.h264);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.avi'), this.options.h264);
return { files: [to + '.avi'], sizes: [1] };
}
else if (platform === Platform_1.Platform.iOS || platform === Platform_1.Platform.OSX) {
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.mp4'), this.options.h264);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.mp4'), this.options.h264);
return { files: [to + '.mp4'], sizes: [1] };
}
else if (platform === Platform_1.Platform.Android) {
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.ts'), this.options.h264);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ts'), this.options.h264);
return { files: [to + '.ts'], sizes: [1] };
}
else {
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.ogv'), this.options.theora);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ogv'), this.options.theora);
return { files: [to + '.ogv'], sizes: [1] };
}
}

View File

@ -1,5 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KoreHLExporter = void 0;
const fs = require("fs-extra");
const path = require("path");
const defaults = require("../defaults");
@ -8,13 +9,14 @@ const Converter_1 = require("../Converter");
const GraphicsApi_1 = require("../GraphicsApi");
const Platform_1 = require("../Platform");
const ImageTool_1 = require("../ImageTool");
const log = require("../log");
class KoreHLExporter extends KhaExporter_1.KhaExporter {
constructor(options) {
super(options);
// Files.removeDirectory(this.directory.resolve(Paths.get(this.sysdir() + "-build", "Sources")));
}
backend() {
return 'KoreHL';
return 'Kore-HL';
}
haxeOptions(name, targetOptions, defines) {
defines.push('no-compilation');
@ -72,26 +74,32 @@ class KoreHLExporter extends KhaExporter_1.KhaExporter {
async copySound(platform, from, to, options) {
if (options.quality < 1) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
let ogg = await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
let ogg = await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
return { files: [to + '.ogg'], sizes: [1] };
}
else {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
if (from.endsWith('.wav')) {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
}
else {
log.error('Can not convert ' + from + ' to wav format.\nSet `{quality: 0.99}` in `project.addAssets` if you want to convert your files to `ogg`.');
process.exit(1);
}
return { files: [to + '.wav'], sizes: [1] };
}
}
async copyImage(platform, from, to, options, cache) {
if (platform === Platform_1.Platform.iOS && options.quality < 1) {
let format = await ImageTool_1.exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'pvr', true, false, cache);
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'pvr', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
else if (platform === Platform_1.Platform.Windows && options.quality < 1 && (this.options.graphics === GraphicsApi_1.GraphicsApi.OpenGL || this.options.graphics === GraphicsApi_1.GraphicsApi.Vulkan)) {
// let format = await exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'ASTC', true, false, cache);
let format = await ImageTool_1.exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'DXT5', true, false, cache);
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'DXT5', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
else {
let format = await ImageTool_1.exportImage(this.options.kha, from, path.join(this.options.to, this.sysdir(), to), options, 'lz4', true, false, cache);
let format = await (0, ImageTool_1.exportImage)(this.options.kha, this.options.kraffiti, from, path.join(this.options.to, this.sysdir(), to), options, 'lz4', true, false, cache);
return { files: [to + '.' + format], sizes: [1] };
}
}
@ -102,19 +110,19 @@ class KoreHLExporter extends KhaExporter_1.KhaExporter {
async copyVideo(platform, from, to) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
if (platform === Platform_1.Platform.Windows) {
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.avi'), this.options.h264);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.avi'), this.options.h264);
return { files: [to + '.avi'], sizes: [1] };
}
else if (platform === Platform_1.Platform.iOS || platform === Platform_1.Platform.OSX) {
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.mp4'), this.options.h264);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.mp4'), this.options.h264);
return { files: [to + '.mp4'], sizes: [1] };
}
else if (platform === Platform_1.Platform.Android) {
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.ts'), this.options.h264);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ts'), this.options.h264);
return { files: [to + '.ts'], sizes: [1] };
}
else {
await Converter_1.convert(from, path.join(this.options.to, this.sysdir(), to + '.ogv'), this.options.theora);
await (0, Converter_1.convert)(from, path.join(this.options.to, this.sysdir(), to + '.ogv'), this.options.theora);
return { files: [to + '.ogv'], sizes: [1] };
}
}

View File

@ -8,6 +8,7 @@ const KhaExporter_1 = require("./KhaExporter");
const Converter_1 = require("../Converter");
const GraphicsApi_1 = require("../GraphicsApi");
const ImageTool_1 = require("../ImageTool");
const log = require("../log");
class KromExporter extends KhaExporter_1.KhaExporter {
constructor(options) {
super(options);
@ -68,7 +69,13 @@ class KromExporter extends KhaExporter_1.KhaExporter {
return { files: [to + '.ogg'], sizes: [1] };
}
else {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
if (from.endsWith('.wav')) {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
}
else {
log.error('Can not convert ' + from + ' to wav format.\nSet `{quality: 0.99}` in `project.addAssets` if you want to convert your files to `ogg`.');
process.exit(1);
}
return { files: [to + '.wav'], sizes: [1] };
}
}

View File

@ -61,7 +61,9 @@ class HaxeCompiler {
this.scheduleCompile();
});
this.startCompilationServer();
this.triggerCompilationServer();
setTimeout(() => {
this.triggerCompilationServer();
}, 50);
}
else {
try {
@ -176,9 +178,11 @@ class HaxeCompiler {
process.stdout.write('\x1Bc');
log.info('Haxe compile end.');
if (this.isLiveReload) {
this.wsClients.forEach(client => {
client.send(JSON.stringify({}));
});
setTimeout(() => {
this.wsClients.forEach(client => {
client.send(JSON.stringify({}));
});
}, 200);
}
for (let callback of ProjectFile_1.Callbacks.postHaxeRecompilation) {
callback();
@ -216,14 +220,6 @@ class HaxeCompiler {
});
});
}
static spinRename(from, to) {
for (;;) {
if (fs.existsSync(from)) {
fs.renameSync(from, to);
return;
}
}
}
}
exports.HaxeCompiler = HaxeCompiler;
//# sourceMappingURL=HaxeCompiler.js.map

View File

@ -112,12 +112,14 @@ function hxml(projectdir, options) {
data += unique('-cp ' + path.relative(projectdir, path.resolve(options.from, options.sources[i])) + '\n'); // from.resolve('build').relativize(from.resolve(this.sources[i])).toString());
}
}
for (let i = 0; i < options.libraries.length; ++i) {
if (path.isAbsolute(options.libraries[i].libpath)) {
data += unique('-cp ' + options.libraries[i].libpath + '\n');
for (const lib of options.libraries) {
if (lib.classPathIsAdded)
continue;
if (path.isAbsolute(lib.libpath)) {
data += unique('-cp ' + lib.libpath + '\n');
}
else {
data += unique('-cp ' + path.relative(projectdir, path.resolve(options.from, options.libraries[i].libpath)) + '\n'); // from.resolve('build').relativize(from.resolve(this.sources[i])).toString());
data += unique('-cp ' + path.relative(projectdir, path.resolve(options.from, lib.libpath)) + '\n'); // from.resolve('build').relativize(from.resolve(this.sources[i])).toString());
}
}
for (let d in options.defines) {

View File

@ -38,7 +38,7 @@ function findIcon(icon, from, options) {
if (fs.existsSync(path.join(from, 'icon.png')))
return path.join(from, 'icon.png');
else
return path.join(options.kha, 'Kinc', 'Tools', exec.sysdir(), 'icon.png');
return path.join(options.kha, 'Kore', 'Tools', exec.sysdir(), 'icon.png');
}
function exportIco(icon, to, from, options) {
run(options.kraffiti, findIcon(icon, from.toString(), options), to.toString(), 0, 0, 'ico', undefined, false, function () { });

View File

@ -7,6 +7,13 @@ const path = require("path");
const log = require("./log");
const ProjectFile_1 = require("./ProjectFile");
class Library {
constructor() {
/**
* If haxelib `classPath` is specified,
* we don't add `libpath` as `-cp` to `hxml`.
*/
this.classPathIsAdded = false;
}
}
exports.Library = Library;
class Target {
@ -66,7 +73,7 @@ class Project {
if (!path.isAbsolute(projectDir)) {
projectDir = path.join(this.scriptdir, projectDir);
}
if (!fs.existsSync(path.join(projectDir, 'khafile.js')) && (fs.existsSync(path.join(projectDir, 'kincfile.js')) || fs.existsSync(path.join(projectDir, 'korefile.js')) || fs.existsSync(path.join(projectDir, 'kfile.js')))) {
if (!fs.existsSync(path.join(projectDir, 'khafile.js')) && (fs.existsSync(path.join(projectDir, 'kfile.js')) || fs.existsSync(path.join(projectDir, 'korefile.js')) || fs.existsSync(path.join(projectDir, 'kincfile.js')))) {
this.libraries.push({
libpath: projectDir,
libroot: projectDir
@ -176,14 +183,13 @@ class Project {
}
addLibrary(library) {
this.addDefine(library);
let self = this;
function findLibraryDirectory(name) {
const findLibraryDirectory = (name) => {
if (path.isAbsolute(name)) {
return { libpath: name, libroot: name };
}
// Tries to load the default library from inside the kha project.
// e.g. 'Libraries/wyngine'
let libpath = path.join(self.scriptdir, self.localLibraryPath, name);
let libpath = path.join(this.scriptdir, this.localLibraryPath, name);
if (fs.existsSync(libpath) && fs.statSync(libpath).isDirectory()) {
let dir = path.resolve(libpath);
return { libpath: dir, libroot: dir };
@ -223,7 +229,7 @@ class Project {
log.error('Error: Library ' + name + ' not found.');
log.error('Add it to the \'Libraries\' subdirectory of your project. You may also install it via haxelib but that\'s less cool.');
throw 'Library ' + name + ' not found.';
}
};
let libInfo = findLibraryDirectory(library);
let dir = libInfo.libpath;
if (dir !== '') {
@ -231,17 +237,18 @@ class Project {
if (elem.libroot === libInfo.libroot)
return '';
}
this.libraries.push({
const lib = {
libpath: dir,
libroot: libInfo.libroot
});
};
this.libraries.push(lib);
// If this is a haxelib library, there must be a haxelib.json
if (fs.existsSync(path.join(dir, 'haxelib.json'))) {
let options = JSON.parse(fs.readFileSync(path.join(dir, 'haxelib.json'), 'utf8'));
// If there is a classPath value, add that directory to be loaded.
// Otherwise, just load the current path.
if (options.classPath) {
// TODO find an example haxelib that has a classPath value
lib.classPathIsAdded = true;
this.sources.push(path.join(dir, options.classPath));
}
else {

View File

@ -197,14 +197,13 @@ class ShaderCompiler {
this.watcher.on('ready', async () => {
ready = true;
let compiledShaders = [];
const self = this;
async function compile(shader, index) {
const compile = async (shader, index) => {
let parsed = path.parse(shader);
if (self.isSupported(shader)) {
if (this.isSupported(shader)) {
log.info('Compiling shader ' + (index + 1) + ' of ' + shaders.length + ' (' + parsed.base + ').');
let compiledShader = null;
try {
compiledShader = await self.compileShader(shader, options, recompileAll);
compiledShader = await this.compileShader(shader, options, recompileAll);
}
catch (error) {
log.error('Compiling shader ' + (index + 1) + ' of ' + shaders.length + ' (' + parsed.base + ') failed:');
@ -223,9 +222,9 @@ class ShaderCompiler {
}
if (compiledShader.files != null && compiledShader.files.length === 0) {
// TODO: Remove when krafix has been recompiled everywhere
compiledShader.files.push(parsed.name + '.' + self.type);
compiledShader.files.push(parsed.name + '.' + this.type);
}
compiledShader.name = AssetConverter_1.AssetConverter.createExportInfo(parsed, false, options, self.exporter.options.from).name;
compiledShader.name = AssetConverter_1.AssetConverter.createExportInfo(parsed, false, options, this.exporter.options.from).name;
compiledShaders.push(compiledShader);
}
else {
@ -233,7 +232,7 @@ class ShaderCompiler {
}
++index;
return Promise.resolve();
}
};
if (this.options.parallelAssetConversion !== 0) {
let todo = shaders.map((shader, index) => {
return async () => {

View File

@ -29,7 +29,12 @@ function sysdir() {
return 'freebsd_x64';
}
else {
return 'macos';
if (os.arch() === 'arm64')
return 'macos_arm64';
else if (os.arch() === 'x64')
return 'macos_x64';
else
throw 'Unsupported CPU';
}
}
exports.sysdir = sysdir;

View File

@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.get = exports.init = void 0;
const path = require("path");
const exec_1 = require("./exec");
let korepath = path.join(__dirname, '..', '..', '..', 'Kinc', 'Tools', (0, exec_1.sysdir)());
let korepath = path.join(__dirname, '..', '..', '..', 'Kore', 'Tools', (0, exec_1.sysdir)());
function init(options) {
korepath = path.join(options.kha, 'Kinc', 'Tools', (0, exec_1.sysdir)());
korepath = path.join(options.kha, 'Kore', 'Tools', (0, exec_1.sysdir)());
}
exports.init = init;
function get() {

View File

@ -18,8 +18,8 @@ const FlashExporter_1 = require("./Exporters/FlashExporter");
const Html5Exporter_1 = require("./Exporters/Html5Exporter");
const Html5WorkerExporter_1 = require("./Exporters/Html5WorkerExporter");
const JavaExporter_1 = require("./Exporters/JavaExporter");
const KincExporter_1 = require("./Exporters/KincExporter");
const KincHLExporter_1 = require("./Exporters/KincHLExporter");
const KoreExporter_1 = require("./Exporters/KoreExporter");
const KoreHLExporter_1 = require("./Exporters/KoreHLExporter");
const KromExporter_1 = require("./Exporters/KromExporter");
const NodeExporter_1 = require("./Exporters/NodeExporter");
const PlayStationMobileExporter_1 = require("./Exporters/PlayStationMobileExporter");
@ -78,12 +78,12 @@ function createKorefile(name, exporter, options, targetOptions, libraries, cdefi
let buildpath = path.relative(options.from, path.join(options.to, exporter.sysdir() + '-build')).replace(/\\/g, '/');
if (buildpath.startsWith('..'))
buildpath = path.resolve(path.join(options.from.toString(), buildpath));
out += 'await project.addProject(\'' + path.join(options.kha, 'Kinc').replace(/\\/g, '/') + '\');\n';
out += 'await project.addProject(\'' + path.join(options.kha, 'Kore').replace(/\\/g, '/') + '\');\n';
out += 'await project.addProject(\'' + buildpath.replace(/\\/g, '/') + '\');\n';
if (korehl)
out += 'await project.addProject(\'' + path.join(options.kha, 'Backends', 'Kinc-HL').replace(/\\/g, '/') + '\');\n';
out += 'await project.addProject(\'' + path.join(options.kha, 'Backends', 'Kore-HL').replace(/\\/g, '/') + '\');\n';
else
out += 'await project.addProject(\'' + path.join(options.kha, 'Backends', 'Kinc-hxcpp').replace(/\\/g, '/') + '\');\n';
out += 'await project.addProject(\'' + path.join(options.kha, 'Backends', 'Kore-hxcpp').replace(/\\/g, '/') + '\');\n';
for (let lib of libraries) {
let libPath = lib.libpath.replace(/\\/g, '/');
out += 'if (fs.existsSync(path.join(\'' + libPath + '\', \'kfile.js\')) || fs.existsSync(path.join(\'' + libPath + '\', \'kincfile.js\')) || fs.existsSync(path.join(\'' + libPath + '\', \'korefile.js\'))) {\n';
@ -153,11 +153,10 @@ async function exportProjectFiles(name, resourceDir, options, exporter, kore, ko
let buildDir = path.join(options.to, exporter.sysdir() + '-build');
if (options.haxe !== '' && kore && !options.noproject) {
// If target is a Kore project, generate additional project folders here.
// generate the kincfile.js
// generate the kfile.js
fs.copySync(path.join(__dirname, '..', 'Data', 'hxcpp', 'kfile.js'), path.join(buildDir, 'kfile.js'), { overwrite: true });
fs.writeFileSync(path.join(options.to, 'kfile.js'), createKorefile(name, exporter, options, targetOptions, libraries, cdefines, cflags, cppflags, stackSize, version, id, false, icon));
// Similar to khamake.js -> main.js -> run(...)
// We now do kincmake.js -> main.js -> run(...)
// This will create additional project folders for the target,
// e.g. 'build/pi-build'
try {
@ -251,7 +250,7 @@ function checkKorePlatform(platform) {
|| platform === 'ps4'
|| platform === 'xboxone'
|| platform === 'switch'
|| platform === 'xboxscarlett'
|| platform === 'xboxseries'
|| platform === 'ps5'
|| platform === 'freebsd';
}
@ -332,7 +331,7 @@ async function exportKhaProject(options) {
log.error(`Unknown platform: ${target} (baseTarget=$${baseTarget})`);
return Promise.reject('');
}
exporter = new KincHLExporter_1.KincHLExporter(options);
exporter = new KoreHLExporter_1.KoreHLExporter(options);
}
else {
kore = true;
@ -341,7 +340,7 @@ async function exportKhaProject(options) {
log.error(`Unknown platform: ${target} (baseTarget=$${baseTarget})`);
return Promise.reject('');
}
exporter = new KincExporter_1.KincExporter(options);
exporter = new KoreExporter_1.KoreExporter(options);
}
break;
}
@ -612,16 +611,28 @@ async function run(options, loglog) {
let haxepath = path.join(options.kha, 'Tools', (0, exec_1.sysdir)());
if (fs.existsSync(haxepath) && fs.statSync(haxepath).isDirectory())
options.haxe = haxepath;
else
log.error('Haxe not found at ' + haxepath);
}
else {
log.info('Using Haxe from ' + options.haxe);
}
if (!options.krafix) {
let krafixpath = path.join(options.kha, 'Kinc', 'Tools', (0, exec_1.sysdir)(), 'krafix' + (0, exec_1.sys)());
let krafixpath = path.join(options.kha, 'Kore', 'Tools', (0, exec_1.sysdir)(), 'krafix' + (0, exec_1.sys)());
if (fs.existsSync(krafixpath))
options.krafix = krafixpath;
else
log.error('krafix not found at ' + krafixpath);
}
else {
log.info('Using krafix from ' + options.krafix);
}
if (!options.kraffiti) {
const kraffitipath = path.join(options.kha, 'Kinc', 'Tools', (0, exec_1.sysdir)(), 'kraffiti' + (0, exec_1.sys)());
const kraffitipath = path.join(options.kha, 'Kore', 'Tools', (0, exec_1.sysdir)(), 'kraffiti' + (0, exec_1.sys)());
if (fs.existsSync(kraffitipath))
options.kraffiti = kraffitipath;
else
log.error('kraffiti not found at ' + kraffitipath);
}
else {
log.info('Using kraffiti from ' + options.kraffiti);
@ -636,11 +647,15 @@ async function run(options, loglog) {
let oggpath = path.join(options.kha, 'Tools', (0, exec_1.sysdir)(), 'oggenc' + (0, exec_1.sys)());
if (fs.existsSync(oggpath))
options.ogg = oggpath + ' {in} -o {out} --quiet';
else
log.error('oggenc not found at ' + oggpath);
}
if (!options.mp3) {
let lamepath = path.join(options.kha, 'Tools', (0, exec_1.sysdir)(), 'lame' + (0, exec_1.sys)());
if (fs.existsSync(lamepath))
options.mp3 = lamepath + ' {in} {out}';
else
log.error('lame not found at ' + lamepath);
}
// if (!options.kravur) {
// let kravurpath = path.join(options.kha, 'Tools', 'kravur', 'kravur' + sys());
@ -662,8 +677,7 @@ async function run(options, loglog) {
options.theora = options.ffmpeg + ' -nostdin -i {in} {out}';
}
if (options.target === 'emscripten') {
console.log();
console.log('Please note that the html5 target\n'
log.info('\nPlease note that the html5 target\n'
+ 'is usually a better choice.\n'
+ 'In particular the html5 target usually runs faster\n'
+ 'than the emscripten target. That is because\n'
@ -672,8 +686,7 @@ async function run(options, loglog) {
+ 'all of the optimizations in modern JavaScript\n'
+ 'runtimes. The emscripten target on the other hand\n'
+ 'has to provide its own garbage collector and many\n'
+ 'other performance critical pieces of infrastructure.');
console.log();
+ 'other performance critical pieces of infrastructure.\n');
}
let name = '';
try {

View File

@ -16,7 +16,7 @@
"fs-extra": "^6.0.0",
"node-static": "^0.7.10",
"uuid": "^3.2.1",
"ws": "^8.3.0"
"ws": "^8.17.1"
},
"devDependencies": {
"promise-parallel-throttle": "^3.1.0",
@ -65,11 +65,11 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@ -110,9 +110,9 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@ -332,15 +332,15 @@
}
},
"node_modules/ws": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {

View File

@ -27,7 +27,7 @@
"fs-extra": "^6.0.0",
"node-static": "^0.7.10",
"uuid": "^3.2.1",
"ws": "^8.3.0"
"ws": "^8.17.1"
},
"devDependencies": {
"promise-parallel-throttle": "^3.1.0",

View File

@ -7,15 +7,16 @@ import * as chokidar from 'chokidar';
import * as crypto from 'crypto';
import * as Throttle from 'promise-parallel-throttle';
import { Options } from './Options';
import { AssetMatcher, AssetMatcherOptions } from './Project';
export class AssetConverter {
options: Options;
exporter: KhaExporter;
platform: string;
assetMatchers: Array<{ match: string, options: any }>;
assetMatchers: Array<AssetMatcher>;
watcher: fs.FSWatcher;
constructor(exporter: KhaExporter, options: Options, assetMatchers: Array<{ match: string, options: any }>) {
constructor(exporter: KhaExporter, options: Options, assetMatchers: Array<AssetMatcher>) {
this.exporter = exporter;
this.options = options;
this.platform = options.target;
@ -26,7 +27,7 @@ export class AssetConverter {
if (this.watcher) this.watcher.close();
}
static replacePattern(pattern: string, name: string, fileinfo: path.ParsedPath, options: any, from: string) {
static replacePattern(pattern: string, name: string, fileinfo: path.ParsedPath, options: AssetMatcherOptions, from: string) {
let basePath: string = options.nameBaseDir ? path.join(from, options.nameBaseDir) : from;
let dirValue: string = path.relative(basePath, fileinfo.dir);
if (basePath.length > 0 && basePath[basePath.length - 1] === path.sep
@ -44,7 +45,7 @@ export class AssetConverter {
return pattern.replace(/{name}/g, name).replace(/{ext}/g, fileinfo.ext).replace(dirRegex, dirValue);
}
static createExportInfo(fileinfo: path.ParsedPath, keepextension: boolean, options: any, from: string): {name: string, destination: string} {
static createExportInfo(fileinfo: path.ParsedPath, keepextension: boolean, options: AssetMatcherOptions, from: string): {name: string, destination: string} {
let nameValue = fileinfo.name;
let destination = fileinfo.name;
@ -77,7 +78,28 @@ export class AssetConverter {
return {name: nameValue, destination: destination};
}
watch(watch: boolean, match: string, temp: string, options: any): Promise<{ name: string, from: string, type: string, files: string[], file_sizes: number[], original_width: number, original_height: number, readable: boolean }[]> {
canDecodeFormat(ext: string): boolean {
// without ffmpeg we need to encode mp3 and ogg files
const hasFFmpeg = !!this.options.ffmpeg;
const hasFFmpegOgg = this.options.ogg?.includes('ffmpeg') ?? false;
const hasFFmpegMp3 = this.options.mp3?.includes('ffmpeg') ?? false;
const hasFFmpegAac = this.options.aac?.includes('ffmpeg') ?? false;
switch (ext) {
case '.wav':
return true;
case '.ogg':
return hasFFmpeg || (hasFFmpegOgg && (hasFFmpegMp3 || hasFFmpegAac));
case '.mp3':
// lame can decode mp3, so we only need ogg ffmpeg encoder
return hasFFmpeg || (hasFFmpegOgg && !!this.options.mp3);
case '.flac':
return hasFFmpeg;
default:
return false;
}
}
watch(watch: boolean, match: string, temp: string, options: AssetMatcherOptions): Promise<{ name: string, from: string, type: string, files: string[], file_sizes: number[], original_width: number, original_height: number, readable: boolean }[]> {
return new Promise<{ name: string, from: string, type: string, files: string[], file_sizes: number[], original_width: number, original_height: number, readable: boolean }[]>((resolve, reject) => {
let ready = false;
let files: string[] = [];
@ -88,11 +110,15 @@ export class AssetConverter {
let outPath = fileinfo.name;
// with subfolders
if (options.destination) {
const from = path.resolve(options.baseDir, '..');
// remove trailing slash
const nameBaseDir = options.nameBaseDir.replace(/\/$/, '');
const lastIndex = options.baseDir.lastIndexOf(nameBaseDir)
const from = path.resolve(options.baseDir.substring(0, lastIndex));
outPath = AssetConverter.replacePattern(options.destination, fileinfo.name, fileinfo, options, from);
}
log.info('Reexporting ' + outPath + fileinfo.ext);
switch (fileinfo.ext) {
const ext = fileinfo.ext.toLowerCase();
log.info('Reexporting ' + outPath + ext);
switch (ext) {
case '.png':
case '.jpg':
case '.jpeg':
@ -104,6 +130,9 @@ export class AssetConverter {
case '.mp3':
case '.flac':
case '.wav': {
if (!this.canDecodeFormat(ext)) {
log.error(`Error: ${fileinfo.base} should be in wav format, or use \`--ffmpeg path/to/ffmpeg\` option to convert ogg/mp3/flac files`);
}
await this.exporter.copySound(this.platform, file, outPath, {});
break;
}
@ -122,10 +151,10 @@ export class AssetConverter {
break;
default:
await this.exporter.copyBlob(this.platform, file, outPath + fileinfo.ext, {});
await this.exporter.copyBlob(this.platform, file, outPath + ext, {});
}
for (let callback of Callbacks.postAssetReexporting) {
callback(outPath + fileinfo.ext);
callback(outPath + ext);
}
};
@ -153,9 +182,7 @@ export class AssetConverter {
cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
}
const self = this;
async function convertAsset( file: string, index: number ) {
const convertAsset = async (file: string, index: number) => {
let fileinfo = path.parse(file);
log.info('Exporting asset ' + (index + 1) + ' of ' + files.length + ' (' + fileinfo.base + ').');
const ext = fileinfo.ext.toLowerCase();
@ -164,13 +191,13 @@ export class AssetConverter {
case '.jpg':
case '.jpeg':
case '.hdr': {
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, self.exporter.options.from);
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
let images: { files: string[], sizes: number[] };
if (options.noprocessing) {
images = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
images = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
}
else {
images = await self.exporter.copyImage(self.platform, file, exportInfo.destination, options, cache);
images = await this.exporter.copyImage(this.platform, file, exportInfo.destination, options, cache);
}
if (!options.notinlist) {
parsedFiles.push({ name: exportInfo.name, from: file, type: 'image', files: images.files, file_sizes: images.sizes, original_width: options.original_width, original_height: options.original_height, readable: options.readable });
@ -181,13 +208,17 @@ export class AssetConverter {
case '.mp3':
case '.flac':
case '.wav': {
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, self.exporter.options.from);
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
let sounds: { files: string[], sizes: number[] };
if (options.noprocessing) {
sounds = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
sounds = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
}
else {
sounds = await self.exporter.copySound(self.platform, file, exportInfo.destination, options);
if (!this.canDecodeFormat(ext)) {
log.error(`Error: ${fileinfo.base} should be in wav format, or use \`--ffmpeg\` option to convert ogg/mp3/flac files`);
process.exit(1);
}
sounds = await this.exporter.copySound(this.platform, file, exportInfo.destination, options);
}
if (sounds.files.length === 0) {
throw 'Audio file ' + file + ' could not be exported, you have to specify a path to ffmpeg.';
@ -198,13 +229,13 @@ export class AssetConverter {
break;
}
case '.ttf': {
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, self.exporter.options.from);
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
let fonts: { files: string[], sizes: number[] };
if (options.noprocessing) {
fonts = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
fonts = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
}
else {
fonts = await self.exporter.copyFont(self.platform, file, exportInfo.destination, options);
fonts = await this.exporter.copyFont(this.platform, file, exportInfo.destination, options);
}
if (!options.notinlist) {
parsedFiles.push({ name: exportInfo.name, from: file, type: 'font', files: fonts.files, file_sizes: fonts.sizes, original_width: undefined, original_height: undefined, readable: undefined });
@ -216,13 +247,13 @@ export class AssetConverter {
case '.mov':
case '.wmv':
case '.avi': {
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, self.exporter.options.from);
let exportInfo = AssetConverter.createExportInfo(fileinfo, false, options, this.exporter.options.from);
let videos: { files: string[], sizes: number[] };
if (options.noprocessing) {
videos = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
videos = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
}
else {
videos = await self.exporter.copyVideo(self.platform, file, exportInfo.destination, options);
videos = await this.exporter.copyVideo(this.platform, file, exportInfo.destination, options);
}
if (videos.files.length === 0) {
log.error('Video file ' + file + ' could not be exported, you have to specify a path to ffmpeg.');
@ -233,8 +264,8 @@ export class AssetConverter {
break;
}
default: {
let exportInfo = AssetConverter.createExportInfo(fileinfo, true, options, self.exporter.options.from);
let blobs = await self.exporter.copyBlob(self.platform, file, exportInfo.destination, options);
let exportInfo = AssetConverter.createExportInfo(fileinfo, true, options, this.exporter.options.from);
let blobs = await this.exporter.copyBlob(this.platform, file, exportInfo.destination, options);
if (!options.notinlist) {
parsedFiles.push({ name: exportInfo.name, from: file, type: 'blob', files: blobs.files, file_sizes: blobs.sizes, original_width: undefined, original_height: undefined, readable: undefined });
}

View File

@ -36,6 +36,9 @@ export function convert(inFilename: string, outFilename: string, encoder: string
else if (parts[i] === '{out}') options.push(outFilename.toString());
else options.push(parts[i]);
}
if (fs.existsSync(outFilename.toString())) {
fs.unlinkSync(outFilename.toString());
}
// About stdio ignore: https://stackoverflow.com/a/20792428
let process = child_process.spawn(exe, options, {stdio: 'ignore'});
process.on('close', (code: number) => {

View File

@ -5,7 +5,7 @@ import {convert} from '../Converter';
import {executeHaxe} from '../Haxe';
import {Options} from '../Options';
import {exportImage} from '../ImageTool';
import {Library} from '../Project';
import {AssetMatcherOptions, Library} from '../Project';
import {VrApi} from '../VrApi';
export class Html5Exporter extends KhaExporter {
@ -215,7 +215,7 @@ export class Html5Exporter extends KhaExporter {
});
}*/
async copySound(platform: string, from: string, to: string, options: any) {
async copySound(platform: string, from: string, to: string, options: AssetMatcherOptions) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
let ogg = await convert(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
let ogg_size = (await fs.stat(path.join(this.options.to, this.sysdir(), to + '.ogg'))).size;

View File

@ -8,9 +8,10 @@ import {GraphicsApi} from '../GraphicsApi';
import {Platform} from '../Platform';
import {exportImage} from '../ImageTool';
import {Options} from '../Options';
import {Library} from '../Project';
import {AssetMatcherOptions, Library} from '../Project';
import * as log from '../log';
export class KincExporter extends KhaExporter {
export class KoreExporter extends KhaExporter {
slowgc: boolean;
constructor(options: Options) {
@ -20,7 +21,7 @@ export class KincExporter extends KhaExporter {
}
backend(): string {
return 'Kinc-hxcpp';
return 'Kore-hxcpp';
}
haxeOptions(name: string, targetOptions: any, defines: Array<string>) {
@ -92,7 +93,7 @@ export class KincExporter extends KhaExporter {
}
async copySound(platform: string, from: string, to: string, options: any) {
async copySound(platform: string, from: string, to: string, options: AssetMatcherOptions) {
if (options.quality < 1) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
await convert(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
@ -103,7 +104,8 @@ export class KincExporter extends KhaExporter {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
}
else {
throw 'Can not convert ' + from + ' to wav format.';
log.error('Can not convert ' + from + ' to wav format.\nSet `{quality: 0.99}` in `project.addAssets` if you want to convert your files to `ogg`.');
process.exit(1);
}
return { files: [to + '.wav'], sizes: [1] };
}

View File

@ -8,16 +8,17 @@ import {GraphicsApi} from '../GraphicsApi';
import {Platform} from '../Platform';
import {exportImage} from '../ImageTool';
import {Options} from '../Options';
import {Library} from '../Project';
import {AssetMatcher, AssetMatcherOptions, Library} from '../Project';
import * as log from '../log';
export class KincHLExporter extends KhaExporter {
export class KoreHLExporter extends KhaExporter {
constructor(options: Options) {
super(options);
// Files.removeDirectory(this.directory.resolve(Paths.get(this.sysdir() + "-build", "Sources")));
}
backend(): string {
return 'Kinc-HL';
return 'Kore-HL';
}
haxeOptions(name: string, targetOptions: any, defines: Array<string>) {
@ -81,14 +82,20 @@ export class KincHLExporter extends KhaExporter {
}
async copySound(platform: string, from: string, to: string, options: any) {
async copySound(platform: string, from: string, to: string, options: AssetMatcherOptions) {
if (options.quality < 1) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
let ogg = await convert(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
return { files: [to + '.ogg'], sizes: [1] };
}
else {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
if (from.endsWith('.wav')) {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
}
else {
log.error('Can not convert ' + from + ' to wav format.\nSet `{quality: 0.99}` in `project.addAssets` if you want to convert your files to `ogg`.');
process.exit(1);
}
return { files: [to + '.wav'], sizes: [1] };
}
}

View File

@ -7,7 +7,8 @@ import {executeHaxe} from '../Haxe';
import {GraphicsApi} from '../GraphicsApi';
import {Options} from '../Options';
import {exportImage} from '../ImageTool';
import {Library} from '../Project';
import {AssetMatcherOptions, Library} from '../Project';
import * as log from '../log';
export class KromExporter extends KhaExporter {
width: number;
@ -72,14 +73,20 @@ export class KromExporter extends KhaExporter {
fs.ensureDirSync(path.join(this.options.to, this.sysdir()));
}
async copySound(platform: string, from: string, to: string, options: any) {
async copySound(platform: string, from: string, to: string, options: AssetMatcherOptions) {
if (options.quality < 1) {
fs.ensureDirSync(path.join(this.options.to, this.sysdir(), path.dirname(to)));
let ogg = await convert(from, path.join(this.options.to, this.sysdir(), to + '.ogg'), this.options.ogg);
return { files: [to + '.ogg'], sizes: [1] };
}
else {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
if (from.endsWith('.wav')) {
fs.copySync(from.toString(), path.join(this.options.to, this.sysdir(), to + '.wav'), { overwrite: true });
}
else {
log.error('Can not convert ' + from + ' to wav format.\nSet `{quality: 0.99}` in `project.addAssets` if you want to convert your files to `ogg`.');
process.exit(1);
}
return { files: [to + '.wav'], sizes: [1] };
}
}

View File

@ -71,7 +71,9 @@ export class HaxeCompiler {
this.scheduleCompile();
});
this.startCompilationServer();
this.triggerCompilationServer();
setTimeout(() => {
this.triggerCompilationServer();
}, 50);
}
else {
try {
@ -196,9 +198,11 @@ export class HaxeCompiler {
process.stdout.write('\x1Bc');
log.info('Haxe compile end.');
if (this.isLiveReload) {
this.wsClients.forEach(client => {
client.send(JSON.stringify({}));
});
setTimeout(() => {
this.wsClients.forEach(client => {
client.send(JSON.stringify({}));
});
}, 200);
}
for (let callback of Callbacks.postHaxeRecompilation) {
callback();
@ -238,13 +242,4 @@ export class HaxeCompiler {
});
});
}
private static spinRename(from: string, to: string): void {
for (; ; ) {
if (fs.existsSync(from)) {
fs.renameSync(from, to);
return;
}
}
}
}

View File

@ -110,7 +110,7 @@ function hxml(projectdir: string, options: any) {
if (lines.indexOf(line) === -1) {
lines.push(line);
return line;
}
}
return '';
}
@ -122,12 +122,13 @@ function hxml(projectdir: string, options: any) {
data += unique('-cp ' + path.relative(projectdir, path.resolve(options.from, options.sources[i])) + '\n'); // from.resolve('build').relativize(from.resolve(this.sources[i])).toString());
}
}
for (let i = 0; i < options.libraries.length; ++i) {
if (path.isAbsolute(options.libraries[i].libpath)) {
data += unique('-cp ' + options.libraries[i].libpath + '\n');
for (const lib of options.libraries) {
if (lib.classPathIsAdded) continue
if (path.isAbsolute(lib.libpath)) {
data += unique('-cp ' + lib.libpath + '\n');
}
else {
data += unique('-cp ' + path.relative(projectdir, path.resolve(options.from, options.libraries[i].libpath)) + '\n'); // from.resolve('build').relativize(from.resolve(this.sources[i])).toString());
data += unique('-cp ' + path.relative(projectdir, path.resolve(options.from, lib.libpath)) + '\n'); // from.resolve('build').relativize(from.resolve(this.sources[i])).toString());
}
}
for (let d in options.defines) {
@ -170,7 +171,7 @@ function hxml(projectdir: string, options: any) {
if (!options.parameters.some((param: string) => param.includes('-main '))) {
const entrypoint = options ? options.main ? options.main : 'Main' : 'Main';
data += unique('-main ' + entrypoint + '\n');
data += unique('-main ' + entrypoint + '\n');
}
fs.outputFileSync(path.join(projectdir, 'project-' + options.system + '.hxml'), data);

View File

@ -34,7 +34,7 @@ function run(exe: string, from: string, to: string, width: number, height: numbe
function findIcon(icon: string, from: string, options: any) {
if (icon && fs.existsSync(path.join(from, icon))) return path.join(from, icon);
if (fs.existsSync(path.join(from, 'icon.png'))) return path.join(from, 'icon.png');
else return path.join(options.kha, 'Kinc', 'Tools', exec.sysdir(), 'icon.png');
else return path.join(options.kha, 'Kore', 'Tools', exec.sysdir(), 'icon.png');
}
export function exportIco(icon: string, to: string, from: string, options: any) {

View File

@ -7,6 +7,11 @@ import {loadProject} from './ProjectFile';
export class Library {
libpath: string;
libroot: string;
/**
* If haxelib `classPath` is specified,
* we don't add `libpath` as `-cp` to `hxml`.
*/
classPathIsAdded? = false;
}
export class Target {
@ -29,6 +34,26 @@ function contains(main: string, sub: string) {
return sub.indexOf(main) === 0 && sub.slice(main.length)[0] === path.sep;
}
export type AssetMatcherOptions = {
name?: string;
nameBaseDir?: string;
baseDir?: string;
namePathSeparator?: string;
destination?: string;
destinationCallback?: (destination: string) => string;
quality?: number;
noprocessing?: boolean;
notinlist?: boolean;
md5sum?: string;
original_height?: number;
original_width?: number;
readable?: boolean;
}
export type AssetMatcher = { match: string, options: AssetMatcherOptions }
export class Project {
static platform: string;
static scriptdir: string;
@ -46,7 +71,7 @@ export class Project {
localLibraryPath: string;
windowOptions: any;
targetOptions: any;
assetMatchers: { match: string, options: any }[];
assetMatchers: AssetMatcher[];
shaderMatchers: { match: string, options: any }[];
customTargets: Map<string, Target>;
stackSize: number;
@ -95,7 +120,7 @@ export class Project {
if (!path.isAbsolute(projectDir)) {
projectDir = path.join(this.scriptdir, projectDir);
}
if (!fs.existsSync(path.join(projectDir, 'khafile.js')) && (fs.existsSync(path.join(projectDir, 'kincfile.js')) || fs.existsSync(path.join(projectDir, 'korefile.js')) || fs.existsSync(path.join(projectDir, 'kfile.js')))) {
if (!fs.existsSync(path.join(projectDir, 'khafile.js')) && (fs.existsSync(path.join(projectDir, 'kfile.js')) || fs.existsSync(path.join(projectDir, 'korefile.js')) || fs.existsSync(path.join(projectDir, 'kincfile.js')))) {
this.libraries.push({
libpath: projectDir,
libroot: projectDir
@ -151,7 +176,7 @@ export class Project {
* Asset types are infered from the file suffix.
* Glob syntax is very simple, the most important patterns are * for anything and ** for anything across directories.
*/
addAssets(match: string, options: any) {
addAssets(match: string, options: AssetMatcherOptions) {
if (!options) options = {};
if (!path.isAbsolute(match)) {
@ -217,15 +242,15 @@ export class Project {
addLibrary(library: string): string {
this.addDefine(library);
let self = this;
function findLibraryDirectory(name: string) {
const findLibraryDirectory = (name: string) => {
if (path.isAbsolute(name)) {
return { libpath: name, libroot: name };
}
// Tries to load the default library from inside the kha project.
// e.g. 'Libraries/wyngine'
let libpath = path.join(self.scriptdir, self.localLibraryPath, name);
let libpath = path.join(this.scriptdir, this.localLibraryPath, name);
if (fs.existsSync(libpath) && fs.statSync(libpath).isDirectory()) {
let dir = path.resolve(libpath);
return { libpath: dir, libroot: dir };
@ -275,17 +300,18 @@ export class Project {
if (elem.libroot === libInfo.libroot)
return '';
}
this.libraries.push({
const lib:Library = {
libpath: dir,
libroot: libInfo.libroot
});
}
this.libraries.push(lib);
// If this is a haxelib library, there must be a haxelib.json
if (fs.existsSync(path.join(dir, 'haxelib.json'))) {
let options = JSON.parse(fs.readFileSync(path.join(dir, 'haxelib.json'), 'utf8'));
// If there is a classPath value, add that directory to be loaded.
// Otherwise, just load the current path.
if (options.classPath) {
// TODO find an example haxelib that has a classPath value
lib.classPathIsAdded = true
this.sources.push(path.join(dir, options.classPath));
}
else {

View File

@ -223,14 +223,13 @@ export class ShaderCompiler {
ready = true;
let compiledShaders: CompiledShader[] = [];
const self = this;
async function compile(shader: any, index: number) {
const compile = async (shader: any, index: number) => {
let parsed = path.parse(shader);
if (self.isSupported(shader)) {
if (this.isSupported(shader)) {
log.info('Compiling shader ' + (index + 1) + ' of ' + shaders.length + ' (' + parsed.base + ').');
let compiledShader: CompiledShader = null;
try {
compiledShader = await self.compileShader(shader, options, recompileAll);
compiledShader = await this.compileShader(shader, options, recompileAll);
}
catch (error) {
log.error('Compiling shader ' + (index + 1) + ' of ' + shaders.length + ' (' + parsed.base + ') failed:');
@ -249,9 +248,9 @@ export class ShaderCompiler {
}
if (compiledShader.files != null && compiledShader.files.length === 0) {
// TODO: Remove when krafix has been recompiled everywhere
compiledShader.files.push(parsed.name + '.' + self.type);
compiledShader.files.push(parsed.name + '.' + this.type);
}
compiledShader.name = AssetConverter.createExportInfo(parsed, false, options, self.exporter.options.from).name;
compiledShader.name = AssetConverter.createExportInfo(parsed, false, options, this.exporter.options.from).name;
compiledShaders.push(compiledShader);
}
else {

View File

@ -23,6 +23,8 @@ export function sysdir() {
return 'freebsd_x64';
}
else {
return 'macos';
if (os.arch() === 'arm64') return 'macos_arm64';
else if (os.arch() === 'x64') return 'macos_x64';
else throw 'Unsupported CPU';
}
}

View File

@ -1,10 +1,10 @@
import * as path from 'path';
import {sysdir} from './exec';
let korepath = path.join(__dirname, '..', '..', '..', 'Kinc', 'Tools', sysdir());
let korepath = path.join(__dirname, '..', '..', '..', 'Kore', 'Tools', sysdir());
export function init(options: any) {
korepath = path.join(options.kha, 'Kinc', 'Tools', sysdir());
korepath = path.join(options.kha, 'Kore', 'Tools', sysdir());
}
export function get() {

View File

@ -21,8 +21,8 @@ import {FlashExporter} from './Exporters/FlashExporter';
import {Html5Exporter} from './Exporters/Html5Exporter';
import {Html5WorkerExporter} from './Exporters/Html5WorkerExporter';
import {JavaExporter} from './Exporters/JavaExporter';
import {KincExporter} from './Exporters/KincExporter';
import {KincHLExporter} from './Exporters/KincHLExporter';
import {KoreExporter} from './Exporters/KoreExporter';
import {KoreHLExporter} from './Exporters/KoreHLExporter';
import {KromExporter} from './Exporters/KromExporter';
import {NodeExporter} from './Exporters/NodeExporter';
import {PlayStationMobileExporter} from './Exporters/PlayStationMobileExporter';
@ -91,10 +91,10 @@ function createKorefile(name: string, exporter: KhaExporter, options: Options, t
let buildpath = path.relative(options.from, path.join(options.to, exporter.sysdir() + '-build')).replace(/\\/g, '/');
if (buildpath.startsWith('..')) buildpath = path.resolve(path.join(options.from.toString(), buildpath));
out += 'await project.addProject(\'' + path.join(options.kha, 'Kinc').replace(/\\/g, '/') + '\');\n';
out += 'await project.addProject(\'' + path.join(options.kha, 'Kore').replace(/\\/g, '/') + '\');\n';
out += 'await project.addProject(\'' + buildpath.replace(/\\/g, '/') + '\');\n';
if (korehl) out += 'await project.addProject(\'' + path.join(options.kha, 'Backends', 'Kinc-HL').replace(/\\/g, '/') + '\');\n';
else out += 'await project.addProject(\'' + path.join(options.kha, 'Backends', 'Kinc-hxcpp').replace(/\\/g, '/') + '\');\n';
if (korehl) out += 'await project.addProject(\'' + path.join(options.kha, 'Backends', 'Kore-HL').replace(/\\/g, '/') + '\');\n';
else out += 'await project.addProject(\'' + path.join(options.kha, 'Backends', 'Kore-hxcpp').replace(/\\/g, '/') + '\');\n';
for (let lib of libraries) {
let libPath: string = lib.libpath.replace(/\\/g, '/');
@ -181,12 +181,11 @@ async function exportProjectFiles(name: string, resourceDir: string, options: Op
if (options.haxe !== '' && kore && !options.noproject) {
// If target is a Kore project, generate additional project folders here.
// generate the kincfile.js
// generate the kfile.js
fs.copySync(path.join(__dirname, '..', 'Data', 'hxcpp', 'kfile.js'), path.join(buildDir, 'kfile.js'), { overwrite: true });
fs.writeFileSync(path.join(options.to, 'kfile.js'), createKorefile(name, exporter, options, targetOptions, libraries, cdefines, cflags, cppflags, stackSize, version, id, false, icon));
// Similar to khamake.js -> main.js -> run(...)
// We now do kincmake.js -> main.js -> run(...)
// This will create additional project folders for the target,
// e.g. 'build/pi-build'
try {
@ -282,7 +281,7 @@ function checkKorePlatform(platform: string) {
|| platform === 'ps4'
|| platform === 'xboxone'
|| platform === 'switch'
|| platform === 'xboxscarlett'
|| platform === 'xboxseries'
|| platform === 'ps5'
|| platform === 'freebsd';
}
@ -372,7 +371,7 @@ async function exportKhaProject(options: Options): Promise<string> {
log.error(`Unknown platform: ${target} (baseTarget=$${baseTarget})`);
return Promise.reject('');
}
exporter = new KincHLExporter(options);
exporter = new KoreHLExporter(options);
}
else {
kore = true;
@ -381,7 +380,7 @@ async function exportKhaProject(options: Options): Promise<string> {
log.error(`Unknown platform: ${target} (baseTarget=$${baseTarget})`);
return Promise.reject('');
}
exporter = new KincExporter(options);
exporter = new KoreExporter(options);
}
break;
}
@ -696,16 +695,25 @@ export async function run(options: Options, loglog: any): Promise<string> {
if (!options.haxe) {
let haxepath = path.join(options.kha, 'Tools', sysdir());
if (fs.existsSync(haxepath) && fs.statSync(haxepath).isDirectory()) options.haxe = haxepath;
else log.error('Haxe not found at ' + haxepath);
}
else {
log.info('Using Haxe from ' + options.haxe);
}
if (!options.krafix) {
let krafixpath = path.join(options.kha, 'Kinc', 'Tools', sysdir(), 'krafix' + sys());
let krafixpath = path.join(options.kha, 'Kore', 'Tools', sysdir(), 'krafix' + sys());
if (fs.existsSync(krafixpath)) options.krafix = krafixpath;
else log.error('krafix not found at ' + krafixpath);
}
else {
log.info('Using krafix from ' + options.krafix);
}
if (!options.kraffiti) {
const kraffitipath = path.join(options.kha, 'Kinc', 'Tools', sysdir(), 'kraffiti' + sys());
const kraffitipath = path.join(options.kha, 'Kore', 'Tools', sysdir(), 'kraffiti' + sys());
if (fs.existsSync(kraffitipath)) options.kraffiti = kraffitipath;
else log.error('kraffiti not found at ' + kraffitipath);
}
else {
log.info('Using kraffiti from ' + options.kraffiti);
@ -722,11 +730,13 @@ export async function run(options: Options, loglog: any): Promise<string> {
if (!options.ogg) {
let oggpath = path.join(options.kha, 'Tools', sysdir(), 'oggenc' + sys());
if (fs.existsSync(oggpath)) options.ogg = oggpath + ' {in} -o {out} --quiet';
else log.error('oggenc not found at ' + oggpath);
}
if (!options.mp3) {
let lamepath = path.join(options.kha, 'Tools', sysdir(), 'lame' + sys());
if (fs.existsSync(lamepath)) options.mp3 = lamepath + ' {in} {out}';
else log.error('lame not found at ' + lamepath);
}
// if (!options.kravur) {
@ -755,8 +765,7 @@ export async function run(options: Options, loglog: any): Promise<string> {
}
if (options.target === 'emscripten') {
console.log();
console.log('Please note that the html5 target\n'
log.info('\nPlease note that the html5 target\n'
+ 'is usually a better choice.\n'
+ 'In particular the html5 target usually runs faster\n'
+ 'than the emscripten target. That is because\n'
@ -765,9 +774,8 @@ export async function run(options: Options, loglog: any): Promise<string> {
+ 'all of the optimizations in modern JavaScript\n'
+ 'runtimes. The emscripten target on the other hand\n'
+ 'has to provide its own garbage collector and many\n'
+ 'other performance critical pieces of infrastructure.'
+ 'other performance critical pieces of infrastructure.\n'
);
console.log();
}
let name = '';

Binary file not shown.

View File

@ -32,13 +32,10 @@
to another type.
**/
@:forward.variance
abstract Any(Dynamic) {
abstract Any(Dynamic) from Dynamic {
@:noCompletion @:to extern inline function __promote<T>():T
return this;
@:noCompletion @:from extern inline static function __cast<T>(value:T):Any
return cast value;
@:noCompletion extern inline function toString():String
return Std.string(this);
}

View File

@ -276,10 +276,10 @@ extern class Math {
static function isFinite(f:Float):Bool;
/**
Tells if `f` is not a valid number.
Tells if `f` is `Math.NaN`.
If `f` is `NaN`, the result is `true`, otherwise the result is `false`.
In particular, both `POSITIVE_INFINITY` and `NEGATIVE_INFINITY` are
In particular, `null`, `POSITIVE_INFINITY` and `NEGATIVE_INFINITY` are
not considered `NaN`.
**/
static function isNaN(f:Float):Bool;

View File

@ -97,21 +97,22 @@ extern class Std {
Leading whitespaces are ignored.
If `x` starts with 0x or 0X, hexadecimal notation is recognized where the following digits may
contain 0-9 and A-F.
`x` may optionally start with a + or - to denote a postive or negative value respectively.
Otherwise `x` is read as decimal number with 0-9 being allowed characters. `x` may also start with
a - to denote a negative value.
If the optional sign is followed 0x or 0X, hexadecimal notation is recognized where the following
digits may contain 0-9 and A-F. Both the prefix and digits are case insensitive.
In decimal mode, parsing continues until an invalid character is detected, in which case the
result up to that point is returned. For hexadecimal notation, the effect of invalid characters
is unspecified.
Otherwise `x` is read as decimal number with 0-9 being allowed characters. Octal and binary
notations are not supported.
Leading 0s that are not part of the 0x/0X hexadecimal notation are ignored, which means octal
notation is not supported.
Parsing continues until an invalid character is detected, in which case the result up to
that point is returned. Scientific notation is not supported. That is `Std.parseInt('10e2')` produces `10`.
If `x` is null, the result is unspecified.
If `x` cannot be parsed as integer, the result is `null`.
If `x` is `null`, the result is `null`.
If `x` cannot be parsed as integer or is empty, the result is `null`.
If `x` starts with a hexadecimal prefix which is not followed by at least one valid hexadecimal
digit, the result is unspecified.
**/
static function parseInt(x:String):Null<Int>;
@ -119,9 +120,12 @@ extern class Std {
Converts a `String` to a `Float`.
The parsing rules for `parseInt` apply here as well, with the exception of invalid input
resulting in a `NaN` value instead of null.
resulting in a `NaN` value instead of `null`. Also, hexadecimal support is **not** specified.
Additionally, decimal notation may contain a single `.` to denote the start of the fractions.
It may also end with `e` or `E` followed by optional minus or plus sign and a sequence of
digits (defines exponent to base 10).
**/
static function parseFloat(x:String):Float;

View File

@ -211,7 +211,7 @@ class StringTools {
public static inline function contains(s:String, value:String):Bool {
#if (js && js_es >= 6)
return (cast s).includes(value);
#else
#else
return s.indexOf(value) != -1;
#end
}
@ -234,6 +234,8 @@ class StringTools {
return python.NativeStringTools.startswith(s, start);
#elseif (js && js_es >= 6)
return (cast s).startsWith(start);
#elseif lua
return untyped __lua__("{0}:sub(1, #{1}) == {1}", s, start);
#else
return (s.length >= start.length && s.lastIndexOf(start, 0) == 0);
#end
@ -259,6 +261,8 @@ class StringTools {
return python.NativeStringTools.endswith(s, end);
#elseif (js && js_es >= 6)
return (cast s).endsWith(end);
#elseif lua
return end == "" || untyped __lua__("{0}:sub(-#{1}) == {1}", s, end);
#else
var elen = end.length;
var slen = s.length;

View File

@ -57,12 +57,24 @@ extern class Sys {
/**
Sets the value of the given environment variable.
If `v` is `null`, the environment variable is removed.
(java) This functionality is not available on Java; calling this function will throw.
**/
static function putEnv(s:String, v:String):Void;
static function putEnv(s:String, v:Null<String>):Void;
/**
Returns all environment variables.
Returns a map of the current environment variables and their values
as of the invocation of the function.
(python) On Windows, the variable names are always in upper case.
(cpp)(hl)(neko) On Windows, the variable names match the last capitalization used when modifying
the variable if the variable has been modified, otherwise they match their capitalization at
the start of the process.
On Windows on remaining targets, variable name capitalization matches however they were capitalized
at the start of the process or at the moment of their creation.
**/
static function environment():Map<String, String>;

View File

@ -26,9 +26,14 @@ import haxe.iterators.StringIteratorUnicode;
import haxe.iterators.StringKeyValueIteratorUnicode;
/**
This abstract provides consistent cross-target unicode support.
This abstract provides consistent cross-target unicode support for characters of any width.
@see https://haxe.org/manual/std-UnicodeString.html
Due to differing internal representations of strings across targets, only the basic
multilingual plane (BMP) is supported consistently by `String` class.
This abstract provides API to consistently handle all characters even beyond BMP.
@see https://haxe.org/manual/std-String-unicode.html
**/
@:forward
@:access(StringTools)

View File

@ -22,7 +22,21 @@
package cpp;
@:coreType @:notNull @:runtimeValue abstract Int64 from Int to Int {
@:coreType @:notNull @:runtimeValue abstract Int64 from Int {
/**
Destructively cast to Int
**/
public inline function toInt():Int {
return cast this;
}
@:to
@:deprecated("Implicit cast from Int64 to Int (32 bits) is deprecated. Use .toInt() or explicitly cast instead.")
inline function implicitToInt(): Int {
return toInt();
}
@:to
#if !cppia inline #end function toInt64():haxe.Int64 {
return cast this;

View File

@ -0,0 +1,154 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package cpp;
import haxe.Int64;
@:headerClassCode("
inline void set(cpp::Int64 key, ::null value) { __int64_hash_set(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, bool value) { __int64_hash_set(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, unsigned char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, signed char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, short value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, unsigned short value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, int value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, unsigned int value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, float value) { __int64_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, double value) { __int64_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, ::String value) { __int64_hash_set_string(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, cpp::Int64 value) { __int64_hash_set_int64(HX_MAP_THIS,key,value); }
template<typename V, typename H>
inline void set(cpp::Int64 key, const ::cpp::Struct<V,H> &value) {__int64_hash_set(HX_MAP_THIS,key,value); }
template<typename F>
inline void set(cpp::Int64 key, const ::cpp::Function<F> &value) {__int64_hash_set(HX_MAP_THIS,key,value); }
template<typename V>
inline void set(cpp::Int64 key, const ::cpp::Pointer<V> &value) {__int64_hash_set(HX_MAP_THIS,key,(Dynamic)value ); }
template<typename VALUE>
inline void set(Dynamic &key, const VALUE &value) { set( (cpp::Int64)key, value ); }
inline bool get_bool(cpp::Int64 key) { return __int64_hash_get_bool(h,key); }
inline int get_int(cpp::Int64 key) { return __int64_hash_get_int(h,key); }
inline Float get_float(cpp::Int64 key) { return __int64_hash_get_float(h,key); }
inline String get_string(cpp::Int64 key) { return __int64_hash_get_string(h,key); }
inline cpp::Int64 get_int64(cpp::Int64 key) { return __int64_hash_get_int64(h,key); }
")
@:coreApi class Int64Map<T> implements haxe.Constraints.IMap<Int64, T> {
@:ifFeature("cpp.Int64Map.*")
private var h:Dynamic;
public function new():Void {}
public function set(key:Int64, value:T):Void {
untyped __global__.__int64_hash_set(__cpp__("HX_MAP_THIS"), key, value);
}
public function get(key:Int64):Null<T> {
return untyped __global__.__int64_hash_get(h, key);
}
public function exists(key:Int64):Bool {
return untyped __global__.__int64_hash_exists(h, key);
}
public function remove(key:Int64):Bool {
return untyped __global__.__int64_hash_remove(h, key);
}
public function keys():Iterator<Int64> {
var a:Array<Int64> = untyped __global__.__int64_hash_keys(h);
return a.iterator();
}
public function iterator():Iterator<T> {
var a:Array<Dynamic> = untyped __global__.__int64_hash_values(h);
return a.iterator();
}
@:runtime public inline function keyValueIterator():KeyValueIterator<Int64, T> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public function copy():Int64Map<T> {
var copied = new Int64Map();
for (key in keys())
copied.set(key, get(key));
return copied;
}
public function toString():String {
return untyped __global__.__int64_hash_to_string(h);
}
public function clear():Void {
#if (hxcpp_api_level >= 400)
return untyped __global__.__int64_hash_clear(h);
#else
h = null;
#end
}
#if (scriptable)
private function setString(key:Int64, val:String):Void {
untyped __int64_hash_set_string(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt(key:Int64, val:Int):Void {
untyped __int64_hash_set_int(__cpp__("HX_MAP_THIS"), key, val);
}
private function setBool(key:Int64, val:Bool):Void {
untyped __int64_hash_set_int(__cpp__("HX_MAP_THIS"), key, val);
}
private function setFloat(key:Int64, val:Float):Void {
untyped __int64_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt64(key:Int64, val:Int64):Void {
untyped __int64_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
}
private function getString(key:Int64):String {
return untyped __int64_hash_get_string(h, key);
}
private function getInt(key:Int64):Int {
return untyped __int64_hash_get_int(h, key);
}
private function getBool(key:Int64):Bool {
return untyped __int64_hash_get_bool(h, key);
}
private function getFloat(key:Int64):Float {
return untyped __int64_hash_get_float(h, key);
}
private function getInt64(key:Int64):Int64 {
return untyped __int64_hash_get_int64(h, key);
}
#end
}

View File

@ -79,7 +79,7 @@ class Lib {
}
@:noDebug @:native("HX_STACK_DO_RETHROW")
extern static function do_rethrow(inExp:Dynamic);
extern static function do_rethrow(inExp:Dynamic):Void;
@:noDebug #if (!cppia) inline #end
public static function rethrow(inExp:Dynamic) {

View File

@ -43,7 +43,7 @@ extern class NativeProcess {
static function process_stdin_close(handle:Dynamic):Void;
@:native("_hx_std_process_exit")
static function process_exit(handle:Dynamic):Int;
static function process_exit(handle:Dynamic, block:Bool):Dynamic;
@:native("_hx_std_process_pid")
static function process_pid(handle:Dynamic):Int;

View File

@ -34,7 +34,7 @@ extern class NativeSys {
extern static function get_env(v:String):String;
@:native("_hx_std_put_env")
extern static function put_env(e:String, v:String):Void;
extern static function put_env(e:String, v:Null<String>):Void;
@:native("_hx_std_sys_sleep")
extern static function sys_sleep(f:Float):Void;

View File

@ -221,7 +221,7 @@ class Xml {
function new():Void {}
@:native("parse_xml")
extern static function parse_xml(str:String, state:NativeXmlState);
extern static function parse_xml(str:String, state:NativeXmlState):String;
public static function parse(str:String):Xml {
var x = new Xml();

View File

@ -22,4 +22,19 @@
package cpp;
@:coreType @:notNull @:runtimeValue abstract UInt64 from Int to Int {}
@:coreType @:notNull @:runtimeValue abstract UInt64 from Int {
/**
Destructively cast to Int
**/
public inline function toInt():Int {
return cast this;
}
@:to
@:deprecated("Implicit cast from UInt64 to Int (32 bits) is deprecated. Use .toInt() or explicitly cast instead.")
inline function implicitToInt(): Int {
return toInt();
}
}

View File

@ -63,7 +63,7 @@ import haxe.SysTools;
return v;
}
public static function putEnv(s:String, v:String):Void {
public static function putEnv(s:String, v:Null<String>):Void {
NativeSys.put_env(s, v);
}

View File

@ -19,7 +19,10 @@ class Exception {
if(Std.isOfType(value, Exception)) {
return value;
} else {
return new ValueException(value, null, value);
var e = new ValueException(value, null, value);
// Undo automatic __shiftStack()
e.__unshiftStack();
return e;
}
}
@ -63,6 +66,12 @@ class Exception {
__skipStack++;
}
@:noCompletion
@:ifFeature("haxe.Exception.get_stack")
inline function __unshiftStack():Void {
__skipStack--;
}
function get_message():String {
return __exceptionMessage;
}

View File

@ -22,13 +22,8 @@
package haxe;
import haxe.Int64Helper;
@:notNull
@:include("cpp/Int64.h")
@:native("cpp::Int64Struct")
private extern class ___Int64 {
private extern class NativeInt64Helper {
@:native("_hx_int64_make")
static function make(high:Int32, low:Int32):__Int64;
@ -132,21 +127,21 @@ private extern class ___Int64 {
static function low(a:__Int64):Int32;
}
private typedef __Int64 = ___Int64;
private typedef __Int64 = cpp.Int64;
@:coreApi
@:transitive
abstract Int64(__Int64) from __Int64 to __Int64 {
@:notNull
abstract Int64(__Int64) from __Int64 from Int to __Int64 {
public #if !cppia inline #end function copy():Int64
return this;
public static #if !cppia inline #end function make(high:Int32, low:Int32):Int64 {
return __Int64.make(high, low);
return NativeInt64Helper.make(high, low);
}
@:from
public static #if !cppia inline #end function ofInt(x:Int):Int64 {
return __Int64.ofInt(x);
return x;
}
public static #if !cppia inline #end function toInt(x:Int64):Int {
@ -158,11 +153,11 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead')
inline public static function is(val:Dynamic):Bool {
return isInt64(val);
return val is cpp.Int64;
}
public static #if !cppia inline #end function isInt64(val:Dynamic):Bool
return __Int64.isInt64(val);
return val is cpp.Int64;
@:deprecated("Use high instead")
public static #if !cppia inline #end function getHigh(x:Int64):Int32
@ -173,22 +168,22 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
return x.low;
public static #if !cppia inline #end function isNeg(x:Int64):Bool
return __Int64.isNeg(x);
return NativeInt64Helper.isNeg(x);
public static #if !cppia inline #end function isZero(x:Int64):Bool
return __Int64.isZero(x);
return NativeInt64Helper.isZero(x);
public static #if !cppia inline #end function compare(a:Int64, b:Int64):Int
return __Int64.compare(a, b);
return NativeInt64Helper.compare(a, b);
public static #if !cppia inline #end function ucompare(a:Int64, b:Int64):Int
return __Int64.ucompare(a, b);
return NativeInt64Helper.ucompare(a, b);
public static #if !cppia inline #end function toStr(x:Int64):String
return x.toString();
return cast x.val;
private #if !cppia inline #end function toString():String
return __Int64.toString(this);
return cast this;
public static function parseString(sParam:String):Int64 {
return Int64Helper.parseString(sParam);
@ -201,7 +196,7 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
public static function divMod(dividend:Int64, divisor:Int64):{quotient:Int64, modulus:Int64} {
var q = dividend / divisor;
if (isZero(divisor))
if (divisor == 0)
throw "divide by zero";
var m = dividend - q * divisor;
@ -209,16 +204,16 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
return {quotient: q, modulus: m};
}
@:op(-A)
@:op(-A)
public static #if !cppia inline #end function neg(x:Int64):Int64
return __Int64.neg(x);
return NativeInt64Helper.neg(x);
@:op(++A) private inline function preIncrement():Int64 {
#if cppia
this = this + make(0, 1);
return this;
#else
return __Int64.preIncrement(this);
return NativeInt64Helper.preIncrement(this);
#end
}
@ -228,7 +223,7 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
this = this + make(0, 1);
return result;
#else
return __Int64.postIncrement(this);
return NativeInt64Helper.postIncrement(this);
#end
}
@ -237,7 +232,7 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
untyped this = this - make(0, 1);
return this;
#else
return __Int64.preDecrement(this);
return NativeInt64Helper.preDecrement(this);
#end
}
@ -247,35 +242,35 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
this = this - make(0, 1);
return result;
#else
return __Int64.postDecrement(this);
return NativeInt64Helper.postDecrement(this);
#end
}
@:op(A + B)
public static #if !cppia inline #end function add(a:Int64, b:Int64):Int64
return __Int64.add(a, b);
return NativeInt64Helper.add(a, b);
@:op(A + B)
@:commutative
private static #if !cppia inline #end function addInt(a:Int64, b:Int):Int64
return __Int64.addInt(a, b);
return NativeInt64Helper.addInt(a, b);
@:op(A - B)
public static #if !cppia inline #end function sub(a:Int64, b:Int64):Int64 {
return __Int64.sub(a, b);
return NativeInt64Helper.sub(a, b);
}
@:op(A - B)
private static #if !cppia inline #end function subInt(a:Int64, b:Int):Int64
return __Int64.subInt(a, b);
return NativeInt64Helper.subInt(a, b);
@:op(A - B)
private static #if !cppia inline #end function intSub(a:Int, b:Int64):Int64
return __Int64.intSub(a, b);
return NativeInt64Helper.intSub(a, b);
@:op(A * B)
public static #if !cppia inline #end function mul(a:Int64, b:Int64):Int64
return __Int64.mul(a, b);
return NativeInt64Helper.mul(a, b);
@:op(A * B)
@:commutative
@ -284,9 +279,9 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:op(A / B)
public static #if !cppia inline #end function div(a:Int64, b:Int64):Int64 {
if (__Int64.isZero(b))
if (NativeInt64Helper.isZero(b))
throw "divide by zero";
return __Int64.div(a, b);
return NativeInt64Helper.div(a, b);
}
@:op(A / B)
@ -299,9 +294,9 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:op(A % B)
public static #if !cppia inline #end function mod(a:Int64, b:Int64):Int64 {
if (__Int64.isZero(b))
if (NativeInt64Helper.isZero(b))
throw "divide by zero";
return __Int64.mod(a, b);
return NativeInt64Helper.mod(a, b);
}
@:op(A % B)
@ -314,16 +309,16 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:op(A == B)
public static #if !cppia inline #end function eq(a:Int64, b:Int64):Bool
return __Int64.eq(a, b);
return NativeInt64Helper.eq(a, b);
@:op(A == B)
@:commutative
private static #if !cppia inline #end function eqInt(a:Int64, b:Int):Bool
return __Int64.eqInt(a, b);
return NativeInt64Helper.eqInt(a, b);
@:op(A != B)
public static #if !cppia inline #end function neq(a:Int64, b:Int64):Bool
return __Int64.neq(a, b);
return NativeInt64Helper.neq(a, b);
@:op(A != B)
@:commutative
@ -380,39 +375,44 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:op(~A)
private static #if !cppia inline #end function complement(a:Int64):Int64
return __Int64.complement(a);
return NativeInt64Helper.complement(a);
@:op(A & B)
public static #if !cppia inline #end function and(a:Int64, b:Int64):Int64
return __Int64.bitAnd(a, b);
return NativeInt64Helper.bitAnd(a, b);
@:op(A | B)
public static #if !cppia inline #end function or(a:Int64, b:Int64):Int64
return __Int64.bitOr(a, b);
return NativeInt64Helper.bitOr(a, b);
@:op(A ^ B)
public static #if !cppia inline #end function xor(a:Int64, b:Int64):Int64
return __Int64.bitXor(a, b);
return NativeInt64Helper.bitXor(a, b);
@:op(A << B)
public static #if !cppia inline #end function shl(a:Int64, b:Int):Int64
return __Int64.shl(a, b);
return NativeInt64Helper.shl(a, b);
@:op(A >> B)
public static #if !cppia inline #end function shr(a:Int64, b:Int):Int64
return __Int64.shr(a, b);
return NativeInt64Helper.shr(a, b);
@:op(A >>> B)
public static #if !cppia inline #end function ushr(a:Int64, b:Int):Int64
return __Int64.ushr(a, b);
return NativeInt64Helper.ushr(a, b);
public var high(get, never):Int32;
private #if !cppia inline #end function get_high():Int32
return __Int64.high(this);
return NativeInt64Helper.high(this);
public var low(get, never):Int32;
private #if !cppia inline #end function get_low():Int32
return __Int64.low(this);
return NativeInt64Helper.low(this);
private var val(get, never):__Int64;
private #if !cppia inline #end function get_val():__Int64
return this;
}

View File

@ -0,0 +1,68 @@
package haxe.atomic;
#if cppia
extern
#end
abstract AtomicInt(cpp.Pointer<Int>) {
#if cppia
public function new(value:Int):Void;
public function add(b:Int):Int;
public function sub(b:Int):Int;
public function and(b:Int):Int;
public function or(b:Int):Int;
public function xor(b:Int):Int;
public function compareExchange(expected:Int, replacement:Int):Int;
public function exchange(value:Int):Int;
public function load():Int;
public function store(value:Int):Int;
#else
public #if !scriptable inline #end function new(value:Int) {
this = cpp.Pointer.ofArray([value]);
}
public #if !scriptable inline #end function add(b:Int):Int {
return untyped __cpp__("_hx_atomic_add({0}, {1})", this, b);
}
public #if !scriptable inline #end function sub(b:Int):Int {
return untyped __cpp__("_hx_atomic_sub({0}, {1})", this, b);
}
public #if !scriptable inline #end function and(b:Int):Int {
return untyped __cpp__("_hx_atomic_and({0}, {1})", this, b);
}
public #if !scriptable inline #end function or(b:Int):Int {
return untyped __cpp__("_hx_atomic_or({0}, {1})", this, b);
}
public #if !scriptable inline #end function xor(b:Int):Int {
return untyped __cpp__("_hx_atomic_xor({0}, {1})", this, b);
}
public #if !scriptable inline #end function compareExchange(expected:Int, replacement:Int):Int {
return untyped __cpp__("_hx_atomic_compare_exchange({0}, {1}, {2})", this, expected, replacement);
}
public #if !scriptable inline #end function exchange(value:Int):Int {
return untyped __cpp__("_hx_atomic_exchange({0}, {1})", this, value);
}
public #if !scriptable inline #end function load():Int {
return untyped __cpp__("_hx_atomic_load({0})", this);
}
public #if !scriptable inline #end function store(value:Int):Int {
return untyped __cpp__("_hx_atomic_store({0}, {1})", this, value);
}
#end
}

View File

@ -35,6 +35,7 @@ package haxe.ds;
inline void set(int key, float value) { __int_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(int key, double value) { __int_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(int key, ::String value) { __int_hash_set_string(HX_MAP_THIS,key,value); }
inline void set(int key, cpp::Int64 value) { __int_hash_set_int64(HX_MAP_THIS,key,value); }
template<typename V, typename H>
inline void set(int key, const ::cpp::Struct<V,H> &value) {__int_hash_set(HX_MAP_THIS,key,value); }
@ -50,6 +51,7 @@ package haxe.ds;
inline int get_int(int key) { return __int_hash_get_int(h,key); }
inline Float get_float(int key) { return __int_hash_get_float(h,key); }
inline String get_string(int key) { return __int_hash_get_string(h,key); }
inline cpp::Int64 get_int64(int key) { return __int_hash_get_int64(h,key); }
")
@:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int, T> {
@:ifFeature("haxe.ds.IntMap.*")
@ -123,6 +125,10 @@ package haxe.ds;
untyped __int_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt64(key:Int, val:haxe.Int64):Void {
untyped __int_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
}
private function getString(key:Int):String {
return untyped __int_hash_get_string(h, key);
}
@ -138,5 +144,9 @@ package haxe.ds;
private function getFloat(key:Int):Float {
return untyped __int_hash_get_float(h, key);
}
private function getInt64(key:Int):haxe.Int64 {
return untyped __int_hash_get_int64(h, key);
}
#end
}

View File

@ -22,6 +22,7 @@
package haxe.ds;
import haxe.Int64;
import haxe.ds.StringMap;
import haxe.ds.IntMap;
import haxe.ds.HashMap;
@ -29,6 +30,7 @@ import haxe.ds.ObjectMap;
import haxe.ds.WeakMap;
import haxe.ds.EnumValueMap;
import haxe.Constraints.IMap;
import cpp.Int64Map;
/**
Map allows key to value mapping for arbitrary value types, and many key
@ -175,6 +177,11 @@ abstract Map<K, V>(IMap<K, V>) {
return new IntMap<V>();
}
@:noDoc
@:to static inline function toInt64Map<K:Int64, V>(t:IMap<K, V>):Int64Map<V> {
return new Int64Map<V>();
}
@:to static inline function toEnumValueMapMap<K:EnumValue, V>(t:IMap<K, V>):EnumValueMap<K, V> {
return new EnumValueMap<K, V>();
}
@ -191,6 +198,11 @@ abstract Map<K, V>(IMap<K, V>) {
return cast map;
}
@:noDoc
@:from static inline function fromInt64Map<V>(map:Int64Map<V>):Map<Int64, V> {
return cast map;
}
@:from static inline function fromObjectMap<K:{}, V>(map:ObjectMap<K, V>):Map<K, V> {
return cast map;
}

View File

@ -35,6 +35,7 @@ package haxe.ds;
inline void set(Dynamic key, float value) { __object_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(Dynamic key, double value) { __object_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(Dynamic key, ::String value) { __object_hash_set_string(HX_MAP_THIS,key,value); }
inline void set(Dynamic key, cpp::Int64 value) { __object_hash_set_int64(HX_MAP_THIS,key,value); }
template<typename V, typename H>
@ -48,7 +49,7 @@ package haxe.ds;
inline int get_int(Dynamic key) { return __object_hash_get_int(h,key); }
inline Float get_float(Dynamic key) { return __object_hash_get_float(h,key); }
inline String get_string(Dynamic key) { return __object_hash_get_string(h,key); }
inline cpp::Int64 get_int64(Dynamic key) { return __object_hash_get_int64(h,key); }
")
@:coreApi
class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
@ -123,6 +124,10 @@ class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
untyped __object_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt64(key:Dynamic, val:haxe.Int64):Void {
untyped __object_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
}
private function getString(key:Dynamic):String {
return untyped __object_hash_get_string(h, key);
}
@ -138,5 +143,9 @@ class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
private function getFloat(key:Dynamic):Float {
return untyped __object_hash_get_float(h, key);
}
private function getInt64(key:Dynamic):haxe.Int64 {
return untyped __object_hash_get_int64(h, key);
}
#end
}

View File

@ -35,6 +35,7 @@ package haxe.ds;
inline void set(String key, float value) { __string_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(String key, double value) { __string_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(String key, ::String value) { __string_hash_set_string(HX_MAP_THIS,key,value); }
inline void set(String key, cpp::Int64 value) { __string_hash_set_int64(HX_MAP_THIS,key,value); }
template<typename V, typename H>
inline void set(String key, const ::cpp::Struct<V,H> &value) {__string_hash_set(HX_MAP_THIS,key,value); }
@ -50,6 +51,7 @@ package haxe.ds;
inline int get_int(String key) { return __string_hash_get_int(h,key); }
inline Float get_float(String key) { return __string_hash_get_float(h,key); }
inline String get_string(String key) { return __string_hash_get_string(h,key); }
inline cpp::Int64 get_int64(String key) { return __string_hash_get_int64(h,key); }
")
@:coreApi class StringMap<T> implements haxe.Constraints.IMap<String, T> {
@:ifFeature("haxe.ds.StringMap.*")
@ -123,6 +125,10 @@ package haxe.ds;
untyped __string_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt64(key:String, val:haxe.Int64):Void {
untyped __string_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
}
private function getString(key:String):String {
return untyped __string_hash_get_string(h, key);
}
@ -138,5 +144,9 @@ package haxe.ds;
private function getFloat(key:String):Float {
return untyped __string_hash_get_float(h, key);
}
private function getInt64(key:String):haxe.Int64 {
return untyped __string_hash_get_int64(h, key);
}
#end
}

View File

@ -35,6 +35,7 @@ package haxe.ds;
inline void set(Dynamic key, float value) { __object_hash_set_float(HX_MAP_THIS,key,value,true); }
inline void set(Dynamic key, double value) { __object_hash_set_float(HX_MAP_THIS,key,value,true); }
inline void set(Dynamic key, ::String value) { __object_hash_set_string(HX_MAP_THIS,key,value,true); }
inline void set(Dynamic key, cpp::Int64 value) { __object_hash_set_int64(HX_MAP_THIS,key,value,true); }
template<typename V, typename H>
inline void set(Dynamic key, const ::cpp::Struct<V,H> &value) {__object_hash_set(HX_MAP_THIS,key,value,true); }

View File

@ -105,9 +105,7 @@ class Process {
}
public function exitCode(block:Bool = true):Null<Int> {
if (block == false)
throw "Non blocking exitCode() not supported on this platform";
return NativeProcess.process_exit(p);
return NativeProcess.process_exit(p, block);
}
public function close():Void {

View File

@ -0,0 +1,33 @@
package sys.thread;
@:coreApi
class Condition {
var c:Dynamic;
public function new():Void {
c = untyped __global__.__hxcpp_condition_create();
}
public function acquire():Void {
untyped __global__.__hxcpp_condition_acquire(c);
}
public function tryAcquire():Bool {
return untyped __global__.__hxcpp_condition_try_acquire(c);
}
public function release():Void {
untyped __global__.__hxcpp_condition_release(c);
}
public function wait():Void {
untyped __global__.__hxcpp_condition_wait(c);
}
public function signal():Void {
untyped __global__.__hxcpp_condition_signal(c);
}
public function broadcast():Void {
untyped __global__.__hxcpp_condition_broadcast(c);
}
}

View File

@ -0,0 +1,22 @@
package sys.thread;
@:coreApi
class Semaphore {
var m:Dynamic;
public function new(value:Int) {
m = untyped __global__.__hxcpp_semaphore_create(value);
}
public function acquire():Void {
untyped __global__.__hxcpp_semaphore_acquire(m);
}
public function tryAcquire(?timeout:Float):Bool {
return untyped __global__.__hxcpp_semaphore_try_acquire(m, timeout == null ? 0 : (timeout:Float));
}
public function release():Void {
untyped __global__.__hxcpp_semaphore_release(m);
}
}

View File

@ -46,6 +46,8 @@ class HostClasses {
"sys.thread.Mutex",
"sys.thread.Thread",
"sys.thread.Tls",
"sys.thread.Semaphore",
"sys.thread.Condition",
"cpp.vm.ExecutionTrace",
"cpp.vm.Gc",
"cpp.vm.Profiler",
@ -53,6 +55,7 @@ class HostClasses {
"cpp.vm.WeakRef",
"cpp.Object",
"cpp.Int64",
"cpp.Int64Map",
"cpp.Finalizable",
"Std",
"StringBuf",
@ -147,6 +150,7 @@ class HostClasses {
"List",
"Map",
"String",
"haxe.atomic.AtomicInt"
];
static function parseClassInfo(externs:Map<String, Bool>, filename:String) {

View File

@ -23,6 +23,8 @@
import cs.Boot;
import cs.Lib;
using StringTools;
@:coreApi @:nativeGen class Std {
@:deprecated('Std.is is deprecated. Use Std.isOfType instead.')
public static inline function is(v:Dynamic, t:Dynamic):Bool {
@ -79,54 +81,74 @@ import cs.Lib;
return cast x;
}
static inline function isSpaceChar(code:Int):Bool
return (code > 8 && code < 14) || code == 32;
static inline function isHexPrefix(cur:Int, next:Int):Bool
return cur == '0'.code && (next == 'x'.code || next == 'X'.code);
static inline function isDecimalDigit(code:Int):Bool
return '0'.code <= code && code <= '9'.code;
static inline function isHexadecimalDigit(code:Int):Bool
return isDecimalDigit(code) || ('a'.code <= code && code <= 'f'.code) || ('A'.code <= code && code <= 'F'.code);
public static function parseInt(x:String):Null<Int> {
if (x == null)
return null;
var base = 10;
var len = x.length;
var foundCount = 0;
var sign = 0;
var firstDigitIndex = 0;
var lastDigitIndex = -1;
var previous = 0;
final len = x.length;
var index = 0;
for(i in 0...len) {
var c = StringTools.fastCodeAt(x, i);
switch c {
case _ if((c > 8 && c < 14) || c == 32):
if(foundCount > 0) {
return null;
}
continue;
case '-'.code if(foundCount == 0):
sign = -1;
case '+'.code if(foundCount == 0):
sign = 1;
case '0'.code if(foundCount == 0 || (foundCount == 1 && sign != 0)):
case 'x'.code | 'X'.code if(previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
base = 16;
case _ if('0'.code <= c && c <= '9'.code):
case _ if(base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
case _:
break;
}
if((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
firstDigitIndex = i;
}
foundCount++;
lastDigitIndex = i;
previous = c;
inline function hasIndex(index:Int)
return index < len;
// skip whitespace
while (hasIndex(index)) {
if (!isSpaceChar(x.unsafeCodeAt(index)))
break;
++index;
}
if(firstDigitIndex <= lastDigitIndex) {
var digits = x.substring(firstDigitIndex, lastDigitIndex + 1);
return try {
(sign == -1 ? -1 : 1) * cs.system.Convert.ToInt32(digits, base);
} catch(e:cs.system.FormatException) {
null;
// handle sign
final isNegative = hasIndex(index) && {
final sign = x.unsafeCodeAt(index);
if (sign == '-'.code || sign == '+'.code) {
++index;
}
sign == '-'.code;
}
return null;
// handle base
final isHexadecimal = hasIndex(index + 1) && isHexPrefix(x.unsafeCodeAt(index), x.unsafeCodeAt(index + 1));
if (isHexadecimal)
index += 2; // skip prefix
// handle digits
final firstInvalidIndex = {
var cur = index;
if (isHexadecimal) {
while (hasIndex(cur)) {
if (!isHexadecimalDigit(x.unsafeCodeAt(cur)))
break;
++cur;
}
} else {
while (hasIndex(cur)) {
if (!isDecimalDigit(x.unsafeCodeAt(cur)))
break;
++cur;
}
}
cur;
}
// no valid digits
if (index == firstInvalidIndex)
return null;
final result = cs.system.Convert.ToInt32(x.substring(index, firstInvalidIndex), if (isHexadecimal) 16 else 10);
return if (isNegative) -result else result;
}
public static function parseFloat(x:String):Float {

View File

@ -26,7 +26,6 @@ import cs.system.threading.Thread;
@:coreApi
class Sys {
private static var _env:haxe.ds.StringMap<String>;
private static var _args:Array<String>;
public static inline function print(v:Dynamic):Void {
@ -50,22 +49,17 @@ class Sys {
return Environment.GetEnvironmentVariable(s);
}
public static function putEnv(s:String, v:String):Void {
public static function putEnv(s:String, v:Null<String>):Void {
Environment.SetEnvironmentVariable(s, v);
if (_env != null)
_env.set(s, v);
}
public static function environment():Map<String, String> {
if (_env == null) {
var e = _env = new haxe.ds.StringMap();
var nenv = Environment.GetEnvironmentVariables().GetEnumerator();
while (nenv.MoveNext()) {
e.set(nenv.Key, nenv.Value);
}
final env = new haxe.ds.StringMap();
final nenv = Environment.GetEnvironmentVariables().GetEnumerator();
while (nenv.MoveNext()) {
env.set(nenv.Key, nenv.Value);
}
return _env;
return env;
}
public static inline function sleep(seconds:Float):Void {
@ -78,7 +72,7 @@ class Sys {
}
public static inline function getCwd():String {
return cs.system.io.Directory.GetCurrentDirectory();
return haxe.io.Path.addTrailingSlash(cs.system.io.Directory.GetCurrentDirectory());
}
public static inline function setCwd(s:String):Void {

View File

@ -1,20 +1,26 @@
package haxe;
import haxe.iterators.RestIterator;
import haxe.iterators.RestKeyValueIterator;
import cs.NativeArray;
import cs.system.Array as CsArray;
import haxe.iterators.RestIterator;
import haxe.iterators.RestKeyValueIterator;
private typedef NativeRest<T> = #if erase_generics NativeArray<Dynamic> #else NativeArray<T> #end;
@:coreApi
abstract Rest<T>(NativeRest<T>) {
public var length(get,never):Int;
public var length(get, never):Int;
inline function get_length():Int
return this.Length;
@:from static public inline function of<T>(array:Array<T>):Rest<T>
#if erase_generics
// This is wrong but so is everything else in my life
return new Rest(@:privateAccess array.__a);
#else
return new Rest(cs.Lib.nativeArray(array, false));
#end
inline function new(a:NativeRest<T>):Void
this = a;
@ -51,4 +57,4 @@ abstract Rest<T>(NativeRest<T>) {
public function toString():String {
return toArray().toString();
}
}
}

View File

@ -0,0 +1,61 @@
package haxe.atomic;
private class IntWrapper {
public var value:Int;
public function new(value:Int) {
this.value = value;
}
}
abstract AtomicInt(IntWrapper) {
public inline function new(value:Int) {
this = new IntWrapper(value);
}
private inline function cas_loop(value:Int, op:(a:Int, b:Int) -> Int):Int {
var oldValue;
var newValue;
do {
oldValue = load();
newValue = op(oldValue, value);
} while(compareExchange(oldValue, newValue) != oldValue);
return oldValue;
}
public inline function add(b:Int):Int {
return cas_loop(b, (a, b) -> a + b);
}
public inline function sub(b:Int):Int {
return cas_loop(b, (a, b) -> a - b);
}
public inline function and(b:Int):Int {
return cas_loop(b, (a, b) -> cast a & b);
}
public inline function or(b:Int):Int {
return cas_loop(b, (a, b) -> cast a | b);
}
public inline function xor(b:Int):Int {
return cas_loop(b, (a, b) -> cast a ^ b);
}
public inline function compareExchange(expected:Int, replacement:Int):Int {
return cs.Syntax.code("System.Threading.Interlocked.CompareExchange(ref ({0}).value, {1}, {2})", this, replacement, expected);
}
public inline function exchange(value:Int):Int {
return cs.Syntax.code("System.Threading.Interlocked.Exchange(ref ({0}).value, {1})", this, value);
}
public inline function load():Int {
return this.value; // according to the CLI spec reads and writes are atomic
}
public inline function store(value:Int):Int {
return this.value = value; // according to the CLI spec reads and writes are atomic
}
}

View File

@ -0,0 +1,33 @@
package haxe.atomic;
import cs.system.threading.Interlocked.*;
private class ObjectWrapper<T:{}> {
public var value:T;
public function new(value:T) {
this.value = value;
}
}
extern abstract AtomicObject<T:{}>(ObjectWrapper<T>) {
public inline function new(value:T) {
this = new ObjectWrapper(value);
}
public inline function compareExchange(expected:T, replacement:T):T {
return cs.Syntax.code("System.Threading.Interlocked.CompareExchange(ref ({0}).value, {1}, {2})", this, replacement, expected);
}
public inline function exchange(value:T):T {
return cs.Syntax.code("System.Threading.Interlocked.Exchange(ref ({0}).value, {1})", this, value);
}
public inline function load():T {
return this.value; // according to the CLI spec reads and writes are atomic
}
public inline function store(value:T):T {
return this.value = value; // according to the CLI spec reads and writes are atomic
}
}

View File

@ -364,7 +364,7 @@ import cs.NativeArray;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -373,7 +373,7 @@ import cs.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -378,7 +378,7 @@ import cs.NativeArray;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(Std.string(i));
@ -387,7 +387,7 @@ import cs.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -377,7 +377,7 @@ import cs.NativeArray;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -386,7 +386,7 @@ import cs.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -0,0 +1,37 @@
package sys.thread;
import cs.system.threading.Monitor;
@:coreApi
@:access(sys.thread.Mutex)
class Condition {
final object:cs.system.Object;
public function new():Void {
this.object = new cs.system.Object();
}
public function acquire():Void {
Monitor.Enter(object);
}
public function tryAcquire():Bool {
return Monitor.TryEnter(object);
}
public function release():Void {
Monitor.Exit(object);
}
public function wait():Void {
Monitor.Wait(object);
}
public function signal():Void {
Monitor.Pulse(object);
}
public function broadcast():Void {
Monitor.PulseAll(object);
}
}

View File

@ -0,0 +1,22 @@
package sys.thread;
@:coreApi
class Semaphore {
final native:cs.system.threading.Semaphore;
public function new(value:Int):Void {
this.native = new cs.system.threading.Semaphore(value, 0x7FFFFFFF);
}
public function acquire():Void {
native.WaitOne();
}
public function tryAcquire(?timeout:Float):Bool {
return native.WaitOne(timeout == null ? 0 : Std.int(timeout * 1000));
}
public function release():Void {
native.Release();
}
}

View File

@ -230,7 +230,7 @@ class DynamicObject extends HxObject {
if (ts != null)
return ts();
var ret = new StringBuf();
ret.add("{");
ret.add("[");
var first = true;
for (f in Reflect.fields(this)) {
if (first)
@ -244,7 +244,7 @@ class DynamicObject extends HxObject {
}
if (!first)
ret.add(" ");
ret.add("}");
ret.add("]");
return ret.toString();
}
}

View File

@ -33,7 +33,7 @@ class Sys {
extern static public function getEnv(s:String):String;
extern static public function putEnv(s:String, v:String):Void;
extern static public function putEnv(s:String, v:Null<String>):Void;
extern static public function environment():Map<String, String>;

View File

@ -18,7 +18,10 @@ class Exception {
if(Std.isOfType(value, Exception)) {
return value;
} else {
return new ValueException(value, null, value);
var e = new ValueException(value, null, value);
// Undo automatic __shiftStack()
e.__unshiftStack();
return e;
}
}
@ -63,6 +66,12 @@ class Exception {
__skipStack++;
}
@:noCompletion
@:ifFeature("haxe.Exception.get_stack")
inline function __unshiftStack():Void {
__skipStack--;
}
function get_message():String {
return __exceptionMessage;
}

View File

@ -5,8 +5,8 @@ import haxe.io.Bytes;
extern class PkContext {
function new():Void;
function parse_key(key:Bytes, ?pwd:String):Int;
function parse_keyfile(path:String, ?password:String):Int;
function parse_key(key:Bytes, ?pwd:String, ctr_dbg: CtrDrbg):Int;
function parse_keyfile(path:String, ?password:String, ctr_dbg: CtrDrbg):Int;
function parse_public_key(key:Bytes):Int;
function parse_public_keyfile(path:String):Int;
}

View File

@ -43,11 +43,11 @@ class Host {
this.ip = ip;
}
extern static public function localhost();
extern static public function localhost():String;
extern static function hostReverse(ip:Int);
extern static function hostReverse(ip:Int):String;
extern static function hostToString(ip:Int);
extern static function hostToString(ip:Int):String;
extern static function resolve(name:String);
extern static function resolve(name:String):Int;
}

View File

@ -38,7 +38,7 @@ class Key {
var code = if (isPublic) {
key.native.parse_public_keyfile(file);
} else {
key.native.parse_keyfile(file, pass);
key.native.parse_keyfile(file, pass, Mbedtls.getDefaultCtrDrbg());
}
if (code != 0) {
throw(mbedtls.Error.strerror(code));
@ -51,7 +51,7 @@ class Key {
var code = if (isPublic) {
key.native.parse_public_key(data);
} else {
key.native.parse_key(data);
key.native.parse_key(data, null, Mbedtls.getDefaultCtrDrbg());
}
if (code != 0) {
throw(mbedtls.Error.strerror(code));

View File

@ -0,0 +1,41 @@
package sys.thread;
@:coreApi class Condition {
final cond:eval.luv.Condition;
final mutex:eval.luv.Mutex;
public function new():Void {
cond = eval.luv.Condition.init().resolve();
mutex = eval.luv.Mutex.init(true).resolve();
eval.vm.Gc.finalise(destroy, this);
}
static function destroy(cond:Condition):Void {
cond.cond.destroy();
cond.mutex.destroy();
}
public function acquire():Void {
mutex.lock();
}
public function tryAcquire():Bool {
return mutex.tryLock().isOk();
}
public function release():Void {
mutex.unlock();
}
public function wait():Void {
cond.wait(mutex);
}
public function signal():Void {
cond.signal();
}
public function broadcast():Void {
cond.broadcast();
}
}

View File

@ -3,12 +3,23 @@ package sys.thread;
import eval.luv.Loop;
import eval.luv.Async;
import eval.luv.Timer as LuvTimer;
import haxe.MainLoop;
/**
When an event loop has an available event to execute.
**/
@:coreApi
enum NextEventTime {
/** There's already an event waiting to be executed */
Now;
/** No new events are expected. */
Never;
/**
An event is expected to arrive at any time.
If `time` is specified, then the event will be ready at that time for sure.
*/
AnyTime(time:Null<Float>);
/** An event is expected to be ready for execution at `time`. */
At(time:Float);
}
@ -27,37 +38,47 @@ private class RegularEvent {
}
}
/**
An event loop implementation used for `sys.thread.Thread`
**/
@:coreApi
class EventLoop {
@:allow(eval.luv.Loop)
final handle:Loop;
final mutex = new Mutex();
final oneTimeEvents = new Array<Null<()->Void>>();
var oneTimeEventsIdx = 0;
final wakeup:Async;
var promisedEventsCount = 0;
var pending:Array<()->Void> = [];
var looping = false;
var started:Bool = false;
var isMainThread:Bool;
static var CREATED : Bool;
public function new():Void {
isMainThread = !CREATED;
CREATED = true;
handle = Loop.init().resolve();
wakeup = Async.init(handle, consumePending).resolve();
wakeup.unref();
}
/**
Schedule event for execution every `intervalMs` milliseconds in current loop.
**/
public function repeat(event:()->Void, intervalMs:Int):EventHandler {
var e = new RegularEvent(event);
mutex.acquire();
pending.push(() -> {
e.timer = LuvTimer.init(handle).resolve();
e.timer.start(e.run, intervalMs, intervalMs < 1 ? 1 : intervalMs).resolve();
});
e.timer = LuvTimer.init(handle).resolve();
e.timer.start(e.run, intervalMs, intervalMs < 1 ? 1 : intervalMs).resolve();
mutex.release();
wakeup.send();
return e;
}
/**
Prevent execution of a previously scheduled event in current loop.
**/
public function cancel(eventHandler:EventHandler):Void {
mutex.acquire();
(eventHandler:RegularEvent).event = noop;
@ -71,6 +92,11 @@ class EventLoop {
}
static final noop = function() {}
/**
Notify this loop about an upcoming event.
This makes the thread stay alive and wait for as many events as the number of
times `.promise()` was called. These events should be added via `.runPromised()`.
**/
public function promise():Void {
mutex.acquire();
++promisedEventsCount;
@ -79,6 +105,9 @@ class EventLoop {
wakeup.send();
}
/**
Execute `event` as soon as possible.
**/
public function run(event:()->Void):Void {
mutex.acquire();
pending.push(event);
@ -86,6 +115,9 @@ class EventLoop {
wakeup.send();
}
/**
Add previously promised `event` for execution.
**/
public function runPromised(event:()->Void):Void {
mutex.acquire();
--promisedEventsCount;
@ -96,7 +128,7 @@ class EventLoop {
}
function refUnref():Void {
if(promisedEventsCount > 0) {
if (promisedEventsCount > 0 || (isMainThread && haxe.MainLoop.hasEvents())) {
wakeup.ref();
} else {
wakeup.unref();
@ -104,37 +136,68 @@ class EventLoop {
}
public function progress():NextEventTime {
//TODO: throw if loop is already running
if((handle:Loop).run(NOWAIT)) {
if (started) throw "Event loop already started";
if (handle.run(NOWAIT)) {
return AnyTime(null);
} else {
return Never;
}
}
/**
Blocks until a new event is added or `timeout` (in seconds) to expires.
Depending on a target platform this method may also automatically execute arriving
events while waiting. However if any event is executed it will stop waiting.
Returns `true` if more events are expected.
Returns `false` if no more events expected.
Depending on a target platform this method may be non-reentrant. It must
not be called from event callbacks.
**/
public function wait(?timeout:Float):Bool {
//TODO: throw if loop is already running
if(timeout == null) {
if (started) throw "Event loop already started";
if(timeout != null) {
var timer = LuvTimer.init(handle).resolve();
timer.start(() -> {
timer.stop().resolve();
timer.close(() -> {});
}, Std.int(timeout * 1000));
return (handle:Loop).run(ONCE);
return handle.run(ONCE);
} else {
return (handle:Loop).run(ONCE);
return handle.run(ONCE);
}
}
/**
Execute all pending events.
Wait and execute as many events as the number of times `promise()` was called.
Runs until all repeating events are cancelled and no more events are expected.
Depending on a target platform this method may be non-reentrant. It must
not be called from event callbacks.
**/
public function loop():Void {
//TODO: throw if loop is already running
if (started) throw "Event loop already started";
started = true;
consumePending();
(handle:Loop).run(DEFAULT);
handle.run(DEFAULT);
}
function consumePending(?_:Async):Void {
mutex.acquire();
var p = pending;
pending = [];
mutex.release();
for(fn in p) fn();
if (started && isMainThread) {
var next = @:privateAccess MainLoop.tick();
if (haxe.MainLoop.hasEvents()) wakeup.send();
refUnref();
}
}
}
}

View File

@ -0,0 +1,36 @@
package sys.thread;
@:coreApi class Semaphore {
final native:eval.luv.Semaphore;
public function new(value:Int):Void {
native = eval.luv.Semaphore.init(value).resolve();
eval.vm.Gc.finalise(destroy, this);
}
static function destroy(sem:Semaphore):Void {
sem.native.destroy();
}
public function acquire():Void {
native.wait();
}
public function tryAcquire(?timeout:Float):Bool {
if (timeout == null) {
return native.tryWait().isOk();
} else {
var t = Sys.time() + timeout;
while (Sys.time() < t) {
if (native.tryWait().isOk()) {
return true;
}
}
return false;
}
}
public function release():Void {
native.post();
}
}

View File

@ -18,10 +18,6 @@ package eval.integers;
/**
Parse the given string value to an unsigned integer.
<<<<<<< HEAD
=======
>>>>>>> development
Throws if the given string is not a valid representation of an unsigned
integer.
**/

View File

@ -60,14 +60,14 @@ typedef DirectoryScan = {
**/
extern class DirSync {
@:inheritDoc(eval.luv.Dir.open)
static public function open(loop:Loop, path:NativeString):Result<Dir>;
static public function open(path:NativeString):Result<Dir>;
@:inheritDoc(eval.luv.Dir.close)
static public function close(dir:Dir, loop:Loop):Result<Result.NoData>;
static public function close(dir:Dir):Result<Result.NoData>;
@:inheritDoc(eval.luv.Dir.read)
static public function read(dir:Dir, loop:Loop, ?numberOfEntries:Int):Result<Array<Dirent>>;
static public function read(dir:Dir, ?numberOfEntries:Int):Result<Array<Dirent>>;
@:inheritDoc(eval.luv.Dir.scan)
static public function scan(loop:Loop, path:NativeString):Result<DirectoryScan>;
static public function scan(path:NativeString):Result<DirectoryScan>;
}

View File

@ -16,6 +16,11 @@ extern class Env {
**/
static function setEnv(name:String, value:NativeString):Result<Result.NoData>;
/**
Deletes an environment variable.
**/
static function unsetEnv(name:String):Result<Result.NoData>;
/**
Retrieves all environment variables.
**/

View File

@ -26,11 +26,11 @@ enum abstract FsEventFlag(Int) {
/**
Starts the handle and watches the given path for changes.
**/
public function start(path:NativeString, ?flags:Array<FsEventFlag>, callback:(result:Result<{file:NativeString,events:Array<FsEventType>}>)->Void):Void;
public function start(path:NativeString, ?flags:Array<FsEventFlag>, callback:(result:Result<{file:Null<NativeString>,events:Array<FsEventType>}>)->Void):Void;
/**
Stops the handle.
**/
public function stop():Result<Result.NoData>;
}
}

View File

@ -41,12 +41,12 @@ extern class Resource {
/**
Evaluates to the amount of free memory, in bytes.
**/
static function freeMemory():UInt64;
static function freeMemory():Null<UInt64>;
/**
Evaluates to the total amount of memory, in bytes.
**/
static function totalMemory():UInt64;
static function totalMemory():Null<UInt64>;
/**
Gets the amount of memory available to the process (in bytes) based on
@ -68,11 +68,11 @@ extern class Resource {
/**
Evaluates to the resident set size for the current process.
**/
static function residentSetMemory(pid:Int):Result<UInt64>;
static function residentSetMemory():Result<UInt64>;
/**
Gets the resource usage measures for the current process.
**/
static function getRUsage():Result<RUsage>;
}
}

View File

@ -162,6 +162,10 @@ enum abstract UVError(Int) {
var UV_EFTYPE = 76;
/** illegal byte sequence */
var UV_EILSEQ = 77;
/** value too large for defined data type **/
var UV_EOVERFLOW = 78;
/** socket type not supported**/
var UV_ESOCKTNOSUPPORT = 79;
/**
Converts a system error code to a libuv error.

View File

@ -100,4 +100,10 @@ class Lib {
str = str.split("\\").join("\\\\");
flash.external.ExternalInterface.call("console." + type, str);
}
public static var parseInt(get, never):(string:String, ?radix:Int) -> Float;
extern static inline function get_parseInt():(string:String, ?radix:Int) -> Float {
return untyped __global__["parseInt"];
}
}

View File

@ -49,13 +49,12 @@ import flash.Boot;
return untyped __int__(x);
}
public static function parseInt(x:String):Null<Int>
untyped {
var v = __global__["parseInt"](x);
if (__global__["isNaN"](v))
return null;
return v;
}
public static function parseInt(x:String):Null<Int> {
final v = flash.Lib.parseInt(x);
if (Math.isNaN(v))
return null;
return cast v;
}
public static function parseFloat(x:String):Float {
return untyped __global__["parseFloat"](x);

View File

@ -69,7 +69,7 @@ package haxe.ds;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -78,7 +78,7 @@ package haxe.ds;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -66,14 +66,14 @@ class ObjectMap<K:{}, V> extends flash.utils.Dictionary implements haxe.Constrai
}
public function toString():String {
var s = "";
var s = "[";
var it = keys();
for (i in it) {
s += (s == "" ? "" : ",") + Std.string(i);
s += " => ";
s += Std.string(get(i));
}
return s + "}";
return s + "]";
}
public function clear():Void {

View File

@ -107,7 +107,7 @@ package haxe.ds;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -116,7 +116,7 @@ package haxe.ds;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -74,7 +74,7 @@ class UnsafeStringMap<T> implements haxe.Constraints.IMap<String, T> {
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -83,7 +83,7 @@ class UnsafeStringMap<T> implements haxe.Constraints.IMap<String, T> {
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -66,14 +66,14 @@ class WeakMap<K:{}, V> extends flash.utils.Dictionary implements haxe.Constraint
}
public function toString():String {
var s = "";
var s = "[";
var it = keys();
for (i in it) {
s += (s == "" ? "" : ",") + Std.string(i);
s += " => ";
s += Std.string(get(i));
}
return s + "}";
return s + "]";
}
public function clear():Void {

View File

@ -8,7 +8,7 @@ package flash.globalization;
function format(dateTime : Date) : String;
function formatUTC(dateTime : Date) : String;
function getDateStyle() : DateTimeStyle;
function getDateTimePattern() : DateTimeStyle;
function getDateTimePattern() : String;
function getFirstWeekday() : Int;
function getMonthNames(?nameStyle : DateTimeNameStyle, ?context : DateTimeNameContext) : flash.Vector<String>;
function getTimeStyle() : DateTimeStyle;

View File

@ -150,6 +150,23 @@ class EntryPoint {
flash.Lib.current.stage.addEventListener(flash.events.Event.ENTER_FRAME, function(_) processEvents());
#elseif (target.threaded && !cppia)
//everything is delegated to sys.thread.EventLoop
#elseif lua
inline function luvRun(mode:String):Bool
return untyped __lua__('_hx_luv.run({0})', mode);
while (true) {
var nextTick = processEvents();
if(untyped __lua__('_hx_luv.loop_alive()')) {
if(nextTick < 0)
luvRun("once")
else
luvRun("nowait");
} else {
if (nextTick < 0)
break;
if (nextTick > 0)
sleepLock.wait(nextTick);
}
}
#elseif sys
while (true) {
var nextTick = processEvents();

View File

@ -40,6 +40,14 @@ abstract EnumFlags<T:EnumValue>(Int) {
this = i;
}
@:from static function from<T:EnumValue>(e:T) : EnumFlags<T> {
return new EnumFlags(1 << e.getIndex());
}
@:op(a|b) function or(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
@:op(a&b) function and(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
@:op(a^b) function xor(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
/**
Checks if the index of enum instance `v` is set.
@ -76,6 +84,22 @@ abstract EnumFlags<T:EnumValue>(Int) {
this &= 0xFFFFFFFF - (1 << Type.enumIndex(v));
}
/**
Depending on the value of `condition` sets (`condition=true`) or unsets (`condition=false`)
the index of enum instance `v`.
This method is optimized if `v` is an enum instance expression such as
`SomeEnum.SomeCtor`.
If `v` is `null`, the result is unspecified.
**/
public inline function setTo(v:T, condition:Bool):Void {
if(condition)
set(v)
else
unset(v);
}
/**
Convert a integer bitflag into a typed one (this is a no-op, it does not
have any impact on speed).

View File

@ -37,7 +37,7 @@ extern class EnumTools {
If `e` is inside a package, the package structure is returned dot-
separated, with another dot separating the enum name:
pack1.pack2.(...).packN.EnumName
If `e` is a sub-type of a Haxe module, that module is not part of the
@ -110,6 +110,11 @@ extern class EnumTools {
static inline function getConstructors<T>(e:Enum<T>):Array<String> {
return Type.getEnumConstructs(e);
}
#if (java && jvm)
@:noCompletion
extern static function values<T>(en:Enum<T>):java.NativeArray<java.lang.Enum<T>>;
#end
}
/**

View File

@ -25,7 +25,7 @@ package haxe;
/**
Cross-platform JSON API: it will automatically use the optimized native API if available.
Use `-D haxeJSON` to force usage of the Haxe implementation even if a native API is found:
This will provide extra encoding features such as enums (replaced by their index) and StringMaps.
This will provide extra encoding (but not decoding) features such as enums (replaced by their index) and StringMaps.
@see https://haxe.org/manual/std-Json.html
**/

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