Added a deferred queue to the AZ Console class (#3298)

* Added a deferred queue to the AZ Console class

An AZ Console instance will now store any console commands that could be
dispatched from a configuration file into a deferred queue, that can be
invoked later.

This can be used to defer execution of console commands in configuration files such as
.cfg, .setreg and .setregpatch files that are defined in gem modules that
have not been loaded yet.
The defered execution can then be invoked at any point later in the
application

Updated the Component Application CreateCommon function to invoke deferred console commands
after all the gems have loaded

fixes #2062

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Fixed variable shadowing in the Console Deferred Command Test

Updated commit for the ClearDeferredQueue function to just mention
clearing the queue

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Filtered out execution of the ConsoleRootCommandKey as a console command

The AZ::Console notification handler is tracking changes to the fields
of "/Amazon/AzCore/Runtime/ConsoleCommands" and it's children.

Now the "/Amazon/AzCore/Runtime/ConsoleCommands" field is the
ConsoleRootCommandKey and not an actual console command so it shouldn't
attempt to be invoked

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Moved the execution of deferred console commands after linking deferred
functors

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Moved the execution of deferred console commands into CreateModuleClass
hook

Any module that loads using the ModuleManager system will attempt to
execute any deferred console commands to allow newly registered commands
from that module to be dispatched.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
This commit is contained in:
lumberyard-employee-dm
2021-08-18 20:58:57 -05:00
committed by GitHub
parent 90845313fb
commit 586678a5f9
5 changed files with 149 additions and 21 deletions
@@ -507,6 +507,70 @@ namespace ConsoleSettingsRegistryTests
AZ::Interface<AZ::IConsole>::Unregister(&testConsole);
}
template<typename T>
using ConsoleDataWrapper = AZ::ConsoleDataWrapper<T, ConsoleThreadSafety<T>>;
TEST_P(ConsoleSettingsRegistryFixture, Console_RecordsUnregisteredCommands_And_IsAbleToDeferDispatchCommand_Successfully)
{
AZ::Console testConsole(*m_registry);
AZ::Interface<AZ::IConsole>::Register(&testConsole);
// GetDeferredHead is invoked for the side effect of to set the s_deferredHeadInvoked value to true
// This allows scoped console variables to be attached immediately
[[maybe_unused]] auto deferredHead = AZ::ConsoleFunctorBase::GetDeferredHead();
ConsoleDataWrapper<int32_t> localTestInit{ {}, nullptr, "testInit", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<char> localTestChar{ {}, nullptr, "testChar", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<bool> localTestBool{ {}, nullptr, "testBool", "", AZ::ConsoleFunctorFlags::Null };
s_consoleFreeFunctionInvoked = false;
// Invoke the Commands for Scoped CVar variables above
auto configFileParams = GetParam();
auto testFilePath = m_testFolder / configFileParams.m_testConfigFileName;
EXPECT_TRUE(AZ::IO::SystemFile::Exists(testFilePath.c_str()));
testConsole.ExecuteConfigFile(testFilePath.Native());
EXPECT_EQ(3, localTestInit);
EXPECT_TRUE(static_cast<bool>(localTestBool));
EXPECT_EQ('Q', localTestChar);
// The following commands from the config files should have been deferred
ConsoleDataWrapper<int8_t> localTestInt8{ {}, nullptr, "testInt8", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<int16_t> localTestInt16{ {}, nullptr, "testInt16", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<int32_t> localTestInt32{ {}, nullptr, "testInt32", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<int64_t> localTestInt64{ {}, nullptr, "testInt64", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<uint8_t> localTestUInt8{ {}, nullptr, "testUInt8", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<uint16_t> localTestUInt16{ {}, nullptr, "testUInt16", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<uint32_t> localTestUInt32{ {}, nullptr, "testUInt32", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<uint64_t> localTestUInt64{ {}, nullptr, "testUInt64", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<float> localTestFloat{ {}, nullptr, "testFloat", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<double> localTestDouble{ {}, nullptr, "testDouble", "", AZ::ConsoleFunctorFlags::Null };
ConsoleDataWrapper<AZ::CVarFixedString> localTestString{ {}, nullptr, "testString", "", AZ::ConsoleFunctorFlags::Null };
// The scoped cvars just above should have all been deferred for execution
// Each of them should have executed resulting in the expected return value
EXPECT_TRUE(testConsole.ExecuteDeferredConsoleCommands());
EXPECT_EQ(24, localTestInt8);
EXPECT_EQ(-32, localTestInt16);
EXPECT_EQ(41, localTestInt32);
EXPECT_EQ(-51, localTestInt64);
EXPECT_EQ(3, localTestUInt8);
EXPECT_EQ(5, localTestUInt16);
EXPECT_EQ(6, localTestUInt32);
EXPECT_EQ(0xFFFF'FFFF'FFFF'FFFF, localTestUInt64);
EXPECT_FLOAT_EQ(1.0f, localTestFloat);
EXPECT_DOUBLE_EQ(2, localTestDouble);
EXPECT_STREQ("Stable", static_cast<AZ::CVarFixedString>(localTestString).c_str());
// All of the deferred console commands should have executed at this point
// Therefore this invocation should return false
EXPECT_FALSE(testConsole.ExecuteDeferredConsoleCommands());
AZ::Interface<AZ::IConsole>::Unregister(&testConsole);
}
static constexpr AZStd::string_view UserINIStyleContent =
R"(