Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented basic console variable support #48

Merged
merged 4 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion Volt/Sandbox/src/Sandbox/Window/LogPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#include <Volt/Log/Log.h>
#include <Volt/Utility/UIUtility.h>
#include <Volt/Utility/StringUtility.h>

#include <Volt/Console/ConsoleVariableRegistry.h>

namespace Utility
{
Expand Down Expand Up @@ -48,10 +51,73 @@ void LogPanel::UpdateMainContent()
myCategories.emplace_back("Default");
}

ImGui::SameLine();
ImGui::PushItemWidth(200.f);

static std::string commandStr;

if (ImGui::InputTextWithHintString("##commandLine", "Command...", &commandStr, ImGuiInputTextFlags_EnterReturnsTrue))
{
auto strings = Utility::SplitStringsByCharacter(commandStr, ' ');
if (!strings.empty())
{
if (Volt::ConsoleVariableRegistry::VariableExists(strings[0]))
{
auto variable = Volt::ConsoleVariableRegistry::GetVariable(strings[0]);

std::string message = std::string(variable->GetName()) + " = ";

if (strings.size() > 1)
{
if (variable->IsFloat())
{
const float value = std::stof(strings[1]);
variable->Set(&value);
}
else if (variable->IsInteger())
{
const int32_t value = std::stoi(strings[1]);
variable->Set(&value);
}
else if (variable->IsString())
{
variable->Set(&strings[1]);
}

message += strings[1];
}
else
{
if (variable->IsFloat())
{
message += std::to_string(*static_cast<const float*>(variable->Get()));
}
else if (variable->IsInteger())
{
message += std::to_string(*static_cast<const int32_t*>(variable->Get()));
}
else if (variable->IsString())
{
message += *static_cast<const std::string*>(variable->Get());
}

}

VT_CORE_TRACE(message);
}
else
{
VT_CORE_TRACE("Command {0} not found!", strings[0]);
}
}

commandStr = "";
}


ImGui::SameLine();
static int32_t logLevel = 0;

ImGui::PushItemWidth(200.f);
if (ImGui::Combo("##level", &logLevel, "Trace\0Info\0Warning\0Error\0Critical"))
{
switch (logLevel)
Expand Down
185 changes: 185 additions & 0 deletions Volt/Volt/src/Volt/Console/ConsoleVariableRegistry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#pragma once

#include "Volt/Core/Base.h"

#include "Volt/Utility/StringUtility.h"

#include <unordered_map>
#include <string_view>

namespace Volt
{
class RegisteredConsoleVariableBase
{
public:
virtual const void* Get() const = 0;
virtual void Set(const void* value) = 0;

virtual std::string_view GetName() const = 0;
virtual std::string_view GetDescription() const = 0;

virtual bool IsInteger() const = 0;
virtual bool IsFloat() const = 0;
virtual bool IsString() const = 0;
};

template<typename T>
concept ValidConsoleVariableType = std::is_same_v<T, int32_t> || std::is_same_v<T, float> || std::is_same_v<T, std::string>;

template<ValidConsoleVariableType T>
class RegisteredConsoleVariable : public RegisteredConsoleVariableBase
{
public:
RegisteredConsoleVariable(const std::string& variableName, const T& defaultValue, std::string_view description);

[[nodiscard]] const void* Get() const override;
void Set(const void* value) override;

[[nodiscard]] inline std::string_view GetName() const override { return m_variableName; }
[[nodiscard]] inline std::string_view GetDescription() const override { return m_description; }

[[nodiscard]] inline constexpr bool IsInteger() const override { return std::is_integral_v<T>; }
[[nodiscard]] inline constexpr bool IsFloat() const override { return std::is_floating_point_v<T>; }
[[nodiscard]] inline constexpr bool IsString() const override { return std::is_same_v<T, std::string>; }

private:
T m_value;
std::string m_variableName;
std::string_view m_description;
};

template<ValidConsoleVariableType T>
class ConsoleVariable
{
public:
ConsoleVariable(std::string_view variableName, const T& defaultValue, std::string_view description);

const T& GetValue() const { return *reinterpret_cast<T*>(m_variableReference->Get()); }
void SetValue(const T& value) { m_variableReference->Set(&value); }

T& operator=(const T& other)
{
if (this == &other)
{
return GetValue();
}

SetValue(other);
}

private:
Weak<RegisteredConsoleVariable<T>> m_variableReference;
};

template<ValidConsoleVariableType T>
class ConsoleVariableRef
{
public:
ConsoleVariableRef(std::string_view variableName);

const T& GetValue() const { return *reinterpret_cast<T*>(m_variableReference->Get()); }
void SetValue(const T& value) { m_variableReference->Set(&value); }

T& operator=(const T& other)
{
if (this == &other)
{
return GetValue();
}

SetValue(other);
}

private:
Weak<RegisteredConsoleVariable<T>> m_variableReference;
};

class ConsoleVariableRegistry
{
public:
template<ValidConsoleVariableType T>
static Weak<RegisteredConsoleVariable<T>> RegisterVariable(std::string_view variableName, const T& defaultValue, std::string_view description);

template<ValidConsoleVariableType T>
static Weak<RegisteredConsoleVariable<T>> FindVariable(const std::string& variableName);

inline static Weak<RegisteredConsoleVariableBase> GetVariable(const std::string& variableName);
inline static bool VariableExists(const std::string& variableName);

static std::unordered_map<std::string, Ref<RegisteredConsoleVariableBase>>& GetRegisteredVariables() { return s_registeredVariables; }

private:
ConsoleVariableRegistry() = delete;

inline static std::unordered_map<std::string, Ref<RegisteredConsoleVariableBase>> s_registeredVariables;
};

inline bool ConsoleVariableRegistry::VariableExists(const std::string& variableName)
{
std::string tempVarName = ::Utility::ToLower(std::string(variableName));
return s_registeredVariables.contains(tempVarName);
}

template<ValidConsoleVariableType T>
inline RegisteredConsoleVariable<T>::RegisteredConsoleVariable(const std::string& variableName, const T& defaultValue, std::string_view description)
: m_value(defaultValue), m_variableName(variableName), m_description(description)
{
}

template<ValidConsoleVariableType T>
inline const void* RegisteredConsoleVariable<T>::Get() const
{
return reinterpret_cast<const void*>(&m_value);
}

template<ValidConsoleVariableType T>
inline void RegisteredConsoleVariable<T>::Set(const void* value)
{
m_value = *reinterpret_cast<const T*>(value);
}

template<ValidConsoleVariableType T>
inline ConsoleVariable<T>::ConsoleVariable(std::string_view variableName, const T& defaultValue, std::string_view description)
{
m_variableReference = ConsoleVariableRegistry::RegisterVariable<T>(variableName, defaultValue, description);
}

template<ValidConsoleVariableType T>
inline Weak<RegisteredConsoleVariable<T>> ConsoleVariableRegistry::RegisterVariable(std::string_view variableName, const T& defaultValue, std::string_view description)
{
std::string tempVarName = ::Utility::ToLower(std::string(variableName));

Ref<RegisteredConsoleVariable<T>> consoleVariable = CreateRef<RegisteredConsoleVariable<T>>(tempVarName, defaultValue, description);

VT_CORE_ASSERT(!s_registeredVariables.contains(tempVarName), "Command variable with name already registered!");
s_registeredVariables[tempVarName] = consoleVariable;

return consoleVariable;
}

template<ValidConsoleVariableType T>
inline Weak<RegisteredConsoleVariable<T>> ConsoleVariableRegistry::FindVariable(const std::string& variableName)
{
const std::string tempVarName = ::Utility::ToLower(variableName);

if (s_registeredVariables.contains(tempVarName))
{
return s_registeredVariables.at(tempVarName);
}

return Weak<RegisteredConsoleVariable<T>>();
}

template<ValidConsoleVariableType T>
inline ConsoleVariableRef<T>::ConsoleVariableRef(std::string_view variableName)
{
m_variableReference = ConsoleVariableRegistry::FindVariable(variableName);
VT_CORE_ASSERT(m_variableReference, "Variable with name not found!");
}

inline Weak<RegisteredConsoleVariableBase> ConsoleVariableRegistry::GetVariable(const std::string& variableName)
{
const std::string tempVarName = ::Utility::ToLower(variableName);
return s_registeredVariables.at(tempVarName);
}
}