mirror of https://github.com/AxioDL/metaforce.git
Merge branch 'dawn' into new-cmodel
# Conflicts: # Runtime/Streams/ContainerReaders.hpp
This commit is contained in:
commit
5e7b8ebacf
|
@ -67,7 +67,6 @@ public:
|
|||
static int RecursiveMakeDir(const char* dir);
|
||||
static void MakeDir(const char* dir);
|
||||
static int Stat(const char* path, Sstat* statOut);
|
||||
static inline void ToLower(std::string& str) { std::transform(str.begin(), str.end(), str.begin(), ::tolower); }
|
||||
};
|
||||
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -579,7 +579,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
SetupBasics(IsClientLoggingEnabled(argc, argv));
|
||||
metaforce::FileStoreManager fileMgr{"metaforce"};
|
||||
metaforce::FileStoreManager fileMgr{"AxioDL", "metaforce"};
|
||||
metaforce::CVarManager cvarMgr{fileMgr};
|
||||
metaforce::CVarCommons cvarCmns{cvarMgr};
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ set(RUNTIME_SOURCES_B
|
|||
Streams/CMemoryInStream.hpp
|
||||
Streams/CZipInputStream.hpp Streams/CZipInputStream.cpp
|
||||
Streams/ContainerReaders.hpp
|
||||
Streams/CTextInStream.hpp Streams/CTextInStream.cpp
|
||||
Streams/CTextOutStream.hpp Streams/CTextOutStream.cpp
|
||||
CGameAllocator.hpp CGameAllocator.cpp
|
||||
CMemoryCardSys.hpp CMemoryCardSys.cpp
|
||||
CScannableObjectInfo.hpp CScannableObjectInfo.cpp
|
||||
|
@ -135,6 +137,7 @@ set(RUNTIME_SOURCES_B
|
|||
GCNTypes.hpp
|
||||
CTextureCache.hpp CTextureCache.cpp
|
||||
CMayaSpline.hpp CMayaSpline.cpp
|
||||
ImGuiPlayerLoadouts.hpp ImGuiPlayerLoadouts.cpp
|
||||
${PLAT_SRCS})
|
||||
|
||||
function(add_runtime_common_library name)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include "Runtime/CStringExtras.hpp"
|
||||
#include "Runtime/CMemoryCardSys.hpp"
|
||||
#include "Runtime/CStateManager.hpp"
|
||||
#include "Runtime/GameGlobalObjects.hpp"
|
||||
|
@ -437,7 +438,7 @@ CPlayerState::EItemType CPlayerState::ItemNameToType(std::string_view name) {
|
|||
}};
|
||||
|
||||
std::string lowName{name};
|
||||
CBasics::ToLower(lowName);
|
||||
CStringExtras::ToLower(lowName);
|
||||
|
||||
const auto iter = std::find_if(typeNameMap.cbegin(), typeNameMap.cend(),
|
||||
[&lowName](const auto& entry) { return entry.first == lowName; });
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace metaforce {
|
||||
class CInputStream;
|
||||
|
@ -42,7 +43,71 @@ public:
|
|||
return s;
|
||||
}
|
||||
|
||||
static inline void ToLower(std::string& str) { std::transform(str.begin(), str.end(), str.begin(), ::tolower); }
|
||||
static std::string ReadString(CInputStream& in);
|
||||
static inline bool ParseBool(std::string_view boolean, bool* valid) {
|
||||
std::string val(boolean);
|
||||
// compare must be case insensitive
|
||||
// This is the cleanest solution since I only need to do it once
|
||||
ToLower(val);
|
||||
|
||||
// Check for true first
|
||||
if (val == "true" || val == "1" || val == "yes" || val == "on") {
|
||||
if (valid)
|
||||
*valid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now false
|
||||
if (val == "false" || val == "0" || val == "no" || val == "off") {
|
||||
if (valid)
|
||||
*valid = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Well that could've gone better
|
||||
|
||||
if (valid)
|
||||
*valid = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline std::vector<std::string>& Split(std::string_view s, char delim, std::vector<std::string>& elems) {
|
||||
std::string tmps(s);
|
||||
std::stringstream ss(tmps);
|
||||
std::string item;
|
||||
|
||||
while (std::getline(ss, item, delim)) {
|
||||
elems.push_back(item);
|
||||
}
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
static inline std::vector<std::string> Split(std::string_view s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
Split(s, delim, elems);
|
||||
return elems;
|
||||
}
|
||||
|
||||
static inline std::string LeftTrim(const std::string &s)
|
||||
{
|
||||
size_t start = s.find_first_not_of(" \n\r\t\f\v");
|
||||
return (start == std::string::npos) ? "" : s.substr(start);
|
||||
}
|
||||
|
||||
static inline std::string RightTrim(const std::string &s)
|
||||
{
|
||||
size_t end = s.find_last_not_of(" \n\r\t\f\v");
|
||||
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
||||
}
|
||||
|
||||
static inline std::string Trim(const std::string &s) {
|
||||
return RightTrim(LeftTrim(s));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "Runtime/ConsoleVariables/CVar.hpp"
|
||||
#include "Runtime/CBasics.hpp"
|
||||
#include "Runtime/CStringExtras.hpp"
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
|
@ -8,56 +9,6 @@
|
|||
#include "Runtime/ConsoleVariables/CVarManager.hpp"
|
||||
|
||||
namespace metaforce {
|
||||
namespace {
|
||||
// TODO: Move these to CBasics?
|
||||
inline bool parseBool(std::string_view boolean, bool* valid) {
|
||||
std::string val(boolean);
|
||||
// compare must be case insensitive
|
||||
// This is the cleanest solution since I only need to do it once
|
||||
CBasics::ToLower(val);
|
||||
|
||||
// Check for true first
|
||||
if (val == "true" || val == "1" || val == "yes" || val == "on") {
|
||||
if (valid)
|
||||
*valid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now false
|
||||
if (val == "false" || val == "0" || val == "no" || val == "off") {
|
||||
if (valid)
|
||||
*valid = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Well that could've gone better
|
||||
|
||||
if (valid)
|
||||
*valid = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::vector<std::string>& split(std::string_view s, char delim, std::vector<std::string>& elems) {
|
||||
std::string tmps(s);
|
||||
std::stringstream ss(tmps);
|
||||
std::string item;
|
||||
|
||||
while (std::getline(ss, item, delim)) {
|
||||
elems.push_back(item);
|
||||
}
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string_view s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
split(s, delim, elems);
|
||||
return elems;
|
||||
}
|
||||
}
|
||||
extern CVar* com_developer;
|
||||
extern CVar* com_enableCheats;
|
||||
|
||||
|
@ -250,7 +201,7 @@ bool CVar::toBoolean(bool* isValid) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
return parseBool(m_value, isValid);
|
||||
return CStringExtras::ParseBool(m_value, isValid);
|
||||
}
|
||||
|
||||
int32_t CVar::toSigned(bool* isValid) const {
|
||||
|
@ -494,12 +445,12 @@ bool isReal(const std::vector<std::string>& v) {
|
|||
}
|
||||
|
||||
bool CVar::isValidInput(std::string_view input) const {
|
||||
std::vector<std::string> parts = split(input, ' ');
|
||||
std::vector<std::string> parts = CStringExtras::Split(input, ' ');
|
||||
char* p;
|
||||
switch (m_type) {
|
||||
case EType::Boolean: {
|
||||
bool valid = false;
|
||||
parseBool(input, &valid);
|
||||
CStringExtras::ParseBool(input, &valid);
|
||||
return valid;
|
||||
}
|
||||
case EType::Signed:
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
|
||||
#include "Runtime/ConsoleVariables/FileStoreManager.hpp"
|
||||
#include "Runtime/CBasics.hpp"
|
||||
|
||||
#include "Runtime/Streams/CTextInStream.hpp"
|
||||
#include "Runtime/Streams/CTextOutStream.hpp"
|
||||
#include "Runtime/Streams/CMemoryInStream.hpp"
|
||||
#include "Runtime/Streams/CMemoryStreamOut.hpp"
|
||||
#include "Runtime/CStringExtras.hpp"
|
||||
#include <logvisor/logvisor.hpp>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
@ -19,8 +23,7 @@ static const std::regex cmdLineRegex(R"(\+([\w\.]+)([=])?([\/\\\s\w\.\-]+)?)");
|
|||
CVarManager* CVarManager::m_instance = nullptr;
|
||||
|
||||
static logvisor::Module CVarLog("CVarManager");
|
||||
CVarManager::CVarManager(FileStoreManager& store, bool useBinary)
|
||||
: m_store(store), m_useBinary(useBinary) {
|
||||
CVarManager::CVarManager(FileStoreManager& store, bool useBinary) : m_store(store), m_useBinary(useBinary) {
|
||||
m_instance = this;
|
||||
com_configfile =
|
||||
newCVar("config", "File to store configuration", std::string("config"),
|
||||
|
@ -38,7 +41,7 @@ CVarManager::~CVarManager() {}
|
|||
|
||||
CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) {
|
||||
std::string tmp(cvar->name());
|
||||
CBasics::ToLower(tmp);
|
||||
CStringExtras::ToLower(tmp);
|
||||
|
||||
if (m_cvars.find(tmp) != m_cvars.end()) {
|
||||
return nullptr;
|
||||
|
@ -51,7 +54,7 @@ CVar* CVarManager::registerCVar(std::unique_ptr<CVar>&& cvar) {
|
|||
|
||||
CVar* CVarManager::findCVar(std::string_view name) {
|
||||
std::string lower(name);
|
||||
CBasics::ToLower(lower);
|
||||
CStringExtras::ToLower(lower);
|
||||
auto search = m_cvars.find(lower);
|
||||
if (search == m_cvars.end())
|
||||
return nullptr;
|
||||
|
@ -78,15 +81,14 @@ std::vector<CVar*> CVarManager::cvars(CVar::EFlags filter) const {
|
|||
}
|
||||
|
||||
void CVarManager::deserialize(CVar* cvar) {
|
||||
/* Make sure we're not trying to deserialize a CVar that is invalid or not exposed, unless it's been specified on the
|
||||
* command line (i.e deferred) */
|
||||
/* Make sure we're not trying to deserialize a CVar that is invalid*/
|
||||
if (!cvar) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* First let's check for a deferred value */
|
||||
std::string lowName = cvar->name().data();
|
||||
CBasics::ToLower(lowName);
|
||||
CStringExtras::ToLower(lowName);
|
||||
if (const auto iter = m_deferedCVars.find(lowName); iter != m_deferedCVars.end()) {
|
||||
std::string val = std::move(iter->second);
|
||||
m_deferedCVars.erase(lowName);
|
||||
|
@ -106,103 +108,89 @@ void CVarManager::deserialize(CVar* cvar) {
|
|||
if (!cvar->isArchive() && !cvar->isInternalArchivable()) {
|
||||
return;
|
||||
}
|
||||
#if 0 // TODO: Reimplement this
|
||||
/* We were either unable to find a deferred value or got an invalid value */
|
||||
std::string filename =
|
||||
std::string(m_store.getStoreRoot()) + '/' + com_configfile->toLiteral();
|
||||
CBascis::Sstat st;
|
||||
|
||||
if (m_useBinary) {
|
||||
CVarContainer container;
|
||||
filename += ".bin";
|
||||
if (CBascis::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
|
||||
return;
|
||||
athena::io::FileReader reader(filename);
|
||||
if (reader.isOpen())
|
||||
container.read(reader);
|
||||
|
||||
if (container.cvars.size() > 0) {
|
||||
auto serialized = std::find_if(container.cvars.begin(), container.cvars.end(),
|
||||
[&cvar](const DNACVAR::CVar& c) { return c.m_name == cvar->name(); });
|
||||
|
||||
if (serialized != container.cvars.end()) {
|
||||
DNACVAR::CVar& tmp = *serialized;
|
||||
|
||||
if (cvar->m_value != tmp.m_value) {
|
||||
std::string filename = std::string(m_store.getStoreRoot()) + '/' + com_configfile->toLiteral() + ".yaml";
|
||||
auto container = loadCVars(filename);
|
||||
auto serialized =
|
||||
std::find_if(container.cbegin(), container.cend(), [&cvar](const auto& c) { return c.m_name == cvar->name(); });
|
||||
if (serialized != container.cend()) {
|
||||
if (cvar->m_value != serialized->m_value) {
|
||||
CVarUnlocker lc(cvar);
|
||||
cvar->fromLiteralToType(tmp.m_value);
|
||||
cvar->fromLiteralToType(serialized->m_value);
|
||||
cvar->m_wasDeserialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filename += ".yaml";
|
||||
if (Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
|
||||
return;
|
||||
athena::io::FileReader reader(filename);
|
||||
if (reader.isOpen()) {
|
||||
athena::io::YAMLDocReader docReader;
|
||||
if (docReader.parse(&reader)) {
|
||||
std::unique_ptr<athena::io::YAMLNode> root = docReader.releaseRootNode();
|
||||
auto serialized = std::find_if(root->m_mapChildren.begin(), root->m_mapChildren.end(),
|
||||
[&cvar](const auto& c) { return c.first == cvar->name(); });
|
||||
|
||||
if (serialized != root->m_mapChildren.end()) {
|
||||
const std::unique_ptr<athena::io::YAMLNode>& tmp = serialized->second;
|
||||
|
||||
if (cvar->m_value != tmp->m_scalarString) {
|
||||
CVarUnlocker lc(cvar);
|
||||
cvar->fromLiteralToType(tmp->m_scalarString);
|
||||
cvar->m_wasDeserialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CVarManager::serialize() {
|
||||
#if 0 // TODO: reimplement this
|
||||
std::string filename =
|
||||
std::string(m_store.getStoreRoot()) + '/' + com_configfile->toLiteral();
|
||||
std::string filename = std::string(m_store.getStoreRoot()) + '/' + com_configfile->toLiteral() + ".yaml";
|
||||
|
||||
if (m_useBinary) {
|
||||
CVarContainer container;
|
||||
/* If we have an existing config load it in, so we can update it */
|
||||
auto container = loadCVars(filename);
|
||||
|
||||
u32 minLength = 0;
|
||||
for (const auto& pair : m_cvars) {
|
||||
const auto& cvar = pair.second;
|
||||
|
||||
if (cvar->isArchive() || (cvar->isInternalArchivable() && cvar->wasDeserialized() && !cvar->hasDefaultValue())) {
|
||||
container.cvars.push_back(*cvar);
|
||||
}
|
||||
}
|
||||
container.cvarCount = u32(container.cvars.size());
|
||||
|
||||
filename += ".bin";
|
||||
athena::io::FileWriter writer(filename);
|
||||
if (writer.isOpen())
|
||||
container.write(writer);
|
||||
/* Look for an existing CVar in the file... */
|
||||
auto serialized =
|
||||
std::find_if(container.begin(), container.end(), [&cvar](const auto& c) { return c.m_name == cvar->name(); });
|
||||
if (serialized != container.end()) {
|
||||
/* Found it! Update the value */
|
||||
serialized->m_value = cvar->value();
|
||||
} else {
|
||||
filename += ".yaml";
|
||||
|
||||
athena::io::FileReader r(filename);
|
||||
athena::io::YAMLDocWriter docWriter(r.isOpen() ? &r : nullptr);
|
||||
r.close();
|
||||
|
||||
docWriter.setStyle(athena::io::YAMLNodeStyle::Block);
|
||||
for (const auto& pair : m_cvars) {
|
||||
const auto& cvar = pair.second;
|
||||
|
||||
if (cvar->isArchive() || (cvar->isInternalArchivable() && cvar->wasDeserialized() && !cvar->hasDefaultValue())) {
|
||||
docWriter.writeString(cvar->name().data(), cvar->toLiteral());
|
||||
/* Store this value as a new CVar in the config */
|
||||
container.emplace_back(StoreCVar::CVar{std::string(cvar->name()), cvar->value()});
|
||||
}
|
||||
/* Compute length needed for this cvar */
|
||||
minLength += cvar->name().length() + cvar->value().length() + 2;
|
||||
}
|
||||
}
|
||||
|
||||
athena::io::FileWriter w(filename);
|
||||
if (w.isOpen())
|
||||
docWriter.finish(&w);
|
||||
// Allocate enough space to write all the strings with some space to spare
|
||||
const auto requiredLen = minLength + (4 * container.size());
|
||||
std::unique_ptr<u8[]> workBuf(new u8[requiredLen]);
|
||||
CMemoryStreamOut memOut(workBuf.get(), requiredLen);
|
||||
CTextOutStream textOut(memOut);
|
||||
for (const auto& cvar : container) {
|
||||
textOut.WriteString(fmt::format(FMT_STRING("{}: {}"), cvar.m_name, cvar.m_value));
|
||||
}
|
||||
#endif
|
||||
|
||||
auto* file = fopen(filename.c_str(), "wbe");
|
||||
if (file != nullptr) {
|
||||
fwrite(workBuf.get(), 1, memOut.GetWritePosition(), file);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
std::vector<StoreCVar::CVar> CVarManager::loadCVars(const std::string& filename) const {
|
||||
std::vector<StoreCVar::CVar> ret;
|
||||
CBasics::Sstat st;
|
||||
if (CBasics::Stat(filename.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
|
||||
|
||||
auto* file = fopen(filename.c_str(), "rbe");
|
||||
if (file != nullptr) {
|
||||
|
||||
std::unique_ptr<u8[]> inBuf(new u8[st.st_size]);
|
||||
fread(inBuf.get(), 1, st.st_size, file);
|
||||
fclose(file);
|
||||
CMemoryInStream mem(inBuf.get(), st.st_size, CMemoryInStream::EOwnerShip::NotOwned);
|
||||
CTextInStream textIn(mem, st.st_size);
|
||||
while (!textIn.IsEOF()) {
|
||||
auto cvString = textIn.GetNextLine();
|
||||
if (cvString.empty()) {
|
||||
continue;
|
||||
}
|
||||
auto parts = CStringExtras::Split(cvString, ':');
|
||||
if (parts.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
ret.emplace_back(StoreCVar::CVar{CStringExtras::Trim(parts[0]), CStringExtras::Trim(parts[1])});
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CVarManager* CVarManager::instance() { return m_instance; }
|
||||
|
@ -234,7 +222,7 @@ bool CVarManager::restartRequired() const {
|
|||
void CVarManager::parseCommandLine(const std::vector<std::string>& args) {
|
||||
bool oldDeveloper = suppressDeveloper();
|
||||
std::string developerName(com_developer->name());
|
||||
CBasics::ToLower(developerName);
|
||||
CStringExtras::ToLower(developerName);
|
||||
for (const std::string& arg : args) {
|
||||
if (arg[0] != '+') {
|
||||
continue;
|
||||
|
@ -267,13 +255,13 @@ void CVarManager::parseCommandLine(const std::vector<std::string>& args) {
|
|||
cv->fromLiteralToType(cvarValue);
|
||||
}
|
||||
cv->m_wasDeserialized = true;
|
||||
CBasics::ToLower(cvarName);
|
||||
CStringExtras::ToLower(cvarName);
|
||||
if (developerName == cvarName)
|
||||
/* Make sure we're not overriding developer mode when we restore */
|
||||
oldDeveloper = com_developer->toBoolean();
|
||||
} else {
|
||||
/* Unable to find an existing CVar, let's defer for the time being 8 */
|
||||
CBasics::ToLower(cvarName);
|
||||
CStringExtras::ToLower(cvarName);
|
||||
m_deferedCVars.insert_or_assign(std::move(cvarName), std::move(cvarValue));
|
||||
}
|
||||
}
|
||||
|
@ -303,4 +291,4 @@ void CVarManager::proc() {
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace hecl
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -102,12 +102,15 @@ public:
|
|||
|
||||
void parseCommandLine(const std::vector<std::string>& args);
|
||||
|
||||
FileStoreManager& fileStoreManager() { return m_store; }
|
||||
|
||||
private:
|
||||
bool suppressDeveloper();
|
||||
void restoreDeveloper(bool oldDeveloper);
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<CVar>> m_cvars;
|
||||
std::unordered_map<std::string, std::string> m_deferedCVars;
|
||||
std::vector<StoreCVar::CVar> loadCVars(const std::string& filename) const;
|
||||
};
|
||||
|
||||
} // namespace hecl
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "Runtime/CBasics.hpp"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
#if _WIN32
|
||||
#include <nowide/convert.hpp>
|
||||
|
@ -16,9 +17,19 @@ using namespace Windows::Storage;
|
|||
#endif
|
||||
|
||||
namespace metaforce {
|
||||
namespace {
|
||||
static logvisor::Module Log("FileStoreManager");
|
||||
FileStoreManager* g_instance = nullptr;
|
||||
}
|
||||
|
||||
FileStoreManager::FileStoreManager(std::string_view domain) : m_domain(domain) {
|
||||
FileStoreManager::FileStoreManager(std::string_view org, std::string_view domain) : m_org(org), m_domain(domain) {
|
||||
if (g_instance != nullptr) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("Attempting to build another FileStoreManager!!"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto prefPath = SDL_GetPrefPath(org.data(), domain.data());
|
||||
if (prefPath == nullptr) {
|
||||
#if _WIN32
|
||||
#if !WINDOWS_STORE
|
||||
WCHAR home[MAX_PATH];
|
||||
|
@ -30,7 +41,7 @@ FileStoreManager::FileStoreManager(std::string_view domain) : m_domain(domain) {
|
|||
StorageFolder ^ cacheFolder = ApplicationData::Current->LocalCacheFolder;
|
||||
std::string path(cacheFolder->Path->Data());
|
||||
#endif
|
||||
path += "/.heclrun";
|
||||
path += "/." + m_org;
|
||||
|
||||
CBasics::MakeDir(path.c_str());
|
||||
path += '/';
|
||||
|
@ -52,12 +63,23 @@ FileStoreManager::FileStoreManager(std::string_view domain) : m_domain(domain) {
|
|||
path = home;
|
||||
path += "/.local/share";
|
||||
}
|
||||
path += "/hecl/";
|
||||
path += domain.data();
|
||||
if (CBasics::RecursiveMakeDir(path.c_str()) != 0)
|
||||
path += "/" + m_org + "/" + domain.data();
|
||||
if (CBasics::RecursiveMakeDir(path.c_str()) != 0) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("unable to mkdir at {}"), path);
|
||||
}
|
||||
m_storeRoot = path;
|
||||
#endif
|
||||
} else {
|
||||
m_storeRoot = std::string(prefPath);
|
||||
}
|
||||
g_instance = this;
|
||||
}
|
||||
|
||||
FileStoreManager* FileStoreManager::instance() {
|
||||
if (g_instance == nullptr) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("Requested FileStoreManager instance before it's built!"));
|
||||
return nullptr;
|
||||
}
|
||||
return g_instance;
|
||||
}
|
||||
} // namespace hecl::Runtime
|
||||
|
|
|
@ -7,16 +7,23 @@ namespace metaforce {
|
|||
* @brief Per-platform file store resolution
|
||||
*/
|
||||
class FileStoreManager {
|
||||
std::string m_org;
|
||||
std::string m_domain;
|
||||
std::string m_storeRoot;
|
||||
|
||||
public:
|
||||
FileStoreManager(std::string_view domain);
|
||||
FileStoreManager(FileStoreManager&) = delete;
|
||||
FileStoreManager(FileStoreManager&&) = delete;
|
||||
void operator=(FileStoreManager&) = delete;
|
||||
void operator=(FileStoreManager&&) = delete;
|
||||
FileStoreManager(std::string_view org, std::string_view domain);
|
||||
std::string_view getOrg() const { return m_org; }
|
||||
std::string_view getDomain() const { return m_domain; }
|
||||
/**
|
||||
* @brief Returns the full path to the file store, including domain
|
||||
* @return Full path to store e.g /home/foo/.hecl/bar
|
||||
*/
|
||||
std::string_view getStoreRoot() const { return m_storeRoot; }
|
||||
static FileStoreManager* instance();
|
||||
};
|
||||
}
|
|
@ -263,7 +263,7 @@ static void RenderEntityColumns(const ImGuiEntityEntry& entry) {
|
|||
}
|
||||
|
||||
void ImGuiConsole::ShowInspectWindow(bool* isOpen) {
|
||||
float initialWindowSize = 400.f * ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
float initialWindowSize = 400.f * aurora::get_window_size().scale;
|
||||
ImGui::SetNextWindowSize(ImVec2{initialWindowSize, initialWindowSize * 1.5f}, ImGuiCond_FirstUseEver);
|
||||
|
||||
if (ImGui::Begin("Inspect", isOpen)) {
|
||||
|
@ -383,7 +383,7 @@ bool ImGuiConsole::ShowEntityInfoWindow(TUniqueId uid) {
|
|||
|
||||
void ImGuiConsole::ShowConsoleVariablesWindow() {
|
||||
// For some reason the window shows up tiny without this
|
||||
float initialWindowSize = 350.f * ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
float initialWindowSize = 350.f * aurora::get_window_size().scale;
|
||||
ImGui::SetNextWindowSize(ImVec2{initialWindowSize, initialWindowSize}, ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("Console Variables", &m_showConsoleVariablesWindow)) {
|
||||
if (ImGui::Button("Clear")) {
|
||||
|
@ -633,7 +633,7 @@ std::optional<std::string> ImGuiConsole::ShowAboutWindow(bool canClose, std::str
|
|||
flags |= ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove;
|
||||
}
|
||||
if (ImGui::Begin("About", open, flags)) {
|
||||
float iconSize = 128.f * ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
float iconSize = 128.f * aurora::get_window_size().scale;
|
||||
ImGui::SameLine(ImGui::GetWindowSize().x / 2 - iconSize + (iconSize / 2));
|
||||
ImGui::Image(ImGuiEngine::metaforceIcon, ImVec2{iconSize, iconSize});
|
||||
ImGui::PushFont(ImGuiEngine::fontLarge);
|
||||
|
@ -942,7 +942,7 @@ void ImGuiConsole::ShowInputViewer() {
|
|||
}
|
||||
ImGui::SetNextWindowBgAlpha(0.65f);
|
||||
if (ImGui::Begin("Input Overlay", nullptr, windowFlags)) {
|
||||
float scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
float scale = aurora::get_window_size().scale;
|
||||
if (!m_controllerName.empty()) {
|
||||
TextCenter(m_controllerName);
|
||||
ImGui::Separator();
|
||||
|
@ -1508,7 +1508,7 @@ void ImGuiConsole::ShowItemsWindow() {
|
|||
|
||||
void ImGuiConsole::ShowLayersWindow() {
|
||||
// For some reason the window shows up tiny without this
|
||||
float initialWindowSize = 350.f * ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
float initialWindowSize = 350.f * aurora::get_window_size().scale;
|
||||
ImGui::SetNextWindowSize(ImVec2{initialWindowSize, initialWindowSize}, ImGuiCond_FirstUseEver);
|
||||
|
||||
if (ImGui::Begin("Layers", &m_showLayersWindow)) {
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
#include "Runtime/ImGuiPlayerLoadouts.hpp"
|
||||
#include "Runtime/Streams/ContainerReaders.hpp"
|
||||
#include "Runtime/Streams/ContainerWriters.hpp"
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
#include "magic_enum.hpp"
|
||||
namespace metaforce {
|
||||
namespace {
|
||||
logvisor::Module Log("metaforce::ImGuiPlayerLoadouts");
|
||||
constexpr u32 CurrentVersion = 1;
|
||||
} // namespace
|
||||
ImGuiPlayerLoadouts::Item::Item(CInputStream& in)
|
||||
: type(magic_enum::enum_cast<CPlayerState::EItemType>(in.Get<std::string>()).value()), amount(in.ReadLong()) {}
|
||||
|
||||
void ImGuiPlayerLoadouts::Item::PutTo(COutputStream& out) const {
|
||||
out.Put(magic_enum::enum_name<CPlayerState::EItemType>(type));
|
||||
out.Put(amount);
|
||||
}
|
||||
ImGuiPlayerLoadouts::LoadOut::LoadOut(CInputStream& in) : name(in.Get<std::string>()) { read_vector(items, in); }
|
||||
|
||||
void ImGuiPlayerLoadouts::LoadOut::PutTo(COutputStream& out) const {
|
||||
out.Put(name);
|
||||
write_vector(items, out);
|
||||
}
|
||||
|
||||
ImGuiPlayerLoadouts::ImGuiPlayerLoadouts(CInputStream& in) {
|
||||
FourCC magic;
|
||||
in.Get(reinterpret_cast<u8*>(&magic), 4);
|
||||
auto version = in.ReadLong();
|
||||
if (magic != FOURCC('LOAD') && version != CurrentVersion) {
|
||||
Log.report(logvisor::Error, FMT_STRING("Incorrect loadout version, expected {} got {}"), CurrentVersion, version);
|
||||
return;
|
||||
}
|
||||
read_vector(loadouts, in);
|
||||
}
|
||||
void ImGuiPlayerLoadouts::PutTo(COutputStream& out) const {
|
||||
auto magic = FOURCC('LOAD');
|
||||
out.Put(reinterpret_cast<const u8*>(&magic), 4);
|
||||
out.Put(CurrentVersion);
|
||||
write_vector(loadouts, out);
|
||||
}
|
||||
} // namespace metaforce
|
|
@ -1,23 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <athena/DNA.hpp>
|
||||
#include <athena/DNAYaml.hpp>
|
||||
#include "Runtime/CPlayerState.hpp"
|
||||
|
||||
namespace metaforce {
|
||||
struct ImGuiPlayerLoadouts : athena::io::DNA<athena::Endian::Big> {
|
||||
AT_DECL_DNA_YAML
|
||||
struct Item : athena::io::DNA<athena::Endian::Big> {
|
||||
AT_DECL_DNA_YAML
|
||||
String<-1> type;
|
||||
Value<u32> amount;
|
||||
struct ImGuiPlayerLoadouts {
|
||||
struct Item {
|
||||
CPlayerState::EItemType type = CPlayerState::EItemType::Invalid;
|
||||
u32 amount = 0;
|
||||
Item() = default;
|
||||
explicit Item(CInputStream& in);
|
||||
void PutTo(COutputStream& out) const;
|
||||
};
|
||||
struct LoadOut : athena::io::DNA<athena::Endian::Big> {
|
||||
AT_DECL_DNA_YAML
|
||||
String<-1> name;
|
||||
Value<u32> itemCount;
|
||||
Vector<Item, AT_DNA_COUNT(itemCount)> items;
|
||||
struct LoadOut{
|
||||
std::string name;
|
||||
std::vector<Item> items;
|
||||
LoadOut() = default;
|
||||
explicit LoadOut(CInputStream& in);
|
||||
void PutTo(COutputStream& out) const;
|
||||
};
|
||||
Value<u32> loadoutCount;
|
||||
Vector<LoadOut, AT_DNA_COUNT(loadoutCount)> loadouts;
|
||||
std::vector<LoadOut> loadouts;
|
||||
|
||||
ImGuiPlayerLoadouts() = default;
|
||||
explicit ImGuiPlayerLoadouts(CInputStream& in);
|
||||
void PutTo(COutputStream& out) const;
|
||||
};
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -89,32 +89,36 @@ u32 CInputStream::ReadBytes(void* dest, u32 len) {
|
|||
return curReadLen;
|
||||
}
|
||||
|
||||
u32 CInputStream::ReadBits(u32 bitCount) {
|
||||
u32 ret = x20_bitOffset;
|
||||
if (ret < bitCount) {
|
||||
const u32 shiftAmt = bitCount - x20_bitOffset;
|
||||
const u32 mask = ret == 32 ? -1 : (1 << x20_bitOffset) - 1;
|
||||
|
||||
u32 uVar2 = x1c_bitWord;
|
||||
x20_bitOffset = 0;
|
||||
u32 len = min_containing_bytes(shiftAmt);
|
||||
Get(reinterpret_cast<u8*>(&x1c_bitWord), len);
|
||||
u32 CInputStream::ReadBits(u32 bitCount) {
|
||||
u32 ret = 0;
|
||||
const s32 shiftAmt = x20_bitOffset - s32(bitCount);
|
||||
if (shiftAmt < 0) {
|
||||
/* OR in remaining bits of cached value */
|
||||
u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
|
||||
ret |= (x1c_bitWord << u32(-shiftAmt)) & mask;
|
||||
/* Load in exact number of bytes remaining */
|
||||
auto loadDiv = std::div(-shiftAmt, 8);
|
||||
if (loadDiv.rem != 0) {
|
||||
++loadDiv.quot;
|
||||
}
|
||||
Get(reinterpret_cast<u8*>(&x1c_bitWord) + 4 - loadDiv.quot, loadDiv.quot);
|
||||
#if METAFORCE_TARGET_BYTE_ORDER == __ORDER_LITTLE_ENDIAN__
|
||||
x1c_bitWord = CBasics::SwapBytes(x1c_bitWord);
|
||||
#endif
|
||||
|
||||
const u32 retMask = shiftAmt == 32 ? -1 : (1 << shiftAmt) - 1;
|
||||
const u32 tmpOffset = x20_bitOffset;
|
||||
x20_bitOffset = len * 8;
|
||||
ret = ((mask & uVar2) >> (32 - ret) << shiftAmt) | (retMask & (x1c_bitWord >> (32 - shiftAmt))) << tmpOffset;
|
||||
x20_bitOffset -= shiftAmt;
|
||||
x1c_bitWord <<= shiftAmt;
|
||||
/* New bit offset */
|
||||
x20_bitOffset = loadDiv.quot * 8 + shiftAmt;
|
||||
/* OR in next bits */
|
||||
mask = (1U << u32(-shiftAmt)) - 1;
|
||||
ret |= (x1c_bitWord >> x20_bitOffset) & mask;
|
||||
} else {
|
||||
/* OR in bits of cached value */
|
||||
const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
|
||||
ret |= (x1c_bitWord >> u32(shiftAmt)) & mask;
|
||||
/* New bit offset */
|
||||
x20_bitOffset -= bitCount;
|
||||
ret = bitCount == 32 ? -1 : (1 << bitCount) - 1;
|
||||
ret &= x1c_bitWord >> (32 - bitCount);
|
||||
x1c_bitWord <<= bitCount;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ void CMemoryStreamOut::Write(const u8* ptr, u32 len) {
|
|||
|
||||
if (len != 0) {
|
||||
memcpy(x7c_ptr + x84_position, ptr, len);
|
||||
x84_position += len;
|
||||
}
|
||||
}
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -22,5 +22,6 @@ public:
|
|||
~CMemoryStreamOut() override;
|
||||
|
||||
void Write(const u8* ptr, u32 len) override;
|
||||
u32 GetWritePosition() const { return x84_position; }
|
||||
};
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -78,27 +78,27 @@ void COutputStream::Put(const u8* ptr, u32 len) {
|
|||
}
|
||||
|
||||
void COutputStream::WriteBits(u32 val, u32 bitCount) {
|
||||
const u32 bitOffset = x18_shiftRegisterOffset;
|
||||
if (x18_shiftRegisterOffset < bitCount) {
|
||||
const s32 shiftAmt = x18_shiftRegisterOffset - s32(bitCount);
|
||||
if (shiftAmt < 0) {
|
||||
/* OR remaining bits to cached value */
|
||||
const u32 shiftAmt = (bitCount - x18_shiftRegisterOffset);
|
||||
const u32 mask = bitOffset == 32 ? -1 : (1 << bitOffset) - 1;
|
||||
const u32 mask = (1U << x18_shiftRegisterOffset) - 1;
|
||||
x14_shiftRegister |= (val >> u32(-shiftAmt)) & mask;
|
||||
|
||||
/* Write out 32-bits */
|
||||
x14_shiftRegister |= (val >> shiftAmt) & mask;
|
||||
x18_shiftRegisterOffset = 0;
|
||||
FlushShiftRegister();
|
||||
|
||||
/* Cache remaining bits */
|
||||
x14_shiftRegister = (val & (shiftAmt == 32 ? -1 : (1 << shiftAmt) - 1)) << (32 - shiftAmt);
|
||||
x18_shiftRegisterOffset -= shiftAmt;
|
||||
x18_shiftRegisterOffset = 0x20 + shiftAmt;
|
||||
x14_shiftRegister = val << x18_shiftRegisterOffset;
|
||||
} else {
|
||||
/* OR bits to cached value */
|
||||
const u32 mask = bitOffset == 0x20 ? -1 : (1 << bitOffset) - 1;
|
||||
x14_shiftRegister |= (val & mask) << (bitOffset - bitCount);
|
||||
const u32 mask = bitCount == 32 ? UINT32_MAX : ((1U << bitCount) - 1);
|
||||
x14_shiftRegister |= (val & mask) << u32(shiftAmt);
|
||||
|
||||
/* New bit offset */
|
||||
x18_shiftRegisterOffset -= bitCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void COutputStream::WriteChar(u8 c) {
|
||||
|
@ -199,6 +199,14 @@ void coutput_stream_helper(const std::string& t, COutputStream& out) {
|
|||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void coutput_stream_helper(const std::string_view& t, COutputStream& out) {
|
||||
for (size_t i = 0; i < t.size() + 1; ++i) {
|
||||
out.FlushShiftRegister();
|
||||
out.Put(t[i]);
|
||||
}
|
||||
}
|
||||
|
||||
u32 COutputStream::GetBitCount(u32 val) {
|
||||
int bits = 0;
|
||||
for (; val != 0; val >>= 1) {
|
||||
|
|
|
@ -86,4 +86,6 @@ template <>
|
|||
void coutput_stream_helper(const double& t, COutputStream& out);
|
||||
template <>
|
||||
void coutput_stream_helper(const std::string& t, COutputStream& out);
|
||||
template <>
|
||||
void coutput_stream_helper(const std::string_view& t, COutputStream& out);
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#include "Runtime/Streams/CTextInStream.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace metaforce {
|
||||
CTextInStream::CTextInStream(CInputStream& in, int len) : m_in(&in), m_len(len) {}
|
||||
|
||||
std::string CTextInStream::GetNextLine() {
|
||||
std::string ret;
|
||||
while (true) {
|
||||
auto chr = m_in->ReadChar();
|
||||
ret += chr;
|
||||
if (ret.back() == '\r' || ret.back() == '\n') {
|
||||
if (ret.back() == '\r') {
|
||||
m_in->ReadChar();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret.erase(std::remove(ret.begin(), ret.end(), '\r'), ret.end());
|
||||
ret.erase(std::remove(ret.begin(), ret.end(), '\n'), ret.end());
|
||||
return ret;
|
||||
}
|
||||
} // namespace metaforce
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include "Runtime/Streams/CInputStream.hpp"
|
||||
|
||||
namespace metaforce {
|
||||
class CTextInStream {
|
||||
CInputStream* m_in;
|
||||
s32 m_len;
|
||||
|
||||
public:
|
||||
CTextInStream(CInputStream& in, int len);
|
||||
|
||||
bool IsEOF() { return m_in->GetReadPosition() >= m_len; }
|
||||
std::string GetNextLine();
|
||||
};
|
||||
} // namespace metaforce
|
|
@ -0,0 +1,30 @@
|
|||
#include "Runtime/Streams/CTextOutStream.hpp"
|
||||
|
||||
namespace metaforce {
|
||||
CTextOutStream::CTextOutStream(COutputStream& out) : m_out(&out) {}
|
||||
|
||||
void CTextOutStream::WriteString(const std::string& str) { CTextOutStream::WriteString(str.c_str(), str.length()); }
|
||||
void CTextOutStream::WriteString(const char* str, u32 len) {
|
||||
bool wroteCarriageReturn = false;
|
||||
bool wroteLineFeed = false;
|
||||
for (u32 i = 0; i < len; ++i) {
|
||||
if (str[i] == '\r') {
|
||||
wroteCarriageReturn = true;
|
||||
} else if (str[i] == '\n' && !wroteCarriageReturn) {
|
||||
m_out->WriteChar('\r');
|
||||
wroteLineFeed = true;
|
||||
wroteCarriageReturn = true;
|
||||
}
|
||||
m_out->WriteChar(str[i]);
|
||||
}
|
||||
|
||||
/* If we didn't write either a line feed or carriage return we need to do that now */
|
||||
if (!wroteCarriageReturn && !wroteLineFeed) {
|
||||
m_out->WriteChar('\r');
|
||||
m_out->WriteChar('\n');
|
||||
}
|
||||
|
||||
/* Since this is a text buffer, we always want to flush after writing a string */
|
||||
m_out->Flush();
|
||||
}
|
||||
} // namespace metaforce
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include "Runtime/Streams/COutputStream.hpp"
|
||||
|
||||
namespace metaforce {
|
||||
class CTextOutStream {
|
||||
COutputStream* m_out;
|
||||
|
||||
public:
|
||||
explicit CTextOutStream(COutputStream& out);
|
||||
|
||||
void WriteString(const std::string& str);
|
||||
void WriteString(const char* str, u32 len);
|
||||
};
|
||||
} // namespace metaforce
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "Runtime/Streams/CInputStream.hpp"
|
||||
#include "Runtime/rstl.hpp"
|
||||
|
||||
#include <vector>
|
||||
namespace metaforce {
|
||||
template <class T, size_t N>
|
||||
void read_reserved_vector(rstl::reserved_vector<T, N>& v, CInputStream& in) {
|
||||
|
@ -11,4 +12,13 @@ void read_reserved_vector(rstl::reserved_vector<T, N>& v, CInputStream& in) {
|
|||
v[i] = in.Get<T>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void read_vector(std::vector<T>& v, CInputStream& in) {
|
||||
u32 count = in.ReadLong();
|
||||
v.reserve(count);
|
||||
for (u32 i = 0; i < count; ++i) {
|
||||
v.emplace_back(in.Get<T>());
|
||||
}
|
||||
}
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "Runtime/Streams/COutputStream.hpp"
|
||||
#include "Runtime/rstl.hpp"
|
||||
#include <vector>
|
||||
namespace metaforce {
|
||||
template <class T, size_t N>
|
||||
void write_reserved_vector(const rstl::reserved_vector<T, N>& v, COutputStream& out) {
|
||||
out.Put(v.size());
|
||||
for (const auto& t : v) {
|
||||
out.Put(t);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write_vector(const std::vector<T>& v, COutputStream& out) {
|
||||
out.Put(v.size());
|
||||
for (const auto& t : v) {
|
||||
out.Put(t);
|
||||
}
|
||||
}
|
||||
} // namespace metaforce
|
|
@ -29,7 +29,7 @@ add_library(aurora STATIC
|
|||
lib/gfx/colored_quad/shader.cpp
|
||||
)
|
||||
target_compile_definitions(aurora PRIVATE IMGUI_USER_CONFIG="imconfig_user.h") # IMGUI_USE_WCHAR32
|
||||
target_include_directories(aurora PUBLIC include ../Runtime)
|
||||
target_include_directories(aurora PUBLIC include ../ )
|
||||
target_include_directories(aurora PRIVATE ../imgui ../extern/imgui)
|
||||
target_include_directories(aurora PRIVATE
|
||||
../extern/dawn/src
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
||||
#include "RetroTypes.hpp"
|
||||
#include "Runtime/RetroTypes.hpp"
|
||||
|
||||
namespace aurora {
|
||||
template <typename T>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "gpu.hpp"
|
||||
|
||||
#include "Runtime/ConsoleVariables/FileStoreManager.hpp"
|
||||
#include <SDL.h>
|
||||
#include <aurora/aurora.hpp>
|
||||
#include <aurora/imgui.hpp>
|
||||
|
@ -16,11 +17,16 @@ using gpu::g_queue;
|
|||
|
||||
static float g_scale;
|
||||
|
||||
static std::string g_imguiSettings{};
|
||||
static std::string g_imguiLog{};
|
||||
void create_context() noexcept {
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
g_imguiSettings = std::string(metaforce::FileStoreManager::instance()->getStoreRoot()) + "/imgui.ini";
|
||||
g_imguiLog = std::string(metaforce::FileStoreManager::instance()->getStoreRoot()) + "/imgui.log";
|
||||
io.IniFilename = g_imguiSettings.c_str();
|
||||
io.LogFilename = g_imguiLog.c_str();
|
||||
}
|
||||
|
||||
void initialize(SDL_Window* window) noexcept {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 72893dcacb02ebff11b354832c55f3763ab523b7
|
||||
Subproject commit 258076c2986f2d77d887a8405f1194405bb4b99d
|
Loading…
Reference in New Issue