First pass, removing gridmate touchpoints from AzFramework and non inclusive terminology purge
This commit is contained in:
@@ -26,12 +26,9 @@
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
|
||||
#include <AzFramework/Script/ScriptComponent.h>
|
||||
#include <AzFramework/Script/ScriptNetBindings.h>
|
||||
|
||||
#include <AzFramework/Network/NetworkContext.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <GridMate/Replica/ReplicaChunk.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
|
||||
|
||||
@@ -429,83 +426,60 @@ namespace AzFramework
|
||||
{
|
||||
LSV_BEGIN(lua, 1);
|
||||
|
||||
// calling format __index(table,key)
|
||||
ScriptNetBindingTable* netBindingTable = reinterpret_cast<ScriptNetBindingTable*>(lua_touserdata(lua, lua_upvalueindex(1)));
|
||||
AZ::ScriptContext::FromNativeContext(lua)->Error(AZ::ScriptContext::ErrorType::Warning, true,
|
||||
"Property %s not found in entity table. Please push this property to your slice to avoid decrease in performance.", lua_tostring(lua, -1));
|
||||
int lookupKey = lua_gettop(lua);
|
||||
|
||||
bool readValue = false;
|
||||
|
||||
if (netBindingTable != nullptr)
|
||||
int lookupTable = lookupKey - 1;
|
||||
// This is a slow function and it's made slow so we don't cache any extra data.
|
||||
// This is done because this function will be called only the exported components
|
||||
// and script are not in sync and we added new properties.
|
||||
lua_getmetatable(lua, -2); // get the metatable which will be the top property table
|
||||
int entityProperties = lua_gettop(lua);
|
||||
if (lua_getmetatable(lua, -1) == 0) // get the metatable of the property which will be the original table
|
||||
{
|
||||
AZ_Error("ScriptComponent",netBindingTable->GetScriptContext() != nullptr,"ScriptNetBindingTable is missing ScriptContext.");
|
||||
AZ_Error("ScriptComponent",netBindingTable->GetScriptContext() == nullptr || netBindingTable->GetScriptContext()->NativeContext() == lua,"Trying to use a NetBindingTable in wrong lua context");
|
||||
|
||||
AZ::ScriptContext* scriptContext = netBindingTable->GetScriptContext();
|
||||
|
||||
if (scriptContext)
|
||||
{
|
||||
AZ::ScriptDataContext stackContext;
|
||||
scriptContext->ReadStack(stackContext);
|
||||
|
||||
readValue = netBindingTable->InspectTableValue(stackContext);
|
||||
}
|
||||
// we are looking at top level properties
|
||||
lua_pushvalue(lua, -2); // copy the key
|
||||
lua_rawget(lua, -2); // read the value
|
||||
}
|
||||
|
||||
if (!readValue)
|
||||
else
|
||||
{
|
||||
AZ::ScriptContext::FromNativeContext(lua)->Error(AZ::ScriptContext::ErrorType::Warning, true,
|
||||
"Property %s not found in entity table. Please push this property to your slice to avoid decrease in performance.", lua_tostring(lua, -1));
|
||||
int lookupKey = lua_gettop(lua);
|
||||
|
||||
int lookupTable = lookupKey - 1;
|
||||
// This is a slow function and it's made slow so we don't cache any extra data.
|
||||
// This is done because this function will be called only the exported components
|
||||
// and script are not in sync and we added new properties.
|
||||
lua_getmetatable(lua, -2); // get the metatable which will be the top property table
|
||||
int entityProperties = lua_gettop(lua);
|
||||
if (lua_getmetatable(lua, -1) == 0) // get the metatable of the property which will be the original table
|
||||
// we are looking into the sub table, so do a slow traversal
|
||||
int scriptProperties = lua_gettop(lua);
|
||||
if (!Properties__IndexFindSubtable(lua, lookupTable, entityProperties, scriptProperties))
|
||||
{
|
||||
// we are looking at top level properties
|
||||
lua_pushvalue(lua, -2); // copy the key
|
||||
lua_rawget(lua, -2); // read the value
|
||||
lua_pushnil(lua);
|
||||
return 1; // we did not find the table
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are looking into the sub table, so do a slow traversal
|
||||
int scriptProperties = lua_gettop(lua);
|
||||
if (!Properties__IndexFindSubtable(lua, lookupTable, entityProperties, scriptProperties))
|
||||
{
|
||||
lua_pushnil(lua);
|
||||
return 1; // we did not find the table
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushvalue(lua, lookupKey);
|
||||
lua_rawget(lua, -2);
|
||||
}
|
||||
}
|
||||
|
||||
if (lua_istable(lua, -1))
|
||||
{
|
||||
// if we are here the target table is on the top if the stack
|
||||
lua_pushstring(lua, ScriptComponent::DefaultFieldName);
|
||||
lua_pushvalue(lua, lookupKey);
|
||||
lua_rawget(lua, -2);
|
||||
if (lua_isnil(lua, -1))
|
||||
{
|
||||
// parent table is a group, pop the value and return the table
|
||||
lua_pop(lua, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate the value, so once the storage is done its on top of the stack, and returned
|
||||
lua_pushvalue(lua, -1);
|
||||
|
||||
// Push key, and then move it below the value
|
||||
lua_pushvalue(lua, lookupKey);
|
||||
lua_insert(lua, -2);
|
||||
|
||||
// Cache the value so that subsequent accesses to this property don't result in warnings
|
||||
lua_rawset(lua, lookupTable);
|
||||
}
|
||||
|
||||
if (lua_istable(lua, -1))
|
||||
{
|
||||
// if we are here the target table is on the top if the stack
|
||||
lua_pushstring(lua, ScriptComponent::DefaultFieldName);
|
||||
lua_rawget(lua, -2);
|
||||
if (lua_isnil(lua, -1))
|
||||
{
|
||||
// parent table is a group, pop the value and return the table
|
||||
lua_pop(lua, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate the value, so once the storage is done its on top of the stack, and returned
|
||||
lua_pushvalue(lua, -1);
|
||||
|
||||
// Push key, and then move it below the value
|
||||
lua_pushvalue(lua, lookupKey);
|
||||
lua_insert(lua, -2);
|
||||
|
||||
// Cache the value so that subsequent accesses to this property don't result in warnings
|
||||
lua_rawset(lua, lookupTable);
|
||||
|
||||
return 1;
|
||||
}
|
||||
//=========================================================================
|
||||
@@ -515,30 +489,7 @@ namespace AzFramework
|
||||
{
|
||||
LSV_BEGIN_VARIABLE(lua);
|
||||
|
||||
// calling format __newindex(table,key,value)
|
||||
ScriptNetBindingTable* netBindingTable = reinterpret_cast<ScriptNetBindingTable*>(lua_touserdata(lua, lua_upvalueindex(1)));
|
||||
if (netBindingTable != nullptr)
|
||||
{
|
||||
AZ_Error("ScriptContext",netBindingTable->GetScriptContext() != nullptr,"ScriptNetBindingTable is missing ScriptContext.");
|
||||
AZ_Error("ScriptContext",netBindingTable->GetScriptContext() == nullptr || netBindingTable->GetScriptContext()->NativeContext() == lua,"Trying to use a NetBindingTable in wrong lua context");
|
||||
|
||||
AZ::ScriptContext* scriptContext = netBindingTable->GetScriptContext();
|
||||
if (scriptContext)
|
||||
{
|
||||
AZ::ScriptDataContext stackContext;
|
||||
scriptContext->ReadStack(stackContext);
|
||||
|
||||
const bool assignedValue = netBindingTable->AssignTableValue(stackContext);
|
||||
if (assignedValue)
|
||||
{
|
||||
LSV_END_VARIABLE(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't assign the value above, we want
|
||||
// to raw set the value to avoid coming back in here.
|
||||
// We want to raw set the value to avoid coming back in here.
|
||||
lua_rawset(lua, 1);
|
||||
LSV_END_VARIABLE(-2);
|
||||
return 0;
|
||||
@@ -553,7 +504,6 @@ namespace AzFramework
|
||||
// [8/9/2013]
|
||||
//=========================================================================
|
||||
|
||||
const char* ScriptComponent::NetRPCFieldName = "NetRPCs";
|
||||
const char* ScriptComponent::DefaultFieldName = "default";
|
||||
|
||||
ScriptComponent::ScriptComponent()
|
||||
@@ -561,7 +511,6 @@ namespace AzFramework
|
||||
, m_contextId(AZ::ScriptContextIds::DefaultScriptContextId)
|
||||
, m_script(AZ::Data::AssetLoadBehavior::PreLoad)
|
||||
, m_table(LUA_NOREF)
|
||||
, m_netBindingTable(nullptr)
|
||||
{
|
||||
m_properties.m_name = "Properties";
|
||||
}
|
||||
@@ -573,8 +522,6 @@ namespace AzFramework
|
||||
ScriptComponent::~ScriptComponent()
|
||||
{
|
||||
m_properties.Clear();
|
||||
|
||||
delete m_netBindingTable;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -604,11 +551,6 @@ namespace AzFramework
|
||||
return m_properties.GetProperty(propertyName);
|
||||
}
|
||||
|
||||
const AZ::ScriptProperty* ScriptComponent::GetNetworkedScriptProperty(const char* propertyName) const
|
||||
{
|
||||
return m_netBindingTable->FindScriptProperty(propertyName);
|
||||
}
|
||||
|
||||
void ScriptComponent::Init()
|
||||
{
|
||||
// Grab the script context
|
||||
@@ -622,11 +564,6 @@ namespace AzFramework
|
||||
//=========================================================================
|
||||
void ScriptComponent::Activate()
|
||||
{
|
||||
if (m_isSyncEnabled && m_netBindingTable == nullptr)
|
||||
{
|
||||
m_netBindingTable = aznew ScriptNetBindingTable();
|
||||
}
|
||||
|
||||
// if we have valid asset listen for script asset events, like reload
|
||||
if (m_script.GetId().IsValid())
|
||||
{
|
||||
@@ -681,43 +618,6 @@ namespace AzFramework
|
||||
LoadScript();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ScriptComponent::GetNetworkBinding
|
||||
//=========================================================================
|
||||
GridMate::ReplicaChunkPtr ScriptComponent::GetNetworkBinding()
|
||||
{
|
||||
if (m_netBindingTable == nullptr)
|
||||
{
|
||||
m_netBindingTable = aznew ScriptNetBindingTable();
|
||||
}
|
||||
|
||||
return m_netBindingTable->GetNetworkBinding();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ScriptComponent::SetNetworkBinding
|
||||
//=========================================================================
|
||||
void ScriptComponent::SetNetworkBinding(GridMate::ReplicaChunkPtr chunk)
|
||||
{
|
||||
if (m_netBindingTable == nullptr)
|
||||
{
|
||||
m_netBindingTable = aznew ScriptNetBindingTable();
|
||||
}
|
||||
|
||||
m_netBindingTable->SetNetworkBinding(chunk);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ScriptComponent::UnbindFromNetwork
|
||||
//=========================================================================
|
||||
void ScriptComponent::UnbindFromNetwork()
|
||||
{
|
||||
if (m_netBindingTable)
|
||||
{
|
||||
m_netBindingTable->UnbindFromNetwork();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// LoadScript
|
||||
//=========================================================================
|
||||
@@ -741,11 +641,6 @@ namespace AzFramework
|
||||
AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::Script, "Unload: %s", m_script.GetHint().c_str());
|
||||
|
||||
DestroyEntityTable();
|
||||
|
||||
if (m_netBindingTable)
|
||||
{
|
||||
m_netBindingTable->Unload();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -798,12 +693,10 @@ namespace AzFramework
|
||||
// set the __index so we can read values in case we change the script
|
||||
// after we export the component
|
||||
lua_pushliteral(lua, "__index");
|
||||
lua_pushlightuserdata(lua, m_netBindingTable);
|
||||
lua_pushcclosure(lua, &Internal::Properties__Index, 1);
|
||||
lua_rawset(lua, -3);
|
||||
|
||||
lua_pushliteral(lua, "__newindex");
|
||||
lua_pushlightuserdata(lua, m_netBindingTable);
|
||||
lua_pushcclosure(lua, &Internal::Properties__NewIndex, 1);
|
||||
lua_rawset(lua, -3);
|
||||
}
|
||||
@@ -835,8 +728,7 @@ namespace AzFramework
|
||||
{
|
||||
const char* tableName = lua_tolstring(lua, -2, nullptr);
|
||||
if (strncmp(tableName, "__", 2) == 0 || // skip metatables
|
||||
strcmp(tableName, propertyTableName) == 0 || // Skip the Properties table
|
||||
strcmp(tableName, ScriptComponent::NetRPCFieldName) == 0) // Want to skip the RPC table as well
|
||||
strcmp(tableName, propertyTableName) == 0) // Skip the Properties table
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -904,13 +796,10 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
lua_createtable(lua, 0, 1); // Create entity table;
|
||||
int entityStackIndex = lua_gettop(lua);
|
||||
[[maybe_unused]] int entityStackIndex = lua_gettop(lua);
|
||||
|
||||
// Stack: ScriptRootTable PropertiesTable EntityTable
|
||||
|
||||
// Create our network binding.
|
||||
CreateNetworkBindingTable(baseStackIndex, entityStackIndex);
|
||||
|
||||
if (basePropertyTable > -1) // if property table exists
|
||||
{
|
||||
CreatePropertyGroup(m_properties, basePropertyTable, lua_gettop(lua), basePropertyTable, true);
|
||||
@@ -932,11 +821,6 @@ namespace AzFramework
|
||||
// Keep the entity table in the registry
|
||||
m_table = luaL_ref(lua, LUA_REGISTRYINDEX);
|
||||
|
||||
if (m_netBindingTable)
|
||||
{
|
||||
m_netBindingTable->FinalizeNetworkTable(m_context, m_table);
|
||||
}
|
||||
|
||||
// call OnActivate
|
||||
lua_pushliteral(lua, "OnActivate");
|
||||
lua_rawget(lua, baseStackIndex); // ScriptTable[OnActivate]
|
||||
@@ -993,18 +877,6 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// CreateNetworkBindingTable
|
||||
// [6/27/2016]
|
||||
//=========================================================================
|
||||
void ScriptComponent::CreateNetworkBindingTable(int baseStackIndex, int entityStackIndex)
|
||||
{
|
||||
if (m_netBindingTable)
|
||||
{
|
||||
m_netBindingTable->CreateNetworkBindingTable(m_context, baseStackIndex, entityStackIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// CreatePropertyGroup
|
||||
// [3/3/2014]
|
||||
@@ -1028,12 +900,10 @@ namespace AzFramework
|
||||
// Ensure that this instance of Properties table has the proper __index and __newIndex metamethods.
|
||||
lua_newtable(lua); // This new table will become the Properties instance metatable. Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {}
|
||||
lua_pushliteral(lua, "__index"); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {} __index
|
||||
lua_pushlightuserdata(lua, m_netBindingTable); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {} __index m_netBinding
|
||||
lua_pushcclosure(lua, &Internal::Properties__Index, 1); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {} __index function
|
||||
lua_rawset(lua, -3); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {__index=Internal::Properties__Index}
|
||||
|
||||
lua_pushliteral(lua, "__newindex");
|
||||
lua_pushlightuserdata(lua, m_netBindingTable);
|
||||
lua_pushcclosure(lua, &Internal::Properties__NewIndex, 1);
|
||||
lua_rawset(lua, -3); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {} {__index=Internal::Properties__Index __newindex=Internal::Properties__NewIndex}
|
||||
lua_setmetatable(lua, -2); // Stack: ScriptRootTable PropertiesTable EntityTable "Properties" {Meta{__index=Internal::Properties__Index __newindex=Internal::Properties__NewIndex} }
|
||||
@@ -1050,55 +920,6 @@ namespace AzFramework
|
||||
{
|
||||
AZ::ScriptProperty* prop = group.m_properties[i];
|
||||
|
||||
if (m_netBindingTable != nullptr)
|
||||
{
|
||||
lua_pushlstring(lua, prop->m_name.c_str(), prop->m_name.length());
|
||||
lua_rawget(lua, propertyGroupTableIndex);
|
||||
|
||||
// Stack: ... SomePropertyInThePropertiesTable. This may be any basic lua type (number, string, table etc)
|
||||
if (lua_istable(lua, -1))
|
||||
{
|
||||
bool isNetworkedProperty = false;
|
||||
|
||||
AZ::ScriptDataContext stackContext;
|
||||
|
||||
// If we find a table value. We want to inspect it for information.
|
||||
if (m_context->ReadStack(stackContext))
|
||||
{
|
||||
// check if the current property, which is a table, has a sub-table called "netSynched"
|
||||
lua_pushliteral(lua, "netSynched"); // Stack: ... SomePropertyInThePropertiesTable netSynched
|
||||
lua_rawget(lua, -2); // Stack: ... SomePropertyInThePropertiesTable NetSynchedSubTable/nil
|
||||
if (stackContext.IsTable(-1))
|
||||
{
|
||||
AZ::ScriptDataContext networkTableContext;
|
||||
if (stackContext.InspectTable(-1, networkTableContext)) // Stack: ... SomePropertyInThePropertiesTable NetSynchedSubTable NetSynchedSubTable nil nil
|
||||
{
|
||||
// RegisterDataSet will make sure our __NewIndex function callback will be triggered whenever modifying netSynched Properties.
|
||||
//isNetworkedProperty = true;
|
||||
isNetworkedProperty = m_netBindingTable->RegisterDataSet(networkTableContext, prop);
|
||||
}
|
||||
}
|
||||
|
||||
// Network binding table
|
||||
lua_pop(lua, 1); // Stack: ... SomePropertyInThePropertiesTable
|
||||
}
|
||||
|
||||
// Pop this PropertiesTable's property
|
||||
lua_pop(lua, 1);
|
||||
|
||||
// If the property is networked, we don't want to copy it over into the table.
|
||||
if (isNetworkedProperty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove the value we just pushed onto the stack
|
||||
lua_pop(lua, 1);
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushlstring(lua, prop->m_name.c_str(), prop->m_name.length());
|
||||
if (prop->Write(*m_context))
|
||||
{
|
||||
@@ -1157,7 +978,7 @@ namespace AzFramework
|
||||
return true;
|
||||
};
|
||||
|
||||
serializeContext->Class<ScriptComponent, AZ::Component, NetBindable>()
|
||||
serializeContext->Class<ScriptComponent, AZ::Component>()
|
||||
->Version(3, converter)
|
||||
->Field("ContextID", &ScriptComponent::m_contextId)
|
||||
->Field("Properties", &ScriptComponent::m_properties)
|
||||
@@ -1174,8 +995,6 @@ namespace AzFramework
|
||||
AZ::ScriptProperties::Reflect(reflection);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptNetBindingTable::Reflect(reflection);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/smart_ptr/intrusive_ptr.h>
|
||||
|
||||
#include <AzFramework/Network/NetBindable.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ScriptProperty;
|
||||
@@ -37,8 +35,6 @@ namespace AzToolsFramework
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class ScriptNetBindingTable;
|
||||
|
||||
struct ScriptCompileRequest;
|
||||
|
||||
using WriteFunction = AZStd::function< AZ::Outcome<void, AZStd::string>(const ScriptCompileRequest&, AZ::IO::GenericStream& in, AZ::IO::GenericStream& out) >;
|
||||
@@ -92,15 +88,13 @@ namespace AzFramework
|
||||
class ScriptComponent
|
||||
: public AZ::Component
|
||||
, private AZ::Data::AssetBus::Handler
|
||||
, public AzFramework::NetBindable
|
||||
{
|
||||
friend class AzToolsFramework::Components::ScriptEditorComponent;
|
||||
|
||||
public:
|
||||
static const char* NetRPCFieldName;
|
||||
static const char* DefaultFieldName;
|
||||
|
||||
AZ_COMPONENT(AzFramework::ScriptComponent, "{8D1BC97E-C55D-4D34-A460-E63C57CD0D4B}", NetBindable);
|
||||
AZ_COMPONENT(AzFramework::ScriptComponent, "{8D1BC97E-C55D-4D34-A460-E63C57CD0D4B}", AZ::Component);
|
||||
|
||||
/// \red ComponentDescriptor::Reflect
|
||||
static void Reflect(AZ::ReflectContext* reflection);
|
||||
@@ -116,7 +110,6 @@ namespace AzFramework
|
||||
|
||||
// Methods used for unit tests
|
||||
AZ::ScriptProperty* GetScriptProperty(const char* propertyName);
|
||||
const AZ::ScriptProperty* GetNetworkedScriptProperty(const char* propertyName) const;
|
||||
|
||||
protected:
|
||||
ScriptComponent(const ScriptComponent&) = delete;
|
||||
@@ -133,13 +126,6 @@ namespace AzFramework
|
||||
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// NetBindable
|
||||
GridMate::ReplicaChunkPtr GetNetworkBinding() override;
|
||||
void SetNetworkBinding(GridMate::ReplicaChunkPtr chunk) override;
|
||||
void UnbindFromNetwork() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Load script (unless already by other instances) and creates the script instance into the VM
|
||||
void LoadScript();
|
||||
/// Removes the script instance and unloads the script (unless needed by other instances)
|
||||
@@ -152,8 +138,6 @@ namespace AzFramework
|
||||
void CreateEntityTable();
|
||||
void DestroyEntityTable();
|
||||
|
||||
void CreateNetworkBindingTable(int baseStackIndex, int entityStackIndex);
|
||||
|
||||
void CreatePropertyGroup(const ScriptPropertyGroup& group, int propertyGroupTableIndex, int parentIndex, int metatableIndex, bool isRoot);
|
||||
|
||||
AZ::ScriptContext* m_context; ///< Context in which the script will be running
|
||||
@@ -161,7 +145,6 @@ namespace AzFramework
|
||||
AZ::Data::Asset<AZ::ScriptAsset> m_script; ///< Reference to the script asset used for this component.
|
||||
int m_table; ///< Cached table index
|
||||
ScriptPropertyGroup m_properties; ///< List with all properties that were tweaked in the editor and should override values in the m_sourceScriptName class inside m_script.
|
||||
ScriptNetBindingTable* m_netBindingTable; ///< Table that will hold our networked script values, and manage callbacks
|
||||
};
|
||||
} // namespace AZ
|
||||
|
||||
|
||||
@@ -1,573 +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.
|
||||
*
|
||||
*/
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Script/ScriptProperty.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <GridMate/Serialize/Buffer.h>
|
||||
#include <GridMate/Serialize/DataMarshal.h>
|
||||
#include <GridMate/Serialize/UuidMarshal.h>
|
||||
#include <GridMate/Serialize/ContainerMarshal.h>
|
||||
|
||||
#include <AzFramework/Script/ScriptNetBindings.h>
|
||||
#include <AzFramework/Network/DynamicSerializableFieldMarshaler.h>
|
||||
#include <AzFramework/Network/EntityIdMarshaler.h>
|
||||
|
||||
#include "AzFramework/Script/ScriptMarshal.h"
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
////////////////////////////
|
||||
// ScriptPropertyMarshaler
|
||||
////////////////////////////
|
||||
|
||||
template<class T>
|
||||
bool UnmarshalGenericType(AZ::DynamicSerializableField& serializableField, GridMate::ReadBuffer& rb)
|
||||
{
|
||||
bool valueChanged = true;
|
||||
|
||||
GridMate::Marshaler<AZ::DynamicSerializableField> serializableFieldMarshaler;
|
||||
|
||||
// Store the old value, to compare with the unmarshaled value, to signal
|
||||
T oldValue = (*serializableField.Get<T>());
|
||||
|
||||
serializableFieldMarshaler.Unmarshal(serializableField,rb);
|
||||
|
||||
// If our type hasn't changed, compare the values.
|
||||
if (serializableField.m_typeId == T::TYPEINFO_Uuid())
|
||||
{
|
||||
valueChanged = !(oldValue == (*serializableField.Get<T>()));
|
||||
}
|
||||
|
||||
return valueChanged;
|
||||
}
|
||||
|
||||
class ScriptPropertyTableMarshalerHelper
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
static void MarshalScriptPropertyGenericMap(const ScriptPropertyMarshaler& scriptPropertyMarshaler, GridMate::WriteBuffer& wb, const AZ::ScriptPropertyTable* scriptPropertyTable)
|
||||
{
|
||||
GridMate::Marshaler<AZ::u32> sizeMarshaler;
|
||||
|
||||
auto mapIter = scriptPropertyTable->m_genericMapping.find(T::TYPEINFO_Uuid());
|
||||
|
||||
if (mapIter != scriptPropertyTable->m_genericMapping.end())
|
||||
{
|
||||
AZ::ScriptPropertyGenericClassMapImpl<T>* genericClassKeyMap = static_cast<AZ::ScriptPropertyGenericClassMapImpl<T>*>(mapIter->second);
|
||||
|
||||
auto& valueMap = genericClassKeyMap->GetPairMapping();
|
||||
|
||||
// We will write out all of our keys. Since it is easier to write out nil values for the properties.
|
||||
sizeMarshaler.Marshal(wb,static_cast<AZ::u32>(valueMap.size()));
|
||||
|
||||
GridMate::Marshaler<T> keyMarshaler;
|
||||
|
||||
for (auto& mapPair : valueMap)
|
||||
{
|
||||
keyMarshaler.Marshal(wb,mapPair.first);
|
||||
scriptPropertyMarshaler.Marshal(wb,mapPair.second.m_valueProperty);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sizeMarshaler.Marshal(wb,0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool UnmarshalScriptPropertyGenericMap(const ScriptPropertyMarshaler& scriptPropertyMarshaler, AZ::ScriptPropertyTable* scriptPropertyTable, GridMate::ReadBuffer& rb)
|
||||
{
|
||||
bool valueChanged = false;
|
||||
|
||||
AZ::SerializeContext* useContext = nullptr;
|
||||
EBUS_EVENT_RESULT(useContext, AZ::ComponentApplicationBus, GetSerializeContext);
|
||||
|
||||
if (useContext)
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* classData = useContext->FindClassData(T::TYPEINFO_Uuid());
|
||||
|
||||
if (classData && classData->m_factory)
|
||||
{
|
||||
auto mapIter = scriptPropertyTable->m_genericMapping.find(T::TYPEINFO_Uuid());
|
||||
|
||||
if (mapIter != scriptPropertyTable->m_genericMapping.end())
|
||||
{
|
||||
// This whole thing is an in-place map update.
|
||||
// to try to minimize the number of allocations. We try to re-use objects as much as possible.
|
||||
//
|
||||
// Two phase approach: Step one, update all of the existing properties, while keeping track of all of the used keys.
|
||||
// Step two, go through and delete any unupdated keys from the mapping.
|
||||
AZ::ScriptPropertyGenericClassMapImpl<T>* genericClassKeyMap = static_cast<AZ::ScriptPropertyGenericClassMapImpl<T>*>(mapIter->second);
|
||||
|
||||
AZStd::unordered_set<T> newKeys;
|
||||
|
||||
GridMate::Marshaler<AZ::u32> sizeMarshaler;
|
||||
|
||||
AZ::u32 mapSize;
|
||||
sizeMarshaler.Unmarshal(mapSize,rb);
|
||||
|
||||
auto& valueMap = genericClassKeyMap->GetPairMapping();
|
||||
|
||||
GridMate::Marshaler<T> keyMarshaler;
|
||||
|
||||
for (unsigned int i=0; i < mapSize; ++i)
|
||||
{
|
||||
T propertyKey;
|
||||
keyMarshaler.Unmarshal(propertyKey,rb);
|
||||
|
||||
newKeys.insert(propertyKey);
|
||||
|
||||
auto valueIter = valueMap.find(propertyKey);
|
||||
|
||||
if (valueIter != valueMap.end())
|
||||
{
|
||||
if (scriptPropertyMarshaler.UnmarshalToPointer(valueIter->second.m_valueProperty,rb))
|
||||
{
|
||||
valueChanged = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valueChanged = true;
|
||||
|
||||
AZ::ScriptProperty* newValueProperty = nullptr;
|
||||
scriptPropertyMarshaler.UnmarshalToPointer(newValueProperty,rb);
|
||||
|
||||
AZ::ScriptPropertyGenericClassMap::MapValuePair newPair;
|
||||
|
||||
newPair.m_valueProperty = newValueProperty;
|
||||
|
||||
T* serializableData = nullptr;
|
||||
serializableData = static_cast<T*>(classData->m_factory->Create("ScriptProperty"));
|
||||
(*serializableData) = propertyKey;
|
||||
|
||||
AZ::ScriptPropertyGenericClass* genericPropertyClass = aznew AZ::ScriptPropertyGenericClass();
|
||||
|
||||
genericPropertyClass->Set<T>(serializableData);
|
||||
|
||||
newPair.m_keyProperty = genericPropertyClass;
|
||||
|
||||
valueMap.emplace(propertyKey,newPair);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all of the unused keyes from the map
|
||||
auto valueIter = valueMap.begin();
|
||||
|
||||
while (valueIter != valueMap.end())
|
||||
{
|
||||
if (newKeys.find(valueIter->first) == newKeys.end())
|
||||
{
|
||||
valueChanged = true;
|
||||
valueIter->second.Destroy();
|
||||
valueIter = valueMap.erase(valueIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++valueIter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return valueChanged;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
void ScriptPropertyMarshaler::Marshal(GridMate::WriteBuffer& wb, AZ::ScriptProperty*const& property) const
|
||||
{
|
||||
GridMate::Marshaler<AZ::Uuid> typeMarshaler;
|
||||
GridMate::Marshaler<AZ::u64> idMarshaler;
|
||||
GridMate::Marshaler<AZStd::string> nameMarshaler;
|
||||
|
||||
if (property == nullptr)
|
||||
{
|
||||
// Write out a nil property if we have a nullptr property
|
||||
nameMarshaler.Marshal(wb,"");
|
||||
idMarshaler.Marshal(wb,0);
|
||||
typeMarshaler.Marshal(wb,AZ::ScriptPropertyNil::RTTI_Type());
|
||||
return;
|
||||
}
|
||||
|
||||
// Common points:
|
||||
// Always going to marshal the uuid of the type(or something similar)
|
||||
// so we know what type we have on the other side.
|
||||
//
|
||||
// Next need to pass along the name field.
|
||||
const AZ::Uuid& typeId = azrtti_typeid(property);
|
||||
|
||||
nameMarshaler.Marshal(wb,property->m_name);
|
||||
idMarshaler.Marshal(wb,property->m_id);
|
||||
|
||||
// Method 1:
|
||||
// - Allow each ScriptProperty to marshal itself.
|
||||
// - Currently unavailable since the ScriptProperties live in AZCore
|
||||
// and the WriteBuffer is in GridMate.
|
||||
// cont.Marshal(wb);
|
||||
|
||||
// Method 2:
|
||||
// - Process all of our known marshallable types and use the appropriate marshaler
|
||||
if (typeId == AZ::ScriptPropertyBoolean::RTTI_Type())
|
||||
{
|
||||
typeMarshaler.Marshal(wb,typeId);
|
||||
|
||||
GridMate::Marshaler<bool> boolMarshaler;
|
||||
boolMarshaler.Marshal(wb,static_cast<const AZ::ScriptPropertyBoolean*>(property)->m_value);
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyNumber::RTTI_Type())
|
||||
{
|
||||
typeMarshaler.Marshal(wb,typeId);
|
||||
|
||||
GridMate::Marshaler<double> doubleMarshaler;
|
||||
doubleMarshaler.Marshal(wb,static_cast<const AZ::ScriptPropertyNumber*>(property)->m_value);
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyString::RTTI_Type())
|
||||
{
|
||||
typeMarshaler.Marshal(wb,typeId);
|
||||
|
||||
GridMate::Marshaler<AZStd::string> stringMarshaler;
|
||||
stringMarshaler.Marshal(wb,static_cast<const AZ::ScriptPropertyString*>(property)->m_value);
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyGenericClass::RTTI_Type())
|
||||
{
|
||||
const AZ::DynamicSerializableField& serializableField = static_cast<const AZ::ScriptPropertyGenericClass*>(property)->GetSerializableField();
|
||||
|
||||
typeMarshaler.Marshal(wb,typeId);
|
||||
|
||||
GridMate::Marshaler<AZ::DynamicSerializableField> serializableFieldMarshaler;
|
||||
serializableFieldMarshaler.Marshal(wb,serializableField);
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyTable::TYPEINFO_Uuid())
|
||||
{
|
||||
const AZ::ScriptPropertyTable* scriptPropertyTable = static_cast<const AZ::ScriptPropertyTable*>(property);
|
||||
|
||||
typeMarshaler.Marshal(wb,typeId);
|
||||
|
||||
GridMate::Marshaler<AZ::u32> mapSizeMarshaler;
|
||||
mapSizeMarshaler.Marshal(wb,static_cast<AZ::u32>(scriptPropertyTable->m_indexMapping.size()));
|
||||
|
||||
GridMate::Marshaler<int> indexMarshaler;
|
||||
|
||||
// Currently only support integers as keys inside of the table.
|
||||
for (auto& mapPair : scriptPropertyTable->m_indexMapping)
|
||||
{
|
||||
indexMarshaler.Marshal(wb,mapPair.first);
|
||||
this->Marshal(wb,mapPair.second);
|
||||
}
|
||||
|
||||
mapSizeMarshaler.Marshal(wb, static_cast<AZ::u32>(scriptPropertyTable->m_keyMapping.size()));
|
||||
|
||||
GridMate::Marshaler<AZ::u32> hashMarshaler;
|
||||
|
||||
for (auto& mapPair : scriptPropertyTable->m_keyMapping)
|
||||
{
|
||||
// For hashed values. The name of the script property is the same as the hash it should be using.
|
||||
// We still synchronize the Crc so we can unmarshal in place on the other side.
|
||||
hashMarshaler.Marshal(wb,mapPair.first);
|
||||
Marshal(wb,mapPair.second);
|
||||
}
|
||||
|
||||
// EntityId's
|
||||
ScriptPropertyTableMarshalerHelper::MarshalScriptPropertyGenericMap<AZ::EntityId>((*this), wb, scriptPropertyTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
typeMarshaler.Marshal(wb,AZ::ScriptPropertyNil::RTTI_Type());
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptPropertyMarshaler::UnmarshalToPointer(AZ::ScriptProperty*& target, GridMate::ReadBuffer& rb) const
|
||||
{
|
||||
bool typeChanged = false;
|
||||
AZ::Uuid typeId;
|
||||
AZ::u64 id;
|
||||
AZStd::string name;
|
||||
|
||||
GridMate::Marshaler<AZ::Uuid> typeMarshaler;
|
||||
GridMate::Marshaler<AZ::u64> idMarshaler;
|
||||
GridMate::Marshaler<AZStd::string> nameMarshaler;
|
||||
|
||||
nameMarshaler.Unmarshal(name,rb);
|
||||
idMarshaler.Unmarshal(id,rb);
|
||||
typeMarshaler.Unmarshal(typeId,rb);
|
||||
|
||||
if (target == nullptr || typeId != azrtti_typeid(target))
|
||||
{
|
||||
typeChanged = true;
|
||||
|
||||
AZ::ScriptProperty* actualScriptProperty = nullptr;
|
||||
if (typeId == AZ::ScriptPropertyBoolean::RTTI_Type())
|
||||
{
|
||||
actualScriptProperty = aznew AZ::ScriptPropertyBoolean();
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyNumber::RTTI_Type())
|
||||
{
|
||||
actualScriptProperty = aznew AZ::ScriptPropertyNumber();
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyString::RTTI_Type())
|
||||
{
|
||||
actualScriptProperty = aznew AZ::ScriptPropertyString();
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyGenericClass::RTTI_Type())
|
||||
{
|
||||
actualScriptProperty = aznew AZ::ScriptPropertyGenericClass();
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyTable::RTTI_Type())
|
||||
{
|
||||
actualScriptProperty = aznew AZ::ScriptPropertyTable();
|
||||
}
|
||||
else
|
||||
{
|
||||
actualScriptProperty = aznew AZ::ScriptPropertyNil();
|
||||
}
|
||||
|
||||
actualScriptProperty->m_name = name;
|
||||
delete target;
|
||||
|
||||
target = actualScriptProperty;
|
||||
}
|
||||
|
||||
// Update our ID
|
||||
target->m_id = id;
|
||||
|
||||
// Method 1:
|
||||
// - Allow each ScriptProperty to unmarshal itself
|
||||
// - Currently unavailable since the ScriptProperties live in AZCore
|
||||
// and the WriteBuffer is in GridMate
|
||||
// actualScriptProperty->Unmarshal(rb);
|
||||
//
|
||||
// Method 2:
|
||||
// - Process all of our known marshallable types and use the appropriate marshaler
|
||||
|
||||
bool valueChanged = false;
|
||||
|
||||
if (typeId == AZ::ScriptPropertyBoolean::RTTI_Type())
|
||||
{
|
||||
AZ::ScriptPropertyBoolean* booleanProperty = static_cast<AZ::ScriptPropertyBoolean*>(target);
|
||||
bool oldValue = booleanProperty->m_value;
|
||||
|
||||
GridMate::Marshaler<bool> boolMarshaler;
|
||||
boolMarshaler.Unmarshal(booleanProperty->m_value,rb);
|
||||
|
||||
valueChanged = !(oldValue == booleanProperty->m_value);
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyString::RTTI_Type())
|
||||
{
|
||||
AZ::ScriptPropertyString* stringProperty = static_cast<AZ::ScriptPropertyString*>(target);
|
||||
AZStd::string oldValue = stringProperty->m_value;
|
||||
|
||||
GridMate::Marshaler<AZStd::string> stringMarshaler;
|
||||
stringMarshaler.Unmarshal(stringProperty->m_value,rb);
|
||||
|
||||
valueChanged = !(oldValue == stringProperty->m_value);
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyNumber::RTTI_Type())
|
||||
{
|
||||
AZ::ScriptPropertyNumber* numberProperty = static_cast<AZ::ScriptPropertyNumber*>(target);
|
||||
double oldValue = numberProperty->m_value;
|
||||
|
||||
GridMate::Marshaler<double> numberMarshaler;
|
||||
numberMarshaler.Unmarshal(numberProperty->m_value,rb);
|
||||
|
||||
valueChanged = !(oldValue == numberProperty->m_value);
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyGenericClass::RTTI_Type())
|
||||
{
|
||||
AZ::ScriptPropertyGenericClass* genericProperty = static_cast<AZ::ScriptPropertyGenericClass*>(target);
|
||||
|
||||
AZ::DynamicSerializableField& serializableField = genericProperty->m_value;
|
||||
|
||||
AZ::DynamicSerializableField oldField;
|
||||
|
||||
oldField.CopyDataFrom(serializableField);
|
||||
|
||||
GridMate::Marshaler<AZ::DynamicSerializableField> serializableFieldMarshaler;
|
||||
serializableFieldMarshaler.Unmarshal(serializableField,rb);
|
||||
|
||||
// If our type hasn't changed, compare the values.
|
||||
valueChanged = !oldField.IsEqualTo(serializableField);
|
||||
}
|
||||
else if (typeId == AZ::ScriptPropertyTable::RTTI_Type())
|
||||
{
|
||||
AZ::ScriptPropertyTable* scriptPropertyTable = static_cast<AZ::ScriptPropertyTable*>(target);
|
||||
GridMate::Marshaler<AZ::u32> mapSizeMarshaler;
|
||||
|
||||
// Unmarshal all of the indexes properties
|
||||
{
|
||||
AZ::u32 mapSize = 0;
|
||||
mapSizeMarshaler.Unmarshal(mapSize, rb);
|
||||
|
||||
AZStd::unordered_set<int> newIndexes;
|
||||
GridMate::Marshaler<int> indexMarshaler;
|
||||
|
||||
for (AZ::u32 i=0; i < mapSize; ++i)
|
||||
{
|
||||
int index = 0;
|
||||
indexMarshaler.Unmarshal(index,rb);
|
||||
|
||||
auto mapIter = scriptPropertyTable->m_indexMapping.find(index);
|
||||
|
||||
if (mapIter != scriptPropertyTable->m_indexMapping.end())
|
||||
{
|
||||
if (UnmarshalToPointer(mapIter->second,rb))
|
||||
{
|
||||
valueChanged = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valueChanged = true;
|
||||
|
||||
AZ::ScriptProperty* scriptProperty = nullptr;
|
||||
UnmarshalToPointer(scriptProperty,rb);
|
||||
auto insertResult = scriptPropertyTable->m_indexMapping.emplace(index,scriptProperty);
|
||||
mapIter = insertResult.first;
|
||||
}
|
||||
|
||||
if (mapIter->second == nullptr || azrtti_istypeof<AZ::ScriptPropertyNil>(mapIter->second))
|
||||
{
|
||||
valueChanged = true;
|
||||
|
||||
delete mapIter->second;
|
||||
scriptPropertyTable->m_indexMapping.erase(mapIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
newIndexes.insert(index);
|
||||
}
|
||||
}
|
||||
|
||||
auto mapIter = scriptPropertyTable->m_indexMapping.begin();
|
||||
|
||||
while (mapIter != scriptPropertyTable->m_indexMapping.end())
|
||||
{
|
||||
if (newIndexes.find(mapIter->first) == newIndexes.end())
|
||||
{
|
||||
valueChanged = true;
|
||||
|
||||
delete mapIter->second;
|
||||
mapIter = scriptPropertyTable->m_indexMapping.erase(mapIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++mapIter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unmarshal all of the hashed values
|
||||
{
|
||||
AZ::u32 mapSize = 0;
|
||||
mapSizeMarshaler.Unmarshal(mapSize, rb);
|
||||
|
||||
AZStd::unordered_set<AZ::u32> newHashes;
|
||||
GridMate::Marshaler<AZ::u32> hashMarshaler;
|
||||
|
||||
for (AZ::u32 i=0; i < mapSize; ++i)
|
||||
{
|
||||
AZ::u32 newHash;
|
||||
hashMarshaler.Unmarshal(newHash, rb);
|
||||
|
||||
auto mapIter = scriptPropertyTable->m_keyMapping.find(newHash);
|
||||
|
||||
if (mapIter != scriptPropertyTable->m_keyMapping.end())
|
||||
{
|
||||
if (UnmarshalToPointer(mapIter->second,rb))
|
||||
{
|
||||
valueChanged = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valueChanged = true;
|
||||
|
||||
AZ::ScriptProperty* scriptProperty = nullptr;
|
||||
UnmarshalToPointer(scriptProperty,rb);
|
||||
auto emplaceResult = scriptPropertyTable->m_keyMapping.emplace(newHash,scriptProperty);
|
||||
mapIter = emplaceResult.first;
|
||||
}
|
||||
|
||||
if (mapIter->second == nullptr || azrtti_istypeof<AZ::ScriptPropertyNil>(mapIter->second))
|
||||
{
|
||||
valueChanged = true;
|
||||
|
||||
delete mapIter->second;
|
||||
scriptPropertyTable->m_keyMapping.erase(mapIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
newHashes.insert(newHash);
|
||||
}
|
||||
}
|
||||
|
||||
auto mapIter = scriptPropertyTable->m_keyMapping.begin();
|
||||
|
||||
while (mapIter != scriptPropertyTable->m_keyMapping.end())
|
||||
{
|
||||
if (newHashes.find(mapIter->first) == newHashes.end())
|
||||
{
|
||||
valueChanged = true;
|
||||
|
||||
delete mapIter->second;
|
||||
mapIter = scriptPropertyTable->m_keyMapping.erase(mapIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++mapIter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unmarshal all of the generic properties
|
||||
|
||||
// EntityId's
|
||||
if (ScriptPropertyTableMarshalerHelper::UnmarshalScriptPropertyGenericMap<AZ::EntityId>((*this), scriptPropertyTable, rb))
|
||||
{
|
||||
valueChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
return typeChanged || valueChanged;
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// ScriptPropertyThrottler
|
||||
////////////////////////////
|
||||
|
||||
ScriptPropertyThrottler::ScriptPropertyThrottler()
|
||||
: m_isDirty(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ScriptPropertyThrottler::SignalDirty()
|
||||
{
|
||||
m_isDirty = true;
|
||||
}
|
||||
|
||||
bool ScriptPropertyThrottler::WithinThreshold(AZ::ScriptProperty* newValue) const
|
||||
{
|
||||
return newValue == nullptr || !m_isDirty;
|
||||
}
|
||||
|
||||
void ScriptPropertyThrottler::UpdateBaseline(AZ::ScriptProperty* baseline)
|
||||
{
|
||||
(void)baseline;
|
||||
|
||||
m_isDirty = false;
|
||||
}
|
||||
}
|
||||
@@ -1,94 +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.
|
||||
*
|
||||
*/
|
||||
#ifndef AZFRAMEWORK_SCRIPT_SCRIPTMARSHAL_H
|
||||
#define AZFRAMEWORK_SCRIPT_SCRIPTMARSHAL_H
|
||||
|
||||
#include <GridMate/Serialize/ContainerMarshal.h>
|
||||
|
||||
#include <AzCore/RTTI/BehaviorObjectSignals.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ScriptProperty;
|
||||
}
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
/**
|
||||
* Specalized helper marshaler for ScriptProperty class
|
||||
*/
|
||||
class ScriptPropertyMarshaler
|
||||
{
|
||||
public:
|
||||
void Marshal(GridMate::WriteBuffer& wb, AZ::ScriptProperty*const& cont) const;
|
||||
bool UnmarshalToPointer(AZ::ScriptProperty*& target, GridMate::ReadBuffer& rb) const;
|
||||
};
|
||||
|
||||
class ScriptPropertyThrottler
|
||||
{
|
||||
public:
|
||||
ScriptPropertyThrottler();
|
||||
|
||||
void SignalDirty();
|
||||
bool WithinThreshold(AZ::ScriptProperty* newValue) const;
|
||||
void UpdateBaseline(AZ::ScriptProperty* baseline);
|
||||
|
||||
private:
|
||||
bool m_isDirty;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialized helper marshaler to help with the vector creation/destruction
|
||||
*/
|
||||
class ScriptRPCMarshaler
|
||||
{
|
||||
public:
|
||||
|
||||
typedef AZStd::vector< AZ::ScriptProperty* > Container;
|
||||
|
||||
ScriptRPCMarshaler()
|
||||
{
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE void Marshal(GridMate::WriteBuffer& wb, const Container& container) const
|
||||
{
|
||||
AZ_Assert(container.size() < USHRT_MAX, "Container has too many elements for marshaling!");
|
||||
AZ::u16 size = static_cast<AZ::u16>(container.size());
|
||||
wb.Write(size);
|
||||
for (const auto& i : container)
|
||||
{
|
||||
m_marshaler.Marshal(wb, i);
|
||||
}
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE void Unmarshal(Container& container, GridMate::ReadBuffer& rb) const
|
||||
{
|
||||
container.clear();
|
||||
|
||||
AZ::u16 size;
|
||||
rb.Read(size);
|
||||
container.reserve(size);
|
||||
|
||||
for (AZ::u16 i = 0; i < size; ++i)
|
||||
{
|
||||
AZ::ScriptProperty* readProperty = nullptr;
|
||||
m_marshaler.UnmarshalToPointer(readProperty, rb);
|
||||
container.insert(container.end(), readProperty);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ScriptPropertyMarshaler m_marshaler;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,320 +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.
|
||||
*
|
||||
*/
|
||||
#ifndef AZFRAMEWORK_SCRIPT_NET_BINDINGS_H
|
||||
#define AZFRAMEWORK_SCRIPT_NET_BINDINGS_H
|
||||
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <GridMate/Replica/ReplicaChunkInterface.h>
|
||||
#include <GridMate/Replica/DataSet.h>
|
||||
#include <GridMate/Replica/RemoteProcedureCall.h>
|
||||
#include <GridMate/Replica/RemoteProcedureCall.h>
|
||||
|
||||
#include <AzCore/Script/ScriptProperty.h>
|
||||
#include <AzCore/Script/ScriptPropertyTable.h>
|
||||
#include <AzCore/Script/ScriptPropertyWatcherBus.h>
|
||||
#include <AzFramework/Script/ScriptMarshal.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class ScriptPropertyDataSet;
|
||||
class ScriptComponentReplicaChunk;
|
||||
|
||||
// ScriptNetBindingTable will act as the go between for the ScriptComponent and the Replica's.
|
||||
// It will also allow for holding of values in the case where you haven't been bound to a replica chunk yet and the
|
||||
// script tries to interact with something that is networked.
|
||||
//
|
||||
// Allows for scripts to be re-used seamlessly in a offline vs online scenario(and support for going from offline to online),
|
||||
// including RPCs(will alawys call the master version if offline)
|
||||
class ScriptNetBindingTable
|
||||
: public GridMate::ReplicaChunkInterface
|
||||
{
|
||||
private:
|
||||
friend class ScriptComponentReplicaChunk;
|
||||
friend class ScriptPropertyDataSet;
|
||||
|
||||
// Helper struct to keep track of a a ScriptContext
|
||||
// and the entityTableReference. Mainly used for
|
||||
// calling in to functions in LUA where we want
|
||||
// to push in the table reference as the first parameter
|
||||
struct EntityScriptContext
|
||||
{
|
||||
public:
|
||||
EntityScriptContext();
|
||||
|
||||
void Unload();
|
||||
|
||||
bool HasEntityTableRegistryIndex() const;
|
||||
int GetEntityTableRegistryIndex() const;
|
||||
|
||||
bool HasScriptContext() const;
|
||||
AZ::ScriptContext* GetScriptContext() const;
|
||||
|
||||
void ConfigureContext(AZ::ScriptContext* scriptContext, int entityTableRegistryIndex);
|
||||
|
||||
private:
|
||||
|
||||
bool SanityCheckContext() const;
|
||||
|
||||
AZ::ScriptContext* m_scriptContext;
|
||||
int m_entityTableRegistryIndex;
|
||||
};
|
||||
|
||||
class NetworkedTableValue;
|
||||
friend NetworkedTableValue;
|
||||
|
||||
typedef AZStd::unordered_map<AZStd::string, NetworkedTableValue> NetworkedTableMap;
|
||||
|
||||
class RPCBindingHelper;
|
||||
friend RPCBindingHelper;
|
||||
|
||||
typedef AZStd::unordered_map<AZStd::string, RPCBindingHelper> RPCHelperMap;
|
||||
|
||||
// Helper class that will wrap up our interactions with the actual stored value
|
||||
// to hide the general use case of if we are connected to a replica or not.
|
||||
//
|
||||
// Additionally this will serve as a holding ground for a 'networked'
|
||||
// value that doesn't have a dataset.
|
||||
//
|
||||
// Lastly holds onto the Callback references.
|
||||
class NetworkedTableValue
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(NetworkedTableValue, AZ::SystemAllocator, 0);
|
||||
|
||||
NetworkedTableValue(AZ::ScriptProperty* initialValue = nullptr);
|
||||
~NetworkedTableValue();
|
||||
|
||||
void Destroy();
|
||||
|
||||
// Methods to register this value to a chunk
|
||||
bool HasDataSet() const;
|
||||
void RegisterDataSet(ScriptPropertyDataSet* dataSet);
|
||||
void UnbindFromDataSet();
|
||||
ScriptPropertyDataSet* GetDataSet() const;
|
||||
|
||||
// Information kept in order to force these values to use a particular dataset for debugging.
|
||||
bool HasForcedDataSetIndex() const;
|
||||
void SetForcedDataSetIndex(int index);
|
||||
int GetForcedDataSetIndex() const;
|
||||
|
||||
// Callback functions
|
||||
bool HasCallback() const;
|
||||
void RegisterCallback(int functionReference);
|
||||
void ReleaseCallback(AZ::ScriptContext& scriptContext);
|
||||
void InvokeCallback(EntityScriptContext& scriptContext, const GridMate::TimeContext& timeContext);
|
||||
|
||||
bool AssignValue(AZ::ScriptDataContext& scriptDataContext, const AZStd::string& propertyName);
|
||||
bool InspectValue(AZ::ScriptContext* scriptContext) const;
|
||||
|
||||
// Methods used for unit tests
|
||||
const AZ::ScriptProperty* GetShimmedScriptProperty() const { return m_shimmedScriptProperty; }
|
||||
private:
|
||||
|
||||
// This value will be used if we have a networked property, but don't have a valid chunk yet.
|
||||
// Works as a temporary store, which will be resolved once we get assigned to a DataSet
|
||||
AZ::ScriptProperty* m_shimmedScriptProperty;
|
||||
|
||||
// The data set we are bound to
|
||||
ScriptPropertyDataSet* m_dataSet;
|
||||
int m_forcedDataSetIndex;
|
||||
|
||||
int m_functionReference;
|
||||
};
|
||||
|
||||
// Future thoughts
|
||||
// - Move the actual RPC meta table creation
|
||||
// into this guy
|
||||
class RPCBindingHelper
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(RPCBindingHelper, AZ::SystemAllocator, 0);
|
||||
|
||||
RPCBindingHelper();
|
||||
~RPCBindingHelper();
|
||||
|
||||
void ReleaseTableIndex(AZ::ScriptContext& scriptContext);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
void SetMasterFunction(int masterReference);
|
||||
bool InvokeMaster(EntityScriptContext& entityScriptContext, const ScriptRPCMarshaler::Container& params);
|
||||
|
||||
void SetProxyFunction(int masterReference);
|
||||
void InvokeProxy(EntityScriptContext& entityScriptContext, const ScriptRPCMarshaler::Container& params);
|
||||
|
||||
private:
|
||||
int m_masterReference;
|
||||
int m_proxyReference;
|
||||
};
|
||||
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ScriptNetBindingTable, AZ::SystemAllocator, 0);
|
||||
static void Reflect(AZ::ReflectContext* reflect);
|
||||
|
||||
ScriptNetBindingTable();
|
||||
~ScriptNetBindingTable();
|
||||
|
||||
void Unload();
|
||||
|
||||
void CreateNetworkBindingTable(AZ::ScriptContext* scriptContext, int baseTableIndex, int entityTableIndex);
|
||||
void FinalizeNetworkTable(AZ::ScriptContext* scriptContext, int entityTableRegistryIndex);
|
||||
|
||||
AZ::ScriptContext* GetScriptContext() const;
|
||||
|
||||
bool IsMaster() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DataSet Functionality
|
||||
//
|
||||
// Called when the script wants to bind a function callback to when
|
||||
// a value changes
|
||||
//
|
||||
// Might change this to just be register DataSet
|
||||
bool RegisterDataSet(AZ::ScriptDataContext& stackContext, AZ::ScriptProperty* scriptProperty);
|
||||
|
||||
// Called when the script wants to assign a value to the script value
|
||||
bool AssignTableValue(AZ::ScriptDataContext& stackContext);
|
||||
|
||||
// Called when the script wants to know the value of a script value.
|
||||
bool InspectTableValue(AZ::ScriptDataContext& stackContext) const;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// RPC Functionality
|
||||
void RegisterRPC(AZ::ScriptDataContext& rpcTableContext, const AZStd::string& rpcName, int elementIndex, int tableStackIndex);
|
||||
bool InvokeRPC(AZ::ScriptDataContext& stackContext);
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Netbinding Interface duplication here to be called from the ScriptComponent
|
||||
GridMate::ReplicaChunkPtr GetNetworkBinding();
|
||||
void SetNetworkBinding(GridMate::ReplicaChunkPtr chunk);
|
||||
void UnbindFromNetwork();
|
||||
|
||||
void OnPropertyUpdate(AZ::ScriptProperty*const& scriptProperty, const GridMate::TimeContext& tc);
|
||||
bool OnInvokeRPC(AZStd::string functionName, AZStd::vector< AZ::ScriptProperty*> properties, const GridMate::RpcContext& rpcContext);
|
||||
|
||||
// Methods used for unit tests
|
||||
const AZ::ScriptProperty* FindScriptProperty(const AZStd::string& name) const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void RegisterMetaTableCache();
|
||||
|
||||
template<typename PropertyType, typename PropertyArrayType>
|
||||
AZ::ScriptPropertyTable* ConvertPropertyArrayToTable(PropertyArrayType* arrayProperty)
|
||||
{
|
||||
AZ::ScriptPropertyTable* scriptPropertyTable = aznew AZ::ScriptPropertyTable(arrayProperty->m_name.c_str());
|
||||
|
||||
PropertyType propertyType;
|
||||
|
||||
for (unsigned int i=0; i < arrayProperty->m_values.size(); ++i)
|
||||
{
|
||||
propertyType.m_value = arrayProperty->m_values[i];
|
||||
|
||||
// Offset by 1 to deal with lua 1 indexing.
|
||||
// Table will make a clone of our object.
|
||||
scriptPropertyTable->SetTableValue(i+1, &propertyType);
|
||||
}
|
||||
|
||||
return scriptPropertyTable;
|
||||
}
|
||||
|
||||
void AssignDataSets();
|
||||
|
||||
NetworkedTableValue* FindTableValue(const AZStd::string& name);
|
||||
const NetworkedTableValue* FindTableValue(const AZStd::string& name) const;
|
||||
|
||||
EntityScriptContext m_entityScriptContext;
|
||||
|
||||
GridMate::ReplicaChunkPtr m_replicaChunk;
|
||||
|
||||
NetworkedTableMap m_networkedTable;
|
||||
RPCHelperMap m_rpcHelperMap;
|
||||
};
|
||||
|
||||
// Typedeffing out the RPC and DataSet definitions.
|
||||
typedef GridMate::Rpc< GridMate::RpcArg< AZStd::string >, GridMate::RpcArg< ScriptRPCMarshaler::Container, ScriptRPCMarshaler > >::BindInterface<ScriptNetBindingTable, &ScriptNetBindingTable::OnInvokeRPC> ScriptPropertyRPC;
|
||||
typedef GridMate::DataSet<AZ::ScriptProperty*, ScriptPropertyMarshaler, ScriptPropertyThrottler>::BindInterface<ScriptNetBindingTable, &ScriptNetBindingTable::OnPropertyUpdate> ScriptPropertyDataSetType;
|
||||
|
||||
class ScriptComponentReplicaChunk;
|
||||
|
||||
// Specialized DataSet used by the ScriptProperties, just to add some wrapped around functionality
|
||||
// and to allow me to manipulate the DataSet throttler in order to properly manage a dirty flag
|
||||
class ScriptPropertyDataSet
|
||||
: public ScriptPropertyDataSetType
|
||||
, public AZ::ScriptPropertyWatcherBus::Handler
|
||||
, public AZ::ScriptPropertyWatcher
|
||||
{
|
||||
private:
|
||||
friend class ScriptComponentReplicaChunk;
|
||||
friend class ScriptNetBindingTable::NetworkedTableValue;
|
||||
|
||||
const char* GetDataSetName();
|
||||
|
||||
public:
|
||||
ScriptPropertyDataSet();
|
||||
~ScriptPropertyDataSet();
|
||||
bool IsReserved() const;
|
||||
|
||||
bool UpdateScriptProperty(AZ::ScriptDataContext& scriptDataContext, const AZStd::string& propertyName);
|
||||
void SetScriptProperty(AZ::ScriptProperty* scriptProperty);
|
||||
|
||||
void OnObjectModified() override;
|
||||
|
||||
private:
|
||||
void Reserve(ScriptNetBindingTable::NetworkedTableValue* reserver);
|
||||
void Release(ScriptNetBindingTable::NetworkedTableValue* reserver);
|
||||
|
||||
ScriptNetBindingTable::NetworkedTableValue* m_reserver;
|
||||
};
|
||||
|
||||
// The actual ReplicaChunk that the script will use
|
||||
class ScriptComponentReplicaChunk
|
||||
: public GridMate::ReplicaChunkBase
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ScriptComponentReplicaChunk, AZ::SystemAllocator,0);
|
||||
static const int k_maxScriptableDataSets = GM_MAX_DATASETS_IN_CHUNK;
|
||||
|
||||
static const char* GetChunkName() { return "ScriptComponentReplicaChunk"; }
|
||||
|
||||
// Might want to add some type of comment field into the various fields so this can be properly parsed
|
||||
// and determined what we are actually sending.
|
||||
ScriptComponentReplicaChunk();
|
||||
~ScriptComponentReplicaChunk();
|
||||
|
||||
bool IsReplicaMigratable() override;
|
||||
|
||||
AZ::u32 CalculateDirtyDataSetMask(GridMate::MarshalContext& marshalContext) override;
|
||||
|
||||
// Called from the Master, will assign the table value to the DataSet specified by the helper.
|
||||
bool AssignDataSet(ScriptNetBindingTable::NetworkedTableValue& helper);
|
||||
|
||||
// Called from teh Proxy. Will Assign the TableValue to the DataSet that contains the target property
|
||||
void AssignDataSetForProperty(ScriptNetBindingTable::NetworkedTableValue& helper, AZ::ScriptProperty* targetProperty);
|
||||
|
||||
// Only called inside of an assert, checks that the DataSet that the targetProperty is in is the same as the assumedDataSet
|
||||
// Used to confirm that we don't get a confusion between master/proxy about which ScriptProperty is assigned to which DataSet.
|
||||
bool SanityCheckDataSet(AZ::ScriptProperty* targetProperty, ScriptPropertyDataSet* assumedDataSet);
|
||||
|
||||
ScriptPropertyRPC m_scriptRPC;
|
||||
|
||||
private:
|
||||
AZ::u32 m_enabledDataSetMask;
|
||||
ScriptPropertyDataSet m_propertyDataSets[k_maxScriptableDataSets];
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user