Remove legacy serialization and QPropertyTree (#684)

Remove:
- CryCommon/CryExtension/*
- CryCommon/Serialization/*
- Sandbox/Plugins/EditorCommon/QPropertyTree/*
- All related CryCommon interfaces
- All CrySystem implementations
- Various related Editor classes
This commit is contained in:
bosnichd
2021-05-11 09:31:02 -06:00
committed by GitHub
parent a009e38064
commit 3defbce31b
338 changed files with 16 additions and 63358 deletions
+1 -8
View File
@@ -15,10 +15,6 @@
#include "System.h"
#include <AZCrySystemInitLogSink.h>
#include "DebugCallStack.h"
#if defined(AZ_MONOLITHIC_BUILD)
#include <CryCommon/CryExtension/Impl/ICryFactoryRegistryImpl.h>
#include <CryCommon/CryExtension/Impl/RegFactoryNode.h>
#endif
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
@@ -132,10 +128,7 @@ CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupPar
#define AZ_RESTRICTED_SECTION DLLMAIN_CPP_SECTION_2
#include AZ_RESTRICTED_FILE(DllMain_cpp)
#endif
#if defined(AZ_MONOLITHIC_BUILD)
ICryFactoryRegistryImpl* pCryFactoryImpl = static_cast<ICryFactoryRegistryImpl*>(pSystem->GetCryFactoryRegistry());
pCryFactoryImpl->RegisterFactories(g_pHeadToRegFactories);
#endif // AZ_MONOLITHIC_BUILD
// the earliest point the system exists - w2e tell the callback
if (startupParams.pUserCallback)
{
@@ -1,359 +0,0 @@
/*
* 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.
// Description : Part of CryEngine's extension framework.
#include "CrySystem_precompiled.h"
#include "CryFactoryRegistryImpl.h"
#include "../System.h"
#include <CryExtension/ICryUnknown.h>
#include <CryExtension/Impl/RegFactoryNode.h>
#include <CryExtension/Impl/CryGUIDHelper.h>
#include <algorithm>
CCryFactoryRegistryImpl::CCryFactoryRegistryImpl()
: m_guard()
, m_byCName()
, m_byCID()
, m_byIID()
, m_callbacks()
{
}
CCryFactoryRegistryImpl::~CCryFactoryRegistryImpl()
{
}
CCryFactoryRegistryImpl& CCryFactoryRegistryImpl::Access()
{
static StaticInstance<CCryFactoryRegistryImpl, AZStd::no_destruct<CCryFactoryRegistryImpl>> s_registry;
return s_registry;
}
ICryFactory* CCryFactoryRegistryImpl::GetFactory(const char* cname) const
{
AUTO_READLOCK(m_guard);
if (!cname)
{
return 0;
}
const FactoryByCName search(cname);
FactoriesByCNameConstIt it = std::lower_bound(m_byCName.begin(), m_byCName.end(), search);
return it != m_byCName.end() && !(search < *it) ? (*it).m_ptr : 0;
}
ICryFactory* CCryFactoryRegistryImpl::GetFactory(const CryClassID& cid) const
{
AUTO_READLOCK(m_guard);
const FactoryByCID search(cid);
FactoriesByCIDConstIt it = std::lower_bound(m_byCID.begin(), m_byCID.end(), search);
return it != m_byCID.end() && !(search < *it) ? (*it).m_ptr : 0;
}
void CCryFactoryRegistryImpl::IterateFactories(const CryInterfaceID& iid, ICryFactory** pFactories, size_t& numFactories) const
{
AUTO_READLOCK(m_guard);
typedef std::pair<FactoriesByIIDConstIt, FactoriesByIIDConstIt> SearchResult;
SearchResult res = std::equal_range(m_byIID.begin(), m_byIID.end(), FactoryByIID(iid, 0), LessPredFactoryByIIDOnly());
const size_t numFactoriesFound = std::distance(res.first, res.second);
if (pFactories)
{
numFactories = min(numFactories, numFactoriesFound);
FactoriesByIIDConstIt it = res.first;
for (size_t i = 0; i < numFactories; ++i, ++it)
{
pFactories[i] = (*it).m_ptr;
}
}
else
{
numFactories = numFactoriesFound;
}
}
void CCryFactoryRegistryImpl::RegisterCallback(ICryFactoryRegistryCallback* pCallback)
{
if (!pCallback)
{
return;
}
{
AUTO_MODIFYLOCK(m_guard);
Callbacks::iterator it = std::lower_bound(m_callbacks.begin(), m_callbacks.end(), pCallback);
if (it == m_callbacks.end() || pCallback < *it)
{
m_callbacks.insert(it, pCallback);
}
else
{
assert(0 && "CCryFactoryRegistryImpl::RegisterCallback() -- pCallback already registered!");
}
}
{
AUTO_READLOCK(m_guard);
typedef std::pair<FactoriesByIIDConstIt, FactoriesByIIDConstIt> SearchResult;
SearchResult res = std::equal_range(m_byIID.begin(), m_byIID.end(), FactoryByIID(cryiidof<ICryUnknown>(), 0), LessPredFactoryByIIDOnly());
for (; res.first != res.second; ++res.first)
{
pCallback->OnNotifyFactoryRegistered((*res.first).m_ptr);
}
}
}
void CCryFactoryRegistryImpl::UnregisterCallback(ICryFactoryRegistryCallback* pCallback)
{
if (!pCallback)
{
return;
}
AUTO_MODIFYLOCK(m_guard);
Callbacks::iterator it = std::lower_bound(m_callbacks.begin(), m_callbacks.end(), pCallback);
if (it != m_callbacks.end() && !(pCallback < *it))
{
m_callbacks.erase(it);
}
}
bool CCryFactoryRegistryImpl::GetInsertionPos(ICryFactory* pFactory, FactoriesByCNameIt& itPosForCName, FactoriesByCIDIt& itPosForCID)
{
assert(pFactory);
struct FatalError
{
static void Report(ICryFactory* pKnownFactory, ICryFactory* pNewFactory)
{
char err[1024];
sprintf_s(err, sizeof(err), "Conflicting factories...\n"
"Factory (0x%p): ClassID = %s, ClassName = \"%s\"\n"
"Factory (0x%p): ClassID = %s, ClassName = \"%s\"",
pKnownFactory, pKnownFactory ? CryGUIDHelper::Print(pKnownFactory->GetClassID()).c_str() : "$unknown$", pKnownFactory ? pKnownFactory->GetName() : "$unknown$",
pNewFactory, pNewFactory ? CryGUIDHelper::Print(pNewFactory->GetClassID()).c_str() : "$unknown$", pNewFactory ? pNewFactory->GetName() : "$unknown$");
#if AZ_LEGACY_CRYSYSTEM_TRAIT_FACTORY_REGISTRY_USE_PRINTF_FOR_FATAL
printf("\n!!! Fatal error !!!\n");
printf(err);
printf("\n");
#elif defined(WIN32) || defined(WIN64)
OutputDebugStringA("\n!!! Fatal error !!!\n");
OutputDebugStringA(err);
OutputDebugStringA("\n");
MessageBoxA(0, err, "!!! Fatal error !!!", MB_OK | MB_ICONERROR);
#endif
assert(0);
exit(0);
}
};
FactoryByCName searchByCName(pFactory);
FactoriesByCNameIt itForCName = std::lower_bound(m_byCName.begin(), m_byCName.end(), searchByCName);
if (itForCName != m_byCName.end())
{
// If the addresses match, then this factory is already registered. It's not really worth error-ing about,
// as double registration will not cause any harm.
if (itForCName->m_ptr == pFactory)
{
return false;
}
if (!(searchByCName < *itForCName))
{
FatalError::Report((*itForCName).m_ptr, pFactory);
}
}
FactoryByCID searchByCID(pFactory);
FactoriesByCIDIt itForCID = std::lower_bound(m_byCID.begin(), m_byCID.end(), searchByCID);
if (itForCID != m_byCID.end() && !(searchByCID < *itForCID))
{
FatalError::Report((*itForCID).m_ptr, pFactory);
}
itPosForCName = itForCName;
itPosForCID = itForCID;
return true;
}
void CCryFactoryRegistryImpl::RegisterFactories(const SRegFactoryNode* pFactories)
{
size_t numFactoriesToAdd = 0;
size_t numInterfacesSupported = 0;
{
const SRegFactoryNode* p = pFactories;
while (p)
{
ICryFactory* pFactory = p->m_pFactory;
assert(pFactory);
if (pFactory)
{
const CryInterfaceID* pIIDs = 0;
size_t numIIDs = 0;
pFactory->ClassSupports(pIIDs, numIIDs);
numInterfacesSupported += numIIDs;
++numFactoriesToAdd;
}
p = p->m_pNext;
}
}
{
AUTO_MODIFYLOCK(m_guard);
m_byCName.reserve(m_byCName.size() + numFactoriesToAdd);
m_byCID.reserve(m_byCID.size() + numFactoriesToAdd);
m_byIID.reserve(m_byIID.size() + numInterfacesSupported);
size_t numFactoriesAdded = 0;
const SRegFactoryNode* p = pFactories;
while (p)
{
ICryFactory* pFactory = p->m_pFactory;
if (pFactory)
{
FactoriesByCNameIt itPosForCName;
FactoriesByCIDIt itPosForCID;
if (GetInsertionPos(pFactory, itPosForCName, itPosForCID))
{
m_byCName.insert(itPosForCName, FactoryByCName(pFactory));
m_byCID.insert(itPosForCID, FactoryByCID(pFactory));
const CryInterfaceID* pIIDs = 0;
size_t numIIDs = 0;
pFactory->ClassSupports(pIIDs, numIIDs);
for (size_t i = 0; i < numIIDs; ++i)
{
const FactoryByIID newFactory(pIIDs[i], pFactory);
m_byIID.push_back(newFactory);
}
for (size_t i = 0, s = m_callbacks.size(); i < s; ++i)
{
m_callbacks[i]->OnNotifyFactoryRegistered(pFactory);
}
++numFactoriesAdded;
}
}
p = p->m_pNext;
}
if (numFactoriesAdded)
{
std::sort(m_byIID.begin(), m_byIID.end());
}
}
}
void CCryFactoryRegistryImpl::UnregisterFactories(const SRegFactoryNode* pFactories)
{
AUTO_MODIFYLOCK(m_guard);
const SRegFactoryNode* p = pFactories;
while (p)
{
ICryFactory* pFactory = p->m_pFactory;
UnregisterFactoryInternal(pFactory);
p = p->m_pNext;
}
}
void CCryFactoryRegistryImpl::UnregisterFactory(ICryFactory* const pFactory)
{
AUTO_MODIFYLOCK(m_guard);
UnregisterFactoryInternal(pFactory);
}
void CCryFactoryRegistryImpl::UnregisterFactoryInternal(ICryFactory* const pFactory)
{
if (pFactory)
{
FactoryByCName searchByCName(pFactory);
FactoriesByCNameIt itForCName = std::lower_bound(m_byCName.begin(), m_byCName.end(), searchByCName);
if (itForCName != m_byCName.end() && !(searchByCName < *itForCName))
{
assert((*itForCName).m_ptr == pFactory);
if ((*itForCName).m_ptr == pFactory)
{
m_byCName.erase(itForCName);
}
}
FactoryByCID searchByCID(pFactory);
FactoriesByCIDIt itForCID = std::lower_bound(m_byCID.begin(), m_byCID.end(), searchByCID);
if (itForCID != m_byCID.end() && !(searchByCID < *itForCID))
{
assert((*itForCID).m_ptr == pFactory);
if ((*itForCID).m_ptr == pFactory)
{
m_byCID.erase(itForCID);
}
}
const CryInterfaceID* pIIDs = 0;
size_t numIIDs = 0;
pFactory->ClassSupports(pIIDs, numIIDs);
for (size_t i = 0; i < numIIDs; ++i)
{
FactoryByIID searchByIID(pIIDs[i], pFactory);
FactoriesByIIDIt itForIID = std::lower_bound(m_byIID.begin(), m_byIID.end(), searchByIID);
if (itForIID != m_byIID.end() && !(searchByIID < *itForIID))
{
m_byIID.erase(itForIID);
}
}
for (size_t i = 0, s = m_callbacks.size(); i < s; ++i)
{
m_callbacks[i]->OnNotifyFactoryUnregistered(pFactory);
}
}
}
ICryFactoryRegistry* CSystem::GetCryFactoryRegistry() const
{
return &CCryFactoryRegistryImpl::Access();
}
@@ -1,128 +0,0 @@
/*
* 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.
// Description : Part of CryEngine's extension framework.
#ifndef CRYINCLUDE_CRYSYSTEM_EXTENSIONSYSTEM_CRYFACTORYREGISTRYIMPL_H
#define CRYINCLUDE_CRYSYSTEM_EXTENSIONSYSTEM_CRYFACTORYREGISTRYIMPL_H
#pragma once
#include <CryExtension/Impl/ICryFactoryRegistryImpl.h>
#include <CryExtension/ICryFactory.h>
#include <AzCore/std/containers/vector.h>
class CCryFactoryRegistryImpl
: public ICryFactoryRegistryImpl
{
public:
virtual ICryFactory* GetFactory(const char* cname) const;
virtual ICryFactory* GetFactory(const CryClassID& cid) const;
virtual void IterateFactories(const CryInterfaceID& iid, ICryFactory** pFactories, size_t& numFactories) const;
virtual void RegisterCallback(ICryFactoryRegistryCallback* pCallback);
virtual void UnregisterCallback(ICryFactoryRegistryCallback* pCallback);
virtual void RegisterFactories(const SRegFactoryNode* pFactories);
virtual void UnregisterFactories(const SRegFactoryNode* pFactories);
virtual void UnregisterFactory(ICryFactory* const pFactory);
public:
static CCryFactoryRegistryImpl& Access();
CCryFactoryRegistryImpl();
~CCryFactoryRegistryImpl();
private:
struct FactoryByCName
{
const char* m_cname;
ICryFactory* m_ptr;
FactoryByCName(const char* cname)
: m_cname(cname)
, m_ptr(0) {assert(m_cname); }
FactoryByCName(ICryFactory* ptr)
: m_cname(ptr ? ptr->GetName() : 0)
, m_ptr(ptr) {assert(m_cname && m_ptr); }
bool operator <(const FactoryByCName& rhs) const {return strcmp(m_cname, rhs.m_cname) < 0; }
};
typedef std::vector<FactoryByCName> FactoriesByCName;
typedef FactoriesByCName::iterator FactoriesByCNameIt;
typedef FactoriesByCName::const_iterator FactoriesByCNameConstIt;
struct FactoryByCID
{
CryClassID m_cid;
ICryFactory* m_ptr;
FactoryByCID(const CryClassID& cid)
: m_cid(cid)
, m_ptr(0) {}
FactoryByCID(ICryFactory* ptr)
: m_cid(ptr ? ptr->GetClassID() : MAKE_CRYGUID(0, 0))
, m_ptr(ptr) {assert(m_ptr); }
bool operator <(const FactoryByCID& rhs) const {return m_cid < rhs.m_cid; }
};
typedef std::vector<FactoryByCID> FactoriesByCID;
typedef FactoriesByCID::iterator FactoriesByCIDIt;
typedef FactoriesByCID::const_iterator FactoriesByCIDConstIt;
struct FactoryByIID
{
CryInterfaceID m_iid;
ICryFactory* m_ptr;
FactoryByIID(CryInterfaceID iid, ICryFactory* pFactory)
: m_iid(iid)
, m_ptr(pFactory) {}
bool operator <(const FactoryByIID& rhs) const
{
if (m_iid != rhs.m_iid)
{
return m_iid < rhs.m_iid;
}
return m_ptr < rhs.m_ptr;
}
};
typedef std::vector<FactoryByIID> FactoriesByIID;
typedef FactoriesByIID::iterator FactoriesByIIDIt;
typedef FactoriesByIID::const_iterator FactoriesByIIDConstIt;
struct LessPredFactoryByIIDOnly
{
bool operator ()(const FactoryByIID& lhs, const FactoryByIID& rhs) const {return lhs.m_iid < rhs.m_iid; }
};
typedef std::vector<ICryFactoryRegistryCallback*> Callbacks;
typedef Callbacks::iterator CallbacksIt;
typedef Callbacks::const_iterator CallbacksConstIt;
private:
bool GetInsertionPos(ICryFactory* pFactory, FactoriesByCNameIt& itPosForCName, FactoriesByCIDIt& itPosForCID);
void UnregisterFactoryInternal(ICryFactory* const pFactory);
private:
mutable CryReadModifyLock m_guard;
FactoriesByCName m_byCName;
FactoriesByCID m_byCID;
FactoriesByIID m_byIID;
Callbacks m_callbacks;
};
#endif // CRYINCLUDE_CRYSYSTEM_EXTENSIONSYSTEM_CRYFACTORYREGISTRYIMPL_H
@@ -1,955 +0,0 @@
/*
* 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.
// Description : Part of CryEngine's extension framework.
#include "CrySystem_precompiled.h"
#include "TestExtensions.h"
#ifdef EXTENSION_SYSTEM_INCLUDE_TESTCASES
#include <CryExtension/Impl/ClassWeaver.h>
#include <CryExtension/Impl/ICryFactoryRegistryImpl.h>
#include <CryExtension/CryCreateClassInstance.h>
//////////////////////////////////////////////////////////////////////////
namespace TestComposition
{
struct ITestExt1
: public ICryUnknown
{
CRYINTERFACE_DECLARE(ITestExt1, 0x9d9e0dcfa5764cb0, 0xa73701595f75bd32)
virtual void Call1() const = 0;
};
DECLARE_SMART_POINTERS(ITestExt1);
class CTestExt1
: public ITestExt1
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(ITestExt1)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CTestExt1, "TestExt1", 0x43b04e7cc1be45ca, 0x9df6ccb1c0dc1ad8)
public:
virtual void Call1() const;
private:
int i;
};
CRYREGISTER_CLASS(CTestExt1)
CTestExt1::CTestExt1()
{
i = 1;
}
CTestExt1::~CTestExt1()
{
printf("Inside CTestExt1 dtor\n");
}
void CTestExt1::Call1() const
{
printf("Inside CTestExt1::Call1()\n");
}
//////////////////////////////////////////////////////////////////////////
struct ITestExt2
: public ICryUnknown
{
CRYINTERFACE_DECLARE(ITestExt2, 0x8eb7a4b399874b9c, 0xb96bd6da7a8c72f9)
virtual void Call2() = 0;
};
DECLARE_SMART_POINTERS(ITestExt2);
class CTestExt2
: public ITestExt2
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(ITestExt2)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CTestExt2, "TestExt2", 0x25b3ebf8f1754b9a, 0xb5494e3da7cdd80f)
public:
virtual void Call2();
private:
int i;
};
CRYREGISTER_CLASS(CTestExt2)
CTestExt2::CTestExt2()
{
i = 2;
}
CTestExt2::~CTestExt2()
{
printf("Inside CTestExt2 dtor\n");
}
void CTestExt2::Call2()
{
printf("Inside CTestExt2::Call2()\n");
}
//////////////////////////////////////////////////////////////////////////
class CComposed
: public ICryUnknown
{
CRYGENERATE_CLASS(CComposed, "Composed", 0x0439d74b8dcd4b7f, 0x9287dcdf7e26a3a5)
CRYCOMPOSITE_BEGIN()
CRYCOMPOSITE_ADD(m_pTestExt1, "Ext1")
CRYCOMPOSITE_ADD(m_pTestExt2, "Ext2")
CRYCOMPOSITE_END(CComposed)
CRYINTERFACE_BEGIN()
CRYINTERFACE_END()
private:
ITestExt1Ptr m_pTestExt1;
ITestExt2Ptr m_pTestExt2;
};
CRYREGISTER_CLASS(CComposed)
CComposed::CComposed()
: m_pTestExt1()
, m_pTestExt2()
{
CryCreateClassInstance("TestExt1", m_pTestExt1);
CryCreateClassInstance("TestExt2", m_pTestExt2);
}
CComposed::~CComposed()
{
}
//////////////////////////////////////////////////////////////////////////
struct ITestExt3
: public ICryUnknown
{
CRYINTERFACE_DECLARE(ITestExt3, 0xdd017935a2134898, 0xbd2fffa145551876)
virtual void Call3() = 0;
};
DECLARE_SMART_POINTERS(ITestExt3);
class CTestExt3
: public ITestExt3
{
CRYGENERATE_CLASS(CTestExt3, "TestExt3", 0xeceab40bc4bb4988, 0xa9f63c1db85a69b1)
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(ITestExt3)
CRYINTERFACE_END()
public:
virtual void Call3();
private:
int i;
};
CRYREGISTER_CLASS(CTestExt3)
CTestExt3::CTestExt3()
{
i = 3;
}
CTestExt3::~CTestExt3()
{
printf("Inside CTestExt3 dtor\n");
}
void CTestExt3::Call3()
{
printf("Inside CTestExt3::Call3()\n");
}
//////////////////////////////////////////////////////////////////////////
class CComposed2
: public ICryUnknown
{
CRYGENERATE_CLASS(CComposed2, "Composed2", 0x0439d74b8dcd4b7e, 0x9287dcdf7e26a3a6)
CRYCOMPOSITE_BEGIN()
CRYCOMPOSITE_ADD(m_pTestExt3, "Ext3")
CRYCOMPOSITE_END(CComposed2)
CRYINTERFACE_BEGIN()
CRYINTERFACE_END()
private:
ITestExt3Ptr m_pTestExt3;
};
CRYREGISTER_CLASS(CComposed2)
CComposed2::CComposed2()
: m_pTestExt3()
{
CryCreateClassInstance("TestExt3", m_pTestExt3);
}
CComposed2::~CComposed2()
{
}
//////////////////////////////////////////////////////////////////////////
class CTestExt4
: public ITestExt1
, public ITestExt2
, public ITestExt3
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(ITestExt1)
CRYINTERFACE_ADD(ITestExt2)
CRYINTERFACE_ADD(ITestExt3)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CTestExt4, "TestExt4", 0x43204e7cc1be45ca, 0x9df4ccb1c0dc1ad8)
public:
virtual void Call1() const;
virtual void Call2();
virtual void Call3();
private:
int i;
};
CRYREGISTER_CLASS(CTestExt4)
CTestExt4::CTestExt4()
{
i = 4;
}
CTestExt4::~CTestExt4()
{
printf("Inside CTestExt4 dtor\n");
}
void CTestExt4::Call1() const
{
printf("Inside CTestExt4::Call1()\n");
}
void CTestExt4::Call2()
{
printf("Inside CTestExt4::Call2()\n");
}
void CTestExt4::Call3()
{
printf("Inside CTestExt4::Call3()\n");
}
//////////////////////////////////////////////////////////////////////////
class CMegaComposed
: public CComposed
, public CComposed2
{
CRYGENERATE_CLASS(CMegaComposed, "MegaComposed", 0x512787559f84503, 0x421ac1af66f2fb6f)
CRYCOMPOSITE_BEGIN()
CRYCOMPOSITE_ADD(m_pTestExt4, "Ext4")
CRYCOMPOSITE_ENDWITHBASE2(CMegaComposed, CComposed, CComposed2)
CRYINTERFACE_BEGIN()
CRYINTERFACE_END()
private:
AZStd::shared_ptr<CTestExt4> m_pTestExt4;
};
CRYREGISTER_CLASS(CMegaComposed)
CMegaComposed::CMegaComposed()
: m_pTestExt4()
{
printf("Inside CMegaComposed ctor\n");
m_pTestExt4 = CTestExt4::CreateClassInstance();
}
CMegaComposed::~CMegaComposed()
{
printf("Inside CMegaComposed dtor\n");
}
//////////////////////////////////////////////////////////////////////////
static void TestComposition()
{
printf("\nTest composition:\n");
ICryUnknownPtr p;
if (CryCreateClassInstance("MegaComposed", p))
{
ITestExt1Ptr p1 = cryinterface_cast<ITestExt1>(crycomposite_query(p, "Ext1"));
if (p1)
{
p1->Call1(); // calls CTestExt1::Call1()
}
ITestExt2Ptr p2 = cryinterface_cast<ITestExt2>(crycomposite_query(p, "Ext2"));
if (p2)
{
p2->Call2(); // calls CTestExt2::Call2()
}
ITestExt3Ptr p3 = cryinterface_cast<ITestExt3>(crycomposite_query(p, "Ext3"));
if (p3)
{
p3->Call3(); // calls CTestExt3::Call3()
}
p3 = cryinterface_cast<ITestExt3>(crycomposite_query(p, "Ext4"));
if (p3)
{
p3->Call3(); // calls CTestExt4::Call3()
}
p1 = cryinterface_cast<ITestExt1>(crycomposite_query(p.get(), "Ext4"));
p2 = cryinterface_cast<ITestExt2>(crycomposite_query(p.get(), "Ext4"));
bool b = CryIsSameClassInstance(p1, p2); // true
}
{
ICryUnknownConstPtr pCUnk = p;
ICryUnknownConstPtr pComp1 = crycomposite_query(pCUnk.get(), "Ext1");
//ICryUnknownPtr pComp1 = crycomposite_query(pCUnk, "Ext1"); // must fail to compile due to const rules
ITestExt1ConstPtr p1 = cryinterface_cast<const ITestExt1>(pComp1);
if (p1)
{
p1->Call1();
}
}
}
} // namespace TestComposition
//////////////////////////////////////////////////////////////////////////
namespace TestExtension
{
class CFoobar
: public IFoobar
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(IFoobar)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CFoobar, "Foobar", 0x76c8dd6d16634531, 0x95d3b1cfabcf7ef4)
public:
virtual void Foo();
};
CRYREGISTER_CLASS(CFoobar)
CFoobar::CFoobar()
{
}
CFoobar::~CFoobar()
{
}
void CFoobar::Foo()
{
printf("Inside CFoobar::Foo()\n");
}
static void TestFoobar()
{
AZStd::shared_ptr<CFoobar> p = CFoobar::CreateClassInstance();
{
CryInterfaceID iid = cryiidof<IFoobar>();
CryClassID clsid = p->GetFactory()->GetClassID();
int t = 0;
}
{
IAPtr sp_ = cryinterface_cast<IA>(p); // sp_ == NULL
ICryUnknownPtr sp1 = cryinterface_cast<ICryUnknown>(p);
IFoobarPtr sp = cryinterface_cast<IFoobar>(sp1);
sp->Foo();
}
{
CFoobar* pF = p.get();
pF->Foo();
ICryUnknown* p1 = cryinterface_cast<ICryUnknown>(pF);
}
IFoobar* pFoo = cryinterface_cast<IFoobar>(p.get());
ICryFactory* pF1 = pFoo->GetFactory();
pFoo->Foo();
int t = 0;
}
//////////////////////////////////////////////////////////////////////////
class CRaboof
: public IRaboof
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(IRaboof)
CRYINTERFACE_END()
CRYGENERATE_SINGLETONCLASS(CRaboof, "Raabof", 0xba482ce12b2e4309, 0x8238ed8b52cb1f1e)
public:
virtual void Rab();
};
CRYREGISTER_SINGLETON_CLASS(CRaboof)
CRaboof::CRaboof()
{
}
CRaboof::~CRaboof()
{
}
void CRaboof::Rab()
{
printf("Inside CRaboof::Rab()\n");
}
static void TestRaboof()
{
AZStd::shared_ptr<CRaboof> pFoo0_ = CRaboof::CreateClassInstance();
IRaboofPtr pFoo0 = cryinterface_cast<IRaboof>(pFoo0_);
ICryUnknownPtr p0 = cryinterface_cast<ICryUnknown>(pFoo0);
CryInterfaceID iid = cryiidof<IRaboof>();
CryClassID clsid = p0->GetFactory()->GetClassID();
AZStd::shared_ptr<CRaboof> pFoo1 = CRaboof::CreateClassInstance();
pFoo0->Rab();
pFoo1->Rab();
}
//////////////////////////////////////////////////////////////////////////
class CAB
: public IA
, public IB
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(IA)
CRYINTERFACE_ADD(IB)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CAB, "AB", 0xb9e54711a64448c0, 0xa4819b4ed3024d04)
public:
virtual void A();
virtual void B();
private:
int i;
};
CRYREGISTER_CLASS(CAB)
CAB::CAB()
{
i = 0x12345678;
}
CAB::~CAB()
{
}
void CAB::A()
{
printf("Inside CAB::A()\n");
}
void CAB::B()
{
printf("Inside CAB::B()\n");
}
//////////////////////////////////////////////////////////////////////////
class CABC
: public CAB
, public IC
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(IC)
CRYINTERFACE_ENDWITHBASE(CAB)
CRYGENERATE_CLASS(CABC, "ABC", 0x4e61feae11854be7, 0xa16157c5f8baadd9)
public:
virtual void C();
private:
int a;
};
CRYREGISTER_CLASS(CABC)
CABC::CABC()
//: CAB()
{
a = 0x87654321;
}
CABC::~CABC()
{
}
void CABC::C()
{
printf("Inside CABC::C()\n");
}
//////////////////////////////////////////////////////////////////////////
class CCustomC
: public ICustomC
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(IC)
CRYINTERFACE_ADD(ICustomC)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CCustomC, "CustomC", 0xee61760b98a44b71, 0xa05e7372b44bd0fd)
public:
virtual void C();
virtual void C1();
private:
int a;
};
CRYREGISTER_CLASS(CCustomC)
CCustomC::CCustomC()
{
a = 0x87654321;
}
CCustomC::~CCustomC()
{
}
void CCustomC::C()
{
printf("Inside CCustomC::C()\n");
}
void CCustomC::C1()
{
printf("Inside CCustomC::C1()\n");
}
//////////////////////////////////////////////////////////////////////////
class CMultiBase
: public CAB
, public CCustomC
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ENDWITHBASE2(CAB, CCustomC)
CRYGENERATE_CLASS(CMultiBase, "MultiBase", 0x75966b8f98644d42, 0x8fbdd489e94cc29e)
public:
virtual void A();
virtual void C1();
int i;
};
CRYREGISTER_CLASS(CMultiBase)
CMultiBase::CMultiBase()
{
i = 0x87654321;
}
CMultiBase::~CMultiBase()
{
}
void CMultiBase::C1()
{
printf("Inside CMultiBase::C1()\n");
}
void CMultiBase::A()
{
printf("Inside CMultiBase::A()\n");
}
//////////////////////////////////////////////////////////////////////////
static void TestComplex()
{
{
ICPtr p;
if (CryCreateClassInstance(MAKE_CRYGUID(0x75966b8f98644d42, 0x8fbdd489e94cc29e), p))
{
p->C();
}
}
{
ICustomCPtr p;
if (CryCreateClassInstance("MultiBase", p))
{
p->C();
}
}
{
IFoobarPtr p;
if (CryCreateClassInstance(MAKE_CRYGUID(0x75966b8f98644d42, 0x8fbdd489e94cc29e), p))
{
p->Foo();
}
}
{
AZStd::shared_ptr<CMultiBase> p = CMultiBase::CreateClassInstance();
AZStd::shared_ptr<const CMultiBase> pc = p;
{
ICryUnknownPtr pUnk = cryinterface_cast<ICryUnknown>(p);
ICryUnknownConstPtr pCUnk0 = cryinterface_cast<const ICryUnknown>(p);
ICryUnknownConstPtr pCUnk1 = cryinterface_cast<const ICryUnknown>(pc);
//ICryUnknownPtr pUnkF = cryinterface_cast<ICryUnknown>(pc); // must fail to compile due to const rules
ICryFactory* pF = pUnk->GetFactory();
int t = 0;
}
ICPtr pC = cryinterface_cast<IC>(p);
ICustomCPtr pCC = cryinterface_cast<ICustomC>(pC);
p->C();
p->C1();
pC->C();
pCC->C1();
IAPtr pA = cryinterface_cast<IA>(p);
pA->A();
p->A();
}
{
AZStd::shared_ptr<CCustomC> p = CCustomC::CreateClassInstance();
ICPtr pC = cryinterface_cast<IC>(p);
ICustomCPtr pCC = cryinterface_cast<ICustomC>(pC);
p->C();
p->C1();
pC->C();
pCC->C1();
}
{
CryInterfaceID ia = cryiidof<IA>();
CryInterfaceID ib = cryiidof<IB>();
CryInterfaceID ic = cryiidof<IC>();
CryInterfaceID ico = cryiidof<ICryUnknown>();
}
{
AZStd::shared_ptr<CAB> p = CAB::CreateClassInstance();
CryClassID clsid = p->GetFactory()->GetClassID();
IAPtr pA = cryinterface_cast<IA>(p);
IBPtr pB = cryinterface_cast<IB>(p);
IBPtr pB1 = cryinterface_cast<IB>(pA);
IAPtr pA1 = cryinterface_cast<IA>(pB);
pA->A();
pB->B();
ICryUnknownPtr p1 = cryinterface_cast<ICryUnknown>(pA);
ICryUnknownPtr p2 = cryinterface_cast<ICryUnknown>(pB);
const ICryUnknown* p3 = cryinterface_cast<const ICryUnknown>(pB.get());
int t = 0;
}
{
AZStd::shared_ptr<CABC> pABC = CABC::CreateClassInstance();
CryClassID clsid = pABC->GetFactory()->GetClassID();
ICryFactory* pFac = pABC->GetFactory();
pFac->ClassSupports(cryiidof<IA>());
pFac->ClassSupports(cryiidof<IRaboof>());
IAPtr pABC0 = cryinterface_cast<IA>(pABC);
IBPtr pABC1 = cryinterface_cast<IB>(pABC0);
ICPtr pABC2 = cryinterface_cast<IC>(pABC1);
pABC2->C();
pABC1->B();
pABC2->GetFactory();
const IC* pCconst = pABC2.get();
const ICryUnknown* pOconst = cryinterface_cast<const ICryUnknown>(pCconst);
const IA* pAconst = cryinterface_cast<const IA>(pOconst);
const IB* pBconst = cryinterface_cast<const IB>(pAconst);
//const IA* pA11 = cryinterface_cast<IA>(pOconst);
pCconst = cryinterface_cast<const IC>(pBconst);
IC* pC = static_cast<IC*>(static_cast<void*>(pABC1.get()));
pC->C(); // calls IB::B()
int t = 0;
}
}
//////////////////////////////////////////////////////////////////////////
// use of extension system without any of the helper macros/templates
class CDontLikeMacrosFactory
: public ICryFactory
{
// ICryFactory
public:
virtual const char* GetClassName() const
{
return "DontLikeMacros";
}
virtual const CryClassID& GetClassID() const
{
static const CryClassID cid = {0x73c3ab0042e6488aull, 0x89ca1a3763365565ull};
return cid;
}
virtual bool ClassSupports(const CryInterfaceID& iid) const
{
return iid == cryiidof<ICryUnknown>() || iid == cryiidof<IDontLikeMacros>();
}
virtual void ClassSupports(const CryInterfaceID*& pIIDs, size_t& numIIDs) const
{
static const CryInterfaceID iids[2] = {cryiidof<ICryUnknown>(), cryiidof<IDontLikeMacros>()};
pIIDs = iids;
numIIDs = 2;
}
virtual ICryUnknownPtr CreateClassInstance() const;
public:
static CDontLikeMacrosFactory& Access()
{
return s_factory;
}
private:
CDontLikeMacrosFactory() {}
~CDontLikeMacrosFactory() {}
private:
static CDontLikeMacrosFactory s_factory;
};
CDontLikeMacrosFactory CDontLikeMacrosFactory::s_factory;
class CDontLikeMacros
: public IDontLikeMacros
{
// ICryUnknown
public:
virtual ICryFactory* GetFactory() const
{
return &CDontLikeMacrosFactory::Access();
};
// only needed to be able to create initial shared_ptr<CDontLikeMacros> so we don't lose type info for debugging (i.e. inspecting shared_ptr<>)
template <class T>
friend void AZStd::Internal::sp_ms_deleter<T>::destroy();
template <class T>
friend AZStd::shared_ptr<T> AZStd::make_shared<T>();
protected:
virtual void* QueryInterface(const CryInterfaceID& iid) const
{
if (iid == cryiidof<ICryUnknown>())
{
return (void*) (ICryUnknown*) this;
}
else if (iid == cryiidof<IDontLikeMacros>())
{
return (void*) (IDontLikeMacros*) this;
}
else
{
return 0;
}
}
virtual void* QueryComposite(const char*) const
{
return 0;
}
// IDontLikeMacros
public:
virtual void CallMe()
{
printf("Yey, no macros...\n");
}
CDontLikeMacros() {}
protected:
virtual ~CDontLikeMacros() {}
};
ICryUnknownPtr CDontLikeMacrosFactory::CreateClassInstance() const
{
AZStd::shared_ptr<CDontLikeMacros> p = AZStd::make_shared<CDontLikeMacros>();
return ICryUnknownPtr(*static_cast<AZStd::shared_ptr<ICryUnknown>*>(static_cast<void*>(&p)));
}
static SRegFactoryNode g_dontLikeMacrosFactory(&CDontLikeMacrosFactory::Access());
//////////////////////////////////////////////////////////////////////////
static void TestDontLikeMacros()
{
ICryFactory* f = &CDontLikeMacrosFactory::Access();
f->ClassSupports(cryiidof<ICryUnknown>());
f->ClassSupports(cryiidof<IDontLikeMacros>());
const CryInterfaceID* pIIDs = 0;
size_t numIIDs = 0;
f->ClassSupports(pIIDs, numIIDs);
ICryUnknownPtr p = f->CreateClassInstance();
IDontLikeMacrosPtr pp = cryinterface_cast<IDontLikeMacros>(p);
ICryUnknownPtr pq = crycomposite_query(p, "blah");
pp->CallMe();
}
} // namespace TestExtension
//////////////////////////////////////////////////////////////////////////
void TestExtensions(ICryFactoryRegistryImpl* pReg)
{
printf("Test extensions:\n");
struct MyCallback
: public ICryFactoryRegistryCallback
{
virtual void OnNotifyFactoryRegistered(ICryFactory* pFactory)
{
int test = 0;
}
virtual void OnNotifyFactoryUnregistered(ICryFactory* pFactory)
{
int test = 0;
}
};
//pReg->RegisterCallback((ICryFactoryRegistryCallback*) 0x4);
//pReg->RegisterCallback((ICryFactoryRegistryCallback*) 0x1);
//pReg->RegisterCallback((ICryFactoryRegistryCallback*) 0x3);
//pReg->RegisterCallback((ICryFactoryRegistryCallback*) 0x3);
//pReg->RegisterCallback((ICryFactoryRegistryCallback*) 0x2);
//pReg->UnregisterCallback((ICryFactoryRegistryCallback*) 0x2);
//pReg->UnregisterCallback((ICryFactoryRegistryCallback*) 0x2);
//pReg->UnregisterCallback((ICryFactoryRegistryCallback*) 0x4);
//pReg->UnregisterCallback((ICryFactoryRegistryCallback*) 0x3);
//pReg->UnregisterCallback((ICryFactoryRegistryCallback*) 0x1);
//MyCallback callback0;
//pReg->RegisterCallback(&callback0);
//pReg->RegisterFactories(g_pHeadToRegFactories);
//pReg->RegisterFactories(g_pHeadToRegFactories);
//pReg->UnregisterFactories(g_pHeadToRegFactories);
ICryFactory* pF[4];
size_t numFactories = 4;
pReg->IterateFactories(cryiidof<IA>(), pF, numFactories);
pReg->IterateFactories(MAKE_CRYGUID(-1, -1), pF, numFactories);
numFactories = (size_t) -1;
pReg->IterateFactories(cryiidof<ICryUnknown>(), 0, numFactories);
MyCallback callback1;
pReg->RegisterCallback(&callback1);
pReg->UnregisterCallback(&callback1);
ICryFactory* p;
p = pReg->GetFactory(MAKE_CRYGUID(0xee61760b98a44b71, 0xa05e7372b44bd0fd));
p = pReg->GetFactory("CustomC");
p = pReg->GetFactory("ABC");
p = pReg->GetFactory((const char*)0);
p = pReg->GetFactory("DontLikeMacros");
p = pReg->GetFactory(MAKE_CRYGUID(0x73c3ab0042e6488a, 0x89ca1a3763365565));
TestExtension::TestFoobar();
TestExtension::TestRaboof();
TestExtension::TestComplex();
TestExtension::TestDontLikeMacros();
TestComposition::TestComposition();
}
#endif // #ifdef EXTENSION_SYSTEM_INCLUDE_TESTCASES
@@ -1,126 +0,0 @@
/*
* 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.
// Description : Part of CryEngine's extension framework.
#ifndef CRYINCLUDE_CRYSYSTEM_EXTENSIONSYSTEM_TESTCASES_TESTEXTENSIONS_H
#define CRYINCLUDE_CRYSYSTEM_EXTENSIONSYSTEM_TESTCASES_TESTEXTENSIONS_H
#pragma once
//#define EXTENSION_SYSTEM_INCLUDE_TESTCASES
#ifdef EXTENSION_SYSTEM_INCLUDE_TESTCASES
#include <CryExtension/ICryUnknown.h>
struct ICryFactoryRegistryImpl;
void TestExtensions(ICryFactoryRegistryImpl* pReg);
struct IFoobar
: public ICryUnknown
{
CRYINTERFACE_DECLARE(IFoobar, 0x539e9c672cad4a03, 0x9ecd8069c99a846b)
virtual void Foo() = 0;
};
DECLARE_SMART_POINTERS(IFoobar);
struct IRaboof
: public ICryUnknown
{
CRYINTERFACE_DECLARE(IRaboof, 0x135ca25e634b4d13, 0x9e4467968a708822)
virtual void Rab() = 0;
};
DECLARE_SMART_POINTERS(IRaboof);
struct IA
: public ICryUnknown
{
CRYINTERFACE_DECLARE(IA, 0xd93aaceb35ec427e, 0xb64bf8dec4997e67)
virtual void A() = 0;
};
DECLARE_SMART_POINTERS(IA);
struct IB
: public ICryUnknown
{
CRYINTERFACE_DECLARE(IB, 0xe0d830c826424e11, 0x9eacfa19eaf31ffb)
virtual void B() = 0;
};
DECLARE_SMART_POINTERS(IB);
struct IC
: public ICryUnknown
{
CRYINTERFACE_DECLARE(IC, 0x577509a20fc5477c, 0x893757c9ca88b27b)
virtual void C() = 0;
};
DECLARE_SMART_POINTERS(IC);
struct ICustomC
: public IC
{
CRYINTERFACE_DECLARE(ICustomC, 0x2ac769da4c7443bf, 0x80911033e21dfbcf)
virtual void C1() = 0;
};
DECLARE_SMART_POINTERS(ICustomC);
//////////////////////////////////////////////////////////////////////////
// use of extension system without any of the helper macros/templates
struct IDontLikeMacros
: public ICryUnknown
{
template <class T>
friend const CryInterfaceID& InterfaceCastSemantics::cryiidof();
template <class T>
friend void AZStd::Internal::sp_ms_deleter<T>::destroy();
template <class T>
friend AZStd::shared_ptr<T> AZStd::make_shared<T>();
protected:
virtual ~IDontLikeMacros() {}
private:
// It's very important that this static function is implemented for each interface!
// Otherwise the consistency of cryinterface_cast<T>() is compromised because
// cryiidof<T>() = cryiidof<baseof<T>>() {baseof<T> = ICryUnknown in most cases}
static const CryInterfaceID& IID()
{
static const CryInterfaceID iid = {0x0f43b7e3f1364af0ull, 0xb4a16a975bea3ec4ull};
return iid;
}
public:
virtual void CallMe() = 0;
};
DECLARE_SMART_POINTERS(IDontLikeMacros);
#endif // #ifdef EXTENSION_SYSTEM_INCLUDE_TESTCASES
#endif // CRYINCLUDE_CRYSYSTEM_EXTENSIONSYSTEM_TESTCASES_TESTEXTENSIONS_H
-191
View File
@@ -1,191 +0,0 @@
/*
* 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.
// Description : Remote command system implementation
#include "CrySystem_precompiled.h"
#include "IServiceNetwork.h"
#include "RemoteCommand.h"
#include "RemoteCommandHelpers.h"
//-----------------------------------------------------------------------------
// remote system internal logging
#ifdef RELEASE
#define LOG_VERBOSE(level, txt, ...)
#else
#define LOG_VERBOSE(level, txt, ...) if (GetManager()->CheckVerbose(level)) { GetManager()->Log(txt, __VA_ARGS__); }
#endif
//-----------------------------------------------------------------------------
CRemoteCommandManager::CRemoteCommandManager()
{
// Create the CVAR
m_pVerboseLevel = gEnv->pConsole->RegisterInt("rc_debugVerboseLevel", 0, VF_DEV_ONLY);
}
CRemoteCommandManager::~CRemoteCommandManager()
{
// Release the CVar
if (NULL != m_pVerboseLevel)
{
m_pVerboseLevel->Release();
m_pVerboseLevel = NULL;
}
}
IRemoteCommandServer* CRemoteCommandManager::CreateServer(uint16 localPort)
{
// Create the listener
IServiceNetworkListener* listener = gEnv->pServiceNetwork->CreateListener(localPort);
if (NULL == listener)
{
return NULL;
}
// Create the wrapper
return new CRemoteCommandServer(this, listener);
}
IRemoteCommandClient* CRemoteCommandManager::CreateClient()
{
// Create the wrapper
return new CRemoteCommandClient(this);
}
void CRemoteCommandManager::RegisterCommandClass(IRemoteCommandClass& commandClass)
{
// Make sure command class is not already registered
const string& className(commandClass.GetName());
TClassMap::const_iterator it = m_pClasses.find(className);
if (it != m_pClasses.end())
{
LOG_VERBOSE(1, "Class '%s' is already registered",
className.c_str());
return;
}
const uint32 classID = m_pClassesByID.size();
m_pClassesByID.push_back(&commandClass);
m_pClassesMap[ className ] = classID;
m_pClasses[ className ] = &commandClass;
// Verbose
LOG_VERBOSE(1, "Registered command class '%s' with id %d",
className.c_str(),
classID);
}
#ifndef RELEASE
bool CRemoteCommandManager::CheckVerbose(const uint32 level) const
{
const int verboseLevel = m_pVerboseLevel->GetIVal();
return (int)level < verboseLevel;
}
void CRemoteCommandManager::Log(const char* txt, ...) const
{
// format the print buffer
char buffer[512];
va_list ap;
va_start(ap, txt);
vsprintf_s(buffer, sizeof(buffer), txt, ap);
va_end(ap);
// pass to log
gEnv->pLog->LogAlways(buffer);
}
#endif
void CRemoteCommandManager::BuildClassMapping(const std::vector<string>& classNames, std::vector< IRemoteCommandClass* >& outClasses)
{
LOG_VERBOSE(3, "Building class mapping for %d classes",
classNames.size());
// Output list size has the same size as class names array
const uint32 numClasses = classNames.size();
outClasses.resize(numClasses);
// Match the classes
for (size_t i = 0; i < numClasses; ++i)
{
// Find the matching class
const string& className = classNames[i];
TClassMap::const_iterator it = m_pClasses.find(className);
if (it != m_pClasses.end())
{
CRY_ASSERT(className == it->second->GetName());
CRY_ASSERT(it->second != NULL);
outClasses[i] = it->second;
// Report class mapping in heavy verbose mode
LOG_VERBOSE(3, "Class[%d] = %s",
i,
className.c_str());
}
else
{
outClasses[i] = NULL;
// Class not mapped (this can cause errors)
LOG_VERBOSE(0, "Remote command class '%s' not found on this machine",
className.c_str());
}
}
}
void CRemoteCommandManager::SetVerbosityLevel(const uint32 level)
{
// propagate the value to CVar (so it is consistent across the engine)
if (NULL != m_pVerboseLevel)
{
m_pVerboseLevel->Set((int)level);
}
}
void CRemoteCommandManager::GetClassList(std::vector<string>& outClassNames) const
{
const uint32 numClasses = m_pClassesByID.size();
outClassNames.resize(numClasses);
for (size_t id = 0; id < numClasses; ++id)
{
IRemoteCommandClass* theClass = m_pClassesByID[id];
if (NULL != theClass)
{
outClassNames[id] = theClass->GetName();
}
}
}
bool CRemoteCommandManager::FindClassId(IRemoteCommandClass* commandClass, uint32& outClassId) const
{
// Local search (linear, slower)
TClassIDMap::const_iterator it = m_pClassesMap.find(commandClass->GetName());
if (it != m_pClassesMap.end())
{
outClassId = it->second;
return true;
}
// Not found
return false;
}
//-----------------------------------------------------------------------------
// Do not remove (can mess up the uber file builds)
#undef LOG_VERBOSE
//-----------------------------------------------------------------------------
-459
View File
@@ -1,459 +0,0 @@
/*
* 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.
// Description : Remote command system implementation
#pragma once
//-----------------------------------------------------------------------------
#include "IServiceNetwork.h"
#include "IRemoteCommand.h"
#include "CryThread.h"
class CRemoteCommandManager;
// Remote command client implementation
class CRemoteCommandClient
: public IRemoteCommandClient
, public CryRunnable
{
protected:
//-------------------------------------------------------------
class Command
{
public:
ILINE IServiceNetworkMessage* GetMessage() const
{
return m_pMessage;
}
ILINE uint32 GetCommandId() const
{
return m_id;
}
public:
// Create command data from serializing a remote command object
static Command* Compile(const IRemoteCommand& cmd, const uint32 commandId, const uint32 classId);
void AddRef();
void Release();
private:
Command();
~Command();
volatile int m_refCount;
uint32 m_id;
const char* m_szClassName; // debug only
IServiceNetworkMessage* m_pMessage;
};
//-------------------------------------------------------------
// Local connection reference to command
// NOTE: pCommand is reference counted from the calling code
struct CommandRef
{
Command* m_pCommand;
uint64 m_lastSentTime;
ILINE CommandRef()
: m_pCommand(NULL)
, m_lastSentTime(0)
{}
ILINE CommandRef(Command* pCommand)
: m_pCommand(pCommand)
, m_lastSentTime(0)
{}
// Order function for set container (we want to keep the commands sorted by ID)
static ILINE bool CompareCommandRefs(CommandRef* const& a, CommandRef* const& b)
{
return a->m_pCommand->GetCommandId() < b->m_pCommand->GetCommandId();
}
};
//-------------------------------------------------------------
// Remote server connection wrapper
class Connection
: public IRemoteCommandConnection
{
// How many commands we can send upfront before waiting for an ACK
static const uint32 kCommandSendLead = 50;
// How much command data can be merged into a single packet (KB)
static const uint32 kCommandMaxMergePacketSize = 1024;
// Time after which we start resending commands (ms)
static const uint32 kCommandResendTime = 2000;
protected:
CRemoteCommandManager* m_pManager;
volatile int m_refCount;
// Connection (from service network layer)
IServiceNetworkConnection* m_pConnection;
// Cached address of the remote endpoint
ServiceNetworkAddress m_remoteAddress;
// Pending commands, they are kept ed here until they are ACKed as executed by server
typedef std::vector<CommandRef*> TCommands;
TCommands m_pCommands;
CryMutex m_commandAccessMutex;
// A queue of raw messages
typedef CryMT::CLocklessPointerQueue<IServiceNetworkMessage> TRawMessageQueue;
TRawMessageQueue m_pRawMessages;
CryMutex m_rawMessagesMutex;
// Last command that was ACKed as received by server
// This is used to synchronize the both ends of the pipeline
uint32 m_lastReceivedCommand;
// Last command that was ACKed as executed by server
// This is used to synchronize the both ends of the pipeline
uint32 m_lastExecutedCommand;
public:
ILINE CRemoteCommandManager* GetManager() const
{
return m_pManager;
}
public:
Connection(CRemoteCommandManager* pManager, IServiceNetworkConnection* pConnection, uint32 currentCommandId);
// Add command to sending queue in this connection
void AddToSendQueue(Command* pCommand);
// Process the communication, returns false if connection should be deleted
bool Update();
// Send the "disconnect" message to the remote side therefore gracefully closing the connection.
void SendDisconnectMessage();
public:
// IRemoteCommandConnection interface implementation
virtual bool IsAlive() const;
virtual const ServiceNetworkAddress& GetRemoteAddress() const;
virtual bool SendRawMessage(IServiceNetworkMessage* pMessage);
virtual IServiceNetworkMessage* ReceiveRawMessage();
virtual void Close(bool bFlushQueueBeforeClosing = false);
virtual void AddRef();
virtual void Release();
private:
~Connection();
};
protected:
CRemoteCommandManager* m_pManager;
typedef std::vector<Connection*> TConnections;
TConnections m_pConnections;
TConnections m_pConnectionsToDelete;
CryMutex m_accessMutex;
// Local command ID counter, incremented atomically using CryInterlockedIncrement
volatile uint32 m_commandId;
typedef CryThread<CRemoteCommandClient> TRemoteClientThread;
TRemoteClientThread* m_pThread;
CryEvent m_threadEvent;
bool m_bCloseThread;
public:
ILINE CRemoteCommandManager* GetManager() const
{
return m_pManager;
}
public:
CRemoteCommandClient(CRemoteCommandManager* pManager);
virtual ~CRemoteCommandClient();
// IRemoteCommandClient interface
virtual void Delete();
virtual bool Schedule(const IRemoteCommand& command);
virtual IRemoteCommandConnection* ConnectToServer(const class ServiceNetworkAddress& serverAddress);
// CryRunnable interface implementation
virtual void Run();
virtual void Cancel();
};
//-----------------------------------------------------------------------------
// Remote command server implementation
class CRemoteCommandServer
: public IRemoteCommandServer
, public CryRunnable
{
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(RemoteCommand_h)
#endif
protected:
// Wrapped commands
class WrappedCommand
{
private:
IRemoteCommand* m_pCommand;
volatile int m_refCount;
uint32 m_commandID;
public:
ILINE const uint32 GetId() const
{
return m_commandID;
}
ILINE IRemoteCommand* GetCommand() const
{
return m_pCommand;
}
public:
WrappedCommand(IRemoteCommand* pCommand, const uint32 commandId);
void AddRef();
void Release();
private:
~WrappedCommand();
};
// Local endpoint
class Endpoint
{
private:
IServiceNetworkConnection* m_pConnection;
class CRemoteCommandServer* m_pServer;
CRemoteCommandManager* m_pManager;
// ACK counters for synchronization
uint32 m_lastReceivedCommand;
uint32 m_lastExecutedCommand;
uint32 m_lastReceivedCommandACKed;
uint32 m_lastExecutedCommandACKed;
CryMutex m_accessLock;
// We have received class list (it's a valid RC connection)
bool m_bHasReceivedClassList;
// Locally mapped class id (because IDs on remote side can be different than here)
typedef std::vector< IRemoteCommandClass* > TLocalClassFactoryList;
TLocalClassFactoryList m_pLocalClassFactories;
// Commands that were received and should be executed
typedef CryMT::CLocklessPointerQueue< WrappedCommand > TCommandQueue;
TCommandQueue m_pCommandsToExecute;
CryMutex m_commandListLock;
public:
ILINE CRemoteCommandManager* GetManager() const
{
return m_pManager;
}
// Get the endpoint connection
ILINE IServiceNetworkConnection* GetConnection() const
{
return m_pConnection;
}
// Have we received a class list from the client
ILINE bool HasReceivedClassList() const
{
return m_bHasReceivedClassList;
}
public:
Endpoint(CRemoteCommandManager* pManager, class CRemoteCommandServer* pServer, IServiceNetworkConnection* pConnection);
~Endpoint();
// Execute pending commands (called from main thread)
void Execute();
// Update (send/receive, etc) Returns false if endpoint died.
bool Update();
// Get the class name as translated by this endpoint (by ID)
const char* GetClassName(const uint32 classId) const;
// Create command object by class ID
IRemoteCommand* CreateObject(const uint32 classId) const;
};
// Received raw message
// Beware to use always via pointer to this type since propper reference counting is not implemented for copy and assigment
struct RawMessage
{
// We keep a reference to connection so we know where to send the response
IServiceNetworkConnection* m_pConnection;
IServiceNetworkMessage* m_pMessage;
ILINE RawMessage(IServiceNetworkConnection* pConnection, IServiceNetworkMessage* pMessage)
: m_pConnection(pConnection)
, m_pMessage(pMessage)
{
m_pMessage->AddRef();
m_pConnection->AddRef();
}
ILINE ~RawMessage()
{
m_pMessage->Release();
m_pConnection->Release();
}
private:
ILINE RawMessage([[maybe_unused]] const RawMessage& other) {};
ILINE RawMessage& operator==([[maybe_unused]] const RawMessage& other) { return *this; }
};
protected:
CRemoteCommandManager* m_pManager;
// Network listening socket
IServiceNetworkListener* m_pListener;
// Live endpoints
typedef std::vector<Endpoint*> TEndpoints;
TEndpoints m_pEndpoints;
TEndpoints m_pUpdateEndpoints;
CryMutex m_accessLock;
// Endpoints that were discarded and should be deleted
// We can delete endpoints only from the update thread
TEndpoints m_pEndpointToDelete;
// Received raw messages
typedef CryMT::CLocklessPointerQueue<RawMessage> TRawMessagesQueue;
TRawMessagesQueue m_pRawMessages;
CryMutex m_rawMessagesLock;
// Listeners for raw messages that require synchronous processing
typedef std::vector<IRemoteCommandListenerSync*> TRawMessageListenersSync;
TRawMessageListenersSync m_pRawListenersSync;
// Listeners for raw messages that can be processed asynchronously (faster path)
typedef std::vector<IRemoteCommandListenerAsync*> TRawMessageListenersAsync;
TRawMessageListenersAsync m_pRawListenersAsync;
// Command communication and deserialization is done on thread
typedef CryThread<CRemoteCommandServer> TRemoteServerThread;
TRemoteServerThread* m_pThread;
// Suppression counter (execution of commands is suppressed when>0)
// This is updated using CryInterlocked* functions
volatile int m_suppressionCounter;
bool m_bIsSuppressed;
// Request to close the network thread
bool m_bCloseThread;
public:
ILINE CRemoteCommandManager* GetManager() const
{
return m_pManager;
}
public:
CRemoteCommandServer(CRemoteCommandManager* pManager, IServiceNetworkListener* pListener);
virtual ~CRemoteCommandServer();
// IRemoteCommandServer interface implementation
virtual void Delete();
virtual void FlushCommandQueue();
virtual void SuppressCommands();
virtual void ResumeCommands();
virtual void RegisterSyncMessageListener(IRemoteCommandListenerSync* pListener);
virtual void UnregisterSyncMessageListener(IRemoteCommandListenerSync* pListener);
virtual void RegisterAsyncMessageListener(IRemoteCommandListenerAsync* pListener);
virtual void UnregisterAsyncMessageListener(IRemoteCommandListenerAsync* pListener);
virtual void Broadcast(IServiceNetworkMessage* pMessage);
virtual bool HasConnectedClients() const;
// CryRunnable
virtual void Run();
virtual void Cancel();
protected:
void ProcessRawMessageAsync(IServiceNetworkMessage* pMessage, IServiceNetworkConnection* pConnection);
void ProcessRawMessagesSync();
};
//-----------------------------------------------------------------------------
// Remote command manager implementation
class CRemoteCommandManager
: public IRemoteCommandManager
{
public:
CRemoteCommandManager();
virtual ~CRemoteCommandManager();
// IRemoteCommandManager interface implementation
virtual void SetVerbosityLevel(const uint32 level);
virtual IRemoteCommandServer* CreateServer(uint16 localPort);
virtual IRemoteCommandClient* CreateClient();
virtual void RegisterCommandClass(IRemoteCommandClass& commandClass);
// Debug print
#ifdef RELEASE
void Log([[maybe_unused]] const char* txt, ...) const {};
bool CheckVerbose([[maybe_unused]] const uint32 level) const { return false; }
#else
void Log(const char* txt, ...) const;
bool CheckVerbose(const uint32 level) const;
#endif
// Build ID->Class Factory mapping given the class name list, will report errors to the log.
void BuildClassMapping(const std::vector<string>& classNames, std::vector< IRemoteCommandClass* >& outClasses);
// Get list of class names (in order of their IDs)
void GetClassList(std::vector<string>& outClassNames) const;
// Find class ID for given class, returns false if not found
bool FindClassId(IRemoteCommandClass* commandClass, uint32& outClassId) const;
public:
ILINE CRemoteCommandManager* GetManager()
{
return this;
}
private:
// Class name mapping
typedef std::map< string, IRemoteCommandClass* > TClassMap;
TClassMap m_pClasses;
// Class ID lookup
typedef std::vector< IRemoteCommandClass* > TClassIDList;
TClassIDList m_pClassesByID;
// Class ID mapping
typedef std::map< string, int > TClassIDMap;
TClassIDMap m_pClassesMap;
// Verbose level
ICVar* m_pVerboseLevel;
};
@@ -1,756 +0,0 @@
/*
* 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.
// Description : Remote command system implementation
#include "CrySystem_precompiled.h"
#include "IServiceNetwork.h"
#include "RemoteCommand.h"
#include "RemoteCommandHelpers.h"
//-----------------------------------------------------------------------------
// remote system internal logging
#ifdef RELEASE
#define LOG_VERBOSE(level, txt, ...)
#else
#define LOG_VERBOSE(level, txt, ...) if (GetManager()->CheckVerbose(level)) { GetManager()->Log(txt, __VA_ARGS__); }
#endif
//-----------------------------------------------------------------------------
CRemoteCommandClient::Command::Command()
: m_refCount(1)
, m_szClassName(NULL)
, m_id(0)
{
}
CRemoteCommandClient::Command::~Command()
{
// Release message buffer with compiled command data
if (m_pMessage != NULL)
{
m_pMessage->Release();
m_pMessage = NULL;
}
}
CRemoteCommandClient::Command* CRemoteCommandClient::Command::Compile(const IRemoteCommand& cmd, const uint32 commandId, const uint32 classId)
{
// Build command header
CommandHeader header;
header.classId = classId;
header.commandId = commandId;
header.size = 0; // not known yet
// Output stream builder
CDataWriteStreamBuffer writer;
// Start the packet with a command header (it will be later overwritten)
writer << header;
// Serialize command header and data
const uint32 commandDataStart = writer.GetSize();
cmd.SaveToStream(writer);
const uint32 commandDataEnd = writer.GetSize();
// Extract a message from the stream
IServiceNetworkMessage* pMessage = writer.BuildMessage();
if (NULL == pMessage)
{
// No message was generated (for some reason)
// Do not allow this command to compile
return NULL;
}
// Rewrite header with the proper command size
// This is a little bit over-the-top because it uses another serializer created
// on top of the message buffer. The advantage is that we have the endianess problem abstracted away.
// TODO: consider writing the size directly
{
// update header with popper data size
const uint32 dataSize = commandDataEnd - commandDataStart;
header.size = dataSize;
// rewrite the header in existing message
CDataWriteStreamToMessage inPlaceWriter(pMessage);
inPlaceWriter << header;
}
// Create command wrapper
Command* pCommand = new Command();
pCommand->m_id = commandId;
pCommand->m_szClassName = cmd.GetClass()->GetName();
pCommand->m_pMessage = pMessage;
return pCommand;
}
void CRemoteCommandClient::Command::AddRef()
{
CryInterlockedIncrement(&m_refCount);
}
void CRemoteCommandClient::Command::Release()
{
if (0 == CryInterlockedDecrement(&m_refCount))
{
delete this;
}
}
//-----------------------------------------------------------------------------
CRemoteCommandClient::Connection::Connection(CRemoteCommandManager* pManager, IServiceNetworkConnection* pConnection, uint32 currentCommandId)
: m_pConnection(pConnection)
, m_pManager(pManager)
, m_lastReceivedCommand(currentCommandId)
, m_lastExecutedCommand(currentCommandId)
, m_remoteAddress(pConnection->GetRemoteAddress())
, m_refCount(1)
{
// The first thing to do after the connection is initialized is to
// send the message with list of classes supported by this side.
{
// Write the header
PackedHeader header;
header.magic = PackedHeader::kMagic;
header.msgType = PackedHeader::eCommand_ClassList;
header.count = currentCommandId; // send the intial command ID so we can be in sync
// Get the class list for our local remote command manager
std::vector< string > classList;
GetManager()->GetClassList(classList);
// Write the message
CDataWriteStreamBuffer writer;
writer << header;
writer << classList;
// Send the message to the remote side
IServiceNetworkMessage* pMsg = writer.BuildMessage();
if (NULL != pMsg)
{
LOG_VERBOSE(1, "Sent class list message (%d classes, size=%d) to '%s'",
classList.size(),
pMsg->GetSize(),
m_pConnection->GetRemoteAddress().ToString().c_str());
// TODO: well, there is no reason this can fail since the connection is brand new, but...
// We still relay on the service network to deliver this message unharmed.
m_pConnection->SendMsg(pMsg);
// cleanup
pMsg->Release();
}
}
}
CRemoteCommandClient::Connection::~Connection()
{
// Close the connection
const bool bFlushBeforeClosing = false;
Close(bFlushBeforeClosing);
// Release any commands left over on the list
for (TCommands::const_iterator it = m_pCommands.begin();
it != m_pCommands.end(); ++it)
{
(*it)->m_pCommand->Release();
delete (*it);
}
m_pCommands.clear();
// Release all of the raw messages that were not picked up
while (!m_pRawMessages.empty())
{
IServiceNetworkMessage* pMessage = m_pRawMessages.pop();
pMessage->Release();
}
// Release the connection object
SAFE_RELEASE(m_pConnection);
}
void CRemoteCommandClient::Connection::SendDisconnectMessage()
{
if (NULL != m_pConnection && m_pConnection->IsAlive())
{
IDataWriteStream* pWriter = gEnv->pServiceNetwork->CreateMessageWriter();
if (NULL != pWriter)
{
// write header to message
PackedHeader header;
header.magic = PackedHeader::kMagic;
header.count = 0;
header.msgType = PackedHeader::eCommand_Disconnect;
*pWriter << header;
// Send the disconnect signal
IServiceNetworkMessage* pMessage = pWriter->BuildMessage();
if (NULL != pMessage)
{
m_pConnection->SendMsg(pMessage);
pMessage->Release();
}
pWriter->Delete();
}
}
}
void CRemoteCommandClient::Connection::AddToSendQueue(Command* pCommand)
{
// Do not add commands if the connection is closed
if (m_pConnection == NULL)
{
return;
}
// Add command to local list
// NOTE: this list always needs to be sorted in increasing command ID for various optimization reason.
// This is achieved by resorting after pushing each element. Usually the cost of this is close to nothing
// because incoming commands tend to be added with increasing command IDs.
// The only case when something else can happen is when commands are added from different threads
// and the one that was lower CommandID took longer to serialize and therefore is added later.
// Anyway, this case is handled here.
{
CryAutoLock<CryMutex> lock(m_commandAccessMutex);
// Always add to the end (don't try to guess position)
// TODO: consider binary search
m_pCommands.push_back(new CommandRef(pCommand));
// Resort, NODE: This usually does not sort anything because the vector is already sorted
std::sort(m_pCommands.begin(), m_pCommands.end(), CommandRef::CompareCommandRefs);
}
// Keep local reference to command (since we added it to our array)
pCommand->AddRef();
}
bool CRemoteCommandClient::Connection::Update()
{
// If the network connection got dead we should close this one to
if ((NULL == m_pConnection) || !m_pConnection->IsAlive())
{
return false;
}
// Receive ACKs first so we have better view of what to send
uint32 newLastExecutedCommand = m_lastExecutedCommand;
uint32 newLastReceivedCommand = m_lastReceivedCommand;
IServiceNetworkMessage* pMsg = m_pConnection->ReceiveMsg();
while (pMsg != NULL)
{
// Deserialize the message
{
CDataReadStreamFormMessage reader(pMsg);
ResponseHeader response;
reader << response;
// is this proper command system message ?
if (response.magic == PackedHeader::kMagic)
{
if (response.msgType == PackedHeader::eCommand_ACK)
{
// Update internal ACK values
// This code supports getting the ACK messages out of order.
newLastExecutedCommand = max<uint32>(newLastExecutedCommand, response.lastCommandExecuted);
newLastReceivedCommand = max<uint32>(newLastReceivedCommand, response.lastCommandReceived);
LOG_VERBOSE(3, "ACK (rcv=%d, exe=%d) received from '%s'",
response.lastCommandReceived,
response.lastCommandExecuted,
m_pConnection->GetRemoteAddress().ToString().c_str());
}
else if (response.msgType == PackedHeader::eCommand_Disconnect)
{
// Disconnect request was received
LOG_VERBOSE(3, "DISCONNECT (rcv=%d, exe=%d) received from '%s'",
response.lastCommandReceived,
response.lastCommandExecuted,
m_pConnection->GetRemoteAddress().ToString().c_str());
// Close connection
m_pConnection->Close();
m_pConnection->Release();
m_pConnection = NULL;
// release the message
pMsg->Release();
// Signal manager to delete this object
return false;
}
}
else
{
// Keep an extra reference for the message in the raw message list
pMsg->AddRef();
// Assume it's a raw message, add it to the raw list
m_pRawMessages.push(pMsg);
}
}
// Release message data
pMsg->Release();
// Get next message from the network
pMsg = m_pConnection->ReceiveMsg();
}
// ACK was updated
if ((newLastExecutedCommand != m_lastExecutedCommand) ||
(newLastReceivedCommand != m_lastReceivedCommand))
{
m_lastExecutedCommand = newLastExecutedCommand;
m_lastReceivedCommand = newLastReceivedCommand;
// Drop commands that were ACKed as received (server has them and they will be executed soon)
{
CryAutoLock<CryMutex> lock(m_commandAccessMutex);
// we use this to count how many elements we need to remove later from the command vector
uint32 numCommandsToDelete = 0;
for (TCommands::const_iterator it = m_pCommands.begin();
it != m_pCommands.end(); ++it)
{
CommandRef* cmdRef = *it;
// Command is still needed because it was not yet received by the remote part
if (cmdRef->m_pCommand->GetCommandId() > newLastReceivedCommand)
{
break;
}
// Drop the command data
cmdRef->m_pCommand->Release();
delete cmdRef;
++numCommandsToDelete;
}
// Erase the command slots in the vector (in one batch)
if (numCommandsToDelete > 0)
{
m_pCommands.erase(m_pCommands.begin(), m_pCommands.begin() + numCommandsToDelete);
}
}
}
// (Re)Send the commands
{
// Calculate the maximum command ID we can send, this depends on
// the last command that was ACKed as executed on the remote side.
// This effectively throttles the communication and prevents the
// situation when remote side is flooded with unprocessed commands.
// NOTE: the time when command is executed is different to the
// time that command is received. Sometimes if the server is suppressed (level loading)
// it can take a long time before commands begin to execute.
const uint32 maxCommandIdToSend = m_lastExecutedCommand + kCommandSendLead;
// Calculate the cutoff time for sending (all commands that were not send before this time will be sent again)
// This assumes that the last sent time for new commands is 0 (so they will always got sent the first time)
// This situation can only happen due to the network failure since RemoteCommand layer does not require the commands to be resent.
const uint64 currentTime = gEnv->pTimer->GetAsyncTime().GetMilliSecondsAsInt64();
const uint64 cutoffTime = currentTime - kCommandResendTime;
std::vector< CommandRef* > commandsInPacket; // temp array
// Process until we send all that there is to send
for (;; )
{
// When sending connections try to merge them in larger packets.
// NOTE: this should not impact delivery time since we are not waiting
// for pending commands to accumulate before sending them, it's just an optimization
// to prevent may small messages from being sent.
uint32 packetDataSizeSoFar = 0;
{
CryAutoLock<CryMutex> lock(m_commandAccessMutex);
// fast local clear
// TODO: do we have a good template alternative to temporary array on stack?
packetDataSizeSoFar = 0;
commandsInPacket.resize(0);
for (TCommands::iterator it = m_pCommands.begin();
it != m_pCommands.end(); ++it)
{
CommandRef* commandRef = *it;
// this command is to new, don't send it
if (commandRef->m_pCommand->GetCommandId() >= maxCommandIdToSend)
{
break;
}
// should we send this command ?
if (commandRef->m_lastSentTime < cutoffTime)
{
// will it fit into current packet ?
const uint32 commandDataSize = commandRef->m_pCommand->GetMessage()->GetSize();
if (packetDataSizeSoFar == 0 || // always add at least one command to the packet (no splitting)
(packetDataSizeSoFar + commandDataSize < kCommandMaxMergePacketSize))
{
if (commandRef->m_lastSentTime == 0)
{
LOG_VERBOSE(3, "Command ID=%d is sent FIRST TIME to '%s'",
commandRef->m_pCommand->GetCommandId(),
m_pConnection->GetRemoteAddress().ToString().c_str());
}
else
{
LOG_VERBOSE(3, "Command ID=%d is resent to '%s'",
commandRef->m_pCommand->GetCommandId(),
m_pConnection->GetRemoteAddress().ToString().c_str());
}
// will be sent
commandsInPacket.push_back(commandRef);
packetDataSizeSoFar += commandDataSize;
}
else
{
LOG_VERBOSE(3, "Command ID=%d is to big (%d) to fit packet size limit (%d)",
commandRef->m_pCommand->GetCommandId(),
commandDataSize,
kCommandMaxMergePacketSize);
// no more commands will fit current packet
break;
}
}
}
}
// No new commands to be send
if (commandsInPacket.empty())
{
break;
}
// Stats
LOG_VERBOSE(3, "Sending %d commands in packet, total size=%d, maxID=%d, dest: %s",
commandsInPacket.size(),
packetDataSizeSoFar,
maxCommandIdToSend,
m_pConnection->GetRemoteAddress().ToString().c_str());
// Estimate the size of the network packet
const uint32 messageDataSize = packetDataSizeSoFar + PackedHeader::kSerializationSize;
// Allocate and fill the message buffer
IServiceNetworkMessage* pSendMsg = gEnv->pServiceNetwork->AllocMessageBuffer(messageDataSize);
if (NULL != pSendMsg)
{
CDataWriteStreamToMessage writer(pSendMsg);
// Packet header
PackedHeader header;
header.magic = PackedHeader::kMagic;
header.msgType = PackedHeader::eCommand_Command;
header.count = commandsInPacket.size(); // number commands to send in this packet
writer << header;
// Merge data of single commands
for (size_t i = 0; i < commandsInPacket.size(); ++i)
{
const IServiceNetworkMessage* pCommandMsg = commandsInPacket[i]->m_pCommand->GetMessage();
writer.Write(pCommandMsg->GetPointer(), pCommandMsg->GetSize());
}
// Schedule the packet for sending via our network connection
if (m_pConnection->SendMsg(pSendMsg))
{
// Only after the network layer has accepted our message we can assume that the commands were sent
for (size_t i = 0; i < commandsInPacket.size(); ++i)
{
CommandRef* cmdRef = commandsInPacket[i];
cmdRef->m_lastSentTime = currentTime;
}
// Release temporary message memory
pSendMsg->Release();
}
else
{
// We failed to send the message (possibly the send queue is full)
pSendMsg->Release();
break;
}
}
else
{
// No message was created, stop sending
break;
}
}
}
// Keep the connection alive
return true;
}
bool CRemoteCommandClient::Connection::IsAlive() const
{
return (NULL != m_pConnection) && (m_pConnection->IsAlive());
}
const ServiceNetworkAddress& CRemoteCommandClient::Connection::GetRemoteAddress() const
{
return m_remoteAddress;
}
void CRemoteCommandClient::Connection::Close(bool bFlushQueueBeforeClosing /*= false*/)
{
// Close the connection
if (NULL != m_pConnection)
{
if (m_pConnection->IsAlive() && bFlushQueueBeforeClosing)
{
// We have a chance to send a graceful disconnect message, so send it
SendDisconnectMessage();
// Send all the messages from the send queue before closing this connection.
// This does not block current thread.
m_pConnection->FlushAndClose(IServiceNetworkConnection::kDefaultFlushTime);
}
else
{
// Just close the connection (hasher way)
m_pConnection->Close();
}
}
}
bool CRemoteCommandClient::Connection::SendRawMessage(IServiceNetworkMessage* pMessage)
{
// We can send the raw messages right away
if (NULL != m_pConnection && m_pConnection->IsAlive())
{
return m_pConnection->SendMsg(pMessage);
}
else
{
return false;
}
}
IServiceNetworkMessage* CRemoteCommandClient::Connection::ReceiveRawMessage()
{
return m_pRawMessages.pop();
}
void CRemoteCommandClient::Connection::AddRef()
{
CryInterlockedIncrement(&m_refCount);
}
void CRemoteCommandClient::Connection::Release()
{
if (0 == CryInterlockedDecrement(&m_refCount))
{
delete this;
}
}
//-----------------------------------------------------------------------------
CRemoteCommandClient::CRemoteCommandClient(CRemoteCommandManager* pManager)
: m_pManager(pManager)
, m_commandId(0)
, m_bCloseThread(false)
{
// Start processing thread (sending, etc)
m_pThread = new TRemoteClientThread();
m_pThread->Start(*this);
}
CRemoteCommandClient::~CRemoteCommandClient()
{
// Stop the thread
if (NULL != m_pThread)
{
m_pThread->Cancel();
m_pThread->Stop();
m_pThread->WaitForThread();
delete m_pThread;
}
// Delete connections
for (size_t i = 0; i < m_pConnections.size(); ++i)
{
m_pConnections[i]->Release();
}
m_pConnections.clear();
}
void CRemoteCommandClient::Delete()
{
delete this;
}
IRemoteCommandConnection* CRemoteCommandClient::ConnectToServer(const class ServiceNetworkAddress& serverAddress)
{
CryAutoLock< CryMutex > lock(m_accessMutex);
// Do not connect twice to the same server
for (TConnections::const_iterator it = m_pConnections.begin();
it != m_pConnections.end(); ++it)
{
if (ServiceNetworkAddress::CompareBaseAddress((*it)->GetRemoteAddress(), serverAddress))
{
LOG_VERBOSE(0, "Failed to connect to server '%s': already connected",
serverAddress.ToString().c_str());
return NULL;
}
}
// Open a network connection
IServiceNetworkConnection* pNetConnection = gEnv->pServiceNetwork->Connect(serverAddress);
if (NULL == pNetConnection)
{
LOG_VERBOSE(0, "Failed to connect to server '%s': server is not responding",
serverAddress.ToString().c_str());
return NULL;
}
// Get current command ID (only commands after this one will be sent)
const uint32 firstCommandId = m_commandId;
// Create a wrapping class and add it to the connection list
Connection* pConnection = new Connection(GetManager(), pNetConnection, firstCommandId);
m_pConnections.push_back(pConnection);
// Keep internal reference
pConnection->AddRef();
LOG_VERBOSE(0, "Connected to remote command server '%s', first command ID=%d",
serverAddress.ToString().c_str(),
firstCommandId);
return pConnection;
}
bool CRemoteCommandClient::Schedule(const IRemoteCommand& command)
{
// No connections
if (m_pConnections.empty())
{
return false;
}
// Find ClassID for command
uint32 classId = 0;
if (!GetManager()->FindClassId(command.GetClass(), classId))
{
LOG_VERBOSE(0, "Class '%s' not recognized. Did you call RegisterClass() ?",
command.GetClass()->GetName());
return false;
}
// Alloc new command ID and compile command data
// TODO: consider moving the compilation to thread (this may be unsafe).
const uint32 commandId = CryInterlockedIncrement((volatile int*) &m_commandId);
Command* pCommand = Command::Compile(command, commandId, classId);
// Register new command in all of the existing server connections
if (NULL != pCommand)
{
CryAutoLock<CryMutex> lock(m_accessMutex);
for (TConnections::const_iterator it = m_pConnections.begin();
it != m_pConnections.end(); ++it)
{
(*it)->AddToSendQueue(pCommand);
}
// We are done with our reference
pCommand->Release();
}
// Signal the thread to process data
m_threadEvent.Set();
return true;
}
void CRemoteCommandClient::Run()
{
TConnections pUpdateList;
CryThreadSetName(-1, "RemoteCommandThread");
while (!m_bCloseThread)
{
// copy to local list for updating
{
CryAutoLock<CryMutex> lock(m_accessMutex);
pUpdateList = m_pConnections;
}
// update current connection list
for (TConnections::const_iterator it = pUpdateList.begin();
it != pUpdateList.end(); ++it)
{
if (!(*it)->Update())
{
CryAutoLock<CryMutex> lock(m_accessMutex);
m_pConnectionsToDelete.push_back(*it);
}
}
// delete pending connections
{
CryAutoLock<CryMutex> lock(m_accessMutex);
for (TConnections::iterator it = m_pConnectionsToDelete.begin();
it != m_pConnectionsToDelete.end(); ++it)
{
// delete the object
(*it)->Release();
(*it)->Close(true);
// remove from connection list
TConnections::iterator jt = std::find(m_pConnections.begin(), m_pConnections.end(), *it);
if (jt != m_pConnections.end())
{
m_pConnections.erase(jt);
}
}
// reset the array
m_pConnectionsToDelete.clear();
}
// Limit the CPU usage
const uint32 maxWaitTime = 100;
m_threadEvent.Wait(maxWaitTime);
}
}
void CRemoteCommandClient::Cancel()
{
m_bCloseThread = true;
}
//-----------------------------------------------------------------------------
// Do not remove (can mess up the uber file builds)
#undef LOG_VERBOSE
//-----------------------------------------------------------------------------
@@ -1,361 +0,0 @@
/*
* 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.
// Description : Helper classes for remote command system
#include "CrySystem_precompiled.h"
#include "IServiceNetwork.h"
#include "RemoteCommandHelpers.h"
//-----------------------------------------------------------------------------
CDataReadStreamFormMessage::CDataReadStreamFormMessage(const IServiceNetworkMessage* message)
: m_pMessage(message)
, m_size(message->GetSize())
, m_pData(static_cast<const char*>(message->GetPointer()))
, m_offset(0)
{
// AddRef() is not const unfortunatelly
const_cast<IServiceNetworkMessage*>(m_pMessage)->AddRef();
}
CDataReadStreamFormMessage::~CDataReadStreamFormMessage()
{
// Release() is not const unfortunatelly
const_cast<IServiceNetworkMessage*>(m_pMessage)->Release();
}
void CDataReadStreamFormMessage::Delete()
{
delete this;
}
void CDataReadStreamFormMessage::Skip(const uint32 size)
{
CRY_ASSERT(m_offset + size < m_size);
m_offset += size;
}
void CDataReadStreamFormMessage::Read(void* pData, const uint32 size)
{
CRY_ASSERT(m_offset + size < m_size);
const char* pReadPtr = m_pData + m_offset;
memcpy(pData, pReadPtr, size);
m_offset += size;
}
void CDataReadStreamFormMessage::Read8(void* pData)
{
// it does not actually matter if its uint64, int64 or double so use any
ReadType<uint64>(pData);
}
void CDataReadStreamFormMessage::Read4(void* pData)
{
// it does not actually matter if its uint32, int32 or float so use any
ReadType<uint32>(pData);
}
void CDataReadStreamFormMessage::Read2(void* pData)
{
// it does not actually matter if its uint16, int16 so use any
ReadType<uint16>(pData);
}
void CDataReadStreamFormMessage::Read1(void* pData)
{
// it does not actually matter if its uint8, int8 so use any
ReadType<uint8>(pData);
}
const void* CDataReadStreamFormMessage::GetPointer()
{
const char* pReadPtr = m_pData + m_offset;
return pReadPtr;
}
//-----------------------------------------------------------------------------
CDataWriteStreamToMessage::CDataWriteStreamToMessage(IServiceNetworkMessage* pMessage)
: m_pMessage(pMessage)
, m_size(pMessage->GetSize())
, m_pData(static_cast<char*>(pMessage->GetPointer()))
, m_offset(0)
{
m_pMessage->AddRef();
}
CDataWriteStreamToMessage::~CDataWriteStreamToMessage()
{
m_pMessage->Release();
}
void CDataWriteStreamToMessage::Delete()
{
delete this;
}
const uint32 CDataWriteStreamToMessage::GetSize() const
{
return m_size;
}
void CDataWriteStreamToMessage::CopyToBuffer(void* pData) const
{
memcpy(pData, m_pData, m_size);
}
IServiceNetworkMessage* CDataWriteStreamToMessage::BuildMessage() const
{
m_pMessage->AddRef();
return m_pMessage;
}
void CDataWriteStreamToMessage::Write(const void* pData, const uint32 size)
{
CRY_ASSERT(m_offset + size < m_size);
memcpy((char*)m_pData + m_offset, pData, size);
m_offset += size;
}
void CDataWriteStreamToMessage::Write8(const void* pData)
{
// it does not actually matter if its uint64, int64 or double so use any
WriteType<uint64>(pData);
}
void CDataWriteStreamToMessage::Write4(const void* pData)
{
// it does not actually matter if its uint32, int32 or float so use any
WriteType<uint32>(pData);
}
void CDataWriteStreamToMessage::Write2(const void* pData)
{
// it does not actually matter if its uint16, int16 so use any
WriteType<uint16>(pData);
}
void CDataWriteStreamToMessage::Write1(const void* pData)
{
// it does not actually matter if its uint8, int8 so use any
WriteType<uint8>(pData);
}
//-----------------------------------------------------------------------------
CDataReadStreamMemoryBuffer::CDataReadStreamMemoryBuffer(const void* pData, const uint32 size)
: m_size(size)
, m_offset(0)
{
m_pData = new uint8 [size];
memcpy(m_pData, pData, size);
}
CDataReadStreamMemoryBuffer::~CDataReadStreamMemoryBuffer()
{
delete [] m_pData;
m_pData = NULL;
}
void CDataReadStreamMemoryBuffer::Delete()
{
delete this;
}
void CDataReadStreamMemoryBuffer::Skip(const uint32 size)
{
CRY_ASSERT(m_offset + size <= m_size);
m_offset += size;
}
void CDataReadStreamMemoryBuffer::Read8(void* pData)
{
Read(pData, 8);
SwapEndian(*reinterpret_cast<uint64*>(pData));
}
void CDataReadStreamMemoryBuffer::Read4(void* pData)
{
Read(pData, 4);
SwapEndian(*reinterpret_cast<uint32*>(pData));
}
void CDataReadStreamMemoryBuffer::Read2(void* pData)
{
Read(pData, 2);
SwapEndian(*reinterpret_cast<uint16*>(pData));
}
void CDataReadStreamMemoryBuffer::Read1(void* pData)
{
return Read(pData, 1);
}
const void* CDataReadStreamMemoryBuffer::GetPointer()
{
return m_pData + m_offset;
};
void CDataReadStreamMemoryBuffer::Read(void* pData, const uint32 size)
{
CRY_ASSERT(m_offset + size <= m_size);
memcpy(pData, m_pData + m_offset, size);
m_offset += size;
}
//-----------------------------------------------------------------------------
CDataWriteStreamBuffer::CDataWriteStreamBuffer()
: m_size(0)
{
// Start with the initial (preallocated) partition
// This optimization assumes that initial size of most of the messages will be small.
// NOTE: default partition is not added to the partition table (that would require push_backs to vector)
char* partitionMemory = &m_defaultPartition[0];
m_pCurrentPointer = partitionMemory;
m_leftInPartition = sizeof(m_defaultPartition);
}
CDataWriteStreamBuffer::~CDataWriteStreamBuffer()
{
// Free all memory partitions that were allocated dynamically
for (size_t i = 0; i < m_pPartitions.size(); ++i)
{
CryModuleFree(m_pPartitions[i]);
}
}
void CDataWriteStreamBuffer::Delete()
{
delete this;
}
const uint32 CDataWriteStreamBuffer::GetSize() const
{
return m_size;
}
void CDataWriteStreamBuffer::CopyToBuffer(void* pData) const
{
uint32 dataLeft = m_size;
char* pWritePtr = (char*)pData;
// Copy data from default (preallocated) partition
{
const uint32 partitionSize = sizeof(m_defaultPartition);
const uint32 dataToCopy = min<uint32>(partitionSize, dataLeft);
memcpy(pWritePtr, &m_defaultPartition[0], dataToCopy);
// advance
pWritePtr += dataToCopy;
dataLeft -= dataToCopy;
}
// Copy data from dynamic partitions
for (uint32 i = 0; i < m_pPartitions.size(); ++i)
{
// get size of data to copy
const uint32 partitionSize = m_partitionSizes[i];
const uint32 dataToCopy = min<uint32>(partitionSize, dataLeft);
memcpy(pWritePtr, m_pPartitions[i], dataToCopy);
// advance
pWritePtr += dataToCopy;
dataLeft -= dataToCopy;
}
// Make sure all data was written
CRY_ASSERT(dataLeft == 0);
}
IServiceNetworkMessage* CDataWriteStreamBuffer::BuildMessage() const
{
// No data written, no message created
if (0 == m_size)
{
return NULL;
}
// Create message to hold all the data
IServiceNetworkMessage* pMessage = gEnv->pServiceNetwork->AllocMessageBuffer(m_size);
if (NULL == pMessage)
{
return NULL;
}
// Copy data to messages
CopyToBuffer(pMessage->GetPointer());
return pMessage;
}
void CDataWriteStreamBuffer::Write(const void* pData, const uint32 size)
{
static const uint32 kAdditionalPartitionSize = 65536;
uint32 dataLeft = size;
while (dataLeft > 0)
{
// new partition needed
if (m_leftInPartition == 0)
{
// Allocate new partition data
char* partitionMemory = (char*)CryModuleMalloc(kAdditionalPartitionSize);
CRY_ASSERT(partitionMemory != NULL);
// add new partition to list
m_partitionSizes.push_back(kAdditionalPartitionSize);
m_pPartitions.push_back(partitionMemory);
m_pCurrentPointer = partitionMemory;
m_leftInPartition = kAdditionalPartitionSize;
}
// how many bytes can we write to current partition ?
const uint32 maxToWrite = min<uint32>(m_leftInPartition, dataLeft);
memcpy(m_pCurrentPointer, pData, maxToWrite);
// advance
m_size += maxToWrite;
dataLeft -= maxToWrite;
pData = (const char*)pData + maxToWrite;
m_pCurrentPointer += maxToWrite;
m_leftInPartition -= maxToWrite;
}
}
void CDataWriteStreamBuffer::Write8(const void* pData)
{
// it does not actually matter if its uint64, int64 or double so use any
WriteType<uint64>(pData);
}
void CDataWriteStreamBuffer::Write4(const void* pData)
{
// it does not actually matter if its uint32, int32 or float so use any
WriteType<uint32>(pData);
}
void CDataWriteStreamBuffer::Write2(const void* pData)
{
// it does not actually matter if its uint16, int16 so use any
WriteType<uint16>(pData);
}
void CDataWriteStreamBuffer::Write1(const void* pData)
{
// it does not actually matter if its uint8, int8 so use any
WriteType<uint8>(pData);
}
//-----------------------------------------------------------------------------
@@ -1,307 +0,0 @@
/*
* 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.
// Description : Remote command system helper classes
#ifndef CRYINCLUDE_CRYSYSTEM_REMOTECOMMANDHELPERS_H
#define CRYINCLUDE_CRYSYSTEM_REMOTECOMMANDHELPERS_H
#pragma once
//------------------------------------------------------------------------
#include "IRemoteCommand.h"
struct IServiceNetworkMessage;
//------------------------------------------------------------------------
// Stream reader for service network message
// Implements automatic byte swapping
class CDataReadStreamFormMessage
: public IDataReadStream
{
private:
const IServiceNetworkMessage* m_pMessage;
const char* m_pData;
uint32 m_offset;
uint32 m_size;
private:
template<typename T>
ILINE void ReadType(void* pData)
{
CRY_ASSERT(m_offset + sizeof(T) < m_size);
const T& readPos = *reinterpret_cast<const T*>(m_pData + m_offset);
*reinterpret_cast<T*>(pData) = readPos;
SwapEndian(*reinterpret_cast<T*>(pData));
m_offset += sizeof(T);
}
public:
CDataReadStreamFormMessage(const IServiceNetworkMessage* message);
virtual ~CDataReadStreamFormMessage();
const uint32 GetOffset() const
{
return m_offset;
}
void SetPosition(uint32 offset)
{
m_offset = offset;
}
public:
// IDataReadStream interface
virtual void Delete();
virtual void Skip(const uint32 size);
virtual void Read(void* pData, const uint32 size);
virtual void Read8(void* pData);
virtual void Read4(void* pData);
virtual void Read2(void* pData);
virtual void Read1(void* pData);
virtual const void* GetPointer();
};
//------------------------------------------------------------------------
// Stream writer that writes into the service network message
class CDataWriteStreamToMessage
: public IDataWriteStream
{
private:
IServiceNetworkMessage* m_pMessage;
char* m_pData;
uint32 m_offset;
uint32 m_size;
private:
template<typename T>
ILINE void WriteType(const void* pData)
{
CRY_ASSERT(m_offset + sizeof(T) < m_size);
T& writePos = *reinterpret_cast<T*>(m_pData + m_offset);
writePos = *reinterpret_cast<const T*>(pData);
SwapEndian(writePos);
m_offset += sizeof(T);
}
public:
CDataWriteStreamToMessage(IServiceNetworkMessage* pMessage);
virtual ~CDataWriteStreamToMessage();
// IDataWriteStream interface implementation
virtual void Delete();
virtual const uint32 GetSize() const;
virtual struct IServiceNetworkMessage* BuildMessage() const;
virtual void CopyToBuffer(void* pData) const;
virtual void Write(const void* pData, const uint32 size);
virtual void Write8(const void* pData);
virtual void Write4(const void* pData);
virtual void Write2(const void* pData);
virtual void Write1(const void* pData);
};
//------------------------------------------------------------------------
/// Stream reader reading from owner memory buffer
class CDataReadStreamMemoryBuffer
: public IDataReadStream
{
private:
const uint32 m_size;
uint8* m_pData;
uint32 m_offset;
public:
// memory is copied!
CDataReadStreamMemoryBuffer(const void* pData, const uint32 size);
virtual ~CDataReadStreamMemoryBuffer();
virtual void Delete();
virtual void Skip(const uint32 size);
virtual void Read8(void* pData);
virtual void Read4(void* pData);
virtual void Read2(void* pData);
virtual void Read1(void* pData);
virtual const void* GetPointer();
virtual void Read(void* pData, const uint32 size);
};
//------------------------------------------------------------------------
// Stream writer that writes into the internal memory buffer
class CDataWriteStreamBuffer
: public IDataWriteStream
{
static const uint32 kStaticPartitionSize = 4096;
private:
// Default (preallocated) partition
char m_defaultPartition[ kStaticPartitionSize ];
// Allocated dynamic partitions
std::vector<char*> m_pPartitions;
// Size of the dynamic message partitions
std::vector<uint32> m_partitionSizes;
// Pointer to current writing position in the current partition
char* m_pCurrentPointer;
// Space left in current partition
uint32 m_leftInPartition;
// Total message size so far
uint32 m_size;
private:
// Directly write typed data into the stream
template<typename T>
ILINE void WriteType(const void* pData)
{
// try to use the faster path if we are not crossing the partition boundary
if (m_leftInPartition >= sizeof(T))
{
// faster case
T& writePos = *reinterpret_cast<T*>(m_pCurrentPointer);
writePos = *reinterpret_cast<const T*>(pData);
SwapEndian(writePos);
m_pCurrentPointer += sizeof(T);
m_leftInPartition -= sizeof(T);
m_size += sizeof(T);
}
else
{
// slower case (more generic)
T tempVal(*reinterpret_cast<const T*>(pData));
SwapEndian(tempVal);
Write(&tempVal, sizeof(tempVal));
}
}
public:
CDataWriteStreamBuffer();
virtual ~CDataWriteStreamBuffer();
// IDataWriteStream interface implementation
virtual void Delete();
virtual const uint32 GetSize() const;
virtual IServiceNetworkMessage* BuildMessage() const;
virtual void CopyToBuffer(void* pData) const;
virtual void Write(const void* pData, const uint32 size);
virtual void Write8(const void* pData);
virtual void Write4(const void* pData);
virtual void Write2(const void* pData);
virtual void Write1(const void* pData);
};
//-----------------------------------------------------------------------------
// Packet header
struct PackedHeader
{
// Estimation (or better yet, exact value) of how much data this header will take when written.
// Please make sure that actual size after serialization is not bigger than this value.
static const uint32 kSerializationSize = sizeof(uint8) + sizeof(uint32) + sizeof(uint32);
// Magic value that identifies command messages vs raw messages
static const uint32 kMagic = 0xABBAF00D;
// Command type
// Keep the values unchanged as this may break the protocol
enum ECommand
{
// Server class list mapping
eCommand_ClassList = 0,
// Command data
eCommand_Command = 1,
// Disconnect signal
eCommand_Disconnect = 2,
// ACK packet
eCommand_ACK = 3,
};
uint32 magic;
uint8 msgType;
uint32 count;
// serialization operator
template< class T >
friend T& operator<<(T& stream, PackedHeader& header)
{
stream << header.magic;
stream << header.msgType;
stream << header.count;
return stream;
}
};
// Header sent with every command
struct CommandHeader
{
uint32 commandId;
uint32 classId;
uint32 size;
CommandHeader()
: commandId(0)
, classId(0)
, size(0)
{}
// serialization operator
template< class T >
friend T& operator<<(T& stream, CommandHeader& header)
{
stream << header.commandId;
stream << header.classId;
stream << header.size;
return stream;
}
};
// General Response/ACK header
struct ResponseHeader
{
uint32 magic;
uint8 msgType;
uint32 lastCommandReceived;
uint32 lastCommandExecuted;
ResponseHeader()
: lastCommandReceived(0)
, lastCommandExecuted(0)
, msgType(PackedHeader::eCommand_ACK)
{}
// serialization operator
template< class T >
friend T& operator<<(T& stream, ResponseHeader& header)
{
stream << header.magic;
stream << header.msgType;
stream << header.lastCommandReceived;
stream << header.lastCommandExecuted;
return stream;
}
};
//-----------------------------------------------------------------------------
#endif // CRYINCLUDE_CRYSYSTEM_REMOTECOMMANDHELPERS_H
@@ -1,832 +0,0 @@
/*
* 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.
// Description : Remote command system implementation (server)
#include "CrySystem_precompiled.h"
#include "IServiceNetwork.h"
#include "RemoteCommand.h"
#include "RemoteCommandHelpers.h"
//-----------------------------------------------------------------------------
// remote system internal logging
#ifdef RELEASE
#define LOG_VERBOSE(level, txt, ...)
#else
#define LOG_VERBOSE(level, txt, ...) if (GetManager()->CheckVerbose(level)) { GetManager()->Log(txt, __VA_ARGS__); }
#endif
//-----------------------------------------------------------------------------
CRemoteCommandServer::WrappedCommand::WrappedCommand(IRemoteCommand* pCommand, const uint32 commandId)
: m_pCommand(pCommand)
, m_refCount(1)
, m_commandID(commandId)
{
}
CRemoteCommandServer::WrappedCommand::~WrappedCommand()
{
CRY_ASSERT(m_refCount == 0);
m_pCommand->Delete();
}
void CRemoteCommandServer::WrappedCommand::AddRef()
{
CryInterlockedIncrement(&m_refCount);
}
void CRemoteCommandServer::WrappedCommand::Release()
{
if (0 == CryInterlockedDecrement(&m_refCount))
{
delete this;
}
}
//-----------------------------------------------------------------------------
CRemoteCommandServer::Endpoint::Endpoint(CRemoteCommandManager* pManager, class CRemoteCommandServer* pServer, IServiceNetworkConnection* pConnection)
: m_pConnection(pConnection)
, m_pManager(pManager)
, m_pServer(pServer)
, m_lastReceivedCommand(0)
, m_lastExecutedCommand(0)
, m_lastReceivedCommandACKed(0)
, m_lastExecutedCommandACKed(0)
, m_bHasReceivedClassList(false)
{
}
CRemoteCommandServer::Endpoint::~Endpoint()
{
// release commands that were not yet executed
// this will release the command memory buffers (if they are not referenced elsewhere)
while (!m_pCommandsToExecute.empty())
{
WrappedCommand* pCommand = m_pCommandsToExecute.pop();
pCommand->Release();
}
// make sure the network connection is closed
if (NULL != m_pConnection)
{
// send the disconnect message
{
CDataWriteStreamBuffer writer;
// format messages
PackedHeader header;
header.magic = PackedHeader::kMagic;
header.msgType = PackedHeader::eCommand_Disconnect;
header.count = 0;
writer << header;
// Send the message
IServiceNetworkMessage* pMessage = writer.BuildMessage();
if (NULL != pMessage)
{
m_pConnection->SendMsg(pMessage);
pMessage->Release();
}
}
// close the connection (but try to send messages out)
m_pConnection->FlushAndClose(IServiceNetworkConnection::kDefaultFlushTime);
m_pConnection->Release();
m_pConnection = NULL;
}
}
const char* CRemoteCommandServer::Endpoint::GetClassName(const uint32 classId) const
{
// class index is out of bounds
if (classId >= m_pLocalClassFactories.size())
{
return "InvalidClassID";
}
// get class factory for the class ID
IRemoteCommandClass* theClass = m_pLocalClassFactories[ classId ];
if (NULL == theClass)
{
// ID is valid but we do not support this class
// Can happen, usually due to version mismatch between client and server binaries
return "UnsupportedClassID";
}
return theClass->GetName();
}
IRemoteCommand* CRemoteCommandServer::Endpoint::CreateObject(const uint32 classId) const
{
// class index is out of bounds
if (classId >= m_pLocalClassFactories.size())
{
return NULL;
}
// get class factory for given class index
IRemoteCommandClass* theClass = m_pLocalClassFactories[ classId ];
if (NULL == theClass)
{
// ID is valid but we do not support this class
// Can happen, usually due to version mismatch between client and server binaries
return NULL;
}
// use the class definition to create the instance of the remote command object
return theClass->CreateObject();
}
void CRemoteCommandServer::Endpoint::Execute()
{
uint32 idOfLastExecutedCommand = 0;
// Process the commands on the execution list
while (!m_pCommandsToExecute.empty())
{
// Pop the command from the stack
WrappedCommand* pCommand = m_pCommandsToExecute.pop();
LOG_VERBOSE(3, "Executing command '%s', ID %d",
pCommand->GetCommand()->GetClass()->GetName(),
pCommand->GetId());
// Here is where the magic happens
{
pCommand->GetCommand()->Execute();
}
// Keep track of the command ID executed so far (so we can update the ACK later)
CRY_ASSERT(pCommand->GetId() > idOfLastExecutedCommand);
idOfLastExecutedCommand = pCommand->GetId();
// Command was executed, we can release it
pCommand->Release();
}
// Update the ACK data (if it's needed)
if (idOfLastExecutedCommand != 0)
{
CryAutoLock<CryMutex> lock(m_accessLock);
LOG_VERBOSE(3, "Updating LastExecutedCommandID %d->%d",
m_lastExecutedCommand,
idOfLastExecutedCommand);
// Well, it only makes sens if the current command ID is greater that the last one executed
CRY_ASSERT(idOfLastExecutedCommand > m_lastExecutedCommand);
if (idOfLastExecutedCommand > m_lastExecutedCommand)
{
m_lastExecutedCommand = idOfLastExecutedCommand;
}
}
}
bool CRemoteCommandServer::Endpoint::Update()
{
// Check connection status
if (!m_pConnection->IsAlive())
{
// Signal the owner that this endpoint should be deleted
return false;
}
// Receive and deserialize the commands
// Note that this is done asynchronously so commands can be decoded even if the main thread is busy
// Note that execution is DEFERRED to the main thread (I wouldn't risk doing it from this thread ;-))
bool bDisconnectReceived = false;
IServiceNetworkMessage* pMsg = m_pConnection->ReceiveMsg();
while (NULL != pMsg && !bDisconnectReceived)
{
CDataReadStreamFormMessage reader(pMsg);
// read back the packet header
PackedHeader packetHeader;
reader << packetHeader;
// Is this a command system messages ?
if (packetHeader.magic == PackedHeader::kMagic)
{
switch (packetHeader.msgType)
{
// Class list, usually sent as first thing after connection
case PackedHeader::eCommand_ClassList:
{
// deserialize class names
std::vector< string > classNames;
reader << classNames;
// sync the command ID to the current value on the client
const uint32 firstCommandID = packetHeader.count;
m_lastExecutedCommand = firstCommandID;
m_lastExecutedCommandACKed = firstCommandID;
m_lastReceivedCommand = firstCommandID;
m_lastReceivedCommandACKed = firstCommandID;
m_bHasReceivedClassList = true;
LOG_VERBOSE(3, "Received class list packet, count=%d, first message=%d from '%s'",
classNames.size(),
packetHeader.count,
m_pConnection->GetRemoteAddress().ToString().c_str());
// create class mapping between remote client and this server
GetManager()->BuildClassMapping(classNames, m_pLocalClassFactories);
break;
}
// Actual command packets
case PackedHeader::eCommand_Command:
{
LOG_VERBOSE(3, "Received packet, count=%d from '%s'",
packetHeader.count,
m_pConnection->GetRemoteAddress().ToString().c_str());
// load the serialized commands
const uint32 numCommands = packetHeader.count;
for (uint32 i = 0; i < numCommands; ++i)
{
// Each command is prefixed with header
CommandHeader header;
reader << header;
// We must be able to skip to the end of the command data because sometimes
// some data can be omitted - either by dropping the command altogether or
// by faulty deserialization. Don't trust the user.
const uint32 offset = reader.GetOffset();
const uint32 endOffset = offset + header.size; // here is where we can skip
LOG_VERBOSE(3, "Received command ID=%d (class id=%d, size=%d) from '%s'",
header.commandId,
header.classId,
header.size,
m_pConnection->GetRemoteAddress().ToString().c_str());
// Do not process commands out of order.
// This should not happen if network is in good health, but we cannot assume that, never-ever.
// This code will cause our side to stop executing new commands until the remote side to resend the missing ones.
// Typically it is better than executing commands out of order.
const uint32 expectedNextCommand = m_lastReceivedCommand + 1;
if (header.commandId > expectedNextCommand)
{
LOG_VERBOSE(0, "Out of order command ID (%d > %d) received from '%s'",
header.commandId,
expectedNextCommand,
m_pConnection->GetRemoteAddress().ToString().c_str());
// next commands will be even older, no need to check them
break;
}
// Do not process the old commands
// This may happen pretty often when command is resent while the ACK is "in-flight"
// Just drop the data and go on.
if (header.commandId <= m_lastReceivedCommand)
{
// getting old command is not an error, it just means that we have large enough lag
// that the client started resending old commands.
LOG_VERBOSE(1, "Old command (%d <= %d) received from '%s'",
header.commandId,
m_lastReceivedCommand,
m_pConnection->GetRemoteAddress().ToString().c_str());
}
else
{
// next command received, we are very strict about matchig the command IDs here
CRY_ASSERT(header.commandId == expectedNextCommand);
m_lastReceivedCommand = expectedNextCommand;
// create the command
IRemoteCommand* pCommand = CreateObject(header.classId);
if (NULL != pCommand)
{
// Fine-grain logging
LOG_VERBOSE(3, "Received command '%s', classId=%d, commandId=%d from '%s'",
pCommand->GetClass()->GetName(),
header.classId,
header.commandId,
m_pConnection->GetRemoteAddress().ToString().c_str());
// Deserialize the command data from network message
pCommand->LoadFromStream(reader);
// Add to list of commands to execute
{
m_pCommandsToExecute.push(new WrappedCommand(pCommand, header.commandId));
}
}
else
{
LOG_VERBOSE(0, "ClassId %d not recognized. Skipping command ID%d from '%s'",
header.classId,
header.commandId,
m_pConnection->GetRemoteAddress().ToString().c_str());
}
// Update the last command ID
m_lastReceivedCommand = header.commandId;
}
// Sync the message stream to popper position
CRY_ASSERT(reader.GetOffset() <= endOffset);
reader.SetPosition(endOffset);
}
break;
}
// request to disconnect (graceful)
case PackedHeader::eCommand_Disconnect:
{
LOG_VERBOSE(3, "Received disconnect request from '%s'",
m_pConnection->GetRemoteAddress().ToString().c_str());
m_pConnection->Close();
bDisconnectReceived = true;
break;
}
// should not happen
default:
{
LOG_VERBOSE(0, "Invalid message type '%s' received from '%s'",
packetHeader.msgType,
m_pConnection->GetRemoteAddress().ToString().c_str());
break;
}
}
}
else
{
// This is a raw message, try to process immediately using async listeners.
// If it fails, add to the queue for processing on the main thread by sync listeners.
m_pServer->ProcessRawMessageAsync(pMsg, m_pConnection);
}
// Release the message data
pMsg->Release();
// Get the next message from network
if (!bDisconnectReceived)
{
pMsg = m_pConnection->ReceiveMsg();
}
}
// The value of lastExecutedCommand can change outside this thread,
// so capture it one and keep it constant for the duration of the logic in this function.
const uint32 snapshotLastExecutedCommand = m_lastExecutedCommand;
// Determine if we should send generate the ACK signal
if ((snapshotLastExecutedCommand != m_lastExecutedCommandACKed) ||
(m_lastReceivedCommand != m_lastReceivedCommandACKed)) // this can
{
ResponseHeader header;
header.magic = PackedHeader::kMagic;
header.msgType = PackedHeader::eCommand_ACK;
header.lastCommandReceived = m_lastReceivedCommand;
header.lastCommandExecuted = snapshotLastExecutedCommand; // note that we use the captured values
LOG_VERBOSE(3, "Sending ACK to '%s' with LastReceived=%d, LastExecuted=%d",
m_pConnection->GetRemoteAddress().ToString().c_str(),
header.lastCommandReceived,
header.lastCommandExecuted);
// Write header into the message
CDataWriteStreamBuffer writer;
writer << header;
// Extract the message
IServiceNetworkMessage* pMessage = writer.BuildMessage();
if (NULL != pMessage)
{
// Send it back over the connection (works as ACK)
if (m_pConnection->SendMsg(pMessage))
{
// Only after the message is accepted by the network we can assume that we have ACKed it properly
// This can still leave a possibility that this message gets eaten in the network but we will resend newer ACK
// soon enough that we don't need to bother with this.
m_lastExecutedCommandACKed = header.lastCommandExecuted;
m_lastReceivedCommandACKed = header.lastCommandReceived;
}
pMessage->Release();
}
}
// Continue
return true;
}
//-----------------------------------------------------------------------------
CRemoteCommandServer::CRemoteCommandServer(CRemoteCommandManager* pManager, IServiceNetworkListener* pListener)
: m_pManager(pManager)
, m_pListener(pListener)
, m_bCloseThread(false)
, m_suppressionCounter(0)
, m_bIsSuppressed(false)
{
// Start processing thread (receiving from network, deserialization, etc)
m_pThread = new TRemoteServerThread();
m_pThread->Start(*this);
}
CRemoteCommandServer::~CRemoteCommandServer()
{
// Stop the thread, assumes that thread is responsive
if (NULL != m_pThread)
{
m_pThread->Cancel();
m_pThread->Stop();
m_pThread->WaitForThread();
delete m_pThread;
}
// Cleanup the clients endpoints
for (TEndpoints::const_iterator it = m_pEndpoints.begin();
it != m_pEndpoints.end(); ++it)
{
delete (*it);
}
m_pEndpoints.clear();
// Cleanup the clients that were not yet deleted but are dead
for (TEndpoints::const_iterator it = m_pEndpointToDelete.begin();
it != m_pEndpointToDelete.end(); ++it)
{
delete (*it);
}
m_pEndpointToDelete.clear();
// Cleanup the raw messages
while (!m_pRawMessages.empty())
{
delete m_pRawMessages.pop();
}
// Properly close the listening socket
if (m_pListener != NULL)
{
m_pListener->Close();
m_pListener->Release();
m_pListener = NULL;
}
}
void CRemoteCommandServer::ProcessRawMessageAsync(IServiceNetworkMessage* pMessage, IServiceNetworkConnection* pConnection)
{
// we lock for the whole duration of the function - I think that's the safest.
// this function is being called from remote command server thread and even if it locks for a moment that's not a tragic situation.
CryAutoLock<CryMutex> lock(m_rawMessagesLock);
// Process the message using async listeners
bool bWasProcessed = false;
for (TRawMessageListenersAsync::const_iterator it = m_pRawListenersAsync.begin();
it != m_pRawListenersAsync.end(); ++it)
{
CDataReadStreamFormMessage reader(pMessage);
CDataWriteStreamBuffer writer;
// Request the listener to process this message
if ((*it)->OnRawMessageAsync(pConnection->GetRemoteAddress(), reader, writer))
{
// Send response back using the source connection
if (writer.GetSize() > 0)
{
IServiceNetworkMessage* pNewMessage = writer.BuildMessage();
if (NULL != pNewMessage)
{
pConnection->SendMsg(pNewMessage);
pNewMessage->Release();
}
}
// mark as processed
bWasProcessed = true;
break;
}
}
// Stats
if (bWasProcessed)
{
LOG_VERBOSE(3, "Raw message from '%s', size %d ASYNC, PROCESSED",
pConnection->GetRemoteAddress().ToString().c_str(),
pMessage->GetSize());
}
else
{
LOG_VERBOSE(3, "Raw message from '%s', size %d ASYNC, NOT PROCESSED",
pConnection->GetRemoteAddress().ToString().c_str(),
pMessage->GetSize());
}
// If we have sync listeners add the raw message for processing on the main thread
if (!bWasProcessed && !m_pRawListenersSync.empty())
{
m_pRawMessages.push(new RawMessage(pConnection, pMessage));
}
}
void CRemoteCommandServer::ProcessRawMessagesSync()
{
// get messages
TRawMessageListenersSync listeners;
{
CryAutoLock<CryMutex> lock(m_rawMessagesLock);
listeners = m_pRawListenersSync;
}
// process each message
while (!m_pRawMessages.empty())
{
RawMessage* pMsg = m_pRawMessages.pop();
// Process messages only from alive connection (they could die before we got a chance to process the message)
if (pMsg && pMsg->m_pConnection->IsAlive())
{
// Try to process by on of the listeners
bool bWasProcessed = false;
for (TRawMessageListenersSync::const_iterator jt = listeners.begin();
jt != listeners.end(); ++jt)
{
CDataReadStreamFormMessage reader(pMsg->m_pMessage);
CDataWriteStreamBuffer writer;
// Request the listener to process this message
if ((*jt)->OnRawMessageSync(pMsg->m_pConnection->GetRemoteAddress(), reader, writer))
{
// Send response back using the source connection
if (writer.GetSize() > 0)
{
IServiceNetworkMessage* pMessage = writer.BuildMessage();
if (NULL != pMessage)
{
pMsg->m_pConnection->SendMsg(pMessage);
pMessage->Release();
}
}
// mark as processed
bWasProcessed = true;
break;
}
}
// Stats
if (bWasProcessed)
{
LOG_VERBOSE(3, "Raw message from '%s', size %d SYNC PROCESSED",
pMsg->m_pConnection->GetRemoteAddress().ToString().c_str(),
pMsg->m_pMessage->GetSize());
}
else
{
LOG_VERBOSE(3, "Raw message from '%s', size %d SYNC NOT PROCESSED",
pMsg->m_pConnection->GetRemoteAddress().ToString().c_str(),
pMsg->m_pMessage->GetSize());
}
}
/// Cleanup
delete pMsg;
}
}
void CRemoteCommandServer::Delete()
{
delete this;
}
void CRemoteCommandServer::FlushCommandQueue()
{
// Always process raw messages, even if commands are suspended
ProcessRawMessagesSync();
// When the command server is suppressed externally, well, then don't execute any commands
// This is usually used when the main thread is doing some heavy stuff.
// TODO: Consider signaling the clients about this condition.
if (m_bIsSuppressed)
{
LOG_VERBOSE(4, "FlushCommandQueue: suppressed (counter=%d)",
m_suppressionCounter);
return;
}
// Update the endpoints from a copy of the list
{
CryAutoLock<CryMutex> lock(m_accessLock);
m_pUpdateEndpoints = m_pEndpoints;
}
// Execute the commands for each endpoint
for (TEndpoints::const_iterator it = m_pUpdateEndpoints.begin();
it != m_pUpdateEndpoints.end(); ++it)
{
(*it)->Execute();
}
// Delete endpoints that were discarded within the thread (due to network errors)
// We couldn't do that there because we would need to lock to much inside the mutex (bad idea)
if (!m_pEndpointToDelete.empty())
{
// TODO: consider using different CS for pDeletedEnpoints array
CryAutoLock<CryMutex> lock(m_accessLock);
// delete the endpoint structured (deferred)
for (size_t i = 0; i < m_pEndpointToDelete.size(); ++i)
{
delete m_pEndpointToDelete[i];
}
m_pEndpointToDelete.clear();
}
}
void CRemoteCommandServer::SuppressCommands()
{
if (CryInterlockedIncrement(&m_suppressionCounter) > 0)
{
m_bIsSuppressed = true;
}
}
void CRemoteCommandServer::ResumeCommands()
{
if (CryInterlockedDecrement(&m_suppressionCounter) == 0)
{
m_bIsSuppressed = false;
}
}
void CRemoteCommandServer::Run()
{
TEndpoints updateList;
CryThreadSetName(-1, "RemoteCommandThread");
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(RemoteCommandServer_cpp)
#endif
while (!m_bCloseThread)
{
// Accept new connections
{
IServiceNetworkConnection* pNewConnection = m_pListener->Accept();
if (NULL != pNewConnection)
{
LOG_VERBOSE(2, "New endpoint created with connection '%s'",
pNewConnection->GetRemoteAddress().ToString().c_str());
// Create endpoint wrapper
Endpoint* pEndPoint = new Endpoint(GetManager(), this, pNewConnection);
// Add to endpoint list
{
CryAutoLock<CryMutex> lock(m_accessLock);
m_pEndpoints.push_back(pEndPoint);
}
}
}
// Get the current endpoint table (for update)
{
CryAutoLock<CryMutex> lock(m_accessLock);
updateList = m_pEndpoints;
}
// Update endpoints
for (TEndpoints::iterator it = updateList.begin();
it != updateList.end(); ++it)
{
Endpoint* ep = (*it);
if (!ep->Update())
{
LOG_VERBOSE(2, "RemoteCommand endpoint '%s' closed",
ep->GetConnection()->GetRemoteAddress().ToString().c_str());
// remove the endpoint from the original list
{
CryAutoLock<CryMutex> lock(m_accessLock);
// it's safe to remove from the endpoints list - we are iterating over a copy
m_pEndpoints.erase(std::find(m_pEndpoints.begin(), m_pEndpoints.end(), ep));
// don't delete the endpoint structure now (it may still be executed on main thread)
// instead add it to a list that will be processed at the end of execution so this endpoint can get deleted
m_pEndpointToDelete.push_back(ep);
}
}
}
// Limit the CPU usage
// TODO: consider using some event based mechanism since the only source of
// work for this thread is the network we can esily be triggered by that.
Sleep(5);
}
}
void CRemoteCommandServer::Cancel()
{
m_bCloseThread = true;
}
void CRemoteCommandServer::RegisterSyncMessageListener(IRemoteCommandListenerSync* pListener)
{
CryAutoLock<CryMutex> lock(m_rawMessagesLock);
m_pRawListenersSync.push_back(pListener);
}
void CRemoteCommandServer::UnregisterSyncMessageListener(IRemoteCommandListenerSync* pListener)
{
CryAutoLock<CryMutex> lock(m_rawMessagesLock);
TRawMessageListenersSync::iterator it = std::find(m_pRawListenersSync.begin(), m_pRawListenersSync.end(), pListener);
if (it != m_pRawListenersSync.end())
{
m_pRawListenersSync.erase(it);
}
}
void CRemoteCommandServer::RegisterAsyncMessageListener(IRemoteCommandListenerAsync* pListener)
{
CryAutoLock<CryMutex> lock(m_rawMessagesLock);
m_pRawListenersAsync.push_back(pListener);
}
void CRemoteCommandServer::UnregisterAsyncMessageListener(IRemoteCommandListenerAsync* pListener)
{
CryAutoLock<CryMutex> lock(m_rawMessagesLock);
TRawMessageListenersAsync::iterator it = std::find(m_pRawListenersAsync.begin(), m_pRawListenersAsync.end(), pListener);
if (it != m_pRawListenersAsync.end())
{
m_pRawListenersAsync.erase(it);
}
}
void CRemoteCommandServer::Broadcast(IServiceNetworkMessage* pMessage)
{
if (NULL != pMessage && pMessage->GetSize() > 0)
{
CryAutoLock<CryMutex> lock(m_rawMessagesLock);
for (TEndpoints::const_iterator jt = m_pEndpoints.begin();
jt != m_pEndpoints.end(); ++jt)
{
Endpoint* pEndpoint = (*jt);
if (pEndpoint->HasReceivedClassList())
{
IServiceNetworkConnection* pConnection = pEndpoint->GetConnection();
if (NULL != pConnection)
{
pConnection->SendMsg(pMessage);
}
}
}
}
}
bool CRemoteCommandServer::HasConnectedClients() const
{
CryAutoLock<CryMutex> lock(m_rawMessagesLock);
for (TEndpoints::const_iterator jt = m_pEndpoints.begin();
jt != m_pEndpoints.end(); ++jt)
{
Endpoint* pEndpoint = (*jt);
if (pEndpoint->HasReceivedClassList())
{
IServiceNetworkConnection* pConnection = pEndpoint->GetConnection();
if (pConnection->IsAlive())
{
return true;
}
}
}
return false;
}
//-----------------------------------------------------------------------------
// Do not remove (can mess up the uber file builds)
#undef LOG_VERBOSE
//-----------------------------------------------------------------------------
@@ -1,239 +0,0 @@
/*
* 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.
#include "CrySystem_precompiled.h"
#include <Serialization/IArchiveHost.h>
#include "JSONIArchive.h"
#include "JSONOArchive.h"
#include "BinArchive.h"
#include "XmlIArchive.h"
#include "XmlOArchive.h"
#include <Serialization/ClassFactoryImpl.h>
namespace Serialization
{
bool LoadFile(std::vector<char>& content, const char* filename)
{
AZ::IO::HandleType fileHandle = gEnv->pCryPak->FOpen(filename, "rb");
if (!fileHandle)
{
return false;
}
gEnv->pCryPak->FSeek(fileHandle, 0, SEEK_END);
size_t size = gEnv->pCryPak->FTell(fileHandle);
gEnv->pCryPak->FSeek(fileHandle, 0, SEEK_SET);
content.resize(size);
bool result = true;
if (size != 0)
{
result = gEnv->pCryPak->FRead(&content[0], size, fileHandle) == size;
}
gEnv->pCryPak->FClose(fileHandle);
return result;
}
class CArchiveHost
: public IArchiveHost
{
public:
bool LoadJsonFile(const SStruct& obj, const char* filename) override
{
std::vector<char> content;
if (!LoadFile(content, filename))
{
return false;
}
JSONIArchive ia;
if (!ia.open(content.data(), content.size()))
{
return false;
}
return ia(obj);
}
bool SaveJsonFile(const char* gameFilename, const SStruct& obj) override
{
char buffer[AZ::IO::IArchive::MaxPath];
const char* filename = gEnv->pCryPak->AdjustFileName(gameFilename, buffer, AZ_ARRAY_SIZE(buffer), AZ::IO::IArchive::FLAGS_FOR_WRITING);
JSONOArchive oa;
if (!oa(obj))
{
return false;
}
return oa.save(filename);
}
bool LoadJsonBuffer(const SStruct& obj, const char* buffer, size_t bufferLength) override
{
if (bufferLength == 0)
{
return false;
}
JSONIArchive ia;
if (!ia.open(buffer, bufferLength))
{
return false;
}
return ia(obj);
}
bool SaveJsonBuffer(DynArray<char>& buffer, const SStruct& obj) override
{
JSONOArchive oa;
if (!oa(obj))
{
return false;
}
buffer.assign(oa.buffer(), oa.buffer() + oa.length());
return true;
}
bool LoadBinaryFile(const SStruct& obj, const char* filename) override
{
std::vector<char> content;
if (!LoadFile(content, filename))
{
return false;
}
BinIArchive ia;
if (!ia.open(content.data(), content.size()))
{
return false;
}
return ia(obj);
}
bool SaveBinaryFile(const char* gameFilename, const SStruct& obj) override
{
char buffer[AZ::IO::IArchive::MaxPath];
const char* filename = gEnv->pCryPak->AdjustFileName(gameFilename, buffer, AZ_ARRAY_SIZE(buffer), AZ::IO::IArchive::FLAGS_FOR_WRITING);
BinOArchive oa;
obj(oa);
return oa.save(filename);
}
bool LoadBinaryBuffer(const SStruct& obj, const char* buffer, size_t bufferLength) override
{
if (bufferLength == 0)
{
return false;
}
BinIArchive ia;
if (!ia.open(buffer, bufferLength))
{
return false;
}
return ia(obj);
}
bool SaveBinaryBuffer(DynArray<char>& buffer, const SStruct& obj) override
{
BinOArchive oa;
obj(oa);
buffer.assign(oa.buffer(), oa.buffer() + oa.length());
return true;
}
bool CloneBinary(const SStruct& dest, const SStruct& src) override
{
BinOArchive oa;
src(oa);
BinIArchive ia;
if (!ia.open(oa.buffer(), oa.length()))
{
return false;
}
dest(ia);
return true;
}
bool CompareBinary(const SStruct& lhs, const SStruct& rhs) override
{
BinOArchive oa1;
lhs(oa1);
BinOArchive oa2;
rhs(oa2);
if (oa1.length() != oa2.length())
{
return false;
}
return memcmp(oa1.buffer(), oa2.buffer(), oa1.length()) == 0;
}
bool SaveXmlFile(const char* filename, const SStruct& obj, const char* rootNodeName) override
{
XmlNodeRef node = SaveXmlNode(obj, rootNodeName);
if (!node)
{
return false;
}
return node->saveToFile(filename);
}
bool LoadXmlFile(const SStruct& obj, const char* filename) override
{
XmlNodeRef node = gEnv->pSystem->LoadXmlFromFile(filename);
if (!node)
{
return false;
}
return LoadXmlNode(obj, node);
}
XmlNodeRef SaveXmlNode(const SStruct& obj, const char* nodeName) override
{
CXmlOArchive oa;
XmlNodeRef node = gEnv->pSystem->CreateXmlNode(nodeName);
if (!node)
{
return XmlNodeRef();
}
oa.SetXmlNode(node);
if (!obj(oa))
{
return XmlNodeRef();
}
return oa.GetXmlNode();
}
bool SaveXmlNode(XmlNodeRef& node, const SStruct& obj) override
{
if (!node)
{
return false;
}
CXmlOArchive oa;
oa.SetXmlNode(node);
return obj(oa);
}
bool LoadXmlNode(const SStruct& obj, const XmlNodeRef& node) override
{
CXmlIArchive ia;
ia.SetXmlNode(node);
if (!obj(ia))
{
return false;
}
return true;
}
};
IArchiveHost* CreateArchiveHost()
{
return new CArchiveHost;
}
}
@@ -1,21 +0,0 @@
/*
* 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.
#pragma once
#include <Serialization/IArchiveHost.h>
namespace Serialization
{
IArchiveHost* CreateArchiveHost();
}
@@ -1,839 +0,0 @@
/*
* 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.
#include "CrySystem_precompiled.h"
#include "BinArchive.h"
#include <map>
#include "Serialization/ClassFactory.h"
namespace Serialization {
static const unsigned char SIZE16 = 254;
static const unsigned char SIZE32 = 255;
static const unsigned int BIN_MAGIC = 0xb1a4c17f;
//#ifdef _DEBUG
//typedef std::map<unsigned short, string> HashMap;
//static HashMap hashMap;
//#endif
BinOArchive::BinOArchive()
: IArchive(OUTPUT | BINARY)
{
clear();
}
void BinOArchive::clear()
{
stream_.clear();
stream_.write((const char*)&BIN_MAGIC, sizeof(BIN_MAGIC));
}
size_t BinOArchive::length() const
{
return stream_.position();
}
bool BinOArchive::save(const char* filename)
{
FILE* f = nullptr;
azfopen(&f, filename, "wb");
if (!f)
{
return false;
}
if (fwrite(buffer(), 1, length(), f) != length())
{
fclose(f);
return false;
}
fclose(f);
return true;
}
inline void BinOArchive::openNode(const char* name, bool size8)
{
if (!strlen(name))
{
return;
}
unsigned short hash = calcHash(name);
stream_.write(hash);
blockSizeOffsets_.push_back(int(stream_.position()));
stream_.write((unsigned char)0);
if (!size8)
{
stream_.write((unsigned short)0);
}
#ifdef _DEBUG
// HashMap::iterator i = hashMap.find(hash);
// if(i != hashMap.end() && i->second != name)
// ASSERT_STR(0, name);
// hashMap[hash] = name;
#endif
}
inline void BinOArchive::closeNode(const char* name, bool size8)
{
if (!strlen(name))
{
return;
}
unsigned int offset = blockSizeOffsets_.back();
unsigned int size = (unsigned int)(stream_.position() - offset - sizeof(unsigned char) - (size8 ? 0 : sizeof(unsigned short)));
blockSizeOffsets_.pop_back();
unsigned char* sizePtr = (unsigned char*)(stream_.buffer() + offset);
if (size < SIZE16)
{
*sizePtr = size;
if (!size8)
{
unsigned char* buffer = sizePtr + 3;
memmove(buffer - 2, buffer, size);
stream_.setPosition(stream_.position() - 2);
}
}
else
{
YASLI_ASSERT(!size8);
if (size < 0x10000)
{
*sizePtr = SIZE16;
*((unsigned short*)(sizePtr + 1)) = size;
}
else
{
unsigned char* buffer = sizePtr + 3;
stream_.write((unsigned short)0);
*sizePtr = SIZE32;
memmove(buffer + 2, buffer, size);
*((unsigned int*)(sizePtr + 1)) = size;
}
}
}
bool BinOArchive::operator()(bool& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(IString& value, const char* name, [[maybe_unused]] const char* label)
{
bool size8 = strlen(value.get()) + 1 < SIZE16;
openNode(name, size8);
stream_ << value.get();
stream_.write(char(0));
closeNode(name, size8);
return true;
}
bool BinOArchive::operator()(IWString& value, const char* name, [[maybe_unused]] const char* label)
{
bool size8 = (wcslen(value.get()) + 1) * 2 < SIZE16;
openNode(name, size8);
stream_ << value.get();
stream_.write(short(0));
closeNode(name, size8);
return true;
}
bool BinOArchive::operator()(float& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(double& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(int16& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(int8& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(uint8& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(char& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(uint16& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(int32& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(uint32& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(int64& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(uint64& value, const char* name, [[maybe_unused]] const char* label)
{
openNode(name);
stream_.write(value);
closeNode(name);
return true;
}
bool BinOArchive::operator()(const SStruct& ser, const char* name, [[maybe_unused]] const char* label)
{
openNode(name, false);
ser(*this);
closeNode(name, false);
return true;
}
bool BinOArchive::operator()(IContainer& ser, const char* name, [[maybe_unused]] const char* label)
{
openNode(name, false);
unsigned int size = (unsigned int)ser.size();
if (size < SIZE16)
{
stream_.write((unsigned char)size);
}
else if (size < 0x10000)
{
stream_.write(SIZE16);
stream_.write((unsigned short)size);
}
else
{
stream_.write(SIZE32);
stream_.write(size);
}
if (strlen(name))
{
if (size > 0)
{
int i = 0;
do
{
char elementName[16];
azitoa(i++, elementName, AZ_ARRAY_SIZE(elementName), 10);
ser(*this, elementName, "");
} while (ser.next());
}
closeNode(name, false);
}
else
{
if (size > 0)
{
do
{
ser(*this, "", "");
}
while (ser.next());
}
}
return true;
}
bool BinOArchive::operator()(IPointer& ptr, const char* name, [[maybe_unused]] const char* label)
{
openNode(name, false);
const char* typeName = ptr.registeredTypeName();
if (!typeName)
{
typeName = "";
}
if (typeName[0] == '\0' && ptr.get())
{
CRY_ASSERT_MESSAGE(0, "Writing unregistered class. Use SERIALIZATION_CLASS_NAME macro for registration.");
}
TypeID baseType = ptr.baseType();
if (ptr.get())
{
stream_ << typeName;
stream_.write(char(0));
ptr.serializer()(*this);
}
else
{
stream_.write(char(0));
}
closeNode(name, false);
return true;
}
//////////////////////////////////////////////////////////////////////////
BinIArchive::BinIArchive()
: IArchive(INPUT | BINARY)
, loadedData_(0)
{
}
BinIArchive::~BinIArchive()
{
close();
}
bool BinIArchive::load(const char* filename)
{
close();
FILE* f = nullptr;
azfopen(&f, filename, "rb");
if (!f)
{
return false;
}
fseek(f, 0, SEEK_END);
size_t length = ftell(f);
fseek(f, 0, SEEK_SET);
if (length == 0)
{
fclose(f);
return false;
}
loadedData_ = new char[length];
if (fread((void*)loadedData_, 1, length, f) != length || !open(loadedData_, length))
{
close();
fclose(f);
return false;
}
fclose(f);
return true;
}
bool BinIArchive::open(const char* buffer, size_t size)
{
if (size < sizeof(int))
{
return false;
}
if (*(unsigned*)(buffer) != BIN_MAGIC)
{
return false;
}
buffer += sizeof(unsigned int);
size -= sizeof(unsigned int);
blocks_.push_back(Block(buffer, (unsigned int)size));
return true;
}
void BinIArchive::close()
{
if (loadedData_)
{
delete[] loadedData_;
}
loadedData_ = 0;
}
bool BinIArchive::openNode(const char* name)
{
Block block(0, 0);
if (currentBlock().get(name, block))
{
blocks_.push_back(block);
return true;
}
return false;
}
void BinIArchive::closeNode([[maybe_unused]] const char* name, [[maybe_unused]] bool check)
{
YASLI_ASSERT(!check || currentBlock().validToClose());
blocks_.pop_back();
}
bool BinIArchive::operator()(bool& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(IString& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
string str;
read(str);
value.set(str.c_str());
return true;
}
if (!openNode(name))
{
return false;
}
string str;
read(str);
value.set(str.c_str());
closeNode(name);
return true;
}
bool BinIArchive::operator()(IWString& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
wstring str;
read(str);
value.set(str.c_str());
return true;
}
if (!openNode(name))
{
return false;
}
wstring str;
read(str);
value.set(str.c_str());
closeNode(name);
return true;
}
bool BinIArchive::operator()(float& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(double& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(int16& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(uint16& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(int32& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(uint32& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(int64& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(uint64& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(int8& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(uint8& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(char& value, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
read(value);
return true;
}
if (!openNode(name))
{
return false;
}
read(value);
closeNode(name);
return true;
}
bool BinIArchive::operator()(const SStruct& ser, const char* name, [[maybe_unused]] const char* label)
{
if (!strlen(name))
{
ser(*this);
return true;
}
if (!openNode(name))
{
return false;
}
ser(*this);
closeNode(name, false);
return true;
}
bool BinIArchive::operator()(IContainer& ser, const char* name, [[maybe_unused]] const char* label)
{
if (strlen(name))
{
if (!openNode(name))
{
return false;
}
size_t size = currentBlock().readPackedSize();
ser.resize(size);
if (size > 0)
{
int i = 0;
do
{
char elementName[16];
azitoa(i++, elementName, AZ_ARRAY_SIZE(elementName), 10);
ser(*this, elementName, "");
}
while (ser.next());
}
closeNode(name);
return true;
}
else
{
size_t size = currentBlock().readPackedSize();
ser.resize(size);
if (size > 0)
{
do
{
ser(*this, "", "");
}
while (ser.next());
}
return true;
}
}
bool BinIArchive::operator()(IPointer& ptr, const char* name, [[maybe_unused]] const char* label)
{
if (strlen(name) && !openNode(name))
{
return false;
}
string typeName;
read(typeName);
if (ptr.get() && (typeName.empty() || strcmp(typeName.c_str(), ptr.registeredTypeName()) != 0))
{
ptr.create(""); // 0
}
if (!typeName.empty() && !ptr.get())
{
ptr.create(typeName.c_str());
}
if (SStruct ser = ptr.serializer())
{
ser(*this);
}
if (strlen(name))
{
closeNode(name);
}
return true;
}
unsigned int BinIArchive::Block::readPackedSize()
{
unsigned char size8;
read(size8);
if (size8 < SIZE16)
{
return size8;
}
if (size8 == SIZE16)
{
unsigned short size16;
read(size16);
return size16;
}
unsigned int size32;
read(size32);
return size32;
}
bool BinIArchive::Block::get(const char* name, Block& block)
{
if (begin_ == end_)
{
return false;
}
complex_ = true;
unsigned short hashName = calcHash(name);
const char* currInitial = curr_;
bool restarted = false;
for (;; )
{
if (curr_ >= end_)
{
return false;
}
unsigned short hash;
read(hash);
unsigned int size = readPackedSize();
const char* currPrev = curr_;
if ((curr_ += size) == end_)
{
if (restarted)
{
return false;
}
curr_ = begin_;
restarted = true;
}
//ASSERT(curr_ < end_);
if (hash == hashName)
{
block = Block(currPrev, size);
return true;
}
if (curr_ == currInitial)
{
return false;
}
}
}
}
@@ -1,180 +0,0 @@
/*
* 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.
#pragma once
// For tags 16-bit xor-hash is used, with check for uniquness in debug
// Block size is automatic: 8, 16 or 32 bits
#include "Serialization/IArchive.h"
#include "MemoryWriter.h"
namespace Serialization {
inline unsigned short calcHash(const char* str)
{
unsigned short hash = 0;
const unsigned short* p = (const unsigned short*)(str);
for (;; )
{
unsigned short w = *p++;
if (!(w & 0xff))
{
break;
}
hash ^= w;
if (!(w & 0xff00))
{
break;
}
}
return hash;
}
class BinOArchive
: public IArchive
{
public:
BinOArchive();
~BinOArchive() {}
void clear();
size_t length() const;
const char* buffer() const { return stream_.buffer(); }
bool save(const char* fileName);
bool operator()(bool& value, const char* name, const char* label);
bool operator()(IString& value, const char* name, const char* label);
bool operator()(IWString& value, const char* name, const char* label);
bool operator()(float& value, const char* name, const char* label);
bool operator()(double& value, const char* name, const char* label);
bool operator()(int32& value, const char* name, const char* label);
bool operator()(uint32& value, const char* name, const char* label);
bool operator()(int16& value, const char* name, const char* label);
bool operator()(uint16& value, const char* name, const char* label);
bool operator()(int64& value, const char* name, const char* label);
bool operator()(uint64& value, const char* name, const char* label);
bool operator()(int8& value, const char* name, const char* label);
bool operator()(uint8& value, const char* name, const char* label);
bool operator()(char& value, const char* name, const char* label);
bool operator()(const SStruct& ser, const char* name, const char* label);
bool operator()(IContainer& ser, const char* name, const char* label);
bool operator()(IPointer& ptr, const char* name, const char* label);
using IArchive::operator();
private:
void openContainer(const char* name, int size, const char* typeName);
void openNode(const char* name, bool size8 = true);
void closeNode(const char* name, bool size8 = true);
std::vector<unsigned int> blockSizeOffsets_;
MemoryWriter stream_;
};
//////////////////////////////////////////////////////////////////////////
class BinIArchive
: public IArchive
{
public:
BinIArchive();
~BinIArchive();
bool load(const char* fileName);
bool open(const char* buffer, size_t length); // doesn't copy the buffer
bool open(const BinOArchive& ar) { return open(ar.buffer(), ar.length()); }
void close();
bool operator()(bool& value, const char* name, const char* label);
bool operator()(IString& value, const char* name, const char* label);
bool operator()(IWString& value, const char* name, const char* label);
bool operator()(float& value, const char* name, const char* label);
bool operator()(double& value, const char* name, const char* label);
bool operator()(int16& value, const char* name, const char* label);
bool operator()(uint16& value, const char* name, const char* label);
bool operator()(int32& value, const char* name, const char* label);
bool operator()(uint32& value, const char* name, const char* label);
bool operator()(int64& value, const char* name, const char* label);
bool operator()(uint64& value, const char* name, const char* label);
bool operator()(int8& value, const char* name, const char* label);
bool operator()(uint8& value, const char* name, const char* label);
bool operator()(char& value, const char* name, const char* label);
bool operator()(const SStruct& ser, const char* name, const char* label);
bool operator()(IContainer& ser, const char* name, const char* label);
bool operator()(IPointer& ptr, const char* name, const char* label);
using IArchive::operator();
private:
class Block
{
public:
Block(const char* data, int size)
: begin_(data)
, end_(data + size)
, curr_(data)
, complex_(false) {}
bool get(const char* name, Block& block);
void read(void* data, int size)
{
YASLI_ASSERT(curr_ + size <= end_);
memcpy(data, curr_, size);
curr_ += size;
}
template<class T>
void read(T& x){ read(&x, sizeof(x)); }
void read(string& s)
{
YASLI_ASSERT(curr_ + strlen(curr_) < end_);
s = curr_;
curr_ += strlen(curr_) + 1;
}
void read(wstring& s)
{
YASLI_ASSERT(curr_ + sizeof(wchar_t) * wcslen((wchar_t*)curr_) < end_);
s = (wchar_t*)curr_;
curr_ += (wcslen((wchar_t*)curr_) + 1) * sizeof(wchar_t);
}
unsigned int readPackedSize();
bool validToClose() const { return complex_ || curr_ == end_; }
private:
const char* begin_;
const char* end_;
const char* curr_;
bool complex_;
};
typedef std::vector<Block> Blocks;
Blocks blocks_;
const char* loadedData_;
bool openNode(const char* name);
void closeNode(const char* name, bool check = true);
Block& currentBlock() { return blocks_.back(); }
template<class T>
void read(T& t) { currentBlock().read(t); }
};
}
File diff suppressed because it is too large Load Diff
@@ -1,95 +0,0 @@
/*
* 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.
#pragma once
#include "Serialization/IArchive.h"
#include "MemoryReader.h"
#include "Token.h"
#include <memory>
namespace Serialization {
class MemoryReader;
class JSONIArchive
: public IArchive
{
public:
JSONIArchive();
~JSONIArchive();
bool load(const char* filename);
bool open(const char* buffer, size_t length, bool free = false);
// virtuals:
bool operator()(bool& value, const char* name = "", const char* label = 0);
bool operator()(IString& value, const char* name = "", const char* label = 0);
bool operator()(IWString& value, const char* name = "", const char* label = 0);
bool operator()(float& value, const char* name = "", const char* label = 0);
bool operator()(double& value, const char* name = "", const char* label = 0);
bool operator()(int16& value, const char* name = "", const char* label = 0);
bool operator()(uint16& value, const char* name = "", const char* label = 0);
bool operator()(int32& value, const char* name = "", const char* label = 0);
bool operator()(uint32& value, const char* name = "", const char* label = 0);
bool operator()(int64& value, const char* name = "", const char* label = 0);
bool operator()(uint64& value, const char* name = "", const char* label = 0);
bool operator()(int8& value, const char* name = "", const char* label = 0);
bool operator()(uint8& value, const char* name = "", const char* label = 0);
bool operator()(char& value, const char* name = "", const char* label = 0);
bool operator()(const SStruct& ser, const char* name = "", const char* label = 0);
bool operator()(const SBlackBox& ser, const char* name = "", const char* label = 0);
bool operator()(IContainer& ser, const char* name = "", const char* label = 0);
bool operator()(IKeyValue& ser, const char* name = "", const char* label = 0);
bool operator()(IPointer& ser, const char* name = "", const char* label = 0);
using IArchive::operator();
private:
bool findName(const char* name, Token* outName = 0);
bool openBracket();
bool closeBracket();
bool openContainerBracket();
bool closeContainerBracket();
void checkValueToken();
bool checkStringValueToken();
void readToken();
void putToken();
int line(const char* position) const;
bool isName(Token token) const;
bool expect(char token);
void skipBlock();
struct Level
{
const char* start;
const char* firstToken;
bool isContainer;
bool isKeyValue;
Level()
: isContainer(false)
, isKeyValue(false) {}
};
typedef std::vector<Level> Stack;
Stack stack_;
std::unique_ptr<MemoryReader> reader_;
Token token_;
std::vector<char> unescapeBuffer_;
string filename_;
void* buffer_;
};
}
@@ -1,828 +0,0 @@
/*
* 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.
#include "CrySystem_precompiled.h"
#include "JSONOArchive.h"
#include "MemoryWriter.h"
#include "Serialization/KeyValue.h"
#include "Serialization/ClassFactory.h"
#include "Serialization/BlackBox.h"
#include <float.h>
namespace Serialization {
// Some of non-latin1 characters here are not escaped to
// keep compatibility with 8-bit local encoding (e.g. windows-1251)
static const char* escapeTable[256] = {
"\\0" /* 0x00: */,
"\\x01" /* 0x01: */,
"\\x02" /* 0x02: */,
"\\x03" /* 0x03: */,
"\\x04" /* 0x04: */,
"\\x05" /* 0x05: */,
"\\x06" /* 0x06: */,
"\\x07" /* 0x07: */,
"\\x08" /* 0x08: */,
"\\t" /* 0x09: \t */,
"\\n" /* 0x0A: \n */,
"\\x0B" /* 0x0B: */,
"\\x0C" /* 0x0C: */,
"\\r" /* 0x0D: */,
"\\x0E" /* 0x0E: */,
"\\x0F" /* 0x0F: */,
"\\x10" /* 0x10: */,
"\\x11" /* 0x11: */,
"\\x12" /* 0x12: */,
"\\x13" /* 0x13: */,
"\\x14" /* 0x14: */,
"\\x15" /* 0x15: */,
"\\x16" /* 0x16: */,
"\\x17" /* 0x17: */,
"\\x18" /* 0x18: */,
"\\x19" /* 0x19: */,
"\\x1A" /* 0x1A: */,
"\\x1B" /* 0x1B: */,
"\\x1C" /* 0x1C: */,
"\\x1D" /* 0x1D: */,
"\\x1E" /* 0x1E: */,
"\\x1F" /* 0x1F: */,
" " /* 0x20: */,
"!" /* 0x21: ! */,
"\\\"" /* 0x22: " */,
"#" /* 0x23: # */,
"$" /* 0x24: $ */,
"%" /* 0x25: % */,
"&" /* 0x26: & */,
"'" /* 0x27: ' */,
"(" /* 0x28: ( */,
")" /* 0x29: ) */,
"*" /* 0x2A: * */,
"+" /* 0x2B: + */,
"," /* 0x2C: , */,
"-" /* 0x2D: - */,
"." /* 0x2E: . */,
"/" /* 0x2F: / */,
"0" /* 0x30: 0 */,
"1" /* 0x31: 1 */,
"2" /* 0x32: 2 */,
"3" /* 0x33: 3 */,
"4" /* 0x34: 4 */,
"5" /* 0x35: 5 */,
"6" /* 0x36: 6 */,
"7" /* 0x37: 7 */,
"8" /* 0x38: 8 */,
"9" /* 0x39: 9 */,
":" /* 0x3A: : */,
";" /* 0x3B: ; */,
"<" /* 0x3C: < */,
"=" /* 0x3D: = */,
">" /* 0x3E: > */,
"?" /* 0x3F: ? */,
"@" /* 0x40: @ */,
"A" /* 0x41: A */,
"B" /* 0x42: B */,
"C" /* 0x43: C */,
"D" /* 0x44: D */,
"E" /* 0x45: E */,
"F" /* 0x46: F */,
"G" /* 0x47: G */,
"H" /* 0x48: H */,
"I" /* 0x49: I */,
"J" /* 0x4A: J */,
"K" /* 0x4B: K */,
"L" /* 0x4C: L */,
"M" /* 0x4D: M */,
"N" /* 0x4E: N */,
"O" /* 0x4F: O */,
"P" /* 0x50: P */,
"Q" /* 0x51: Q */,
"R" /* 0x52: R */,
"S" /* 0x53: S */,
"T" /* 0x54: T */,
"U" /* 0x55: U */,
"V" /* 0x56: V */,
"W" /* 0x57: W */,
"X" /* 0x58: X */,
"Y" /* 0x59: Y */,
"Z" /* 0x5A: Z */,
"[" /* 0x5B: [ */,
"\\\\" /* 0x5C: \ */,
"]" /* 0x5D: ] */,
"^" /* 0x5E: ^ */,
"_" /* 0x5F: _ */,
"`" /* 0x60: ` */,
"a" /* 0x61: a */,
"b" /* 0x62: b */,
"c" /* 0x63: c */,
"d" /* 0x64: d */,
"e" /* 0x65: e */,
"f" /* 0x66: f */,
"g" /* 0x67: g */,
"h" /* 0x68: h */,
"i" /* 0x69: i */,
"j" /* 0x6A: j */,
"k" /* 0x6B: k */,
"l" /* 0x6C: l */,
"m" /* 0x6D: m */,
"n" /* 0x6E: n */,
"o" /* 0x6F: o */,
"p" /* 0x70: p */,
"q" /* 0x71: q */,
"r" /* 0x72: r */,
"s" /* 0x73: s */,
"t" /* 0x74: t */,
"u" /* 0x75: u */,
"v" /* 0x76: v */,
"w" /* 0x77: w */,
"x" /* 0x78: x */,
"y" /* 0x79: y */,
"z" /* 0x7A: z */,
"{" /* 0x7B: { */,
"|" /* 0x7C: | */,
"}" /* 0x7D: } */,
"~" /* 0x7E: ~ */,
"\x7F" /* 0x7F: */, // for utf-8
"\x80" /* 0x80: */,
"\x81" /* 0x81: */,
"\x82" /* 0x82: */,
"\x83" /* 0x83: */,
"\x84" /* 0x84: */,
"\x85" /* 0x85: */,
"\x86" /* 0x86: */,
"\x87" /* 0x87: */,
"\x88" /* 0x88: */,
"\x89" /* 0x89: */,
"\x8A" /* 0x8A: */,
"\x8B" /* 0x8B: */,
"\x8C" /* 0x8C: */,
"\x8D" /* 0x8D: */,
"\x8E" /* 0x8E: */,
"\x8F" /* 0x8F: */,
"\x90" /* 0x90: */,
"\x91" /* 0x91: */,
"\x92" /* 0x92: */,
"\x93" /* 0x93: */,
"\x94" /* 0x94: */,
"\x95" /* 0x95: */,
"\x96" /* 0x96: */,
"\x97" /* 0x97: */,
"\x98" /* 0x98: */,
"\x99" /* 0x99: */,
"\x9A" /* 0x9A: */,
"\x9B" /* 0x9B: */,
"\x9C" /* 0x9C: */,
"\x9D" /* 0x9D: */,
"\x9E" /* 0x9E: */,
"\x9F" /* 0x9F: */,
"\xA0" /* 0xA0: */,
"\xA1" /* 0xA1: */,
"\xA2" /* 0xA2: */,
"\xA3" /* 0xA3: */,
"\xA4" /* 0xA4: */,
"\xA5" /* 0xA5: */,
"\xA6" /* 0xA6: */,
"\xA7" /* 0xA7: */,
"\xA8" /* 0xA8: */,
"\xA9" /* 0xA9: */,
"\xAA" /* 0xAA: */,
"\xAB" /* 0xAB: */,
"\xAC" /* 0xAC: */,
"\xAD" /* 0xAD: */,
"\xAE" /* 0xAE: */,
"\xAF" /* 0xAF: */,
"\xB0" /* 0xB0: */,
"\xB1" /* 0xB1: */,
"\xB2" /* 0xB2: */,
"\xB3" /* 0xB3: */,
"\xB4" /* 0xB4: */,
"\xB5" /* 0xB5: */,
"\xB6" /* 0xB6: */,
"\xB7" /* 0xB7: */,
"\xB8" /* 0xB8: */,
"\xB9" /* 0xB9: */,
"\xBA" /* 0xBA: */,
"\xBB" /* 0xBB: */,
"\xBC" /* 0xBC: */,
"\xBD" /* 0xBD: */,
"\xBE" /* 0xBE: */,
"\xBF" /* 0xBF: */,
"\xC0" /* 0xC0: */,
"\xC1" /* 0xC1: */,
"\xC2" /* 0xC2: */,
"\xC3" /* 0xC3: */,
"\xC4" /* 0xC4: */,
"\xC5" /* 0xC5: */,
"\xC6" /* 0xC6: */,
"\xC7" /* 0xC7: */,
"\xC8" /* 0xC8: */,
"\xC9" /* 0xC9: */,
"\xCA" /* 0xCA: */,
"\xCB" /* 0xCB: */,
"\xCC" /* 0xCC: */,
"\xCD" /* 0xCD: */,
"\xCE" /* 0xCE: */,
"\xCF" /* 0xCF: */,
"\xD0" /* 0xD0: */,
"\xD1" /* 0xD1: */,
"\xD2" /* 0xD2: */,
"\xD3" /* 0xD3: */,
"\xD4" /* 0xD4: */,
"\xD5" /* 0xD5: */,
"\xD6" /* 0xD6: */,
"\xD7" /* 0xD7: */,
"\xD8" /* 0xD8: */,
"\xD9" /* 0xD9: */,
"\xDA" /* 0xDA: */,
"\xDB" /* 0xDB: */,
"\xDC" /* 0xDC: */,
"\xDD" /* 0xDD: */,
"\xDE" /* 0xDE: */,
"\xDF" /* 0xDF: */,
"\xE0" /* 0xE0: */,
"\xE1" /* 0xE1: */,
"\xE2" /* 0xE2: */,
"\xE3" /* 0xE3: */,
"\xE4" /* 0xE4: */,
"\xE5" /* 0xE5: */,
"\xE6" /* 0xE6: */,
"\xE7" /* 0xE7: */,
"\xE8" /* 0xE8: */,
"\xE9" /* 0xE9: */,
"\xEA" /* 0xEA: */,
"\xEB" /* 0xEB: */,
"\xEC" /* 0xEC: */,
"\xED" /* 0xED: */,
"\xEE" /* 0xEE: */,
"\xEF" /* 0xEF: */,
"\xF0" /* 0xF0: */,
"\xF1" /* 0xF1: */,
"\xF2" /* 0xF2: */,
"\xF3" /* 0xF3: */,
"\xF4" /* 0xF4: */,
"\xF5" /* 0xF5: */,
"\xF6" /* 0xF6: */,
"\xF7" /* 0xF7: */,
"\xF8" /* 0xF8: */,
"\xF9" /* 0xF9: */,
"\xFA" /* 0xFA: */,
"\xFB" /* 0xFB: */,
"\xFC" /* 0xFC: */,
"\xFD" /* 0xFD: */,
"\xFE" /* 0xFE: */,
"\xFF" /* 0xFF: */
};
static void escapeString(MemoryWriter& dest, const char* begin, const char* end)
{
while (begin != end)
{
const char* str = escapeTable[(unsigned char)(*begin)];
dest.write(str);
++begin;
}
}
// ---------------------------------------------------------------------------
static const int TAB_WIDTH = 2;
JSONOArchive::JSONOArchive(int textWidth, const char* header)
: IArchive(OUTPUT | TEXT)
, header_(header)
, textWidth_(textWidth)
, compactOffset_(0)
{
buffer_.reset(new MemoryWriter(1024, true));
if (header_)
{
(*buffer_) << header_;
}
YASLI_ASSERT(stack_.empty());
stack_.push_back(Level(false, 0, 0));
}
JSONOArchive::~JSONOArchive()
{
}
bool JSONOArchive::save(const char* fileName)
{
YASLI_ESCAPE(fileName && strlen(fileName) > 0, return false);
YASLI_ESCAPE(stack_.size() == 1, return false);
YASLI_ESCAPE(buffer_.get() != 0, return false);
YASLI_ESCAPE(buffer_->position() <= buffer_->size(), return false);
stack_.pop_back();
FILE* file = nullptr;
azfopen(&file, fileName, "wb");
if (file)
{
if (fwrite(buffer_->c_str(), 1, buffer_->position(), file) != buffer_->position())
{
fclose(file);
return false;
}
fclose(file);
return true;
}
else
{
return false;
}
}
const char* JSONOArchive::c_str() const
{
return buffer_->c_str();
}
size_t JSONOArchive::length() const
{
return buffer_->position();
}
void JSONOArchive::openBracket()
{
*buffer_ << "{";
}
void JSONOArchive::closeBracket()
{
*buffer_ << "}";
}
void JSONOArchive::openContainerBracket()
{
*buffer_ << "[";
}
void JSONOArchive::closeContainerBracket()
{
*buffer_ << "]";
}
void JSONOArchive::placeName(const char* name)
{
if (stack_.back().isKeyValue)
{
return;
}
if ((name[0] != '\0' || !stack_.back().isContainer) && stack_.size() > 1)
{
*buffer_ << "\"";
*buffer_ << name;
*buffer_ << "\": ";
stack_.back().nameIndex += 1;
}
}
void JSONOArchive::placeIndent(bool putComma)
{
if (stack_.back().isKeyValue)
{
return;
}
if (putComma && stack_.back().elementIndex > 0)
{
*buffer_ << ",";
}
if (buffer_->position() > 0)
{
*buffer_ << "\n";
}
int count = int(stack_.size() - 1);
stack_.back().indentCount += count;
stack_.back().elementIndex += 1;
for (int i = 0; i < count; ++i)
{
*buffer_ << "\t";
}
compactOffset_ = 0;
}
void JSONOArchive::placeIndentCompact(bool putComma)
{
if (stack_.back().isKeyValue)
{
return;
}
if (putComma && stack_.back().elementIndex > 0)
{
*buffer_ << ",";
}
if ((compactOffset_ % 32) != 0 && stack_.back().isContainer)
{
*buffer_ << " ";
compactOffset_ += 1;
stack_.back().elementIndex += 1;
}
else if (buffer_->size())
{
*buffer_ << "\n";
int count = int(stack_.size() - 1);
stack_.back().indentCount += count /* * TAB_WIDTH*/;
stack_.back().elementIndex += 1;
for (int i = 0; i < count; ++i)
{
*buffer_ << "\t";
}
compactOffset_ = 1;
}
}
bool JSONOArchive::operator()(bool& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndent();
placeName(name);
*buffer_ << (value ? "true" : "false");
return true;
}
bool JSONOArchive::operator()(IString& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndent();
placeName(name);
(*buffer_) << "\"";
const char* str = value.get();
escapeString(*buffer_, str, str + strlen(value.get()));
(*buffer_) << "\"";
return true;
}
inline char* writeUtf16ToUtf8(char* s, unsigned int ch)
{
const unsigned char byteMark = 0x80;
const unsigned char byteMask = 0xBF;
size_t len;
if (ch < 0x80)
{
len = 1;
}
else if (ch < 0x800)
{
len = 2;
}
else if (ch < 0x10000)
{
len = 3;
}
else if (ch < 0x200000)
{
len = 4;
}
else
{
return s;
}
s += len;
const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
switch (len)
{
case 4:
*--s = (char)((ch | byteMark) & byteMask);
ch >>= 6;
case 3:
*--s = (char)((ch | byteMark) & byteMask);
ch >>= 6;
case 2:
*--s = (char)((ch | byteMark) & byteMask);
ch >>= 6;
case 1:
*--s = (char)(ch | firstByteMark[len]);
}
return s + len;
}
bool JSONOArchive::operator()(IWString& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndent();
placeName(name);
(*buffer_) << "\"";
const wchar_t* in = value.get();
for (; *in; ++in)
{
char buf[6];
escapeString(*buffer_, buf, writeUtf16ToUtf8(buf, *in));
}
(*buffer_) << "\"";
return true;
}
bool JSONOArchive::operator()(float& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(double& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(int32& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(uint32& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(int16& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(uint16& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(int64& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(uint64& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(uint8& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(int8& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(char& value, const char* name, [[maybe_unused]] const char* label)
{
placeIndentCompact();
placeName(name);
(*buffer_) << value;
return true;
}
bool JSONOArchive::operator()(const SStruct& ser, const char* name, [[maybe_unused]] const char* label)
{
placeIndent();
placeName(name);
std::size_t position = buffer_->position();
openBracket();
stack_.push_back(Level(false, position, int(strlen(name) + 2 * (name[0] & 1) + (stack_.size() - 1) * TAB_WIDTH + 2)));
YASLI_ASSERT(ser);
ser(*this);
bool joined = joinLinesIfPossible();
bool noNames = stack_.back().nameIndex == 0;
if (noNames)
{
if (stack_.size() != 2)
{
buffer_->buffer()[stack_.back().startPosition] = '[';
}
}
stack_.pop_back();
if (!joined)
{
placeIndent(false);
}
else
{
*buffer_ << " ";
}
if (noNames)
{
closeContainerBracket();
}
else
{
closeBracket();
}
return true;
}
bool JSONOArchive::operator()(const SBlackBox& box, const char* name, [[maybe_unused]] const char* label)
{
if (strcmp(box.format, "json") != 0)
{
return false;
}
if (box.size == 0)
{
return false;
}
placeIndent();
placeName(name);
return buffer_->write(box.data, box.size);
}
bool JSONOArchive::operator()(IKeyValue& keyValue, [[maybe_unused]] const char* name, [[maybe_unused]] const char* label)
{
placeIndent();
*buffer_ << "\"";
*buffer_ << keyValue.get();
*buffer_ << "\": ";
stack_.back().nameIndex += 1;
stack_.back().isKeyValue = true;
keyValue.serializeValue(*this, "", 0);
stack_.back().isKeyValue = false;
if (stack_.back().isContainer)
{
stack_.back().isDictionary = true;
}
return true;
}
bool JSONOArchive::operator()(IPointer& ser, const char* name, [[maybe_unused]] const char* label)
{
placeIndent();
placeName(name);
openBracket();
const char* registeredTypeName = ser.registeredTypeName();
if (registeredTypeName && registeredTypeName[0] != '\0')
{
*buffer_ << " ";
placeName(registeredTypeName);
stack_.back().isKeyValue = true;
operator()(ser.serializer(), "");
stack_.back().isKeyValue = false;
*buffer_ << " ";
}
closeBracket();
return true;
}
bool JSONOArchive::operator()(IContainer& ser, const char* name, [[maybe_unused]] const char* label)
{
placeIndent();
placeName(name);
std::size_t position = buffer_->position();
openContainerBracket();
stack_.push_back(Level(true, position, int(strlen(name) + 2 * (name[0] & 1) + stack_.size() - 1 * TAB_WIDTH + 2)));
std::size_t size = ser.size();
if (size > 0)
{
do
{
ser(*this, "", "");
} while (ser.next());
}
bool joined = joinLinesIfPossible();
bool isDictionary = stack_.back().isDictionary;
if (isDictionary)
{
buffer_->buffer()[stack_.back().startPosition] = '{';
}
stack_.pop_back();
if (!joined)
{
placeIndent(false);
}
else
{
*buffer_ << " ";
}
if (isDictionary)
{
closeBracket();
}
else
{
closeContainerBracket();
}
return true;
}
static char* joinLines(char* start, char* end)
{
YASLI_ASSERT(start <= end);
char* next = start;
while (next != end)
{
if (*next != '\t' && *next != '\r')
{
if (*next != '\n')
{
*start = *next;
}
else
{
*start = ' ';
}
++start;
}
++next;
}
return start;
}
bool JSONOArchive::joinLinesIfPossible()
{
YASLI_ASSERT(!stack_.empty());
std::size_t startPosition = stack_.back().startPosition;
YASLI_ASSERT(startPosition < buffer_->size());
int indentCount = stack_.back().indentCount;
//YASLI_ASSERT(startPosition >= indentCount);
if (buffer_->position() - startPosition - indentCount < std::size_t(textWidth_))
{
char* buffer = buffer_->buffer();
char* start = buffer + startPosition;
char* end = buffer + buffer_->position();
end = joinLines(start, end);
std::size_t newPosition = end - buffer;
YASLI_ASSERT(newPosition <= buffer_->position());
buffer_->setPosition(newPosition);
return true;
}
return false;
}
}
// vim:ts=4 sw=4:
@@ -1,102 +0,0 @@
/*
* 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.
#pragma once
#include <memory>
#include "Serialization/IArchive.h"
#include "Serialization/MemoryWriter.h"
namespace Serialization {
class MemoryWriter;
class JSONOArchive
: public IArchive
{
public:
// header = 0 - default header, use "" to omit
JSONOArchive(int textWidth = 80, const char* header = 0);
~JSONOArchive();
bool save(const char* fileName);
const char* c_str() const;
const char* buffer() const { return c_str(); }
size_t length() const;
// from Archive:
bool operator()(bool& value, const char* name = "", const char* label = 0);
bool operator()(IString& value, const char* name = "", const char* label = 0);
bool operator()(IWString& value, const char* name = "", const char* label = 0);
bool operator()(float& value, const char* name = "", const char* label = 0);
bool operator()(double& value, const char* name = "", const char* label = 0);
bool operator()(int16& value, const char* name = "", const char* label = 0);
bool operator()(uint16& value, const char* name = "", const char* label = 0);
bool operator()(int32& value, const char* name = "", const char* label = 0);
bool operator()(uint32& value, const char* name = "", const char* label = 0);
bool operator()(int64& value, const char* name = "", const char* label = 0);
bool operator()(uint64& value, const char* name = "", const char* label = 0);
bool operator()(char& value, const char* name = "", const char* label = 0);
bool operator()(int8& value, const char* name = "", const char* label = 0);
bool operator()(uint8& value, const char* name = "", const char* label = 0);
bool operator()(const SStruct& ser, const char* name = "", const char* label = 0);
bool operator()(const SBlackBox& box, const char* name = "", const char* label = 0);
bool operator()(IContainer& ser, const char* name = "", const char* label = 0);
bool operator()(IKeyValue& keyValue, const char* name = "", const char* label = 0);
bool operator()(IPointer& ser, const char* name = "", const char* label = 0);
// ^^^
using IArchive::operator();
private:
void openBracket();
void closeBracket();
void openContainerBracket();
void closeContainerBracket();
void placeName(const char* name);
void placeIndent(bool putComma = true);
void placeIndentCompact(bool putComma = true);
bool joinLinesIfPossible();
struct Level
{
Level(bool _isContainer, std::size_t position, int column)
: isKeyValue(false)
, isContainer(_isContainer)
, isDictionary(false)
, startPosition(position)
, nameIndex(0)
, elementIndex(0)
, indentCount(-column)
{}
bool isKeyValue;
bool isContainer;
bool isDictionary;
std::size_t startPosition;
int nameIndex;
int elementIndex;
int indentCount;
};
typedef std::vector<Level> Stack;
Stack stack_;
std::unique_ptr<MemoryWriter> buffer_;
const char* header_;
int textWidth_;
string fileName_;
int compactOffset_;
bool isKeyValue_;
};
}
@@ -1,92 +0,0 @@
/*
* 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.
#include "CrySystem_precompiled.h"
#include <platform.h>
#include "Serialization/Assert.h"
#include "MemoryReader.h"
#include <stdlib.h>
#include <memory.h>
namespace Serialization {
MemoryReader::MemoryReader()
: size_(0)
, position_(0)
, memory_(0)
, ownedMemory_(false)
{
}
MemoryReader::MemoryReader(const void* memory, std::size_t size, bool ownAndFree)
: size_(size)
, position_((const char*)(memory))
, memory_((const char*)(memory))
, ownedMemory_(ownAndFree)
{
}
MemoryReader::~MemoryReader()
{
if (ownedMemory_)
{
free(const_cast<char*>(memory_));
memory_ = 0;
size_ = 0;
}
}
void MemoryReader::setPosition(const char* position)
{
position_ = position;
}
void MemoryReader::read(void* data, std::size_t size)
{
YASLI_ASSERT(memory_ && position_);
YASLI_ASSERT(position_ - memory_ + size <= size_);
memcpy(data, position_, size);
position_ += size;
}
bool MemoryReader::checkedRead(void* data, std::size_t size)
{
if (!memory_ || !position_)
{
return false;
}
if (position_ - memory_ + size > size_)
{
return false;
}
memcpy(data, position_, size);
position_ += size;
return true;
}
bool MemoryReader::checkedSkip(std::size_t size)
{
if (!memory_ || !position_)
{
return false;
}
if (position_ - memory_ + size > size_)
{
return false;
}
position_ += size;
return true;
}
}
@@ -1,56 +0,0 @@
/*
* 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.
#pragma once
#include <cstddef>
namespace Serialization {
class MemoryReader
{
public:
MemoryReader();
MemoryReader(const void* memory, size_t size, bool ownAndFree = false);
~MemoryReader();
void setPosition(const char* position);
const char* position(){ return position_; }
template<class T>
void read(T& value)
{
read(reinterpret_cast<void*>(&value), sizoef(value));
}
void read(void* data, size_t size);
bool checkedSkip(size_t size);
bool checkedRead(void* data, size_t size);
template<class T>
bool checkedRead(T& t)
{
return checkedRead((void*)&t, sizeof(t));
}
const char* buffer() const{ return memory_; }
size_t size() const{ return size_; }
const char* begin() const{ return memory_; }
const char* end() const{ return memory_ + size_; }
private:
size_t size_;
const char* position_;
const char* memory_;
bool ownedMemory_;
};
}
// vim:ts=4 sw=4:
@@ -1,236 +0,0 @@
/*
* 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.
#include "CrySystem_precompiled.h"
#include <platform.h>
#include "Serialization/Assert.h"
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <math.h>
#ifdef _MSC_VER
# include <float.h>
# define isnan _isnan
#endif
#include "MemoryWriter.h"
#undef YASLI_ASSERT
#define YASLI_ASSERT(x)
namespace Serialization {
MemoryWriter::MemoryWriter(std::size_t size, bool reallocate)
: size_(size)
, reallocate_(reallocate)
, digits_(5)
{
allocate(size);
}
MemoryWriter::~MemoryWriter()
{
position_ = 0;
CryModuleFree(memory_);
}
void MemoryWriter::allocate(std::size_t initialSize)
{
memory_ = (char*)CryModuleMalloc(initialSize + 1);
position_ = memory_;
}
void MemoryWriter::reallocate(std::size_t newSize)
{
YASLI_ASSERT(newSize > size_);
std::size_t pos = position();
// Supressing the warning as we generally don't handle malloc errors.
// cppcheck-suppress memleakOnRealloc
memory_ = (char*)CryModuleRealloc(memory_, newSize + 1);
YASLI_ASSERT(memory_ != 0);
position_ = memory_ + pos;
size_ = newSize;
}
MemoryWriter& MemoryWriter::operator<<(int value)
{
// TODO: optimize
char buffer[12];
sprintf_s(buffer, "%i", value);
return operator<<((const char*)buffer);
}
MemoryWriter& MemoryWriter::operator<<(long value)
{
// TODO: optimize
char buffer[12];
#ifdef _MSC_VER
sprintf_s(buffer, "%i", value);
#else
sprintf_s(buffer, "%li", value);
#endif
return operator<<((const char*)buffer);
}
MemoryWriter& MemoryWriter::operator<<(unsigned long value)
{
// TODO: optimize
char buffer[12];
#ifdef _MSC_VER
sprintf_s(buffer, "%u", value);
#else
sprintf_s(buffer, "%lu", value);
#endif
return operator<<((const char*)buffer);
}
MemoryWriter& MemoryWriter::operator<<(long long value)
{
// TODO: optimize
char buffer[24];
#ifdef _MSC_VER
sprintf_s(buffer, "%I64i", value);
#else
sprintf_s(buffer, "%lli", value);
#endif
return operator<<((const char*)buffer);
}
MemoryWriter& MemoryWriter::operator<<(unsigned long long value)
{
// TODO: optimize
char buffer[24];
sprintf_s(buffer, "%llu", value);
return operator<<((const char*)buffer);
}
MemoryWriter& MemoryWriter::operator<<(unsigned int value)
{
// TODO: optimize
char buffer[12];
sprintf_s(buffer, "%u", value);
return operator<<((const char*)buffer);
}
MemoryWriter& MemoryWriter::operator<<(char value)
{
char buffer[12];
sprintf_s(buffer, "%i", int(value));
return operator<<((const char*)buffer);
}
MemoryWriter& MemoryWriter::operator<<(unsigned char value)
{
char buffer[12];
sprintf_s(buffer, "%i", int(value));
return operator<<((const char*)buffer);
}
MemoryWriter& MemoryWriter::operator<<(signed char value)
{
char buffer[12];
sprintf_s(buffer, "%i", int(value));
return operator<<((const char*)buffer);
}
inline void cutRightZeros(const char* str)
{
for (char* p = (char*)str + strlen(str) - 1; p >= str; --p)
{
if (*p == '0')
{
*p = 0;
}
else
{
return;
}
}
}
MemoryWriter& MemoryWriter::operator<<(double value)
{
YASLI_ASSERT(!isnan(value));
char buf[64] = { 0 };
sprintf_s(buf, "%f", value);
operator<<(buf);
return *this;
}
MemoryWriter& MemoryWriter::operator<<(const char* value)
{
write((void*)value, strlen(value));
YASLI_ASSERT(position() < size());
*position_ = '\0';
return *this;
}
MemoryWriter& MemoryWriter::operator<<(const wchar_t* value)
{
write((void*)value, wcslen(value) * sizeof(wchar_t));
YASLI_ASSERT(position() < size());
*position_ = '\0';
return *this;
}
void MemoryWriter::setPosition(std::size_t pos)
{
YASLI_ASSERT(pos < size_);
YASLI_ASSERT(memory_ + pos <= position_);
position_ = memory_ + pos;
}
void MemoryWriter::write(const char* value)
{
write((void*)value, strlen(value));
}
bool MemoryWriter::write(const void* data, std::size_t size)
{
YASLI_ASSERT(memory_ <= position_);
YASLI_ASSERT(position() < this->size());
if (size_ - position() > size)
{
memcpy(position_, data, size);
position_ += size;
}
else
{
if (!reallocate_)
{
return false;
}
reallocate(size_ * 2);
write(data, size);
}
YASLI_ASSERT(position() < this->size());
return true;
}
void MemoryWriter::write(char c)
{
if (size_ - position() > 1)
{
*(char*)(position_) = c;
++position_;
}
else
{
YASLI_ESCAPE(reallocate_, return );
reallocate(size_ * 2);
write(c);
}
YASLI_ASSERT(position() < this->size());
}
}
@@ -1,72 +0,0 @@
/*
* 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.
#pragma once
#include <cstddef>
namespace Serialization {
class MemoryWriter
{
public:
MemoryWriter(std::size_t size = 128, bool reallocate = true);
~MemoryWriter();
const char* c_str() { return memory_; };
const wchar_t* w_str() { return (wchar_t*)memory_; };
char* buffer() { return memory_; }
const char* buffer() const { return memory_; }
std::size_t size() const{ return size_; }
void clear() { position_ = memory_; }
// String interface (after this calls '\0' is always written)
MemoryWriter& operator<<(int value);
MemoryWriter& operator<<(long value);
MemoryWriter& operator<<(unsigned long value);
MemoryWriter& operator<<(unsigned int value);
MemoryWriter& operator<<(long long value);
MemoryWriter& operator<<(unsigned long long value);
MemoryWriter& operator<<(float value) { return (*this) << double(value); }
MemoryWriter& operator<<(double value);
MemoryWriter& operator<<(signed char value);
MemoryWriter& operator<<(unsigned char value);
MemoryWriter& operator<<(char value);
MemoryWriter& operator<<(const char* value);
MemoryWriter& operator<<(const wchar_t* value);
// Binary interface (does not writes trailing '\0')
template<class T>
void write(const T& value)
{
write(reinterpret_cast<const T*>(&value), sizeof(value));
}
void write(char c);
void write(const char* str);
bool write(const void* data, std::size_t size);
std::size_t position() const{ return position_ - memory_; }
void setPosition(std::size_t pos);
MemoryWriter& setDigits(int digits) { digits_ = (unsigned char)digits; return *this; }
private:
void allocate(std::size_t initialSize);
void reallocate(std::size_t newSize);
std::size_t size_;
char* position_;
char* memory_;
bool reallocate_;
unsigned char digits_;
};
}
@@ -1,492 +0,0 @@
/*
* 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.
#include "CrySystem_precompiled.h"
#include <AzTest/AzTest.h>
#include <AzCore/UnitTest/TestTypes.h>
#include "ArchiveHost.h"
#include <Serialization/STL.h>
#include <Serialization/IArchive.h>
#include <Serialization/StringList.h>
#include <Serialization/SmartPtr.h>
#include <memory>
namespace Serialization
{
struct SMember
{
string name;
float weight;
SMember()
: weight(0.0f)
{}
void CheckEquality(const SMember& copy) const
{
EXPECT_TRUE(name == copy.name);
EXPECT_TRUE(weight == copy.weight);
}
void Change(int index)
{
name = "Changed name ";
name += (index % 10) + '0';
weight = float(index);
}
void Serialize(IArchive& ar)
{
ar(name, "name");
ar(weight, "weight");
}
};
class CPolyBase
: public _i_reference_target_t
{
public:
CPolyBase()
{
baseMember = "Regular base member";
}
virtual void Change()
{
baseMember = "Changed base member";
}
virtual void Serialize(IArchive& ar)
{
ar(baseMember, "baseMember");
}
virtual void CheckEquality(const CPolyBase* copy) const
{
EXPECT_TRUE(baseMember == copy->baseMember);
}
virtual bool IsDerivedA() const
{
return false;
}
virtual bool IsDerivedB() const
{
return false;
}
protected:
string baseMember;
};
class CPolyDerivedA
: public CPolyBase
{
public:
void Serialize(IArchive& ar)
{
CPolyBase::Serialize(ar);
ar(derivedMember, "derivedMember");
}
bool IsDerivedA() const override
{
return true;
}
void CheckEquality(const CPolyBase* copyBase) const
{
EXPECT_TRUE(copyBase->IsDerivedA());
const CPolyDerivedA* copy = (CPolyDerivedA*)copyBase;
EXPECT_TRUE(derivedMember == copy->derivedMember);
CPolyBase::CheckEquality(copyBase);
}
protected:
string derivedMember;
};
class CPolyDerivedB
: public CPolyBase
{
public:
CPolyDerivedB()
: derivedMember("B Derived")
{}
bool IsDerivedB() const override
{
return true;
}
void Serialize(IArchive& ar)
{
CPolyBase::Serialize(ar);
ar(derivedMember, "derivedMember");
}
void CheckEquality(const CPolyBase* copyBase) const
{
EXPECT_TRUE(copyBase->IsDerivedB());
const CPolyDerivedB* copy = (const CPolyDerivedB*)copyBase;
EXPECT_TRUE(derivedMember == copy->derivedMember);
CPolyBase::CheckEquality(copyBase);
}
protected:
string derivedMember;
};
struct SNumericTypes
{
SNumericTypes()
: m_bool(false)
, m_char(0)
, m_int8(0)
, m_uint8(0)
, m_int16(0)
, m_uint16(0)
, m_int32(0)
, m_uint32(0)
, m_int64(0)
, m_uint64(0)
, m_float(0.0f)
, m_double(0.0)
{}
void Change()
{
m_bool = true;
m_char = -1;
m_int8 = -2;
m_uint8 = 0xff - 3;
m_int16 = -6;
m_uint16 = 0xff - 7;
m_int32 = -4;
m_uint32 = -5;
m_int64 = -8ll;
m_uint64 = 9ull;
m_float = -10.0f;
m_double = -11.0;
}
void Serialize(IArchive& ar)
{
ar(m_bool, "bool");
ar(m_char, "char");
ar(m_int8, "int8");
ar(m_uint8, "uint8");
ar(m_int16, "int16");
ar(m_uint16, "uint16");
ar(m_int32, "int32");
ar(m_uint32, "uint32");
ar(m_int64, "int64");
ar(m_uint64, "uint64");
ar(m_float, "float");
ar(m_double, "double");
}
void CheckEquality(const SNumericTypes& rhs) const
{
EXPECT_TRUE(m_bool == rhs.m_bool);
EXPECT_TRUE(m_char == rhs.m_char);
EXPECT_TRUE(m_int8 == rhs.m_int8);
EXPECT_TRUE(m_uint8 == rhs.m_uint8);
EXPECT_TRUE(m_int16 == rhs.m_int16);
EXPECT_TRUE(m_uint16 == rhs.m_uint16);
EXPECT_TRUE(m_int32 == rhs.m_int32);
EXPECT_TRUE(m_uint32 == rhs.m_uint32);
EXPECT_TRUE(m_int64 == rhs.m_int64);
EXPECT_TRUE(m_uint64 == rhs.m_uint64);
EXPECT_TRUE(m_float == rhs.m_float);
EXPECT_TRUE(m_double == rhs.m_double);
}
bool m_bool;
char m_char;
int8 m_int8;
uint8 m_uint8;
int16 m_int16;
uint16 m_uint16;
int32 m_int32;
uint32 m_uint32;
int64 m_int64;
uint64 m_uint64;
float m_float;
double m_double;
};
class CComplexClass
{
public:
CComplexClass()
: index(0)
{
name = "Foo";
stringList.push_back("Choice 1");
stringList.push_back("Choice 2");
stringList.push_back("Choice 3");
polyPtr.reset(new CPolyDerivedA());
polyVector.push_back(new CPolyDerivedB);
polyVector.push_back(new CPolyBase);
SMember& a = stringToStructMap["a"];
a.name = "A";
SMember& b = stringToStructMap["b"];
b.name = "B";
members.resize(13);
intToString.push_back(std::make_pair(1, "one"));
intToString.push_back(std::make_pair(2, "two"));
intToString.push_back(std::make_pair(3, "three"));
stringToInt.push_back(std::make_pair("one", 1));
stringToInt.push_back(std::make_pair("two", 2));
stringToInt.push_back(std::make_pair("three", 3));
}
void Change()
{
name = "Slightly changed name";
index = 2;
polyPtr.reset(new CPolyDerivedB());
polyPtr->Change();
for (size_t i = 0; i < members.size(); ++i)
{
members[i].Change(int(i));
}
members.erase(members.begin());
for (size_t i = 0; i < polyVector.size(); ++i)
{
polyVector[i]->Change();
}
polyVector.resize(4);
polyVector.push_back(new CPolyBase());
polyVector[4]->Change();
const size_t arrayLen = sizeof(array) / sizeof(array[0]);
for (size_t i = 0; i < arrayLen; ++i)
{
array[i].Change(int(arrayLen - i));
}
numericTypes.Change();
vectorOfStrings.push_back("str1");
vectorOfStrings.push_back("2str");
vectorOfStrings.push_back("thirdstr");
stringToStructMap.erase("a");
SMember& c = stringToStructMap["c"];
c.name = "C";
intToString.push_back(std::make_pair(4, "four"));
stringToInt.push_back(std::make_pair("four", 4));
}
void Serialize(IArchive& ar)
{
ar(name, "name");
ar(polyPtr, "polyPtr");
ar(polyVector, "polyVector");
ar(members, "members");
{
StringListValue value(stringList, stringList[index]);
ar(value, "stringList");
index = value.index();
if (index == -1)
{
index = 0;
}
}
ar(array, "array");
ar(numericTypes, "numericTypes");
ar(vectorOfStrings, "vectorOfStrings");
ar(stringToInt, "stringToInt");
}
void CheckEquality(const CComplexClass& copy) const
{
EXPECT_TRUE(name == copy.name);
EXPECT_TRUE(index == copy.index);
EXPECT_TRUE(polyPtr != 0);
EXPECT_TRUE(copy.polyPtr != 0);
polyPtr->CheckEquality(copy.polyPtr);
EXPECT_TRUE(members.size() == copy.members.size());
for (size_t i = 0; i < members.size(); ++i)
{
members[i].CheckEquality(copy.members[i]);
}
EXPECT_TRUE(polyVector.size() == copy.polyVector.size());
for (size_t i = 0; i < polyVector.size(); ++i)
{
if (polyVector[i] == 0)
{
EXPECT_TRUE(copy.polyVector[i] == 0);
continue;
}
EXPECT_TRUE(copy.polyVector[i] != 0);
polyVector[i]->CheckEquality(copy.polyVector[i]);
}
const size_t arrayLen = sizeof(array) / sizeof(array[0]);
for (size_t i = 0; i < arrayLen; ++i)
{
array[i].CheckEquality(copy.array[i]);
}
numericTypes.CheckEquality(copy.numericTypes);
EXPECT_TRUE(stringToInt.size() == copy.stringToInt.size());
for (size_t i = 0; i < stringToInt.size(); ++i)
{
EXPECT_TRUE(stringToInt[i] == copy.stringToInt[i]);
}
}
protected:
string name;
typedef std::vector<SMember> Members;
std::vector<string> vectorOfStrings;
std::vector<std::pair<int, string> > intToString;
std::vector<std::pair<string, int> > stringToInt;
Members members;
int32 index;
SNumericTypes numericTypes;
StringListStatic stringList;
std::vector< _smart_ptr<CPolyBase> > polyVector;
_smart_ptr<CPolyBase> polyPtr;
std::map<string, SMember> stringToStructMap;
SMember array[5];
};
struct ArchiveHostTests
: ::testing::Test
{
public:
void SetUp() override
{
AZ::AllocatorInstance<AZ::LegacyAllocator>::Create();
AZ::AllocatorInstance<CryStringAllocator>::Create();
m_classFactoryRTTI = AZStd::make_unique<ClassFactoryRTTI>();
}
void TearDown()
{
m_classFactoryRTTI.reset();
AZ::AllocatorInstance<CryStringAllocator>::Destroy();
AZ::AllocatorInstance<AZ::LegacyAllocator>::Destroy();
}
struct ClassFactoryRTTI
{
ClassFactoryRTTI()
: CPolyBaseCPolyBase_DerivedDescription("base", "Base")
, CPolyBaseCPolyBase_Creator(&CPolyBaseCPolyBase_DerivedDescription)
, TypeCPolyBase_DerivedDescription("derived_a", "Derived A")
, TypeCPolyBase_Creator(&TypeCPolyBase_DerivedDescription)
, CPolyDerivedBCPolyBase_DerivedDescription("derived_b", "Derived B")
, CPolyDerivedBCPolyBase_Creator(&CPolyDerivedBCPolyBase_DerivedDescription)
{}
~ClassFactoryRTTI()
{
Serialization::ClassFactory<CPolyBase>::destroy();
}
const Serialization::TypeDescription CPolyBaseCPolyBase_DerivedDescription;
Serialization::ClassFactory<CPolyBase>::Creator<CPolyBase> CPolyBaseCPolyBase_Creator;
const Serialization::TypeDescription TypeCPolyBase_DerivedDescription;
Serialization::ClassFactory<CPolyBase>::Creator<CPolyDerivedA> TypeCPolyBase_Creator;
const Serialization::TypeDescription CPolyDerivedBCPolyBase_DerivedDescription;
Serialization::ClassFactory<CPolyBase>::Creator<CPolyDerivedB> CPolyDerivedBCPolyBase_Creator;
};
AZStd::unique_ptr<ClassFactoryRTTI> m_classFactoryRTTI;
};
TEST_F(ArchiveHostTests, JsonBasicTypes)
{
std::unique_ptr<IArchiveHost> host(CreateArchiveHost());
DynArray<char> bufChanged;
CComplexClass objChanged;
objChanged.Change();
host->SaveJsonBuffer(bufChanged, SStruct(objChanged));
EXPECT_TRUE(!bufChanged.empty());
DynArray<char> bufResaved;
{
CComplexClass obj;
EXPECT_TRUE(host->LoadJsonBuffer(SStruct(obj), bufChanged.data(), bufChanged.size()));
EXPECT_TRUE(host->SaveJsonBuffer(bufResaved, SStruct(obj)));
EXPECT_TRUE(!bufResaved.empty());
obj.CheckEquality(objChanged);
}
EXPECT_TRUE(bufChanged.size() == bufResaved.size());
for (size_t i = 0; i < bufChanged.size(); ++i)
{
EXPECT_TRUE(bufChanged[i] == bufResaved[i]);
}
}
TEST_F(ArchiveHostTests, BinBasicTypes)
{
std::unique_ptr<IArchiveHost> host(CreateArchiveHost());
DynArray<char> bufChanged;
CComplexClass objChanged;
objChanged.Change();
host->SaveBinaryBuffer(bufChanged, SStruct(objChanged));
EXPECT_TRUE(!bufChanged.empty());
DynArray<char> bufResaved;
{
CComplexClass obj;
EXPECT_TRUE(host->LoadBinaryBuffer(SStruct(obj), bufChanged.data(), bufChanged.size()));
EXPECT_TRUE(host->SaveBinaryBuffer(bufResaved, SStruct(obj)));
EXPECT_TRUE(!bufResaved.empty());
obj.CheckEquality(objChanged);
}
EXPECT_TRUE(bufChanged.size() == bufResaved.size());
for (size_t i = 0; i < bufChanged.size(); ++i)
{
EXPECT_TRUE(bufChanged[i] == bufResaved[i]);
}
}
}
@@ -1,89 +0,0 @@
/*
* 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.
#pragma once
#include <string.h>
#include "Serialization/Strings.h"
namespace Serialization {
struct Token
{
Token(const char* _str = 0)
: start(_str)
, end(_str ? _str + strlen(_str) : 0)
{
}
Token(const char* _str, size_t _len)
: start(_str)
, end(_str + _len) {}
Token(const char* _start, const char* _end)
: start(_start)
, end(_end) {}
void set(const char* _start, const char* _end) { start = _start; end = _end; }
std::size_t length() const{ return end - start; }
bool operator==(const Token& rhs) const
{
if (length() != rhs.length())
{
return false;
}
return memcmp(start, rhs.start, length()) == 0;
}
bool operator==(const string& rhs) const
{
if (length() != rhs.size())
{
return false;
}
return memcmp(start, rhs.c_str(), length()) == 0;
}
bool operator==(const char* text) const
{
if (strncmp(text, start, length()) == 0)
{
return text[length()] == '\0';
}
return false;
}
bool operator!=(const char* text) const
{
if (strncmp(text, start, length()) == 0)
{
return text[length()] != '\0';
}
return true;
}
bool operator==(char c) const
{
return length() == 1 && *start == c;
}
bool operator!=(char c) const
{
return length() != 1 || *start != c;
}
operator bool() const{
return start != end;
}
string str() const{ return string(start, end); }
const char* start;
const char* end;
};
}
@@ -1,297 +0,0 @@
/*
* 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.
#include "CrySystem_precompiled.h"
#include "CryExtension/Impl/ClassWeaver.h"
#include <Serialization/STL.h>
#include <Serialization/ClassFactory.h>
#include "XmlIArchive.h"
#include <Serialization/STLImpl.h>
#include <Serialization/ClassFactoryImpl.h>
namespace XmlUtil
{
int g_hintSuccess = 0;
int g_hintFail = 0;
XmlNodeRef FindChildNode(XmlNodeRef pParent, const int childIndexOverride, int& childIndexHint, const char* const name)
{
CRY_ASSERT(pParent);
if (0 <= childIndexOverride)
{
CRY_ASSERT(childIndexOverride < pParent->getChildCount());
return pParent->getChild(childIndexOverride);
}
else
{
CRY_ASSERT(name);
CRY_ASSERT(name[ 0 ]);
CRY_ASSERT(0 <= childIndexHint);
const int childCount = pParent->getChildCount();
const bool hasValidChildHint = (childIndexHint < childCount);
if (hasValidChildHint)
{
XmlNodeRef pChildNode = pParent->getChild(childIndexHint);
if (pChildNode->isTag(name))
{
g_hintSuccess++;
const int nextChildIndexHint = childIndexHint + 1;
childIndexHint = (nextChildIndexHint < childCount) ? nextChildIndexHint : 0;
return pChildNode;
}
else
{
g_hintFail++;
}
}
for (int i = 0; i < childCount; ++i)
{
XmlNodeRef pChildNode = pParent->getChild(i);
if (pChildNode->isTag(name))
{
const int nextChildIndexHint = i + 1;
childIndexHint = (nextChildIndexHint < childCount) ? nextChildIndexHint : 0;
return pChildNode;
}
}
}
return XmlNodeRef();
}
template< typename T, typename TOut >
bool ReadChildNodeAs(XmlNodeRef pParent, const int childIndexOverride, int& childIndexHint, const char* const name, TOut& valueOut)
{
XmlNodeRef pChild = FindChildNode(pParent, childIndexOverride, childIndexHint, name);
if (pChild)
{
T tmp;
const bool readValueSuccess = pChild->getAttr("value", tmp);
if (readValueSuccess)
{
valueOut = tmp;
}
return readValueSuccess;
}
return false;
}
template< typename T >
bool ReadChildNode(XmlNodeRef pParent, const int childIndexOverride, int& childIndexHint, const char* const name, T& valueOut)
{
return ReadChildNodeAs< T >(pParent, childIndexOverride, childIndexHint, name, valueOut);
}
}
Serialization::CXmlIArchive::CXmlIArchive()
: IArchive(INPUT | NO_EMPTY_NAMES)
, m_childIndexOverride(-1)
, m_childIndexHint(0)
{
}
Serialization::CXmlIArchive::CXmlIArchive(XmlNodeRef pRootNode)
: IArchive(INPUT | NO_EMPTY_NAMES)
, m_pRootNode(pRootNode)
, m_childIndexOverride(-1)
, m_childIndexHint(0)
{
CRY_ASSERT(m_pRootNode);
}
Serialization::CXmlIArchive::~CXmlIArchive()
{
}
void Serialization::CXmlIArchive::SetXmlNode(XmlNodeRef pNode)
{
m_pRootNode = pNode;
}
XmlNodeRef Serialization::CXmlIArchive::GetXmlNode() const
{
return m_pRootNode;
}
bool Serialization::CXmlIArchive::operator()(bool& value, const char* name, [[maybe_unused]] const char* label)
{
XmlNodeRef pChild = XmlUtil::FindChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name);
if (pChild)
{
const char* const stringValue = pChild->getAttr("value");
if (stringValue)
{
value = (strcmp("true", stringValue) == 0);
value = value || (strcmp("1", stringValue) == 0);
return true;
}
return false;
}
return false;
}
bool Serialization::CXmlIArchive::operator()(IString& value, const char* name, [[maybe_unused]] const char* label)
{
XmlNodeRef pChild = XmlUtil::FindChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name);
if (pChild)
{
const char* const stringValue = pChild->getAttr("value");
if (stringValue)
{
value.set(stringValue);
return true;
}
return false;
}
return false;
}
bool Serialization::CXmlIArchive::operator()([[maybe_unused]] IWString& value, [[maybe_unused]] const char* name, [[maybe_unused]] const char* label)
{
CryFatalError("CXmlIArchive::operator() with IWString is not implemented");
return false;
}
bool Serialization::CXmlIArchive::operator()(float& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(double& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(int16& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNodeAs< int >(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(uint16& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNodeAs< uint >(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(int32& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(uint32& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(int64& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(uint64& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(int8& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNodeAs< int >(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(uint8& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNodeAs< uint >(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(char& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::ReadChildNodeAs< int >(m_pRootNode, m_childIndexOverride, m_childIndexHint, name, value);
}
bool Serialization::CXmlIArchive::operator()(const SStruct& ser, const char* name, [[maybe_unused]] const char* label)
{
CRY_ASSERT(name);
CRY_ASSERT(name[ 0 ]);
XmlNodeRef pChild = XmlUtil::FindChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name);
if (pChild)
{
CXmlIArchive childArchive(pChild);
childArchive.SetFilter(GetFilter());
childArchive.SetInnerContext(GetInnerContext());
const bool serializeSuccess = ser(childArchive);
return serializeSuccess;
}
return false;
}
bool Serialization::CXmlIArchive::operator()(IContainer& ser, const char* name, [[maybe_unused]] const char* label)
{
CRY_ASSERT(name);
CRY_ASSERT(name[ 0 ]);
bool serializeSuccess = true;
XmlNodeRef pChild = XmlUtil::FindChildNode(m_pRootNode, m_childIndexOverride, m_childIndexHint, name);
if (pChild)
{
const int elementCount = pChild->getChildCount();
ser.resize(elementCount);
if (0 < elementCount)
{
CXmlIArchive childArchive(pChild);
childArchive.SetFilter(GetFilter());
childArchive.SetInnerContext(GetInnerContext());
for (int i = 0; i < elementCount; ++i)
{
childArchive.m_childIndexOverride = i;
serializeSuccess &= ser(childArchive, "Element", "Element");
ser.next();
}
}
}
return serializeSuccess;
}
@@ -1,62 +0,0 @@
/*
* 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 __XML_I_ARCHIVE__H__
#define __XML_I_ARCHIVE__H__
#include <Serialization/IArchive.h>
namespace Serialization
{
class CXmlIArchive
: public IArchive
{
public:
CXmlIArchive();
CXmlIArchive(XmlNodeRef pRootNode);
~CXmlIArchive();
void SetXmlNode(XmlNodeRef pNode);
XmlNodeRef GetXmlNode() const;
// IArchive
bool operator()(bool& value, const char* name = "", const char* label = 0) override;
bool operator()(IString& value, const char* name = "", const char* label = 0) override;
bool operator()(IWString& value, const char* name = "", const char* label = 0) override;
bool operator()(float& value, const char* name = "", const char* label = 0) override;
bool operator()(double& value, const char* name = "", const char* label = 0) override;
bool operator()(int16& value, const char* name = "", const char* label = 0) override;
bool operator()(uint16& value, const char* name = "", const char* label = 0) override;
bool operator()(int32& value, const char* name = "", const char* label = 0) override;
bool operator()(uint32& value, const char* name = "", const char* label = 0) override;
bool operator()(int64& value, const char* name = "", const char* label = 0) override;
bool operator()(uint64& value, const char* name = "", const char* label = 0) override;
bool operator()(int8& value, const char* name = "", const char* label = 0) override;
bool operator()(uint8& value, const char* name = "", const char* label = 0) override;
bool operator()(char& value, const char* name = "", const char* label = 0) override;
bool operator()(const SStruct& ser, const char* name = "", const char* label = 0) override;
bool operator()(IContainer& ser, const char* name = "", const char* label = 0) override;
// ~IArchive
using IArchive::operator();
private:
XmlNodeRef m_pRootNode;
int m_childIndexOverride;
int m_childIndexHint;
};
}
#endif
@@ -1,213 +0,0 @@
/*
* 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.
#include "CrySystem_precompiled.h"
#include "CryExtension/Impl/ClassWeaver.h"
#include <Serialization/STL.h>
#include <Serialization/IClassFactory.h>
#include "XmlOArchive.h"
#include <Serialization/STLImpl.h>
#include <Serialization/ClassFactory.h>
namespace XmlUtil
{
XmlNodeRef CreateChildNode(XmlNodeRef pParent, const char* const name)
{
CRY_ASSERT(pParent);
CRY_ASSERT(name);
CRY_ASSERT(name[ 0 ]);
XmlNodeRef pChild = pParent->createNode(name);
CRY_ASSERT(pChild);
pParent->addChild(pChild);
return pChild;
}
template < typename T, typename TIn >
bool WriteChildNodeAs(XmlNodeRef pParent, const char* const name, const TIn& value)
{
XmlNodeRef pChild = XmlUtil::CreateChildNode(pParent, name);
CRY_ASSERT(pChild);
pChild->setAttr("value", static_cast< T >(value));
return true;
}
template < typename T >
bool WriteChildNode(XmlNodeRef pParent, const char* const name, const T& value)
{
return WriteChildNodeAs< T >(pParent, name, value);
}
}
Serialization::CXmlOArchive::CXmlOArchive()
: IArchive(OUTPUT | NO_EMPTY_NAMES)
{
}
Serialization::CXmlOArchive::CXmlOArchive(XmlNodeRef pRootNode)
: IArchive(OUTPUT | NO_EMPTY_NAMES)
, m_pRootNode(pRootNode)
{
CRY_ASSERT(m_pRootNode);
}
Serialization::CXmlOArchive::~CXmlOArchive()
{
}
void Serialization::CXmlOArchive::SetXmlNode(XmlNodeRef pNode)
{
m_pRootNode = pNode;
}
XmlNodeRef Serialization::CXmlOArchive::GetXmlNode() const
{
return m_pRootNode;
}
bool Serialization::CXmlOArchive::operator()(bool& value, const char* name, [[maybe_unused]] const char* label)
{
const char* const stringValue = value ? "true" : "false";
return XmlUtil::WriteChildNode(m_pRootNode, name, stringValue);
}
bool Serialization::CXmlOArchive::operator()(IString& value, const char* name, [[maybe_unused]] const char* label)
{
const char* const stringValue = value.get();
return XmlUtil::WriteChildNode(m_pRootNode, name, stringValue);
}
bool Serialization::CXmlOArchive::operator()([[maybe_unused]] IWString& value, [[maybe_unused]] const char* name, [[maybe_unused]] const char* label)
{
CryFatalError("CXmlOArchive::operator() with IWString is not implemented");
return false;
}
bool Serialization::CXmlOArchive::operator()(float& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNode(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(double& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNode(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(int16& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNodeAs< int >(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(uint16& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNodeAs< uint >(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(int32& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNode(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(uint32& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNode(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(int64& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNode(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(uint64& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNode(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(int8& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNodeAs< int >(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(uint8& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNodeAs< uint >(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(char& value, const char* name, [[maybe_unused]] const char* label)
{
return XmlUtil::WriteChildNodeAs< int >(m_pRootNode, name, value);
}
bool Serialization::CXmlOArchive::operator()(const SStruct& ser, const char* name, [[maybe_unused]] const char* label)
{
CRY_ASSERT(name);
CRY_ASSERT(name[ 0 ]);
XmlNodeRef pChild = XmlUtil::CreateChildNode(m_pRootNode, name);
CXmlOArchive childArchive(pChild);
childArchive.SetFilter(GetFilter());
childArchive.SetInnerContext(GetInnerContext());
const bool serializeSuccess = ser(childArchive);
return serializeSuccess;
}
bool Serialization::CXmlOArchive::operator()(IContainer& ser, const char* name, [[maybe_unused]] const char* label)
{
CRY_ASSERT(name);
CRY_ASSERT(name[ 0 ]);
bool serializeSuccess = true;
XmlNodeRef pChild = XmlUtil::CreateChildNode(m_pRootNode, name);
CXmlOArchive childArchive(pChild);
childArchive.SetFilter(GetFilter());
childArchive.SetInnerContext(GetInnerContext());
const size_t containerSize = ser.size();
if (0 < containerSize)
{
do
{
serializeSuccess &= ser(childArchive, "Element", "Element");
} while (ser.next());
}
return serializeSuccess;
}
@@ -1,60 +0,0 @@
/*
* 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 __XML_O_ARCHIVE__H__
#define __XML_O_ARCHIVE__H__
#include <Serialization/IArchive.h>
namespace Serialization
{
class CXmlOArchive
: public IArchive
{
public:
CXmlOArchive();
CXmlOArchive(XmlNodeRef pRootNode);
~CXmlOArchive();
void SetXmlNode(XmlNodeRef pNode);
XmlNodeRef GetXmlNode() const;
// IArchive
bool operator()(bool& value, const char* name = "", const char* label = 0) override;
bool operator()(IString& value, const char* name = "", const char* label = 0) override;
bool operator()(IWString& value, const char* name = "", const char* label = 0) override;
bool operator()(float& value, const char* name = "", const char* label = 0) override;
bool operator()(double& value, const char* name = "", const char* label = 0) override;
bool operator()(int16& value, const char* name = "", const char* label = 0) override;
bool operator()(uint16& value, const char* name = "", const char* label = 0) override;
bool operator()(int32& value, const char* name = "", const char* label = 0) override;
bool operator()(uint32& value, const char* name = "", const char* label = 0) override;
bool operator()(int64& value, const char* name = "", const char* label = 0) override;
bool operator()(uint64& value, const char* name = "", const char* label = 0) override;
bool operator()(int8& value, const char* name = "", const char* label = 0) override;
bool operator()(uint8& value, const char* name = "", const char* label = 0) override;
bool operator()(char& value, const char* name = "", const char* label = 0) override;
bool operator()(const SStruct& ser, const char* name = "", const char* label = 0) override;
bool operator()(IContainer& ser, const char* name = "", const char* label = 0) override;
// ~IArchive
using IArchive::operator();
private:
XmlNodeRef m_pRootNode;
};
}
#endif
File diff suppressed because it is too large Load Diff
-475
View File
@@ -1,475 +0,0 @@
/*
* 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.
// Description : Service network implementation
#pragma once
//-----------------------------------------------------------------------------
#include "IServiceNetwork.h"
#include <AzCore/Socket/AzSocket_fwd.h>
class CServiceNetwork;
//-----------------------------------------------------------------------------
// General message buffer
class CServiceNetworkMessage
: public IServiceNetworkMessage
{
private:
void* m_pData;
uint32 m_id;
uint32 m_size;
int volatile m_refCount;
public:
CServiceNetworkMessage(const uint32 id, const uint32 size);
virtual ~CServiceNetworkMessage();
// IServiceNetworMessage interface
virtual uint32 GetId() const;
virtual uint32 GetSize() const;
virtual void* GetPointer();
virtual const void* GetPointer() const;
virtual struct IDataReadStream* CreateReader() const;
virtual void AddRef();
virtual void Release();
};
//-----------------------------------------------------------------------------
// General network TCP/IP connection
class CServiceNetworkConnection
: public IServiceNetworkConnection
{
public:
friend class CServiceNetworkListener;
// maximum size of a single message (0.5MB by default)
static const uint32 kMaximumMessageSize = 5 << 19;
// initialization message send period (ms)
static const uint64 kInitializationPerior = 1000;
// keep alive period (ms), by default every 2s
static const uint64 kKeepAlivePeriod = 2000;
// reconnection retries period (ms)
static const uint64 kReconnectTryPerior = 1000;
// timeout for assuming server side connection dead (reconnection timeout)
static const uint64 hReconnectTimeOut = 30 * 1000;
// communication time out (ms)
static const uint64 kTimeout = 5000;
// Type of endpoint
enum EEndpoint
{
// This is the server side of the connection (on the side of the listening socket)
eEndpoint_Server,
// This is the client side of the connection (we connected to the listening socket)
eEndpoint_Client,
};
// Internal state machine
enum EState
{
// Connection is initializing
eState_Initializing,
// Connection is valid
eState_Valid,
// Operation on the socket failed (we may need to reconnect)
eState_Lost,
// Connection is closed
eState_Closed,
};
// Command IDs, do not change the numerical values
enum ECommand
{
// Data block command
eCommand_Data = 1,
// Keep alive command
eCommand_KeepAlive = 2,
// Initialize communication channel (sent only once)
eCommand_Initialize = 3,
};
#pragma pack(push)
#pragma pack(1)
struct Header
{
uint8 m_cmd;
uint32 m_size;
void Swap();
};
struct InitHeader
{
uint8 m_cmd;
uint8 m_pad0;
uint8 m_pad1;
uint8 m_pad2;
uint32 m_tryCount;
uint64 m_guid0;
uint64 m_guid1;
void Swap();
};
#pragma pack(pop)
private:
CServiceNetwork* m_pManager;
// Type of endpoint (client/server)
EEndpoint m_endpointType;
// Connection state (internal)
EState m_state;
// Reference count (updated using CryInterlocked* functions)
int volatile m_refCount;
// Internal socket data
AZSOCKET m_socket;
// Local address
ServiceNetworkAddress m_localAddress;
// Remote connection address
ServiceNetworkAddress m_remoteAddress;
// Internal connection ID (unique)
CryGUID m_connectionID;
// Internal time counters
uint64 m_lastReconnectTime;
uint64 m_lastKeepAliveSendTime;
uint64 m_lastMessageReceivedTime;
uint64 m_lastInitializationSendTime;
uint32 m_reconnectTryCount;
// Statistics (updated from threads using CryIntelocked* functions)
volatile uint32 m_statsNumPacketsSend;
volatile uint32 m_statsNumPacketsReceived;
volatile uint32 m_statsNumDataSend;
volatile uint32 m_statsNumDataReceived;
// Queue of messages to send (thread access possible)
typedef CryMT::CLocklessPointerQueue< CServiceNetworkMessage > TSendQueue;
CServiceNetworkMessage* m_pSendedMessages;
TSendQueue m_pSendQueue;
uint32 m_messageDataSentSoFar;
volatile int m_sendQueueDataSize;
// Queue of received message
typedef CryMT::CLocklessPointerQueue< CServiceNetworkMessage > TReceiveQueue;
TReceiveQueue m_pReceiveQueue;
uint32 m_receiveQueueDataSize;
uint32 m_messageDataReceivedSoFar;
uint32 m_messageReceiveLength;
// Message being received "right now"
CServiceNetworkMessage* m_pCurrentReceiveMessage;
uint32 m_messageDummyReadLength;
// External request to close this connection was issued
bool m_bCloseRequested;
// Do not accept any new data for sending or receiving
bool m_bDisableCommunication;
public:
ILINE bool IsInitialized() const
{
return m_state != eState_Initializing;
}
ILINE bool IsSendingQueueEmpty() const
{
return m_pSendQueue.empty();
}
ILINE CServiceNetwork* GetManager() const
{
return m_pManager;
}
public:
CServiceNetworkConnection(
class CServiceNetwork* manager,
EEndpoint endpointType,
AZSOCKET socket,
const CryGUID& connectionID,
const ServiceNetworkAddress& localAddress,
const ServiceNetworkAddress& remoteAddress);
virtual ~CServiceNetworkConnection();
// IServiceNetworkConnection interface implementation
virtual const ServiceNetworkAddress& GetRemoteAddress() const;
virtual const ServiceNetworkAddress& GetLocalAddress() const;
virtual const CryGUID& GetGUID() const;
virtual bool IsAlive() const;
virtual uint32 GetMessageSendCount() const;
virtual uint32 GetMessageReceivedCount() const;
virtual uint64 GetMessageSendDataSize() const;
virtual uint64 GetMessageReceivedDataSize() const;
virtual bool SendMsg(IServiceNetworkMessage* message);
virtual IServiceNetworkMessage* ReceiveMsg();
virtual void FlushAndClose(const uint32 timeout);
virtual void FlushAndWait();
virtual void Close();
virtual void AddRef();
virtual void Release();
// All remote connections are updated on the client side
// This is called from service network update thread, try not to call by hand :)
void Update();
private:
void ProcessSendingQueue();
void ProcessReceivingQueue();
// Keep alive message handling
void ProcessKeepAlive();
void SendKeepAlive(const uint64 currentNetworkTime);
bool HandleTimeout(const uint64 currentNetworkTime);
// Handle the reconnection request
bool HandleReconnect(AZSOCKET socket, const uint32 tryCount);
// General send/receive functions with error handling.
// If socket error occurs the connection will be put in the lost state.
uint32 TrySend(const void* dataBuffer, uint32 dataSize, bool autoHandleErrors);
// Internal receive function with error handling
uint32 TryReceive(void* dataBuffer, uint32 dataSize, bool autoHandleErrors);
// Try to reconnect to the remote address
bool TryReconnect();
// Try to send the initialization header
bool TryInitialize();
// Low-level socket shutdown (hash way)
void Shutdown();
// Reset the connection (put in the lost state and reconnect)
void Reset();
};
//-----------------------------------------------------------------------------
// TCP/IP listener
class CServiceNetworkListener
: public IServiceNetworkListener
{
typedef CServiceNetworkConnection::InitHeader TInitHeader;
struct PendingConnection
{
// Connection socket
AZSOCKET m_socket;
// Initialization of initialization header received so far
uint32 m_dataReceivedSoFar;
// Initialization header
TInitHeader m_initHeader;
// Remote address (as returned from accept)
ServiceNetworkAddress m_remoteAddress;
};
protected:
// Owner (the manager)
CServiceNetwork* m_pManager;
// Reference count, updated using CryInterlocked* functions
int volatile m_refCount;
// Listening socket
AZSOCKET m_socket;
// Local address (usually has the IP in 127.0.0.1:port form)
ServiceNetworkAddress m_localAddress;
// Request to close this listener was received
bool m_closeRequestReceived;
// Pending connections (but not yet initialized)
typedef std::vector< PendingConnection* > TPendingConnectionList;
TPendingConnectionList m_pPendingConnections;
// All active connections spawned from this listener
typedef std::vector< CServiceNetworkConnection* > TConnectionList;
TConnectionList m_pLocalConnections;
// Access lock for the class members (thread safe)
CryMutex m_accessLock;
public:
ILINE CServiceNetwork* GetManager() const
{
return m_pManager;
}
public:
CServiceNetworkListener(CServiceNetwork* pManager, AZSOCKET socket, const ServiceNetworkAddress& address);
virtual ~CServiceNetworkListener();
void Update();
// IServiceNetworkListener interface implementation
virtual const ServiceNetworkAddress& GetLocalAddress() const;
virtual uint32 GetConnectionCount() const;
virtual IServiceNetworkConnection* Accept();
virtual bool IsAlive() const;
virtual void AddRef();
virtual void Release();
virtual void Close();
private:
void ProcessIncomingConnections();
void ProcessPendingConnections();
};
//-----------------------------------------------------------------------------
// TCP/IP manager for service connection channels
class CServiceNetwork
: public IServiceNetwork
, public CryRunnable
{
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(ServiceNetwork_h)
#endif
protected:
struct ConnectionToClose
{
CServiceNetworkConnection* pConnection;
// timeout for forded close
uint64 maxWaitTime;
};
protected:
// Local listeners
typedef std::vector< CServiceNetworkListener* > TListenerArray;
TListenerArray m_pListeners;
// Local connections
typedef std::vector< CServiceNetworkConnection* > TConnectionArray;
TConnectionArray m_pConnections;
// Connections that are waiting for all of their data to be sent before closing
typedef std::vector< ConnectionToClose > TConnectionsToCloseArray;
TConnectionsToCloseArray m_connectionsToClose;
// We are running on threads, needed to sync the access to arrays
CryMutex m_accessMutex;
// Current network time (ms)
uint64 m_networkTime;
// Exit was requested
bool m_bExitRequested;
// Message verbose level
ICVar* m_pVerboseLevel;
// Thread
typedef CryThread< CServiceNetwork > TServiceNetworkThread;
TServiceNetworkThread* m_pThread;
// Buffer ID allocator (unique, incremented atomically using CryInterlockedIncrement)
volatile int m_bufferID;
// Random number generator for GUID creation
CRndGen m_guidGenerator;
// Send/Receive queue size limit
ICVar* m_pReceiveDataQueueLimit;
ICVar* m_pSendDataQueueLimit;
public:
ILINE const uint64 GetNetworkTime() const
{
return m_networkTime;
}
ILINE const CServiceNetwork* GetManager() const
{
return this;
}
ILINE const uint32 GetReceivedDataQueueLimit() const
{
return m_pReceiveDataQueueLimit->GetIVal();
}
ILINE const uint32 GetSendDataQueueLimit() const
{
return m_pSendDataQueueLimit->GetIVal();
}
public:
CServiceNetwork();
virtual ~CServiceNetwork();
// IServiceNetwork interface implementation
virtual void SetVerbosityLevel(const uint32 level);
virtual IServiceNetworkMessage* AllocMessageBuffer(const uint32 size);
virtual struct IDataWriteStream* CreateMessageWriter();
virtual struct IDataReadStream* CreateMessageReader(const void* pData, const uint32 dataSize);
virtual ServiceNetworkAddress GetHostAddress(const string& addressString, uint16 optionalPort = 0) const;
virtual IServiceNetworkListener* CreateListener(uint16 localPort);
virtual IServiceNetworkConnection* Connect(const ServiceNetworkAddress& remoteAddress);
// CryRunnable
virtual void Run();
virtual void Cancel();
// Register connection in the connection list (thread safe)
void RegisterConnection(CServiceNetworkConnection& con);
// Register connection for closing one all of the outgoing messages are sent
void RegisterForDeferredClose(CServiceNetworkConnection& con, const uint32 timeout);
// Debug print
#ifdef RELEASE
void Log([[maybe_unused]] const char* txt, ...) const {};
bool CheckVerbose([[maybe_unused]] const uint32 level) const { return false; }
#else
void Log(const char* txt, ...) const;
bool CheckVerbose(const uint32 level) const;
#endif
};
//-----------------------------------------------------------------------------
-5
View File
@@ -121,7 +121,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#include <IRenderer.h>
#include <IMovieSystem.h>
#include <ServiceNetwork.h>
#include <ILog.h>
#include <IAudioSystem.h>
#include <IProcess.h>
@@ -145,7 +144,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#include "LocalizedStringManager.h"
#include "XML/XmlUtils.h"
#include "Serialization/ArchiveHost.h"
#include "SystemEventDispatcher.h"
#include "ServerThrottle.h"
#include "ResourceManager.h"
@@ -445,7 +443,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
m_pXMLUtils = new CXmlUtils(this);
m_pArchiveHost = Serialization::CreateArchiveHost();
m_pMemoryManager = CryGetIMemoryManager();
m_pThreadTaskManager = new CThreadTaskManager;
m_pResourceManager = new CResourceManager;
@@ -499,7 +496,6 @@ CSystem::~CSystem()
CRY_ASSERT(m_windowMessageHandlers.empty() && "There exists a dangling window message handler somewhere");
SAFE_DELETE(m_pXMLUtils);
SAFE_DELETE(m_pArchiveHost);
SAFE_DELETE(m_pThreadTaskManager);
SAFE_DELETE(m_pResourceManager);
SAFE_DELETE(m_pSystemEventDispatcher);
@@ -671,7 +667,6 @@ void CSystem::ShutDown()
SAFE_DELETE(m_env.pResourceCompilerHelper);
SAFE_RELEASE(m_env.pMovieSystem);
SAFE_DELETE(m_env.pServiceNetwork);
SAFE_RELEASE(m_env.pLyShine);
SAFE_RELEASE(m_env.pCryFont);
if (m_env.pConsole)
-9
View File
@@ -42,7 +42,6 @@ namespace AzFramework
struct IConsoleCmdArgs;
class CServerThrottle;
struct ICryFactoryRegistryImpl;
struct IZLibCompressor;
class CWatchdogThread;
class CThreadManager;
@@ -486,8 +485,6 @@ public:
virtual IXmlUtils* GetXmlUtils();
//////////////////////////////////////////////////////////////////////////
virtual Serialization::IArchiveHost* GetArchiveHost() const { return m_pArchiveHost; }
void SetViewCamera(CCamera& Camera){ m_ViewCamera = Camera; }
CCamera& GetViewCamera() { return m_ViewCamera; }
@@ -584,15 +581,11 @@ public:
// static as memReplay needs it before CSystem has been setup - expose a ISystem interface to this function if you need it outside CrySystem
static void debug_GetCallStackRaw(void** callstack, uint32& callstackLength);
virtual ICryFactoryRegistry* GetCryFactoryRegistry() const;
public:
#if !defined(RELEASE)
void SetVersionInfo(const char* const szVersion);
#endif
virtual bool InitializeEngineModule(const char* dllName, const char* moduleClassName, const SSystemInitParams& initParams) override;
virtual bool UnloadEngineModule(const char* dllName, const char* moduleClassName);
virtual const IImageHandler* GetImageHandler() const override { return m_imageHandler.get(); }
void ShutdownModuleLibraries();
@@ -809,8 +802,6 @@ private: // ------------------------------------------------------
// XML Utils interface.
class CXmlUtils* m_pXMLUtils;
Serialization::IArchiveHost* m_pArchiveHost;
int m_iApplicationInstance;
//! to hold the values stored in system.cfg
-172
View File
@@ -46,8 +46,6 @@
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <IEngineModule.h>
#include <CryExtension/CryCreateClassInstance.h>
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
#include <AzCore/IO/Streamer/Streamer.h>
#include <AzCore/IO/Streamer/StreamerComponent.h>
@@ -113,16 +111,12 @@
#include "ResourceManager.h"
#include "MTSafeAllocator.h"
#include "NotificationNetwork.h"
#include "ExtensionSystem/CryFactoryRegistryImpl.h"
#include "ExtensionSystem/TestCases/TestExtensions.h"
#include "ProfileLogSystem.h"
#include "SoftCode/SoftCodeMgr.h"
#include "ZLibCompressor.h"
#include "ZLibDecompressor.h"
#include "ZStdDecompressor.h"
#include "LZ4Decompressor.h"
#include "ServiceNetwork.h"
#include "RemoteCommand.h"
#include "LevelSystem/LevelSystem.h"
#include "LevelSystem/SpawnableLevelSystem.h"
#include "ViewSystem/ViewSystem.h"
@@ -856,148 +850,6 @@ bool CSystem::UnloadDLL(const char* dllName)
return isSuccess;
}
//////////////////////////////////////////////////////////////////////////
bool CSystem::InitializeEngineModule(const char* dllName, const char* moduleClassName, const SSystemInitParams& initParams)
{
bool bResult = false;
stack_string msg;
msg = "Initializing ";
AZStd::string dll = dllName;
// Strip off Cry if the dllname is Cry<something>
if (dll.find("Cry") == 0)
{
msg += dll.substr(3).c_str();
}
else
{
msg += dllName;
}
msg += "...";
if (m_pUserCallback)
{
m_pUserCallback->OnInitProgress(msg.c_str());
}
AZ_TracePrintf(moduleClassName, "%s", msg.c_str());
IMemoryManager::SProcessMemInfo memStart, memEnd;
if (GetIMemoryManager())
{
GetIMemoryManager()->GetProcessMemInfo(memStart);
}
else
{
ZeroStruct(memStart);
}
stack_string dllfile = "";
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_16
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
dllfile.append(dllName);
#if defined(LINUX)
dllfile = "lib" + PathUtil::ReplaceExtension(dllfile, "so");
#ifndef LINUX
dllfile.MakeLower();
#endif
#elif defined(AZ_PLATFORM_MAC)
dllfile = "lib" + PathUtil::ReplaceExtension(dllfile, "dylib");
#elif defined(AZ_PLATFORM_IOS)
PathUtil::RemoveExtension(dllfile);
#else
dllfile = PathUtil::ReplaceExtension(dllfile, "dll");
#endif
#endif
#if !defined(AZ_MONOLITHIC_BUILD)
m_moduleDLLHandles.insert(std::make_pair(dllfile.c_str(), LoadDLL(dllfile.c_str())));
if (!m_moduleDLLHandles[dllfile.c_str()])
{
return bResult;
}
#endif // #if !defined(AZ_MONOLITHIC_BUILD)
AZStd::shared_ptr<IEngineModule> pModule;
if (CryCreateClassInstance(moduleClassName, pModule))
{
bResult = pModule->Initialize(m_env, initParams);
// After initializing the module, give it a chance to register any AZ console vars
// declared within the module.
pModule->RegisterConsoleVars();
}
if (GetIMemoryManager())
{
GetIMemoryManager()->GetProcessMemInfo(memEnd);
#if defined(AZ_ENABLE_TRACING)
uint64 memUsed = memEnd.WorkingSetSize - memStart.WorkingSetSize;
#endif
AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "Initializing %s %s, MemUsage=%uKb", dllName, pModule ? "done" : "failed", uint32(memUsed / 1024));
}
return bResult;
}
//////////////////////////////////////////////////////////////////////////
bool CSystem::UnloadEngineModule(const char* dllName, const char* moduleClassName)
{
bool isSuccess = false;
// Remove the factory.
ICryFactoryRegistryImpl* const pReg = static_cast<ICryFactoryRegistryImpl*>(GetCryFactoryRegistry());
if (pReg != nullptr)
{
ICryFactory* pICryFactory = pReg->GetFactory(moduleClassName);
if (pICryFactory != nullptr)
{
pReg->UnregisterFactory(pICryFactory);
}
}
stack_string msg;
msg = "Unloading ";
msg += dllName;
msg += "...";
AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "%s", msg.c_str());
stack_string dllfile = dllName;
#if defined(LINUX)
dllfile = "lib" + PathUtil::ReplaceExtension(dllfile, "so");
#ifndef LINUX
dllfile.MakeLower();
#endif
#elif defined(APPLE)
dllfile = "lib" + PathUtil::ReplaceExtension(dllfile, "dylib");
#else
dllfile = PathUtil::ReplaceExtension(dllfile, "dll");
#endif
#if !defined(AZ_MONOLITHIC_BUILD)
isSuccess = UnloadDLL(dllfile.c_str());
#endif // #if !defined(AZ_MONOLITHIC_BUILD)
return isSuccess;
}
//////////////////////////////////////////////////////////////////////////
void CSystem::ShutdownModuleLibraries()
{
@@ -1872,12 +1724,6 @@ bool CSystem::Init(const SSystemInitParams& startupParams)
AZ_Assert(CryMemory::IsHeapValid(), "Memory heap must be valid before continuing SystemInit.");
#ifdef EXTENSION_SYSTEM_INCLUDE_TESTCASES
TestExtensions(&CCryFactoryRegistryImpl::Access());
#endif
//_controlfp(0, _EM_INVALID|_EM_ZERODIVIDE | _PC_64 );
#if defined(WIN32) || defined(WIN64)
// check OS version - we only want to run on XP or higher - talk to Martin Mittring if you want to change this
{
@@ -2412,8 +2258,6 @@ AZ_POP_DISABLE_WARNING
}
InlineInitializationProcessing("CSystem::Init InitShine");
//////////////////////////////////////////////////////////////////////////
// CONSOLE
//////////////////////////////////////////////////////////////////////////
if (!InitConsole())
@@ -2421,22 +2265,6 @@ AZ_POP_DISABLE_WARNING
return false;
}
//////////////////////////////////////////////////////////////////////////
// SERVICE NETWORK
//////////////////////////////////////////////////////////////////////////
if (!startupParams.bSkipNetwork && !startupParams.bMinimal)
{
m_env.pServiceNetwork = new CServiceNetwork();
}
//////////////////////////////////////////////////////////////////////////
// REMOTE COMMAND SYTSTEM
//////////////////////////////////////////////////////////////////////////
if (!startupParams.bSkipNetwork && !startupParams.bMinimal)
{
m_env.pRemoteCommandManager = new CRemoteCommandManager();
}
if (m_pUserCallback)
{
m_pUserCallback->OnInitProgress("Initializing additional systems...");
-1
View File
@@ -28,7 +28,6 @@
#include <ISystem.h>
#include <ILog.h>
#include <IProcess.h>
#include <IRemoteCommand.h>
#include <IRenderAuxGeom.h>
#include "ConsoleHelpGen.h" // CConsoleHelpGen
@@ -55,13 +55,7 @@ set(FILES
SystemScheduler.h
UnixConsole.h
SystemInit.h
Serialization/MemoryReader.h
XML/ReadWriteXMLSink.h
Serialization/ArchiveHost.h
Serialization/MemoryWriter.h
Serialization/JSONIArchive.h
Serialization/JSONOArchive.h
Serialization/BinArchive.h
AZCrySystemInitLogSink.h
AZCoreLogSink.h
CmdLine.h
@@ -127,10 +121,6 @@ set(FILES
ThreadConfigManager.h
ThreadConfigManager.cpp
SystemThreading.cpp
ExtensionSystem/CryFactoryRegistryImpl.cpp
ExtensionSystem/CryFactoryRegistryImpl.h
ExtensionSystem/TestCases/TestExtensions.cpp
ExtensionSystem/TestCases/TestExtensions.h
ZLibCompressor.cpp
ZLibCompressor.h
SoftCode/SoftCodeMgr.cpp
@@ -141,14 +131,6 @@ set(FILES
RemoteConsole/RemoteConsole.h
RemoteConsole/RemoteConsole_impl.inl
RemoteConsole/RemoteConsole_none.inl
ServiceNetwork.cpp
ServiceNetwork.h
RemoteCommand.cpp
RemoteCommand.h
RemoteCommandHelpers.cpp
RemoteCommandHelpers.h
RemoteCommandServer.cpp
RemoteCommandClient.cpp
ZLibDecompressor.h
ZLibDecompressor.cpp
LZ4Decompressor.h
@@ -165,17 +147,6 @@ set(FILES
ViewSystem/ViewSystem.h
ZStdDecompressor.h
ZStdDecompressor.cpp
Serialization/ArchiveHost.cpp
Serialization/BinArchive.cpp
Serialization/JSONIArchive.cpp
Serialization/JSONOArchive.cpp
Serialization/MemoryReader.cpp
Serialization/MemoryWriter.cpp
Serialization/Token.h
Serialization/XmlIArchive.cpp
Serialization/XmlIArchive.h
Serialization/XmlOArchive.cpp
Serialization/XmlOArchive.h
StreamEngine/StreamAsyncFileRequest.cpp
StreamEngine/StreamAsyncFileRequest_Jobs.cpp
StreamEngine/StreamEngine.cpp
@@ -11,7 +11,6 @@
set(FILES
Components/MathConversionTests.cpp
Serialization/Test_ArchiveHost.cpp
Tests/Test_CLog.cpp
Tests/Test_CommandRegistration.cpp
Tests/Test_CryPrimitives.cpp