/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #ifndef CRYINCLUDE_CRYCOMMON_SERIALIZATION_CRYEXTENSIONIMPL_H #define CRYINCLUDE_CRYCOMMON_SERIALIZATION_CRYEXTENSIONIMPL_H #pragma once #include #include #include #include namespace Serialization { // Generate user-friendly class name, e.g. convert // "AnimationPoseModifier_FootStore" -> "Foot Store" inline string MakePrettyClassName(const char* className) { const char* firstSep = strchr(className, '_'); if (!firstSep) { // name doesn't follow expected convention, return as is return className; } const char* start = firstSep + 1; string result; result.reserve(strlen(start) + 4); const char* p = start; while (*p != '\0') { if (*p >= 'A' && *p <= 'Z' && *(p - 1) >= 'a' && *(p - 1) <= 'z') { result += ' '; } if (*p == '_') { result += ' '; } else { result += *p; } ++p; } return result; } // Provides Serialization::IClassFactory interface for classes // registered with CryExtension to IArchive. // // TSerializable can be used to expose Serialize method through // a separate interface, rathern than TBase. Safe to missing // as QueryInterface is used to check its presence. template class CryExtensionClassFactory : public Serialization::IClassFactory { public: size_t size() const override { return m_types.size(); } static CryExtensionClassFactory& the() { static CryExtensionClassFactory instance; return instance; } CryExtensionClassFactory() : IClassFactory(Serialization::TypeID::get()) { setNullLabel("[ None ]"); ICryFactoryRegistry* factoryRegistry = gEnv->pSystem->GetCryFactoryRegistry(); size_t factoryCount = 0; factoryRegistry->IterateFactories(cryiidof(), 0, factoryCount); if (factoryCount) { string sharedPrefix; bool hasSharedPrefix = true; AZStd::unique_ptr factories(new ICryFactory*[factoryCount]); factoryRegistry->IterateFactories(cryiidof(), factories.get(), factoryCount); for (size_t i = 0; i < factoryCount; ++i) { ICryFactory* factory = factories[i]; if (factory->ClassSupports(cryiidof())) { m_factories.push_back(factory); if (hasSharedPrefix) { // make sure that shared prefix is the same for all the names const char* name = factory->GetName(); const char* lastPrefixCharacter = strchr(name, '_'); if (lastPrefixCharacter == 0) { hasSharedPrefix = false; } else { if (!sharedPrefix.empty()) { if (strncmp(name, sharedPrefix.c_str(), sharedPrefix.size()) != 0) { hasSharedPrefix = false; } } else { sharedPrefix.assign(name, lastPrefixCharacter + 1); } } } } } size_t usableFactoriesCount = m_factories.size(); m_types.reserve(usableFactoriesCount); m_labels.reserve(usableFactoriesCount); for (size_t i = 0; i < usableFactoriesCount; ++i) { ICryFactory* factory = m_factories[i]; m_classIds.push_back(factory->GetClassID()); const char* name = factory->GetName(); m_labels.push_back(MakePrettyClassName(name)); if (hasSharedPrefix) { name += sharedPrefix.size(); } m_types.push_back(Serialization::TypeDescription(name, m_labels.back().c_str())); } } } const Serialization::TypeDescription* descriptionByIndex(int index) const override { if (size_t(index) >= m_types.size()) { return 0; } return &m_types[index]; } const Serialization::TypeDescription* descriptionByRegisteredName(const char* registeredName) const override { size_t count = m_types.size(); for (size_t i = 0; i < m_types.size(); ++i) { if (strcmp(m_types[i].name(), registeredName) == 0) { return &m_types[i]; } } return 0; } const char* findAnnotation(const char* typeName, const char* name) const override { return ""; } void serializeNewByIndex(IArchive& ar, int index, const char* name, const char* label) override { if (size_t(index) >= m_types.size()) { return; } AZStd::shared_ptr ptr(create(m_types[index].name())); if (TSerializable* ser = cryinterface_cast(ptr.get())) { ar(*ser, name, label); } } AZStd::shared_ptr create(const char* registeredName) { size_t count = m_types.size(); for (size_t i = 0; i < count; ++i) { if (strcmp(m_types[i].name(), registeredName) == 0) { return AZStd::static_pointer_cast(m_factories[i]->CreateClassInstance()); } } return AZStd::shared_ptr(); } const char* getRegisteredTypeName(const AZStd::shared_ptr& ptr) const { if (!ptr.get()) { return ""; } CryInterfaceID id = AZStd::static_pointer_cast(ptr)->GetFactory()->GetClassID(); size_t count = m_classIds.size(); for (size_t i = 0; i < count; ++i) { if (m_classIds[i] == id) { return m_types[i].name(); } } return ""; } private: std::vector m_types; std::vector m_labels; std::vector m_factories; std::vector m_classIds; }; // Exposes CryExtension shared_ptr<> as serializeable type for Serialization::IArchive template class CryExtensionSharedPtr : public Serialization::IPointer { public: CryExtensionSharedPtr(AZStd::shared_ptr& ptr) : m_ptr(ptr) {} const char* registeredTypeName() const override { if (m_ptr) { return factory()->getRegisteredTypeName(m_ptr); } else { return ""; } } void create(const char* registeredTypeName) const override { if (registeredTypeName[0] != '\0') { m_ptr = factory()->create(registeredTypeName); } else { m_ptr.reset((T*)0); } } Serialization::TypeID baseType() const{ return Serialization::TypeID::get(); } virtual Serialization::SStruct serializer() const override { if (TSerializable* ser = cryinterface_cast(m_ptr.get())) { return Serialization::SStruct(*ser); } else { return Serialization::SStruct(); } } void* get() const override { return reinterpret_cast(m_ptr.get()); } const void* handle() const override { return &m_ptr; } Serialization::TypeID pointerType() const override { return Serialization::TypeID::get >(); } CryExtensionClassFactory* factory() const override { return &CryExtensionClassFactory::the(); } protected: AZStd::shared_ptr& m_ptr; }; } #endif // CRYINCLUDE_CRYCOMMON_SERIALIZATION_CRYEXTENSIONIMPL_H