/* * 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 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 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