You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
9.6 KiB
C++
282 lines
9.6 KiB
C++
/*
|
|
* 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 <Serialization/StringList.h>
|
|
#include <CryExtension/ICryFactoryRegistry.h>
|
|
#include <CryExtension/CryTypeID.h>
|
|
#include <ISystem.h>
|
|
|
|
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 TBase, class TSerializable = TBase>
|
|
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<TBase>())
|
|
{
|
|
setNullLabel("[ None ]");
|
|
ICryFactoryRegistry* factoryRegistry = gEnv->pSystem->GetCryFactoryRegistry();
|
|
|
|
size_t factoryCount = 0;
|
|
factoryRegistry->IterateFactories(cryiidof<TBase>(), 0, factoryCount);
|
|
|
|
if (factoryCount)
|
|
{
|
|
string sharedPrefix;
|
|
bool hasSharedPrefix = true;
|
|
AZStd::unique_ptr<ICryFactory*[]> factories(new ICryFactory*[factoryCount]);
|
|
factoryRegistry->IterateFactories(cryiidof<TBase>(), factories.get(), factoryCount);
|
|
|
|
for (size_t i = 0; i < factoryCount; ++i)
|
|
{
|
|
ICryFactory* factory = factories[i];
|
|
if (factory->ClassSupports(cryiidof<TSerializable>()))
|
|
{
|
|
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<TBase> ptr(create(m_types[index].name()));
|
|
if (TSerializable* ser = cryinterface_cast<TSerializable>(ptr.get()))
|
|
{
|
|
ar(*ser, name, label);
|
|
}
|
|
}
|
|
|
|
AZStd::shared_ptr<TBase> 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<TBase>(m_factories[i]->CreateClassInstance());
|
|
}
|
|
}
|
|
return AZStd::shared_ptr<TBase>();
|
|
}
|
|
|
|
const char* getRegisteredTypeName(const AZStd::shared_ptr<TBase>& ptr) const
|
|
{
|
|
if (!ptr.get())
|
|
{
|
|
return "";
|
|
}
|
|
CryInterfaceID id = AZStd::static_pointer_cast<TBase>(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<Serialization::TypeDescription> m_types;
|
|
std::vector<string> m_labels;
|
|
std::vector<ICryFactory*> m_factories;
|
|
std::vector<CryInterfaceID> m_classIds;
|
|
};
|
|
|
|
// Exposes CryExtension shared_ptr<> as serializeable type for Serialization::IArchive
|
|
template<class T, class TSerializable>
|
|
class CryExtensionSharedPtr
|
|
: public Serialization::IPointer
|
|
{
|
|
public:
|
|
CryExtensionSharedPtr(AZStd::shared_ptr<T>& 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<T>(); }
|
|
virtual Serialization::SStruct serializer() const override
|
|
{
|
|
if (TSerializable* ser = cryinterface_cast<TSerializable>(m_ptr.get()))
|
|
{
|
|
return Serialization::SStruct(*ser);
|
|
}
|
|
else
|
|
{
|
|
return Serialization::SStruct();
|
|
}
|
|
}
|
|
void* get() const override { return reinterpret_cast<void*>(m_ptr.get()); }
|
|
const void* handle() const override { return &m_ptr; }
|
|
Serialization::TypeID pointerType() const override { return Serialization::TypeID::get<AZStd::shared_ptr<T> >(); }
|
|
CryExtensionClassFactory<T, TSerializable>* factory() const override { return &CryExtensionClassFactory<T, TSerializable>::the(); }
|
|
protected:
|
|
AZStd::shared_ptr<T>& m_ptr;
|
|
};
|
|
}
|
|
|
|
#endif // CRYINCLUDE_CRYCOMMON_SERIALIZATION_CRYEXTENSIONIMPL_H
|