Got stuck on a feature for my plugin “MultiEdit” to synchronize components of actors between editors. For example if one user changes the light color to blue, the other editor on a different machine will update that component, so that light will become blue as well.
I am using FObjectReader and FObjectWriter and my reference is the code in DiffPackagesCommendlet.cpp at line 352/360 (I am using UE4.6) in the function CopyObjectToPackage. I tried this locally (in one editor) and that worked fine.
TArray<uint8> Bytes;
FObjectWriter(Object, Bytes);
// make a new object
UObject* NewObject = StaticConstructObject(Object->GetClass(), NewOuter, Object->GetFName(), Object->GetFlags(), Object->GetArchetype(), true);
// serialize old objects on top of the new object
FObjectReader Reader(NewObject, Bytes);
Here is my code:
//Message created, initialized and send by an editor
bool FMessageUpdateComponent::Serialize(MEMessageHandler* MessageHandler, AActor* Actor)
{
ID = ID_UPDATECOMPONENT;
Object = Actor->GetRootComponent();
ObjectName = Object->GetFName();
ObjectClassName = Object->GetClass()->GetName();
ActorID = MessageHandler->GetIDFromActor(Actor);
// serialize out the original object
FObjectWriter(Object, ObjectBytes);
return FMessage::Serialize(MessageHandler);
}
//The serializing and deserializing of the message
void FMessageUpdateComponent::SaveLoad(FArchive& Archive)
{
//TArray<uint8> The component in binary
Archive << ObjectBytes;
//The ID of the actor that owns that component
Archive << ActorID;
//The class name of the component
Archive << ObjectClassName;
//The name of the component
Archive << ObjectName;
}
//The handle for when an editor received the message to update a component
bool FMessageUpdateComponent::Handle(FMemoryReader& Reader, MEMessageHandler* MessageHandler, FSocket* Sender)
{
Deserialize(Reader);
if (ObjectClassName.Equals("BrushComponent")) return false;
//Find the class from the name
UClass* const ObjectClass = FindObject<UClass>(ANY_PACKAGE, *ObjectClassName);
//Make a new object (things I tried to create an UObject)
//UObject* CreatedObject = StaticConstructObject(ObjectClass, (UObject*)GetTransientPackage(), ObjectName, RF_NoFlags, (UObject*)0, true);
//UObject* CreatedObject = ConstructObject<UObject>(ObjectClass, (UObject*)GetTransientPackage(), ObjectName, RF_NoFlags);
UObject* CreatedObject = NewObject<UObject>((UObject*)GetTransientPackage(), ObjectClass);
FObjectReader ObjectReader(CreatedObject, ObjectBytes); //BREAKS HERE!
if (Object)
{
//TODO update the component of the actor here
}
return true;
}
Main differences from the reference:
- The binary TArray created by the FObjectWriter is not local in one function but it is send (with FSocket) to another editor that receives the message.
- I don’t use the StaticConstructObject like the reference does, because this creates an instance.
Notes:
- I debugged the TArray (ObjectBytes) and it appears to be the same before sending it in one editor and after receiving it in the other editor. So the data is not corrupted or something.
- I tested the above mentioned case with this technique in one editor and it worked.
Currently it crashes on FObjectReader(CreatedObject, ObjectBytes)
Many thanks in advance!