a quickjs binding version is under development, it supports more modern javascript features. unity-jsb
Integerate duktape (an embedded javascript engine) into unity, you can load and run javascript at runtime.
Typescript is a preferred choice, it provides type checks.
- nodejs-like module or browser-like singular js depends on you
- generate C# to js type binding code, and coresponding d.ts type definition files
- setTimeout/setInterval/clearTimeout/clearInterval compatible
- c# delegates
- optimized unity common valuetypes (Vector2/3,Quaternion,Color...)
- fixed-point math support (libfixmath)
- websocket (libwebsockets)
- iOS (64bit, bitcode)
- Android (v7a, v8a, x86)
- remote debugger (vscode)
- promise (bluebird.js)
- coroutine (duktape thread)
- socket (tcp/udp)
- kcp (not implemented)
You can use lots of pure js libraries in your project, such as protobufjs.
The generated d.ts files will improve auto-complete. It will give the information of exposed types from C# and C.
- delegate type information
- generic constraints for out/ref parameter
- friendly interface for AddComponent/GetComponent
If you use typescript, install typescript at first
npm install -g typescript
# --depth=1 is highly recommended
git clone https://github.com/ialex32x/duktape-unity --depth=1
python/pip/pyyaml is prerequisites.
pip install pyyaml
duktape original source code is at /duktape-/src-input
./configure_duktape.bat # combined duktape source code will be generated
# at:
# /build/src-debug (with debugger)
# /build/src-release (without debugger)
./make_duktape_<platform>.bat # or ./make_duktape_<platform>.sh in osx
if you build duktape for android in windows, run make_duktape_android.bat in visual studio cross tools commandline (e.g VS2015 x64 ARM Cross Tools Command Prompt).
'./scratch' is a playground for duktape testing in a simple command line app.
./configure_duktape_scratch.bat
./make_duktape_scratch.bat
// if your tsconfig.json defined {"module": "commonjs"}, you can 'import' modules like node-js.
// import module
import { B } from "base/b"
// import module with relative path (. or ..)
import { C } from "./base/c"
class MyPlayer {
Start() {
console.log("MyPlayer.Start")
this.Jump()
}
// Update() {
// }
Jump() {
console.log("MyPlayer.Jump")
}
}
export class A {
private go: GameObject
constructor () {
this.go = new GameObject("test go")
this.go.transform.localPosition = new Vector3(1, 2, 3)
// use Bridge to receive Enable/Disable/Update
// don't use the approach a lot, it's better to dispatch futher logic in a single Bridge
this.go.AddComponent(DuktapeJS.Bridge).SetBridge(new MyPlayer())
let f = new Custom()
// you can assign function to c# delegate
f.onopen = function () {
// ...
}
// if you want to register multiple listener, use DuktapeJS.Dispather
// you can also use typed Dispatcher generated in _DuktapeDelegates.d.ts, it provides type checks
f.onload = new DuktapeJS.Dispatcher1<void, string>()
f.onload.on(this, this.onload) // add listener
f.onload.off(this, this.onload) // remove listener
f.onload.off(this) // clear all listeners of this
f.onload.clear() // clear all
// 'out' parameter in c#
let v = {}
if (System.Int32.TryParse("123", v)) {
console.log(v.target)
}
}
private onload(ev: string) {
let timer1 = setInterval(() => {
console.log("interval")
}, 1000)
setTimeout((a, b) => {
console.log("timeout", a, b)
clearInterval(timer1)
}, 5000, "Arg1", 123)
}
square() {
console.log("A.square")
}
}
// websocket
let ws = DuktapeJS.WebSocket()
ws.on("open", () => {
console.log("connected")
setInterval(() => {
ws.send("hello, world") // string or buffer
}, 1000)
})
ws.on("data", data => {
console.log("ws receive data", data) // string or buffer (depends on websocket message type you use)
})
ws.on("close", () => {
console.log("connection lost")
})
ws.connect("ws://127.0.0.1:8080/echo")
setInterval(() => {
ws.poll()
}, 50)
// http request example
console.log("http requesting...");
HttpRequest.GET("http://t.weather.sojson.com/api/weather/city/101030100", null, (status, res) => {
console.warn("http response:", status, res);
if (status) {
let obj = JSON.parse(res);
console.log("as object", obj.message);
}
});
// coroutine example
let co = new Coroutine(function (x) {
console.log("duktape thread, start:", x);
for (var i = 1; i <= 5; ++i) {
let r = Coroutine.yield(i);
console.log("duktape thread, yield:", r);
}
// Coroutine.break();
return "all done!";
});
let c = 'A'.charCodeAt(0);
while (co.next(String.fromCharCode(c++))) {
console.log("duktape thread, next:", co.value);
}
console.log("duktape thread, done:", co.value);
It's not stable enough, do not use it in production environment.
Vector2/Matrix3x3/Matrix4x4/Quaternion valuetypes optimization is partially written in c, and not fully tested.
Execute menu item [Duktape -> Generate Bindings] to generate binding code. Typescript source files will be compiled into js after your modification and switch back to Unity Editor.
- duktape.json modify the basic configuration at ./duktape.json (details in Assets/Duktape/Editor/Prefs.cs)
{
"outDir": "Assets/Generated",
"typescriptDir": "Assets/Generated",
"extraExt": "",
// rootpath of ts/js project
"workspace": "",
"logPath": "Temp/duktape.log",
// auto, cr, lf, crlf
"newLineStyle": "auto",
"implicitAssemblies": [
"UnityEngine",
"UnityEngine.CoreModule",
"UnityEngine.UI",
"UnityEngine.UIModule"
],
"explicitAssemblies": [
"Assembly-CSharp"
],
// types in blacklist will not be exported
"typePrefixBlacklist": [
"JetBrains.",
"Unity.Collections.",
"Unity.Jobs.",
"Unity.Profiling.",
"UnityEditor.",
"UnityEditorInternal.",
"UnityEngineInternal.",
"UnityEditor.Experimental.",
"UnityEngine.Experimental.",
"Unity.IO.LowLevel.",
"Unity.Burst.",
// more types ...
"UnityEngine.Assertions."
],
"ns": "DuktapeJS",
"tab": " "
}
- implements Duktape.IBindingProcess interface or extends AbstractBindingProcess class
public class MyCustomBinding : AbstractBindingProcess
{
public override void OnPreCollectTypes(BindingManager bindingManager)
{
/*
bindingManager.AddExportedType(typeof(MyCustomClass));
bindingManager.TransformType(typeof(MyCustomClass))
.SetMethodBlocked("AMethodName")
.SetMethodBlocked("AMethodNameWithParameters", typeof(string), typeof(int))
*/
}
public override void OnCleanup(BindingManager bindingManager)
{
Debug.Log($"finish @ {DateTime.Now}");
}
}
Assets/Scenes/main.unity (Sample.cs) demonstrate the basic usage.
Support js/ts remote debug.
the libraries in unity project is built with debugger support. if you want to use a release version without debugger support, checkout /prebuilt/release. or compile them by yourself.
Name: Duktape Debugger
Id: haroldbrenes.duk-debug
Description: Debug Adapter for Duktape runtimes.
Version: 0.5.6
Publisher: HaroldBrenes
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=HaroldBrenes.duk-debug
If you are debugging ts sources, this extension has some path-resolve issues break the debug process, you can try the modified version.