Merge branch 'main' of https://github.com/aws-lumberyard/o3de into cgalvan/DuplicateEntities

main
Chris Galvan 5 years ago
commit 20ee399864

@ -7,28 +7,33 @@ AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: false
AlignTrailingComments: false
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: None
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
BeforeLambdaBody: true
AfterStruct: true
SplitEmptyFunction: true
AfterControlStatement: true
BeforeElse: true
SplitEmptyFunction: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
ColumnLimit: 140
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
Cpp11BracedListStyle: false
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseBlocks: true
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 4
@ -38,27 +43,17 @@ NamespaceIndentation: All
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
SortIncludes: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
Standard: c++17
UseTab: Never
# Not available in clang-format version 6.0.0
# BasedOnStyle: Microsoft
# Standard: c++17
# AllowAllArgumentsOnNextLine: true
# AllowShortLambdasOnASingleLine: None
# BreakInheritanceList: BeforeComma
# SpaceAfterLogicalNot: false
# SpaceBeforeCpp11BracedList: false
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# SpaceBeforeRangeBasedForLoopColon: true
# Not available in clang-format version 10.0.0
# BeforeLambdaBody: true (BraceWrapping)
# IndentCaseBlocks: true

@ -43,7 +43,6 @@ set(GEM_DEPENDENCIES
Gem::GradientSignal
Gem::Vegetation
Gem::Atom_AtomBridge
Gem::AtomFont
Gem::NvCloth
Gem::Blast
Gem::AWSCore

@ -55,7 +55,6 @@ set(GEM_DEPENDENCIES
Gem::Atom_RHI.Private
Gem::Atom_Feature_Common.Editor
Gem::Atom_AtomBridge.Editor
Gem::AtomFont
Gem::NvCloth.Editor
Gem::Blast.Editor
Gem::AWSCore.Editor

@ -133,7 +133,15 @@ namespace AZ
if (!id.m_guid.IsNull())
{
*instance = AssetManager::Instance().FindOrCreateAsset(id, instance->GetType(), instance->GetAutoLoadBehavior());
if (!instance->GetId().IsValid())
{
// If the asset failed to be created, FindOrCreateAsset returns an asset instance with a null
// id. To preserve the asset id in the source json, reset the asset to an empty one, but with
// the right id.
const auto loadBehavior = instance->GetAutoLoadBehavior();
*instance = Asset<AssetData>(id, instance->GetType());
instance->SetAutoLoadBehavior(loadBehavior);
}
result.Combine(context.Report(result, "Successfully created Asset<T> with id."));
}

@ -880,6 +880,13 @@ namespace AZ
const Specializations& specializations, const rapidjson::Pointer& historyPointer, AZStd::string_view folderPath)
{
using namespace rapidjson;
if (&lhs == &rhs)
{
// Early return to avoid setting the collisionFound reference to true
// std::sort is allowed to pass in the same memory address for the left and right elements
return false;
}
AZ_Assert(!lhs.m_tags.empty(), "Comparing a settings file without at least a name tag.");
AZ_Assert(!rhs.m_tags.empty(), "Comparing a settings file without at least a name tag.");

@ -30,6 +30,16 @@ namespace AzPhysics
classElement.AddElementWithData(context, "name", name);
return true;
}
bool SimulatedBodyVersionConverter([[maybe_unused]] AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
{
if (classElement.GetVersion() <= 1)
{
classElement.RemoveElementByName(AZ_CRC_CE("scale"));
}
return true;
}
}
AZ_CLASS_ALLOCATOR_IMPL(SimulatedBodyConfiguration, AZ::SystemAllocator, 0);
@ -40,11 +50,10 @@ namespace AzPhysics
{
serializeContext->ClassDeprecate("WorldBodyConfiguration", "{6EEB377C-DC60-4E10-AF12-9626C0763B2D}", &Internal::DeprecateWorldBodyConfiguration);
serializeContext->Class<SimulatedBodyConfiguration>()
->Version(1)
->Version(2, &Internal::SimulatedBodyVersionConverter)
->Field("name", &SimulatedBodyConfiguration::m_debugName)
->Field("position", &SimulatedBodyConfiguration::m_position)
->Field("orientation", &SimulatedBodyConfiguration::m_orientation)
->Field("scale", &SimulatedBodyConfiguration::m_scale)
->Field("entityId", &SimulatedBodyConfiguration::m_entityId)
->Field("startSimulationEnabled", &SimulatedBodyConfiguration::m_startSimulationEnabled)
;

@ -38,7 +38,6 @@ namespace AzPhysics
// Basic initial settings.
AZ::Vector3 m_position = AZ::Vector3::CreateZero();
AZ::Quaternion m_orientation = AZ::Quaternion::CreateIdentity();
AZ::Vector3 m_scale = AZ::Vector3::CreateOne();
bool m_startSimulationEnabled = true;
// Entity/object association.

@ -18,7 +18,6 @@
#include <AzCore/std/numeric.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Windowing/WindowBus.h>
namespace AzFramework
{
@ -160,24 +159,27 @@ namespace AzFramework
bool CameraSystem::HandleEvents(const InputEvent& event)
{
if (const auto& cursor = AZStd::get_if<CursorEvent>(&event))
if (const auto& horizonalMotion = AZStd::get_if<HorizontalMotionEvent>(&event))
{
m_cursorState.SetCurrentPosition(cursor->m_position);
m_motionDelta.m_x = horizonalMotion->m_delta;
}
else if (const auto& verticalMotion = AZStd::get_if<VerticalMotionEvent>(&event))
{
m_motionDelta.m_y = verticalMotion->m_delta;
}
else if (const auto& scroll = AZStd::get_if<ScrollEvent>(&event))
{
m_scrollDelta = scroll->m_delta;
}
return m_cameras.HandleEvents(event, m_cursorState.CursorDelta(), m_scrollDelta);
return m_cameras.HandleEvents(event, m_motionDelta, m_scrollDelta);
}
Camera CameraSystem::StepCamera(const Camera& targetCamera, const float deltaTime)
{
const auto nextCamera = m_cameras.StepCamera(targetCamera, m_cursorState.CursorDelta(), m_scrollDelta, deltaTime);
m_cursorState.Update();
const auto nextCamera = m_cameras.StepCamera(targetCamera, m_motionDelta, m_scrollDelta, deltaTime);
m_motionDelta = ScreenVector{0, 0};
m_scrollDelta = 0.0f;
return nextCamera;
@ -720,7 +722,7 @@ namespace AzFramework
return camera;
}
InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize)
InputEvent BuildInputEvent(const InputChannel& inputChannel)
{
const auto& inputChannelId = inputChannel.GetInputChannelId();
const auto& inputDeviceId = inputChannel.GetInputDevice().GetInputDeviceId();
@ -730,13 +732,13 @@ namespace AzFramework
return button == inputChannelId;
});
if (inputChannelId == InputDeviceMouse::Movement::X || inputChannelId == InputDeviceMouse::Movement::Y)
if (inputChannelId == InputDeviceMouse::Movement::X)
{
const auto* position = inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
AZ_Assert(position, "Expected PositionData2D but found nullptr");
return CursorEvent{ScreenPoint(
position->m_normalizedPosition.GetX() * windowSize.m_width, position->m_normalizedPosition.GetY() * windowSize.m_height)};
return HorizontalMotionEvent{(int)inputChannel.GetValue()};
}
else if (inputChannelId == InputDeviceMouse::Movement::Y)
{
return VerticalMotionEvent{(int)inputChannel.GetValue()};
}
else if (inputChannelId == InputDeviceMouse::Movement::Z)
{

@ -18,7 +18,6 @@
#include <AzCore/std/optional.h>
#include <AzFramework/Input/Channels/InputChannel.h>
#include <AzFramework/Viewport/ClickDetector.h>
#include <AzFramework/Viewport/CursorState.h>
#include <AzFramework/Viewport/ScreenGeometry.h>
#include <AzFramework/Viewport/ViewportId.h>
@ -72,11 +71,16 @@ namespace AzFramework
void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform);
struct CursorEvent
//! Generic motion type
template<typename MotionTag>
struct MotionEvent
{
ScreenPoint m_position;
int m_delta;
};
using HorizontalMotionEvent = MotionEvent<struct HorizontalMotionTag>;
using VerticalMotionEvent = MotionEvent<struct VerticalMotionTag>;
struct ScrollEvent
{
float m_delta;
@ -88,7 +92,7 @@ namespace AzFramework
InputChannel::State m_state; //!< Channel state. (e.g. Begin/update/end event).
};
using InputEvent = AZStd::variant<AZStd::monostate, CursorEvent, ScrollEvent, DiscreteInputEvent>;
using InputEvent = AZStd::variant<AZStd::monostate, HorizontalMotionEvent, VerticalMotionEvent, ScrollEvent, DiscreteInputEvent>;
class CameraInput
{
@ -194,6 +198,7 @@ namespace AzFramework
m_activeCameraInputs.begin(), m_activeCameraInputs.end(), [](const auto& cameraInput) { return cameraInput->Exclusive(); });
}
//! Responsible for updating a series of cameras given various inputs.
class CameraSystem
{
public:
@ -203,8 +208,8 @@ namespace AzFramework
Cameras m_cameras;
private:
CursorState m_cursorState;
float m_scrollDelta = 0.0f;
ScreenVector m_motionDelta; //!< The delta used for look/orbit/pan (rotation + translation) - two dimensional.
float m_scrollDelta = 0.0f; //!< The delta used for dolly/movement (translation) - one dimensional.
};
class RotateCameraInput : public CameraInput
@ -419,8 +424,6 @@ namespace AzFramework
return true;
}
struct WindowSize;
//! Map from a generic InputChannel event to a camera specific InputEvent.
InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize);
InputEvent BuildInputEvent(const InputChannel& inputChannel);
} // namespace AzFramework

@ -19,6 +19,8 @@
namespace AzNetworking
{
using NetworkInterfaces = AZStd::unordered_map<AZ::Name, AZStd::unique_ptr<INetworkInterface>>;
//! @class INetworking
//! @brief The interface for creating and working with network interfaces.
class INetworking
@ -60,5 +62,25 @@ namespace AzNetworking
//! @param name The name of the Compressor factory to unregister, must match result of factory->GetFactoryName()
//! @return Whether the factory was found and unregistered
virtual bool UnregisterCompressorFactory(AZ::Name name) = 0;
//! Returns the raw network interfaces owned by the networking instance.
//! @return the raw network interfaces owned by the networking instance
virtual const NetworkInterfaces& GetNetworkInterfaces() const = 0;
//! Returns the number of sockets monitored by our TcpListenThread.
//! @return the number of sockets monitored by our TcpListenThread
virtual uint32_t GetTcpListenThreadSocketCount() const = 0;
//! Returns the total time spent updating our TcpListenThread.
//! @return the total time spent updating our TcpListenThread
virtual AZ::TimeMs GetTcpListenThreadUpdateTime() const = 0;
//! Returns the number of sockets monitored by our UdpReaderThread.
//! @return the number of sockets monitored by our UdpReaderThread
virtual uint32_t GetUdpReaderThreadSocketCount() const = 0;
//! Returns the total time spent updating our UdpReaderThread.
//! @return the total time spent updating our UdpReaderThread
virtual AZ::TimeMs GetUdpReaderThreadUpdateTime() const = 0;
};
}

@ -149,12 +149,37 @@ namespace AzNetworking
return m_compressorFactories.erase(name) > 0;
}
const NetworkInterfaces& NetworkingSystemComponent::GetNetworkInterfaces() const
{
return m_networkInterfaces;
}
uint32_t NetworkingSystemComponent::GetTcpListenThreadSocketCount() const
{
return m_listenThread->GetSocketCount();
}
AZ::TimeMs NetworkingSystemComponent::GetTcpListenThreadUpdateTime() const
{
return m_listenThread->GetUpdateTimeMs();
}
uint32_t NetworkingSystemComponent::GetUdpReaderThreadSocketCount() const
{
return m_readerThread->GetSocketCount();
}
AZ::TimeMs NetworkingSystemComponent::GetUdpReaderThreadUpdateTime() const
{
return m_readerThread->GetUpdateTimeMs();
}
void NetworkingSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
AZLOG_INFO("Total sockets monitored by TcpListenThread: %u", m_listenThread->GetSocketCount());
AZLOG_INFO("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(m_listenThread->GetUpdateTimeMs()));
AZLOG_INFO("Total sockets monitored by UdpReaderThread: %u", m_readerThread->GetSocketCount());
AZLOG_INFO("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(m_readerThread->GetUpdateTimeMs()));
AZLOG_INFO("Total sockets monitored by TcpListenThread: %u", GetTcpListenThreadSocketCount());
AZLOG_INFO("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(GetTcpListenThreadUpdateTime()));
AZLOG_INFO("Total sockets monitored by UdpReaderThread: %u", GetUdpReaderThreadSocketCount());
AZLOG_INFO("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(GetUdpReaderThreadUpdateTime()));
for (auto& networkInterface : m_networkInterfaces)
{

@ -63,6 +63,11 @@ namespace AzNetworking
void RegisterCompressorFactory(ICompressorFactory* factory) override;
AZStd::unique_ptr<ICompressor> CreateCompressor(AZ::Name name) override;
bool UnregisterCompressorFactory(AZ::Name name) override;
const NetworkInterfaces& GetNetworkInterfaces() const override;
uint32_t GetTcpListenThreadSocketCount() const override;
AZ::TimeMs GetTcpListenThreadUpdateTime() const override;
uint32_t GetUdpReaderThreadSocketCount() const override;
AZ::TimeMs GetUdpReaderThreadUpdateTime() const override;
//! @}
//! Console commands.
@ -74,7 +79,6 @@ namespace AzNetworking
AZ_CONSOLEFUNC(NetworkingSystemComponent, DumpStats, AZ::ConsoleFunctorFlags::Null, "Dumps stats for all instantiated network interfaces");
using NetworkInterfaces = AZStd::unordered_map<AZ::Name, AZStd::unique_ptr<INetworkInterface>>;
NetworkInterfaces m_networkInterfaces;
AZStd::unique_ptr<TcpListenThread> m_listenThread;
AZStd::unique_ptr<UdpReaderThread> m_readerThread;

@ -46,6 +46,12 @@ namespace AzNetworking
void TcpSocketManager::ProcessEvents(AZ::TimeMs maxBlockMs, const SocketEventCallback& readCallback, const SocketEventCallback& writeCallback)
{
if(static_cast<int32_t>(m_maxFd) <= 0 && m_socketFds.empty())
{
// There are no available sockets to process
return;
}
m_readerFdSet = m_sourceFdSet;
m_writerFdSet = m_sourceFdSet;

@ -93,28 +93,12 @@ namespace AzToolsFramework
EditorContextMenuBus::Handler::BusConnect();
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
AZ::Interface<PrefabIntegrationInterface>::Register(this);
bool prefabWipFeaturesEnabled = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
if (prefabWipFeaturesEnabled)
{
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
}
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
}
PrefabIntegrationManager::~PrefabIntegrationManager()
{
bool prefabWipFeaturesEnabled = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
if (prefabWipFeaturesEnabled)
{
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
}
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
AZ::Interface<PrefabIntegrationInterface>::Unregister(this);
PrefabInstanceContainerNotificationBus::Handler::BusDisconnect();
EditorContextMenuBus::Handler::BusDisconnect();
@ -137,66 +121,63 @@ namespace AzToolsFramework
void PrefabIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu) const
{
bool prefabWipFeaturesEnabled = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
AzToolsFramework::EntityIdList selectedEntities;
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
selectedEntities, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
if (prefabWipFeaturesEnabled)
bool prefabWipFeaturesEnabled = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
// Create Prefab
{
// Create Prefab
if (!selectedEntities.empty())
{
if (!selectedEntities.empty())
// Hide if the only selected entity is the Level Container
if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))
{
// Hide if the only selected entity is the Level Container
if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))
{
bool layerInSelection = false;
bool layerInSelection = false;
for (AZ::EntityId entityId : selectedEntities)
for (AZ::EntityId entityId : selectedEntities)
{
if (!layerInSelection)
{
if (!layerInSelection)
{
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
layerInSelection, entityId,
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
layerInSelection, entityId,
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
if (layerInSelection)
{
break;
}
if (layerInSelection)
{
break;
}
}
}
// Layers can't be in prefabs.
if (!layerInSelection)
{
QAction* createAction = menu->addAction(QObject::tr("Create Prefab..."));
createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities."));
// Layers can't be in prefabs.
if (!layerInSelection)
{
QAction* createAction = menu->addAction(QObject::tr("Create Prefab..."));
createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities."));
QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] {
ContextMenu_CreatePrefab(selectedEntities);
});
}
QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] {
ContextMenu_CreatePrefab(selectedEntities);
});
}
}
}
}
// Instantiate Prefab
{
QAction* instantiateAction = menu->addAction(QObject::tr("Instantiate Prefab..."));
instantiateAction->setToolTip(QObject::tr("Instantiates a prefab file in the scene."));
QObject::connect(
instantiateAction, &QAction::triggered, instantiateAction, [this] { ContextMenu_InstantiatePrefab(); });
}
// Instantiate Prefab
{
QAction* instantiateAction = menu->addAction(QObject::tr("Instantiate Prefab..."));
instantiateAction->setToolTip(QObject::tr("Instantiates a prefab file in the scene."));
menu->addSeparator();
QObject::connect(
instantiateAction, &QAction::triggered, instantiateAction, [this] { ContextMenu_InstantiatePrefab(); });
}
menu->addSeparator();
bool itemWasShown = false;
// Edit/Save Prefab

@ -15,7 +15,6 @@
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Viewport/CameraInput.h>
#include <AzFramework/Windowing/WindowBus.h>
namespace UnitTest
{
@ -68,23 +67,21 @@ namespace UnitTest
TEST_F(CameraInputFixture, BeginEndOrbitCameraConsumesCorrectEvents)
{
// set initial mouse position
const bool consumed1 = HandleEventAndUpdate(AzFramework::CursorEvent{AzFramework::ScreenPoint(5, 5)});
// begin orbit camera
const bool consumed2 = HandleEventAndUpdate(
const bool consumed1 = HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceKeyboard::Key::ModifierAltL, AzFramework::InputChannel::State::Began});
// begin listening for orbit rotate (click detector) - event is not consumed
const bool consumed3 = HandleEventAndUpdate(
const bool consumed2 = HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began});
// begin orbit rotate (mouse has moved sufficient distance to initiate)
const bool consumed4 = HandleEventAndUpdate(AzFramework::CursorEvent{AzFramework::ScreenPoint(10, 10)});
const bool consumed3 = HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{5});
// end orbit (mouse up) - event is not consumed
const bool consumed5 = HandleEventAndUpdate(
const bool consumed4 = HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Ended});
const auto allConsumed = AZStd::vector<bool>{consumed1, consumed2, consumed3, consumed4, consumed5};
const auto allConsumed = AZStd::vector<bool>{consumed1, consumed2, consumed3, consumed4};
using ::testing::ElementsAre;
EXPECT_THAT(allConsumed, ElementsAre(false, true, false, true, false));
EXPECT_THAT(allConsumed, ElementsAre(true, false, true, false));
}
} // namespace UnitTest

@ -109,13 +109,9 @@ namespace SandboxEditor
bool ModernViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
{
AzFramework::WindowSize windowSize;
AzFramework::WindowRequestBus::EventResult(
windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
if (ShouldHandle(event.m_priority, m_cameraSystem.m_cameras.Exclusive()))
{
return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel, windowSize));
return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel));
}
return false;

@ -508,6 +508,42 @@ namespace O3DE::ProjectManager
}
}
bool PythonBindings::AddGemToProject(const QString& gemPath, const QString& projectPath)
{
bool result = ExecuteWithLock([&] {
pybind11::str pyGemPath = gemPath.toStdString();
pybind11::str pyProjectPath = projectPath.toStdString();
m_registration.attr("add_gem_to_project")(
pybind11::none(), // gem_name
pyGemPath,
pybind11::none(), // gem_target
pybind11::none(), // project_name
pyProjectPath
);
});
return result;
}
bool PythonBindings::RemoveGemFromProject(const QString& gemPath, const QString& projectPath)
{
bool result = ExecuteWithLock([&] {
pybind11::str pyGemPath = gemPath.toStdString();
pybind11::str pyProjectPath = projectPath.toStdString();
m_registration.attr("remove_gem_to_project")(
pybind11::none(), // gem_name
pyGemPath,
pybind11::none(), // gem_target
pybind11::none(), // project_name
pyProjectPath
);
});
return result;
}
bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo)
{
return false;

@ -47,6 +47,8 @@ namespace O3DE::ProjectManager
AZ::Outcome<ProjectInfo> GetProject(const QString& path) override;
AZ::Outcome<QVector<ProjectInfo>> GetProjects() override;
bool UpdateProject(const ProjectInfo& projectInfo) override;
bool AddGemToProject(const QString& gemPath, const QString& projectPath) override;
bool RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override;
// ProjectTemplate
AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates() override;

@ -96,6 +96,22 @@ namespace O3DE::ProjectManager
*/
virtual bool UpdateProject(const ProjectInfo& projectInfo) = 0;
/**
* Add a gem to a project
* @param gemPath the absolute path to the gem
* @param projectPath the absolute path to the project
* @return true on success, false on failure
*/
virtual bool AddGemToProject(const QString& gemPath, const QString& projectPath) = 0;
/**
* Remove gem to a project
* @param gemPath the absolute path to the gem
* @param projectPath the absolute path to the project
* @return true on success, false on failure
*/
virtual bool RemoveGemFromProject(const QString& gemPath, const QString& projectPath) = 0;
// Project Templates

@ -75,13 +75,13 @@ namespace AZ
const bool allMeshesHaveTangentsAndBitangents = AZStd::all_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
if (!allMeshesHaveTangentsAndBitangents)
{
const char* mixedBitangentsError =
"Node with name %s has meshes with and without bitangents. "
"Placeholder incorrect bitangents will be generated to allow the data to process, "
"but the source art needs to be fixed to correct this. Either apply bitangents to all meshes on this node, "
"or remove all bitangents from all meshes on this node.";
AZ_Error(
Utilities::ErrorWindow, false, mixedBitangentsError, currentNode->mName.C_Str());
Utilities::ErrorWindow, false,
"Node with name %s has meshes with and without bitangents. "
"Placeholder incorrect bitangents will be generated to allow the data to process, "
"but the source art needs to be fixed to correct this. Either apply bitangents to all meshes on this node, "
"or remove all bitangents from all meshes on this node.",
currentNode->mName.C_Str());
}
const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);

@ -77,13 +77,13 @@ namespace AZ
const bool allMeshesHaveTangentsAndBitangents = AZStd::all_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
if (!allMeshesHaveTangentsAndBitangents)
{
const char* mixedTangentsError =
"Node with name %s has meshes with and without tangents. "
"Placeholder incorrect tangents will be generated to allow the data to process, "
"but the source art needs to be fixed to correct this. Either apply tangents to all meshes on this node, "
"or remove all tangents from all meshes on this node.";
AZ_Error(
Utilities::ErrorWindow, false, mixedTangentsError, currentNode->mName.C_Str());
Utilities::ErrorWindow, false,
"Node with name %s has meshes with and without tangents. "
"Placeholder incorrect tangents will be generated to allow the data to process, "
"but the source art needs to be fixed to correct this. Either apply tangents to all meshes on this node, "
"or remove all tangents from all meshes on this node.",
currentNode->mName.C_Str());
}
const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);

@ -89,13 +89,13 @@ namespace AZ
for (int texCoordIndex = 0; texCoordIndex < meshesPerTextureCoordinateIndex.size(); ++texCoordIndex)
{
int meshesWithIndex = meshesPerTextureCoordinateIndex[texCoordIndex];
AZ_Error(
Utilities::ErrorWindow,
meshesWithIndex == 0 || meshesWithIndex == currentNode->mNumMeshes,
meshesPerTextureCoordinateIndex[texCoordIndex] == 0 ||
meshesPerTextureCoordinateIndex[texCoordIndex] == currentNode->mNumMeshes,
"Texture coordinate index %d for node %s is not on all meshes on this node. "
"Placeholder arbitrary texture values will be generated to allow the data to process, but the source art "
"needs to be fixed to correct this. All meshes on this node should have the same number of texture coordinate channels.",
"Placeholder arbitrary texture values will be generated to allow the data to process, but the source art "
"needs to be fixed to correct this. All meshes on this node should have the same number of texture coordinate channels.",
texCoordIndex,
currentNode->mName.C_Str());
}

@ -39,4 +39,4 @@ namespace AWSClientAuth
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
AZ_DECLARE_MODULE_CLASS(AWSClientAuth_c74f2756f5874c0d8d29646dfc9cb0ad, AWSClientAuth::AWSClientAuthModule)
AZ_DECLARE_MODULE_CLASS(Gem_AWSClientAuth, AWSClientAuth::AWSClientAuthModule)

@ -32,4 +32,4 @@ namespace AWSMetrics
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
AZ_DECLARE_MODULE_CLASS(AWSMetrics_cc6fc7a18fc047039a369a26100fcbbe, AWSMetrics::AWSMetricsModule)
AZ_DECLARE_MODULE_CLASS(Gem_AWSMetrics, AWSMetrics::AWSMetricsModule)

@ -98,7 +98,6 @@ ly_add_target(
Gem::Atom_RPI.Edit
RUNTIME_DEPENDENCIES
3rdParty::DirectXShaderCompilerDxc
3rdParty::DirectXShaderCompilerDxcAz
3rdParty::SPIRVCross
3rdParty::azslc
)

@ -118,7 +118,7 @@ namespace AZ
// Register Shader Asset Builder
AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor;
shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder";
shaderAssetBuilderDescriptor.m_version = 99; // ATOM-15276
shaderAssetBuilderDescriptor.m_version = 100; // ATOM-14298
// .shader file changes trigger rebuilds
shaderAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderAssetBuilder>();
@ -133,7 +133,7 @@ namespace AZ
shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder";
// Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update
// ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder".
shaderVariantAssetBuilderDescriptor.m_version = 20; // ATOM-15276
shaderVariantAssetBuilderDescriptor.m_version = 21; // ATOM-14298
shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderVariantAssetBuilder>();
shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);

@ -31,8 +31,7 @@
},
"CompilerHints" : {
"DisableOptimizations" : true,
"DxcGenerateDebugInfo" : true
"DisableOptimizations" : false
},
"ProgramSettings":

@ -91,7 +91,7 @@ float3 SampleProbeIrradiance(uint2 probeIrradianceCoords, float depth, float3 no
{
for (int x = -extent; x <= extent; ++x)
{
float3 downsampledNormal = PassSrg::m_downsampledNormal.Load(int3(probeIrradianceCoords, 0), int2(x, y)).rgb;
float3 downsampledNormal = PassSrg::m_downsampledNormal.Load(int3(probeIrradianceCoords + int2(x, y), 0)).rgb;
downsampledNormal = downsampledNormal * 2.0f - 1.0f;
float normalDot = dot(downsampledNormal, normal);
@ -100,10 +100,10 @@ float3 SampleProbeIrradiance(uint2 probeIrradianceCoords, float depth, float3 no
if (normalDot > NormalMatchTolerance)
{
// the normals are almost identical, if the depth is within the tolerance we can optimize by just taking this sample
float downsampledDepth = PassSrg::m_downsampledDepth.Load(int3(probeIrradianceCoords, 0), int2(x, y)).r;
float downsampledDepth = PassSrg::m_downsampledDepth.Load(int3(probeIrradianceCoords + int2(x, y), 0)).r;
if (abs(depth - downsampledDepth) <= DepthTolerance)
{
float3 probeIrradiance = PassSrg::m_downsampledProbeIrradiance.Load(int3(probeIrradianceCoords,0), int2(x, y)).rgb;
float3 probeIrradiance = PassSrg::m_downsampledProbeIrradiance.Load(int3(probeIrradianceCoords + int2(x, y),0)).rgb;
probeIrradiance = saturate(probeIrradiance);
return probeIrradiance;
}
@ -115,7 +115,7 @@ float3 SampleProbeIrradiance(uint2 probeIrradianceCoords, float depth, float3 no
}
}
float3 probeIrradiance = PassSrg::m_downsampledProbeIrradiance.Load(int3(probeIrradianceCoords, 0), closestOffset).rgb;
float3 probeIrradiance = PassSrg::m_downsampledProbeIrradiance.Load(int3(probeIrradianceCoords + closestOffset, 0)).rgb;
probeIrradiance = saturate(probeIrradiance);
return probeIrradiance;
}

@ -70,8 +70,8 @@ PSOutput MainPS(VSOutput IN)
{
for (uint x = 0; x < ImageScale; ++x)
{
float depth = PassSrg::m_depth.Load(int3(screenCoords, 0), int2(x, y)).r;
float4 encodedNormal = PassSrg::m_normal.Load(int3(screenCoords, 0), int2(x, y));
float depth = PassSrg::m_depth.Load(int3(screenCoords + int2(x, y), 0)).r;
float4 encodedNormal = PassSrg::m_normal.Load(int3(screenCoords + int2(x, y), 0));
// take the closest depth sample to ensure we're getting the normal closest to the viewer
// (larger depth value due to reverse depth)

@ -11,7 +11,7 @@
*/
#pragma once
#define AZ_TRAIT_ATOM_SHADERBUILDER_DXC "Builders/DirectXShaderCompilerAz/dxc.exe"
#define AZ_TRAIT_ATOM_SHADERBUILDER_DXC "Builders/DirectXShaderCompiler/dxc.exe"
#define AZ_TRAIT_ATOM_VULKAN_DISABLE_DUAL_SOURCE_BLENDING 0
#define AZ_TRAIT_ATOM_VULKAN_DLL "vulkan.dll"
#define AZ_TRAIT_ATOM_VULKAN_DLL_1 "vulkan-1.dll"

@ -334,6 +334,7 @@ namespace AZ
if (it == m_propertyMetadata.end())
{
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property: %s.", propertyName.GetCStr());
return nullptr;
}
return &it->second;
@ -345,6 +346,7 @@ namespace AZ
if (it == m_propertyGroupMetadata.end())
{
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property group: %s.", propertyGroupName.GetCStr());
return nullptr;
}
return &it->second;

@ -269,13 +269,13 @@ namespace AZ
{
ImGui::BeginChild(heapMemoryId.c_str());
ImGui::SetScrollY(scrollingY);
ImGui::End();
ImGui::EndChild();
}
{
ImGui::BeginChild(scopesId.c_str());
ImGui::SetScrollX(scrollingX);
ImGui::End();
ImGui::EndChild();
}
ImGui::PopStyleVar(3);

@ -12,7 +12,7 @@
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME AtomFont ${PAL_TRAIT_MONOLITHIC_DRIVEN_LIBRARY_TYPE}
NAME AtomFont ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
FILES_CMAKE
atomfont_files.cmake

@ -304,6 +304,11 @@ namespace AZ
for (auto& groupPair : m_groups)
{
AZ::RPI::MaterialPropertyGroupDynamicMetadata& metadata = propertyGroupDynamicMetadata[AZ::Name{groupPair.first}];
for (auto& property : groupPair.second.m_properties)
{
AtomToolsFramework::ConvertToPropertyMetaData(propertyDynamicMetadata[property.GetId()], property.GetConfig());
}
// It's significant that we check IsGroupHidden rather than IsGroupVisisble, because it follows the same rules as QWidget::isHidden().
// We don't care whether the widget and all its parents are visible, we only care about whether the group was hidden within the context

@ -32,10 +32,11 @@ namespace Blast
Physics::MaterialId m_physicsMaterialId;
AZ::Vector3 m_parentLinearVelocity = AZ::Vector3::CreateZero();
AZ::Vector3 m_parentCenterOfMass = AZ::Vector3::CreateZero();
AzPhysics::RigidBodyConfiguration m_bodyConfiguration; //! Either rigid dynamic or rigid static
AZStd::vector<uint32_t> m_chunkIndices; //! Chunks that are going to simulate this actor.
AZStd::shared_ptr<AZ::Entity> m_entity; //! Entity that the actor should use to simulate rigid body
bool m_isStatic = false; //! Denotes whether actor should be simulated by a static or dynamic rigid body.
bool m_isLeafChunk = false; //! Denotes whether this actor represented by a single leaf chunk.
AzPhysics::RigidBodyConfiguration m_bodyConfiguration; //!< Either rigid dynamic or rigid static
AZStd::vector<uint32_t> m_chunkIndices; //!< Chunks that are going to simulate this actor.
AZStd::shared_ptr<AZ::Entity> m_entity; //!< Entity that the actor should use to simulate rigid body
bool m_isStatic = false; //!< Denotes whether actor should be simulated by a static or dynamic rigid body.
bool m_isLeafChunk = false; //!< Denotes whether this actor represented by a single leaf chunk.
float m_scale = 1.0f; //!< Uniform scale applied to the actor.
};
} // namespace Blast

@ -45,6 +45,7 @@ namespace Blast
, m_parentLinearVelocity(desc.m_parentLinearVelocity)
, m_parentCenterOfMass(desc.m_parentCenterOfMass)
, m_bodyConfiguration(desc.m_bodyConfiguration)
, m_scale(desc.m_scale)
{
// Store pointer to ourselves in the blast toolkit actor's userData
m_tkActor.userData = this;
@ -67,7 +68,7 @@ namespace Blast
auto transform = AZ::Transform::CreateFromQuaternionAndTranslation(
m_bodyConfiguration.m_orientation, m_bodyConfiguration.m_position);
transform.MultiplyByScale(m_bodyConfiguration.m_scale);
transform.MultiplyByScale(AZ::Vector3(m_scale));
AZ::TransformBus::Event(m_entity->GetId(), &AZ::TransformInterface::SetWorldTM, transform);
@ -130,7 +131,7 @@ namespace Blast
Physics::NativeShapeConfiguration shapeConfiguration;
shapeConfiguration.m_nativeShapePtr =
reinterpret_cast<void*>(const_cast<physx::PxConvexMeshGeometry*>(&subchunk.geometry)->convexMesh);
shapeConfiguration.m_nativeShapeScale = m_bodyConfiguration.m_scale;
shapeConfiguration.m_nativeShapeScale = AZ::Vector3(m_scale);
AZStd::shared_ptr<Physics::Shape> shape = AZ::Interface<Physics::SystemRequests>::Get()->CreateShape(
colliderConfiguration, shapeConfiguration);

@ -77,5 +77,6 @@ namespace Blast
AZ::Vector3 m_parentLinearVelocity = AZ::Vector3::CreateZero();
AZ::Vector3 m_parentCenterOfMass = AZ::Vector3::CreateZero();
AzPhysics::RigidBodyConfiguration m_bodyConfiguration;
float m_scale = 1.0f;
};
} // namespace Blast

@ -147,6 +147,7 @@ namespace Blast
void BlastFamilyComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("BlastFamilyService"));
incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
}
void BlastFamilyComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)

@ -85,6 +85,7 @@ namespace Blast
void EditorBlastFamilyComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("BlastFamilyService"));
incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
}
void EditorBlastFamilyComponent::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)

@ -43,6 +43,7 @@ namespace Blast
AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("BlastMeshDataService"));
incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
}
void EditorBlastMeshDataComponent::Reflect(AZ::ReflectContext* context)

@ -202,7 +202,7 @@ namespace Blast
if (parentBody)
{
parentTransform = parentBody->GetTransform();
parentTransform.MultiplyByScale(m_initialTransform.GetScale());
parentTransform.MultiplyByScale(AZ::Vector3(m_initialTransform.GetScale().GetMaxElement()));
}
else
{
@ -239,7 +239,6 @@ namespace Blast
AzPhysics::RigidBodyConfiguration configuration;
configuration.m_position = transform.GetTranslation();
configuration.m_orientation = transform.GetRotation();
configuration.m_scale = transform.GetScale();
configuration.m_ccdEnabled = m_actorConfiguration.m_isCcdEnabled;
configuration.m_startSimulationEnabled = m_actorConfiguration.m_isSimulated;
configuration.m_initialAngularVelocity = AZ::Vector3::CreateZero();
@ -255,6 +254,7 @@ namespace Blast
actorDesc.m_parentCenterOfMass = transform.GetTranslation();
actorDesc.m_parentLinearVelocity = AZ::Vector3::CreateZero();
actorDesc.m_bodyConfiguration = configuration;
actorDesc.m_scale = transform.GetScale().GetMaxElement();
return actorDesc;
}

@ -137,7 +137,7 @@ namespace Blast
.Times(1)
.WillOnce(Return(false));
AZ::Transform transform = AZ::Transform::CreateScale(AZ::Vector3::CreateOne());
AZ::Transform transform = AZ::Transform::CreateIdentity();
blastFamily->Spawn(transform);
}

@ -35,6 +35,7 @@ namespace Multiplayer
using EntityStopEvent = AZ::Event<const ConstNetworkEntityHandle&>;
using EntityDirtiedEvent = AZ::Event<>;
using EntitySyncRewindEvent = AZ::Event<>;
using EntityMigrationStartEvent = AZ::Event<ClientInputId>;
using EntityMigrationEndEvent = AZ::Event<>;
using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>;
@ -73,6 +74,7 @@ namespace Multiplayer
NetworkEntityHandle GetEntityHandle();
void SetOwningConnectionId(AzNetworking::ConnectionId connectionId);
AzNetworking::ConnectionId GetOwningConnectionId() const;
void SetAllowAutonomy(bool value);
MultiplayerComponentInputVector AllocateComponentInputs();
bool IsProcessingInput() const;
@ -91,12 +93,14 @@ namespace Multiplayer
void MarkDirty();
void NotifyLocalChanges();
void NotifySyncRewindState();
void NotifyMigrationStart(ClientInputId migratedInputId);
void NotifyMigrationEnd();
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler);
void AddEntitySyncRewindEventHandler(EntitySyncRewindEvent::Handler& eventHandler);
void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler);
void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler);
void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler);
@ -144,6 +148,7 @@ namespace Multiplayer
EntityStopEvent m_entityStopEvent;
EntityDirtiedEvent m_dirtiedEvent;
EntitySyncRewindEvent m_syncRewindEvent;
EntityMigrationStartEvent m_entityMigrationStartEvent;
EntityMigrationEndEvent m_entityMigrationEndEvent;
EntityServerMigrationEvent m_entityServerMigrationEvent;
@ -157,6 +162,8 @@ namespace Multiplayer
NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;
NetEntityId m_netEntityId = InvalidNetEntityId;
AzNetworking::ConnectionId m_owningConnectionId = AzNetworking::InvalidConnectionId;
bool m_isProcessingInput = false;
bool m_isMigrationDataValid = false;
bool m_needsToBeStopped = false;

@ -48,7 +48,6 @@ namespace Multiplayer
using ConnectionAcquiredEvent = AZ::Event<MultiplayerAgentDatum>;
using SessionInitEvent = AZ::Event<AzNetworking::INetworkInterface*>;
using SessionShutdownEvent = AZ::Event<AzNetworking::INetworkInterface*>;
using OnConnectFunctor = AZStd::function<NetworkEntityHandle(AzNetworking::IConnection*, MultiplayerAgentDatum)>;
//! IMultiplayer provides insight into the Multiplayer session and its Agents
class IMultiplayer
@ -78,10 +77,6 @@ namespace Multiplayer
//! @param handler The SessionShutdownEvent handler to add
virtual void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) = 0;
//! Overrides the default connect behaviour with the provided functor.
//! @param functor the function to invoke during a new connection event
virtual void SetOnConnectFunctor(const OnConnectFunctor& functor) = 0;
//! Sends a packet telling if entity update messages can be sent
//! @param readyForEntityUpdates Ready for entity updates or not
virtual void SendReadyForEntityUpdates(bool readyForEntityUpdates) = 0;

@ -18,6 +18,7 @@
#include <AzCore/std/string/fixed_string.h>
#include <AzNetworking/Serialization/ISerializer.h>
#include <AzNetworking/ConnectionLayer/ConnectionEnums.h>
#include <AzNetworking/DataStructures/ByteBuffer.h>
namespace Multiplayer
{
@ -85,8 +86,7 @@ namespace Multiplayer
Activate
};
// This is just a placeholder
// The level/prefab cooking will devise the actual solution for identifying a dynamically spawnable entity within a prefab
// Structure for identifying a specific entity within a spawnable
struct PrefabEntityId
{
AZ_TYPE_INFO(PrefabEntityId, "{EFD37465-CCAC-4E87-A825-41B4010A2C75}");
@ -121,6 +121,13 @@ namespace Multiplayer
return serializer.IsValid();
}
};
struct EntityMigrationMessage
{
NetEntityId m_entityId;
PrefabEntityId m_prefabEntityId;
AzNetworking::PacketEncodingBuffer m_propertyUpdateData;
};
}
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::HostId);

@ -24,14 +24,12 @@ namespace Multiplayer
ReplicationRecordStats() = default;
ReplicationRecordStats
(
uint32_t authorityToAuthorityCount,
uint32_t authorityToClientCount,
uint32_t authorityToServerCount,
uint32_t authorityToAutonomousCount,
uint32_t autonomousToAuthorityCount
);
uint32_t m_authorityToAuthorityCount = 0;
uint32_t m_authorityToClientCount = 0;
uint32_t m_authorityToServerCount = 0;
uint32_t m_authorityToAutonomousCount = 0;
@ -63,19 +61,16 @@ namespace Multiplayer
bool Serialize(AzNetworking::ISerializer& serializer);
void ConsumeAuthorityToAuthorityBits(uint32_t consumedBits);
void ConsumeAuthorityToClientBits(uint32_t consumedBits);
void ConsumeAuthorityToServerBits(uint32_t consumedBits);
void ConsumeAuthorityToAutonomousBits(uint32_t consumedBits);
void ConsumeAutonomousToAuthorityBits(uint32_t consumedBits);
bool ContainsAuthorityToAuthorityBits() const;
bool ContainsAuthorityToClientBits() const;
bool ContainsAuthorityToServerBits() const;
bool ContainsAuthorityToAutonomousBits() const;
bool ContainsAutonomousToAuthorityBits() const;
uint32_t GetRemainingAuthorityToAuthorityBits() const;
uint32_t GetRemainingAuthorityToClientBits() const;
uint32_t GetRemainingAuthorityToServerBits() const;
uint32_t GetRemainingAuthorityToAutonomousBits() const;
@ -84,13 +79,11 @@ namespace Multiplayer
ReplicationRecordStats GetStats() const;
using RecordBitset = AzNetworking::FixedSizeVectorBitset<MaxRecordBits>;
RecordBitset m_authorityToAuthority;
RecordBitset m_authorityToClient;
RecordBitset m_authorityToServer;
RecordBitset m_authorityToAutonomous;
RecordBitset m_autonomousToAuthority;
uint32_t m_authorityToAuthorityConsumedBits = 0;
uint32_t m_authorityToClientConsumedBits = 0;
uint32_t m_authorityToServerConsumedBits = 0;
uint32_t m_authorityToAutonomousConsumedBits = 0;

@ -188,6 +188,69 @@ virtual void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnect
{% endmacro %}
{#
#}
{% macro DeclareRpcEventGetter(Property, HandleOn) %}
{% set paramNames = [] %}
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{% set PropertyName = UpperFirst(Property.attrib['Name']) %}
{{ ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
AZ::Event<{{ ', '.join(paramTypes) }}>& Get{{ PropertyName }}Event() { return m_{{ PropertyName }}Event; }
{% endmacro %}
{#
#}
{% macro DeclareRpcEventGetters(Component, InvokeFrom, HandleOn) %}
{% call(Property) ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
{{- DeclareRpcEventGetter(Property, HandleOn) -}}
{% endif %}
{% endcall %}
{% endmacro %}
{#
#}
{% macro DeclareRpcEvent(Property, HandleOn) %}
{% set paramNames = [] %}
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{% set PropertyName = UpperFirst(Property.attrib['Name']) %}
{{ ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
AZ::Event<{{ ', '.join(paramTypes) }}> m_{{ PropertyName }}Event;
{% endmacro %}
{#
#}
{% macro DeclareRpcEvents(Component, InvokeFrom, HandleOn) %}
{% call(Property) ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
{{- DeclareRpcEvent(Property, HandleOn) -}}
{% endif %}
{% endcall %}
{% endmacro %}
{#
#}
{% macro DeclareRpcSignal(Property, HandleOn) %}
{% set paramNames = [] %}
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{% set PropertyName = UpperFirst(Property.attrib['Name']) %}
{{ ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
void Signal{{ PropertyName }}({{ ', '.join(paramDefines) }});
{% endmacro %}
{#
#}
{% macro DeclareRpcSignals(Component, InvokeFrom, HandleOn) %}
{% call(Property) ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
{{- DeclareRpcSignal(Property, HandleOn) -}}
{% endif %}
{% endcall %}
{% endmacro %}
{#
#}
{%- macro EmitDerivedClassesComment(dataFileNames, Component, ComponentName, ComponentNameBase, ComponentDerived, ControllerName, ControllerNameBase, ControllerDerived, NetworkInputCount) -%}
{% if ComponentDerived or ControllerDerived %}
@ -214,6 +277,10 @@ namespace {{ Component.attrib['Namespace'] }}
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
{{ DeclareRpcHandlers(Component, 'Authority', 'Client', true)|indent(8) }}
{{ DeclareRpcSignals(Component, 'Authority', 'Client')|indent(8) }}
{{ DeclareRpcEventGetters(Component, 'Authority', 'Client')|indent(8) }}
protected:
{{ DeclareRpcEvents(Component, 'Authority', 'Client')|indent(8) }}
};
{% endif %}
@ -236,6 +303,20 @@ namespace {{ Component.attrib['Namespace'] }}
{{ DeclareRpcHandlers(Component, 'Client', 'Authority', true)|indent(8) }}
{{ DeclareRpcHandlers(Component, 'Autonomous', 'Authority', true)|indent(8) }}
{{ DeclareRpcHandlers(Component, 'Authority', 'Autonomous', true)|indent(8) }}
{{ DeclareRpcSignals(Component, 'Server', 'Authority')|indent(8) }}
{{ DeclareRpcSignals(Component, 'Client', 'Authority')|indent(8) }}
{{ DeclareRpcSignals(Component, 'Autonomous', 'Authority')|indent(8) }}
{{ DeclareRpcSignals(Component, 'Authority', 'Autonomous')|indent(8) }}
{{ DeclareRpcEventGetters(Component, 'Server', 'Authority')|indent(8) }}
{{ DeclareRpcEventGetters(Component, 'Client', 'Authority')|indent(8) }}
{{ DeclareRpcEventGetters(Component, 'Autonomous', 'Authority')|indent(8) }}
{{ DeclareRpcEventGetters(Component, 'Authority', 'Autonomous')|indent(8) }}
protected:
{{ DeclareRpcEvents(Component, 'Server', 'Authority')|indent(8) }}
{{ DeclareRpcEvents(Component, 'Client', 'Authority')|indent(8) }}
{{ DeclareRpcEvents(Component, 'Autonomous', 'Authority')|indent(8) }}
{{ DeclareRpcEvents(Component, 'Authority', 'Autonomous')|indent(8) }}
};
{% endif %}
}

@ -125,7 +125,7 @@ void {{ PropertyName }}({{ ', '.join(paramDefines) }});
{% macro DeclareRpcInvocations(Component, Section, HandleOn, ProctectedSection) %}
{% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, Section, HandleOn) %}
{% if Property.attrib['IsPublic']|booleanTrue == ProctectedSection %}
{{- DeclareRpcInvocation(Property, HandleOn) -}}
{{ DeclareRpcInvocation(Property, HandleOn) -}}
{% endif %}
{% endcall %}
{% endmacro %}
@ -274,13 +274,6 @@ namespace {{ Component.attrib['Namespace'] }}
//! Sets the bits in the attached record that correspond to predictable network properties.
void SetPredictableBits();
{% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Authority') %}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
{% if networkPropertyCount.value > 0 %}
AzNetworking::FixedSizeBitsetView m_authorityToAuthority;
{% endif %}
{% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Client') %}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
@ -293,7 +286,7 @@ namespace {{ Component.attrib['Namespace'] }}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
{% if networkPropertyCount.value > 0 %}
AzNetworking::FixedSizeBitsetView m_authorityToServer};
AzNetworking::FixedSizeBitsetView m_authorityToServer;
{% endif %}
{% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Autonomous') %}
@ -314,7 +307,6 @@ namespace {{ Component.attrib['Namespace'] }}
{{ RecordName }}
(
Multiplayer::ReplicationRecord& replicationRecord,
uint32_t authorityToAuthoritySimluationStartOffset,
uint32_t authorityToClientSimluationStartOffset,
uint32_t authorityToServerSimluationStartOffset,
uint32_t authorityToAutonomousStartOffset,
@ -367,14 +359,12 @@ namespace {{ Component.attrib['Namespace'] }}
void ProcessInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime) override {}
//! @}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Authority', false)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Authority', true)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Server', false)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Server', true)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Client', false)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Client', true)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Autonomous', false)|indent(8) }}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Autonomous', true)|indent(8) }}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Autonomous', false)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Autonomous', true)|indent(8) -}}
{{ DeclareArchetypePropertyGetters(Component)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Server', 'Authority', true)|indent(8) -}}
@ -384,17 +374,31 @@ namespace {{ Component.attrib['Namespace'] }}
{{ DeclareRpcInvocations(Component, 'Autonomous', 'Authority', true)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Authority', 'Autonomous', false)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Authority', 'Autonomous', true)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Authority', 'Client', false)|indent(8) }}
{{ DeclareRpcInvocations(Component, 'Authority', 'Client', true)|indent(8) }}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Server', 'Authority', false)|indent(8) }}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Client', 'Authority', false)|indent(8) }}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Autonomous', 'Authority', false)|indent(8) }}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Autonomous', false)|indent(8) }}
{{ DeclareRpcInvocations(Component, 'Authority', 'Client', false)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Authority', 'Client', true)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Server', 'Authority', false)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Client', 'Authority', false)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Autonomous', 'Authority', false)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Autonomous', false)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcSignals(Component, 'Server', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcSignals(Component, 'Client', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcSignals(Component, 'Autonomous', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcSignals(Component, 'Authority', 'Autonomous')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Server', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Client', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Autonomous', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Autonomous')|indent(8) }}
{% for Service in Component.iter('ComponentRelation') %}
{% if (Service.attrib['HasController']|booleanTrue) and (Service.attrib['Constraint'] != 'Incompatible') %}
{{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}Controller* Get{{ Service.attrib['Name'] }}Controller();
{% endif %}
{% endfor %}
protected:
{{ AutoComponentMacros.DeclareRpcEvents(Component, 'Server', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEvents(Component, 'Client', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEvents(Component, 'Autonomous', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEvents(Component, 'Authority', 'Autonomous')|indent(8) }}
};
static const AZ::Uuid s_{{ LowerFirst(ComponentName) }}ConcreteUuid = "{{ (ComponentName) | createHashGuid }}";
@ -435,9 +439,10 @@ namespace {{ Component.attrib['Namespace'] }}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', false)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Autonomous', false)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', false)|indent(8) }}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', false)|indent(8) -}}
{{ DeclareArchetypePropertyGetters(Component)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) }}
{{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Client')|indent(8) -}}
//! MultiplayerComponent interface
//! @{
@ -457,13 +462,14 @@ namespace {{ Component.attrib['Namespace'] }}
void NetworkAttach(Multiplayer::NetBindComponent* netBindComponent, Multiplayer::ReplicationRecord& currentEntityRecord, Multiplayer::ReplicationRecord& predictableEntityRecord) override;
//! @}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Authority', true)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', true)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Autonomous', true)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', true)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', true)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Server', 'Authority', true)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Client', false)|indent(8) }}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Client', false)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcSignals(Component, 'Authority', 'Client')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEvents(Component, 'Authority', 'Client')|indent(8) }}
{% for Service in Component.iter('ComponentRelation') %}
{% if Service.attrib['Constraint'] != 'Incompatible' %}
const {{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}* Get{{ Service.attrib['Name'] }}() const;
@ -471,10 +477,6 @@ namespace {{ Component.attrib['Namespace'] }}
{% endif %}
{% endfor %}
private:
//! Authority To Authority serializers (hot backup in case of server failure)
bool SerializeAuthorityToAuthorityProperties({{ RecordName }}& replicationRecord, AzNetworking::ISerializer& serializer);
void NotifyChangesAuthorityToAuthorityProperties(const {{ RecordName }}& replicationRecord) const;
//! Authority to Client serializers
bool SerializeAuthorityToClientProperties({{ RecordName }}& replicationRecord, AzNetworking::ISerializer& serializer);
void NotifyChangesAuthorityToClientProperties(const {{ RecordName }}& replicationRecord) const;
@ -499,21 +501,18 @@ namespace {{ Component.attrib['Namespace'] }}
AZStd::unique_ptr<{{ ControllerName }}> m_controller;
//! Network Properties
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Authority')|indent(8) -}}
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Server')|indent(8) -}}
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Client')|indent(8) -}}
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Autonomous')|indent(8) -}}
{{ DeclareNetworkPropertyVars(Component, 'Autonomous', 'Authority')|indent(8) }}
//! Network Properties for reflection and editor support
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Authority')|indent(8) -}}
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Server')|indent(8) -}}
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Client')|indent(8) -}}
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Autonomous')|indent(8) -}}
{{ DeclareNetworkPropertyReflectVars(Component, 'Autonomous', 'Authority')|indent(8) }}
//! NetworkProperty Events
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Authority')|indent(8) -}}
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Server')|indent(8) -}}
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Client')|indent(8) -}}
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Autonomous')|indent(8) -}}

@ -315,16 +315,86 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par
{% endmacro %}
{#
#}
{% macro DefineRpcSignal(Component, ClassName, Property, InvokeFrom) %}
{% set paramNames = [] %}
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramDefines) }})
{
m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ ', '.join(paramNames) }});
}
{% endmacro %}
{#
#}
{% macro DefineRpcInvocations(Component, ClassName, InvokeFrom, HandleOn, ProctectedSection) %}
{% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
{% if Property.attrib['IsPublic']|booleanTrue == ProctectedSection %}
{{ DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) }}
{{ DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) -}}
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
{{ DefineRpcSignal(Component, ClassName, Property, InvokeFrom) -}}
{% endif %}
{% endif %}
{% endcall %}
{% endmacro %}
{#
#}
{% macro ReflectRpcInvocations(Component, ClassName, InvokeFrom, HandleOn) %}
{% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
{% set paramNames = [] %}
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
->Method("{{ UpperFirst(Property.attrib['Name']) }}", [](const {{ ClassName }}* self, {{ ', '.join(paramDefines) }}) {
self->m_controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }});
})
{% endif %}
{% endcall %}
{% endmacro %}
{#
#}
{% macro ReflectRpcEventDescs(Component, ClassName, InvokeFrom, HandleOn) %}
{% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
{% set paramNames = [] %}
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
// Create the BehaviorAZEventDescription needed to reflect the
// Get{{ UpperFirst(Property.attrib['Name']) }}Event method to the BehaviorContext without errors
AZ::BehaviorAzEventDescription {{ LowerFirst(Property.attrib['Name']) }}EventDesc;
{{ LowerFirst(Property.attrib['Name']) }}EventDesc.m_eventName = "{{ UpperFirst(Property.attrib['Name']) }} Notify Event";
{% for Param in Property.iter('Param') %}
{{ LowerFirst(Property.attrib['Name']) }}EventDesc.m_parameterNames.push_back("{{ LowerFirst(Param.attrib['Name']) }}");
{% endfor %}
{% endif %}
{% endcall %}
{% endmacro %}
{#
#}
{% macro ReflectRpcEvents(Component, ClassName, InvokeFrom, HandleOn) %}
{% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
{% set paramNames = [] %}
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
->Method("Get{{ UpperFirst(Property.attrib['Name']) }}Event", [](const {{ ClassName }}* self) -> AZ::Event<{{ ', '.join(paramTypes) }}>&
{
return self->m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event();
})
->Attribute(AZ::Script::Attributes::AzEventDescription, AZStd::move({{ LowerFirst(Property.attrib['Name']) }}EventDesc))
{% endif %}
{% endcall %}
{% endmacro %}
{#
#}
{% macro DeclareRpcHandleCases(Component, ComponentDerived, InvokeFrom, HandleOn, ValidationFunction) %}
{% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
@ -347,6 +417,9 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp
{
AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Authority, "Entity proxy does not have authority");
m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }});
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
m_controller->Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }});
{% endif %}
}
{% if Property.attrib['IsReliable']|booleanTrue %}
{# if the rpc is not reliable we can simply drop it, also note message reliability type is default reliable in EntityRpcMessage #}
@ -361,6 +434,9 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp
{
AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Autonomous, "Entity proxy does not have autonomy");
m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }});
{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
m_controller->Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }});
{% endif %}
}
{% else %}
Handle{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }});
@ -1017,7 +1093,6 @@ namespace {{ Component.attrib['Namespace'] }}
{
{{ DeclareRemoteProcedureEnumerations(Component)|indent(8) }}
{{ DeclareNetworkPropertyEnumerations(Component)|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Authority')|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Client')|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Server')|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Autonomous')|indent(8) }}
@ -1032,7 +1107,6 @@ namespace {{ Component.attrib['Namespace'] }}
{{ RecordName }}::{{ RecordName }}
(
[[maybe_unused]] Multiplayer::ReplicationRecord& replicationRecord,
[[maybe_unused]] uint32_t authorityToAuthorityStartOffset,
[[maybe_unused]] uint32_t authorityToClientStartOffset,
[[maybe_unused]] uint32_t authorityToServerStartOffset,
[[maybe_unused]] uint32_t authorityToAutonomousStartOffset,
@ -1040,13 +1114,6 @@ namespace {{ Component.attrib['Namespace'] }}
)
{% set comma = joiner(" ,") %}
{% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Authority') %}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
{% if networkPropertyCount.value > 0 %}
{{ comma()|default(" :", true) }} m_authorityToAuthority(replicationRecord.m_authorityToAuthority, authorityToAuthorityStartOffset, replicationRecord.ContainsAuthorityToAuthorityBits() ? static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Authority') }}::Count) : 0)
{% endif %}
{% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Client') %}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
@ -1058,7 +1125,7 @@ namespace {{ Component.attrib['Namespace'] }}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
{% if networkPropertyCount.value > 0 %}
{{ comma()|default(" :", true) }} authorityToServer }}(replicationRecord.m_authorityToServer, authorityToServerStartOffset, replicationRecord.ContainsAuthorityToServerBits() ? static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Server') }}::Count) : 0)
{{ comma()|default(" :", true) }} m_authorityToServer(replicationRecord.m_authorityToServer, authorityToServerStartOffset, replicationRecord.ContainsAuthorityToServerBits() ? static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Server') }}::Count) : 0)
{% endif %}
{% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Autonomous') %}
@ -1080,9 +1147,6 @@ namespace {{ Component.attrib['Namespace'] }}
AZStd::unique_ptr<{{ RecordName }}> {{ RecordName }}::AllocateRecord(Multiplayer::ReplicationRecord& replicationRecord)
{
uint32_t authorityToAuthorityStart = replicationRecord.m_authorityToAuthority.GetSize();
replicationRecord.m_authorityToAuthority.Resize(authorityToAuthorityStart + static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Authority') }}::Count));
uint32_t authorityToClientStart = replicationRecord.m_authorityToClient.GetSize();
replicationRecord.m_authorityToClient.Resize(authorityToClientStart + static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count));
@ -1096,7 +1160,6 @@ namespace {{ Component.attrib['Namespace'] }}
replicationRecord.m_autonomousToAuthority.Resize(autonomousToAuthorityStart + static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Autonomous', 'Authority') }}::Count));
return AZStd::unique_ptr<{{ RecordName }}>(new {{ RecordName }}(replicationRecord,
authorityToAuthorityStart,
authorityToClientStart,
authorityToServerStart,
authorityToAutonomousStart,
@ -1106,7 +1169,6 @@ namespace {{ Component.attrib['Namespace'] }}
bool {{ RecordName }}::CanAttachRecord(Multiplayer::ReplicationRecord& replicationRecord)
{
bool canAttach{ true };
canAttach &= replicationRecord.ContainsAuthorityToAuthorityBits() ? (replicationRecord.GetRemainingAuthorityToAuthorityBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Authority') }}::Count)) : true;
canAttach &= replicationRecord.ContainsAuthorityToClientBits() ? (replicationRecord.GetRemainingAuthorityToClientBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count)) : true;
canAttach &= replicationRecord.ContainsAuthorityToServerBits() ? (replicationRecord.GetRemainingAuthorityToServerBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Server') }}::Count)) : true;
canAttach &= replicationRecord.ContainsAuthorityToAutonomousBits() ? (replicationRecord.GetRemainingAuthorityToAutonomousBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Autonomous') }}::Count)) : true;
@ -1116,9 +1178,6 @@ namespace {{ Component.attrib['Namespace'] }}
{{ RecordName }} {{ RecordName }}::AttachRecord(Multiplayer::ReplicationRecord& replicationRecord)
{
uint32_t authorityToAuthorityStart = replicationRecord.m_authorityToAuthorityConsumedBits;
replicationRecord.ConsumeAuthorityToAuthorityBits(static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Authority') }}::Count));
uint32_t authorityToClientStart = replicationRecord.m_authorityToClientConsumedBits;
replicationRecord.ConsumeAuthorityToClientBits(static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count));
@ -1132,7 +1191,6 @@ namespace {{ Component.attrib['Namespace'] }}
replicationRecord.ConsumeAutonomousToAuthorityBits(static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Autonomous', 'Authority') }}::Count));
return {{ RecordName }}(replicationRecord,
authorityToAuthorityStart,
authorityToClientStart,
authorityToServerStart,
authorityToAutonomousStart,
@ -1142,9 +1200,9 @@ namespace {{ Component.attrib['Namespace'] }}
void {{ RecordName }}::SetPredictableBits()
{
{{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Authority', 'Client')|indent(8) -}}
{{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Authority', 'Server')|indent(8) -}}
{{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Authority', 'Autonomous')|indent(8) -}}
{{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Autonomous', 'Authority')|indent(8) }}
{{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Authority', 'Server')|indent(8) -}}
{{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Authority', 'Autonomous')|indent(8) -}}
{{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Autonomous', 'Authority')|indent(8) }}
}
{% if NetworkInputCount > 0 %}
@ -1206,23 +1264,22 @@ namespace {{ Component.attrib['Namespace'] }}
return static_cast<{{ ComponentName }}&>(GetOwner());
}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Authority', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Authority', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Autonomous', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Autonomous', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', true, ControllerBaseName)|indent(4) }}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Autonomous', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Autonomous', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', true, ControllerBaseName)|indent(4) }}
{{ DefineArchetypePropertyGets(Component, ClassType, ControllerBaseName, "GetParent().")|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Autonomous', 'Authority', false)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Autonomous', 'Authority', true)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Autonomous', false)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Autonomous', true)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Client', false)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Client', true)|indent(4) }}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Autonomous', 'Authority', false)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Autonomous', 'Authority', true)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Autonomous', false)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Autonomous', true)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Client', false)|indent(4) -}}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Client', true)|indent(4) }}
{% for Service in Component.iter('ComponentRelation') %}
{% if (Service.attrib['HasController']|booleanTrue) and (Service.attrib['Constraint'] != 'Incompatible') %}
{{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}Controller* {{ ControllerBaseName }}::Get{{ Service.attrib['Name'] }}Controller()
@ -1241,11 +1298,10 @@ namespace {{ Component.attrib['Namespace'] }}
{
serializeContext->Class<{{ ComponentBaseName }}, Multiplayer::MultiplayerComponent>()
->Version(1)
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Authority', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Server', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(16) }}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Server', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(16) }}
{{ DefineArchetypePropertyReflection(Component, ComponentBaseName)|indent(16) }};
}
ReflectToEditContext(context);
@ -1264,11 +1320,10 @@ namespace {{ Component.attrib['Namespace'] }}
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "{{ Component.attrib['Namespace'] }}")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Authority', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Server', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(20) }}
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Server', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(20) }}
{{ DefineArchetypePropertyEditReflection(Component, ComponentBaseName)|indent(20) }};
{% if ComponentDerived %}
@ -1286,18 +1341,34 @@ namespace {{ Component.attrib['Namespace'] }}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
{{ ReflectRpcEventDescs(Component, ComponentName, 'Server', 'Authority')|indent(4) -}}
{{ ReflectRpcEventDescs(Component, ComponentName, 'Autonomous', 'Authority')|indent(4) -}}
{{ ReflectRpcEventDescs(Component, ComponentName, 'Authority', 'Autonomous')|indent(4) -}}
{{ ReflectRpcEventDescs(Component, ComponentName, 'Authority', 'Client')|indent(4) }}
behaviorContext->Class<{{ ComponentName }}>("{{ ComponentName }}")
->Attribute(AZ::Script::Attributes::Module, "{{ LowerFirst(Component.attrib['Namespace']) }}")
->Attribute(AZ::Script::Attributes::Category, "{{ UpperFirst(Component.attrib['Namespace']) }}")
// Reflect Network Properties Get, Set, and OnChanged methods
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Authority', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Server', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Client', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Autonomous', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Autonomous', 'Authority', ComponentName) | indent(16) -}}
{{- DefineArchetypePropertyBehaviorReflection(Component, ComponentName) | indent(16) }}
;
// Reflect Network Properties Get, Set, and OnChanged methods
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Authority', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Server', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Client', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Autonomous', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Autonomous', 'Authority', ComponentName) | indent(16) -}}
// Reflect RPCs
{{ ReflectRpcInvocations(Component, ComponentName, 'Server', 'Authority')|indent(4) -}}
{{ ReflectRpcInvocations(Component, ComponentName, 'Autonomous', 'Authority')|indent(4) -}}
{{ ReflectRpcInvocations(Component, ComponentName, 'Authority', 'Autonomous')|indent(4) -}}
{{ ReflectRpcInvocations(Component, ComponentName, 'Authority', 'Client')|indent(4) -}}
{{ ReflectRpcEvents(Component, ComponentName, 'Server', 'Authority')|indent(4) -}}
{{ ReflectRpcEvents(Component, ComponentName, 'Autonomous', 'Authority')|indent(4) -}}
{{ ReflectRpcEvents(Component, ComponentName, 'Authority', 'Autonomous')|indent(4) -}}
{{ ReflectRpcEvents(Component, ComponentName, 'Authority', 'Client')|indent(4) -}}
{{- DefineArchetypePropertyBehaviorReflection(Component, ComponentName) | indent(16) }}
;
}
}
@ -1385,17 +1456,15 @@ namespace {{ Component.attrib['Namespace'] }}
{% endcall %}
}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Authority', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Autonomous', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Client', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Authority', true, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', true, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Autonomous', true, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', true, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Client', true, ComponentBaseName)|indent(4) }}
{{ DefineArchetypePropertyGets(Component, ClassType, ComponentBaseName)|indent(4) -}}
{{ DefineArchetypePropertyGets(Component, ClassType, ComponentBaseName)|indent(4) -}}
{{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', false)|indent(4) -}}
{{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', true)|indent(4) }}
@ -1448,10 +1517,6 @@ namespace {{ Component.attrib['Namespace'] }}
{{ RecordName }} record = {{ RecordName }}::AttachRecord(replicationRecord);
if (replicationRecord.ContainsAuthorityToAuthorityBits())
{
SerializeAuthorityToAuthorityProperties(record, serializer);
}
if (replicationRecord.ContainsAuthorityToClientBits())
{
SerializeAuthorityToClientProperties(record, serializer);
@ -1527,8 +1592,7 @@ namespace {{ Component.attrib['Namespace'] }}
void {{ ComponentBaseName }}::NetworkAttach(Multiplayer::NetBindComponent* netBindComponent, Multiplayer::ReplicationRecord& currentEntityRecord, Multiplayer::ReplicationRecord& predictableEntityRecord)
{
m_netBindComponent = netBindComponent;
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Authority', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Server', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Server', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Client', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(8) }}
@ -1541,8 +1605,6 @@ namespace {{ Component.attrib['Namespace'] }}
m_controller.get()->NetworkAttach(netBindComponent, predictableEntityRecord);
}
{{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Authority', ComponentBaseName, RecordName)|indent(4) }}
{{ DeclareNetworkPropertySetNotifyChanges(Component, 'Authority', 'Authority', ComponentBaseName, RecordName)|indent(4) }}
{{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Server', ComponentBaseName, RecordName)|indent(4) }}
{{ DeclareNetworkPropertySetNotifyChanges(Component, 'Authority', 'Server', ComponentBaseName, RecordName)|indent(4) }}
{{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Client', ComponentBaseName, RecordName)|indent(4) }}

@ -17,20 +17,20 @@
<Include File="Source/NetworkInput/NetworkInputMigrationVector.h"/>
<Include File="AzNetworking/DataStructures/ByteBuffer.h"/>
<NetworkProperty Type="Multiplayer::ClientInputId" Name="LastInputId" Init="Multiplayer::ClientInputId{ 0 }" ReplicateFrom="Authority" ReplicateTo="Authority" IsRewindable="false" IsPredictable="false" IsPublic="false" Container="Object" ExposeToEditor="false" GenerateEventBindings="false" />
<NetworkProperty Type="Multiplayer::ClientInputId" Name="LastInputId" Init="Multiplayer::ClientInputId{ 0 }" ReplicateFrom="Authority" ReplicateTo="Server" IsRewindable="false" IsPredictable="false" IsPublic="false" Container="Object" ExposeToEditor="false" GenerateEventBindings="false" />
<RemoteProcedure Name="SendClientInput" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="true" IsReliable="false" Description="Client to server move / input RPC">
<RemoteProcedure Name="SendClientInput" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="true" IsReliable="false" GenerateEventBindings="false" Description="Client to server move / input RPC">
<Param Type="Multiplayer::NetworkInputArray" Name="inputArray" />
<Param Type="AZ::HashValue32" Name="stateHash" />
<Param Type="AzNetworking::PacketEncodingBuffer" Name="clientState" Description="This is for debugging desyncs only; release games should not populate this parameter" />
</RemoteProcedure>
<RemoteProcedure Name="SendClientInputCorrection" InvokeFrom="Authority" HandleOn="Autonomous" IsPublic="true" IsReliable="false" Description="Autonomous proxy correction RPC">
<RemoteProcedure Name="SendClientInputCorrection" InvokeFrom="Authority" HandleOn="Autonomous" IsPublic="true" IsReliable="false" GenerateEventBindings="false" Description="Autonomous proxy correction RPC">
<Param Type="Multiplayer::ClientInputId" Name="inputId" />
<Param Type="AzNetworking::PacketEncodingBuffer" Name="correction" />
</RemoteProcedure>
<RemoteProcedure Name="SendMigrateClientInput" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="true" IsReliable="false" Description="Client to server migrate move / input RPC">
<RemoteProcedure Name="SendMigrateClientInput" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="true" IsReliable="false" GenerateEventBindings="false" Description="Client to server migrate move / input RPC">
<Param Type="Multiplayer::NetworkInputMigrationVector" Name="inputArray" />
</RemoteProcedure>
</Component>

@ -28,12 +28,6 @@
<Member Type="Multiplayer::LongNetworkString" Name="command" />
</Packet>
<Packet Name="SyncConnectionCvars" Desc="Packet for synchornizing connection quality of service simulation cvars">
<Member Type="int32_t" Name="lossPercent" Init="0" />
<Member Type="AZ::TimeMs" Name="latencyMs" Init="AZ::TimeMs{ 0 }" />
<Member Type="AZ::TimeMs" Name="varianceMs" Init="AZ::TimeMs{ 0 }" />
</Packet>
<Packet Name="EntityUpdates" Desc="A packet that contains multiple entity updates">
<Member Type="AZ::TimeMs" Name="hostTimeMs" Init="AZ::TimeMs{ 0 }" />
<Member Type="Multiplayer::HostFrameId" Name="hostFrameId" Init="Multiplayer::InvalidHostFrameId" />
@ -49,15 +43,4 @@
<Member Type="AzNetworking::IpAddress" Name="remoteServerAddress" Init="AzNetworking::IpAddress()" />
<Member Type="AZ::TimeMs" Name="lastInputGameTimeMs" Init="AZ::TimeMs{ 0 }" />
</Packet>
<Packet Name="NotifyClientMigration" Desc="Tells a server that a client is about to migrate">
<Member Type="uint64_t" Name="temporaryUserIdentifier" Init="0" />
</Packet>
<Packet Name="EntityMigration" Desc="A packet that migrates a set of entities to a new server">
<Member Type="Multiplayer::NetEntityId" Name="entityId" Init="Multiplayer::InvalidNetEntityId" />
<Member Type="Multiplayer::PrefabEntityId" Name="prefabEntityId" Init="" />
<Member Type="AzNetworking::PacketEncodingBuffer" Name="propertyUpdateData" Init="" SuppressFromInitializerList="true" />
</Packet>
</PacketGroup>

@ -24,6 +24,80 @@ namespace Multiplayer
serializeContext->Class<MultiplayerComponent, AZ::Component>()
->Version(1);
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<MultiplayerComponent>("MultiplayerComponent")
->Attribute(AZ::Script::Attributes::Module, "multiplayer")
->Attribute(AZ::Script::Attributes::Category, "Multiplayer")
->Method("IsAuthority", [](AZ::EntityId id) -> bool {
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(id);
if (!entity)
{
AZ_Warning( "MultiplayerComponent", false, "MultiplayerComponent IsAuthority failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return false;
}
MultiplayerComponent* multiplayerComponent = entity->FindComponent<MultiplayerComponent>();
if (!multiplayerComponent)
{
AZ_Warning( "MultiplayerComponent", false, "MultiplayerComponent IsAuthority failed. Entity '%s' (id: %s) is missing a MultiplayerComponent, make sure this entity contains a component which derives from MultiplayerComponent.", entity->GetName().c_str(), id.ToString().c_str())
return false;
}
return multiplayerComponent->IsAuthority();
})
->Method("IsAutonomous", [](AZ::EntityId id) -> bool {
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(id);
if (!entity)
{
AZ_Warning( "MultiplayerComponent", false, "MultiplayerComponent IsAutonomous failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return false;
}
MultiplayerComponent* multiplayerComponent = entity->FindComponent<MultiplayerComponent>();
if (!multiplayerComponent)
{
AZ_Warning("MultiplayerComponent", false, "MultiplayerComponent IsAutonomous failed. Entity '%s' (id: %s) is missing a MultiplayerComponent, make sure this entity contains a component which derives from MultiplayerComponent.", entity->GetName().c_str(), id.ToString().c_str())
return false;
}
return multiplayerComponent->IsAutonomous();
})
->Method("IsClient", [](AZ::EntityId id) -> bool {
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(id);
if (!entity)
{
AZ_Warning( "MultiplayerComponent", false, "MultiplayerComponent IsClient failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return false;
}
MultiplayerComponent* multiplayerComponent = entity->FindComponent<MultiplayerComponent>();
if (!multiplayerComponent)
{
AZ_Warning("MultiplayerComponent", false, "MultiplayerComponent IsClient failed. Entity '%s' (id: %s) is missing a MultiplayerComponent, make sure this entity contains a component which derives from MultiplayerComponent.", entity->GetName().c_str(), id.ToString().c_str())
return false;
}
return multiplayerComponent->IsClient();
})
->Method("IsServer", [](AZ::EntityId id) -> bool {
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(id);
if (!entity)
{
AZ_Warning( "MultiplayerComponent", false, "MultiplayerComponent IsServer failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return false;
}
MultiplayerComponent* multiplayerComponent = entity->FindComponent<MultiplayerComponent>();
if (!multiplayerComponent)
{
AZ_Warning("MultiplayerComponent", false, "MultiplayerComponent IsServer failed. Entity '%s' (id: %s) is missing a MultiplayerComponent, make sure this entity contains a component which derives from MultiplayerComponent.", entity->GetName().c_str(), id.ToString().c_str())
return false;
}
return multiplayerComponent->IsServer();
})
;
}
}
void MultiplayerComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)

@ -154,12 +154,18 @@ namespace Multiplayer
void NetBindComponent::SetOwningConnectionId(AzNetworking::ConnectionId connectionId)
{
m_owningConnectionId = connectionId;
for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector)
{
multiplayerComponent->SetOwningConnectionId(connectionId);
}
}
AzNetworking::ConnectionId NetBindComponent::GetOwningConnectionId() const
{
return m_owningConnectionId;
}
void NetBindComponent::SetAllowAutonomy(bool value)
{
// This flag allows a player host to autonomously control their player entity, even though the entity is in an authority role
@ -290,6 +296,11 @@ namespace Multiplayer
m_localNotificationRecord.Clear();
}
void NetBindComponent::NotifySyncRewindState()
{
m_syncRewindEvent.Signal();
}
void NetBindComponent::NotifyMigrationStart(ClientInputId migratedInputId)
{
m_entityMigrationStartEvent.Signal(migratedInputId);
@ -315,6 +326,11 @@ namespace Multiplayer
eventHandler.Connect(m_dirtiedEvent);
}
void NetBindComponent::AddEntitySyncRewindEventHandler(EntitySyncRewindEvent::Handler& eventHandler)
{
eventHandler.Connect(m_syncRewindEvent);
}
void NetBindComponent::AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler)
{
eventHandler.Connect(m_entityMigrationStartEvent);

@ -13,6 +13,8 @@
#include <Source/Debug/MultiplayerDebugSystemComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Interface/Interface.h>
#include <AzNetworking/Framework/INetworking.h>
#include <AzNetworking/Framework/INetworkInterface.h>
#include <Multiplayer/IMultiplayer.h>
namespace Multiplayer
@ -233,6 +235,43 @@ namespace Multiplayer
const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
if (m_displayNetworkingStats)
{
if (ImGui::Begin("Networking Stats", &m_displayNetworkingStats, ImGuiWindowFlags_None))
{
AzNetworking::INetworking* networking = AZ::Interface<AzNetworking::INetworking>::Get();
ImGui::Text("Total sockets monitored by TcpListenThread: %u", networking->GetTcpListenThreadSocketCount());
ImGui::Text("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(networking->GetTcpListenThreadUpdateTime()));
ImGui::Text("Total sockets monitored by UdpReaderThread: %u", networking->GetUdpReaderThreadSocketCount());
ImGui::Text("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(networking->GetUdpReaderThreadUpdateTime()));
for (auto& networkInterface : networking->GetNetworkInterfaces())
{
const char* protocol = networkInterface.second->GetType() == AzNetworking::ProtocolType::Tcp ? "Tcp" : "Udp";
const char* trustZone = networkInterface.second->GetTrustZone() == AzNetworking::TrustZone::ExternalClientToServer ? "ExternalClientToServer" : "InternalServerToServer";
const uint32_t port = aznumeric_cast<uint32_t>(networkInterface.second->GetPort());
ImGui::Text("%sNetworkInterface: %s - open to %s on port %u", protocol, networkInterface.second->GetName().GetCStr(), trustZone, port);
const AzNetworking::NetworkInterfaceMetrics& metrics = networkInterface.second->GetMetrics();
ImGui::Text(" - Total time spent updating in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_updateTimeMs));
ImGui::Text(" - Total number of connections: %llu", aznumeric_cast<AZ::u64>(metrics.m_connectionCount));
ImGui::Text(" - Total send time in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_sendTimeMs));
ImGui::Text(" - Total sent packets: %llu", aznumeric_cast<AZ::s64>(metrics.m_sendPackets));
ImGui::Text(" - Total sent bytes after compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytes));
ImGui::Text(" - Total sent bytes before compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytesUncompressed));
ImGui::Text(" - Total sent compressed packets without benefit: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendCompressedPacketsNoGain));
ImGui::Text(" - Total gain from packet compression: %lld", aznumeric_cast<AZ::s64>(metrics.m_sendBytesCompressedDelta));
ImGui::Text(" - Total packets resent: %llu", aznumeric_cast<AZ::u64>(metrics.m_resentPackets));
ImGui::Text(" - Total receive time in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_recvTimeMs));
ImGui::Text(" - Total received packets: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvPackets));
ImGui::Text(" - Total received bytes after compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytes));
ImGui::Text(" - Total received bytes before compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytesUncompressed));
ImGui::Text(" - Total packets discarded due to load: %llu", aznumeric_cast<AZ::u64>(metrics.m_discardedPackets));
}
}
}
if (m_displayMultiplayerStats)
{
if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_None))

@ -113,6 +113,10 @@ namespace Multiplayer
{
editorNetworkInterface->Disconnect(m_editorConnId, AzNetworking::DisconnectReason::TerminatedByClient);
}
if (auto console = AZ::Interface<AZ::IConsole>::Get(); console)
{
console->PerformCommand("disconnect");
}
break;
}
}

@ -163,9 +163,13 @@ namespace Multiplayer
// Handle deferred local rpc messages that were generated during the updates
m_networkEntityManager.DispatchLocalDeferredRpcMessages();
m_networkEntityManager.NotifyEntitiesChanged();
// INetworking ticks immediately before IMultiplayer, so all our pending RPC's and network property updates have now been processed
// Restore any entities that were rewound during input processing so that normal gameplay updates have the correct state
Multiplayer::GetNetworkTime()->ClearRewoundEntities();
// Let the network system know the frame is done and we can collect dirty bits
m_networkEntityManager.NotifyEntitiesChanged();
m_networkEntityManager.NotifyEntitiesDirtied();
MultiplayerStats& stats = GetStats();
@ -304,25 +308,32 @@ namespace Multiplayer
bool MultiplayerSystemComponent::HandleRequest
(
[[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::SyncConsole& packet
AzNetworking::IConnection* connection,
[[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
MultiplayerPackets::ReadyForEntityUpdates& packet
)
{
ExecuteConsoleCommandList(connection, packet.GetCommandSet());
return true;
IConnectionData* connectionData = reinterpret_cast<IConnectionData*>(connection->GetUserData());
if (connectionData)
{
connectionData->SetCanSendUpdates(packet.GetReadyForEntityUpdates());
return true;
}
return false;
}
bool MultiplayerSystemComponent::HandleRequest
(
[[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::ConsoleCommand& packet
[[maybe_unused]] MultiplayerPackets::SyncConsole& packet
)
{
const bool isAcceptor = (connection->GetConnectionRole() == ConnectionRole::Acceptor); // We're hosting if we accepted the connection
const AZ::ConsoleFunctorFlags requiredSet = isAcceptor ? AZ::ConsoleFunctorFlags::AllowClientSet : AZ::ConsoleFunctorFlags::Null;
AZ::Interface<AZ::IConsole>::Get()->PerformCommand(packet.GetCommand().c_str(), AZ::ConsoleSilentMode::NotSilent, AZ::ConsoleInvokedFrom::AzNetworking, requiredSet);
if (GetAgentType() != MultiplayerAgentType::Client)
{
return false;
}
ExecuteConsoleCommandList(connection, packet.GetCommandSet());
return true;
}
@ -330,10 +341,12 @@ namespace Multiplayer
(
[[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::SyncConnectionCvars& packet
[[maybe_unused]] MultiplayerPackets::ConsoleCommand& packet
)
{
connection->SetConnectionQuality(ConnectionQuality(packet.GetLossPercent(), packet.GetLatencyMs(), packet.GetVarianceMs()));
const bool isClient = (GetAgentType() == MultiplayerAgentType::Client);
const AZ::ConsoleFunctorFlags requiredSet = isClient ? AZ::ConsoleFunctorFlags::Null : AZ::ConsoleFunctorFlags::AllowClientSet;
AZ::Interface<AZ::IConsole>::Get()->PerformCommand(packet.GetCommand().c_str(), AZ::ConsoleSilentMode::NotSilent, AZ::ConsoleInvokedFrom::AzNetworking, requiredSet);
return true;
}
@ -397,39 +410,6 @@ namespace Multiplayer
return false;
}
bool MultiplayerSystemComponent::HandleRequest
(
[[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::NotifyClientMigration& packet
)
{
return false;
}
bool MultiplayerSystemComponent::HandleRequest
(
[[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::EntityMigration& packet
)
{
return false;
}
bool MultiplayerSystemComponent::HandleRequest( AzNetworking::IConnection* connection,
[[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet)
{
IConnectionData* connectionData = reinterpret_cast<IConnectionData*>(connection->GetUserData());
if (connectionData)
{
connectionData->SetCanSendUpdates(packet.GetReadyForEntityUpdates());
return true;
}
return false;
}
ConnectResult MultiplayerSystemComponent::ValidateConnect
(
[[maybe_unused]] const IpAddress& remoteAddress,
@ -458,44 +438,36 @@ namespace Multiplayer
m_connAcquiredEvent.Signal(datum);
}
if (m_onConnectFunctor)
if (GetAgentType() == MultiplayerAgentType::ClientServer
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
{
// Default OnConnect behaviour has been overridden
m_onConnectFunctor(connection, datum);
PrefabEntityId playerPrefabEntityId(AZ::Name(static_cast<AZ::CVarFixedString>(sv_defaultPlayerSpawnAsset).c_str()), 1);
INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity());
NetworkEntityHandle controlledEntity;
if (entityList.size() > 0)
{
controlledEntity = entityList[0];
controlledEntity.GetNetBindComponent()->SetOwningConnectionId(connection->GetConnectionId());
}
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
{
connection->SetUserData(new ServerToClientConnectionData(connection, *this, controlledEntity));
}
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<ServerToClientReplicationWindow>(controlledEntity, connection);
reinterpret_cast<ServerToClientConnectionData*>(connection->GetUserData())->GetReplicationManager().SetReplicationWindow(AZStd::move(window));
}
else
{
if (GetAgentType() == MultiplayerAgentType::ClientServer
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
{
PrefabEntityId playerPrefabEntityId(AZ::Name(static_cast<AZ::CVarFixedString>(sv_defaultPlayerSpawnAsset).c_str()), 1);
INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity());
NetworkEntityHandle controlledEntity;
if (entityList.size() > 0)
{
controlledEntity = entityList[0];
controlledEntity.GetNetBindComponent()->SetOwningConnectionId(connection->GetConnectionId());
}
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
{
connection->SetUserData(new ServerToClientConnectionData(connection, *this, controlledEntity));
}
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<ServerToClientReplicationWindow>(controlledEntity, connection);
reinterpret_cast<ServerToClientConnectionData*>(connection->GetUserData())->GetReplicationManager().SetReplicationWindow(AZStd::move(window));
connection->SetUserData(new ClientToServerConnectionData(connection, *this));
}
else
{
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
{
connection->SetUserData(new ClientToServerConnectionData(connection, *this));
}
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<NullReplicationWindow>();
reinterpret_cast<ClientToServerConnectionData*>(connection->GetUserData())->GetReplicationManager().SetEntityActivationTimeSliceMs(cl_defaultNetworkEntityActivationTimeSliceMs);
}
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<NullReplicationWindow>();
reinterpret_cast<ClientToServerConnectionData*>(connection->GetUserData())->GetReplicationManager().SetEntityActivationTimeSliceMs(cl_defaultNetworkEntityActivationTimeSliceMs);
}
}
@ -568,11 +540,6 @@ namespace Multiplayer
handler.Connect(m_shutdownEvent);
}
void MultiplayerSystemComponent::SetOnConnectFunctor(const OnConnectFunctor& functor)
{
m_onConnectFunctor = functor;
}
void MultiplayerSystemComponent::SendReadyForEntityUpdates(bool readyForEntityUpdates)
{
IConnectionSet& connectionSet = m_networkInterface->GetConnectionSet();

@ -66,15 +66,12 @@ namespace Multiplayer
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Connect& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Accept& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::SyncConsole& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ConsoleCommand& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::SyncConnectionCvars& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityUpdates& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityRpcs& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ClientMigration& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::NotifyClientMigration& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityMigration& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet);
//! IConnectionListener interface
//! @{
@ -92,7 +89,6 @@ namespace Multiplayer
void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override;
void AddSessionInitHandler(SessionInitEvent::Handler& handler) override;
void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override;
void SetOnConnectFunctor(const OnConnectFunctor& functor) override;
void SendReadyForEntityUpdates(bool readyForEntityUpdates) override;
AZ::TimeMs GetCurrentHostTimeMs() const override;
INetworkTime* GetNetworkTime() override;
@ -124,8 +120,6 @@ namespace Multiplayer
SessionShutdownEvent m_shutdownEvent;
ConnectionAcquiredEvent m_connAcquiredEvent;
OnConnectFunctor m_onConnectFunctor = nullptr;
AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 };
HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId;

@ -656,7 +656,7 @@ namespace Multiplayer
{
case Mode::LocalServerToRemoteClient:
{
// don't trust the client by default
// Don't trust the client by default
result = UpdateValidationResult::DropMessageAndDisconnect;
// Clients sending data must have a replicator and be sending in the correct mode, further, they must have a replicator and can never delete a replicator
if (updateMessage.GetNetworkRole() == NetEntityRole::Authority && entityReplicator && !updateMessage.GetIsDelete())
@ -671,7 +671,7 @@ namespace Multiplayer
}
else
{
// we can process this
// We can process this
result = UpdateValidationResult::HandleMessage;
}
} // If we've migrated the entity away from the server, but we get this late, just drop it
@ -699,7 +699,7 @@ namespace Multiplayer
case Mode::LocalServerToRemoteServer:
{
AZ_Assert(updateMessage.GetNetworkRole() == NetEntityRole::Server || updateMessage.GetIsDelete(), "Unexpected update type coming from peer server");
// trust messages from a peer server by default
// Trust messages from a peer server by default
result = UpdateValidationResult::HandleMessage;
// If we have a replicator, make sure we're in the correct state
if (entityReplicator)
@ -782,7 +782,7 @@ namespace Multiplayer
PrefabEntityId prefabEntityId;
if (updateMessage.GetHasValidPrefabId())
{
// If the update packet contained a sliceEntryId, use that directly
// If the update packet contained a PrefabEntityId, use that directly
prefabEntityId = updateMessage.GetPrefabEntityId();
}
else
@ -940,7 +940,7 @@ namespace Multiplayer
{
const ReplicationSet& newWindow = m_replicationWindow->GetReplicationSet();
// walk both for adds and removals
// Walk both for adds and removals
auto newWindowIter = newWindow.begin();
auto currWindowIter = m_entityReplicatorMap.begin();
while (newWindowIter != newWindow.end() && currWindowIter != m_entityReplicatorMap.end())
@ -959,9 +959,9 @@ namespace Multiplayer
}
++currWindowIter;
}
else // same entity
else // Same entity
{
// check if we changed modes
// Check if we changed modes
EntityReplicator* currReplicator = currWindowIter->second.get();
if (currReplicator->GetRemoteNetworkRole() != newWindowIter->second.m_netEntityRole)
{
@ -973,14 +973,14 @@ namespace Multiplayer
}
}
// do remaining adds
// Do remaining adds
while (newWindowIter != newWindow.end())
{
AddEntityReplicator(newWindowIter->first, newWindowIter->second.m_netEntityRole);
++newWindowIter;
}
// do remaining removes
// Do remaining removes
while (currWindowIter != m_entityReplicatorMap.end())
{
EntityReplicator* currReplicator = currWindowIter->second.get();
@ -1028,13 +1028,13 @@ namespace Multiplayer
const EntityReplicator* entityReplicator = GetEntityReplicator(entityHandle.GetNetEntityId());
hasAuthority = (netBindComponent->GetNetEntityRole() == NetEntityRole::Authority); // Make sure someone hasn't migrated this already
isInDomain = (m_remoteEntityDomain && m_remoteEntityDomain->IsInDomain(entityHandle)); // Make sure the remote side would want it
isInDomain = (m_remoteEntityDomain && m_remoteEntityDomain->IsInDomain(entityHandle)); // Make sure the remote side would want it
if (entityReplicator && entityReplicator->GetBoundLocalNetworkRole() == NetEntityRole::Authority)
{
isMarkedForRemoval = entityReplicator->IsMarkedForRemoval(); // Make sure we aren't telling the other side to remove the replicator
isMarkedForRemoval = entityReplicator->IsMarkedForRemoval(); // Make sure we aren't telling the other side to remove the replicator
const PropertyPublisher* propertyPublisher = entityReplicator->GetPropertyPublisher();
AZ_Assert(propertyPublisher, "Expected to have a property publisher");
isRemoteReplicatorEstablished = propertyPublisher->IsRemoteReplicatorEstablished(); // Make sure they are setup to receive the replicator
isRemoteReplicatorEstablished = propertyPublisher->IsRemoteReplicatorEstablished(); // Make sure they are setup to receive the replicator
}
return hasAuthority && isInDomain && !isMarkedForRemoval && isRemoteReplicatorEstablished;
@ -1094,9 +1094,9 @@ namespace Multiplayer
}
bool didSucceed = true;
MultiplayerPackets::EntityMigration message;
message.SetEntityId(replicator->GetEntityHandle().GetNetEntityId());
message.SetPrefabEntityId(netBindComponent->GetPrefabEntityId());
EntityMigrationMessage message;
message.m_entityId = replicator->GetEntityHandle().GetNetEntityId();
message.m_prefabEntityId = netBindComponent->GetPrefabEntityId();
if (localEnt->GetState() == AZ::Entity::State::Active)
{
@ -1110,17 +1110,18 @@ namespace Multiplayer
// Send an update packet if it needs one
propPublisher->GenerateRecord();
bool needsNetworkPropertyUpdate = propPublisher->PrepareSerialization();
AzNetworking::NetworkInputSerializer inputSerializer(message.ModifyPropertyUpdateData().GetBuffer(), message.ModifyPropertyUpdateData().GetCapacity());
AzNetworking::NetworkInputSerializer inputSerializer(message.m_propertyUpdateData.GetBuffer(), message.m_propertyUpdateData.GetCapacity());
if (needsNetworkPropertyUpdate)
{
// write out entity state into the buffer
// Write out entity state into the buffer
propPublisher->UpdateSerialization(inputSerializer);
}
didSucceed &= inputSerializer.IsValid();
message.ModifyPropertyUpdateData().Resize(inputSerializer.GetSize());
message.m_propertyUpdateData.Resize(inputSerializer.GetSize());
}
AZ_Assert(didSucceed, "Failed to migrate entity from server");
m_connection.SendReliablePacket(message);
// TODO: Move this to an event
//m_connection.SendReliablePacket(message);
AZLOG(NET_RepDeletes, "Migration packet sent %u to remote manager id %d", netEntityId, aznumeric_cast<int32_t>(GetRemoteHostId()));
// Immediately add a new replicator so that we catch RPC invocations, the remote side will make us a new one, and then remove us if needs be
@ -1128,21 +1129,21 @@ namespace Multiplayer
}
}
bool EntityReplicationManager::HandleMessage([[maybe_unused]] AzNetworking::IConnection* invokingConnection, MultiplayerPackets::EntityMigration& message)
bool EntityReplicationManager::HandleEntityMigration([[maybe_unused]] AzNetworking::IConnection* invokingConnection, EntityMigrationMessage& message)
{
EntityReplicator* replicator = GetEntityReplicator(message.GetEntityId());
EntityReplicator* replicator = GetEntityReplicator(message.m_entityId);
{
if (message.GetPropertyUpdateData().GetSize() > 0)
if (message.m_propertyUpdateData.GetSize() > 0)
{
AzNetworking::TrackChangedSerializer<AzNetworking::NetworkOutputSerializer> outputSerializer(message.ModifyPropertyUpdateData().GetBuffer(), message.ModifyPropertyUpdateData().GetSize());
AzNetworking::TrackChangedSerializer<AzNetworking::NetworkOutputSerializer> outputSerializer(message.m_propertyUpdateData.GetBuffer(), message.m_propertyUpdateData.GetSize());
if (!HandlePropertyChangeMessage
(
replicator,
AzNetworking::InvalidPacketId,
message.GetEntityId(),
message.m_entityId,
NetEntityRole::Server,
outputSerializer,
message.GetPrefabEntityId()
message.m_prefabEntityId
))
{
AZ_Assert(false, "Unable to process network properties during server entity migration");
@ -1150,10 +1151,10 @@ namespace Multiplayer
}
}
}
// the HandlePropertyChangeMessage will have made a replicator if we didn't have one already
// The HandlePropertyChangeMessage will have made a replicator if we didn't have one already
if (!replicator)
{
replicator = GetEntityReplicator(message.GetEntityId());
replicator = GetEntityReplicator(message.m_entityId);
}
AZ_Assert(replicator, "Do not have replicator after handling migration message");
@ -1170,7 +1171,7 @@ namespace Multiplayer
netBindComponent->ActivateControllers(EntityIsMigrating::True);
}
// change the role on the replicator
// Change the role on the replicator
AddEntityReplicator(entityHandle, NetEntityRole::Server);
AZLOG(NET_RepDeletes, "Handle Migration %u new authority from remote manager id %d", entityHandle.GetNetEntityId(), aznumeric_cast<int32_t>(GetRemoteHostId()));

@ -17,6 +17,8 @@
#include <Multiplayer/EntityDomains/IEntityDomain.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
#include <AzNetworking/DataStructures/TimeoutQueue.h>
#include <AzNetworking/PacketLayer/IPacketHeader.h>
@ -26,7 +28,6 @@
#include <AzCore/std/limits.h>
#include <AzCore/EBus/Event.h>
#include <AzCore/EBus/ScheduledEvent.h>
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
namespace AzNetworking
{
@ -82,7 +83,7 @@ namespace Multiplayer
void AddAutonomousEntityReplicatorCreatedHandle(AZ::Event<NetEntityId>::Handler& handler);
bool HandleMessage(AzNetworking::IConnection* invokingConnection, MultiplayerPackets::EntityMigration& message);
bool HandleEntityMigration(AzNetworking::IConnection* invokingConnection, EntityMigrationMessage& message);
bool HandleEntityDeleteMessage(EntityReplicator* entityReplicator, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage);
bool HandleEntityUpdateMessage(AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage);
bool HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message);

@ -16,14 +16,12 @@ namespace Multiplayer
{
ReplicationRecordStats::ReplicationRecordStats
(
uint32_t authorityToAuthorityCount,
uint32_t authorityToClientCount,
uint32_t authorityToServerCount,
uint32_t authorityToAutonomousCount,
uint32_t autonomousToAuthorityCount
)
: m_authorityToAuthorityCount(authorityToAuthorityCount)
, m_authorityToClientCount(authorityToClientCount)
: m_authorityToClientCount(authorityToClientCount)
, m_authorityToServerCount(authorityToServerCount)
, m_authorityToAutonomousCount(authorityToAutonomousCount)
, m_autonomousToAuthorityCount(autonomousToAuthorityCount)
@ -33,8 +31,7 @@ namespace Multiplayer
bool ReplicationRecordStats::operator ==(const ReplicationRecordStats& rhs) const
{
return (m_authorityToAuthorityCount == rhs.m_authorityToAuthorityCount)
&& (m_authorityToClientCount == rhs.m_authorityToClientCount)
return (m_authorityToClientCount == rhs.m_authorityToClientCount)
&& (m_authorityToServerCount == rhs.m_authorityToServerCount)
&& (m_authorityToAutonomousCount == rhs.m_authorityToAutonomousCount)
&& (m_autonomousToAuthorityCount == rhs.m_autonomousToAuthorityCount);
@ -44,7 +41,6 @@ namespace Multiplayer
{
return ReplicationRecordStats
{
(m_authorityToAuthorityCount - rhs.m_authorityToAuthorityCount),
(m_authorityToClientCount - rhs.m_authorityToClientCount),
(m_authorityToServerCount - rhs.m_authorityToServerCount),
(m_authorityToAutonomousCount - rhs.m_authorityToAutonomousCount),
@ -71,7 +67,6 @@ namespace Multiplayer
bool ReplicationRecord::AreAllBitsConsumed() const
{
bool ret = true;
ret &= m_authorityToAuthorityConsumedBits == m_authorityToAuthority.GetSize();
ret &= m_authorityToClientConsumedBits == m_authorityToClient.GetSize();
ret &= m_authorityToServerConsumedBits == m_authorityToServer.GetSize();
ret &= m_authorityToAutonomousConsumedBits == m_authorityToAutonomous.GetSize();
@ -81,7 +76,6 @@ namespace Multiplayer
void ReplicationRecord::ResetConsumedBits()
{
m_authorityToAuthorityConsumedBits = 0;
m_authorityToClientConsumedBits = 0;
m_authorityToServerConsumedBits = 0;
m_authorityToAutonomousConsumedBits = 0;
@ -92,11 +86,7 @@ namespace Multiplayer
{
ResetConsumedBits();
uint32_t recordSize = m_authorityToAuthority.GetSize();
m_authorityToAuthority.Clear();
m_authorityToAuthority.Resize(recordSize);
recordSize = m_authorityToClient.GetSize();
uint32_t recordSize = m_authorityToClient.GetSize();
m_authorityToClient.Clear();
m_authorityToClient.Resize(recordSize);
@ -115,7 +105,6 @@ namespace Multiplayer
void ReplicationRecord::Append(const ReplicationRecord &rhs)
{
m_authorityToAuthority |= rhs.m_authorityToAuthority;
m_authorityToClient |= rhs.m_authorityToClient;
m_authorityToServer |= rhs.m_authorityToServer;
m_authorityToAutonomous |= rhs.m_authorityToAutonomous;
@ -124,7 +113,6 @@ namespace Multiplayer
void ReplicationRecord::Subtract(const ReplicationRecord &rhs)
{
m_authorityToAuthority.Subtract(rhs.m_authorityToAuthority);
m_authorityToClient.Subtract(rhs.m_authorityToClient);
m_authorityToServer.Subtract(rhs.m_authorityToServer);
m_authorityToAutonomous.Subtract(rhs.m_authorityToAutonomous);
@ -134,10 +122,6 @@ namespace Multiplayer
bool ReplicationRecord::HasChanges() const
{
bool hasChanges(false);
if (ContainsAuthorityToAuthorityBits())
{
hasChanges = hasChanges ? hasChanges : m_authorityToAuthority.AnySet();
}
if (ContainsAuthorityToClientBits())
{
hasChanges = hasChanges ? hasChanges : m_authorityToClient.AnySet();
@ -159,10 +143,6 @@ namespace Multiplayer
bool ReplicationRecord::Serialize(AzNetworking::ISerializer& serializer)
{
if (ContainsAuthorityToAuthorityBits())
{
serializer.Serialize(m_authorityToAuthority, "AuthorityToAuthorityRecord");
}
if (ContainsAuthorityToClientBits())
{
serializer.Serialize(m_authorityToClient, "AuthorityToClientRecord");
@ -182,14 +162,6 @@ namespace Multiplayer
return serializer.IsValid();
}
void ReplicationRecord::ConsumeAuthorityToAuthorityBits(uint32_t consumedBits)
{
if (ContainsAuthorityToAuthorityBits())
{
m_authorityToAuthorityConsumedBits += consumedBits;
}
}
void ReplicationRecord::ConsumeAuthorityToClientBits(uint32_t consumedBits)
{
if (ContainsAuthorityToClientBits())
@ -222,12 +194,6 @@ namespace Multiplayer
}
}
bool ReplicationRecord::ContainsAuthorityToAuthorityBits() const
{
return (m_netEntityRole == NetEntityRole::Authority)
|| (m_netEntityRole == NetEntityRole::InvalidRole);
}
bool ReplicationRecord::ContainsAuthorityToClientBits() const
{
return (m_netEntityRole != NetEntityRole::Authority)
@ -252,11 +218,6 @@ namespace Multiplayer
|| (m_netEntityRole == NetEntityRole::InvalidRole);
}
uint32_t ReplicationRecord::GetRemainingAuthorityToAuthorityBits() const
{
return m_authorityToAuthorityConsumedBits < m_authorityToAuthority.GetValidBitCount() ? m_authorityToAuthority.GetValidBitCount() - m_authorityToAuthorityConsumedBits : 0;
}
uint32_t ReplicationRecord::GetRemainingAuthorityToClientBits() const
{
return m_authorityToClientConsumedBits < m_authorityToClient.GetValidBitCount() ? m_authorityToClient.GetValidBitCount() - m_authorityToClientConsumedBits : 0;
@ -281,7 +242,6 @@ namespace Multiplayer
{
return ReplicationRecordStats
{
m_authorityToAuthorityConsumedBits,
m_authorityToClientConsumedBits,
m_authorityToServerConsumedBits,
m_authorityToAutonomousConsumedBits,

@ -13,10 +13,15 @@
#include <Source/NetworkTime/NetworkTime.h>
#include <Multiplayer/IMultiplayer.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/Components/NetworkTransformComponent.h>
#include <AzCore/Math/ShapeIntersection.h>
#include <AzFramework/Visibility/IVisibilitySystem.h>
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
namespace Multiplayer
{
AZ_CVAR(float, sv_RewindVolumeExtrudeDistance, 50.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "The amount to increase rewind volume checks to account for fast moving entities");
NetworkTime::NetworkTime()
{
AZ::Interface<INetworkTime>::Register(this);
@ -73,35 +78,59 @@ namespace Multiplayer
void NetworkTime::SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume)
{
// TODO: extrude rewind volume for initial gather
AZStd::vector<AzFramework::VisibilityEntry*> gatheredEntries;
AZ::Interface<AzFramework::IVisibilitySystem>::Get()->GetDefaultVisibilityScene()->Enumerate(rewindVolume, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData)
// Since the vis system doesn't support rewound queries, first query with an expanded volume to catch any fast moving entities
const AZ::Aabb expandedVolume = rewindVolume.GetExpanded(AZ::Vector3(sv_RewindVolumeExtrudeDistance));
AzFramework::IEntityBoundsUnion* entityBoundsUnion = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get();
AZStd::vector<NetBindComponent*> gatheredEntities;
AZ::Interface<AzFramework::IVisibilitySystem>::Get()->GetDefaultVisibilityScene()->Enumerate(expandedVolume,
[entityBoundsUnion, rewindVolume, &gatheredEntities](const AzFramework::IVisibilityScene::NodeData& nodeData)
{
gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size());
gatheredEntities.reserve(gatheredEntities.size() + nodeData.m_entries.size());
for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries)
{
if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity)
{
// TODO: offset aabb for exact rewound position and check against the non-extruded rewind volume
gatheredEntries.push_back(visEntry);
AZ::Entity* entity = static_cast<AZ::Entity*>(visEntry->m_userData);
const AZ::Aabb currentBounds = entityBoundsUnion->GetEntityLocalBoundsUnion(entity->GetId());
const AZ::Vector3 currentCenter = currentBounds.GetCenter();
NetworkTransformComponent* networkTransform = entity->template FindComponent<NetworkTransformComponent>();
if (networkTransform != nullptr)
{
const AZ::Vector3 rewindCenter = networkTransform->GetTranslation(); // Get the rewound position
const AZ::Vector3 rewindOffset = rewindCenter - currentCenter; // Compute offset between rewound and current positions
const AZ::Aabb rewoundAabb = currentBounds.GetTranslated(rewindOffset); // Apply offset to the entity aabb
if (AZ::ShapeIntersection::Overlaps(rewoundAabb, rewindVolume)) // Validate the rewound aabb intersects our rewind volume
{
// Due to component constraints, netBindComponent must exist if networkTransform exists
NetBindComponent* netBindComponent = entity->template FindComponent<NetBindComponent>();
gatheredEntities.push_back(netBindComponent);
}
}
}
}
});
for (AzFramework::VisibilityEntry* visEntry : gatheredEntries)
NetworkEntityTracker* networkEntityTracker = GetNetworkEntityTracker();
for (NetBindComponent* netBindComponent : gatheredEntities)
{
AZ::Entity* entity = static_cast<AZ::Entity*>(visEntry->m_userData);
[[maybe_unused]] NetBindComponent* entryNetBindComponent = entity->template FindComponent<NetBindComponent>();
if (entryNetBindComponent != nullptr)
{
// TODO: invoke the sync to rewind event on the netBindComponent and add the entity to the rewound entity set
}
netBindComponent->NotifySyncRewindState();
m_rewoundEntities.push_back(NetworkEntityHandle(netBindComponent, networkEntityTracker));
}
}
void NetworkTime::ClearRewoundEntities()
{
AZ_Assert(!IsTimeRewound(), "Cannot clear rewound entity state while still within scoped rewind");
// TODO: iterate all rewound entities, signal them to sync rewind state, and clear the rewound entity set
for (NetworkEntityHandle entityHandle : m_rewoundEntities)
{
NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent();
netBindComponent->NotifySyncRewindState();
}
m_rewoundEntities.clear();
}
}

@ -13,6 +13,7 @@
#pragma once
#include <Multiplayer/NetworkTime/INetworkTime.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Console/IConsole.h>
@ -42,6 +43,8 @@ namespace Multiplayer
private:
AZStd::vector<NetworkEntityHandle> m_rewoundEntities;
HostFrameId m_hostFrameId = HostFrameId{ 0 };
HostFrameId m_unalteredFrameId = HostFrameId{ 0 };
AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 };

@ -0,0 +1,99 @@
/*
* 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 "ImageProcessing_precompiled.h"
#include "AtlasBuilderComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
namespace TextureAtlasBuilder
{
// AZ Components should only initialize their members to null and empty in constructor
// Allocation of data should occur in Init(), once we can guarantee reflection and registration of types
AtlasBuilderComponent::AtlasBuilderComponent()
{
}
// Handle deallocation of your memory allocated in Init()
AtlasBuilderComponent::~AtlasBuilderComponent()
{
}
// Init is where you'll actually allocate memory or create objects
// This ensures that any dependency components will have been been created and serialized
void AtlasBuilderComponent::Init()
{
}
// Activate is where you'd perform registration with other objects and systems.
// All builder classes owned by this component should be registered here
// Any EBuses for the builder classes should also be connected at this point
void AtlasBuilderComponent::Activate()
{
AssetBuilderSDK::AssetBuilderDesc builderDescriptor;
builderDescriptor.m_name = "Atlas Worker Builder";
builderDescriptor.m_version = 1;
builderDescriptor.m_patterns.emplace_back(AssetBuilderSDK::AssetBuilderPattern("*.texatlas", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
builderDescriptor.m_busId = azrtti_typeid<AtlasBuilderWorker>();
builderDescriptor.m_createJobFunction = AZStd::bind(&AtlasBuilderWorker::CreateJobs, &m_atlasBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
builderDescriptor.m_processJobFunction = AZStd::bind(&AtlasBuilderWorker::ProcessJob, &m_atlasBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
m_atlasBuilder.BusConnect(builderDescriptor.m_busId);
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
}
// Disconnects from any EBuses we connected to in Activate()
// Unregisters from objects and systems we register with in Activate()
void AtlasBuilderComponent::Deactivate()
{
m_atlasBuilder.BusDisconnect();
// We don't need to unregister the builder - the AP will handle this for us, because it is managing the lifecycle of this component
}
// Reflect the input and output formats for the serializer
void AtlasBuilderComponent::Reflect(AZ::ReflectContext* context)
{
// components also get Reflect called automatically
// this is your opportunity to perform static reflection or type registration of any types you want the serializer to know about
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<AtlasBuilderComponent, AZ::Component>()
->Version(0)
->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector<AZ::Crc32>({ AssetBuilderSDK::ComponentTags::AssetBuilder }))
;
}
AtlasBuilderInput::Reflect(context);
}
void AtlasBuilderComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("Atlas Builder Plugin Service", 0x35974d0d));
}
void AtlasBuilderComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("Atlas Builder Plugin Service", 0x35974d0d));
}
void AtlasBuilderComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
AZ_UNUSED(required);
}
void AtlasBuilderComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
AZ_UNUSED(dependent);
}
}

@ -0,0 +1,44 @@
/*
* 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.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include "AtlasBuilderWorker.h"
namespace TextureAtlasBuilder
{
class AtlasBuilderComponent : public AZ::Component
{
public:
AZ_COMPONENT(AtlasBuilderComponent, "{F49987FB-3375-4417-AB83-97B44C78B335}");
AtlasBuilderComponent();
~AtlasBuilderComponent() override;
void Init() override;
void Activate() override;
void Deactivate() override;
//! Reflect formats for input and output
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
private:
AtlasBuilderWorker m_atlasBuilder;
};
} // namespace TextureAtlasBuilder

File diff suppressed because it is too large Load Diff

@ -0,0 +1,230 @@
/*
* 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.
*
*/
#pragma once
#include <AzCore/RTTI/RTTI.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <AssetBuilderSDK/AssetBuilderBusses.h>
#include <qimage.h>
#include <TextureAtlas/TextureAtlasBus.h>
namespace TextureAtlasBuilder
{
//! Struct that is used to communicate input commands
struct AtlasBuilderInput
{
AZ_CLASS_ALLOCATOR(AtlasBuilderInput, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(AtlasBuilderInput, "{F54477F9-1BDE-4274-8CC0-8320A3EF4A42}");
bool m_forceSquare;
bool m_forcePowerOf2;
// Includes a white default texture for the UI to use under certain circumstances
bool m_includeWhiteTexture;
int m_maxDimension;
// At least this much padding will surround each texture except on the edges of the atlas
int m_padding;
// Color used in wasted space
AZ::Color m_unusedColor;
// A preset to use for the texture atlas image processing
AZStd::string m_presetName;
AZStd::vector<AZStd::string> m_filePaths;
AtlasBuilderInput():
m_forceSquare(false),
m_forcePowerOf2(false),
m_includeWhiteTexture(true),
m_maxDimension(4096),
m_padding(1),
// Default color should be a non-transparent color that isn't used often in uis
m_unusedColor(.235f, .702f, .443f, 1)
{
}
static void Reflect(AZ::ReflectContext* context);
//! Attempts to read the input from a .texatlas file. "valid" is for reporting exceptions and telling the asset
//! proccesor to fail the job. Supports parsing through a human readable custom parser.
static AtlasBuilderInput ReadFromFile(const AZStd::string& path, const AZStd::string& directory, bool& valid);
//! Resolves any wild cards in paths
static void AddFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert);
//! Removes anything that matches the wildcard
static void RemoveFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove);
//! Compare considering wildcards
static bool DoesPathnameMatchWildCard(const AZStd::string& rule, const AZStd::string& path);
//! As FollowsRule but allows extra items after the last '/'
static bool DoesWildCardDirectoryIncludePathname(const AZStd::string& rule, const AZStd::string& path);
//! Helper function for DoesPathnameMatchWildCard
static bool TokenMatchesWildcard(const AZStd::string& rule, const AZStd::string& token);
//! Resolves any folder paths into image file paths
static void AddFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert, bool& valid);
//! Resolves remove commands for folders
static void RemoveFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove);
};
//! Struct that is used to represent an object with a width and height in pixels
struct ImageDimension
{
int m_width;
int m_height;
ImageDimension(int width, int height)
{
m_width = width;
m_height = height;
}
};
//! Typedef for an ImageDimension paired with an integer
using IndexImageDimension = AZStd::pair<int, ImageDimension>;
//! Typedef for a list of ImageDimensions paired with integers
using ImageDimensionData = AZStd::vector<IndexImageDimension>;
//! Typedef to simplify references to TextureAtlas::AtlasCoordinates
using AtlasCoordinates = TextureAtlasNamespace::AtlasCoordinates;
//! Number of bytes in a pixel
const int bytesPerPixel = 4;
//! The size of the padded sorting units (important for compression)
const int cellSize = 4;
//! Indexes of the products
enum class Product
{
TexatlasidxProduct = 0,
DdsProduct = 1
};
//! An asset builder for texture atlases
class AtlasBuilderWorker : public AssetBuilderSDK::AssetBuilderCommandBus::Handler
{
public:
AZ_RTTI(AtlasBuilderWorker, "{79036188-E017-4575-9EC0-8D39CB560EA6}");
AtlasBuilderWorker() = default;
~AtlasBuilderWorker() = default;
//! Asset Builder Callback Functions
//! Called by asset processor to gather information on a job for a ".texatlas" file
void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request,
AssetBuilderSDK::CreateJobsResponse& response);
//! Called by asset proccessor when it wants us to execute a job
void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request,
AssetBuilderSDK::ProcessJobResponse& response);
//! Returns the job related information used by the builder
static AssetBuilderSDK::JobDescriptor GetJobDescriptor(const AZStd::string& sourceFile, const AtlasBuilderInput& input);
//////////////////////////////////////////////////////////////////////////
//! AssetBuilderSDK::AssetBuilderCommandBus interface
void ShutDown() override; // if you get this you must fail all existing jobs and return.
//////////////////////////////////////////////////////////////////////////
private:
bool m_isShuttingDown = false;
//! This is the main function that takes a set of inputs and attempts to pack them into an atlas of a given
//! size. Returns true if succesful, does not update out on failure.
static bool TryPack(const ImageDimensionData& images,
int targetWidth,
int targetHeight,
int padding,
size_t& amountFit,
AZStd::vector<AtlasCoordinates>& out);
//! Removes any overlap between slotList and the given item
static void TrimOverlap(AZStd::vector<AtlasCoordinates>& slotList, AtlasCoordinates item);
//! Uses the proper tightening method based on the input and returns the maximum number of items that were able to be fit
bool TryTightening(AtlasBuilderInput input,
const ImageDimensionData& images,
int smallestWidth,
int smallestHeight,
int targetArea,
int padding,
int& resultWidth,
int& resultHeight,
size_t& amountFit,
AZStd::vector<AtlasCoordinates>& out);
//! Finds the tightest square fit achievable by expanding a square area until a valid fit is found
bool TryTighteningSquare(const ImageDimensionData& images,
int lowerBound,
int maxDimension,
int targetArea,
bool powerOfTwo,
int padding,
int& resultWidth,
int& resultHeight,
size_t& amountFit,
AZStd::vector<AtlasCoordinates>& out);
//! Finds the tightest fit achievable by starting with the optimal thin solution and attempting to resize to be
//! a better shape
bool TryTighteningOptimal(const ImageDimensionData& images,
int smallestWidth,
int smallestHeight,
int maxDimension,
int targetArea,
bool powerOfTwo,
int padding,
int& resultWidth,
int& resultHeight,
size_t& amountFit,
AZStd::vector<AtlasCoordinates>& out);
//! Sorting logic for adding a slot to a sorted list in order to maintain increasing order
static void InsertInOrder(AZStd::vector<AtlasCoordinates>& slotList, AtlasCoordinates item);
//! Misc Logic For Estimating Target Shape
//! Returns the width of the widest element
static int GetWidest(const ImageDimensionData& imageList);
//! Returns the height of the tallest area
static int GetTallest(const ImageDimensionData& imageList);
};
//! Used for sorting ImageDimensions
static bool operator<(ImageDimension a, ImageDimension b);
//! Used to expose the ImageDimension in a pair to AZStd::Sort
static bool operator<(IndexImageDimension a, IndexImageDimension b);
//! Returns true if two coordinate sets overlap
static bool Collides(AtlasCoordinates a, AtlasCoordinates b);
//! Returns true if item collides with any object in list
static bool Collides(AtlasCoordinates item, AZStd::vector<AtlasCoordinates> list);
//! Returns the portion of the second item that overlaps with the first
static AtlasCoordinates GetOverlap(AtlasCoordinates a, AtlasCoordinates b);
//! Performs an operation that copies a pixel to the output
static void SetPixels(AZ::u8* dest, const AZ::u8* source, int destBytes);
//! Checks if we can insert an image into a slot
static bool CanInsert(AtlasCoordinates slot, ImageDimension image, int padding, int farRight, int farBot);
//! Adds the necessary padding to an Atlas Coordinate
static void AddPadding(AtlasCoordinates& slot, int padding, int farRight, int farBot);
}

@ -27,8 +27,7 @@ ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform
ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665)
ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4)
ly_associate_package(PACKAGE_NAME SPIRVCross-2020.04.20-rev1-multiplatform TARGETS SPIRVCross PACKAGE_HASH 7c8c0eaa0166c26745c62d2238525af7e27ac058a5db3defdbaec1878e8798dd)
ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-2020.08.07-rev1-multiplatform TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 04a6850ce03d4c16e19ed206f7093d885276dfb74047e6aa99f0a834c8b7cc73)
ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxcAz-5.0.0_az-rev1-multiplatform TARGETS DirectXShaderCompilerDxcAz PACKAGE_HASH 94f24989a7a371d840b513aa5ffaff02747b3d19b119bc1f899427e29978f753)
ly_associate_package(PACKAGE_NAME DirectXShaderCompiler-1.6.2104-o3de-rev1-mac TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 4e97484f8fcf73fc39f22fc85ae86933a8f2e3ba0748fcec128bce05795035a6)
ly_associate_package(PACKAGE_NAME azslc-1.7.21-rev1-multiplatform TARGETS azslc PACKAGE_HASH 772b7a2d9cc68aa1da4f0ee7db57ee1b4e7a8f20b81961fc5849af779582f4df)
ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee)
ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5)

@ -27,8 +27,7 @@ ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform
ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665)
ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4)
ly_associate_package(PACKAGE_NAME SPIRVCross-2020.04.20-rev1-multiplatform TARGETS SPIRVCross PACKAGE_HASH 7c8c0eaa0166c26745c62d2238525af7e27ac058a5db3defdbaec1878e8798dd)
ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-2020.08.07-rev1-multiplatform TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 04a6850ce03d4c16e19ed206f7093d885276dfb74047e6aa99f0a834c8b7cc73)
ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxcAz-5.0.0_az-rev1-multiplatform TARGETS DirectXShaderCompilerDxcAz PACKAGE_HASH 94f24989a7a371d840b513aa5ffaff02747b3d19b119bc1f899427e29978f753)
ly_associate_package(PACKAGE_NAME DirectXShaderCompiler-1.6.2104-o3de-rev1-windows TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 2c60297758d73f7833911e5ae3006fe0b10ced6e0b1b54764b33ae2b86e0d41d)
ly_associate_package(PACKAGE_NAME azslc-1.7.21-rev1-multiplatform TARGETS azslc PACKAGE_HASH 772b7a2d9cc68aa1da4f0ee7db57ee1b4e7a8f20b81961fc5849af779582f4df)
ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee)
ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5)

@ -9,6 +9,7 @@
Version="$(var.CPACK_PACKAGE_VERSION)"
Manufacturer="$(var.CPACK_PACKAGE_VENDOR)"
UpgradeCode="$(var.CPACK_BOOTSTRAP_UPGRADE_GUID)"
IconSourceFile="$(var.CPACK_WIX_PRODUCT_ICON)"
DisableModify="yes">
<Variable Name="InstallFolder"
@ -20,12 +21,14 @@
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense">
<bal:WixStandardBootstrapperApplication
LicenseUrl="$(var.CPACK_LICENSE_URL)"
LogoFile="$(var.CPACK_WIX_PRODUCT_LOGO)"
ShowVersion="yes" />
</BootstrapperApplicationRef>
<?else?>
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication
LicenseFile="$(var.CPACK_WIX_LICENSE_RTF)"
LogoFile="$(var.CPACK_WIX_PRODUCT_LOGO)"
ShowVersion="yes" />
</BootstrapperApplicationRef>
<?endif?>

@ -0,0 +1,68 @@
<?xml version='1.0' encoding='windows-1252'?>
<?include "cpack_variables.wxi"?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="$(var.CPACK_PACKAGE_NAME)">
<Directory Id="VersionedApplicationProgramsFolder" Name="$(var.CPACK_PACKAGE_VERSION)"/>
</Directory>
</Directory>
<Directory Id="DesktopFolder" SourceName="Desktop"/>
</DirectoryRef>
<!-- the WorkingDirectory attribute for shortcuts uses directory refs -->
<DirectoryRef Id="INSTALL_ROOT">
<Directory Id="root.bin" Name="bin">
<Directory Id="root.bin.Windows" Name="Windows">
<Directory Id="root.bin.Windows.profile" Name="profile" />
</Directory>
</Directory>
</DirectoryRef>
<DirectoryRef Id="DesktopFolder">
<Component Id="DesktopShortcuts" Guid="{2600B54A-65FB-4507-A7CD-3CE4817C7173}">
<Shortcut Id="DesktopShortcut_Launcher"
Target="[root.bin.Windows.profile]o3de.exe"
WorkingDirectory="root.bin.Windows.profile"
Name="$(var.CPACK_PACKAGE_NAME) $(var.CPACK_PACKAGE_VERSION)" />
<RemoveFolder Id="DesktopFolder" On="uninstall"/>
<RegistryValue
Root="HKCU"
Key="Software\$(var.CPACK_PACKAGE_VENDOR)\$(var.CPACK_PACKAGE_NAME)"
Name="installed"
Type="integer"
Value="1"
KeyPath="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="VersionedApplicationProgramsFolder">
<Component Id="StartMenuShortcuts" Guid="{E6447F0F-A46E-4A72-83D8-600707B590E8}">
<Shortcut Id="StartMenuShortcut_Launcher"
Target="[root.bin.Windows.profile]o3de.exe"
WorkingDirectory="root.bin.Windows.profile"
Name="$(var.CPACK_PACKAGE_NAME)" />
<RemoveFolder Id="RemoveVersionedApplicationProgramsFolder" Directory='VersionedApplicationProgramsFolder' On="uninstall"/>
<RemoveFolder Id="RemoveApplicationProgramsFolder" Directory="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue
Root="HKCU"
Key="Software\$(var.CPACK_PACKAGE_VENDOR)\$(var.CPACK_PACKAGE_NAME)"
Name="installed"
Type="integer"
Value="1"
KeyPath="yes"/>
</Component>
</DirectoryRef>
</Fragment>
</Wix>

@ -38,7 +38,10 @@
<WixVariable Id="WixUIDialogBmp" Value="$(var.CPACK_WIX_UI_DIALOG)"/>
<?endif?>
<FeatureRef Id="ProductFeature"/>
<FeatureRef Id="ProductFeature">
<ComponentRef Id="DesktopShortcuts"/>
<ComponentRef Id="StartMenuShortcuts"/>
</FeatureRef>
<UIRef Id="$(var.CPACK_WIX_UI_REF)" />

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c042fce57915fc749abc7b37de765fd697c3c4d7de045a3d44805aa0ce29901a
size 107016

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ac0348c906c91de864cba91c0231b4794d8a00fafa630d13f2232351b90aa59b
size 11074

@ -30,6 +30,7 @@ set(_addtional_defines
-dCPACK_LOCAL_INSTALLER_DIR=${_cpack_wix_out_dir}
-dCPACK_PACKAGE_FILE_NAME=${CPACK_PACKAGE_FILE_NAME}
-dCPACK_PACKAGE_INSTALL_DIRECTORY=${_fixed_package_install_dir}
-dCPACK_WIX_PRODUCT_LOGO=${CPACK_WIX_PRODUCT_LOGO}
)
if(CPACK_LICENSE_URL)
@ -43,7 +44,7 @@ set(_candle_command
"-I${_cpack_wix_out_dir}" # to include cpack_variables.wxi
${_addtional_defines}
${_ext_flags}
"${CPACK_SOURCE_DIR}/Platform/Windows/PackagingBootstrapper.wxs"
"${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Bootstrapper.wxs"
-o "${_bootstrap_out_dir}/"
)

@ -48,29 +48,28 @@ set(_guid_seed_base "${PROJECT_NAME}_${LY_VERSION_STRING}")
generate_wix_guid(_wix_default_product_guid "${_guid_seed_base}_ProductID" )
generate_wix_guid(_wix_default_upgrade_guid "${_guid_seed_base}_UpgradeCode")
set(LY_WIX_PRODUCT_GUID "${_wix_default_product_guid}" CACHE STRING "GUID for the Product ID field. Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
set(LY_WIX_UPGRADE_GUID "${_wix_default_upgrade_guid}" CACHE STRING "GUID for the Upgrade Code field. Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
set(LY_WIX_PRODUCT_GUID "" CACHE STRING "GUID for the Product ID field. Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
set(LY_WIX_UPGRADE_GUID "" CACHE STRING "GUID for the Upgrade Code field. Format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
set(_uses_default_product_guid FALSE)
if(NOT LY_WIX_PRODUCT_GUID OR LY_WIX_PRODUCT_GUID STREQUAL ${_wix_default_product_guid})
set(_uses_default_product_guid TRUE)
set(LY_WIX_PRODUCT_GUID ${_wix_default_product_guid})
# clear previously cached default values to correct future runs. this will
# unfortunately only work if the seed properties still haven't changed
if(LY_WIX_PRODUCT_GUID STREQUAL ${_wix_default_product_guid})
unset(LY_WIX_PRODUCT_GUID CACHE)
endif()
set(_uses_default_upgrade_guid FALSE)
if(NOT LY_WIX_UPGRADE_GUID OR LY_WIX_UPGRADE_GUID STREQUAL ${_wix_default_upgrade_guid})
set(_uses_default_upgrade_guid TRUE)
set(LY_WIX_UPGRADE_GUID ${_wix_default_upgrade_guid})
if(LY_WIX_UPGRADE_GUID STREQUAL ${_wix_default_upgrade_guid})
unset(LY_WIX_UPGRADE_GUID CACHE)
endif()
if(_uses_default_product_guid OR _uses_default_upgrade_guid)
if(NOT (LY_WIX_PRODUCT_GUID AND LY_WIX_UPGRADE_GUID))
message(STATUS "One or both WiX GUIDs were auto generated. It is recommended you supply your own GUIDs through LY_WIX_PRODUCT_GUID and LY_WIX_UPGRADE_GUID.")
if(_uses_default_product_guid)
if(NOT LY_WIX_PRODUCT_GUID)
set(LY_WIX_PRODUCT_GUID ${_wix_default_product_guid})
message(STATUS "-> Default LY_WIX_PRODUCT_GUID = ${LY_WIX_PRODUCT_GUID}")
endif()
if(_uses_default_upgrade_guid)
if(NOT LY_WIX_UPGRADE_GUID)
set(LY_WIX_UPGRADE_GUID ${_wix_default_upgrade_guid})
message(STATUS "-> Default LY_WIX_UPGRADE_GUID = ${LY_WIX_UPGRADE_GUID}")
endif()
endif()
@ -78,7 +77,14 @@ endif()
set(CPACK_WIX_PRODUCT_GUID ${LY_WIX_PRODUCT_GUID})
set(CPACK_WIX_UPGRADE_GUID ${LY_WIX_UPGRADE_GUID})
set(CPACK_WIX_TEMPLATE "${CPACK_SOURCE_DIR}/Platform/Windows/PackagingTemplate.wxs.in")
set(CPACK_WIX_PRODUCT_LOGO ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/product_logo.png)
set(CPACK_WIX_PRODUCT_ICON ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/product_icon.ico)
set(CPACK_WIX_TEMPLATE "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Template.wxs.in")
set(CPACK_WIX_EXTRA_SOURCES
"${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Shortcuts.wxs"
)
set(_embed_artifacts "yes")

@ -24,7 +24,8 @@ set(FILES
PALDetection_windows.cmake
Install_windows.cmake
Packaging_windows.cmake
PackagingBootstrapper.wxs
PackagingPostBuild.cmake
PackagingTemplate.wxs.in
Packaging/Bootstrapper.wxs
Packaging/Shortcuts.wxs
Packaging/Template.wxs.in
)

@ -0,0 +1,68 @@
#!/bin/bash
# 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.
# This script must be run as root
if [[ $EUID -ne 0 ]]
then
echo "This script must be run as root (sudo)"
exit 1
fi
# Install python3 if necessary
python3 --version >/dev/null 2>&1
if [ $? -ne 0 ]
then
echo Installing Python3
apt-get install python3
if [ $? -ne 0 ]
then
echo Error installing python3
exit 1
fi
else
PYTHON_VERSION=$(python3 --version)
echo Python3 already installed \($PYTHON_VERSION\)
fi
# Install python3 pip if necessary
pip3 --version >/dev/null 2>&1
if [ $? -ne 0 ]
then
echo Installing Python3 PIP
apt-get install -y python3-pip
if [ $? -ne 0 ]
then
echo Error installing python3
exit 1
fi
else
PYTHON_VERSION=$(pip3 --version | awk '{print $2}')
echo Python3 Pip already installed \($PYTHON_VERSION\)
fi
# Read from the package list and process each package
PIP_REQUIREMENTS_FILE=requirements.txt
pip3 install -r $PIP_REQUIREMENTS_FILE
if [ $? -ne 0 ]
then
echo Error installing python3
exit 1
fi
echo Python3 setup complete
exit 0

@ -0,0 +1,43 @@
boto3==1.16.18 \
--hash=sha256:51c419d890ae216b9b031be31f3182739dc3deb5b64351f286bffca2818ddb35 \
--hash=sha256:d70d21ea137d786e84124639a62be42f92f4b09472ebfb761156057c92dc5366
psutil==5.8.0 \
--hash=sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64 \
--hash=sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131 \
--hash=sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c \
--hash=sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6 \
--hash=sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023 \
--hash=sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df \
--hash=sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394 \
--hash=sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4 \
--hash=sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b \
--hash=sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2 \
--hash=sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d \
--hash=sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65 \
--hash=sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d \
--hash=sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef \
--hash=sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7 \
--hash=sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60 \
--hash=sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6 \
--hash=sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8 \
--hash=sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b \
--hash=sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d \
--hash=sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac \
--hash=sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935 \
--hash=sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d \
--hash=sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28 \
--hash=sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876 \
--hash=sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0 \
--hash=sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3 \
--hash=sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563
requests==2.25.1 \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e
traceback2==1.4.0 \
--hash=sha256:05acc67a09980c2ecfedd3423f7ae0104839eccb55fc645773e1caa0951c3030 \
--hash=sha256:8253cebec4b19094d67cc5ed5af99bf1dba1285292226e98a31929f87a5d6b23
urllib3==1.26.4 \
--hash=sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df \
--hash=sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937
tempfile2==0.1.1 \
--hash=sha256:77fdd256c16804053d3d588168b79595099ea5e874c3fb171893b0ababd10340
Loading…
Cancel
Save