Giter VIP home page Giter VIP logo

puerts's Introduction

Logo

license PRs Welcome

unreal

unity Unity_Test

跳转中文

WHAT is PuerTS (PUER Typescript)?

PuerTS is a TypeScript programming solution in Unity/Unreal/DotNet.

  • provides a JavaScript Runtime.
  • allows TypeScript to access the host engine with the help of TypeScript declarations generation.

WHY should I use PuerTS?

  • Facilitates game-building processes by combining JavaScript/Node.js ecosystem and professional game engines
  • In contrast to Lua script, TypeScript supports static type checking, which significantly improves code robustness and maintainability.
  • High efficiency: supports reflection call throughout the host - no extra steps needed for interop with C++/C#.
  • High performance: supports static wrapper generation - handles complex scenes with high-performance demands.
  • Talented WebGL Support: massive advantage in performance and dev efficiency compared to Lua, even faster than pure C# in some cases.

HOW can I start to use PuerTS

Documentation


FAQ

How to Install

Changelog

Known issues


Avaliable on these Engine

  • unreal engine 4.22 ~ latest

  • unity 5 ~ latest

  • Any .net project

Available on these Platform

  • iOS
  • Android
  • Windows
  • Macos

Ask for help

Discord

Github Discussion


WHAT - 普洱TS是什么?

PuerTS是 Unity/Unreal/Dotnet 下的TypeScript编程解决方案

  • 提供了一个JavaScript运行时
  • 提供TypeScript声明文件生成能力,易于通过TypeScript访问宿主引擎,

WHY - 为什么我该用普洱TS?

  • JavaScript生态有众多的库和工具链,结合专业商业引擎的渲染能力,快速打造游戏
  • 相比游戏领域常用的lua脚本,TypeScript的静态类型检查有助于编写更健壮,可维护性更好的程序
  • 高效:全引擎,全平台支持反射调用,无需额外步骤即可与宿主C++/C#通信。
  • 高性能:全引擎,全平台支持生成静态调用桥梁,兼顾了高性能的场景。
  • WebGL平台下的天生优势:相比Lua脚本在WebGL版本的表现,PuerTS在性能和效率上都有极大提升,目前极限情况甚至比C#更快。

HOW - 我该怎么开始


常见问题

最新版本安装

改动日志

已知问题与解决办法


可用引擎

  • unreal engine 4.22 ~ latest

  • unity 5 ~ latest

  • 任意.net环境

可用平台

  • iOS
  • Android
  • Windows
  • Macos

技术支持

Discord

Github Discussion

QQ群:942696334

UE4专属群:689643903

开发博客

知乎专栏

puerts's People

Contributors

ailhc avatar alanwalk avatar annayxguo avatar arnochenfx avatar b1gm0use avatar blackplume233 avatar bluedoom avatar blurrylight avatar chexiongsheng avatar dawnarc avatar fishorbear avatar hewenning avatar jayatubi avatar jihuayu avatar lcyexiaoci avatar littlesome avatar liuwjchinal avatar ljporljp avatar lzj10 avatar mingxxming avatar morirain avatar mysticfarer avatar primaryfantasty avatar ps5mh avatar qqwx1986 avatar tangxinwei avatar throw-out avatar xtutu avatar zhenlinyang avatar zombieyang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

puerts's Issues

ts 类型判断上空类全一样

可以使用如下代码判断两个类型是否相等。

type Equals<X, Y> =
    (<T>() => T extends X ? 1 : 2) extends
        (<T>() => T extends Y ? 1 : 2) ? true : false;

由于,空类在类型推断时无法被区分,所以导致无法判断拓展函数的第一个参数是否相等。#78
建议给每一个类加一个标识符以便区分。
比如:

class A{
  type:"A"
}

是否有关于v8与lua垃圾回收性能的对比?

因为我之前做过cocos2d-js开发,当时的js引擎是spridemonkey,游戏开发到后期遇到了GC过于频繁的问题,在lua里面比较常见的table(比如Vector2)在js里面都要使用池。
想知道v8的垃圾回收性能与lua对比如何?在网上我没有搜索到相关的文章。
如果没有的话能否提供相关的测试对比,或者讨论一下测试思路我来实现一下?

Unity C#转ts,多载方法变成没有多载

我在Unity C#写了一个函数void Foo(string s = "bar"),按下Generate Code,转成ts,该函数变成Foo(s:string):void。但这样就没有多载,只能手动填入C#函数的预设参数。

生成代码失败UnityEngine_Vector3Int_Wrap.cs

        [Puerts.MonoPInvokeCallback(typeof(Puerts.V8FunctionCallback))]
        private static void O_op_Explicit(IntPtr isolate, IntPtr info, IntPtr self, int paramLen, long data)
        {
            try
            {
                
                
                {
                    
                    var argHelper0 = new Puerts.ArgumentHelper((int)data, isolate, info, 0);
                    
                    
                    
                    {
                        
                        var arg0 = argHelper0.Get<UnityEngine.Vector3Int>(false);
                        var result = undefinedarg0; //<========================
                        Puerts.ResultHelper.Set((int)data, isolate, info, result);
                        
                    }
                }
                
                
            }
            catch (Exception e)
            {
                Puerts.PuertsDLL.ThrowException(isolate, "c# exception:" + e.Message + ",stack:" + e.StackTrace);
            }
        }

是否能支持C#拓展方法

未来是否能通过优化生成index.d.ts来支持C#的拓展方法。Unity中DOTween和一些自己写的拓展方法,目前不好调用。

生成有可选参数的Method,参数数量判断不对

class Test {
 public void Hello(string str, string[] strArray = null, int value = 1)
}

生成的Hello 只会判断paramLen == 3 和 paramLen == 2
还缺少paramLen == 1

发现是Generator的HasValue判断有问题,如果为Optional,应该就是可以重载的,为啥还要判断!=null

关于开启BlittableCopy的类,生成的调用函数建议

比如Vector3的S_y
生成后为

[Puerts.MonoPInvokeCallback(typeof(Puerts.V8FunctionCallback))]
unsafe private static void S_y(IntPtr isolate, IntPtr info, IntPtr self, int paramLen, long data)
{
    try
    {
        var obj = (UnityEngine.Vector3)Puerts.Utils.GetSelf((int)data, self); // 实际返回了新的Vector3
        var argHelper = new Puerts.ArgumentHelper((int)data, isolate, info, 0);
        obj.y = argHelper.GetFloat(false); // 这种操作没法改变原始Vector3.y的值
    }
    catch (Exception e)
    {
        Puerts.PuertsDLL.ThrowException(isolate, "c# exception:" + e.Message + ",stack:" + e.StackTrace);
    }
}

如果开启BlittableCopy,是不是应该生成指针操作

try
{
    var obj = (UnityEngine.Vector3*)self; // 类型指针转换
    var argHelper = new Puerts.ArgumentHelper((int)data, isolate, info, 0);
    obj->y = argHelper.GetFloat(false); // 通过指针操作
}
catch (Exception e)
{
    Puerts.PuertsDLL.ThrowException(isolate, "c# exception:" + e.Message + ",stack:" + e.StackTrace);
}

代码生成模板type.tpl.txt

js函数getSelf 是否应该先判断it是不是BlittableCopy,而不是ValueType,这样才能返回指针类型转换

function getSelf(type) {
    if (it.BlittableCopy) {
        return `(${type.Name}*)self`; // 去掉指针取值*
    } else if (type.IsValueType) {
        return `(${type.Name})Puerts.Utils.GetSelf((int)data, self)`;
    } else {
        return `Puerts.Utils.GetSelf((int)data, self) as ${type.Name}`;
    }
}

之后再每个方法的【obj.】改成根据BlittableCopy和IsStatic设置为【.】或者【->】

开启Vector3的 BlittableCopy 时,使用transform.Rotate(vector3) 会有GC

版本:Plugin_v6

发现是ArgumentHelper.IsMatch 调用时做了装箱操作

const cs = require('csharp');

let vector3 = new cs.UnityEngine.Vector3(0, 10, 0);
let gameObjectTrans;

exports.init = function(bindTo) {
    bindTo.JsStart = () => gameObjectTrans = new cs.UnityEngine.GameObject("go").transform;
    bindTo.JsUpdate = () => gameObjectTrans.Rotate(vector3);
}

调用某些 C# 函数报错

这段代码再 C# 中正常

System.Text.Encoding.UTF8.GetBytes("Hello World")

在TS中调用会在如下位置报异常

public void Action<T1>(T1 p1)
{
StaticTranslate<T1>.Set(jsEnv.Idx, isolate, NativeValueApi.SetValueToArgument, nativeJsFuncPtr, p1);
IntPtr resultInfo = PuertsDLL.InvokeJSFunction(nativeJsFuncPtr, false);
if (resultInfo == IntPtr.Zero)
{
string exceptionInfo = PuertsDLL.GetFunctionLastExceptionInfo(nativeJsFuncPtr);
throw new Exception(exceptionInfo);
}
}

报错内如如下

Exception: D:/work/repositories/zombie/project/Assets/StreamingAssets\scripts\webapi.js:520: Error: invalid arguments to GetBytes
    return csharp__WEBPACK_IMPORTED_MODULE_0__["System"].Convert.ToBase64String(csharp__WEBPACK_IMPORTED_MODULE_0__["System"].Text.Encoding.UTF8.GetBytes(text));
                                                                                                                                                 ^
Error: invalid arguments to GetBytes
    at btoa (D:/work/repositories/zombie/project/Assets/StreamingAssets\scripts\webapi.js:520:146)
    at GameLauncher.initialize (D:/work/repositories/zombie/project/Assets/StreamingAssets\scripts\bundle.js:128:22)
    at JavaScriptApplication.initialize (D:/work/repositories/zombie/project/Assets/StreamingAssets\scripts\bundle.js:190:26)
    at new JavaScriptApplication (D:/work/repositories/zombie/project/Assets/StreamingAssets\scripts\bundle.js:186:14)
    at main (D:/work/repositories/zombie/project/Assets/StreamingAssets\scripts\bundle.js:172:5)
Puerts.GenericDelegate.Action[T1] (T1 p1) (at Assets/Libraries/Puerts/Src/GenericDelegate.cs:311)
tiny.JavaScript.Awake () (at Assets/Scripts/tiny/scripts/JavaScript.cs:74)
UnityEngine.GameObject:AddComponent()
tiny.main:Awake() (at Assets/Scripts/main.cs:12)

【unity】泛型支持不完善

Unity 部分泛型支持不完善
无法支持以下:

public T Test<T>() where T : Object
{
    return null;
}

这种类型的代码。

Unity 断点调试时执行表达式会崩溃

复现方式

  • 启动任意项目
  • 使用 VSCode 调试器连接 puerts 的 V8 调试器
  • 按暂定键或通过 debugger 进入断点
  • 在VSCode 中切换到调试窗口,打开 调试控制台
  • 在控制台内输入任意 JavaScript 表达式
  • 如未复现,重复上一步,手动输入如 globalThis.puerts 之类的即可复现

[Unity] 继承C#类的JS类,其对象的引用问题

举个例子说明一下

// C#代码
class TreeNode
{
  public object userData;
}
// TS代码
class MyNodeData extends System.Object
{
   text: string;
}

const node = new TreeNode();
const userData = new MyNodeData();
userData.text = "test";
node.userData = userData;  // 这里看起来像对userData产生了引用,实际上并没有,userData会被GC

rootNode.Add(node);

非常容易踩坑,是否应该在构造JS对象的时候维护一个 C#对象对JS对象的引用关系?

无法在ts声明C#的Queue<Interface>

我在Unity C#声明了一个interface,例如IFoo。然后按Generate Code。接着在ts声明一个Queue<IFoo>,写法如下:
let Queue = $generic(System.Collections.Generic.Queue$1, IFoo);
但IFoo的部分报错如下:
TS2693: 'IFoo' only refers to a type, but is being used as a value here.

require相对路径,读取到的类的静态属性为null

在Unity C#内,执行JsEnv.Eval("require('ClassA')"),将ClassA.js内的ClassA的静态属性给与非null的值。
然后再执行JsEnv.Eval("require('ClassB')")。ClassB.js内有require('../../ClassA'),require内的路径对应到ClassB.js与ClassA.js实质上的相对路径。但是此时require出来的ClassA的静态属性为null。
原因可能为require('ClassA')与require('../../ClassA')被认定是require不同的档案。

蓝图类会被提前释放

如下代码,js可能在循环中完成gc,由于没有对该蓝图示例的引用,会导致蓝图类因为引用计数为0而被释放,后续访问该蓝图类会崩溃。

OnLoginBtnClick(){


        let MyTestActor = blueprint<typeof UE.MyTestActor_C>(`/Game/MyPreciousImmortal/Core/Character/MyTestActor.MyTestActor_C`);
        let world = TSGame.GetWorld();

        for(let i=0; i<100; i++){
            let pos = new UE.Vector(i, i, 0);
            let Rotator = new UE.Rotator();
            let actor = world.SpawnActor(MyTestActor.StaticClass(), pos, Rotator ) as UE.MyTestActor_C;
            actor.SetActorName("ID:" + i);
            actor.Init(pos, Rotator);
            
        }
    }

无法传入某些类型的回调函数

unity:

public class Test
{
    public static void TestCallbackString(System.Action<string> cb)
    {
        cb(UnityEngine.Random.value.ToString());
    }
    public static void TestCallbackFloat(System.Action<float> cb)
    {
        cb(UnityEngine.Random.value);
    }
}

typescript:

    Test.TestCallbackString(s => console.log('string', s)) //可以执行
    Test.TestCallbackFloat(s => console.log('float', s)) //不能执行

System.Action 当T为class时正常, T为简单类型或结构体时 发生错误

[Unity] JsEnv 初始化时默认加载的js文件能否改成可配置的?

我用 https://github.com/vercel/ncc 这个工具打包单文件服务的时候, 在正常的 NodeJS 环境下可以运行, 比如 apollo-server-express 这个包 , 参考网址 但是Puerts里面, 会在启动时和默认加载的 puerts/modular.js 有冲突, 因为工具打包以后所有的模块都在一个文件里面, 和 modular.js 判断模块是否存在的方式有冲突, 这些默认加载的js文件能否提供某种方式进行手动控制或者配置呢?

反射调用,struct作为引用参数时报错

public struct ss
{
int age;
string name;
public int Age
{
get { return age; }
set { age = value; }
}
public string Name
{
get{return name;}
set{name = value;}
}
public ss(int i, string j) : this()
{
age = i;
name = j;
}
}

public class Su : Ba
{
public string printStructRef(ref ss s)
{
s.Age = 20;
return ("name : " + s.Name + " , age : " + s.Age);
}
}

不点击Generate Code时,报错
image
点击Generate Code后,就没有错误

BlittableCopy 开启后 jsEnv访问权限问题

var typeId = Puerts.JsEnv.jsEnvs[jsEnvIdx].GetTypeId(typeof(UnityEngine.Vector3));
// Cannot access internal field 'jsEnvs' here

BlittableCopy 开启后 jsEnv访问权限问题,因为jsEnv为内部变量
可能需要调整jsEnv访问方式
因为我把Puerts放在了一个Assembly,而生成的代码在我的另一个Assembly内,导致无权限访问

[Unity] C# 类中的静态成员没有导出到JS中

如下的 C# 类中, static_property 这个静态成员未导出到JS中。

namespace tiny {
	public class CSClass {
		static string static_property = "CSClass";
		public float property { get; set; }
		public string member = "ABCD";
		
		public CSClass() {
			property = 3.14f;
			UnityEngine.Debug.Log("CSClass");
		}
		
		public int method() {
			return 100;
		}

		~CSClass() {
			UnityEngine.Debug.Log("~CSClass");
		}
	}
}

生成的声明文件内容如下

namespace tiny {
        class CSClass extends System.Object {
            public member: string;
            public property: number;
            public constructor();
            public method():number;
            
        }
        
    }

typeof (tiny.CSClass.static_property) 取值为 undefined

[unity] DISABLE掉自动注册,手动注册时导致某些类被重复注册报错

ExecuteFile("puerts/log.js"); // 执行此语句时会去LoadType(Vector3)

手动调用

AutoStaticCodeRegister.Register

由于Vector3使用了BlittableCopy
当执行

UnityEngine_Vector3_Wrap.InitBlittableCopy(jsEnv);

提示已经注册

报错信息

ArgumentException: An item with the same key has already been added. Key: UnityEngine.Vector3
System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) (at <9577ac7a62ef43179789031239ba8798>:0)
System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at <9577ac7a62ef43179789031239ba8798>:0)
Puerts.GeneralGetterManager.RegisterGetter (System.Type type, Puerts.GeneralGetter generalGetter) (at Assets/Kunpo/ThirdParty/Puerts/Src/DataTranslate.cs:280)
Puerts.JsEnv.RegisterGeneralGetSet (System.Type type, Puerts.GeneralGetter getter, Puerts.GeneralSetter setter) (at Assets/Kunpo/ThirdParty/Puerts/Src/JsEnv.cs:227)

AutoStaticCodeRegister生成部分代码
image

Timer需进行异常处理

setInterval和setTimeout. 如果触发时抛出异常, 会导致计时器紊乱:

  1. 计时器抛出异常后, 该计时器没有被认为没有执行过, 在下一次Tick中又会被执行.

  2. 一个计时器抛出异常, 会导致其他计时器也无法执行.
    timer.js.txt源码:
    `
    function timerUpdate() {
    const now = Date.now();
    while (true) {
    const time = timers.peek();
    if (time && time.next_time <= now) {

             if(removing_timers.has(time.id)){
                 removing_timers.delete(time.id)
             }
             else {
    
                 time.handler(time.args);  //这里的调用如果抛出异常, 接下来的逻辑都会中断, 包括pop和调用其他的计时器
                 if (time.timeout) {
                     time.next_time = now + time.timeout;
                     timers.push(time);
                 }
             }
             timers.pop();
         } else {
             break;
         }
     }
    

    }
    `

Question about custom Blueprint functions

Hey - Got a Unreal engine 4 related question about puerts.

Can we use JavaScript or typescript with puerts to make custom blueprint functions?

Thank you for your time

如何处理js未主动捕获的异常

目前发现可以主动捕获的异常有:

  1. jsEnv.Eval 相关的js执行异常
  2. jsEnv.Tick 相关的js执行异常

而其他情况发生的异常, 没有找到办法捕获, unity也看不到报错
例如:

  1. 将js方法注册为button的点击事件, 这个js方法如果执行异常, 没地方可以检测到
  2. j某个异步方法内抛出异常, 调用者没有主动catch, 也没地方可以检测到异步方法内部的异常

在浏览器端, 可以监听全局的error事件, 获得这样的异常
在nodejs中, 可以process中的uncaughtException事件, 获得这样的异常

请问puerts如何捕获这种异常

功能需求

在某些情况下,比如接入flatbuffer, flatbuffer不会被打包进js中,因此需要在Eval脚本前这样调用一下 jsEnv.ExecuteFile("puerts/flatbuffers.js"); , 为了不修改Puerts框架代码, 希望 ExecuteFile 这个方法声明为public , 或者框架中提供一个执行用户自定义文件的方法

提醒开发者在使用 Timer API 时调用 JsEnv.Tick()

有一些开发者因为使用了 setInterval 等 API 却没有在 Update 函数中调用 JsEnv.Tick() 导致 setInterval 等 API 无效果。
这种情况不会有任何报错显示,很容易让开发者无从下手。

可以修改初始化方法,在第一次调用 JsEnv.Tick() 时初始化 setInterval 等函数。若不调用 JsEnv.Tick() ,先调用 setInterval 等函数,会抛出异常,让开发者先调用 JsEnv.Tick() 函数。

缺点是,如果需要在游戏第一个 Update 前使用 setInterval 等函数,需要在执行 JS 代码前手动调用一次 JsEnv.Tick() 初始化。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.