Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
From e95af80064ec8e20790daeb002d8de1d74e3bf80 Mon Sep 17 00:00:00 2001
From: Vianney Petit <xxxxx@gmail.com>
Date: Sun, 6 Nov 2016 17:26:41 +0100
Subject: [PATCH] Add plugins cache hack
---
SupRuntime/src/index.ts | 46 +++++++++++++------
plugins/default/typescript/runtime/script.ts | 69 +++++++++++++++++++++-------
2 files changed, 83 insertions(+), 32 deletions(-)
diff --git a/SupRuntime/src/index.ts b/SupRuntime/src/index.ts
index 67dd6fb..bf0e149 100644
--- a/SupRuntime/src/index.ts
+++ b/SupRuntime/src/index.ts
@@ -14,6 +14,8 @@ export { Player };
export const plugins: { [name: string]: SupRuntime.RuntimePlugin } = {};
export const resourcePlugins: { [name: string]: SupRuntime.RuntimeResourcePlugin } = {};
+export let jsGlobalsCache : any = null;
+
export function registerPlugin(name: string, plugin: SupRuntime.RuntimePlugin) {
if (plugins[name] != null) {
console.error(`SupRuntime.registerPlugin: Tried to register two or more plugins named "${name}"`);
@@ -122,8 +124,14 @@ const onLoaded = (err: Error) => {
}, (qs.project == null) ? 500 : 0);
};
+const loadGame = () => {
+ const buildPath = (qs.project != null) ? `/builds/${qs.project}/${qs.build}/` : "./";
+ player = new Player(canvas, buildPath, { debug: qs.debug != null });
+ player.load(onLoadProgress, onLoaded);
+}
+
// Load plugins
-const pluginBundleNames = [ "components", "runtime", "typescriptAPI" ];
+let pluginBundleNames : string[];
supFetch("plugins.json", "json", (err: Error, pluginsInfo: SupCore.PluginsInfo) => {
if (err != null) {
@@ -132,20 +140,28 @@ supFetch("plugins.json", "json", (err: Error, pluginsInfo: SupCore.PluginsInfo)
return;
}
- async.each(pluginsInfo.list, (pluginName, cb) => {
- async.each(pluginBundleNames, (bundle, cb) => {
- const script = document.createElement("script");
- script.src = `plugins/${pluginName}/bundles/${bundle}.js`;
- script.addEventListener("load", () => cb(null));
- script.addEventListener("error", (err) => cb(null));
- document.body.appendChild(script);
- }, cb);
- }, (err) => {
- if (err != null) console.log(err);
- // Load game
- const buildPath = (qs.project != null) ? `/builds/${qs.project}/${qs.build}/` : "./";
- player = new Player(canvas, buildPath, { debug: qs.debug != null });
- player.load(onLoadProgress, onLoaded);
+ supFetch("jsGlobalsCache.json", "json", (err: Error, data: any) => {
+ if (err === null) {
+ console.log("jsGlobalsCache.json HIT!");
+ jsGlobalsCache = data;
+ pluginBundleNames = [ "components", "runtime" ];
+ } else {
+ pluginBundleNames = [ "components", "runtime", "typescriptAPI" ];
+ }
+
+ async.each(pluginsInfo.list, (pluginName, cb) => {
+ async.each(pluginBundleNames, (bundle, cb) => {
+ const script = document.createElement("script");
+ script.src = `plugins/${pluginName}/bundles/${bundle}.js`;
+ script.addEventListener("load", () => cb(null));
+ script.addEventListener("error", (err) => cb(null));
+ document.body.appendChild(script);
+ }, cb);
+ }, (err) => {
+ if (err != null) console.log(err);
+ // Load game
+ loadGame();
+ });
});
});
diff --git a/plugins/default/typescript/runtime/script.ts b/plugins/default/typescript/runtime/script.ts
index 5c8a4be..a06d006 100644
--- a/plugins/default/typescript/runtime/script.ts
+++ b/plugins/default/typescript/runtime/script.ts
@@ -18,6 +18,10 @@ const scripts: {[name: string]: string} = {};
const actorComponentTypesByName: {[name: string]: any} = {};
const actorComponentAccessors: string[] = [];
+declare const URLSearchParams : any;
+const pluginsDump : any = {};
+let dump = false;
+
export function init(player: any, callback: Function) {
player.behaviorClasses = {};
@@ -25,7 +29,13 @@ export function init(player: any, callback: Function) {
return new (<any>window).Sup.Actor(name, parentActor, options);
};
- const plugins = SupCore.system.getPlugins<SupCore.TypeScriptAPIPlugin>("typescriptAPI");
+ let plugins : any;
+ if (typeof (SupRuntime as any).jsGlobalsCache !== "undefined" && (SupRuntime as any).jsGlobalsCache !== null) {
+ console.log("Getting plugins from cache...");
+ plugins = (SupRuntime as any).jsGlobalsCache.plugins;
+ } else {
+ plugins = SupCore.system.getPlugins<SupCore.TypeScriptAPIPlugin>("typescriptAPI");
+ }
player.createComponent = (type: string, actor: any, config: any) => {
if (type === "Behavior") {
@@ -46,6 +56,12 @@ export function init(player: any, callback: Function) {
}
};
+ /* Dump plugins? */
+ if (typeof URLSearchParams !== "undefined") {
+ const params = new URLSearchParams(window.location.search);
+ if (params.has("dump")) dump = true;
+ }
+
for (const pluginName in plugins) {
const plugin = plugins[pluginName];
if (plugin.code != null) {
@@ -53,8 +69,15 @@ export function init(player: any, callback: Function) {
globals[`${pluginName}.ts`] = plugin.code;
}
- if (plugin.defs != null) globalDefs[`${pluginName}.d.ts`] = plugin.defs;
- if (plugin.exposeActorComponent != null) actorComponentAccessors.push(`${plugin.exposeActorComponent.propertyName}: ${plugin.exposeActorComponent.className};`);
+ if (dump) pluginsDump[pluginName] = {};
+ if (plugin.defs != null) {
+ if (dump) pluginsDump[pluginName].defs = plugin.defs;
+ globalDefs[`${pluginName}.d.ts`] = plugin.defs;
+ }
+ if (plugin.exposeActorComponent != null) {
+ if (dump) pluginsDump[pluginName].exposeActorComponent = plugin.exposeActorComponent;
+ actorComponentAccessors.push(`${plugin.exposeActorComponent.propertyName}: ${plugin.exposeActorComponent.className};`);
+ }
}
callback();
}
@@ -62,20 +85,32 @@ export function init(player: any, callback: Function) {
export function start(player: SupRuntime.Player, callback: Function) {
console.log("Compiling scripts...");
- // Plug component accessors exposed by plugins into Sup.Actor class
- const joinedActorComponentAccessors = actorComponentAccessors.join("\n ");
- globals["Sup.Actor.ts"] = globals["Sup.Actor.ts"].replace("// INSERT_COMPONENT_ACCESSORS", joinedActorComponentAccessors);
- globalDefs["Sup.Actor.d.ts"] = globalDefs["Sup.Actor.d.ts"].replace("// INSERT_COMPONENT_ACCESSORS", joinedActorComponentAccessors);
-
- // Make sure the Sup namespace, Sup.Actor and Sup.ActorComponent are compiled before everything else
- globalNames.unshift(globalNames.splice(globalNames.indexOf("Sup.Actor.ts"), 1)[0]);
- globalNames.unshift(globalNames.splice(globalNames.indexOf("Sup.ts"), 1)[0]);
-
- // Compile plugin globals
- const jsGlobals = compileTypeScript(globalNames, globals, `${globalDefs["lib.d.ts"]}\ndeclare var console, window, localStorage, player, SupEngine, SupRuntime, require;`, { sourceMap: false });
- if (jsGlobals.errors.length > 0) {
- for (const error of jsGlobals.errors) console.log(`${error.file}(${error.position.line}): ${error.message}`);
- callback(new Error("Compilation failed. Check the devtools (F12) for errors."));
+ let jsGlobals : any;
+ if (typeof (SupRuntime as any).jsGlobalsCache !== "undefined" && (SupRuntime as any).jsGlobalsCache !== null) {
+ jsGlobals = { script: (SupRuntime as any).jsGlobalsCache.script };
+ } else {
+ // Plug component accessors exposed by plugins into Sup.Actor class
+ const joinedActorComponentAccessors = actorComponentAccessors.join("\n ");
+ globals["Sup.Actor.ts"] = globals["Sup.Actor.ts"].replace("// INSERT_COMPONENT_ACCESSORS", joinedActorComponentAccessors);
+ globalDefs["Sup.Actor.d.ts"] = globalDefs["Sup.Actor.d.ts"].replace("// INSERT_COMPONENT_ACCESSORS", joinedActorComponentAccessors);
+
+ // Make sure the Sup namespace, Sup.Actor and Sup.ActorComponent are compiled before everything else
+ globalNames.unshift(globalNames.splice(globalNames.indexOf("Sup.Actor.ts"), 1)[0]);
+ globalNames.unshift(globalNames.splice(globalNames.indexOf("Sup.ts"), 1)[0]);
+
+ // Compile plugin globals
+ jsGlobals = compileTypeScript(globalNames, globals, `${globalDefs["lib.d.ts"]}\ndeclare var console, window, localStorage, player, SupEngine, SupRuntime, require;`, { sourceMap: false });
+ if (jsGlobals.errors.length > 0) {
+ for (const error of jsGlobals.errors) console.log(`${error.file}(${error.position.line}): ${error.message}`);
+ callback(new Error("Compilation failed. Check the devtools (F12) for errors."));
+ return;
+ }
+ }
+ if (dump) {
+ document.write(JSON.stringify({
+ "plugins": pluginsDump,
+ "script": jsGlobals.script
+ }));
return;
}
--
2.8.1.windows.1
From 8ba556e877b7898279d958d6545ed6958df6d014 Mon Sep 17 00:00:00 2001
From: vianney <xxxxx@3dduo.com>
Date: Mon, 31 Oct 2016 16:37:40 +0100
Subject: [PATCH] Fix webaudio detection on old Safari
---
SupEngine/src/Audio.ts | 6 ++++--
SupEngine/src/SoundPlayer.ts | 28 +++++++++++++++++++---------
2 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/SupEngine/src/Audio.ts b/SupEngine/src/Audio.ts
index c1f9bce..902efda 100644
--- a/SupEngine/src/Audio.ts
+++ b/SupEngine/src/Audio.ts
@@ -5,9 +5,11 @@ export default class Audio {
constructor() { /* Nothing here */ }
getContext(): AudioContext {
if (this.ctx != null) return this.ctx;
- if ((window as any).AudioContext == null) return null;
- this.ctx = new AudioContext();
+ const ctx = (window as any).AudioContext || (window as any).webkitAudioContext;
+ if (ctx == null) return null;
+
+ this.ctx = new ctx();
this.masterGain = this.ctx.createGain();
this.masterGain.gain.value = 1;
this.masterGain.connect(this.ctx.destination);
diff --git a/SupEngine/src/SoundPlayer.ts b/SupEngine/src/SoundPlayer.ts
index b3b3c9d..0a689d9 100644
--- a/SupEngine/src/SoundPlayer.ts
+++ b/SupEngine/src/SoundPlayer.ts
@@ -51,13 +51,19 @@ class SoundPlayer {
source.playbackRate.value = Math.pow(2, this.pitch);
}
- this.pannerNode = this.audioCtx.createStereoPanner();
- this.pannerNode.pan.value = this.pan;
- this.pannerNode.connect(this.audioMasterGain);
-
this.gainNode = this.audioCtx.createGain();
this.gainNode.gain.value = this.volume;
- this.gainNode.connect(this.pannerNode);
+
+ if (typeof this.audioCtx.createStereoPanner !== "undefined") {
+ this.pannerNode = this.audioCtx.createStereoPanner();
+ this.pannerNode.pan.value = this.pan;
+ this.pannerNode.connect(this.audioMasterGain);
+
+ this.gainNode.connect(this.pannerNode);
+ } else {
+ this.pannerNode = null;
+ this.gainNode.connect(this.audioMasterGain);
+ }
this.source.connect(this.gainNode);
@@ -90,8 +96,10 @@ class SoundPlayer {
this.gainNode.disconnect();
delete this.gainNode;
- this.pannerNode.disconnect();
- delete this.pannerNode;
+ if (typeof this.pannerNode !== "undefined" && this.pannerNode !== null) {
+ this.pannerNode.disconnect();
+ delete this.pannerNode;
+ }
}
this.offset = 0;
@@ -112,8 +120,10 @@ class SoundPlayer {
this.gainNode.disconnect();
delete this.gainNode;
- this.pannerNode.disconnect();
- delete this.pannerNode;
+ if (typeof this.pannerNode !== "undefined" && this.pannerNode !== null) {
+ this.pannerNode.disconnect();
+ delete this.pannerNode;
+ }
this.state = SoundPlayer.State.Paused;
}
--
2.9.3
From 5f1d0b988437f7dc38933d39e9e1392d55214fcf Mon Sep 17 00:00:00 2001
From: Vianney Petit <xxxxx@gmail.com>
Date: Sun, 6 Nov 2016 10:09:21 +0100
Subject: [PATCH] Small asset and script cache
---
SupRuntime/SupRuntime.d.ts | 2 +-
SupRuntime/src/Player.ts | 67 +++++++++++++++++++++-------
plugins/default/typescript/runtime/script.ts | 19 ++++++--
3 files changed, 68 insertions(+), 20 deletions(-)
diff --git a/SupRuntime/SupRuntime.d.ts b/SupRuntime/SupRuntime.d.ts
index e2bfd2b..ebbe877 100644
--- a/SupRuntime/SupRuntime.d.ts
+++ b/SupRuntime/SupRuntime.d.ts
@@ -42,7 +42,7 @@ declare namespace SupRuntime {
constructor(canvas: HTMLCanvasElement, dataURL: string, options: { debug?: boolean; });
load(progressCallback: (progress: number, total: number) => any, callback: any): void;
run(): void;
- getAssetData(path: string, responseType: string, callback: (err: Error, data?: any) => any): any;
+ getAssetData(path: string, responseType: string, callback: (err: Error, data?: any, cached?: boolean) => any): any;
getOuterAsset(assetId: number): any;
createActor(): any;
createComponent(): any;
diff --git a/SupRuntime/src/Player.ts b/SupRuntime/src/Player.ts
index dbbdb94..e51761f 100644
--- a/SupRuntime/src/Player.ts
+++ b/SupRuntime/src/Player.ts
@@ -38,6 +38,8 @@ export default class Player {
lastTimestamp: number;
tickAnimationFrameId: number;
+ cache: any;
+
constructor(canvas: HTMLCanvasElement, dataURL: string, options: { debug?: boolean; enableOnExit?: boolean; }) {
this.canvas = canvas;
this.dataURL = dataURL;
@@ -47,21 +49,28 @@ export default class Player {
}
load(progressCallback: (progress: number, total: number) => any, callback: any) {
- let progress = 0;
+ supFetch(`${this.dataURL}cache.json`, "application/json", (err: Error, data?: any) => {
+ if (err === null) {
+ if (typeof data === "string") { data = JSON.parse(data); }
+ this.cache = data;
+ }
- const innerProgressCallback = () => {
- progress++;
- const total = this.resourcesToLoad.length + this.assetsToLoad.length;
- progressCallback(progress, total);
- };
- async.series([
- (cb) => { this._loadManifest(cb); },
- (cb) => { this._loadResources(innerProgressCallback, cb); },
- (cb) => { this._loadAssets(innerProgressCallback, cb); },
- (cb) => { this._initPlugins(cb); },
- (cb) => { this._startPlugins(cb); },
- (cb) => { this._lateStartPlugins(cb); }
- ], callback);
+ let progress = 0;
+
+ const innerProgressCallback = () => {
+ progress++;
+ const total = this.resourcesToLoad.length + this.assetsToLoad.length;
+ progressCallback(progress, total);
+ };
+ async.series([
+ (cb) => { this._loadManifest(cb); },
+ (cb) => { this._loadResources(innerProgressCallback, cb); },
+ (cb) => { this._loadAssets(innerProgressCallback, cb); },
+ (cb) => { this._initPlugins(cb); },
+ (cb) => { this._startPlugins(cb); },
+ (cb) => { this._lateStartPlugins(cb); }
+ ], callback);
+ });
}
_loadManifest(callback: Function) {
@@ -201,7 +210,35 @@ export default class Player {
if (updates > 0) this.gameInstance.draw();
};
- getAssetData(path: string, responseType: string, callback: (err: Error, data?: any) => any) {
+ getAssetData(path: string, responseType: string, callback: (err: Error, data?: any, cached?: boolean) => any) {
+ if (typeof this.cache !== "undefined") {
+ let pathComponents = path.split("/");
+ const firstComponent = pathComponents.shift();
+ if (firstComponent === "assets") {
+ let node = this.cache;
+ do {
+ const component = pathComponents.shift();
+ let nextNode : any = null;
+ for (let child of node.children) {
+ if (child.name === component) {
+ nextNode = child;
+ break;
+ }
+ }
+
+ // We couldn't find it
+ if (nextNode === null) break;
+ node = nextNode;
+ } while (pathComponents.length > 0);
+ // We found it
+ if (typeof node.content !== "undefined") {
+ callback(null, node.content, true);
+ return;
+ }
+ }
+ }
+
+ // We don't have it, go over the network
supFetch(`${this.dataURL}${path}`, responseType, callback);
}
diff --git a/plugins/default/typescript/runtime/script.ts b/plugins/default/typescript/runtime/script.ts
index cdc65b2..5c8a4be 100644
--- a/plugins/default/typescript/runtime/script.ts
+++ b/plugins/default/typescript/runtime/script.ts
@@ -12,6 +12,7 @@ const globals: {[name: string]: string} = {};
const globalDefs: {[name: string]: string} = {};
const scriptNames: string[] = [];
+const precompiledScriptNames: string[] = [];
const scripts: {[name: string]: string} = {};
const actorComponentTypesByName: {[name: string]: any} = {};
@@ -82,12 +83,17 @@ export function start(player: SupRuntime.Player, callback: Function) {
let concatenatedGlobalDefs = "";
for (const name in globalDefs) concatenatedGlobalDefs += globalDefs[name];
const results = compileTypeScript(scriptNames, scripts, concatenatedGlobalDefs, { sourceMap: true });
- if (results.errors.length > 0) {
+ if (results.errors.length > 0 && scriptNames.length > 0) {
for (const error of results.errors) console.log(`${error.file}(${error.position.line}): ${error.message}`);
callback(new Error("Compilation failed. Check the devtools (F12) for errors."));
return;
}
+ // Add pre-compiled scripts
+ for (let i = 0; i < precompiledScriptNames.length; i++) {
+ results.script += scripts[precompiledScriptNames[i]];
+ }
+
console.log("Compilation successful!");
// Prepare source maps
@@ -126,9 +132,14 @@ ${jsGlobals.script}
}
export function loadAsset(player: SupRuntime.Player, entry: any, callback: (err: Error, asset?: any) => any) {
- scriptNames.push(`${entry.path}.ts`);
- player.getAssetData(`assets/${entry.storagePath}/script.ts`, "text", (err, script) => {
- scripts[`${entry.path}.ts`] = `${script}\n`;
+ player.getAssetData(`assets/${entry.storagePath}/script.ts`, "text", (err, script, cached) => {
+ if (typeof cached !== "undefined") {
+ precompiledScriptNames.push(`${entry.path}.js`);
+ scripts[`${entry.path}.js`] = `${script}\n`;
+ } else {
+ scriptNames.push(`${entry.path}.ts`);
+ scripts[`${entry.path}.ts`] = `${script}\n`;
+ }
callback(null, script);
});
}
--
2.8.1.windows.1
From 7ccbeee19beeeb3c68748ef7ff229715d70a6c4c Mon Sep 17 00:00:00 2001
From: vianney <xxxxx@3dduo.com>
Date: Wed, 2 Nov 2016 10:48:48 +0100
Subject: [PATCH] supclient-fetch-ie11
---
SupClient/fetch.ts | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/SupClient/fetch.ts b/SupClient/fetch.ts
index 4414377..dc0a4ac 100644
--- a/SupClient/fetch.ts
+++ b/SupClient/fetch.ts
@@ -9,7 +9,17 @@ export default function fetch(url: string, type: string, callback: (err: Error,
return;
}
- callback(null, xhr.response);
+ // Workaround for IE11
+ let response = xhr.response;
+ if (type === "json" && typeof xhr.response === "string") {
+ try {
+ response = JSON.parse(xhr.response);
+ } catch (e) {
+ console.log(e);
+ console.log("SupClient: fetch: failed to parse response as json.");
+ }
+ }
+ callback(null, response);
};
xhr.onerror = (event) => {
--
2.9.3
var fs = require('fs'),
path = require('path'),
mime = require('mime'),
ts = require('typescript'),
uglify = require('uglify-js2'),
tslint = require('tslint');
var nameWhilelist = ["scene.json", "sprite.json", "sound.json", "asset.json", "script.ts"];
var mimeWhilelist = ["application/json"];
var maxSize = 10000;
var linterConfig = {
formatter: "stylish",
configuration: {
rules: {
"quotemark": [true, "double"],
"curly": true,
"forin": true,
"no-invalid-this": true,
"no-switch-case-fall-through": true,
"no-unreachable": true,
"no-unused-expression": true,
"no-unused-new": true,
"no-unused-variable": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"triple-equals": true,
"use-isnan": true,
"no-trailing-whitespace": true,
"object-literal-sort-keys": true,
"new-parens": true,
"semicolon": true
}
},
rulesDirectory: "",
formattersDirectory: ""
};
var compressorConfig = {
warnings: true,
dead_code: true
};
// Taken from: https://stackoverflow.com/questions/11194287/convert-a-directory-structure-in-the-filesystem-to-json-with-node-js/11194896
function dirTree(filename) {
var stats = fs.lstatSync(filename),
info = {
name: path.basename(filename),
};
if (stats.isDirectory()) {
info.children = fs.readdirSync(filename).map(function (child) {
return dirTree(filename + '/' + child);
});
} else {
// info.type = "file";
var isize = stats.size;
var imime = mime.lookup(filename);
if (nameWhilelist.indexOf(info.name) > -1) {
if (mimeWhilelist.indexOf(imime) > -1 && isize < maxSize) {
console.log("Caching small asset '" + filename + "'");
info.content = JSON.parse(fs.readFileSync(filename, 'utf8'));
} else if (info.name === "script.ts") {
console.log("Transpiling and caching script '" + filename + "'");
var source = fs.readFileSync(filename, 'utf8');
// Lint ts
var linter = new tslint(filename, source, linterConfig);
var result = linter.lint();
if (result.failureCount) console.log(result.output);
// Transpile form ts to js
source = ts.transpile(source);
// Compress js
var ast = uglify.parse(source);
ast.figure_out_scope();
var compressor = uglify.Compressor(compressorConfig);
ast = ast.transform(compressor);
source = ast.print_to_string();
info.content = source;
// fs.writeFile(filename.slice(0, -3) + ".js", source);
}
}
}
return info;
}
if (module.parent == undefined) {
var util = require('util');
fs.writeFile("cache.json", JSON.stringify(dirTree(process.argv[2]), false, null));
}
var fs = require('fs'),
uglify = require('uglify-js2');
// Compress "script"
var globalCache = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
var ast = uglify.parse(globalCache.script);
ast.figure_out_scope();
var compressor = uglify.Compressor( /*{ ...compressor_options... }*/ );
ast = ast.transform(compressor);
// Drop unecessary data from "plugins"
for (var pluginName in globalCache.plugins) {
// if (pluginName === "lib") continue;
console.log("Trimming plugin '" + pluginName + "'");
delete globalCache.plugins[pluginName].defs;
delete globalCache.plugins[pluginName].code;
}
// Write result to disk
var compGlobalCache = JSON.stringify({"plugins": globalCache.plugins, "script": ast.print_to_string()});
fs.writeFile("jsGlobalsCache.comp.json", compGlobalCache, false, null);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment