Unreal.js icon indicating copy to clipboard operation
Unreal.js copied to clipboard

Subclassing a Blueprint overrides BP defaults

Open filipeuva opened this issue 8 years ago • 6 comments

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 !

filipeuva avatar Nov 13 '16 02:11 filipeuva

Some code : .h

#pragma once

#include "JavascriptCharacter.generated.h"


UCLASS()
class AJavascriptCharacter : public ACharacter {
    GENERATED_UCLASS_BODY()

    UPROPERTY(EditAnywhere) float MaxHealth;

};

Blueprint

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')
}

In-Game Result

filipeuva avatar Nov 13 '16 20:11 filipeuva

It seems like a bug. Maybe I forgot to call some constructor which copies values from CDO.

nakosung avatar Nov 19 '16 02:11 nakosung

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)
    }
(...)

filipeuva avatar Nov 19 '16 03:11 filipeuva

@nakosung any news on this?

gallexme avatar Jan 05 '17 18:01 gallexme

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)

vrachels avatar Jul 17 '19 21:07 vrachels

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 !

futouyiba avatar Aug 12 '19 16:08 futouyiba