merging latest dev

Signed-off-by: kberg-amzn <karlberg@amazon.com>
This commit is contained in:
kberg-amzn
2021-10-01 09:53:16 -07:00
782 changed files with 16514 additions and 12024 deletions
@@ -89,6 +89,9 @@ namespace AZ
// Tracks the asset type used to create the instance.
AssetType m_assetType;
// Boolean to indicate if the instance has been orphaned from the instance database
bool m_isOrphaned = false;
};
/// @cond EXCLUDE_DOCS
@@ -203,6 +203,16 @@ namespace AZ
//! Calls FindOrCreate using a random InstanceId
Data::Instance<Type> Create(const Asset<AssetData>& asset, const AZStd::any* param = nullptr);
/**
* Removes the instance data from the database. Does not release it.
* References to existing instances will remain valid, but new calls to Create/FindOrCreate will create a new instance
* This function is temporary, to provide functionality needed for Model hot-reloading, but will be removed
* once the Model class does not need it anymore.
*
* @param id The id of the instance to remove
*/
void TEMPOrphan(const InstanceId& id);
private:
InstanceDatabase(const AssetType& assetType);
~InstanceDatabase();
@@ -356,6 +366,20 @@ namespace AZ
return FindOrCreate(Data::InstanceId::CreateRandom(), asset, param);
}
template<typename Type>
void InstanceDatabase<Type>::TEMPOrphan(const InstanceId& id)
{
AZStd::scoped_lock<AZStd::recursive_mutex> lock(m_databaseMutex);
// Check if the instance is still in the database, in case it was orphaned twice
auto instanceItr = m_database.find(id);
if (instanceItr != m_database.end())
{
// Mark the instance as orphaned, and remove it from the database
instanceItr->second->m_isOrphaned = true;
m_database.erase(instanceItr);
}
}
template<typename Type>
void InstanceDatabase<Type>::ReleaseInstance(InstanceData* instance, const InstanceId& instanceId)
{
@@ -374,6 +398,12 @@ namespace AZ
m_database.erase(instance->GetId());
m_instanceHandler.m_deleteFunction(static_cast<Type*>(instance));
}
else if (instance->m_isOrphaned && instance->m_useCount.compare_exchange_strong(expectedRefCount, -1))
{
// If the instance was orphaned, it has already been removed from the database,
// but still needs to be deleted when the refcount drops to 0
m_instanceHandler.m_deleteFunction(static_cast<Type*>(instance));
}
}
template<typename Type>
@@ -181,7 +181,76 @@ namespace UnitTest
EXPECT_EQ(instance, instance3);
}
void ParallelInstanceCreateHelper(size_t threadCountMax, size_t assetIdCount, size_t durationSeconds)
TEST_F(InstanceDatabaseTest, InstanceOrphan)
{
auto& assetManager = AssetManager::Instance();
auto& instanceDatabase = InstanceDatabase<TestInstanceA>::Instance();
Asset<TestAssetType> someAsset = assetManager.CreateAsset<TestAssetType>(s_assetId0, AZ::Data::AssetLoadBehavior::Default);
Instance<TestInstanceA> orphanedInstance = instanceDatabase.FindOrCreate(s_instanceId0, someAsset);
EXPECT_NE(orphanedInstance, nullptr);
instanceDatabase.TEMPOrphan(s_instanceId0);
// After orphan, the instance should not be found in the database, but it should still be valid
EXPECT_EQ(instanceDatabase.Find(s_instanceId0), nullptr);
EXPECT_NE(orphanedInstance, nullptr);
instanceDatabase.TEMPOrphan(s_instanceId0);
// Orphaning twice should be a no-op
EXPECT_EQ(instanceDatabase.Find(s_instanceId0), nullptr);
EXPECT_NE(orphanedInstance, nullptr);
Instance<TestInstanceA> instance2 = instanceDatabase.FindOrCreate(s_instanceId0, someAsset);
// Creating another instance with the same id should return a different instance than the one that was orphaned
EXPECT_NE(orphanedInstance, instance2);
}
enum class ParallelInstanceTestCases
{
Create,
CreateAndDeferRemoval,
CreateAndOrphan,
CreateDeferRemovalAndOrphan
};
enum class ParralleInstanceCurrentAction
{
Create,
DeferredRemoval,
Orphan
};
ParralleInstanceCurrentAction ParallelInstanceGetCurrentAction(ParallelInstanceTestCases testCase)
{
switch (testCase)
{
case ParallelInstanceTestCases::CreateAndDeferRemoval:
switch (rand() % 2)
{
case 0: return ParralleInstanceCurrentAction::Create;
case 1: return ParralleInstanceCurrentAction::DeferredRemoval;
}
case ParallelInstanceTestCases::CreateAndOrphan:
switch (rand() % 2)
{
case 0: return ParralleInstanceCurrentAction::Create;
case 1: return ParralleInstanceCurrentAction::Orphan;
}
case ParallelInstanceTestCases::CreateDeferRemovalAndOrphan:
switch (rand() % 3)
{
case 0: return ParralleInstanceCurrentAction::Create;
case 1: return ParralleInstanceCurrentAction::DeferredRemoval;
case 2: return ParralleInstanceCurrentAction::Orphan;
}
case ParallelInstanceTestCases::Create:
default:
return ParralleInstanceCurrentAction::Create;
}
}
void ParallelInstanceCreateHelper(size_t threadCountMax, size_t assetIdCount, float durationSeconds, ParallelInstanceTestCases testCase)
{
printf("Testing threads=%zu assetIds=%zu ... ", threadCountMax, assetIdCount);
@@ -192,6 +261,7 @@ namespace UnitTest
auto& instanceManager = InstanceDatabase<TestInstanceA>::Instance();
AZStd::vector<Uuid> guids;
AZStd::vector<Data::Instance<Data::InstanceData>> instances;
AZStd::vector<Asset<TestAssetType>> assets;
for (size_t i = 0; i < assetIdCount; ++i)
@@ -199,6 +269,7 @@ namespace UnitTest
Uuid guid = Uuid::CreateRandom();
guids.emplace_back(guid);
instances.emplace_back(nullptr);
// Pre-create asset so we don't attempt to load it from the catalog.
assets.emplace_back(assetManager.CreateAsset<TestAssetType>(guid, AZ::Data::AssetLoadBehavior::Default));
@@ -206,6 +277,7 @@ namespace UnitTest
AZStd::vector<AZStd::thread> threads;
AZStd::mutex mutex;
AZStd::mutex referenceTableMutex;
AZStd::atomic<int> threadCount((int)threadCountMax);
AZStd::condition_variable cv;
AZStd::atomic_bool keepDispatching(true);
@@ -225,11 +297,15 @@ namespace UnitTest
for (size_t i = 0; i < threadCountMax; ++i)
{
threads.emplace_back(
[&instanceManager, &threadCount, &cv, &guids, &assets, &durationSeconds]()
[&instanceManager, &threadCount, &cv, &guids, &instances, &assets, &durationSeconds, &testCase, &referenceTableMutex]()
{
AZ::Debug::Timer timer;
timer.Stamp();
bool deferRemoval = testCase == ParallelInstanceTestCases::CreateAndDeferRemoval ||
testCase == ParallelInstanceTestCases::CreateDeferRemovalAndOrphan
? true : false;
while (timer.GetDeltaTimeInSeconds() < durationSeconds)
{
const size_t index = rand() % guids.size();
@@ -237,11 +313,36 @@ namespace UnitTest
const InstanceId instanceId{ uuid };
const AssetId assetId{ uuid };
Instance<TestInstanceA> instance =
instanceManager.FindOrCreate(instanceId, Asset<TestAssetType>(assetId, azrtti_typeid<TestAssetType>()));
EXPECT_NE(instance, nullptr);
EXPECT_EQ(instance->GetId(), instanceId);
EXPECT_EQ(instance->m_asset, assets[index]);
ParralleInstanceCurrentAction currentAction = ParallelInstanceGetCurrentAction(testCase);
if (currentAction == ParralleInstanceCurrentAction::Orphan)
{
// Orphan the instance, but don't decrease its refcount
instanceManager.TEMPOrphan(instanceId);
}
else if (currentAction == ParralleInstanceCurrentAction::DeferredRemoval)
{
// Drop the refcount to zero so the instance will be released
referenceTableMutex.lock();
instances[index] = nullptr;
referenceTableMutex.unlock();
}
else
{
// Otherwise, add a new instance
Instance<TestInstanceA> instance = instanceManager.FindOrCreate(instanceId, assets[index]);
EXPECT_NE(instance, nullptr);
EXPECT_EQ(instance->GetId(), instanceId);
EXPECT_EQ(instance->m_asset, assets[index]);
if (deferRemoval)
{
// Keep a reference to the instance alive so it can be removed later
referenceTableMutex.lock();
instances[index] = instance;
referenceTableMutex.unlock();
}
}
}
threadCount--;
@@ -254,10 +355,12 @@ namespace UnitTest
// Used to detect a deadlock. If we wait for more than 10 seconds, it's likely a deadlock has occurred
while (threadCount > 0 && !timedOut)
{
size_t durationSecondsRoundedUp = static_cast<size_t>(std::ceil(durationSeconds));
AZStd::unique_lock<AZStd::mutex> lock(mutex);
timedOut =
(AZStd::cv_status::timeout ==
cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSeconds * 2)));
cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSecondsRoundedUp * 2)));
}
EXPECT_TRUE(threadCount == 0) << "One or more threads appear to be deadlocked at " << timer.GetDeltaTimeInSeconds() << " seconds";
@@ -273,11 +376,11 @@ namespace UnitTest
printf("Took %f seconds\n", timer.GetDeltaTimeInSeconds());
}
TEST_F(InstanceDatabaseTest, ParallelInstanceCreate)
void ParallelCreateTest(ParallelInstanceTestCases testCase)
{
// This is the original test scenario from when InstanceDatabase was first implemented
// threads, AssetIds, seconds
ParallelInstanceCreateHelper(8, 100, 5);
ParallelInstanceCreateHelper(8, 100, 5, testCase);
// This value is checked in as 1 so this test doesn't take too much time, but can be increased locally to soak the test.
const size_t attempts = 1;
@@ -289,11 +392,11 @@ namespace UnitTest
// The idea behind this series of tests is that there are two threads sharing one Instance, and both threads try to
// create or release that instance at the same time.
// At the time, this set of scenarios has something like a 10% failure rate.
const size_t duration = 2;
const float duration = 2.0f;
// threads, AssetIds, seconds
ParallelInstanceCreateHelper(2, 1, duration);
ParallelInstanceCreateHelper(4, 1, duration);
ParallelInstanceCreateHelper(8, 1, duration);
ParallelInstanceCreateHelper(2, 1, duration, testCase);
ParallelInstanceCreateHelper(4, 1, duration, testCase);
ParallelInstanceCreateHelper(8, 1, duration, testCase);
}
for (size_t i = 0; i < attempts; ++i)
@@ -301,19 +404,39 @@ namespace UnitTest
printf("Attempt %zu of %zu... \n", i, attempts);
// Here we try a bunch of different threadCount:assetCount ratios to be thorough
const size_t duration = 2;
const float duration = 2.0f;
// threads, AssetIds, seconds
ParallelInstanceCreateHelper(2, 1, duration);
ParallelInstanceCreateHelper(4, 1, duration);
ParallelInstanceCreateHelper(4, 2, duration);
ParallelInstanceCreateHelper(4, 4, duration);
ParallelInstanceCreateHelper(8, 1, duration);
ParallelInstanceCreateHelper(8, 2, duration);
ParallelInstanceCreateHelper(8, 3, duration);
ParallelInstanceCreateHelper(8, 4, duration);
ParallelInstanceCreateHelper(2, 1, duration, testCase);
ParallelInstanceCreateHelper(4, 1, duration, testCase);
ParallelInstanceCreateHelper(4, 2, duration, testCase);
ParallelInstanceCreateHelper(4, 4, duration, testCase);
ParallelInstanceCreateHelper(8, 1, duration, testCase);
ParallelInstanceCreateHelper(8, 2, duration, testCase);
ParallelInstanceCreateHelper(8, 3, duration, testCase);
ParallelInstanceCreateHelper(8, 4, duration, testCase);
}
}
TEST_F(InstanceDatabaseTest, ParallelInstanceCreate)
{
ParallelCreateTest(ParallelInstanceTestCases::Create);
}
TEST_F(InstanceDatabaseTest, ParallelInstanceCreateAndDeferRemoval)
{
ParallelCreateTest(ParallelInstanceTestCases::CreateAndDeferRemoval);
}
TEST_F(InstanceDatabaseTest, ParallelInstanceCreateAndOrphan)
{
ParallelCreateTest(ParallelInstanceTestCases::CreateAndOrphan);
}
TEST_F(InstanceDatabaseTest, ParallelInstanceCreateDeferRemovalAndOrphan)
{
ParallelCreateTest(ParallelInstanceTestCases::CreateDeferRemovalAndOrphan);
}
TEST_F(InstanceDatabaseTest, InstanceCreateNoDatabase)
{
bool m_deleted = false;
@@ -340,6 +340,14 @@ namespace AZ
// (Load jobs will attempt to reuse blocked threads before spinning off new job threads)
ProcessLoadJob();
}
// Pump the AssetBus function queue once more after the load has completed in case additional
// functions have been queued between the last call to DispatchEvents and the completion
// of the current load job
if (m_shouldDispatchEvents)
{
AssetManager::Instance().DispatchEvents();
}
}
void Finish()
@@ -13,6 +13,7 @@
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Serialization/Json/RegistrationContext.h>
#include <AzCore/Slice/SliceAssetHandler.h>
#include <AzCore/Slice/SliceComponent.h>
@@ -8,6 +8,7 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/IO/SystemFile.h>
namespace AZ {
@@ -22,6 +22,7 @@
#include <AzCore/Time/TimeSystemComponent.h>
#include <AzCore/Console/LoggerSystemComponent.h>
#include <AzCore/EBus/EventSchedulerSystemComponent.h>
#include <AzCore/Task/TaskGraphSystemComponent.h>
namespace AZ
{
@@ -41,6 +42,7 @@ namespace AZ
TimeSystemComponent::CreateDescriptor(),
LoggerSystemComponent::CreateDescriptor(),
EventSchedulerSystemComponent::CreateDescriptor(),
TaskGraphSystemComponent::CreateDescriptor(),
#if !defined(AZCORE_EXCLUDE_LUA)
ScriptSystemComponent::CreateDescriptor(),
@@ -55,6 +57,7 @@ namespace AZ
azrtti_typeid<TimeSystemComponent>(),
azrtti_typeid<LoggerSystemComponent>(),
azrtti_typeid<EventSchedulerSystemComponent>(),
azrtti_typeid<TaskGraphSystemComponent>(),
};
}
}
@@ -22,6 +22,7 @@
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/SystemAllocator.h> // Used as the allocator for most components.
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/containers/unordered_set.h>
namespace AZ
{
@@ -74,8 +74,6 @@
#include <AzCore/Module/Environment.h>
#include <AzCore/std/string/conversions.h>
AZ_CVAR(float, g_simulation_tick_rate, 0, nullptr, AZ::ConsoleFunctorFlags::Null, "The rate at which the game simulation tick loop runs, or 0 for as fast as possible");
static void PrintEntityName(const AZ::ConsoleCommandContainer& arguments)
{
if (arguments.empty())
@@ -1393,23 +1391,6 @@ namespace AZ
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
// If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame,
// sleeping if there's still time remaining.
if (g_simulation_tick_rate > 0.f)
{
now = AZStd::chrono::system_clock::now();
// Work in microsecond durations here as that's the native measurement time for time_point
constexpr float microsecondsPerSecond = 1000.f * 1000.f;
const AZStd::chrono::microseconds timeBudgetPerTick(static_cast<int>(microsecondsPerSecond / g_simulation_tick_rate));
AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now;
if (timeUntilNextTick.count() > 0)
{
AZStd::this_thread::sleep_for(timeUntilNextTick);
}
}
}
}
@@ -649,6 +649,16 @@ namespace AZ
m_stateEvent.Signal(oldState, m_state);
}
void Entity::SetSpawnTicketId(u32 spawnTicketId)
{
m_spawnTicketId = spawnTicketId;
}
u32 Entity::GetSpawnTicketId() const
{
return m_spawnTicketId;
}
void Entity::OnNameChanged() const
{
EBUS_EVENT_ID(GetId(), EntityBus, OnEntityNameChanged, m_name);
@@ -133,6 +133,14 @@ namespace AZ
//! @return The state of the entity. For example, the entity has been initialized, the entity is active, and so on.
State GetState() const { return m_state; }
//! Gets the ticket id used to spawn the entity.
//! @return the ticket id used to spawn the entity. If entity is not spawned, the id will be 0.
u32 GetSpawnTicketId() const;
//! Sets the ticket id used to spawn the entity. The ticket id in the entity will remain 0 unless it's set using this function.
//! @param spawnTicketId the ticket id used to spawn the entity.
void SetSpawnTicketId(u32 spawnTicketId);
//! Connects an entity state event handler to the entity.
//! All state changes will be signaled through this event.
//! @param handler reference to the EntityStateEvent handler to attach to the entities state event.
@@ -410,6 +418,8 @@ namespace AZ
//! A user-friendly name for the entity. This makes error messages easier to read.
AZStd::string m_name;
u32 m_spawnTicketId = 0;
//! The state of the entity.
State m_state;
@@ -5,8 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZCORE_ENTITY_UTILS_H
#define AZCORE_ENTITY_UTILS_H
#pragma once
#include <AzCore/Component/Entity.h>
#include <AzCore/Debug/Profiler.h>
@@ -217,6 +216,3 @@ namespace AZ
} // namespace EntityUtils
} // namespace AZ
#endif // AZCORE_ENTITY_UTILS_H
#pragma once
@@ -46,8 +46,6 @@ namespace AZ
TICK_PRE_RENDER = 750, ///< Suggested tick handler position to update render-related data.
TICK_RENDER = 800, ///< Suggested tick handler position for rendering.
TICK_DEFAULT = 1000, ///< Default tick handler position when the handler is constructed.
TICK_UI = 2000, ///< Suggested tick handler position for UI components.
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/EBus/Policies.h>
+7 -10
View File
@@ -19,14 +19,11 @@
#pragma once
#include <AzCore/EBus/BusImpl.h>
#include <AzCore/EBus/Environment.h>
#include <AzCore/EBus/Results.h>
#include <AzCore/EBus/Internal/Debug.h>
// Included for backwards compatibility purposes
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/typetraits/is_same.h>
// End backwards compat
#include <AzCore/std/utils.h>
#include <AzCore/std/parallel/scoped_lock.h>
@@ -90,14 +87,14 @@ namespace AZ
* For available settings, see AZ::EBusHandlerPolicy.
* By default, an EBus supports any number of handlers.
*/
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple;
static constexpr EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple;
/**
* Defines how many addresses exist on the EBus.
* For available settings, see AZ::EBusAddressPolicy.
* By default, an EBus uses a single address.
*/
static const EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single;
static constexpr EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single;
/**
* The type of ID that is used to address the EBus.
@@ -152,14 +149,14 @@ namespace AZ
* `<BusName>::ExecuteQueuedEvents()`.
* By default, the event queue is disabled.
*/
static const bool EnableEventQueue = false;
static constexpr bool EnableEventQueue = false;
/**
* Specifies whether the bus should accept queued messages by default or not.
* If set to false, Bus::AllowFunctionQueuing(true) must be called before events are accepted.
* Used only when #EnableEventQueue is true.
*/
static const bool EventQueueingActiveByDefault = true;
static constexpr bool EventQueueingActiveByDefault = true;
/**
* Specifies whether the EBus supports queueing functions which take reference
@@ -168,7 +165,7 @@ namespace AZ
* You should only use this if you know that the data being passed as arguments will
* outlive the dispatch of the queued event.
*/
static const bool EnableQueuedReferences = false;
static constexpr bool EnableQueuedReferences = false;
/**
* Locking primitive that is used when adding and removing
@@ -197,7 +194,7 @@ namespace AZ
* to do.
* By default, the standard policy is used, which locks around all dispatches
*/
static const bool LocklessDispatch = false;
static constexpr bool LocklessDispatch = false;
/**
* Specifies where EBus data is stored.
@@ -13,6 +13,7 @@
#include <AzCore/EBus/EBus.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/RTTI/TypeSafeIntegral.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
namespace AZ
{
+14 -23
View File
@@ -18,9 +18,8 @@
#include <AzCore/std/function/invoke.h>
#include <AzCore/std/containers/queue.h>
#include <AzCore/std/containers/intrusive_set.h>
#include <AzCore/std/parallel/scoped_lock.h>
#include <AzCore/Module/Environment.h>
#include <AzCore/EBus/Environment.h>
namespace AZ
{
@@ -251,29 +250,21 @@ namespace AZ
void Execute()
{
AZ_Warning("System", m_isActive, "You are calling execute queued functions on a bus which has not activated its function queuing! Call YourBus::AllowFunctionQueuing(true)!");
while (true)
MessageQueueType localMessages;
// Swap the current list of queue functions with a local instance
{
BusMessageCall invoke;
AZStd::scoped_lock lock(m_messagesMutex);
AZStd::swap(localMessages, m_messages);
}
//////////////////////////////////////////////////////////////////////////
// Pop element from the queue.
{
AZStd::lock_guard<MutexType> lock(m_messagesMutex);
size_t numMessages = m_messages.size();
if (numMessages == 0)
{
break;
}
AZStd::swap(invoke, m_messages.front());
m_messages.pop();
if (numMessages == 1)
{
m_messages = {};
}
}
//////////////////////////////////////////////////////////////////////////
invoke();
// Execute the queue functions safely now that are owned by the function
while (!localMessages.empty())
{
const BusMessageCall& localMessage = localMessages.front();
localMessage();
localMessages.pop();
}
}
@@ -43,10 +43,12 @@ namespace AZ::IO
m_mainLoopDesc = threadDesc;
m_mainLoopDesc.m_name = "IO Scheduler";
m_mainLoop = AZStd::thread([this]()
{
Thread_MainLoop();
}, &m_mainLoopDesc);
m_mainLoop = AZStd::thread(
m_mainLoopDesc,
[this]()
{
Thread_MainLoop();
});
}
}
@@ -644,11 +644,11 @@ JobManagerWorkStealing::ThreadList JobManagerWorkStealing::CreateWorkerThreads(c
}
info->m_thread = AZStd::thread(
threadDesc,
[this, info]()
{
this->ProcessJobsWorker(info);
},
&threadDesc
}
);
info->m_threadId = info->m_thread.get_id();
@@ -7,6 +7,7 @@
*/
#include <AzCore/Name/NameSerializer.h>
#include <AzCore/IO/GenericStreams.h>
namespace AZ
{
@@ -14,6 +14,7 @@
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/std/containers/array.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/function/invoke.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/string_view.h>
@@ -5,11 +5,13 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Script/ScriptContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Script/lua/lua.h>
#include <AzCore/Script/ScriptProperty.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
@@ -5,8 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZCORE_SCRIPT_SCRIPTPROPERTY_H
#define AZCORE_SCRIPT_SCRIPTPROPERTY_H
#pragma once
#include <AzCore/Component/EntityId.h>
#include <AzCore/Memory/SystemAllocator.h>
@@ -490,5 +489,4 @@ namespace AZ
};
}
#endif
@@ -8,6 +8,7 @@
#include <cinttypes>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Serialization/DataPatch.h>
#include <AzCore/Serialization/DataPatchBus.h>
#include <AzCore/Serialization/DataPatchUpgradeManager.h>
@@ -9,6 +9,7 @@
#include "AzCore/RTTI/TypeInfo.h"
#include <AzCore/Math/UuidSerializer.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Json/CastingHelpers.h>
#include <AzCore/Serialization/Json/JsonDeserializer.h>
#include <AzCore/Serialization/Json/JsonStringConversionUtils.h>
@@ -6,7 +6,9 @@
*
*/
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Json/JsonSerializer.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
@@ -7,6 +7,7 @@
*/
#include <algorithm>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Json/BasicContainerSerializer.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/MapSerializer.h>
@@ -7,6 +7,7 @@
*/
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Serialization/ObjectStream.h>
#include <AzCore/Serialization/DataOverlayInstanceMsgs.h>
#include <AzCore/Serialization/DataOverlayProviderMsgs.h>
@@ -37,7 +37,8 @@ namespace AZ
class GenericStream;
}
namespace ObjectStreamInternal {
namespace ObjectStreamInternal
{
class ObjectStreamImpl;
}
@@ -7,6 +7,8 @@
*/
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/DataOverlay.h>
#include <AzCore/Serialization/DynamicSerializableField.h>
@@ -5,8 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZCORE_SERIALIZE_CONTEXT_H
#define AZCORE_SERIALIZE_CONTEXT_H
#pragma once
#include <limits>
@@ -43,6 +42,12 @@
namespace AZ
{
namespace Data
{
template<typename T>
class Asset;
}
class EditContext;
class ObjectStream;
@@ -2562,11 +2567,13 @@ namespace AZ
#include <AzCore/Serialization/AZStdContainers.inl>
#include <AzCore/Serialization/std/VariantReflection.inl>
/// include asset generics
#include <AzCore/Asset/AssetSerializer.h>
// Forward declare asset serialization helper specialization
namespace AZ
{
template<typename T>
struct SerializeGenericTypeInfo< Data::Asset<T> >;
}
/// include implementation of SerializeContext::EnumBuilder
#include <AzCore/Serialization/SerializeContextEnum.inl>
#endif // AZCORE_SERIALIZE_CONTEXT_H
#pragma once
@@ -717,7 +717,9 @@ namespace AZ::SettingsRegistryMergeUtils
if (registry.Get(cacheRootPath, FilePathKey_CacheRootFolder))
{
mergePath = AZStd::move(cacheRootPath);
mergePath /= SettingsRegistryInterface::RegistryFolder;
AZStd::fixed_string<32> registryFolderLower(SettingsRegistryInterface::RegistryFolder);
AZStd::to_lower(registryFolderLower.begin(), registryFolderLower.end());
mergePath /= registryFolderLower;
registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer);
}
@@ -13,6 +13,7 @@
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/std/algorithm.h>
@@ -10,6 +10,7 @@
#include <AzCore/EBus/BusImpl.h> //Just to get AZ::NullMutex
#include <AzCore/std/chrono/types.h>
#include <AzCore/Statistics/StatisticsManager.h>
#include <AzCore/std/chrono/chrono.h>
#include <AzCore/std/parallel/scoped_lock.h>
namespace AZ
@@ -243,7 +244,7 @@ namespace AZ
//! This one is needed because running statistics are collected many times across
//! several frames. This value is used to calculate a per frame sample for @m_totalTimePerFrameStat,
//! by subtracting @m_prevAccumulatedSums from the accumulated sum in @m_statisticsManager.
//! by subtracting @m_prevAccumulatedSums from the accumulated sum in @m_statisticsManager.
double m_prevAccumulatedSums;
};
@@ -190,11 +190,13 @@ namespace AZ
class TaskWorker
{
public:
void Spawn(::AZ::TaskExecutor& executor, size_t id, AZStd::semaphore& initSemaphore, bool affinitize)
static thread_local TaskWorker* t_worker;
void Spawn(::AZ::TaskExecutor& executor, uint32_t id, AZStd::semaphore& initSemaphore, bool affinitize)
{
m_executor = &executor;
AZStd::string threadName = AZStd::string::format("TaskWorker %zu", id);
AZStd::string threadName = AZStd::string::format("TaskWorker %u", id);
AZStd::thread_desc desc = {};
desc.m_name = threadName.c_str();
if (affinitize)
@@ -203,12 +205,29 @@ namespace AZ
}
m_active.store(true, AZStd::memory_order_release);
m_thread = AZStd::thread{ [this, &initSemaphore]
m_thread = AZStd::thread{ desc,
[this, &initSemaphore]
{
t_worker = this;
initSemaphore.release();
Run();
},
&desc };
} };
}
// Threads that wait on a graph to complete are disqualified from receiving tasks until the wait finishes
void Disable()
{
m_enabled = false;
}
void Enable()
{
m_enabled = true;
}
bool Enabled() const
{
return m_enabled;
}
void Join()
@@ -222,11 +241,7 @@ namespace AZ
{
m_queue.Enqueue(task);
if (!m_busy.exchange(true))
{
// The worker was idle prior to enqueueing the task, release the semaphore
m_semaphore.release();
}
m_semaphore.release();
}
private:
@@ -234,7 +249,6 @@ namespace AZ
{
while (m_active)
{
m_busy = false;
m_semaphore.acquire();
if (!m_active)
@@ -242,8 +256,6 @@ namespace AZ
return;
}
m_busy = true;
Task* task = m_queue.TryDequeue();
while (task)
{
@@ -271,12 +283,15 @@ namespace AZ
AZStd::thread m_thread;
AZStd::atomic<bool> m_active;
AZStd::atomic<bool> m_busy;
AZStd::atomic<bool> m_enabled = true;
AZStd::binary_semaphore m_semaphore;
::AZ::TaskExecutor* m_executor;
TaskQueue m_queue;
friend class ::AZ::TaskExecutor;
};
thread_local TaskWorker* TaskWorker::t_worker = nullptr;
} // namespace Internal
static EnvironmentVariable<TaskExecutor*> s_executor;
@@ -291,13 +306,16 @@ namespace AZ
return **s_executor;
}
// TODO: Create the default executor as part of a component (as in TaskManagerComponent)
void TaskExecutor::SetInstance(TaskExecutor* executor)
{
AZ_Assert(!s_executor, "Attempting to set the global task executor more than once");
s_executor = AZ::Environment::CreateVariable<TaskExecutor*>("GlobalTaskExecutor");
s_executor.Set(executor);
if (!executor)
{
s_executor.Reset();
}
else if (!s_executor) // ignore any calls to set after the first (this happens in unit tests that create new system entities)
{
s_executor = AZ::Environment::CreateVariable<TaskExecutor*>(s_executorName, executor);
}
}
TaskExecutor::TaskExecutor(uint32_t threadCount)
@@ -307,14 +325,12 @@ namespace AZ
m_workers = reinterpret_cast<Internal::TaskWorker*>(azmalloc(m_threadCount * sizeof(Internal::TaskWorker)));
bool affinitize = m_threadCount == AZStd::thread::hardware_concurrency();
AZStd::semaphore initSemaphore;
for (size_t i = 0; i != m_threadCount; ++i)
for (uint32_t i = 0; i != m_threadCount; ++i)
{
new (m_workers + i) Internal::TaskWorker{};
m_workers[i].Spawn(*this, i, initSemaphore, affinitize);
m_workers[i].Spawn(*this, i, initSemaphore, false);
}
for (size_t i = 0; i != m_threadCount; ++i)
@@ -334,9 +350,21 @@ namespace AZ
azfree(m_workers);
}
void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph)
Internal::TaskWorker* TaskExecutor::GetTaskWorker()
{
if (Internal::TaskWorker::t_worker && Internal::TaskWorker::t_worker->m_executor == this)
{
return Internal::TaskWorker::t_worker;
}
return nullptr;
}
void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph, TaskGraphEvent* event)
{
++m_graphsRemaining;
event->m_executor = this; // Used to validate event is not waited for inside a job
// Submit all tasks that have no inbound edges
for (Internal::Task& task : graph.Tasks())
{
@@ -352,11 +380,24 @@ namespace AZ
// TODO: Something more sophisticated is likely needed here.
// First, we are completely ignoring affinity.
// Second, some heuristics on core availability will help distribute work more effectively
m_workers[++m_lastSubmission % m_threadCount].Enqueue(&task);
uint32_t nextWorker = ++m_lastSubmission % m_threadCount;
while (!m_workers[nextWorker].Enabled())
{
// Graphs that are waiting for the completion of a task graph cannot enqueue tasks onto
// the thread issuing the wait.
nextWorker = ++m_lastSubmission % m_threadCount;
}
m_workers[nextWorker].Enqueue(&task);
}
void TaskExecutor::ReleaseGraph()
{
--m_graphsRemaining;
}
void TaskExecutor::ReactivateTaskWorker()
{
GetTaskWorker()->Enable();
}
} // namespace AZ
@@ -72,14 +72,19 @@ namespace AZ
explicit TaskExecutor(uint32_t threadCount = 0);
~TaskExecutor();
void Submit(Internal::CompiledTaskGraph& graph);
// Submit a task graph for execution. Waitable task graphs cannot enqueue work on the task thread
// that is currently active
void Submit(Internal::CompiledTaskGraph& graph, TaskGraphEvent* event);
void Submit(Internal::Task& task);
private:
friend class Internal::TaskWorker;
friend class TaskGraphEvent;
Internal::TaskWorker* GetTaskWorker();
void ReleaseGraph();
void ReactivateTaskWorker();
Internal::TaskWorker* m_workers;
uint32_t m_threadCount = 0;
@@ -14,6 +14,12 @@ namespace AZ
{
using Internal::CompiledTaskGraph;
void TaskGraphEvent::Wait()
{
AZ_Assert(m_executor->GetTaskWorker() == nullptr, "Waiting in a task is unsupported");
m_semaphore.acquire();
}
void TaskToken::PrecedesInternal(TaskToken& comesAfter)
{
AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted.");
@@ -71,7 +77,7 @@ namespace AZ
m_compiledTaskGraph->m_tasks[i].Init();
}
executor.Submit(*m_compiledTaskGraph);
executor.Submit(*m_compiledTaskGraph, waitEvent);
if (m_retained)
{
@@ -22,10 +22,19 @@ namespace AZ
namespace Internal
{
class CompiledTaskGraph;
class TaskWorker;
}
class TaskExecutor;
class TaskGraph;
class TaskGraphActiveInterface
{
public:
AZ_RTTI(TaskGraphActiveInterface, "{08118074-B139-4EF9-B8FD-29F1D6DC9233}");
virtual bool IsTaskGraphActive() const = 0;
};
// A TaskToken is returned each time a Task is added to the TaskGraph. TaskTokens are used to
// express dependencies between tasks within the graph, and have no purpose after the graph
// is submitted (simply let them go out of scope)
@@ -70,9 +79,12 @@ namespace AZ
private:
friend class ::AZ::Internal::CompiledTaskGraph;
friend class TaskGraph;
friend class TaskExecutor;
void Signal();
AZStd::binary_semaphore m_semaphore;
TaskExecutor* m_executor = nullptr;
};
// The TaskGraph encapsulates a set of tasks and their interdependencies. After adding
@@ -89,6 +101,9 @@ namespace AZ
// Reset the state of the task graph to begin recording tasks and edges again
// NOTE: Graph must be in a "settled" state (cannot be in-flight)
void Reset();
// Returns false if 1 or more tasks have been added to the graph
bool IsEmpty();
// Add a task to the graph, retrieiving a token that can be used to express dependencies
// between tasks. The first argument specifies the TaskKind, used for tracking the task.
@@ -33,11 +33,6 @@ namespace AZ
return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 });
}
inline void TaskGraphEvent::Wait()
{
m_semaphore.acquire();
}
inline void TaskGraphEvent::Signal()
{
m_semaphore.release();
@@ -59,6 +54,11 @@ namespace AZ
return { AddTask(descriptor, AZStd::forward<Lambdas>(lambdas))... };
}
inline bool TaskGraph::IsEmpty()
{
return m_tasks.empty();
}
inline void TaskGraph::Detach()
{
m_retained = false;
@@ -0,0 +1,88 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Console/IConsole.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Task/TaskGraphSystemComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
// Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system.
AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)");
static constexpr uint32_t TaskExecutorServiceCrc = AZ_CRC_CE("TaskExecutorService");
namespace AZ
{
void TaskGraphSystemComponent::Activate()
{
AZ_Assert(m_taskExecutor == nullptr, "Error multiple activation of the TaskGraphSystemComponent");
if (Interface<TaskGraphActiveInterface>::Get() == nullptr)
{
Interface<TaskGraphActiveInterface>::Register(this);
m_taskExecutor = aznew TaskExecutor();
TaskExecutor::SetInstance(m_taskExecutor);
}
}
void TaskGraphSystemComponent::Deactivate()
{
if (&TaskExecutor::Instance() == m_taskExecutor) // check that our instance is the global instance (not always true in unit tests)
{
m_taskExecutor->SetInstance(nullptr);
}
if (m_taskExecutor)
{
azdestroy(m_taskExecutor);
m_taskExecutor = nullptr;
}
if (Interface<TaskGraphActiveInterface>::Get() == this)
{
Interface<TaskGraphActiveInterface>::Unregister(this);
}
}
void TaskGraphSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(TaskExecutorServiceCrc);
}
void TaskGraphSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(TaskExecutorServiceCrc);
}
void TaskGraphSystemComponent::GetDependentServices([[maybe_unused]] ComponentDescriptor::DependencyArrayType& dependent)
{
}
void TaskGraphSystemComponent::Reflect(ReflectContext* context)
{
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<TaskGraphSystemComponent, AZ::Component>()
->Version(1)
;
if (AZ::EditContext* ec = serializeContext->GetEditContext())
{
ec->Class<TaskGraphSystemComponent>
("TaskGraph", "System component to create the default executor")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Engine")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
;
}
}
}
bool TaskGraphSystemComponent::IsTaskGraphActive() const
{
return cl_activateTaskGraph;
}
} // namespace AZ
@@ -0,0 +1,47 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Task/TaskExecutor.h>
#include <AzCore/Task/TaskGraph.h>
namespace AZ
{
class TaskGraphSystemComponent
: public Component
, public TaskGraphActiveInterface
{
public:
AZ_COMPONENT(AZ::TaskGraphSystemComponent, "{5D56B829-1FEB-43D5-A0BD-E33C0497EFE2}")
TaskGraphSystemComponent() = default;
// Implement TaskGraphActiveInterface
bool IsTaskGraphActive() const override;
private:
//////////////////////////////////////////////////////////////////////////
// Component base
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
/// \ref ComponentDescriptor::GetProvidedServices
static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided);
/// \ref ComponentDescriptor::GetIncompatibleServices
static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible);
/// \ref ComponentDescriptor::GetDependentServices
static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent);
/// \red ComponentDescriptor::Reflect
static void Reflect(ReflectContext* reflection);
AZ::TaskExecutor* m_taskExecutor = nullptr;
};
}
@@ -633,6 +633,8 @@ set(FILES
Task/TaskGraph.cpp
Task/TaskGraph.h
Task/TaskGraph.inl
Task/TaskGraphSystemComponent.h
Task/TaskGraphSystemComponent.cpp
Threading/ThreadSafeDeque.h
Threading/ThreadSafeDeque.inl
Threading/ThreadSafeObject.h
@@ -87,12 +87,6 @@ namespace AZStd
// construct/copy/destroy:
thread();
/**
* \note thread_desc is AZStd extension.
*/
template <class F>
explicit thread(F&& f, const thread_desc* desc = 0);
~thread();
thread(thread&& rhs)
@@ -108,6 +102,15 @@ namespace AZStd
return *this;
}
template<class F, class... Args, typename = AZStd::enable_if_t<!AZStd::is_convertible_v<AZStd::decay_t<F>, thread_desc>>>
explicit thread(F&& f, Args&&... args);
/**
* \note thread_desc is AZStd extension.
*/
template<class F, class... Args>
thread(const thread_desc& desc, F&& f, Args&&... args);
// Till we fully have RVALUES
template <class F>
explicit thread(Internal::thread_move_t<F> f);
@@ -138,8 +141,8 @@ namespace AZStd
//thread(AZStd::delegate<void ()> d,const thread_desc* desc = 0);
private:
thread(thread&);
thread& operator=(thread&);
thread(const thread&) = delete;
thread& operator=(const thread&) = delete;
native_thread_data_type m_thread;
};
@@ -10,6 +10,8 @@
#include <unistd.h>
#include <sched.h>
#include <AzCore/std/tuple.h>
namespace AZStd
{
namespace Internal
@@ -22,12 +24,20 @@ namespace AZStd
//////////////////////////////////////////////////////////////////////////
// thread
template <class F>
inline thread::thread(F&& f, const thread_desc* desc)
template<class F, class... Args, typename>
thread::thread(F&& f, Args&&... args)
: thread(thread_desc{}, AZStd::forward<F>(f), AZStd::forward<Args>(args)...)
{}
template<class F, class... Args>
thread::thread(const thread_desc& desc, F&& f, Args&&... args)
{
Internal::thread_info* ti = Internal::create_thread_info(AZStd::forward<F>(f));
ti->m_name = desc ? desc->m_name : nullptr;
m_thread = Internal::create_thread(desc, ti);
auto threadfunc = [fn = AZStd::forward<F>(f), argsTuple = AZStd::make_tuple(AZStd::forward<Args>(args)...)]() mutable -> void
{
AZStd::apply(AZStd::move(fn), AZStd::move(argsTuple));
};
Internal::thread_info* ti = Internal::create_thread_info(AZStd::move(threadfunc));
m_thread = Internal::create_thread(&desc, ti);
}
inline bool thread::joinable() const
@@ -18,6 +18,8 @@ extern "C"
AZ_DLL_IMPORT unsigned long __stdcall GetCurrentThreadId(void);
}
#include <AzCore/std/tuple.h>
namespace AZStd
{
namespace Internal
@@ -30,11 +32,20 @@ namespace AZStd
//////////////////////////////////////////////////////////////////////////
// thread
template <class F>
inline thread::thread(F&& f, const thread_desc* desc)
template<class F, class... Args, typename>
thread::thread(F&& f, Args&&... args)
: thread(thread_desc{}, AZStd::forward<F>(f), AZStd::forward<Args>(args)...)
{}
template<class F, class... Args>
thread::thread(const thread_desc& desc, F&& f, Args&&... args)
{
Internal::thread_info* ti = Internal::create_thread_info(AZStd::forward<F>(f));
m_thread.m_handle = Internal::create_thread(desc, ti, &m_thread.m_id);
auto threadfunc = [fn = AZStd::forward<F>(f), argsTuple = AZStd::make_tuple(AZStd::forward<Args>(args)...)]() mutable -> void
{
AZStd::apply(AZStd::move(fn), AZStd::move(argsTuple));
};
Internal::thread_info* ti = Internal::create_thread_info(AZStd::move(threadfunc));
m_thread.m_handle = Internal::create_thread(&desc, ti, &m_thread.m_id);
}
inline bool thread::joinable() const
+77 -77
View File
@@ -195,18 +195,18 @@ namespace UnitTest
void test_thread_id_for_running_thread_is_not_default_constructed_id()
{
const thread_desc* desc = m_numThreadDesc ? &m_desc[0] : nullptr;
AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc);
const thread_desc desc = m_numThreadDesc ? m_desc[0] : thread_desc{};
AZStd::thread t(desc, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZ_TEST_ASSERT(t.get_id() != AZStd::thread::id());
t.join();
}
void test_different_threads_have_different_ids()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr;
AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc1);
AZStd::thread t2(AZStd::bind(&Parallel_Thread::do_nothing, this), desc2);
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{};
AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZ_TEST_ASSERT(t.get_id() != t2.get_id());
t.join();
t2.join();
@@ -214,13 +214,13 @@ namespace UnitTest
void test_thread_ids_have_a_total_order()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr;
const thread_desc* desc3 = m_numThreadDesc ? &m_desc[2] : nullptr;
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{};
const thread_desc desc3 = m_numThreadDesc ? m_desc[2] : thread_desc{};
AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc1);
AZStd::thread t2(AZStd::bind(&Parallel_Thread::do_nothing, this), desc2);
AZStd::thread t3(AZStd::bind(&Parallel_Thread::do_nothing, this), desc3);
AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZStd::thread t3(desc3, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZ_TEST_ASSERT(t.get_id() != t2.get_id());
AZ_TEST_ASSERT(t.get_id() != t3.get_id());
AZ_TEST_ASSERT(t2.get_id() != t3.get_id());
@@ -313,10 +313,10 @@ namespace UnitTest
void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
AZStd::thread::id id;
AZStd::thread t(AZStd::bind(&Parallel_Thread::get_thread_id, this, &id), desc1);
AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::get_thread_id, this, &id));
AZStd::thread::id t_id = t.get_id();
t.join();
AZ_TEST_ASSERT(id == t_id);
@@ -366,10 +366,10 @@ namespace UnitTest
void test_move_on_construction()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
AZStd::thread::id the_id;
AZStd::thread x;
x = AZStd::thread(AZStd::bind(&Parallel_Thread::do_nothing_id, this, &the_id), desc1);
x = AZStd::thread(desc1, AZStd::bind(&Parallel_Thread::do_nothing_id, this, &the_id));
AZStd::thread::id x_id = x.get_id();
x.join();
AZ_TEST_ASSERT(the_id == x_id);
@@ -377,8 +377,8 @@ namespace UnitTest
AZStd::thread make_thread(AZStd::thread::id* the_id)
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
return AZStd::thread(AZStd::bind(&Parallel_Thread::do_nothing_id, this, the_id), desc1);
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
return AZStd::thread(desc1, AZStd::bind(&Parallel_Thread::do_nothing_id, this, the_id));
}
void test_move_from_function_return()
@@ -430,9 +430,9 @@ namespace UnitTest
void do_test_creation()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
m_data = 0;
AZStd::thread t(AZStd::bind(&Parallel_Thread::simple_thread, this), desc1);
AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::simple_thread, this));
t.join();
AZ_TEST_ASSERT(m_data == 999);
}
@@ -445,9 +445,9 @@ namespace UnitTest
void do_test_id_comparison()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
AZStd::thread::id self = this_thread::get_id();
AZStd::thread thrd(AZStd::bind(&Parallel_Thread::comparison_thread, this, self), desc1);
AZStd::thread thrd(desc1, AZStd::bind(&Parallel_Thread::comparison_thread, this, self));
thrd.join();
}
@@ -476,10 +476,10 @@ namespace UnitTest
void do_test_creation_through_reference_wrapper()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
non_copyable_functor f;
AZStd::thread thrd(AZStd::ref(f), desc1);
AZStd::thread thrd(desc1, AZStd::ref(f));
thrd.join();
AZ_TEST_ASSERT(f.value == 999);
}
@@ -491,10 +491,10 @@ namespace UnitTest
void test_swap()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr;
AZStd::thread t(AZStd::bind(&Parallel_Thread::simple_thread, this), desc1);
AZStd::thread t2(AZStd::bind(&Parallel_Thread::simple_thread, this), desc2);
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{};
AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::simple_thread, this));
AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::simple_thread, this));
AZStd::thread::id id1 = t.get_id();
AZStd::thread::id id2 = t2.get_id();
@@ -512,7 +512,7 @@ namespace UnitTest
void run()
{
const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
// We need to have at least one processor
AZ_TEST_ASSERT(AZStd::thread::hardware_concurrency() >= 1);
@@ -520,18 +520,18 @@ namespace UnitTest
// Create thread to increment data till we need to
m_data = 0;
m_dataMax = 10;
AZStd::thread tr(AZStd::bind(&Parallel_Thread::increment_data, this), desc1);
AZStd::thread tr(desc1, AZStd::bind(&Parallel_Thread::increment_data, this));
tr.join();
AZ_TEST_ASSERT(m_data == m_dataMax);
m_data = 0;
AZStd::thread trDel(make_delegate(this, &Parallel_Thread::increment_data), desc1);
AZStd::thread trDel(desc1, make_delegate(this, &Parallel_Thread::increment_data));
trDel.join();
AZ_TEST_ASSERT(m_data == m_dataMax);
chrono::system_clock::time_point startTime = chrono::system_clock::now();
{
AZStd::thread tr1(AZStd::bind(&Parallel_Thread::sleep_thread, this, chrono::milliseconds(100)), desc1);
AZStd::thread tr1(desc1, AZStd::bind(&Parallel_Thread::sleep_thread, this, chrono::milliseconds(100)));
tr1.join();
}
auto sleepTime = chrono::system_clock::now() - startTime;
@@ -563,71 +563,71 @@ namespace UnitTest
{
MfTest x;
AZStd::function<void ()> func = AZStd::bind(&MfTest::f0, &x);
AZStd::thread(func, desc1).join();
AZStd::thread(desc1, func).join();
func = AZStd::bind(&MfTest::f0, AZStd::ref(x));
AZStd::thread(func, desc1).join();
AZStd::thread(desc1, func).join();
func = AZStd::bind(&MfTest::g0, &x);
AZStd::thread(func, desc1).join();
AZStd::thread(desc1, func).join();
func = AZStd::bind(&MfTest::g0, x);
AZStd::thread(func, desc1).join();
AZStd::thread(desc1, func).join();
func = AZStd::bind(&MfTest::g0, AZStd::ref(x));
AZStd::thread(func, desc1).join();
AZStd::thread(desc1, func).join();
//// 1
//thread( AZStd::bind(&MfTest::f1, &x, 1) , desc1).join();
//thread( AZStd::bind(&MfTest::f1, AZStd::ref(x), 1) , desc1).join();
//thread( AZStd::bind(&MfTest::g1, &x, 1) , desc1).join();
//thread( AZStd::bind(&MfTest::g1, x, 1) , desc1).join();
//thread( AZStd::bind(&MfTest::g1, AZStd::ref(x), 1) , desc1).join();
//thread( AZStd::bind(desc1, &MfTest::f1, &x, 1)).join();
//thread( AZStd::bind(desc1, &MfTest::f1, AZStd::ref(x), 1)).join();
//thread( AZStd::bind(desc1, &MfTest::g1, &x, 1)).join();
//thread( AZStd::bind(desc1, &MfTest::g1, x, 1)).join();
//thread( AZStd::bind(desc1, &MfTest::g1, AZStd::ref(x), 1)).join();
//// 2
//thread( AZStd::bind(&MfTest::f2, &x, 1, 2) , desc1).join();
//thread( AZStd::bind(&MfTest::f2, AZStd::ref(x), 1, 2) , desc1).join();
//thread( AZStd::bind(&MfTest::g2, &x, 1, 2) , desc1).join();
//thread( AZStd::bind(&MfTest::g2, x, 1, 2) , desc1).join();
//thread( AZStd::bind(&MfTest::g2, AZStd::ref(x), 1, 2) , desc1).join();
//thread( AZStd::bind(desc1, &MfTest::f2, &x, 1, 2)).join();
//thread( AZStd::bind(desc1, &MfTest::f2, AZStd::ref(x), 1, 2)).join();
//thread( AZStd::bind(desc1, &MfTest::g2, &x, 1, 2)).join();
//thread( AZStd::bind(desc1, &MfTest::g2, x, 1, 2)).join();
//thread( AZStd::bind(desc1, &MfTest::g2, AZStd::ref(x), 1, 2)).join();
//// 3
//thread( AZStd::bind(&MfTest::f3, &x, 1, 2, 3) , desc1).join();
//thread( AZStd::bind(&MfTest::f3, AZStd::ref(x), 1, 2, 3) , desc1).join();
//thread( AZStd::bind(&MfTest::g3, &x, 1, 2, 3) , desc1).join();
//thread( AZStd::bind(&MfTest::g3, x, 1, 2, 3) , desc1).join();
//thread( AZStd::bind(&MfTest::g3, AZStd::ref(x), 1, 2, 3) , desc1).join();
//thread( AZStd::bind(desc1, &MfTest::f3, &x, 1, 2, 3)).join();
//thread( AZStd::bind(desc1, &MfTest::f3, AZStd::ref(x), 1, 2, 3)).join();
//thread( AZStd::bind(desc1, &MfTest::g3, &x, 1, 2, 3)).join();
//thread( AZStd::bind(desc1, &MfTest::g3, x, 1, 2, 3)).join();
//thread( AZStd::bind(desc1, &MfTest::g3, AZStd::ref(x), 1, 2, 3)).join();
//// 4
//thread( AZStd::bind(&MfTest::f4, &x, 1, 2, 3, 4) , desc1).join();
//thread( AZStd::bind(&MfTest::f4, AZStd::ref(x), 1, 2, 3, 4) , desc1).join();
//thread( AZStd::bind(&MfTest::g4, &x, 1, 2, 3, 4) , desc1).join();
//thread( AZStd::bind(&MfTest::g4, x, 1, 2, 3, 4) , desc1).join();
//thread( AZStd::bind(&MfTest::g4, AZStd::ref(x), 1, 2, 3, 4) , desc1).join();
//thread( AZStd::bind(desc1, &MfTest::f4, &x, 1, 2, 3, 4)).join();
//thread( AZStd::bind(desc1, &MfTest::f4, AZStd::ref(x), 1, 2, 3, 4)).join();
//thread( AZStd::bind(desc1, &MfTest::g4, &x, 1, 2, 3, 4)).join();
//thread( AZStd::bind(desc1, &MfTest::g4, x, 1, 2, 3, 4)).join();
//thread( AZStd::bind(desc1, &MfTest::g4, AZStd::ref(x), 1, 2, 3, 4)).join();
//// 5
//thread( AZStd::bind(&MfTest::f5, &x, 1, 2, 3, 4, 5) , desc1).join();
//thread( AZStd::bind(&MfTest::f5, AZStd::ref(x), 1, 2, 3, 4, 5) , desc1).join();
//thread( AZStd::bind(&MfTest::g5, &x, 1, 2, 3, 4, 5) , desc1).join();
//thread( AZStd::bind(&MfTest::g5, x, 1, 2, 3, 4, 5) , desc1).join();
//thread( AZStd::bind(&MfTest::g5, AZStd::ref(x), 1, 2, 3, 4, 5) , desc1).join();
//thread( AZStd::bind(desc1, &MfTest::f5, &x, 1, 2, 3, 4, 5)).join();
//thread( AZStd::bind(desc1, &MfTest::f5, AZStd::ref(x), 1, 2, 3, 4, 5)).join();
//thread( AZStd::bind(desc1, &MfTest::g5, &x, 1, 2, 3, 4, 5)).join();
//thread( AZStd::bind(desc1, &MfTest::g5, x, 1, 2, 3, 4, 5)).join();
//thread( AZStd::bind(desc1, &MfTest::g5, AZStd::ref(x), 1, 2, 3, 4, 5)).join();
//// 6
//thread( AZStd::bind(&MfTest::f6, &x, 1, 2, 3, 4, 5, 6) , desc1).join();
//thread( AZStd::bind(&MfTest::f6, AZStd::ref(x), 1, 2, 3, 4, 5, 6) , desc1).join();
//thread( AZStd::bind(&MfTest::g6, &x, 1, 2, 3, 4, 5, 6) , desc1).join();
//thread( AZStd::bind(&MfTest::g6, x, 1, 2, 3, 4, 5, 6) , desc1).join();
//thread( AZStd::bind(&MfTest::g6, AZStd::ref(x), 1, 2, 3, 4, 5, 6) , desc1).join();
//thread( AZStd::bind(desc1, &MfTest::f6, &x, 1, 2, 3, 4, 5, 6)).join();
//thread( AZStd::bind(desc1, &MfTest::f6, AZStd::ref(x), 1, 2, 3, 4, 5, 6)).join();
//thread( AZStd::bind(desc1, &MfTest::g6, &x, 1, 2, 3, 4, 5, 6)).join();
//thread( AZStd::bind(desc1, &MfTest::g6, x, 1, 2, 3, 4, 5, 6)).join();
//thread( AZStd::bind(desc1, &MfTest::g6, AZStd::ref(x), 1, 2, 3, 4, 5, 6)).join();
//// 7
//thread( AZStd::bind(&MfTest::f7, &x, 1, 2, 3, 4, 5, 6, 7), desc1).join();
//thread( AZStd::bind(&MfTest::f7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7), desc1).join();
//thread( AZStd::bind(&MfTest::g7, &x, 1, 2, 3, 4, 5, 6, 7), desc1).join();
//thread( AZStd::bind(&MfTest::g7, x, 1, 2, 3, 4, 5, 6, 7), desc1).join();
//thread( AZStd::bind(&MfTest::g7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7), desc1).join();
//thread( AZStd::bind(desc1, &MfTest::f7, &x, 1, 2, 3, 4, 5, 6, 7)).join();
//thread( AZStd::bind(desc1, &MfTest::f7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7)).join();
//thread( AZStd::bind(desc1, &MfTest::g7, &x, 1, 2, 3, 4, 5, 6, 7)).join();
//thread( AZStd::bind(desc1, &MfTest::g7, x, 1, 2, 3, 4, 5, 6, 7)).join();
//thread( AZStd::bind(desc1, &MfTest::g7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7)).join();
//// 8
//thread( AZStd::bind(&MfTest::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
//thread( AZStd::bind(&MfTest::f8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
//thread( AZStd::bind(&MfTest::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
//thread( AZStd::bind(&MfTest::g8, x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
//thread( AZStd::bind(&MfTest::g8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
//thread( AZStd::bind(desc1, &MfTest::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8)).join();
//thread( AZStd::bind(desc1, &MfTest::f8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8)).join();
//thread( AZStd::bind(desc1, &MfTest::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8)).join();
//thread( AZStd::bind(desc1, &MfTest::g8, x, 1, 2, 3, 4, 5, 6, 7, 8)).join();
//thread( AZStd::bind(desc1, &MfTest::g8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8)).join();
AZ_TEST_ASSERT(x.m_hash == 1366);
}
@@ -8,6 +8,7 @@
#include <SerializeContextFixture.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/std/any.h>
#include <AzCore/std/containers/variant.h>
#include <AzCore/Component/Entity.h>
@@ -6,6 +6,7 @@
*
*/
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/Console.h>
#include <AzCore/Interface/Interface.h>
@@ -365,6 +366,42 @@ namespace UnitTest
};
static constexpr AZStd::chrono::seconds MaxDispatchTimeoutSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds * 12;
template <typename Pred>
bool DispatchEventsUntilCondition(AZ::Data::AssetManager& assetManager, Pred&& conditionPredicate,
AZStd::chrono::seconds logIntervalSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds,
AZStd::chrono::seconds maxTimeoutSeconds = MaxDispatchTimeoutSeconds)
{
// If the Max Timeout is hit the test will be marked as a failure
AZStd::chrono::time_point dispatchEventTimeStart = AZStd::chrono::system_clock::now();
AZStd::chrono::seconds dispatchEventNextLogTime = logIntervalSeconds;
while (!conditionPredicate())
{
AZStd::chrono::time_point currentTime = AZStd::chrono::system_clock::now();
if (AZStd::chrono::seconds elapsedTime{ currentTime - dispatchEventTimeStart };
elapsedTime >= dispatchEventNextLogTime)
{
const testing::TestInfo* test_info = ::testing::UnitTest::GetInstance()->current_test_info();
AZ_Printf("AssetManagerLoadingTest", "The DispatchEventsUntiTimeout function has been waiting for %llu seconds"
" in test %s.%s", elapsedTime.count(), test_info->test_case_name(), test_info->name());
// Update the next log time to be the next multiple of DefaultTimeout Seconds
// after current elapsed time
dispatchEventNextLogTime = elapsedTime + logIntervalSeconds - ((elapsedTime + logIntervalSeconds) % logIntervalSeconds);
if (elapsedTime >= maxTimeoutSeconds)
{
return false;
}
}
assetManager.DispatchEvents();
AZStd::this_thread::yield();
}
return true;
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_ASSET_MANAGER_FLOOD_TEST
TEST_F(AssetJobsFloodTest, DISABLED_FloodTest)
#else
@@ -1357,42 +1394,74 @@ namespace UnitTest
m_assetHandlerAndCatalog->m_numCreations = 0;
m_assetHandlerAndCatalog->m_numDestructions = 0;
{
ContainerReadyListener containerLoadingCompleteListener(NoLoadAssetId);
OnAssetReadyListener readyListener(NoLoadAssetId, azrtti_typeid<AssetWithAssetReference>());
OnAssetReadyListener depenencyListener(MyAsset2Id, azrtti_typeid<AssetWithAssetReference>());
OnAssetReadyListener dependencyListener(MyAsset2Id, azrtti_typeid<AssetWithAssetReference>());
SCOPED_TRACE("LoadDependencies_BehaviorObeyed");
auto AssetOnlyReady = [&readyListener]() -> bool
{
return readyListener.m_ready;
};
auto AssetAndDependencyReady = [&readyListener, &dependencyListener]() -> bool
{
return readyListener.m_ready && dependencyListener.m_ready;
};
auto AssetContainerReady = [&containerLoadingCompleteListener]() -> bool
{
return containerLoadingCompleteListener.m_ready;
};
auto noLoadRef = m_testAssetManager->GetAsset(NoLoadAssetId, azrtti_typeid<AssetWithAssetReference>(),
AZ::Data::AssetLoadBehavior::Default);
auto maxTimeout = AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds;
// Dispatch AssetBus events until the NoLoadAssetId has signaled an OnAssetReady
// event or the timeout has been reached
EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetOnlyReady))
<< "The DispatchEventsUntiTimeout function has not completed in "
<< MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n";
// Dispatch AssetBus events until the asset container used to load
// NoLoadAssetId has signaled an OnAssetContainerReady event
// or the timeout has been reached
// Wait until the current asset container has finished loading the NoLoadAssetId
// before trigger another load
// If the wait does not occur here, most likely what would occur is
// the AssetManager::m_ownedAssetContainers object is still loading the NoLoadAssetId
// using the default AssetLoadParameters
// If a call to GetAsset occurs at this point while the Asset is still loading
// it will ignore the new loadParams below and instead just re-use the existing
// AssetContainerReader instance, resulting in the dependent MyAsset2Id not
// being loaded
// The function that can return an existing AssetContainer instance is the
// AssetManager::GetAssetContainer. Since it can be in the middle of a load,
// updating the AssetLoadParams would have an effect on the current in progress
// load
EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetContainerReady))
<< "The DispatchEventsUntiTimeout function has not completed in "
<< MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n";
// Reset the ContainerLoadingComplete ready status back to 0
containerLoadingCompleteListener.m_ready = 0;
while (!readyListener.m_ready)
{
m_testAssetManager->DispatchEvents();
if (AZStd::chrono::system_clock::now() > maxTimeout)
{
break;
}
AZStd::this_thread::yield();
}
EXPECT_EQ(readyListener.m_ready, 1);
EXPECT_EQ(depenencyListener.m_ready, 0);
AZ::Data::AssetLoadParameters loadParams(nullptr, AZ::Data::AssetDependencyLoadRules::LoadAll);
loadParams.m_reloadMissingDependencies = true;
auto loadDependencyRef = m_testAssetManager->GetAsset(NoLoadAssetId, azrtti_typeid<AssetWithAssetReference>(),
AZ::Data::AssetLoadBehavior::Default, loadParams);
while (!depenencyListener.m_ready || !readyListener.m_ready)
{
m_testAssetManager->DispatchEvents();
if (AZStd::chrono::system_clock::now() > maxTimeout)
{
break;
}
AZStd::this_thread::yield();
}
// Dispatch AssetBus events until the NoLoadAssetId and the MyAsset2Id has signaled
// an OnAssetReady event or the timeout has been reached
EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetAndDependencyReady))
<< "The DispatchEventsUntiTimeout function has not completed in "
<< MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n";
EXPECT_EQ(readyListener.m_ready, 1);
EXPECT_EQ(depenencyListener.m_ready, 1);
EXPECT_EQ(dependencyListener.m_ready, 1);
EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetContainerReady))
<< "The DispatchEventsUntiTimeout function has not completed in "
<< MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n";
}
CheckFinishedCreationsAndDestructions();
@@ -6,6 +6,7 @@
*
*/
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/IO/SystemFile.h>
@@ -7,6 +7,7 @@
*/
#include <Tests/Asset/BaseAssetManagerTest.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/IO/SystemFile.h>
@@ -10,6 +10,7 @@
#include <AzCore/Asset/AssetJsonSerializer.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetManagerComponent.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/IO/Streamer/StreamerComponent.h>
#include <AzCore/Jobs/JobManagerComponent.h>
#include <AzCore/Jobs/JobManager.h>
@@ -6,6 +6,7 @@
*
*/
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/IO/SystemFile.h>
+5 -5
View File
@@ -151,7 +151,7 @@ namespace UnitTest
AZStd::thread m_threads[m_maxNumThreads];
for (unsigned int i = 0; i < m_maxNumThreads; ++i)
{
m_threads[i] = AZStd::thread(AZStd::bind(&SystemAllocatorTest::ThreadFunc, this), &m_desc[i]);
m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&SystemAllocatorTest::ThreadFunc, this));
// give some time offset to the threads so we can test alloc and dealloc at the same time.
//AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(500));
}
@@ -286,7 +286,7 @@ namespace UnitTest
AZStd::thread m_threads[m_maxNumThreads];
for (unsigned int i = 0; i < m_maxNumThreads; ++i)
{
m_threads[i] = AZStd::thread(AZStd::bind(&SystemAllocatorTest::ThreadFunc, this), &m_desc[i]);
m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&SystemAllocatorTest::ThreadFunc, this));
// give some time offset to the threads so we can test alloc and dealloc at the same time.
AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(500));
}
@@ -724,7 +724,7 @@ namespace UnitTest
AZStd::thread m_threads[m_maxNumThreads];
for (unsigned int i = 0; i < m_maxNumThreads; ++i)
{
m_threads[i] = AZStd::thread(AZStd::bind(&ThreadPoolAllocatorTest::AllocDeallocFunc, this), &m_desc[i]);
m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&ThreadPoolAllocatorTest::AllocDeallocFunc, this));
}
for (unsigned int i = 0; i < m_maxNumThreads; ++i)
@@ -743,12 +743,12 @@ namespace UnitTest
for (unsigned int i = m_maxNumThreads/2; i <m_maxNumThreads; ++i)
{
m_threads[i] = AZStd::thread(AZStd::bind(&ThreadPoolAllocatorTest::SharedDeAlloc, this), &m_desc[i]);
m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&ThreadPoolAllocatorTest::SharedDeAlloc, this));
}
for (unsigned int i = 0; i < m_maxNumThreads/2; ++i)
{
m_threads[i] = AZStd::thread(AZStd::bind(&ThreadPoolAllocatorTest::SharedAlloc, this), &m_desc[i]);
m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&ThreadPoolAllocatorTest::SharedAlloc, this));
}
for (unsigned int i = 0; i < m_maxNumThreads/2; ++i)
@@ -9,6 +9,7 @@
#include "FileIOBaseTestTypes.h"
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Serialization/SerializeContext.h>
+81 -3
View File
@@ -34,7 +34,7 @@ namespace UnitTest
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
m_executor = aznew TaskExecutor(4);
m_executor = aznew TaskExecutor();
}
void TearDown() override
@@ -236,6 +236,82 @@ namespace UnitTest
EXPECT_EQ(x, 1);
}
TEST_F(TaskGraphTestFixture, SingleTask)
{
AZStd::atomic_int32_t x = 0;
TaskGraph graph;
graph.AddTask(
defaultTD,
[&x]
{
x = 1;
});
TaskGraphEvent ev;
graph.SubmitOnExecutor(*m_executor, &ev);
ev.Wait();
EXPECT_EQ(1, x);
}
TEST_F(TaskGraphTestFixture, SingleTaskChain)
{
AZStd::atomic_int32_t x = 0;
TaskGraph graph;
auto a = graph.AddTask(
defaultTD,
[&x]
{
x += 1;
});
auto b = graph.AddTask(
defaultTD,
[&x]
{
x += 1;
});
b.Precedes(a);
TaskGraphEvent ev;
graph.SubmitOnExecutor(*m_executor, &ev);
ev.Wait();
EXPECT_EQ(2, x);
}
TEST_F(TaskGraphTestFixture, MultipleIndependentTaskChains)
{
AZStd::atomic_int32_t x = 0;
constexpr int numChains = 5;
TaskGraph graph;
for( int i = 0; i < numChains; ++i)
{
auto a = graph.AddTask(
defaultTD,
[&x]
{
x += 1;
});
auto b = graph.AddTask(
defaultTD,
[&x]
{
x += 1;
});
b.Precedes(a);
}
TaskGraphEvent ev;
graph.SubmitOnExecutor(*m_executor, &ev);
ev.Wait();
EXPECT_EQ(2*numChains, x);
}
TEST_F(TaskGraphTestFixture, VariadicInterface)
{
int x = 0;
@@ -388,6 +464,7 @@ namespace UnitTest
EXPECT_EQ(3, x);
}
// Waiting inside a task is disallowed , test that it fails correctly
TEST_F(TaskGraphTestFixture, SpawnSubgraph)
{
AZStd::atomic<int> x = 0;
@@ -434,7 +511,10 @@ namespace UnitTest
f.Precedes(g);
TaskGraphEvent ev;
subgraph.SubmitOnExecutor(*m_executor, &ev);
// TaskGraphEvent::Wait asserts if called on a worker thread, suppress & validate assert
AZ_TEST_START_TRACE_SUPPRESSION;
ev.Wait();
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
});
auto d = graph.AddTask(
defaultTD,
@@ -464,8 +544,6 @@ namespace UnitTest
TaskGraphEvent ev;
graph.SubmitOnExecutor(*m_executor, &ev);
ev.Wait();
EXPECT_EQ(3 | 0b100000, x);
}
TEST_F(TaskGraphTestFixture, RetainedGraph)
@@ -7,6 +7,7 @@
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/Math/Uuid.h>
#include <AzCore/std/containers/unordered_set.h>
using namespace AZ;
@@ -28,6 +28,7 @@
#include <AzCore/NativeUI/NativeUISystemComponent.h>
#include <AzCore/Module/ModuleManagerBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Task/TaskGraphSystemComponent.h>
#include <AzFramework/Asset/SimpleAsset.h>
#include <AzFramework/Asset/AssetBundleManifest.h>
@@ -295,6 +296,7 @@ namespace AzFramework
azrtti_typeid<AZ::ScriptSystemComponent>(),
azrtti_typeid<AZ::JobManagerComponent>(),
azrtti_typeid<AZ::SliceSystemComponent>(),
azrtti_typeid<AZ::TaskGraphSystemComponent>(),
azrtti_typeid<AzFramework::AssetCatalogComponent>(),
azrtti_typeid<AzFramework::CustomAssetTypeComponent>(),
@@ -477,14 +479,16 @@ namespace AzFramework
newThreadDesc.m_cpuId = AFFINITY_MASK_USERTHREADS;
newThreadDesc.m_name = newThreadName;
AZStd::binary_semaphore binarySemaphore;
AZStd::thread newThread([&workForNewThread, &binarySemaphore, &newThreadName]
{
AZ_PROFILE_SCOPE(AzFramework,
"Application::PumpSystemEventLoopWhileDoingWorkInNewThread:ThreadWorker %s", newThreadName);
AZStd::thread newThread(
newThreadDesc,
[&workForNewThread, &binarySemaphore, &newThreadName]
{
AZ_PROFILE_SCOPE(AzFramework,
"Application::PumpSystemEventLoopWhileDoingWorkInNewThread:ThreadWorker %s", newThreadName);
workForNewThread();
binarySemaphore.release();
}, &newThreadDesc);
workForNewThread();
binarySemaphore.release();
});
while (!binarySemaphore.try_acquire_for(eventPumpFrequency))
{
PumpSystemEventLoopUntilEmpty();
@@ -1631,7 +1631,20 @@ namespace AZ::IO
return nullptr;
}
ZipDir::CacheFactory factory(ZipDir::ZD_INIT_FAST, nFactoryFlags);
ZipDir::InitMethod initType = ZipDir::InitMethod::Default;
if (!ZipDir::IsReleaseConfig)
{
if ((nFlags & INestedArchive::FLAGS_FULL_VALIDATE) != 0)
{
initType = ZipDir::InitMethod::FullValidation;
}
else if ((nFlags & INestedArchive::FLAGS_VALIDATE_HEADERS) != 0)
{
initType = ZipDir::InitMethod::ValidateHeaders;
}
}
ZipDir::CacheFactory factory(initType, nFactoryFlags);
ZipDir::CachePtr cache = factory.New(szFullPath->c_str());
if (cache)
@@ -11,7 +11,9 @@
#include <AzCore/IO/Path/Path_fwd.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/intrusive_base.h>
#include <AzCore/std/string/string.h>
#include <AzFramework/Archive/Codec.h>
namespace AZ::IO
@@ -71,6 +73,13 @@ namespace AZ::IO
// multiple times
FLAGS_DONT_COMPACT = 1 << 5,
// if this is set, validate header data when opening the archive
FLAGS_VALIDATE_HEADERS = 1 << 9,
// if this is set, validate header data when opening the archive and validate CRCs when decompressing
// & reading files.
FLAGS_FULL_VALIDATE = 1 << 10,
// Disable a pak file without unloading it, this flag is used in combination with patches and multiplayer
// to ensure that specific paks stay in the position(to keep the same priority) but being disabled
// when running multiplayer
@@ -128,6 +137,10 @@ namespace AZ::IO
// Deletes all files and directories in the archive.
virtual int RemoveAll() = 0;
// Summary:
// Lists all the files in the archive.
virtual int ListAllFiles(AZStd::vector<AZ::IO::Path>& outFileEntries) = 0;
// Summary:
// Finds the file; you don't have to close the returned handle.
// Returns:
@@ -89,11 +89,51 @@ namespace AZ::IO
return m_pCache->RemoveDir(fullPath);
}
//////////////////////////////////////////////////////////////////////////
int NestedArchive::RemoveAll()
{
return m_pCache->RemoveAll();
}
//////////////////////////////////////////////////////////////////////////
// Helper for 'ListAllFiles' to recursively traverse the FileEntryTree and gather all the files
void EnumerateFilesRecursive(AZ::IO::Path currentPath, ZipDir::FileEntryTree* currentTree, AZStd::vector<AZ::IO::Path>& fileList)
{
// Drill down directories first...
for (auto dirIter = currentTree->GetDirBegin(); dirIter != currentTree->GetDirEnd(); ++dirIter)
{
if (ZipDir::FileEntryTree* subTree = currentTree->GetDirEntry(dirIter);
subTree != nullptr)
{
EnumerateFilesRecursive(currentPath / currentTree->GetDirName(dirIter), subTree, fileList);
}
}
// Then enumerate the files in current directory...
for (auto fileIter = currentTree->GetFileBegin(); fileIter != currentTree->GetFileEnd(); ++fileIter)
{
fileList.emplace_back(currentPath / currentTree->GetFileName(fileIter));
}
}
//////////////////////////////////////////////////////////////////////////
// lists all files in the archive
int NestedArchive::ListAllFiles(AZStd::vector<AZ::IO::Path>& outFileEntries)
{
AZStd::vector<AZ::IO::Path> filesInArchive;
ZipDir::FileEntryTree* tree = m_pCache->GetRoot();
if (!tree)
{
return ZipDir::ZD_ERROR_UNEXPECTED;
}
EnumerateFilesRecursive(AZ::IO::Path{ AZ::IO::PosixPathSeparator }, tree, filesInArchive);
AZStd::swap(outFileEntries, filesInArchive);
return ZipDir::ZD_ERROR_SUCCESS;
}
//////////////////////////////////////////////////////////////////////////
// Adds a new file to the zip or update an existing one
// adds a directory (creates several nested directories if needed)
@@ -39,7 +39,7 @@ namespace AZ::IO
NestedArchive(IArchive* pArchive, AZStd::string_view strBindRoot, ZipDir::CachePtr pCache, uint32_t nFlags = 0);
~NestedArchive() override;
auto GetRootFolderHandle() -> Handle override;
// Adds a new file to the zip or update an existing one
@@ -68,6 +68,9 @@ namespace AZ::IO
// deletes all files from the archive
int RemoveAll() override;
// lists all the files in the archive
int ListAllFiles(AZStd::vector<AZ::IO::Path>& outFileEntries) override;
// finds the file; you don't have to close the returned handle
Handle FindFile(AZStd::string_view szRelativePath) override;
@@ -79,7 +82,6 @@ namespace AZ::IO
// returns the full path to the archive file
AZ::IO::PathView GetFullPath() const override;
ZipDir::Cache* GetCache();
uint32_t GetFlags() const override;
bool SetFlags(uint32_t nFlagsToSet) override;
@@ -87,12 +89,15 @@ namespace AZ::IO
bool SetPackAccessible(bool bAccessible) override;
ZipDir::Cache* GetCache();
protected:
// returns the pointer to the relative file path to be passed
// to the underlying Cache pointer. Uses the given buffer to construct the path.
// returns nullptr if the file path is invalid
AZ::IO::FixedMaxPathString AdjustPath(AZStd::string_view szRelativePath);
ZipDir::CachePtr m_pCache;
// the binding root may be empty string - in this case, the absolute path binding won't work
AZ::IO::Path m_strBindRoot;
@@ -101,10 +101,11 @@ namespace AZ::IO::ZipDir
FileEntry* operator -> () { return m_pFileEntry; }
FileEntryTransactionAdd(Cache* pCache, AZStd::string_view szRelativePath)
: m_pCache(pCache)
, m_szRelativePath(AZ::IO::PosixPathSeparator)
, m_bCommitted(false)
{
// Update the cache string pool with the relative path to the file
auto pathIt = m_pCache->m_relativePathPool.emplace(AZ::IO::PathView(szRelativePath).LexicallyNormal());
auto pathIt = m_pCache->m_relativePathPool.emplace(AZ::IO::PathView(szRelativePath, AZ::IO::PosixPathSeparator).LexicallyNormal());
m_szRelativePath = *pathIt.first;
// this is the name of the directory - create it or find it
m_pFileEntry = m_pCache->GetRoot()->Add(m_szRelativePath.Native());
@@ -740,6 +741,16 @@ namespace AZ::IO::ZipDir
{
return ZD_ERROR_CORRUPTED_DATA;
}
if (pFileEntry->bCheckCRCNextRead)
{
pFileEntry->bCheckCRCNextRead = false;
uLong uCRC32 = AZ::Crc32((Bytef*)pUncompressed, nSizeUncompressed);
if (uCRC32 != pFileEntry->desc.lCRC32)
{
AZ_Warning("Archive", false, "ZD_ERROR_CRC32_CHECK: Uncompressed stream CRC32 check failed");
return ZD_ERROR_CRC32_CHECK;
}
}
}
}
@@ -18,6 +18,7 @@
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/smart_ptr/intrusive_base.h>
#include <AzFramework/Archive/Codec.h>
#include <AzFramework/Archive/ZipDirStructures.h>
@@ -29,7 +29,7 @@ namespace AZ::IO::ZipDir
// this sets the window size of the blocks of data read from the end of the file to find the Central Directory Record
// since normally there are no
static constexpr size_t CDRSearchWindowSize = 0x100;
CacheFactory::CacheFactory(InitMethodEnum nInitMethod, uint32_t nFlags)
CacheFactory::CacheFactory(InitMethod nInitMethod, uint32_t nFlags)
{
m_nCDREndPos = 0;
m_bBuildFileEntryMap = false; // we only need it for validation/debugging
@@ -448,7 +448,6 @@ namespace AZ::IO::ZipDir
// builds up the m_mapFileEntries
bool CacheFactory::BuildFileEntryMap()
{
Seek(m_CDREnd.lCDROffset);
if (m_CDREnd.lCDRSize == 0)
@@ -530,14 +529,6 @@ namespace AZ::IO::ZipDir
{
// Add this file entry.
char* str = reinterpret_cast<char*>(pFileName);
for (int i = 0; i < pFile->nFileNameLength; i++)
{
str[i] = std::tolower(str[i], std::locale());
if (str[i] == AZ_WRONG_FILESYSTEM_SEPARATOR)
{
str[i] = AZ_CORRECT_FILESYSTEM_SEPARATOR;
}
}
str[pFile->nFileNameLength] = 0; // Not standard!, may overwrite signature of the next memory record data in zip.
AddFileEntry(str, pFile, extra);
}
@@ -574,11 +565,7 @@ namespace AZ::IO::ZipDir
FileEntryBase fileEntry(*pFileHeader, extra);
// when using encrypted headers we should always initialize data offsets from CDR
if ((m_encryptedHeaders != ZipFile::HEADERS_NOT_ENCRYPTED || m_nInitMethod >= ZD_INIT_FULL) && pFileHeader->desc.lSizeCompressed)
{
InitDataOffset(fileEntry, pFileHeader);
}
InitDataOffset(fileEntry, pFileHeader);
if (m_bBuildFileEntryMap)
{
@@ -606,142 +593,81 @@ namespace AZ::IO::ZipDir
{
Seek(pFileHeader->lLocalHeaderOffset);
// read the local file header and the name (for validation) into the buffer
AZStd::vector<char>pBuffer;
uint32_t nBufferLength = sizeof(ZipFile::LocalFileHeader) + pFileHeader->nFileNameLength;
pBuffer.resize(nBufferLength);
Read(&pBuffer[0], nBufferLength);
// Read only the LocalFileHeader w/ no additional bytes ('name' or 'extra' fields)
AZStd::vector<char> buffer;
uint32_t bufferLen = sizeof(ZipFile::LocalFileHeader);
buffer.resize_no_construct(bufferLen);
Read(buffer.data(), bufferLen);
// validate the local file header (compare with the CDR file header - they should contain basically the same information)
const auto* pLocalFileHeader = reinterpret_cast<const ZipFile::LocalFileHeader*>(&pBuffer[0]);
if (pFileHeader->desc != pLocalFileHeader->desc
|| pFileHeader->nMethod != pLocalFileHeader->nMethod
|| pFileHeader->nFileNameLength != pLocalFileHeader->nFileNameLength
// for a tough validation, we can compare the timestamps of the local and central directory entries
// but we won't do that for backward compatibility with ZipDir
//|| pFileHeader->nLastModDate != pLocalFileHeader->nLastModDate
//|| pFileHeader->nLastModTime != pLocalFileHeader->nLastModTime
)
const auto* localFileHeader = reinterpret_cast<const ZipFile::LocalFileHeader*>(buffer.data());
// set the correct file data offset...
fileEntry.nFileDataOffset = pFileHeader->lLocalHeaderOffset + sizeof(ZipFile::LocalFileHeader) +
localFileHeader->nFileNameLength + localFileHeader->nExtraFieldLength;
fileEntry.nEOFOffset = fileEntry.nFileDataOffset + fileEntry.desc.lSizeCompressed;
if (m_nInitMethod != ZipDir::InitMethod::Default)
{
AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:"
" The local file header descriptor doesn't match the basic parameters declared in the global file header in the file."
" The archive content is misconsistent and may be damaged. Please try to repair the archive");
return;
if (m_nInitMethod == ZipDir::InitMethod::FullValidation)
{
// Mark the FileEntry to check CRC when the next read occurs
fileEntry.bCheckCRCNextRead = true;
}
// Timestamps
if (pFileHeader->nLastModDate != localFileHeader->nLastModDate
|| pFileHeader->nLastModTime != localFileHeader->nLastModTime)
{
AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n"
" The local file header's modification timestamps don't match that of the global file header in the archive."
" The archive timestamps are inconsistent and may be damaged. Check the archive file.", m_szFilename.c_str());
// don't return here, it may be ok.
}
// Validate data
if (pFileHeader->desc != localFileHeader->desc // this checks CRCs and compressed/uncompressed sizes
|| pFileHeader->nMethod != localFileHeader->nMethod
|| pFileHeader->nFileNameLength != localFileHeader->nFileNameLength)
{
AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n"
" The local file header descriptor doesn't match basic parameters declared in the global file header in the file."
" The archive content is inconsistent and may be damaged. Please try to repair the archive.", m_szFilename.c_str());
// return here because further checks aren't worse than this.
return;
}
// Read extra data
uint32_t extraDataLen = localFileHeader->nFileNameLength + localFileHeader->nExtraFieldLength;
buffer.resize_no_construct(buffer.size() + extraDataLen);
Read(buffer.data() + buffer.size(), extraDataLen);
// Compare local file name with the CDR file name, they should match
AZStd::string_view zipFileName{ buffer.data() + sizeof(ZipFile::LocalFileHeader), localFileHeader->nFileNameLength };
AZStd::string_view cdrFileName{ reinterpret_cast<const char*>(pFileHeader + 1), pFileHeader->nFileNameLength };
if (zipFileName != cdrFileName)
{
AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n"
" The file name in the local file header doesn't match the name in the global file header."
" The archive content is inconsisten with the directory. Please check the archive.", m_szFilename.c_str());
}
// CDR and local "extra field" lengths may be different, should we compare them if they are equal?
// make sure it's the same file and the fileEntry structure is properly initialized
AZ_Assert(fileEntry.nFileHeaderOffset == pFileHeader->lLocalHeaderOffset,
"The file entry header offset doesn't match the file header local offst (%s)", m_szFilename.c_str());
if (fileEntry.nFileDataOffset >= m_nCDREndPos)
{
AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n"
" The global file header declares the file which crosses the boundaries of the archive."
" The archive is either corrupted or truncated, please try to repair it", m_szFilename.c_str());
}
// End Validation
}
// now compare the local file name with the one recorded in CDR: they must match.
auto CompareNoCase = [](const char lhs, const char rhs) { return std::tolower(lhs, std::locale()) == std::tolower(rhs, std::locale()); };
auto zipFileDataBegin = pBuffer.begin() + sizeof(ZipFile::LocalFileHeader);
auto zipFileDataEnd = zipFileDataBegin + pFileHeader->nFileNameLength;
if (!AZStd::equal(zipFileDataBegin, zipFileDataEnd, reinterpret_cast<const char*>(pFileHeader + 1), CompareNoCase))
{
// either file name, or the extra field do not match
AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:"
" The local file header contains file name which does not match the file name of the global file header."
" The archive content is misconsistent with its directory. Please repair the archive");
return;
}
fileEntry.nFileDataOffset = pFileHeader->lLocalHeaderOffset + sizeof(ZipFile::LocalFileHeader) + pLocalFileHeader->nFileNameLength + pLocalFileHeader->nExtraFieldLength;
}
// make sure it's the same file and the fileEntry structure is properly initialized
AZ_Assert(fileEntry.nFileHeaderOffset == pFileHeader->lLocalHeaderOffset, "The file entry header offset doesn't match the file header local offst");
fileEntry.nEOFOffset = fileEntry.nFileDataOffset + fileEntry.desc.lSizeCompressed;
if (fileEntry.nFileDataOffset >= m_nCDREndPos)
{
AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:"
" The global file header declares the file which crosses the boundaries of the archive."
" The archive is either corrupted or truncated, please try to repair it");
return;
}
if (m_nInitMethod >= ZD_INIT_VALIDATE)
{
Validate(fileEntry);
}
}
//////////////////////////////////////////////////////////////////////////
// reads the file pointed by the given header and entry (they must be coherent)
// and decompresses it; then calculates and validates its CRC32
void CacheFactory::Validate(const FileEntryBase& fileEntry)
{
AZStd::vector<char> pBuffer;
// validate the file contents
// allocate memory for both the compressed data and uncompressed data
pBuffer.resize(fileEntry.desc.lSizeCompressed + fileEntry.desc.lSizeUncompressed);
char* pUncompressed = &pBuffer[fileEntry.desc.lSizeCompressed];
char* pCompressed = &pBuffer[0];
AZ_Assert(fileEntry.nFileDataOffset != FileEntry::INVALID_DATA_OFFSET, "File entry has invalid data offset of %" PRIx32, FileEntry::INVALID_DATA_OFFSET);
Seek(fileEntry.nFileDataOffset);
Read(pCompressed, fileEntry.desc.lSizeCompressed);
size_t nDestSize = fileEntry.desc.lSizeUncompressed;
int nError = Z_OK;
if (fileEntry.nMethod)
{
nError = ZipRawUncompress(pUncompressed, &nDestSize, pCompressed, fileEntry.desc.lSizeCompressed);
}
else
{
AZ_Assert(fileEntry.desc.lSizeCompressed == fileEntry.desc.lSizeUncompressed, "Uncompressed file does not have the same commpressed %u and uncompressed file sizes %u",
fileEntry.desc.lSizeCompressed, fileEntry.desc.lSizeUncompressed);
memcpy(pUncompressed, pCompressed, fileEntry.desc.lSizeUncompressed);
}
switch (nError)
{
case Z_OK:
break;
case Z_MEM_ERROR:
AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_NO_MEMORY: ZLib reported out-of-memory error");
return;
case Z_BUF_ERROR:
AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_CORRUPTED_DATA: ZLib reported compressed stream buffer error");
return;
case Z_DATA_ERROR:
AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_CORRUPTED_DATA: ZLib reported compressed stream data error");
return;
default:
AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_FAILED: ZLib reported an unexpected unknown error");
return;
}
if (nDestSize != fileEntry.desc.lSizeUncompressed)
{
AZ_Warning("Archive", false, "ZD_ERROR_CORRUPTED_DATA: Uncompressed stream doesn't match the size of uncompressed file stored in the archive file headers");
return;
}
uLong uCRC32 = AZ::Crc32((Bytef*)pUncompressed, nDestSize);
if (uCRC32 != fileEntry.desc.lCRC32)
{
AZ_Warning("Archive", false, "ZD_ERROR_CRC32_CHECK: Uncompressed stream CRC32 check failed");
return;
}
}
//////////////////////////////////////////////////////////////////////////
// extracts the file path from the file header with subsequent information
// may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not)
// it's the responsibility of the caller to ensure that the file name is in readable valid memory
char* CacheFactory::GetFilePath(const char* pFileName, uint16_t nFileNameLength)
{
static char strResult[AZ_MAX_PATH_LEN];
AZ_Assert(nFileNameLength < AZ_MAX_PATH_LEN, "Only filenames shorter than %zu can be copied from filename parameter", AZ_MAX_PATH_LEN);
memcpy(strResult, pFileName, nFileNameLength);
strResult[nFileNameLength] = 0;
for (int i = 0; i < nFileNameLength; i++)
{
strResult[i] = std::tolower(strResult[i], std::locale{});
}
return strResult;
}
// seeks in the file relative to the starting position
@@ -39,7 +39,7 @@ namespace AZ::IO::ZipDir
// initializes the internal structures
// nFlags can have FLAGS_READ_ONLY flag, in this case the object will be opened only for reading
CacheFactory(InitMethodEnum nInitMethod, uint32_t nFlags = 0);
CacheFactory(InitMethod nInitMethod, uint32_t nFlags = 0);
~CacheFactory();
// the new function creates a new cache
@@ -66,28 +66,6 @@ namespace AZ::IO::ZipDir
// This function can actually modify strFilePath variable, make sure you use a copy of the real path.
void AddFileEntry(char* strFilePath, const ZipFile::CDRFileHeader* pFileHeader, const SExtraZipFileData& extra);// throw (ErrorEnum);
// extracts the file path from the file header with subsequent information
// may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not)
// it's the responsibility of the caller to ensure that the file name is in readable valid memory
char* GetFilePath(const ZipFile::CDRFileHeader* pFileHeader)
{
return GetFilePath((const char*)(pFileHeader + 1), pFileHeader->nFileNameLength);
}
// extracts the file path from the file header with subsequent information
// may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not)
// it's the responsibility of the caller to ensure that the file name is in readable valid memory
char* GetFilePath(const ZipFile::LocalFileHeader* pFileHeader)
{
return GetFilePath((const char*)(pFileHeader + 1), pFileHeader->nFileNameLength);
}
// extracts the file path from the file header with subsequent information
// may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not)
// it's the responsibility of the caller to ensure that the file name is in readable valid memory
char* GetFilePath(const char* pFileName, uint16_t nFileNameLength);
// validates (if the init method has the corresponding value) the given file/header
void Validate(const FileEntryBase& fileEntry);
// initializes the actual data offset in the file in the fileEntry structure
// searches to the local file header, reads it and calculates the actual offset in the file
void InitDataOffset(FileEntryBase& fileEntry, const ZipFile::CDRFileHeader* pFileHeader);
@@ -104,7 +82,7 @@ namespace AZ::IO::ZipDir
AZStd::string m_szFilename;
CZipFile m_fileExt;
InitMethodEnum m_nInitMethod;
InitMethod m_nInitMethod;
uint32_t m_nFlags;
ZipFile::CDREnd m_CDREnd;
@@ -129,7 +107,7 @@ namespace AZ::IO::ZipDir
ZipFile::CryCustomEncryptionHeader m_headerEncryption;
ZipFile::CrySignedCDRHeader m_headerSignature;
ZipFile::CryCustomExtendedHeader m_headerExtended;
};
}
@@ -68,14 +68,14 @@ namespace AZ::IO::ZipDir
{
for (FileEntryTree::SubdirMap::iterator it = pTree->GetDirBegin(); it != pTree->GetDirEnd(); ++it)
{
AddAllFiles(it->second.get(), (AZ::IO::Path(strRoot) / it->first).Native());
AddAllFiles(it->second.get(), (AZ::IO::Path(strRoot, AZ::IO::PosixPathSeparator) / it->first).Native());
}
for (FileEntryTree::FileMap::iterator it = pTree->GetFileBegin(); it != pTree->GetFileEnd(); ++it)
{
FileRecord rec;
rec.pFileEntryBase = pTree->GetFileEntry(it);
rec.strPath = (AZ::IO::Path(strRoot) / it->first).Native();
rec.strPath = (AZ::IO::Path(strRoot, AZ::IO::PosixPathSeparator) / it->first).Native();
push_back(rec);
}
}
@@ -119,19 +119,28 @@ namespace AZ::IO::ZipDir
const char* m_szDescription;
};
#if defined(_RELEASE)
inline static constexpr bool IsReleaseConfig{ true };
#else
inline static constexpr bool IsReleaseConfig{};
#endif // _RELEASE
// possible initialization methods
enum InitMethodEnum
enum class InitMethod
{
// initialize as fast as possible, with minimal validation
ZD_INIT_FAST,
// after initialization, scan through all file headers, precache the actual file data offset values and validate the headers
ZD_INIT_FULL,
// scan all file headers and try to decompress the data, searching for corrupted files
ZD_INIT_VALIDATE_IN_MEMORY,
// store archive in memory
ZD_INIT_VALIDATE,
// maximum level of validation, checks for integrity of the archive
ZD_INIT_VALIDATE_MAX = ZD_INIT_VALIDATE
// initializes without any sort of extra validation steps
Default,
// initializes with extra validation steps
// not available in RELEASE
// will check CDR and local headers data match
ValidateHeaders,
// initializes with extra validation steps
// not available in RELEASE
// will check CDR and local headers data match
// will check file data CRC matches (when file is read)
FullValidation,
};
// Uncompresses raw (without wrapping) data that is compressed with method 8 (deflated) in the Zip file
@@ -184,7 +193,11 @@ namespace AZ::IO::ZipDir
// the offset to the start of the next file's header - this
// can be used to calculate the available space in zip file
uint32_t nEOFOffset{};
// whether to check the CRC upon the next data read
bool bCheckCRCNextRead{};
};
// this is the record about the file in the Zip file.
struct FileEntry
: FileEntryBase
@@ -8,7 +8,10 @@
#pragma once
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
namespace AZ
{
@@ -8,6 +8,7 @@
*/
#include <AzFramework/Asset/AssetSeedList.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AzFramework
{
@@ -8,7 +8,6 @@
*/
#pragma once
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzFramework/Platform/PlatformDefaults.h>
@@ -7,6 +7,7 @@
*/
#include <AzFramework/Asset/Benchmark/BenchmarkAsset.h>
#include <AzCore/Asset/AssetSerializer.h>
namespace AzFramework
{
@@ -7,6 +7,7 @@
*/
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Asset/SimpleAsset.h>
namespace AzFramework
@@ -36,4 +37,36 @@ namespace AzFramework
return "";
}
void SimpleAssetReferenceBase::Reflect(AZ::ReflectContext *context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<SimpleAssetReferenceBase>()
->Version(1)
->Field("AssetPath", &SimpleAssetReferenceBase::m_assetPath);
AZ::EditContext* edit = serializeContext->GetEditContext();
if (edit)
{
edit->Class<SimpleAssetReferenceBase>("Asset path", "Asset reference as a project-relative path")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
;
}
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<SimpleAssetReferenceBase>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Asset")
->Attribute(AZ::Script::Attributes::Module, "asset")
->Property("assetPath", &SimpleAssetReferenceBase::GetAssetPath, nullptr)
->Property("assetType", &SimpleAssetReferenceBase::GetAssetType, nullptr)
->Property("fileFilter", &SimpleAssetReferenceBase::GetFileFilter, nullptr)
->Method("SetAssetPath", &SimpleAssetReferenceBase::SetAssetPath)
->Attribute(AZ::Script::Attributes::Alias, "set_asset_path")
;
}
}
} // namespace AzFramework
@@ -42,7 +42,6 @@
*/
#include <AzCore/std/string/string.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Component/Component.h>
@@ -74,38 +73,7 @@ namespace AzFramework
virtual AZ::Data::AssetType GetAssetType() const = 0;
virtual const char* GetFileFilter() const = 0;
static void Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<SimpleAssetReferenceBase>()
->Version(1)
->Field("AssetPath", &SimpleAssetReferenceBase::m_assetPath);
AZ::EditContext* edit = serializeContext->GetEditContext();
if (edit)
{
edit->Class<SimpleAssetReferenceBase>("Asset path", "Asset reference as a project-relative path")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
;
}
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<SimpleAssetReferenceBase>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Asset")
->Attribute(AZ::Script::Attributes::Module, "asset")
->Property("assetPath", &SimpleAssetReferenceBase::GetAssetPath, nullptr)
->Property("assetType", &SimpleAssetReferenceBase::GetAssetType, nullptr)
->Property("fileFilter", &SimpleAssetReferenceBase::GetFileFilter, nullptr)
->Method("SetAssetPath", &SimpleAssetReferenceBase::SetAssetPath)
->Attribute(AZ::Script::Attributes::Alias, "set_asset_path")
;
}
}
static void Reflect(AZ::ReflectContext* context);
protected:
@@ -9,6 +9,7 @@
#pragma once
#include <AzCore/std/containers/vector.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/EditContext.h>
@@ -10,6 +10,11 @@
#include <AzCore/EBus/EBus.h>
namespace AZ
{
class Entity;
}
namespace AzFramework
{
using EntityContextId = AZ::Uuid;
@@ -91,15 +91,6 @@ namespace AzFramework
*/
virtual void DestroyGameEntity(const AZ::EntityId& /*id*/) = 0;
/**
* Destroys an entity only in slice mode (when prefabs are disabled). This request is only added as a stop-gap solution
* to prevent the editor from crashing when prefabs are enabled and must only be called through the BehaviorContext binding
* for 'DestroyGameEntity'. No code should be written to directly call this method. This will be removed soon.
*
* @param id The ID of the entity to destroy.
*/
virtual void DestroyGameEntityOnlyInSliceMode(const AZ::EntityId& /*id*/) = 0;
/**
* Destroys an entity and all of its descendants.
* The entity and its descendants are immediately deactivated and will be
@@ -108,15 +99,6 @@ namespace AzFramework
*/
virtual void DestroyGameEntityAndDescendants(const AZ::EntityId& /*id*/) = 0;
/**
* Destroys an entity and its descendants only in slice mode (when prefabs are disabled). This request is only added as a stop-gap
* solution to prevent the editor from crashing when prefabs are enabled and must only be called through the BehaviorContext
* binding for 'DestroyGameEntityAndDescendants'.No code should be written to directly call this method. This will be removed soon.
*
* @param id The ID of the entity to destroy.
*/
virtual void DestroyGameEntityAndDescendantsOnlyInSliceMode(const AZ::EntityId& /*id*/) = 0;
/**
* Activates the game entity.
* @param id The ID of the entity to activate.
@@ -11,9 +11,10 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/Entity/EntityContext.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
#include "GameEntityContextComponent.h"
@@ -47,9 +48,9 @@ namespace AzFramework
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Event("CreateGameEntity", &GameEntityContextRequestBus::Events::CreateGameEntityForBehaviorContext)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("DestroyGameEntity", &GameEntityContextRequestBus::Events::DestroyGameEntityOnlyInSliceMode)
->Event("DestroyGameEntity", &GameEntityContextRequestBus::Events::DestroyGameEntity)
->Event(
"DestroyGameEntityAndDescendants", &GameEntityContextRequestBus::Events::DestroyGameEntityAndDescendantsOnlyInSliceMode)
"DestroyGameEntityAndDescendants", &GameEntityContextRequestBus::Events::DestroyGameEntityAndDescendants)
->Event("ActivateGameEntity", &GameEntityContextRequestBus::Events::ActivateGameEntity)
->Event("DeactivateGameEntity", &GameEntityContextRequestBus::Events::DeactivateGameEntity)
->Attribute(AZ::ScriptCanvasAttributes::DeactivatesInputEntity, true)
@@ -249,23 +250,6 @@ namespace AzFramework
DestroyGameEntityInternal(id, false);
}
void GameEntityContextComponent::DestroyGameEntityOnlyInSliceMode(const AZ::EntityId& id)
{
bool isPrefabSystemEnabled = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!isPrefabSystemEnabled)
{
DestroyGameEntityInternal(id, false);
}
else
{
AZ_Error(
"GameEntityContextComponent", false,
"Destroying a game entity is temporarily disabled until the Spawnable system can support this.");
}
}
//=========================================================================
// GameEntityContextComponent::DestroyGameEntityAndDescendantsById
//=========================================================================
@@ -274,24 +258,6 @@ namespace AzFramework
DestroyGameEntityInternal(id, true);
}
void GameEntityContextComponent::DestroyGameEntityAndDescendantsOnlyInSliceMode(const AZ::EntityId& id)
{
bool isPrefabSystemEnabled = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (!isPrefabSystemEnabled)
{
DestroyGameEntityInternal(id, true);
}
else
{
AZ_Error(
"GameEntityContextComponent", false,
"Destroying a game entity and its descendants is temporarily disabled until the Spawnable system can support this.");
}
}
//=========================================================================
// GameEntityContextComponent::DestroyGameEntityInternal
//=========================================================================
@@ -319,6 +285,28 @@ namespace AzFramework
EBUS_EVENT_RESULT(currentEntity, AZ::ComponentApplicationBus, FindEntity, *entityIdIter);
if (currentEntity)
{
bool isPrefabSystemEnabled = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
if (isPrefabSystemEnabled)
{
if (currentEntity->GetSpawnTicketId() > 0)
{
SpawnableEntitiesDefinition* spawnableEntitiesInterface = SpawnableEntitiesInterface::Get();
AZ_Assert(spawnableEntitiesInterface != nullptr, "SpawnableEntitiesInterface is not found.");
spawnableEntitiesInterface->RetrieveEntitySpawnTicket(
currentEntity->GetSpawnTicketId(),
[spawnableEntitiesInterface, currentEntity](EntitySpawnTicket* entitySpawnTicket)
{
if (entitySpawnTicket != nullptr)
{
spawnableEntitiesInterface->DespawnEntity(currentEntity->GetId(), *entitySpawnTicket);
}
});
return;
}
}
if (currentEntity->GetState() == AZ::Entity::State::Active)
{
// Deactivate the entity, we'll destroy it as soon as it is safe.
@@ -90,11 +90,6 @@ namespace AzFramework
}
private:
//////////////////////////////////////////////////////////////////////////
// GameEntityContextRequestBus
void DestroyGameEntityOnlyInSliceMode(const AZ::EntityId&) override;
void DestroyGameEntityAndDescendantsOnlyInSliceMode(const AZ::EntityId&) override;
/////////////////////////////////////////////////////////////////////////
AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem;
};
@@ -28,34 +28,10 @@ namespace AzFramework
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputChannelId::InputChannelId(const char* name)
: m_crc32(name)
{
memset(m_name, 0, AZ_ARRAY_SIZE(m_name));
azstrncpy(m_name, NAME_BUFFER_SIZE, name, MAX_NAME_LENGTH);
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputChannelId::InputChannelId(const InputChannelId& other)
: m_crc32(other.m_crc32)
{
memset(m_name, 0, AZ_ARRAY_SIZE(m_name));
azstrcpy(m_name, NAME_BUFFER_SIZE, other.m_name);
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputChannelId& InputChannelId::operator=(const InputChannelId& other)
{
azstrcpy(m_name, NAME_BUFFER_SIZE, other.m_name);
m_crc32 = other.m_crc32;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////
const char* InputChannelId::GetName() const
{
return m_name;
return m_name.c_str();
}
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -11,6 +11,7 @@
#include <AzCore/Math/Crc.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/std/hash.h>
#include <AzCore/std/string/fixed_string.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework
@@ -22,8 +23,7 @@ namespace AzFramework
public:
////////////////////////////////////////////////////////////////////////////////////////////
// Constants
static const int NAME_BUFFER_SIZE = 64;
static const int MAX_NAME_LENGTH = NAME_BUFFER_SIZE - 1;
static constexpr int MAX_NAME_LENGTH = 64;
////////////////////////////////////////////////////////////////////////////////////////////
// Allocator
@@ -39,21 +39,28 @@ namespace AzFramework
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
//! \param[in] name Name of the input channel (will be truncated if exceeds MAX_NAME_LENGTH)
explicit InputChannelId(const char* name = "");
//! \param[in] name Name of the input channel (will be ignored if exceeds MAX_NAME_LENGTH)
explicit constexpr InputChannelId(AZStd::string_view name = "")
: m_name(name)
, m_crc32(name)
{
}
////////////////////////////////////////////////////////////////////////////////////////////
//! Copy constructor
//! \param[in] other Another instance of the class to copy from
InputChannelId(const InputChannelId& other);
////////////////////////////////////////////////////////////////////////////////////////////
//! Copy assignment operator
//! \param[in] other Another instance of the class to copy from
InputChannelId& operator=(const InputChannelId& other);
////////////////////////////////////////////////////////////////////////////////////////////
//! Default destructor
constexpr InputChannelId(const InputChannelId& other) = default;
constexpr InputChannelId(InputChannelId&& other) = default;
constexpr InputChannelId& operator=(const InputChannelId& other)
{
m_name = other.m_name;
m_crc32 = other.m_crc32;
return *this;
}
constexpr InputChannelId& operator=(InputChannelId&& other)
{
m_name = AZStd::move(other.m_name);
m_crc32 = AZStd::move(other.m_crc32);
other.m_crc32 = 0;
return *this;
}
~InputChannelId() = default;
////////////////////////////////////////////////////////////////////////////////////////////
@@ -77,7 +84,7 @@ namespace AzFramework
private:
////////////////////////////////////////////////////////////////////////////////////////////
// Variables
char m_name[NAME_BUFFER_SIZE]; //!< Name of the input channel
AZStd::fixed_string<MAX_NAME_LENGTH> m_name; //!< Name of the input channel
AZ::Crc32 m_crc32; //!< Crc32 of the input channel
};
} // namespace AzFramework
@@ -28,91 +28,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == IdForIndex0.GetNameCrc32());
}
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceGamepad::Button::A("gamepad_button_a");
const InputChannelId InputDeviceGamepad::Button::B("gamepad_button_b");
const InputChannelId InputDeviceGamepad::Button::X("gamepad_button_x");
const InputChannelId InputDeviceGamepad::Button::Y("gamepad_button_y");
const InputChannelId InputDeviceGamepad::Button::L1("gamepad_button_l1");
const InputChannelId InputDeviceGamepad::Button::R1("gamepad_button_r1");
const InputChannelId InputDeviceGamepad::Button::L3("gamepad_button_l3");
const InputChannelId InputDeviceGamepad::Button::R3("gamepad_button_r3");
const InputChannelId InputDeviceGamepad::Button::DU("gamepad_button_d_up");
const InputChannelId InputDeviceGamepad::Button::DD("gamepad_button_d_down");
const InputChannelId InputDeviceGamepad::Button::DL("gamepad_button_d_left");
const InputChannelId InputDeviceGamepad::Button::DR("gamepad_button_d_right");
const InputChannelId InputDeviceGamepad::Button::Start("gamepad_button_start");
const InputChannelId InputDeviceGamepad::Button::Select("gamepad_button_select");
const AZStd::array<InputChannelId, 14> InputDeviceGamepad::Button::All =
{{
A,
B,
X,
Y,
L1,
R1,
L3,
R3,
DU,
DD,
DL,
DR,
Start,
Select
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceGamepad::Trigger::L2("gamepad_trigger_l2");
const InputChannelId InputDeviceGamepad::Trigger::R2("gamepad_trigger_r2");
const AZStd::array<InputChannelId, 2> InputDeviceGamepad::Trigger::All =
{{
L2,
R2
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceGamepad::ThumbStickAxis2D::L("gamepad_thumbstick_l");
const InputChannelId InputDeviceGamepad::ThumbStickAxis2D::R("gamepad_thumbstick_r");
const AZStd::array<InputChannelId, 2> InputDeviceGamepad::ThumbStickAxis2D::All =
{{
L,
R
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::LX("gamepad_thumbstick_l_x");
const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::LY("gamepad_thumbstick_l_y");
const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::RX("gamepad_thumbstick_r_x");
const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::RY("gamepad_thumbstick_r_y");
const AZStd::array<InputChannelId, 4> InputDeviceGamepad::ThumbStickAxis1D::All =
{{
LX,
LY,
RX,
RY
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceGamepad::ThumbStickDirection::LU("gamepad_thumbstick_l_up");
const InputChannelId InputDeviceGamepad::ThumbStickDirection::LD("gamepad_thumbstick_l_down");
const InputChannelId InputDeviceGamepad::ThumbStickDirection::LL("gamepad_thumbstick_l_left");
const InputChannelId InputDeviceGamepad::ThumbStickDirection::LR("gamepad_thumbstick_l_right");
const InputChannelId InputDeviceGamepad::ThumbStickDirection::RU("gamepad_thumbstick_r_up");
const InputChannelId InputDeviceGamepad::ThumbStickDirection::RD("gamepad_thumbstick_r_down");
const InputChannelId InputDeviceGamepad::ThumbStickDirection::RL("gamepad_thumbstick_r_left");
const InputChannelId InputDeviceGamepad::ThumbStickDirection::RR("gamepad_thumbstick_r_right");
const AZStd::array<InputChannelId, 8> InputDeviceGamepad::ThumbStickDirection::All =
{{
LU,
LD,
LL,
LR,
RU,
RD,
RL,
RR
}};
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceGamepad::Reflect(AZ::ReflectContext* context)
{
@@ -59,75 +59,115 @@ namespace AzFramework
//! All the input channel ids that identify game-pad digital button input
struct Button
{
static const InputChannelId A; //!< The bottom diamond face button
static const InputChannelId B; //!< The right diamond face button
static const InputChannelId X; //!< The left diamond face button
static const InputChannelId Y; //!< The top diamond face button
static const InputChannelId L1; //!< The top-left shoulder bumper button
static const InputChannelId R1; //!< The top-right shoulder bumper button
static const InputChannelId L3; //!< The left thumb-stick click button
static const InputChannelId R3; //!< The right thumb-stick click button
static const InputChannelId DU; //!< The up directional pad button
static const InputChannelId DD; //!< The down directional pad button
static const InputChannelId DL; //!< The left directional pad button
static const InputChannelId DR; //!< The right directional pad button
static const InputChannelId Start; //!< The start/pause/options button
static const InputChannelId Select; //!< The select/back button
static constexpr inline InputChannelId A{"gamepad_button_a"}; //!< The bottom diamond face button
static constexpr inline InputChannelId B{"gamepad_button_b"}; //!< The right diamond face button
static constexpr inline InputChannelId X{"gamepad_button_x"}; //!< The left diamond face button
static constexpr inline InputChannelId Y{"gamepad_button_y"}; //!< The top diamond face button
static constexpr inline InputChannelId L1{"gamepad_button_l1"}; //!< The top-left shoulder bumper button
static constexpr inline InputChannelId R1{"gamepad_button_r1"}; //!< The top-right shoulder bumper button
static constexpr inline InputChannelId L3{"gamepad_button_l3"}; //!< The left thumb-stick click button
static constexpr inline InputChannelId R3{"gamepad_button_r3"}; //!< The right thumb-stick click button
static constexpr inline InputChannelId DU{"gamepad_button_d_up"}; //!< The up directional pad button
static constexpr inline InputChannelId DD{"gamepad_button_d_down"}; //!< The down directional pad button
static constexpr inline InputChannelId DL{"gamepad_button_d_left"}; //!< The left directional pad button
static constexpr inline InputChannelId DR{"gamepad_button_d_right"}; //!< The right directional pad button
static constexpr inline InputChannelId Start{"gamepad_button_start"}; //!< The start/pause/options button
static constexpr inline InputChannelId Select{"gamepad_button_select"}; //!< The select/back button
//!< All digital game-pad button ids
static const AZStd::array<InputChannelId, 14> All;
static constexpr inline AZStd::array All
{
A,
B,
X,
Y,
L1,
R1,
L3,
R3,
DU,
DD,
DL,
DR,
Start,
Select
};
};
////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad analog trigger input
struct Trigger
{
static const InputChannelId L2; //!< The bottom-left shoulder trigger
static const InputChannelId R2; //!< The bottom-right shoulder trigger
static constexpr inline InputChannelId L2{"gamepad_trigger_l2"}; //!< The bottom-left shoulder trigger
static constexpr inline InputChannelId R2{"gamepad_trigger_r2"}; //!< The bottom-right shoulder trigger
//!< All analog game-pad trigger ids
static const AZStd::array<InputChannelId, 2> All;
static constexpr inline AZStd::array All
{
L2,
R2
};
};
////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick 2D axis input
struct ThumbStickAxis2D
{
static const InputChannelId L; //!< The left-hand thumb-stick
static const InputChannelId R; //!< The right-hand thumb-stick
static constexpr inline InputChannelId L{"gamepad_thumbstick_l"}; //!< The left-hand thumb-stick
static constexpr inline InputChannelId R{"gamepad_thumbstick_r"}; //!< The right-hand thumb-stick
//!< All game-pad thumb-stick 2D axis input channel ids
static const AZStd::array<InputChannelId, 2> All;
static constexpr inline AZStd::array All
{
L,
R
};
};
////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick 1D axis input
struct ThumbStickAxis1D
{
static const InputChannelId LX; //!< X-axis of the left-hand thumb-stick
static const InputChannelId LY; //!< Y-axis of the left-hand thumb-stick
static const InputChannelId RX; //!< X-axis of the right-hand thumb-stick
static const InputChannelId RY; //!< Y-axis of the right-hand thumb-stick
static constexpr inline InputChannelId LX{"gamepad_thumbstick_l_x"}; //!< X-axis of the left-hand thumb-stick
static constexpr inline InputChannelId LY{"gamepad_thumbstick_l_y"}; //!< Y-axis of the left-hand thumb-stick
static constexpr inline InputChannelId RX{"gamepad_thumbstick_r_x"}; //!< X-axis of the right-hand thumb-stick
static constexpr inline InputChannelId RY{"gamepad_thumbstick_r_y"}; //!< Y-axis of the right-hand thumb-stick
//!< All game-pad thumb-stick 1D axis input channel ids
static const AZStd::array<InputChannelId, 4> All;
static constexpr inline AZStd::array All
{
LX,
LY,
RX,
RY
};
};
////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick directional input
struct ThumbStickDirection
{
static const InputChannelId LU; //!< Up on the left-hand thumb-stick
static const InputChannelId LD; //!< Down on the left-hand thumb-stick
static const InputChannelId LL; //!< Left on the left-hand thumb-stick
static const InputChannelId LR; //!< Right on the left-hand thumb-stick
static const InputChannelId RU; //!< Up on the left-hand thumb-stick
static const InputChannelId RD; //!< Down on the left-hand thumb-stick
static const InputChannelId RL; //!< Left on the left-hand thumb-stick
static const InputChannelId RR; //!< Right on the left-hand thumb-stick
static constexpr inline InputChannelId LU{"gamepad_thumbstick_l_up"}; //!< Up on the left-hand thumb-stick
static constexpr inline InputChannelId LD{"gamepad_thumbstick_l_down"}; //!< Down on the left-hand thumb-stick
static constexpr inline InputChannelId LL{"gamepad_thumbstick_l_left"}; //!< Left on the left-hand thumb-stick
static constexpr inline InputChannelId LR{"gamepad_thumbstick_l_right"}; //!< Right on the left-hand thumb-stick
static constexpr inline InputChannelId RU{"gamepad_thumbstick_r_up"}; //!< Up on the left-hand thumb-stick
static constexpr inline InputChannelId RD{"gamepad_thumbstick_r_down"}; //!< Down on the left-hand thumb-stick
static constexpr inline InputChannelId RL{"gamepad_thumbstick_r_left"}; //!< Left on the left-hand thumb-stick
static constexpr inline InputChannelId RR{"gamepad_thumbstick_r_right"}; //!< Right on the left-hand thumb-stick
//!< All game-pad thumb-stick directional input channel ids
static const AZStd::array<InputChannelId, 8> All;
static constexpr inline AZStd::array All
{
LU,
LD,
LL,
LR,
RU,
RD,
RL,
RR
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -24,279 +24,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Alphanumeric Keys
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric0("keyboard_key_alphanumeric_0");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric1("keyboard_key_alphanumeric_1");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric2("keyboard_key_alphanumeric_2");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric3("keyboard_key_alphanumeric_3");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric4("keyboard_key_alphanumeric_4");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric5("keyboard_key_alphanumeric_5");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric6("keyboard_key_alphanumeric_6");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric7("keyboard_key_alphanumeric_7");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric8("keyboard_key_alphanumeric_8");
const InputChannelId InputDeviceKeyboard::Key::Alphanumeric9("keyboard_key_alphanumeric_9");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericA("keyboard_key_alphanumeric_A");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericB("keyboard_key_alphanumeric_B");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericC("keyboard_key_alphanumeric_C");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericD("keyboard_key_alphanumeric_D");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericE("keyboard_key_alphanumeric_E");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericF("keyboard_key_alphanumeric_F");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericG("keyboard_key_alphanumeric_G");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericH("keyboard_key_alphanumeric_H");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericI("keyboard_key_alphanumeric_I");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericJ("keyboard_key_alphanumeric_J");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericK("keyboard_key_alphanumeric_K");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericL("keyboard_key_alphanumeric_L");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericM("keyboard_key_alphanumeric_M");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericN("keyboard_key_alphanumeric_N");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericO("keyboard_key_alphanumeric_O");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericP("keyboard_key_alphanumeric_P");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericQ("keyboard_key_alphanumeric_Q");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericR("keyboard_key_alphanumeric_R");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericS("keyboard_key_alphanumeric_S");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericT("keyboard_key_alphanumeric_T");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericU("keyboard_key_alphanumeric_U");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericV("keyboard_key_alphanumeric_V");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericW("keyboard_key_alphanumeric_W");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericX("keyboard_key_alphanumeric_X");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericY("keyboard_key_alphanumeric_Y");
const InputChannelId InputDeviceKeyboard::Key::AlphanumericZ("keyboard_key_alphanumeric_Z");
////////////////////////////////////////////////////////////////////////////////////////////////
// Edit (and escape) Keys
const InputChannelId InputDeviceKeyboard::Key::EditBackspace("keyboard_key_edit_backspace");
const InputChannelId InputDeviceKeyboard::Key::EditCapsLock("keyboard_key_edit_capslock");
const InputChannelId InputDeviceKeyboard::Key::EditEnter("keyboard_key_edit_enter");
const InputChannelId InputDeviceKeyboard::Key::EditSpace("keyboard_key_edit_space");
const InputChannelId InputDeviceKeyboard::Key::EditTab("keyboard_key_edit_tab");
const InputChannelId InputDeviceKeyboard::Key::Escape("keyboard_key_escape");
////////////////////////////////////////////////////////////////////////////////////////////////
// Function Keys
const InputChannelId InputDeviceKeyboard::Key::Function01("keyboard_key_function_F01");
const InputChannelId InputDeviceKeyboard::Key::Function02("keyboard_key_function_F02");
const InputChannelId InputDeviceKeyboard::Key::Function03("keyboard_key_function_F03");
const InputChannelId InputDeviceKeyboard::Key::Function04("keyboard_key_function_F04");
const InputChannelId InputDeviceKeyboard::Key::Function05("keyboard_key_function_F05");
const InputChannelId InputDeviceKeyboard::Key::Function06("keyboard_key_function_F06");
const InputChannelId InputDeviceKeyboard::Key::Function07("keyboard_key_function_F07");
const InputChannelId InputDeviceKeyboard::Key::Function08("keyboard_key_function_F08");
const InputChannelId InputDeviceKeyboard::Key::Function09("keyboard_key_function_F09");
const InputChannelId InputDeviceKeyboard::Key::Function10("keyboard_key_function_F10");
const InputChannelId InputDeviceKeyboard::Key::Function11("keyboard_key_function_F11");
const InputChannelId InputDeviceKeyboard::Key::Function12("keyboard_key_function_F12");
const InputChannelId InputDeviceKeyboard::Key::Function13("keyboard_key_function_F13");
const InputChannelId InputDeviceKeyboard::Key::Function14("keyboard_key_function_F14");
const InputChannelId InputDeviceKeyboard::Key::Function15("keyboard_key_function_F15");
const InputChannelId InputDeviceKeyboard::Key::Function16("keyboard_key_function_F16");
const InputChannelId InputDeviceKeyboard::Key::Function17("keyboard_key_function_F17");
const InputChannelId InputDeviceKeyboard::Key::Function18("keyboard_key_function_F18");
const InputChannelId InputDeviceKeyboard::Key::Function19("keyboard_key_function_F19");
const InputChannelId InputDeviceKeyboard::Key::Function20("keyboard_key_function_F20");
////////////////////////////////////////////////////////////////////////////////////////////////
// Modifier Keys
const InputChannelId InputDeviceKeyboard::Key::ModifierAltL("keyboard_key_modifier_alt_l");
const InputChannelId InputDeviceKeyboard::Key::ModifierAltR("keyboard_key_modifier_alt_r");
const InputChannelId InputDeviceKeyboard::Key::ModifierCtrlL("keyboard_key_modifier_ctrl_l");
const InputChannelId InputDeviceKeyboard::Key::ModifierCtrlR("keyboard_key_modifier_ctrl_r");
const InputChannelId InputDeviceKeyboard::Key::ModifierShiftL("keyboard_key_modifier_shift_l");
const InputChannelId InputDeviceKeyboard::Key::ModifierShiftR("keyboard_key_modifier_shift_r");
const InputChannelId InputDeviceKeyboard::Key::ModifierSuperL("keyboard_key_modifier_super_l");
const InputChannelId InputDeviceKeyboard::Key::ModifierSuperR("keyboard_key_modifier_super_r");
////////////////////////////////////////////////////////////////////////////////////////////////
// Navigation Keys
const InputChannelId InputDeviceKeyboard::Key::NavigationArrowDown("keyboard_key_navigation_arrow_down");
const InputChannelId InputDeviceKeyboard::Key::NavigationArrowLeft("keyboard_key_navigation_arrow_left");
const InputChannelId InputDeviceKeyboard::Key::NavigationArrowRight("keyboard_key_navigation_arrow_right");
const InputChannelId InputDeviceKeyboard::Key::NavigationArrowUp("keyboard_key_navigation_arrow_up");
const InputChannelId InputDeviceKeyboard::Key::NavigationDelete("keyboard_key_navigation_delete");
const InputChannelId InputDeviceKeyboard::Key::NavigationEnd("keyboard_key_navigation_end");
const InputChannelId InputDeviceKeyboard::Key::NavigationHome("keyboard_key_navigation_home");
const InputChannelId InputDeviceKeyboard::Key::NavigationInsert("keyboard_key_navigation_insert");
const InputChannelId InputDeviceKeyboard::Key::NavigationPageDown("keyboard_key_navigation_page_down");
const InputChannelId InputDeviceKeyboard::Key::NavigationPageUp("keyboard_key_navigation_page_up");
////////////////////////////////////////////////////////////////////////////////////////////////
// Numpad Keys
const InputChannelId InputDeviceKeyboard::Key::NumLock("keyboard_key_num_lock");
const InputChannelId InputDeviceKeyboard::Key::NumPad0("keyboard_key_numpad_0");
const InputChannelId InputDeviceKeyboard::Key::NumPad1("keyboard_key_numpad_1");
const InputChannelId InputDeviceKeyboard::Key::NumPad2("keyboard_key_numpad_2");
const InputChannelId InputDeviceKeyboard::Key::NumPad3("keyboard_key_numpad_3");
const InputChannelId InputDeviceKeyboard::Key::NumPad4("keyboard_key_numpad_4");
const InputChannelId InputDeviceKeyboard::Key::NumPad5("keyboard_key_numpad_5");
const InputChannelId InputDeviceKeyboard::Key::NumPad6("keyboard_key_numpad_6");
const InputChannelId InputDeviceKeyboard::Key::NumPad7("keyboard_key_numpad_7");
const InputChannelId InputDeviceKeyboard::Key::NumPad8("keyboard_key_numpad_8");
const InputChannelId InputDeviceKeyboard::Key::NumPad9("keyboard_key_numpad_9");
const InputChannelId InputDeviceKeyboard::Key::NumPadAdd("keyboard_key_numpad_add");
const InputChannelId InputDeviceKeyboard::Key::NumPadDecimal("keyboard_key_numpad_decimal");
const InputChannelId InputDeviceKeyboard::Key::NumPadDivide("keyboard_key_numpad_divide");
const InputChannelId InputDeviceKeyboard::Key::NumPadEnter("keyboard_key_numpad_enter");
const InputChannelId InputDeviceKeyboard::Key::NumPadMultiply("keyboard_key_numpad_multiply");
const InputChannelId InputDeviceKeyboard::Key::NumPadSubtract("keyboard_key_numpad_subtract");
////////////////////////////////////////////////////////////////////////////////////////////////
// Punctuation Keys
const InputChannelId InputDeviceKeyboard::Key::PunctuationApostrophe("keyboard_key_punctuation_apostrophe");
const InputChannelId InputDeviceKeyboard::Key::PunctuationBackslash("keyboard_key_punctuation_backslash");
const InputChannelId InputDeviceKeyboard::Key::PunctuationBracketL("keyboard_key_punctuation_bracket_l");
const InputChannelId InputDeviceKeyboard::Key::PunctuationBracketR("keyboard_key_punctuation_bracket_r");
const InputChannelId InputDeviceKeyboard::Key::PunctuationComma("keyboard_key_punctuation_comma");
const InputChannelId InputDeviceKeyboard::Key::PunctuationEquals("keyboard_key_punctuation_equals");
const InputChannelId InputDeviceKeyboard::Key::PunctuationHyphen("keyboard_key_punctuation_hyphen");
const InputChannelId InputDeviceKeyboard::Key::PunctuationPeriod("keyboard_key_punctuation_period");
const InputChannelId InputDeviceKeyboard::Key::PunctuationSemicolon("keyboard_key_punctuation_semicolon");
const InputChannelId InputDeviceKeyboard::Key::PunctuationSlash("keyboard_key_punctuation_slash");
const InputChannelId InputDeviceKeyboard::Key::PunctuationTilde("keyboard_key_punctuation_tilde");
////////////////////////////////////////////////////////////////////////////////////////////////
// Supplementary ISO Key
const InputChannelId InputDeviceKeyboard::Key::SupplementaryISO("keyboard_key_supplementary_iso");
////////////////////////////////////////////////////////////////////////////////////////////////
// Windows System Keys
const InputChannelId InputDeviceKeyboard::Key::WindowsSystemPause("keyboard_key_windows_system_pause");
const InputChannelId InputDeviceKeyboard::Key::WindowsSystemPrint("keyboard_key_windows_system_print");
const InputChannelId InputDeviceKeyboard::Key::WindowsSystemScrollLock("keyboard_key_windows_system_scroll_lock");
////////////////////////////////////////////////////////////////////////////////////////////////
const AZStd::array<InputChannelId, 112> InputDeviceKeyboard::Key::All =
{{
// Alphanumeric Keys
Alphanumeric0,
Alphanumeric1,
Alphanumeric2,
Alphanumeric3,
Alphanumeric4,
Alphanumeric5,
Alphanumeric6,
Alphanumeric7,
Alphanumeric8,
Alphanumeric9,
AlphanumericA,
AlphanumericB,
AlphanumericC,
AlphanumericD,
AlphanumericE,
AlphanumericF,
AlphanumericG,
AlphanumericH,
AlphanumericI,
AlphanumericJ,
AlphanumericK,
AlphanumericL,
AlphanumericM,
AlphanumericN,
AlphanumericO,
AlphanumericP,
AlphanumericQ,
AlphanumericR,
AlphanumericS,
AlphanumericT,
AlphanumericU,
AlphanumericV,
AlphanumericW,
AlphanumericX,
AlphanumericY,
AlphanumericZ,
// Edit (and escape) Keys
EditBackspace,
EditCapsLock,
EditEnter,
EditSpace,
EditTab,
Escape,
// Function Keys
Function01,
Function02,
Function03,
Function04,
Function05,
Function06,
Function07,
Function08,
Function09,
Function10,
Function11,
Function12,
Function13,
Function14,
Function15,
Function16,
Function17,
Function18,
Function19,
Function20,
// Modifier Keys
ModifierAltL,
ModifierAltR,
ModifierCtrlL,
ModifierCtrlR,
ModifierShiftL,
ModifierShiftR,
ModifierSuperL,
ModifierSuperR,
// Navigation Keys
NavigationArrowDown,
NavigationArrowLeft,
NavigationArrowRight,
NavigationArrowUp,
NavigationDelete,
NavigationEnd,
NavigationHome,
NavigationInsert,
NavigationPageDown,
NavigationPageUp,
// Numpad Keys
NumLock,
NumPad0,
NumPad1,
NumPad2,
NumPad3,
NumPad4,
NumPad5,
NumPad6,
NumPad7,
NumPad8,
NumPad9,
NumPadAdd,
NumPadDecimal,
NumPadDivide,
NumPadEnter,
NumPadMultiply,
NumPadSubtract,
// Punctuation Keys
PunctuationApostrophe,
PunctuationBackslash,
PunctuationBracketL,
PunctuationBracketR,
PunctuationComma,
PunctuationEquals,
PunctuationHyphen,
PunctuationPeriod,
PunctuationSemicolon,
PunctuationSlash,
PunctuationTilde,
// Supplementary ISO Key
SupplementaryISO,
// Windows System Keys
WindowsSystemPause,
WindowsSystemPrint,
WindowsSystemScrollLock
}};
////////////////////////////////////////////////////////////////////////////////////////////////
ModifierKeyMask GetCorrespondingModifierKeyMask(const InputChannelId& channelId)
{
@@ -94,137 +94,268 @@ namespace AzFramework
struct Key
{
// Alphanumeric Keys
static const InputChannelId Alphanumeric0; //!< The 0 key
static const InputChannelId Alphanumeric1; //!< The 1 key
static const InputChannelId Alphanumeric2; //!< The 2 key
static const InputChannelId Alphanumeric3; //!< The 3 key
static const InputChannelId Alphanumeric4; //!< The 4 key
static const InputChannelId Alphanumeric5; //!< The 5 key
static const InputChannelId Alphanumeric6; //!< The 6 key
static const InputChannelId Alphanumeric7; //!< The 7 key
static const InputChannelId Alphanumeric8; //!< The 8 key
static const InputChannelId Alphanumeric9; //!< The 9 key
static const InputChannelId AlphanumericA; //!< The A key
static const InputChannelId AlphanumericB; //!< The B key
static const InputChannelId AlphanumericC; //!< The C key
static const InputChannelId AlphanumericD; //!< The D key
static const InputChannelId AlphanumericE; //!< The E key
static const InputChannelId AlphanumericF; //!< The F key
static const InputChannelId AlphanumericG; //!< The G key
static const InputChannelId AlphanumericH; //!< The H key
static const InputChannelId AlphanumericI; //!< The I key
static const InputChannelId AlphanumericJ; //!< The J key
static const InputChannelId AlphanumericK; //!< The K key
static const InputChannelId AlphanumericL; //!< The L key
static const InputChannelId AlphanumericM; //!< The M key
static const InputChannelId AlphanumericN; //!< The N key
static const InputChannelId AlphanumericO; //!< The O key
static const InputChannelId AlphanumericP; //!< The P key
static const InputChannelId AlphanumericQ; //!< The Q key
static const InputChannelId AlphanumericR; //!< The R key
static const InputChannelId AlphanumericS; //!< The S key
static const InputChannelId AlphanumericT; //!< The T key
static const InputChannelId AlphanumericU; //!< The U key
static const InputChannelId AlphanumericV; //!< The V key
static const InputChannelId AlphanumericW; //!< The W key
static const InputChannelId AlphanumericX; //!< The X key
static const InputChannelId AlphanumericY; //!< The Y key
static const InputChannelId AlphanumericZ; //!< The Z key
static constexpr inline InputChannelId Alphanumeric0{"keyboard_key_alphanumeric_0"}; //!< The 0 key
static constexpr inline InputChannelId Alphanumeric1{"keyboard_key_alphanumeric_1"}; //!< The 1 key
static constexpr inline InputChannelId Alphanumeric2{"keyboard_key_alphanumeric_2"}; //!< The 2 key
static constexpr inline InputChannelId Alphanumeric3{"keyboard_key_alphanumeric_3"}; //!< The 3 key
static constexpr inline InputChannelId Alphanumeric4{"keyboard_key_alphanumeric_4"}; //!< The 4 key
static constexpr inline InputChannelId Alphanumeric5{"keyboard_key_alphanumeric_5"}; //!< The 5 key
static constexpr inline InputChannelId Alphanumeric6{"keyboard_key_alphanumeric_6"}; //!< The 6 key
static constexpr inline InputChannelId Alphanumeric7{"keyboard_key_alphanumeric_7"}; //!< The 7 key
static constexpr inline InputChannelId Alphanumeric8{"keyboard_key_alphanumeric_8"}; //!< The 8 key
static constexpr inline InputChannelId Alphanumeric9{"keyboard_key_alphanumeric_9"}; //!< The 9 key
static constexpr inline InputChannelId AlphanumericA{"keyboard_key_alphanumeric_A"}; //!< The A key
static constexpr inline InputChannelId AlphanumericB{"keyboard_key_alphanumeric_B"}; //!< The B key
static constexpr inline InputChannelId AlphanumericC{"keyboard_key_alphanumeric_C"}; //!< The C key
static constexpr inline InputChannelId AlphanumericD{"keyboard_key_alphanumeric_D"}; //!< The D key
static constexpr inline InputChannelId AlphanumericE{"keyboard_key_alphanumeric_E"}; //!< The E key
static constexpr inline InputChannelId AlphanumericF{"keyboard_key_alphanumeric_F"}; //!< The F key
static constexpr inline InputChannelId AlphanumericG{"keyboard_key_alphanumeric_G"}; //!< The G key
static constexpr inline InputChannelId AlphanumericH{"keyboard_key_alphanumeric_H"}; //!< The H key
static constexpr inline InputChannelId AlphanumericI{"keyboard_key_alphanumeric_I"}; //!< The I key
static constexpr inline InputChannelId AlphanumericJ{"keyboard_key_alphanumeric_J"}; //!< The J key
static constexpr inline InputChannelId AlphanumericK{"keyboard_key_alphanumeric_K"}; //!< The K key
static constexpr inline InputChannelId AlphanumericL{"keyboard_key_alphanumeric_L"}; //!< The L key
static constexpr inline InputChannelId AlphanumericM{"keyboard_key_alphanumeric_M"}; //!< The M key
static constexpr inline InputChannelId AlphanumericN{"keyboard_key_alphanumeric_N"}; //!< The N key
static constexpr inline InputChannelId AlphanumericO{"keyboard_key_alphanumeric_O"}; //!< The O key
static constexpr inline InputChannelId AlphanumericP{"keyboard_key_alphanumeric_P"}; //!< The P key
static constexpr inline InputChannelId AlphanumericQ{"keyboard_key_alphanumeric_Q"}; //!< The Q key
static constexpr inline InputChannelId AlphanumericR{"keyboard_key_alphanumeric_R"}; //!< The R key
static constexpr inline InputChannelId AlphanumericS{"keyboard_key_alphanumeric_S"}; //!< The S key
static constexpr inline InputChannelId AlphanumericT{"keyboard_key_alphanumeric_T"}; //!< The T key
static constexpr inline InputChannelId AlphanumericU{"keyboard_key_alphanumeric_U"}; //!< The U key
static constexpr inline InputChannelId AlphanumericV{"keyboard_key_alphanumeric_V"}; //!< The V key
static constexpr inline InputChannelId AlphanumericW{"keyboard_key_alphanumeric_W"}; //!< The W key
static constexpr inline InputChannelId AlphanumericX{"keyboard_key_alphanumeric_X"}; //!< The X key
static constexpr inline InputChannelId AlphanumericY{"keyboard_key_alphanumeric_Y"}; //!< The Y key
static constexpr inline InputChannelId AlphanumericZ{"keyboard_key_alphanumeric_Z"}; //!< The Z key
// Edit (and escape) Keys
static const InputChannelId EditBackspace; //!< The backspace key
static const InputChannelId EditCapsLock; //!< The caps lock key
static const InputChannelId EditEnter; //!< The enter/return key
static const InputChannelId EditSpace; //!< The spacebar key
static const InputChannelId EditTab; //!< The tab key
static const InputChannelId Escape; //!< The escape key
// Edit {and escape} Keys
static constexpr inline InputChannelId EditBackspace{"keyboard_key_edit_backspace"}; //!< The backspace key
static constexpr inline InputChannelId EditCapsLock{"keyboard_key_edit_capslock"}; //!< The caps lock key
static constexpr inline InputChannelId EditEnter{"keyboard_key_edit_enter"}; //!< The enter/return key
static constexpr inline InputChannelId EditSpace{"keyboard_key_edit_space"}; //!< The spacebar key
static constexpr inline InputChannelId EditTab{"keyboard_key_edit_tab"}; //!< The tab key
static constexpr inline InputChannelId Escape{"keyboard_key_escape"}; //!< The escape key
// Function Keys
static const InputChannelId Function01; //!< The F1 key
static const InputChannelId Function02; //!< The F2 key
static const InputChannelId Function03; //!< The F3 key
static const InputChannelId Function04; //!< The F4 key
static const InputChannelId Function05; //!< The F5 key
static const InputChannelId Function06; //!< The F6 key
static const InputChannelId Function07; //!< The F7 key
static const InputChannelId Function08; //!< The F8 key
static const InputChannelId Function09; //!< The F9 key
static const InputChannelId Function10; //!< The F10 key
static const InputChannelId Function11; //!< The F11 key
static const InputChannelId Function12; //!< The F12 key
static const InputChannelId Function13; //!< The F13 key
static const InputChannelId Function14; //!< The F14 key
static const InputChannelId Function15; //!< The F15 key
static const InputChannelId Function16; //!< The F16 key
static const InputChannelId Function17; //!< The F17 key
static const InputChannelId Function18; //!< The F18 key
static const InputChannelId Function19; //!< The F19 key
static const InputChannelId Function20; //!< The F20 key
static constexpr inline InputChannelId Function01{"keyboard_key_function_F01"}; //!< The F1 key
static constexpr inline InputChannelId Function02{"keyboard_key_function_F02"}; //!< The F2 key
static constexpr inline InputChannelId Function03{"keyboard_key_function_F03"}; //!< The F3 key
static constexpr inline InputChannelId Function04{"keyboard_key_function_F04"}; //!< The F4 key
static constexpr inline InputChannelId Function05{"keyboard_key_function_F05"}; //!< The F5 key
static constexpr inline InputChannelId Function06{"keyboard_key_function_F06"}; //!< The F6 key
static constexpr inline InputChannelId Function07{"keyboard_key_function_F07"}; //!< The F7 key
static constexpr inline InputChannelId Function08{"keyboard_key_function_F08"}; //!< The F8 key
static constexpr inline InputChannelId Function09{"keyboard_key_function_F09"}; //!< The F9 key
static constexpr inline InputChannelId Function10{"keyboard_key_function_F10"}; //!< The F10 key
static constexpr inline InputChannelId Function11{"keyboard_key_function_F11"}; //!< The F11 key
static constexpr inline InputChannelId Function12{"keyboard_key_function_F12"}; //!< The F12 key
static constexpr inline InputChannelId Function13{"keyboard_key_function_F13"}; //!< The F13 key
static constexpr inline InputChannelId Function14{"keyboard_key_function_F14"}; //!< The F14 key
static constexpr inline InputChannelId Function15{"keyboard_key_function_F15"}; //!< The F15 key
static constexpr inline InputChannelId Function16{"keyboard_key_function_F16"}; //!< The F16 key
static constexpr inline InputChannelId Function17{"keyboard_key_function_F17"}; //!< The F17 key
static constexpr inline InputChannelId Function18{"keyboard_key_function_F18"}; //!< The F18 key
static constexpr inline InputChannelId Function19{"keyboard_key_function_F19"}; //!< The F19 key
static constexpr inline InputChannelId Function20{"keyboard_key_function_F20"}; //!< The F20 key
// Modifier Keys
static const InputChannelId ModifierAltL; //!< The left alt/option key
static const InputChannelId ModifierAltR; //!< The right alt/option key
static const InputChannelId ModifierCtrlL; //!< The left control key
static const InputChannelId ModifierCtrlR; //!< The right control key
static const InputChannelId ModifierShiftL; //!< The left shift key
static const InputChannelId ModifierShiftR; //!< The right shift key
static const InputChannelId ModifierSuperL; //!< The left super (windows or apple) key
static const InputChannelId ModifierSuperR; //!< The right super (windows or apple) key
static constexpr inline InputChannelId ModifierAltL{"keyboard_key_modifier_alt_l"}; //!< The left alt/option key
static constexpr inline InputChannelId ModifierAltR{"keyboard_key_modifier_alt_r"}; //!< The right alt/option key
static constexpr inline InputChannelId ModifierCtrlL{"keyboard_key_modifier_ctrl_l"}; //!< The left control key
static constexpr inline InputChannelId ModifierCtrlR{"keyboard_key_modifier_ctrl_r"}; //!< The right control key
static constexpr inline InputChannelId ModifierShiftL{"keyboard_key_modifier_shift_l"}; //!< The left shift key
static constexpr inline InputChannelId ModifierShiftR{"keyboard_key_modifier_shift_r"}; //!< The right shift key
static constexpr inline InputChannelId ModifierSuperL{"keyboard_key_modifier_super_l"}; //!< The left super {windows or apple} key
static constexpr inline InputChannelId ModifierSuperR{"keyboard_key_modifier_super_r"}; //!< The right super {windows or apple} key
// Navigation Keys
static const InputChannelId NavigationArrowDown; //!< The down arrow key
static const InputChannelId NavigationArrowLeft; //!< The left arrow key
static const InputChannelId NavigationArrowRight; //!< The right arrow key
static const InputChannelId NavigationArrowUp; //!< The up arrow key
static const InputChannelId NavigationDelete; //!< The delete key
static const InputChannelId NavigationEnd; //!< The end key
static const InputChannelId NavigationHome; //!< The home key
static const InputChannelId NavigationInsert; //!< The insert key
static const InputChannelId NavigationPageDown; //!< The page down key
static const InputChannelId NavigationPageUp; //!< The page up key
static constexpr inline InputChannelId NavigationArrowDown{"keyboard_key_navigation_arrow_down"}; //!< The down arrow key
static constexpr inline InputChannelId NavigationArrowLeft{"keyboard_key_navigation_arrow_left"}; //!< The left arrow key
static constexpr inline InputChannelId NavigationArrowRight{"keyboard_key_navigation_arrow_right"}; //!< The right arrow key
static constexpr inline InputChannelId NavigationArrowUp{"keyboard_key_navigation_arrow_up"}; //!< The up arrow key
static constexpr inline InputChannelId NavigationDelete{"keyboard_key_navigation_delete"}; //!< The delete key
static constexpr inline InputChannelId NavigationEnd{"keyboard_key_navigation_end"}; //!< The end key
static constexpr inline InputChannelId NavigationHome{"keyboard_key_navigation_home"}; //!< The home key
static constexpr inline InputChannelId NavigationInsert{"keyboard_key_navigation_insert"}; //!< The insert key
static constexpr inline InputChannelId NavigationPageDown{"keyboard_key_navigation_page_down"}; //!< The page down key
static constexpr inline InputChannelId NavigationPageUp{"keyboard_key_navigation_page_up"}; //!< The page up key
// Numpad Keys
static const InputChannelId NumLock; //!< The num lock key (the clear key on apple keyboards)
static const InputChannelId NumPad0; //!< The numpad 0 key
static const InputChannelId NumPad1; //!< The numpad 1 key
static const InputChannelId NumPad2; //!< The numpad 2 key
static const InputChannelId NumPad3; //!< The numpad 3 key
static const InputChannelId NumPad4; //!< The numpad 4 key
static const InputChannelId NumPad5; //!< The numpad 5 key
static const InputChannelId NumPad6; //!< The numpad 6 key
static const InputChannelId NumPad7; //!< The numpad 7 key
static const InputChannelId NumPad8; //!< The numpad 8 key
static const InputChannelId NumPad9; //!< The numpad 9 key
static const InputChannelId NumPadAdd; //!< The numpad add key
static const InputChannelId NumPadDecimal; //!< The numpad decimal key
static const InputChannelId NumPadDivide; //!< The numpad divide key
static const InputChannelId NumPadEnter; //!< The numpad enter key
static const InputChannelId NumPadMultiply; //!< The numpad multiply key
static const InputChannelId NumPadSubtract; //!< The numpad subtract key
static constexpr inline InputChannelId NumLock{"keyboard_key_num_lock"}; //!< The num lock key {the clear key on apple keyboards}
static constexpr inline InputChannelId NumPad0{"keyboard_key_numpad_0"}; //!< The numpad 0 key
static constexpr inline InputChannelId NumPad1{"keyboard_key_numpad_1"}; //!< The numpad 1 key
static constexpr inline InputChannelId NumPad2{"keyboard_key_numpad_2"}; //!< The numpad 2 key
static constexpr inline InputChannelId NumPad3{"keyboard_key_numpad_3"}; //!< The numpad 3 key
static constexpr inline InputChannelId NumPad4{"keyboard_key_numpad_4"}; //!< The numpad 4 key
static constexpr inline InputChannelId NumPad5{"keyboard_key_numpad_5"}; //!< The numpad 5 key
static constexpr inline InputChannelId NumPad6{"keyboard_key_numpad_6"}; //!< The numpad 6 key
static constexpr inline InputChannelId NumPad7{"keyboard_key_numpad_7"}; //!< The numpad 7 key
static constexpr inline InputChannelId NumPad8{"keyboard_key_numpad_8"}; //!< The numpad 8 key
static constexpr inline InputChannelId NumPad9{"keyboard_key_numpad_9"}; //!< The numpad 9 key
static constexpr inline InputChannelId NumPadAdd{"keyboard_key_numpad_add"}; //!< The numpad add key
static constexpr inline InputChannelId NumPadDecimal{"keyboard_key_numpad_decimal"}; //!< The numpad decimal key
static constexpr inline InputChannelId NumPadDivide{"keyboard_key_numpad_divide"}; //!< The numpad divide key
static constexpr inline InputChannelId NumPadEnter{"keyboard_key_numpad_enter"}; //!< The numpad enter key
static constexpr inline InputChannelId NumPadMultiply{"keyboard_key_numpad_multiply"}; //!< The numpad multiply key
static constexpr inline InputChannelId NumPadSubtract{"keyboard_key_numpad_subtract"}; //!< The numpad subtract key
// Punctuation Keys
static const InputChannelId PunctuationApostrophe; //!< The apostrophe key
static const InputChannelId PunctuationBackslash; //!< The backslash key
static const InputChannelId PunctuationBracketL; //!< The left bracket key
static const InputChannelId PunctuationBracketR; //!< The right bracket key
static const InputChannelId PunctuationComma; //!< The comma key
static const InputChannelId PunctuationEquals; //!< The equals key
static const InputChannelId PunctuationHyphen; //!< The hyphen/underscore key
static const InputChannelId PunctuationPeriod; //!< The period key
static const InputChannelId PunctuationSemicolon; //!< The semicolon key
static const InputChannelId PunctuationSlash; //!< The (forward) slash key
static const InputChannelId PunctuationTilde; //!< The tilde/grave key
static constexpr inline InputChannelId PunctuationApostrophe{"keyboard_key_punctuation_apostrophe"}; //!< The apostrophe key
static constexpr inline InputChannelId PunctuationBackslash{"keyboard_key_punctuation_backslash"}; //!< The backslash key
static constexpr inline InputChannelId PunctuationBracketL{"keyboard_key_punctuation_bracket_l"}; //!< The left bracket key
static constexpr inline InputChannelId PunctuationBracketR{"keyboard_key_punctuation_bracket_r"}; //!< The right bracket key
static constexpr inline InputChannelId PunctuationComma{"keyboard_key_punctuation_comma"}; //!< The comma key
static constexpr inline InputChannelId PunctuationEquals{"keyboard_key_punctuation_equals"}; //!< The equals key
static constexpr inline InputChannelId PunctuationHyphen{"keyboard_key_punctuation_hyphen"}; //!< The hyphen/underscore key
static constexpr inline InputChannelId PunctuationPeriod{"keyboard_key_punctuation_period"}; //!< The period key
static constexpr inline InputChannelId PunctuationSemicolon{"keyboard_key_punctuation_semicolon"}; //!< The semicolon key
static constexpr inline InputChannelId PunctuationSlash{"keyboard_key_punctuation_slash"}; //!< The {forward} slash key
static constexpr inline InputChannelId PunctuationTilde{"keyboard_key_punctuation_tilde"}; //!< The tilde/grave key
// Supplementary ISO Key
static const InputChannelId SupplementaryISO; //!< The supplementary ISO layout key
static constexpr inline InputChannelId SupplementaryISO{"keyboard_key_supplementary_iso"}; //!< The supplementary ISO layout key
// Windows System Keys
static const InputChannelId WindowsSystemPause; //!< The windows pause key
static const InputChannelId WindowsSystemPrint; //!< The windows print key
static const InputChannelId WindowsSystemScrollLock; //!< The windows scroll lock key
static constexpr inline InputChannelId WindowsSystemPause{"keyboard_key_windows_system_pause"}; //!< The windows pause key
static constexpr inline InputChannelId WindowsSystemPrint{"keyboard_key_windows_system_print"}; //!< The windows print key
static constexpr inline InputChannelId WindowsSystemScrollLock{"keyboard_key_windows_system_scroll_lock"}; //!< The windows scroll lock key
//!< All keyboard key ids
static const AZStd::array<InputChannelId, 112> All;
static constexpr inline AZStd::array All
{
// Alphanumeric Keys
Alphanumeric0,
Alphanumeric1,
Alphanumeric2,
Alphanumeric3,
Alphanumeric4,
Alphanumeric5,
Alphanumeric6,
Alphanumeric7,
Alphanumeric8,
Alphanumeric9,
AlphanumericA,
AlphanumericB,
AlphanumericC,
AlphanumericD,
AlphanumericE,
AlphanumericF,
AlphanumericG,
AlphanumericH,
AlphanumericI,
AlphanumericJ,
AlphanumericK,
AlphanumericL,
AlphanumericM,
AlphanumericN,
AlphanumericO,
AlphanumericP,
AlphanumericQ,
AlphanumericR,
AlphanumericS,
AlphanumericT,
AlphanumericU,
AlphanumericV,
AlphanumericW,
AlphanumericX,
AlphanumericY,
AlphanumericZ,
// Edit (and escape) Keys
EditBackspace,
EditCapsLock,
EditEnter,
EditSpace,
EditTab,
Escape,
// Function Keys
Function01,
Function02,
Function03,
Function04,
Function05,
Function06,
Function07,
Function08,
Function09,
Function10,
Function11,
Function12,
Function13,
Function14,
Function15,
Function16,
Function17,
Function18,
Function19,
Function20,
// Modifier Keys
ModifierAltL,
ModifierAltR,
ModifierCtrlL,
ModifierCtrlR,
ModifierShiftL,
ModifierShiftR,
ModifierSuperL,
ModifierSuperR,
// Navigation Keys
NavigationArrowDown,
NavigationArrowLeft,
NavigationArrowRight,
NavigationArrowUp,
NavigationDelete,
NavigationEnd,
NavigationHome,
NavigationInsert,
NavigationPageDown,
NavigationPageUp,
// Numpad Keys
NumLock,
NumPad0,
NumPad1,
NumPad2,
NumPad3,
NumPad4,
NumPad5,
NumPad6,
NumPad7,
NumPad8,
NumPad9,
NumPadAdd,
NumPadDecimal,
NumPadDivide,
NumPadEnter,
NumPadMultiply,
NumPadSubtract,
// Punctuation Keys
PunctuationApostrophe,
PunctuationBackslash,
PunctuationBracketL,
PunctuationBracketR,
PunctuationComma,
PunctuationEquals,
PunctuationHyphen,
PunctuationPeriod,
PunctuationSemicolon,
PunctuationSlash,
PunctuationTilde,
// Supplementary ISO Key
SupplementaryISO,
// Windows System Keys
WindowsSystemPause,
WindowsSystemPrint,
WindowsSystemScrollLock
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -23,44 +23,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMotion::Acceleration::Gravity("motion_acceleration_gravity");
const InputChannelId InputDeviceMotion::Acceleration::Raw("motion_acceleration_raw");
const InputChannelId InputDeviceMotion::Acceleration::User("motion_acceleration_user");
const AZStd::array<InputChannelId, 3> InputDeviceMotion::Acceleration::All =
{{
Gravity,
Raw,
User
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMotion::RotationRate::Raw("motion_rotation_rate_raw");
const InputChannelId InputDeviceMotion::RotationRate::Unbiased("motion_rotation_rate_unbiased");
const AZStd::array<InputChannelId, 2> InputDeviceMotion::RotationRate::All =
{{
Raw,
Unbiased
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMotion::MagneticField::North("motion_magnetic_field_north");
const InputChannelId InputDeviceMotion::MagneticField::Raw("motion_magnetic_field_raw");
const InputChannelId InputDeviceMotion::MagneticField::Unbiased("motion_magnetic_field_unbiased");
const AZStd::array<InputChannelId, 3> InputDeviceMotion::MagneticField::All =
{{
North,
Raw,
Unbiased
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMotion::Orientation::Current("motion_orientation_current");
const AZStd::array<InputChannelId, 1> InputDeviceMotion::Orientation::All =
{{
Current
}};
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceMotion::Reflect(AZ::ReflectContext* context)
{
@@ -44,12 +44,17 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled
struct Acceleration
{
static const InputChannelId Gravity;
static const InputChannelId Raw;
static const InputChannelId User;
static constexpr inline InputChannelId Gravity{"motion_acceleration_gravity"};
static constexpr inline InputChannelId Raw{"motion_acceleration_raw"};
static constexpr inline InputChannelId User{"motion_acceleration_user"};
//!< All acceleration input channel ids
static const AZStd::array<InputChannelId, 3> All;
static constexpr inline AZStd::array All
{
Gravity,
Raw,
User
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -60,11 +65,15 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled
struct RotationRate
{
static const InputChannelId Raw;
static const InputChannelId Unbiased;
static constexpr inline InputChannelId Raw{"motion_rotation_rate_raw"};
static constexpr inline InputChannelId Unbiased{"motion_rotation_rate_unbiased"};
//!< All rotation rate input channel ids
static const AZStd::array<InputChannelId, 2> All;
static constexpr inline AZStd::array All
{
Raw,
Unbiased
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -75,12 +84,17 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled
struct MagneticField
{
static const InputChannelId North;
static const InputChannelId Raw;
static const InputChannelId Unbiased;
static constexpr inline InputChannelId North{"motion_magnetic_field_north"};
static constexpr inline InputChannelId Raw{"motion_magnetic_field_raw"};
static constexpr inline InputChannelId Unbiased{"motion_magnetic_field_unbiased"};
//!< All magnetic field input channel ids
static const AZStd::array<InputChannelId, 3> All;
static constexpr inline AZStd::array All
{
North,
Raw,
Unbiased
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -91,10 +105,13 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled
struct Orientation
{
static const InputChannelId Current;
static constexpr inline InputChannelId Current{"motion_orientation_current"};
//!< All orientation input channel ids
static const AZStd::array<InputChannelId, 1> All;
static constexpr inline AZStd::array All
{
Current
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -33,35 +33,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMouse::Button::Left("mouse_button_left");
const InputChannelId InputDeviceMouse::Button::Right("mouse_button_right");
const InputChannelId InputDeviceMouse::Button::Middle("mouse_button_middle");
const InputChannelId InputDeviceMouse::Button::Other1("mouse_button_other1");
const InputChannelId InputDeviceMouse::Button::Other2("mouse_button_other2");
const AZStd::array<InputChannelId, 5> InputDeviceMouse::Button::All =
{{
Left,
Right,
Middle,
Other1,
Other2
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMouse::Movement::X("mouse_delta_x");
const InputChannelId InputDeviceMouse::Movement::Y("mouse_delta_y");
const InputChannelId InputDeviceMouse::Movement::Z("mouse_delta_z");
const AZStd::array<InputChannelId, 3> InputDeviceMouse::Movement::All =
{{
X,
Y,
Z
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMouse::SystemCursorPosition("mouse_system_cursor_position");
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceMouse::Reflect(AZ::ReflectContext* context)
{
@@ -66,14 +66,21 @@ namespace AzFramework
//! been implemented for windows simply to provide for backwards compatibility with CryInput.
struct Button
{
static const InputChannelId Left; //!< The left mouse button
static const InputChannelId Right; //!< The right mouse button
static const InputChannelId Middle; //!< The middle mouse button
static const InputChannelId Other1; //!< DEPRECATED: the x1 mouse button
static const InputChannelId Other2; //!< DEPRECATED: the x2 mouse button
static constexpr inline InputChannelId Left{"mouse_button_left"}; //!< The left mouse button
static constexpr inline InputChannelId Right{"mouse_button_right"}; //!< The right mouse button
static constexpr inline InputChannelId Middle{"mouse_button_middle"}; //!< The middle mouse button
static constexpr inline InputChannelId Other1{"mouse_button_other1"}; //!< DEPRECATED: the x1 mouse button
static constexpr inline InputChannelId Other2{"mouse_button_other2"}; //!< DEPRECATED: the x2 mouse button
//!< All mouse button ids
static const AZStd::array<InputChannelId, 5> All;
static constexpr inline AZStd::array All
{
Left,
Right,
Middle,
Other1,
Other2
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -82,12 +89,17 @@ namespace AzFramework
//! directly correlate to the mouse position (which is queried directly from the system).
struct Movement
{
static const InputChannelId X; //!< Raw horizontal mouse movement over the last frame
static const InputChannelId Y; //!< Raw vertical mouse movement over the last frame
static const InputChannelId Z; //!< Raw mouse wheel movement over the last frame
static constexpr inline InputChannelId X{"mouse_delta_x"}; //!< Raw horizontal mouse movement over the last frame
static constexpr inline InputChannelId Y{"mouse_delta_y"}; //!< Raw vertical mouse movement over the last frame
static constexpr inline InputChannelId Z{"mouse_delta_z"}; //!< Raw mouse wheel movement over the last frame
//!< All mouse movement ids
static const AZStd::array<InputChannelId, 3> All;
static constexpr inline AZStd::array All
{
X,
Y,
Z
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -96,7 +108,7 @@ namespace AzFramework
//! the system cursor is hidden or visible. When the system cursor has been constrained to
//! the active window values will be in the [0.0, 1.0] range, but not when unconstrained.
//! See also InputSystemCursorRequests::SetSystemCursorState and GetSystemCursorState.
static const InputChannelId SystemCursorPosition;
static constexpr inline InputChannelId SystemCursorPosition{"mouse_system_cursor_position"};
////////////////////////////////////////////////////////////////////////////////////////////
// Allocator
@@ -24,31 +24,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceTouch::Touch::Index0("touch_index_0");
const InputChannelId InputDeviceTouch::Touch::Index1("touch_index_1");
const InputChannelId InputDeviceTouch::Touch::Index2("touch_index_2");
const InputChannelId InputDeviceTouch::Touch::Index3("touch_index_3");
const InputChannelId InputDeviceTouch::Touch::Index4("touch_index_4");
const InputChannelId InputDeviceTouch::Touch::Index5("touch_index_5");
const InputChannelId InputDeviceTouch::Touch::Index6("touch_index_6");
const InputChannelId InputDeviceTouch::Touch::Index7("touch_index_7");
const InputChannelId InputDeviceTouch::Touch::Index8("touch_index_8");
const InputChannelId InputDeviceTouch::Touch::Index9("touch_index_9");
const AZStd::array<InputChannelId, 10> InputDeviceTouch::Touch::All =
{{
Index0,
Index1,
Index2,
Index3,
Index4,
Index5,
Index6,
Index7,
Index8,
Index9
}};
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceTouch::Reflect(AZ::ReflectContext* context)
{
@@ -38,19 +38,31 @@ namespace AzFramework
//! track is arbitrary, but ten seems to be more than sufficient for most game applications.
struct Touch
{
static const InputChannelId Index0; //!< Touch index 0
static const InputChannelId Index1; //!< Touch index 1
static const InputChannelId Index2; //!< Touch index 2
static const InputChannelId Index3; //!< Touch index 3
static const InputChannelId Index4; //!< Touch index 4
static const InputChannelId Index5; //!< Touch index 5
static const InputChannelId Index6; //!< Touch index 6
static const InputChannelId Index7; //!< Touch index 7
static const InputChannelId Index8; //!< Touch index 8
static const InputChannelId Index9; //!< Touch index 9
static constexpr inline InputChannelId Index0{"touch_index_0"}; //!< Touch index 0
static constexpr inline InputChannelId Index1{"touch_index_1"}; //!< Touch index 1
static constexpr inline InputChannelId Index2{"touch_index_2"}; //!< Touch index 2
static constexpr inline InputChannelId Index3{"touch_index_3"}; //!< Touch index 3
static constexpr inline InputChannelId Index4{"touch_index_4"}; //!< Touch index 4
static constexpr inline InputChannelId Index5{"touch_index_5"}; //!< Touch index 5
static constexpr inline InputChannelId Index6{"touch_index_6"}; //!< Touch index 6
static constexpr inline InputChannelId Index7{"touch_index_7"}; //!< Touch index 7
static constexpr inline InputChannelId Index8{"touch_index_8"}; //!< Touch index 8
static constexpr inline InputChannelId Index9{"touch_index_9"}; //!< Touch index 9
//!< All touch input channel ids
static const AZStd::array<InputChannelId, 10> All;
static constexpr inline AZStd::array All
{
Index0,
Index1,
Index2,
Index3,
Index4,
Index5,
Index6,
Index7,
Index8,
Index9
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -23,17 +23,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceVirtualKeyboard::Command::EditEnter("virtual_keyboard_edit_enter");
const InputChannelId InputDeviceVirtualKeyboard::Command::EditClear("virtual_keyboard_edit_clear");
const InputChannelId InputDeviceVirtualKeyboard::Command::NavigationBack("virtual_keyboard_navigation_back");
const AZStd::array<InputChannelId, 3> InputDeviceVirtualKeyboard::Command::All =
{{
EditClear,
EditEnter,
NavigationBack
}};
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceVirtualKeyboard::Reflect(AZ::ReflectContext* context)
{
@@ -39,17 +39,22 @@ namespace AzFramework
struct Command
{
//!< The clear command used to indicate the user wants to clear the active text field
static const InputChannelId EditClear;
static constexpr inline InputChannelId EditClear{"virtual_keyboard_edit_enter"};
//!< The enter/return/close command used to indicate the user has finished text editing
static const InputChannelId EditEnter;
static constexpr inline InputChannelId EditEnter{"virtual_keyboard_edit_clear"};
//!< The back command used to indicate the user wants to navigate 'backwards'.
//!< This is specific to android devices, and does not have an ios equivalent.
static const InputChannelId NavigationBack;
static constexpr inline InputChannelId NavigationBack{"virtual_keyboard_navigation_back"};
//!< All virtual keyboard command ids
static const AZStd::array<InputChannelId, 3> All;
static constexpr inline AZStd::array All
{
EditClear,
EditEnter,
NavigationBack
};
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzFramework/Logging/MissingAssetNotificationBus.h>
namespace AzFramework { class LogFile; }
@@ -593,7 +593,7 @@ namespace AzFramework
DebugMessage("StartThread: Starting %s", thread.m_desc.m_name);
thread.m_join = false;
thread.m_thread = AZStd::thread(thread.m_main, &thread.m_desc);
thread.m_thread = AZStd::thread(thread.m_desc, thread.m_main);
}
void AssetProcessorConnection::JoinThread(ThreadState& thread, AZStd::condition_variable* wakeUpCondition /* = nullptr */)
@@ -13,6 +13,7 @@
#include <AzFramework/Physics/Ragdoll.h>
#include <AzFramework/Physics/Shape.h>
#include <AzFramework/Physics/SystemBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/utils.h>
@@ -9,6 +9,7 @@
#include <AzFramework/Physics/Collision/CollisionEvents.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
@@ -9,6 +9,8 @@
#include <AzFramework/Physics/Collision/CollisionGroups.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Script/ScriptContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Physics/CollisionBus.h>
@@ -10,6 +10,7 @@
#include <AzCore/Interface/Interface.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
@@ -8,6 +8,7 @@
#include <AzFramework/Physics/Configuration/SystemConfiguration.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
@@ -5,6 +5,8 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Interface/Interface.h>

Some files were not shown because too many files have changed in this diff Show More