Unreal.js
Unreal.js copied to clipboard
Subclassing a Blueprint overrides BP defaults
Hi, I'm using the Marketplace version of your plugin and it's been awesome so far. Thanks 👍
I'm trying to extend some Blueprints and I've found that the default Blueprint values get overriden by my generated Javascript class. Am I missing something ?
For example my Character has a variable MaxHealth that defaults to 0 on the base C++ implementation, my BP defaults it to 100 and the generated javascript blueprint overrides it to 0 again, strangely the editor shows the "Reset to Default" button next to it and clicking it defaults to the previous Blueprint value.
Thanks in advance !
Some code : .h
#pragma once
#include "JavascriptCharacter.generated.h"
UCLASS()
class AJavascriptCharacter : public ACharacter {
GENERATED_UCLASS_BODY()
UPROPERTY(EditAnywhere) float MaxHealth;
};
js (modified helloGame.js)
/// <reference path="typings/ue.d.ts">/>
"use strict"
class MyPC extends PlayerController {
ReceiveBeginPlay() {
super.ReceiveBeginPlay()
console.log("Hello, this is MyPC")
}
// RPC function!
test(data/*float*/)/*NetMulticast*/ {
console.log('multicast!',data,this.GetName(),this.Role)
}
TestBinding()/*KeyBinding[Ctrl+E]*/{
this.Server_Call();
}
Server_Call()/*Server*/ {
console.log('this is server call',this.Role);
this.test($time);
}
}
// Blueprint class can be subclassed!
class MyActor extends Blueprint.Load('/Game/JavascriptCharBP').GeneratedClass {
// constructor
ctor() {
// Subobject initialization, property initialization
this.bAlwaysRelevant = true
}
// declare UPROPERTY's here
// ; this.XXXXX/*[attribute+]+type*/;
properties() {
this.Hello/*Replicated+EditAnywhere+int*/;
this.World/*Replicated+EditAnywhere+Actor*/;
this.Position/*EditAnywhere+Vector[]*/;
this.Some/*EditAnywhere+DistanceDatum*/;
}
// Overriding function doesn't need function signature
ReceiveBeginPlay() {
super.ReceiveBeginPlay()
let myPlayerController = GWorld.GetPlayerController(0)
//possess the MyThirdPerson character that just spawned
myPlayerController.Possess(this)
console.log("Hello, this is MyActor")
}
// Override an event which was declared in Blueprint
CustomEvent() {
console.log("This is javascript")
}
// New UFUNCTION needs proper function signature
// ; function-name(arg/*type*/,...) /*UFUNCTION-flag[+another flag]*/
NewFunction(x/*int*/,y/*int*/) /*NetMulticast*/ {
console.log(x+y);
}
}
let MyActor_C = require('uclass')()(global, MyActor)
let MyPC_C = require('uclass')()(global,MyPC)
let _ = require('lodash')
function main() {
// Replicated actor should be created in server node.
if (GWorld.IsServer()) {
Root.GetOuter().PlayerControllerClass = MyPC_C
Root.GetOuter().DefaultPawnClass = MyActor_C
let alive = true
return function () {
alive = false
}
} else {
return function() {}
}
}
try {
module.exports = () => {
let cleanup = null
cleanup = main();
return () => cleanup()
}
}
catch (e) {
require('bootstrap')('helloGame')
}
It seems like a bug. Maybe I forgot to call some constructor which copies values from CDO.
Thanks for the reply!
CDO ?
It should seem that the values are on the Class DefaultObject, they just aren't being copied as you say, I managed to do a quickfix today :
cpp:
void AJavascriptCharacter::CopyDefaultsFromImplementation(AActor* DefaultImplementation)
{
// Iterate over properties
for (TFieldIterator<UProperty> It(GetClass()); It; ++It)
{
UProperty* Prop = *It;
Prop->CopyCompleteValue_InContainer(this, DefaultImplementation);
}
}
javascript
(...)
class MyActor extends Blueprint.Load('/Game/JavascriptCharBP').GeneratedClass {
// constructor
ctor() {
let defaultObject = MySword.GetDefaultObject()
JavascriptCharacter.C(this).CopyDefaultsFromImplementation(defaultObject)
}
(...)
@nakosung any news on this?
Encountered this and tracked it down!
JavascriptContext_Private.cpp
in ExportUnrealEngineClasses, at the end of auto fn = ...
+ Class->UpdateCustomPropertyListForPostConstruction();
auto end = FPlatformTime::Seconds();
(may or may not be needed elsewhere, ie the RebindClassProperties)
Encountered this and tracked it down!
JavascriptContext_Private.cpp
in ExportUnrealEngineClasses, at the end of auto fn = ...
+ Class->UpdateCustomPropertyListForPostConstruction(); auto end = FPlatformTime::Seconds();
(may or may not be needed elsewhere, ie the RebindClassProperties)
You are a hero, @vrachels !