mihe / tsu Goto Github PK
View Code? Open in Web Editor NEWTypeScript plugin for Unreal Engine 4
License: Other
TypeScript plugin for Unreal Engine 4
License: Other
async
functions return promises, which there's currently no support for.
It would be neat if exported async
functions were somehow translated into latent nodes in Blueprint, like Delay
.
Specifically the Scale
parameter of UGameplayStatics::SpawnEmitterAttached
seems to default to a scale of FVector(0.f)
instead of the specified FVector(1.f)
.
If you want to import a file that isn't a "TBP file", or you can't/won't use the import { TBP_Foo } from 'UE/TBP_Foo'
syntax, then you're currently forced to continously compile the TypeScript file to JavaScript.
It would be nice to somehow get rid of this requirement and only ever deal with TypeScript files, kinda like ts-node.
Since the TSU blueprints currently get compiled when you start the editor it can bump up the startup time for the editor quite a bit. There should ideally not be any reason at all to parse the TypeScript since it should all be baked into the .uasset
.
The only thing I could see being a problem is if the generated typings were to change, in which case the TypeScript code should be reparsed and produce an error if faulty.
If recompiling on startup turns out to be unavoidable there's also the new .tsbuildinfo
stuff that was released with TypeScript 3.4, which should cut the initial compile times down significantly.
Due to JavaScript/TypeScript not really having a notion of an integer (outside of the recently added BigInt
) it becomes a problem when you have functions like UKismetMathLibrary::Clamp
, which only clamps int32
.
This then shows up in the typings as:
static clamp(value: number, min: number, max: number): number;
... which looks harmless but will in fact truncate any decimals that gets sent into it. Outside of looking at the actual C++ declaration of the target function there is no way of knowing if something will truncate or not.
I'm not sure how to fix this, but one alternative would be to at least emit some kind of documentation, like:
/**
* @param value Warning: Integer parameter, will truncate
* @param min Warning: Integer parameter, will truncate
* @param max Warning: Integer parameter, will truncate
*/
static clamp(value: number, min: number, max: number): number;
Typings only ever get added to Intermediate/Typings
and never removed, leaving behind typings that could potentially cause problems.
There's no proxy for these like there is for Array
, so they're both read-only at the moment.
With #12 being fixed you can now do stuff like controller.isInputKeyDown(EKeys.SpaceBar)
, but you still can't poll or listen to input mappings.
I still don't how to do this one, at all. I was hoping to leverage the UInputDelegateBinding
stuff that Blueprint itself uses, but it seems so tightly bound to only work with their internal types that I can't piggyback on it, regardless of what hacks I try to employ.
The C++ way of using input mappings involves overriding APawn::SetupPlayerInputComponent
, which obviously isn't possible from just static functions.
I can't really see a small-ish change to UE4 that Epic would be happy to integrate either, but if anyone has any ideas then I'm all ears.
For a start it's gonna involve getting a Linux version of V8, TsuParser and FTsuReplProcess
up and running. Might have some overlap with #22.
Also keep in mind that Win64 is currently the only whitelisted platform in TSU.uplugin
.
It seems UBlueprint::GatherDependencies
isn't doing the trick of signaling to UE4 that certain TSU blueprints are dependant on other blueprints.
If a certain blueprint is only used within TSU code, and not as a parameter type or return type, then it seems those blueprints never get loaded, causing an error when the dependant code tries to import it.
I've tried using LoadObject
instead of FindObject
in FTsuTypeIndex::Find
, but that results in the context resetting itself (due to OnBlueprintPreCompile
) while we're inside a V8 callback, which is not great.
There has to be some other proper way to signal which blueprints is depended on.
With something like...
export function foo(bar = 5) { }
... the bar
parameter will fail to resolve its type, when it should be number
.
As mentioned in #1, we need to somehow get source-map-support into the bootstrapping to be able to read the correct file/line from the inlined source maps.
For a start it's gonna involve getting a macOS version of V8, TsuParser and FTsuReplProcess
up and running.
Also keep in mind that Win64 is currently the only whitelisted platform in TSU.uplugin
.
Currently exceptions produce something along these lines:
LogTsuRuntime: Error: [V8] Uncaught TypeError: Cannot set property 'test' of undefined
LogTsuRuntime: Error: at Saucer/TBP_Saucer.js:19:21
... which comes from FTsuTryCatch
.
Ideally this should produce some sort of call stack, and also make use of source-map-support in order to get the real file name and line numbers from the inlined source maps.
These seem to be handled in blueprint through UK2Node_AddComponent
.
The current workaround would be something similar to how it is in C++:
export function construct(target: BP_Foo, mesh: StaticMesh) {
const component = new StaticMeshComponent(target);
component.registerComponent();
component.setStaticMesh(mesh);
target.addOwnedComponent(component);
}
Trying to do something like:
export function(param: {}) { /* ... */ }
... will result in param
resolving to a UObject
pin in the resulting blueprint function.
This is because FTsuTypeIndex::Find
is too aggressive right now, and will turn any unknown/unresolvable type into UObject
.
It was made to be that way because of prior issues with blueprint types randomly failing to resolve, and instead of just throwing that pin away it was made to fall back on UObject
instead, which would still allow any dependant blueprints to compile.
One potential fix would be to have the parser server report if the type is a derivative of UObject
and only fall back to UObject
if that's the case.
Parameters with the UPARAM(ref)
annotation currently gets treated as an output parameter, which results in some janky typings, like:
declare class Vector2D {
normalize(tolerance?: number): { a: Vector2D };
}
It should instead perform the operation in-place and not return anything.
Some preliminary tests with simply excluding CPF_ReferenceParm
from FTsuReflection::IsOutputParameter
didn't seem to work. The actual invocation probably needs to not copy the value if it's a reference parameter or something.
Currently there's no way to return multiple things back to Blueprint, which is usually done in by returning an object with an entry for each return value, like so:
export function getBounds(target: Actor) {
const origin: Vector = /* ... */;
const extents: Vector = /* ... */;
return { origin, extents };
}
... which would then ideally get translated into a Blueprint node with an output pin for both Origin
and Extents
.
Currently only input reference parameters are nullable (i.e. marked as | null
). This was added as a hack in order to allow null
to be passed to function parameters while having strictNullChecks
enabled.
This problem still applies to reference properties though, and with properties not being nullable you currently can't set them to null
with strictNullChecks
enabled.
The naive solution would be to simply make every reference property nullable as well. However, this makes them way too tiresome to work with, because you end up sprinkling non-null assertions and unnecessary if-statements all over your code. The biggest source of this comes from actor components also being marked as nullable, when in reality they will never be null (in Blueprint classes at least).
A more refined solution would therefore try to figure out if a reference property is in fact an actor component and leave out nullability. However, regular reference properties to actor components or references to actor component declared in C++ can't have the same non-null guarantee and would therefore still have to be nullable.
All-in-all it's messy whichever way you look at it, because the typings are generated from a type system that doesn't express nullability.
I'm leaning towards simply scrapping nullability from the typings entirely and discouraging the use of strictNullChecks
.
When debugging using VS Code you sometimes get errors saying:
Error evaluating `process.pid`: Cannot find context with specified id
It might have something to do with missing or incorrectly implementing parts of the v8_inspector::V8InspectorClient
implementation.
If you connect a second debugger you'll overwrite the session of the first one. Should (hopefully) be as simple as just storing a list of channels/clients instead.
Tons of warnings like these ones show up when starting the editor:
LogClass: Warning: Failed to bind native function REINST_TBP_Something_C_5.someFunction
LogClass: Warning: Failed to bind native function TRASHCLASS_TBP_Something_25.someFunction
Module-scope exceptions can potentially result in some/all functions not being exported, which will make FTsuContext::Invoke
abort early and cause Stack.Code
to never move, resulting in UObject::ProcessInternal
getting stuck on while (*Stack.Code != EX_Return)
.
There's no way to represent things like FVector::ZeroVector
, FRotator::ZeroRotator
or FTransform::Identity
.
Ideally these should somehow be provided as a static readonly
properties on each respective class.
Ideally these should be turned into parameters for the constructor in each respective class.
Right now you have to jump through a lot of hoops in order to setup a new project. Any reduction in the number of steps would be a good thing.
Ideally the plugin would ship with a project template. The biggest problem with that is that it requires the plugin to first of all be installed into the engine plugins (like Marketplace ones do), and also that it's enabled by default, which currently makes it generate a bunch of typings into %LOCALAPPDATA%\UnrealEngine\4.21\Intermediate
.
For whatever reason these don't get typings generated for them.
Currently there's no way to extend typings with new static methods.
There needs to be some way to disambiguate cases like:
UFUNCTION(BlueprintPure)
static float Triple(FVector X, FVector Y, FVector Z);
... where the current way of doing things would translate it to:
declare class Vector {
triple(y: Vector, z: Vector): number;
}
... and instead have it be:
declare class Vector {
static triple(x: Vector, y: Vector, z: Vector): number;
}
Right now there are a few issues preventing TSU from compiling in non-editor builds:
UField
metadata used for marshaling (GetMetaData
, HasMetaData
, etc).FFileHelper::LoadFileToString
for require
(self-imposed restriction).TsuInspectorClient.cpp
.The respective solutions to these would be something like:
require
a part of some V8 startup snapshot.There's probably gonna be more issues down the line as well.
Which is because we defer compilations until after the play session is over, and instead only reload the context.
The only possible fix for this would be to somehow compile the UTsuBlueprint
during a play session, which I don't think is even possible.
Should hopefully just be a matter of shipping a Win32 version of TsuParser and V8.
Also keep in mind that Win64 is currently the only whitelisted platform in TSU.uplugin
.
Custom events defined in a blueprint are callable from other blueprints, but can't be called from TypeScript.
I'm not sure if this is possible at all, but it feels like something that would be nice to have.
For whatever reason the easing functions in UKismetMathLibrary
were marked as BlueprintInternalUseOnly
and instead dynamically chosen through the custom Blueprint node UK2Node_EaseFunction
. This has the unfortunate consequence of the easing functions not being exposed in the typings.
Either we give those functions special treatment and let them get exposed despite being BlueprintInternalUseOnly
, or we add something like TsuMathLibrary
. Alternatively if #3 gets solved they could get added as extensions to UKismetMathLibrary
.
Ideally there would be some script(s) bundled with the repo that downloads the currently targeted version of V8 and builds it for some/all platforms. If not, then at least some instructions on how to build a component (DLL) build of V8.
If you start the editor and a script for whatever reason doesn't parse/compile then calls that are using functions from it can sometimes mysteriously get replaced with calls to similar named functions. This is due to some code inside K2Node_CallFunction.cpp
that explicitly does this for function libraries.
Might be worthwile to submit a PR that lets you disable this functionality somehow.
Things like procedurally getting axis/button values, either through the designated getter node generated from the input mapping, or through APlayerController::IsInputKeyDown
.
Ideally there would be typings generated based on the input mapping or something.
Importing other TypeScript files, whether it's other TSU files or just utility files, need to be compiled down to .js
files first, which quickly becomes tedious and error-prone. It would be nice if this could be solved in some way.
The current workaround for importing other TSU files is to import them using the UE/
prefix, like:
import * as Thing from 'UE/TBP_Thing';
Right now it's hardcoded in FTsuReplProcess
to 5 seconds for both the stdout
and stderr
pipe.
Any function with a parameter of a type marked as BlueprintInternalUseOnly
will currently not get exposed at all.
This includes any asynchronous functions like UKismetSystemLibrary::Delay
or UGameplayStatics::LoadStreamLevel
.
This is deliberately so until I can figure out how to deal with the FLatentActionInfo
stuff.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.