mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-21 17:45:25 -04:00
deb802cfec
* For now, this is limited to instances inside custom objects. This will be made available in the future for all instances in scenes if this works well.
309 lines
12 KiB
C++
309 lines
12 KiB
C++
/*
|
|
* GDevelop Core
|
|
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
|
* reserved. This project is released under the MIT License.
|
|
*/
|
|
|
|
#include "GDCore/Project/InitialInstance.h"
|
|
|
|
#include "GDCore/Project/Layout.h"
|
|
#include "GDCore/Project/Object.h"
|
|
#include "GDCore/Project/ObjectsContainer.h"
|
|
#include "GDCore/Project/Project.h"
|
|
#include "GDCore/Project/PropertyDescriptor.h"
|
|
#include "GDCore/Serialization/SerializerElement.h"
|
|
#include "GDCore/Tools/UUID/UUID.h"
|
|
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
|
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
|
#include "GDCore/Project/CustomBehavior.h"
|
|
#include "GDCore/Tools/Log.h"
|
|
|
|
namespace gd {
|
|
|
|
gd::String* InitialInstance::badStringPropertyValue = NULL;
|
|
|
|
InitialInstance::InitialInstance()
|
|
: objectName(""),
|
|
layer(""),
|
|
persistentUuid(UUID::MakeUuid4()),
|
|
behaviorOverridings(true) {}
|
|
|
|
void InitialInstance::UnserializeFrom(gd::Project &project,
|
|
const SerializerElement &element) {
|
|
SetObjectName(element.GetStringAttribute("name", "", "nom"));
|
|
SetX(element.GetDoubleAttribute("x"));
|
|
SetY(element.GetDoubleAttribute("y"));
|
|
SetZ(element.GetDoubleAttribute("z", 0));
|
|
SetAngle(element.GetDoubleAttribute("angle"));
|
|
SetRotationX(element.GetDoubleAttribute("rotationX", 0));
|
|
SetRotationY(element.GetDoubleAttribute("rotationY", 0));
|
|
SetHasCustomSize(
|
|
element.GetBoolAttribute("customSize", false, "personalizedSize"));
|
|
SetCustomWidth(element.GetDoubleAttribute("width"));
|
|
SetCustomHeight(element.GetDoubleAttribute("height"));
|
|
if (element.HasChild("depth") || element.HasAttribute("depth")) {
|
|
SetHasCustomDepth(true);
|
|
SetCustomDepth(element.GetDoubleAttribute("depth"));
|
|
} else {
|
|
SetHasCustomDepth(false);
|
|
}
|
|
if (element.HasChild("defaultWidth") ||
|
|
element.HasAttribute("defaultWidth")) {
|
|
defaultWidth = element.GetDoubleAttribute("defaultWidth");
|
|
}
|
|
if (element.HasChild("defaultHeight") ||
|
|
element.HasAttribute("defaultHeight")) {
|
|
defaultHeight = element.GetDoubleAttribute("defaultHeight");
|
|
}
|
|
if (element.HasChild("defaultDepth") ||
|
|
element.HasAttribute("defaultDepth")) {
|
|
defaultDepth = element.GetDoubleAttribute("defaultDepth");
|
|
}
|
|
SetZOrder(element.GetIntAttribute("zOrder", 0, "plan"));
|
|
SetOpacity(element.GetIntAttribute("opacity", 255));
|
|
SetLayer(element.GetStringAttribute("layer"));
|
|
SetFlippedX(element.GetBoolAttribute("flippedX", false));
|
|
SetFlippedY(element.GetBoolAttribute("flippedY", false));
|
|
SetFlippedZ(element.GetBoolAttribute("flippedZ", false));
|
|
SetLocked(element.GetBoolAttribute("locked", false));
|
|
SetSealed(element.GetBoolAttribute("sealed", false));
|
|
SetShouldKeepRatio(element.GetBoolAttribute("keepRatio", false));
|
|
|
|
persistentUuid = element.GetStringAttribute("persistentUuid");
|
|
if (persistentUuid.empty()) ResetPersistentUuid();
|
|
|
|
numberProperties.clear();
|
|
if (element.HasChild("numberProperties", "floatInfos")) {
|
|
const SerializerElement& numberPropertiesElement =
|
|
element.GetChild("numberProperties", 0, "floatInfos");
|
|
numberPropertiesElement.ConsiderAsArrayOf("property", "Info");
|
|
for (std::size_t j = 0; j < numberPropertiesElement.GetChildrenCount(); ++j) {
|
|
gd::String name =
|
|
numberPropertiesElement.GetChild(j).GetStringAttribute("name");
|
|
double value =
|
|
numberPropertiesElement.GetChild(j).GetDoubleAttribute("value");
|
|
|
|
// Compatibility with GD <= 5.1.164
|
|
if (name == "z") {
|
|
SetZ(value);
|
|
} else if (name == "rotationX") {
|
|
SetRotationX(value);
|
|
} else if (name == "rotationY") {
|
|
SetRotationY(value);
|
|
} else if (name == "depth") {
|
|
SetHasCustomDepth(true);
|
|
SetCustomDepth(value);
|
|
}
|
|
// end of compatibility code
|
|
else {
|
|
numberProperties[name] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
stringProperties.clear();
|
|
if (element.HasChild("stringProperties", "stringInfos")) {
|
|
const SerializerElement& stringPropElement =
|
|
element.GetChild("stringProperties", 0, "stringInfos");
|
|
stringPropElement.ConsiderAsArrayOf("property", "Info");
|
|
for (std::size_t j = 0; j < stringPropElement.GetChildrenCount(); ++j) {
|
|
gd::String name = stringPropElement.GetChild(j).GetStringAttribute("name");
|
|
gd::String value =
|
|
stringPropElement.GetChild(j).GetStringAttribute("value");
|
|
stringProperties[name] = value;
|
|
}
|
|
}
|
|
|
|
if (element.HasChild("initialVariables", "InitialVariables")) {
|
|
GetVariables().UnserializeFrom(
|
|
element.GetChild("initialVariables", 0, "InitialVariables"));
|
|
}
|
|
|
|
if (element.HasChild("behaviorOverridings")) {
|
|
behaviorOverridings.UnserializeFrom(
|
|
project, element.GetChild("behaviorOverridings"));
|
|
}
|
|
}
|
|
|
|
void InitialInstance::SerializeTo(SerializerElement& element) const {
|
|
element.SetAttribute("name", GetObjectName());
|
|
element.SetAttribute("x", GetX());
|
|
element.SetAttribute("y", GetY());
|
|
if (GetZ() != 0) element.SetAttribute("z", GetZ());
|
|
element.SetAttribute("zOrder", GetZOrder());
|
|
if (GetOpacity() != 255) element.SetAttribute("opacity", GetOpacity());
|
|
if (IsFlippedX()) element.SetAttribute("flippedX", IsFlippedX());
|
|
if (IsFlippedY()) element.SetAttribute("flippedY", IsFlippedY());
|
|
if (IsFlippedZ()) element.SetAttribute("flippedZ", IsFlippedZ());
|
|
element.SetAttribute("layer", GetLayer());
|
|
element.SetAttribute("angle", GetAngle());
|
|
if (GetRotationX() != 0) element.SetAttribute("rotationX", GetRotationX());
|
|
if (GetRotationY() != 0) element.SetAttribute("rotationY", GetRotationY());
|
|
element.SetAttribute("customSize", HasCustomSize());
|
|
element.SetAttribute("width", GetCustomWidth());
|
|
element.SetAttribute("height", GetCustomHeight());
|
|
if (HasCustomDepth()) element.SetAttribute("depth", GetCustomDepth());
|
|
// defaultWidth, defaultHeight and defaultDepth are not serialized
|
|
// because they are evaluated by InGameEditor.
|
|
if (IsLocked()) element.SetAttribute("locked", IsLocked());
|
|
if (IsSealed()) element.SetAttribute("sealed", IsSealed());
|
|
if (ShouldKeepRatio()) element.SetAttribute("keepRatio", ShouldKeepRatio());
|
|
|
|
if (persistentUuid.empty()) persistentUuid = UUID::MakeUuid4();
|
|
element.SetStringAttribute("persistentUuid", persistentUuid);
|
|
|
|
SerializerElement& numberPropertiesElement =
|
|
element.AddChild("numberProperties");
|
|
numberPropertiesElement.ConsiderAsArrayOf("property");
|
|
for (const auto& property : numberProperties) {
|
|
numberPropertiesElement.AddChild("property")
|
|
.SetAttribute("name", property.first)
|
|
.SetAttribute("value", property.second);
|
|
}
|
|
|
|
SerializerElement& stringPropElement = element.AddChild("stringProperties");
|
|
stringPropElement.ConsiderAsArrayOf("property");
|
|
for (const auto& property : stringProperties) {
|
|
stringPropElement.AddChild("property")
|
|
.SetAttribute("name", property.first)
|
|
.SetAttribute("value", property.second);
|
|
}
|
|
|
|
GetVariables().SerializeTo(element.AddChild("initialVariables"));
|
|
|
|
if (!behaviorOverridings.GetAllBehaviorContents().empty()) {
|
|
behaviorOverridings.SerializeTo(element.AddChild("behaviorOverridings"));
|
|
}
|
|
}
|
|
|
|
InitialInstance& InitialInstance::ResetPersistentUuid() {
|
|
persistentUuid = UUID::MakeUuid4();
|
|
return *this;
|
|
}
|
|
|
|
std::map<gd::String, gd::PropertyDescriptor>
|
|
InitialInstance::GetCustomProperties(
|
|
gd::ObjectsContainer& globalObjectsContainer,
|
|
gd::ObjectsContainer& objectsContainer) {
|
|
// Find an object
|
|
if (objectsContainer.HasObjectNamed(GetObjectName()))
|
|
return objectsContainer.GetObject(GetObjectName())
|
|
.GetConfiguration()
|
|
.GetInitialInstanceProperties(*this);
|
|
else if (globalObjectsContainer.HasObjectNamed(GetObjectName()))
|
|
return globalObjectsContainer.GetObject(GetObjectName())
|
|
.GetConfiguration()
|
|
.GetInitialInstanceProperties(*this);
|
|
|
|
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
|
return nothing;
|
|
}
|
|
|
|
bool InitialInstance::UpdateCustomProperty(
|
|
const gd::String& name,
|
|
const gd::String& value,
|
|
gd::ObjectsContainer& globalObjectsContainer,
|
|
gd::ObjectsContainer& objectsContainer) {
|
|
if (objectsContainer.HasObjectNamed(GetObjectName()))
|
|
return objectsContainer.GetObject(GetObjectName())
|
|
.GetConfiguration()
|
|
.UpdateInitialInstanceProperty(*this, name, value);
|
|
else if (globalObjectsContainer.HasObjectNamed(GetObjectName()))
|
|
return globalObjectsContainer.GetObject(GetObjectName())
|
|
.GetConfiguration()
|
|
.UpdateInitialInstanceProperty(*this, name, value);
|
|
|
|
return false;
|
|
}
|
|
|
|
double InitialInstance::GetRawDoubleProperty(const gd::String& name) const {
|
|
const auto& it = numberProperties.find(name);
|
|
return it != numberProperties.end() ? it->second : 0;
|
|
}
|
|
|
|
const gd::String& InitialInstance::GetRawStringProperty(
|
|
const gd::String& name) const {
|
|
if (!badStringPropertyValue) badStringPropertyValue = new gd::String("");
|
|
|
|
const auto& it = stringProperties.find(name);
|
|
return it != stringProperties.end() ? it->second : *badStringPropertyValue;
|
|
}
|
|
|
|
void InitialInstance::SetRawDoubleProperty(const gd::String& name,
|
|
double value) {
|
|
numberProperties[name] = value;
|
|
}
|
|
|
|
void InitialInstance::SetRawStringProperty(const gd::String& name,
|
|
const gd::String& value) {
|
|
stringProperties[name] = value;
|
|
}
|
|
|
|
bool InitialInstance::HasAnyOverriddenProperty(const gd::Object &object) {
|
|
for (auto &behaviorOverridingPair : behaviorOverridings.GetAllBehaviorContents()) {
|
|
auto &behaviorName = behaviorOverridingPair.first;
|
|
if (HasAnyOverriddenPropertyForBehavior(object.GetBehavior(behaviorName))) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InitialInstance::HasAnyOverriddenPropertyForBehavior(
|
|
const gd::Behavior &behavior) {
|
|
auto &behaviorName = behavior.GetName();
|
|
if (!HasBehaviorOverridingNamed(behaviorName)) {
|
|
return false;
|
|
}
|
|
auto &behaviorOverriding = GetBehaviorOverriding(behaviorName);
|
|
if (behaviorOverriding.GetContent().IsEmpty()) {
|
|
return false;
|
|
}
|
|
const auto &overridingProperties = behaviorOverriding.GetProperties();
|
|
for (auto &propertyPair : behavior.GetProperties()) {
|
|
auto &propertyName = propertyPair.first;
|
|
auto &behaviorProperty = propertyPair.second;
|
|
|
|
if (behaviorProperty.GetType() != "Behavior" &&
|
|
behaviorOverriding.HasPropertyValue(propertyName) &&
|
|
overridingProperties.find(propertyName) !=
|
|
overridingProperties.end() &&
|
|
overridingProperties.at(propertyName).GetValue() !=
|
|
behaviorProperty.GetValue()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
gd::Behavior &InitialInstance::GetBehaviorOverriding(const gd::String &name) {
|
|
return behaviorOverridings.GetBehavior(name);
|
|
}
|
|
|
|
const gd::Behavior &
|
|
InitialInstance::GetBehaviorOverriding(const gd::String &name) const {
|
|
return behaviorOverridings.GetBehavior(name);
|
|
}
|
|
|
|
bool InitialInstance::HasBehaviorOverridingNamed(const gd::String &name) const {
|
|
return behaviorOverridings.HasBehaviorNamed(name);
|
|
}
|
|
|
|
void InitialInstance::RemoveBehaviorOverriding(const gd::String &name) {
|
|
behaviorOverridings.RemoveBehavior(name);
|
|
}
|
|
|
|
bool InitialInstance::RenameBehaviorOverriding(const gd::String &name,
|
|
const gd::String &newName) {
|
|
return behaviorOverridings.RenameBehavior(name, newName);
|
|
}
|
|
|
|
gd::Behavior *
|
|
InitialInstance::AddNewBehaviorOverriding(const gd::Project &project,
|
|
const gd::String &type,
|
|
const gd::String &name) {
|
|
return behaviorOverridings.AddNewBehavior(project, type, name);
|
|
}
|
|
|
|
} // namespace gd
|