mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Launcher: light overhaul and use KeyValues class
Reworked some of the code to make globals static and used KeyValues class to parse VDF files instead.
This commit is contained in:
parent
2c5e272c30
commit
890ffa923e
@ -70,29 +70,6 @@ NVIDIA NvAPI
|
||||
// the above Disclaimer (as applicable) and U.S. Government End Users Notice.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
************************************************************************************
|
||||
Recast & Detour
|
||||
************************************************************************************
|
||||
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
************************************************************************************
|
||||
Google protocol buffers
|
||||
************************************************************************************
|
||||
@ -131,6 +108,29 @@ Google protocol buffers
|
||||
// support library is itself covered by the above license.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
************************************************************************************
|
||||
Recast & Detour
|
||||
************************************************************************************
|
||||
|
||||
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
************************************************************************************
|
||||
Dear ImGui
|
||||
************************************************************************************
|
||||
@ -299,33 +299,6 @@ Format {fmt}
|
||||
// without including the above copyright and permission notices.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
************************************************************************************
|
||||
VDF Parser
|
||||
************************************************************************************
|
||||
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Matthias Moeller 2016 m_moeller@live.de
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
************************************************************************************
|
||||
RapidJSON
|
||||
************************************************************************************
|
||||
@ -788,6 +761,7 @@ LZHAM
|
||||
// THE SOFTWARE.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
************************************************************************************
|
||||
CRC32
|
||||
************************************************************************************
|
||||
|
@ -1,711 +0,0 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright(c) 2016 Matthias Moeller
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files(the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions :
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
#ifndef __TYTI_STEAM_VDF_PARSER_H__
|
||||
#define __TYTI_STEAM_VDF_PARSER_H__
|
||||
#pragma warning( disable : 4996 )
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
|
||||
#include <system_error>
|
||||
#include <exception>
|
||||
|
||||
//for wstring support
|
||||
#include <locale>
|
||||
#include <string>
|
||||
|
||||
// internal
|
||||
#include <stack>
|
||||
|
||||
//VS < 2015 has only partial C++11 support
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#ifndef CONSTEXPR
|
||||
#define CONSTEXPR
|
||||
#endif
|
||||
|
||||
#ifndef NOEXCEPT
|
||||
#define NOEXCEPT
|
||||
#endif
|
||||
#else
|
||||
#ifndef CONSTEXPR
|
||||
#define CONSTEXPR constexpr
|
||||
#define TYTI_UNDEF_CONSTEXPR
|
||||
#endif
|
||||
|
||||
#ifndef NOEXCEPT
|
||||
#define NOEXCEPT noexcept
|
||||
#define TYTI_UNDEF_NOEXCEPT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
namespace vdf
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions selecting the right encoding (char/wchar_T)
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T>
|
||||
struct literal_macro_help
|
||||
{
|
||||
static CONSTEXPR const char* result(const char* c, const wchar_t*) NOEXCEPT
|
||||
{
|
||||
return c;
|
||||
}
|
||||
static CONSTEXPR const char result(const char c, const wchar_t) NOEXCEPT
|
||||
{
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct literal_macro_help<wchar_t>
|
||||
{
|
||||
static CONSTEXPR const wchar_t* result(const char*, const wchar_t* wc) NOEXCEPT
|
||||
{
|
||||
return wc;
|
||||
}
|
||||
static CONSTEXPR const wchar_t result(const char, const wchar_t wc) NOEXCEPT
|
||||
{
|
||||
return wc;
|
||||
}
|
||||
};
|
||||
#define TYTI_L(type, text) vdf::detail::literal_macro_help<type>::result(text, L##text)
|
||||
|
||||
inline std::string string_converter(const std::string& w) NOEXCEPT
|
||||
{
|
||||
return w;
|
||||
}
|
||||
|
||||
// utility wrapper to adapt locale-bound facets for wstring/wbuffer convert
|
||||
// from cppreference
|
||||
template <class Facet>
|
||||
struct deletable_facet : Facet
|
||||
{
|
||||
template <class... Args>
|
||||
deletable_facet(Args &&... args) : Facet(std::forward<Args>(args)...) {}
|
||||
~deletable_facet() {}
|
||||
};
|
||||
|
||||
inline std::string string_converter(const std::wstring& w) //todo: use us-locale
|
||||
{
|
||||
std::wstring_convert<deletable_facet<std::codecvt<wchar_t, char, std::mbstate_t>>> conv1;
|
||||
return conv1.to_bytes(w);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Writer helper functions
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename charT>
|
||||
class tabs
|
||||
{
|
||||
const size_t t;
|
||||
|
||||
public:
|
||||
explicit CONSTEXPR tabs(size_t i) NOEXCEPT : t(i) {}
|
||||
std::basic_string<charT> print() const { return std::basic_string<charT>(t, TYTI_L(charT, '\t')); }
|
||||
inline CONSTEXPR tabs operator+(size_t i) const NOEXCEPT
|
||||
{
|
||||
return tabs(t + i);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename oStreamT>
|
||||
oStreamT& operator<<(oStreamT& s, const tabs<typename oStreamT::char_type> t)
|
||||
{
|
||||
s << t.print();
|
||||
return s;
|
||||
}
|
||||
} // end namespace detail
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Interface
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// custom objects and their corresponding write functions
|
||||
|
||||
/// basic object node. Every object has a name and can contains attributes saved as key_value pairs or childrens
|
||||
template <typename CharT>
|
||||
struct basic_object
|
||||
{
|
||||
typedef CharT char_type;
|
||||
std::basic_string<char_type> name;
|
||||
std::unordered_map<std::basic_string<char_type>, std::basic_string<char_type>> attribs;
|
||||
std::unordered_map<std::basic_string<char_type>, std::shared_ptr<basic_object<char_type>>> childs;
|
||||
|
||||
void add_attribute(std::basic_string<char_type> key, std::basic_string<char_type> value)
|
||||
{
|
||||
attribs.emplace(std::move(key), std::move(value));
|
||||
}
|
||||
void add_child(std::unique_ptr<basic_object<char_type>> child)
|
||||
{
|
||||
std::shared_ptr<basic_object<char_type>> obj{ child.release() };
|
||||
childs.emplace(obj->name, obj);
|
||||
}
|
||||
void set_name(std::basic_string<char_type> n)
|
||||
{
|
||||
name = std::move(n);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
struct basic_multikey_object
|
||||
{
|
||||
typedef CharT char_type;
|
||||
std::basic_string<char_type> name;
|
||||
std::unordered_multimap<std::basic_string<char_type>, std::basic_string<char_type>> attribs;
|
||||
std::unordered_multimap<std::basic_string<char_type>, std::shared_ptr<basic_multikey_object<char_type>>> childs;
|
||||
|
||||
void add_attribute(std::basic_string<char_type> key, std::basic_string<char_type> value)
|
||||
{
|
||||
attribs.emplace(std::move(key), std::move(value));
|
||||
}
|
||||
void add_child(std::unique_ptr<basic_multikey_object<char_type>> child)
|
||||
{
|
||||
std::shared_ptr<basic_multikey_object<char_type>> obj{ child.release() };
|
||||
childs.emplace(obj->name, obj);
|
||||
}
|
||||
void set_name(std::basic_string<char_type> n)
|
||||
{
|
||||
name = std::move(n);
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_object<char> object;
|
||||
typedef basic_object<wchar_t> wobject;
|
||||
typedef basic_multikey_object<char> multikey_object;
|
||||
typedef basic_multikey_object<wchar_t> wmultikey_object;
|
||||
|
||||
struct Options
|
||||
{
|
||||
bool strip_escape_symbols;
|
||||
bool ignore_all_platform_conditionals;
|
||||
bool ignore_includes;
|
||||
|
||||
Options() : strip_escape_symbols(true), ignore_all_platform_conditionals(false), ignore_includes(false) {}
|
||||
};
|
||||
|
||||
//forward decls
|
||||
template <typename OutputT, typename iStreamT>
|
||||
OutputT read(iStreamT& inStream, const Options& opt = Options{});
|
||||
|
||||
/** \brief writes given object tree in vdf format to given stream.
|
||||
Output is prettyfied, using tabs
|
||||
*/
|
||||
template <typename oStreamT, typename T>
|
||||
void write(oStreamT& s, const T& r,
|
||||
const detail::tabs<typename oStreamT::char_type> tab = detail::tabs<typename oStreamT::char_type>(0))
|
||||
{
|
||||
typedef typename oStreamT::char_type charT;
|
||||
using namespace detail;
|
||||
s << tab << TYTI_L(charT, '"') << r.name << TYTI_L(charT, "\"\n") << tab << TYTI_L(charT, "{\n");
|
||||
for (const auto& i : r.attribs)
|
||||
s << tab + 1 << TYTI_L(charT, '"') << i.first << TYTI_L(charT, "\"\t\t\"") << i.second << TYTI_L(charT, "\"\n");
|
||||
for (const auto& i : r.childs)
|
||||
if (i.second)
|
||||
write(s, *i.second, tab + 1);
|
||||
s << tab << TYTI_L(charT, "}\n");
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename iStreamT>
|
||||
std::basic_string<typename iStreamT::char_type> read_file(iStreamT& inStream)
|
||||
{
|
||||
// cache the file
|
||||
typedef typename iStreamT::char_type charT;
|
||||
std::basic_string<charT> str;
|
||||
inStream.seekg(0, std::ios::end);
|
||||
str.resize(static_cast<size_t>(inStream.tellg()));
|
||||
if (str.empty())
|
||||
return str;
|
||||
|
||||
inStream.seekg(0, std::ios::beg);
|
||||
inStream.read(&str[0], str.size());
|
||||
return str;
|
||||
}
|
||||
|
||||
/** \brief Read VDF formatted sequences defined by the range [first, last).
|
||||
If the file is malformed, parser will read the file until no longer possible.
|
||||
@param first begin iterator
|
||||
@param end end iterator
|
||||
@param exclude_files list of files which cant be included anymore.
|
||||
prevents circular includes
|
||||
|
||||
can throw:
|
||||
- "std::runtime_error" if a parsing error occured
|
||||
- "std::bad_alloc" if not enough memory could be allocated
|
||||
*/
|
||||
template <typename OutputT, typename IterT>
|
||||
std::vector<std::unique_ptr<OutputT>> read_internal(IterT first, const IterT last,
|
||||
std::unordered_set<std::basic_string<typename std::iterator_traits<IterT>::value_type>>& exclude_files,
|
||||
const Options& opt)
|
||||
{
|
||||
static_assert(std::is_default_constructible<OutputT>::value,
|
||||
"Output Type must be default constructible (provide constructor without arguments)");
|
||||
static_assert(std::is_move_constructible<OutputT>::value,
|
||||
"Output Type must be move constructible");
|
||||
|
||||
typedef typename std::iterator_traits<IterT>::value_type charT;
|
||||
|
||||
const std::basic_string<charT> comment_end_str = TYTI_L(charT, "*/");
|
||||
const std::basic_string<charT> whitespaces = TYTI_L(charT, " \n\v\f\r\t");
|
||||
|
||||
#ifdef WIN32
|
||||
std::function<bool(const std::basic_string<charT>&)> is_platform_str = [](const std::basic_string<charT>& in) {
|
||||
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$WINDOWS");
|
||||
};
|
||||
#elif __APPLE__
|
||||
// WIN32 stands for pc in general
|
||||
std::function<bool(const std::basic_string<charT>&)> is_platform_str = [](const std::basic_string<charT>& in) {
|
||||
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") || in == TYTI_L(charT, "$OSX");
|
||||
};
|
||||
|
||||
#elif __linux__
|
||||
// WIN32 stands for pc in general
|
||||
std::function<bool(const std::basic_string<charT>&)> is_platform_str = [](const std::basic_string<charT>& in) {
|
||||
return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") || in == TYTI_L(charT, "$LINUX");
|
||||
};
|
||||
#else
|
||||
std::function<bool(const std::basic_string<charT>&)> is_platform_str = [](const std::basic_string<charT>& in) {
|
||||
return false;
|
||||
};
|
||||
#endif
|
||||
|
||||
if (opt.ignore_all_platform_conditionals)
|
||||
is_platform_str = [](const std::basic_string<charT>&) {
|
||||
return false;
|
||||
};
|
||||
|
||||
// function for skipping a comment block
|
||||
// iter: itterate position past a '/' character
|
||||
auto skip_comments = [&comment_end_str](IterT iter, const IterT& last) -> IterT {
|
||||
++iter;
|
||||
if (iter != last)
|
||||
{
|
||||
if (*iter == TYTI_L(charT, '/'))
|
||||
{
|
||||
// line comment, skip whole line
|
||||
iter = std::find(iter + 1, last, TYTI_L(charT, '\n'));
|
||||
}
|
||||
|
||||
if (*iter == '*')
|
||||
{
|
||||
// block comment, skip until next occurance of "*\"
|
||||
iter = std::search(iter + 1, last, std::begin(comment_end_str), std::end(comment_end_str));
|
||||
iter += 2;
|
||||
}
|
||||
}
|
||||
return iter;
|
||||
};
|
||||
|
||||
auto end_quote = [](IterT iter, const IterT& last) -> IterT {
|
||||
const auto begin = iter;
|
||||
auto last_esc = iter;
|
||||
do
|
||||
{
|
||||
++iter;
|
||||
iter = std::find(iter, last, TYTI_L(charT, '\"'));
|
||||
if (iter == last)
|
||||
break;
|
||||
|
||||
last_esc = std::prev(iter);
|
||||
while (last_esc != begin && *last_esc == '\\')
|
||||
--last_esc;
|
||||
} while (!(std::distance(last_esc, iter) % 2));
|
||||
if (iter == last)
|
||||
throw std::runtime_error{ "Quote was opened but never closed" };
|
||||
return iter;
|
||||
};
|
||||
|
||||
auto end_word = [&whitespaces](IterT iter, const IterT& last) -> IterT {
|
||||
const auto begin = iter;
|
||||
auto last_esc = iter;
|
||||
do
|
||||
{
|
||||
++iter;
|
||||
iter = std::find_first_of(iter, last, std::begin(whitespaces), std::end(whitespaces));
|
||||
if (iter == last)
|
||||
break;
|
||||
|
||||
last_esc = std::prev(iter);
|
||||
while (last_esc != begin && *last_esc == '\\')
|
||||
--last_esc;
|
||||
} while (!(std::distance(last_esc, iter) % 2));
|
||||
//if (iter == last)
|
||||
// throw std::runtime_error{ "Word wasn't properly ended" };
|
||||
return iter;
|
||||
};
|
||||
|
||||
auto skip_whitespaces = [&whitespaces](IterT iter, const IterT& last) -> IterT {
|
||||
iter = std::find_if_not(iter, last, [&whitespaces](charT c) {
|
||||
// return true if whitespace
|
||||
return std::any_of(std::begin(whitespaces), std::end(whitespaces), [c](charT pc) { return pc == c; });
|
||||
});
|
||||
return iter;
|
||||
};
|
||||
|
||||
std::function<void(std::basic_string<charT>&)> strip_escape_symbols = [](std::basic_string<charT>& s) {
|
||||
auto quote_searcher = [&s](size_t pos) { return s.find(TYTI_L(charT, "\\\""), pos); };
|
||||
auto p = quote_searcher(0);
|
||||
while (p != s.npos)
|
||||
{
|
||||
s.replace(p, 2, TYTI_L(charT, "\""));
|
||||
p = quote_searcher(p);
|
||||
}
|
||||
auto searcher = [&s](size_t pos) { return s.find(TYTI_L(charT, "\\\\"), pos); };
|
||||
p = searcher(0);
|
||||
while (p != s.npos)
|
||||
{
|
||||
s.replace(p, 2, TYTI_L(charT, "\\"));
|
||||
p = searcher(p);
|
||||
}
|
||||
};
|
||||
|
||||
if (!opt.strip_escape_symbols)
|
||||
strip_escape_symbols = [](std::basic_string<charT>&) {};
|
||||
|
||||
auto conditional_fullfilled = [&skip_whitespaces, &is_platform_str](IterT& iter, const IterT& last) {
|
||||
iter = skip_whitespaces(iter, last);
|
||||
if (*iter == '[')
|
||||
{
|
||||
++iter;
|
||||
const auto end = std::find(iter, last, ']');
|
||||
const bool negate = *iter == '!';
|
||||
if (negate)
|
||||
++iter;
|
||||
auto conditional = std::basic_string<charT>(iter, end);
|
||||
|
||||
const bool is_platform = is_platform_str(conditional);
|
||||
iter = end + 1;
|
||||
|
||||
return static_cast<bool>(is_platform ^ negate);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
//read header
|
||||
// first, quoted name
|
||||
std::unique_ptr<OutputT> curObj = nullptr;
|
||||
std::vector<std::unique_ptr<OutputT>> roots;
|
||||
std::stack<std::unique_ptr<OutputT>> lvls;
|
||||
auto curIter = first;
|
||||
|
||||
while (curIter != last && *curIter != '\0')
|
||||
{
|
||||
//find first starting attrib/child, or ending
|
||||
curIter = skip_whitespaces(curIter, last);
|
||||
if (curIter == last || *curIter == '\0')
|
||||
break;
|
||||
if (*curIter == TYTI_L(charT, '/'))
|
||||
{
|
||||
curIter = skip_comments(curIter, last);
|
||||
}
|
||||
else if (*curIter != TYTI_L(charT, '}'))
|
||||
{
|
||||
|
||||
// get key
|
||||
const auto keyEnd = (*curIter == TYTI_L(charT, '\"')) ? end_quote(curIter, last) : end_word(curIter, last);
|
||||
if (*curIter == TYTI_L(charT, '\"'))
|
||||
++curIter;
|
||||
std::basic_string<charT> key(curIter, keyEnd);
|
||||
strip_escape_symbols(key);
|
||||
curIter = keyEnd + ((*keyEnd == TYTI_L(charT, '\"')) ? 1 : 0);
|
||||
|
||||
curIter = skip_whitespaces(curIter, last);
|
||||
|
||||
auto conditional_key = conditional_fullfilled(curIter, last);
|
||||
if (!conditional_key)
|
||||
continue;
|
||||
|
||||
while (*curIter == TYTI_L(charT, '/'))
|
||||
{
|
||||
|
||||
curIter = skip_comments(curIter, last);
|
||||
if (curIter == last || *curIter == '}')
|
||||
throw std::runtime_error{ "Key declared without value" };
|
||||
curIter = skip_whitespaces(curIter, last);
|
||||
if (curIter == last || *curIter == '}')
|
||||
throw std::runtime_error{ "Key declared without value" };
|
||||
}
|
||||
// get value
|
||||
if (*curIter != '{')
|
||||
{
|
||||
const auto valueEnd = (*curIter == TYTI_L(charT, '\"')) ? end_quote(curIter, last) : end_word(curIter, last);
|
||||
if (*curIter == TYTI_L(charT, '\"'))
|
||||
++curIter;
|
||||
|
||||
auto value = std::basic_string<charT>(curIter, valueEnd);
|
||||
strip_escape_symbols(value);
|
||||
curIter = valueEnd + ((*valueEnd == TYTI_L(charT, '\"')) ? 1 : 0);
|
||||
|
||||
auto conditional_value = conditional_fullfilled(curIter, last);
|
||||
if (!conditional_value)
|
||||
continue;
|
||||
|
||||
// process value
|
||||
if (curObj && key != TYTI_L(charT, "#include") && key != TYTI_L(charT, "#base"))
|
||||
{
|
||||
curObj->add_attribute(std::move(key), std::move(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!opt.ignore_includes && exclude_files.find(value) == exclude_files.end())
|
||||
{
|
||||
exclude_files.insert(value);
|
||||
std::basic_ifstream<charT> i(detail::string_converter(value));
|
||||
auto str = read_file(i);
|
||||
auto file_objs = read_internal<OutputT>(str.begin(), str.end(), exclude_files, opt);
|
||||
for (auto& n : file_objs)
|
||||
{
|
||||
if (curObj)
|
||||
curObj->add_child(std::move(n));
|
||||
else
|
||||
roots.push_back(std::move(n));
|
||||
}
|
||||
exclude_files.erase(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*curIter == '{')
|
||||
{
|
||||
if (curObj)
|
||||
lvls.push(std::move(curObj));
|
||||
curObj = std::make_unique<OutputT>();
|
||||
curObj->set_name(std::move(key));
|
||||
++curIter;
|
||||
}
|
||||
}
|
||||
//end of new object
|
||||
else if (*curIter == TYTI_L(charT, '}'))
|
||||
{
|
||||
if (!lvls.empty())
|
||||
{
|
||||
//get object before
|
||||
std::unique_ptr<OutputT> prev{ std::move(lvls.top()) };
|
||||
lvls.pop();
|
||||
|
||||
// add finished obj to obj before and release it from processing
|
||||
prev->add_child(std::move(curObj));
|
||||
curObj = std::move(prev);
|
||||
}
|
||||
else
|
||||
{
|
||||
roots.push_back(std::move(curObj));
|
||||
curObj.reset();
|
||||
}
|
||||
++curIter;
|
||||
}
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** \brief Read VDF formatted sequences defined by the range [first, last).
|
||||
If the file is malformed, parser will read the file until no longer possible.
|
||||
@param first begin iterator
|
||||
@param end end iterator
|
||||
|
||||
can thow:
|
||||
- "std::runtime_error" if a parsing error occurred
|
||||
- "std::bad_alloc" if not enough memory coup be allocated
|
||||
*/
|
||||
template <typename OutputT, typename IterT>
|
||||
OutputT read(IterT first, const IterT last, const Options& opt = Options{})
|
||||
{
|
||||
auto exclude_files = std::unordered_set<std::basic_string<typename std::iterator_traits<IterT>::value_type>>{};
|
||||
auto roots = detail::read_internal<OutputT>(first, last, exclude_files, opt);
|
||||
|
||||
OutputT result;
|
||||
if (roots.size() > 1)
|
||||
{
|
||||
for (auto& i : roots)
|
||||
result.add_child(std::move(i));
|
||||
}
|
||||
else if (roots.size() == 1)
|
||||
result = std::move(*roots[0]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** \brief Read VDF formatted sequences defined by the range [first, last).
|
||||
If the file is malformed, parser will read the file until no longer possible.
|
||||
@param first begin iterator
|
||||
@param end end iterator
|
||||
@param ec output bool. 0 if ok, otherwise, holds an system error code
|
||||
|
||||
Possible error codes:
|
||||
std::errc::protocol_error: file is malformed
|
||||
std::errc::not_enough_memory: not enough space
|
||||
std::errc::invalid_argument: iterators throws e.g. out of range
|
||||
*/
|
||||
template <typename OutputT, typename IterT>
|
||||
OutputT read(IterT first, IterT last, std::error_code& ec, const Options& opt = Options{}) NOEXCEPT
|
||||
|
||||
{
|
||||
ec.clear();
|
||||
OutputT r{};
|
||||
try
|
||||
{
|
||||
r = read<OutputT>(first, last, opt);
|
||||
}
|
||||
catch (std::runtime_error&)
|
||||
{
|
||||
ec = std::make_error_code(std::errc::protocol_error);
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
{
|
||||
ec = std::make_error_code(std::errc::not_enough_memory);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ec = std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** \brief Read VDF formatted sequences defined by the range [first, last).
|
||||
If the file is malformed, parser will read the file until no longer possible.
|
||||
@param first begin iterator
|
||||
@param end end iterator
|
||||
@param ok output bool. true, if parser successed, false, if parser failed
|
||||
*/
|
||||
template <typename OutputT, typename IterT>
|
||||
OutputT read(IterT first, const IterT last, bool* ok, const Options& opt = Options{}) NOEXCEPT
|
||||
{
|
||||
std::error_code ec;
|
||||
auto r = read<OutputT>(first, last, ec, opt);
|
||||
if (ok)
|
||||
*ok = !ec;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
inline auto read(IterT first, const IterT last, bool* ok, const Options& opt = Options{}) NOEXCEPT -> basic_object<typename std::iterator_traits<IterT>::value_type>
|
||||
{
|
||||
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(first, last, ok, opt);
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
inline auto read(IterT first, IterT last, std::error_code& ec, const Options& opt = Options{}) NOEXCEPT
|
||||
-> basic_object<typename std::iterator_traits<IterT>::value_type>
|
||||
{
|
||||
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(first, last, ec, opt);
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
inline auto read(IterT first, const IterT last, const Options& opt = Options{})
|
||||
-> basic_object<typename std::iterator_traits<IterT>::value_type>
|
||||
{
|
||||
return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(first, last, opt);
|
||||
}
|
||||
|
||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
||||
throws "std::bad_alloc" if file buffer could not be allocated
|
||||
*/
|
||||
template <typename OutputT, typename iStreamT>
|
||||
OutputT read(iStreamT& inStream, std::error_code& ec, const Options& opt = Options{})
|
||||
{
|
||||
// cache the file
|
||||
typedef typename iStreamT::char_type charT;
|
||||
std::basic_string<charT> str = detail::read_file(inStream);
|
||||
|
||||
// parse it
|
||||
return read<OutputT>(str.begin(), str.end(), ec, opt);
|
||||
}
|
||||
|
||||
template <typename iStreamT>
|
||||
inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, std::error_code& ec, const Options& opt = Options{})
|
||||
{
|
||||
return read<basic_object<typename iStreamT::char_type>>(inStream, ec, opt);
|
||||
}
|
||||
|
||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
||||
throws "std::bad_alloc" if file buffer could not be allocated
|
||||
ok == false, if a parsing error occured
|
||||
*/
|
||||
template <typename OutputT, typename iStreamT>
|
||||
OutputT read(iStreamT& inStream, bool* ok, const Options& opt = Options{})
|
||||
{
|
||||
std::error_code ec;
|
||||
const auto r = read<OutputT>(inStream, ec, opt);
|
||||
if (ok)
|
||||
*ok = !ec;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename iStreamT>
|
||||
inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, bool* ok, const Options& opt = Options{})
|
||||
{
|
||||
return read<basic_object<typename iStreamT::char_type>>(inStream, ok, opt);
|
||||
}
|
||||
|
||||
/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf formatted data.
|
||||
throws "std::bad_alloc" if file buffer could not be allocated
|
||||
throws "std::runtime_error" if a parsing error occured
|
||||
*/
|
||||
template <typename OutputT, typename iStreamT>
|
||||
OutputT read(iStreamT& inStream, const Options& opt)
|
||||
{
|
||||
|
||||
// cache the file
|
||||
typedef typename iStreamT::char_type charT;
|
||||
std::basic_string<charT> str = detail::read_file(inStream);
|
||||
// parse it
|
||||
return read<OutputT>(str.begin(), str.end(), opt);
|
||||
}
|
||||
|
||||
template <typename iStreamT>
|
||||
inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, const Options& opt = Options{})
|
||||
{
|
||||
return read<basic_object<typename iStreamT::char_type>>(inStream, opt);
|
||||
}
|
||||
|
||||
} // namespace vdf
|
||||
|
||||
#ifndef TYTI_NO_L_UNDEF
|
||||
#undef TYTI_L
|
||||
#endif
|
||||
|
||||
#ifdef TYTI_UNDEF_CONSTEXPR
|
||||
#undef CONSTEXPR
|
||||
#undef TYTI_NO_L_UNDEF
|
||||
#endif
|
||||
|
||||
#ifdef TYTI_UNDEF_NOTHROW
|
||||
#undef NOTHROW
|
||||
#undef TYTI_UNDEF_NOTHROW
|
||||
#endif
|
||||
|
||||
#endif //__TYTI_STEAM_VDF_PARSER_H__
|
@ -38,6 +38,9 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
|
||||
"tier0"
|
||||
"tier1"
|
||||
|
||||
"filesystem_std"
|
||||
"vstdlib"
|
||||
|
||||
"libdetours"
|
||||
"libcppkore"
|
||||
"libspdlog"
|
||||
|
@ -6,7 +6,10 @@
|
||||
#include "basepanel.h"
|
||||
#include "sdklauncher.h"
|
||||
#include "mathlib/bits.h"
|
||||
#include "utility/vdf_parser.h"
|
||||
#include "vstdlib/keyvaluessystem.h"
|
||||
#include "filesystem/filesystem_std.h"
|
||||
|
||||
extern CFileSystem_Stdio* FileSystem();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: creates the surface layout
|
||||
@ -494,6 +497,8 @@ void CSurface::Init()
|
||||
this->PerformLayout();
|
||||
|
||||
// END DESIGNER CODE
|
||||
|
||||
this->Setup();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -522,97 +527,60 @@ void CSurface::Setup()
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSurface::LoadSettings()
|
||||
{
|
||||
const fs::path settingsPath(Format("platform/%s/%s", SDK_SYSTEM_CFG_PATH, LAUNCHER_SETTING_FILE));
|
||||
if (!fs::exists(settingsPath))
|
||||
CUtlString settingsPath;
|
||||
settingsPath.Format("platform/" SDK_SYSTEM_CFG_PATH "%s", LAUNCHER_SETTING_FILE);
|
||||
|
||||
const char* pSettingsPath = settingsPath.String();
|
||||
|
||||
if (!FileSystem()->FileExists(pSettingsPath))
|
||||
return;
|
||||
|
||||
KeyValues kv("LauncherSettings");
|
||||
|
||||
if (!kv.LoadFromFile(FileSystem(), pSettingsPath, nullptr))
|
||||
{
|
||||
printf("%s: Failed to parse VDF file: '%s'\n", __FUNCTION__, pSettingsPath);
|
||||
return;
|
||||
}
|
||||
|
||||
bool success{ };
|
||||
std::ifstream fileStream(settingsPath, fstream::in);
|
||||
vdf::object vRoot = vdf::read(fileStream, &success);
|
||||
const int settingsVersion = kv.GetInt("version", -1);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
printf("%s: Failed to parse VDF file: '%s'\n", __FUNCTION__,
|
||||
settingsPath.u8string().c_str());
|
||||
if (settingsVersion != SDK_LAUNCHER_VERSION)
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
KeyValues* sv = kv.FindKey("vars");
|
||||
|
||||
if (!sv)
|
||||
{
|
||||
string& attributeView = vRoot.attribs["version"];
|
||||
|
||||
int settingsVersion = atoi(attributeView.c_str());
|
||||
if (settingsVersion != SDK_LAUNCHER_VERSION)
|
||||
return;
|
||||
|
||||
vdf::object* pSubKey = vRoot.childs["vars"].get();
|
||||
if (!pSubKey)
|
||||
return;
|
||||
|
||||
// Game.
|
||||
attributeView = pSubKey->attribs["playlistsFile"];
|
||||
this->m_PlaylistFileTextBox->SetText(attributeView.data());
|
||||
|
||||
attributeView = pSubKey->attribs["enableCheats"];
|
||||
this->m_CheatsToggle->SetChecked(attributeView != "0");
|
||||
|
||||
attributeView = pSubKey->attribs["enableDeveloper"];
|
||||
this->m_DeveloperToggle->SetChecked(attributeView != "0");
|
||||
|
||||
attributeView = pSubKey->attribs["enableConsole"];
|
||||
this->m_ConsoleToggle->SetChecked(attributeView != "0");
|
||||
|
||||
attributeView = pSubKey->attribs["colorConsole"];
|
||||
this->m_ColorConsoleToggle->SetChecked(attributeView != "0");
|
||||
|
||||
// Engine.
|
||||
attributeView = pSubKey->attribs["reservedCoreCount"];
|
||||
this->m_ReservedCoresTextBox->SetText(attributeView.data());
|
||||
|
||||
attributeView = pSubKey->attribs["workerThreadCount"];
|
||||
this->m_WorkerThreadsTextBox->SetText(attributeView.data());
|
||||
|
||||
attributeView = pSubKey->attribs["processorAffinity"];
|
||||
this->m_ProcessorAffinityTextBox->SetText(attributeView.data());
|
||||
|
||||
attributeView = pSubKey->attribs["noAsync"]; // No-async
|
||||
this->m_NoAsyncJobsToggle->SetChecked(attributeView != "0");
|
||||
|
||||
// Network.
|
||||
attributeView = pSubKey->attribs["encryptPackets"];
|
||||
this->m_NetEncryptionToggle->SetChecked(attributeView != "0");
|
||||
|
||||
attributeView = pSubKey->attribs["randomNetKey"];
|
||||
this->m_NetRandomKeyToggle->SetChecked(attributeView != "0");
|
||||
|
||||
attributeView = pSubKey->attribs["queuedPackets"];
|
||||
this->m_QueuedPacketThread->SetChecked(attributeView != "0");
|
||||
|
||||
attributeView = pSubKey->attribs["noTimeOut"];
|
||||
this->m_NoTimeOutToggle->SetChecked(attributeView != "0");
|
||||
|
||||
// Video.
|
||||
attributeView = pSubKey->attribs["windowed"];
|
||||
this->m_WindowedToggle->SetChecked(attributeView != "0");
|
||||
|
||||
attributeView = pSubKey->attribs["borderless"];
|
||||
this->m_NoBorderToggle->SetChecked(attributeView != "0");
|
||||
|
||||
attributeView = pSubKey->attribs["maxFPS"];
|
||||
this->m_FpsTextBox->SetText(attributeView.data());
|
||||
|
||||
attributeView = pSubKey->attribs["width"];
|
||||
this->m_WidthTextBox->SetText(attributeView.data());
|
||||
|
||||
attributeView = pSubKey->attribs["height"];
|
||||
this->m_HeightTextBox->SetText(attributeView.data());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
printf("%s: Exception while parsing VDF file: %s\n", __FUNCTION__, e.what());
|
||||
printf("%s: VDF file '%s' lacks subkey: '%s'\n", __FUNCTION__, pSettingsPath, "vars");
|
||||
return; // No settings to apply
|
||||
}
|
||||
|
||||
// Game.
|
||||
this->m_PlaylistFileTextBox->SetText(sv->GetString("playlistsFile"));
|
||||
this->m_CheatsToggle->SetChecked(sv->GetBool("enableCheats"));
|
||||
this->m_DeveloperToggle->SetChecked(sv->GetBool("enableDeveloper"));
|
||||
this->m_ConsoleToggle->SetChecked(sv->GetBool("enableConsole"));
|
||||
this->m_ColorConsoleToggle->SetChecked(sv->GetBool("colorConsole"));
|
||||
|
||||
// Engine.
|
||||
this->m_ReservedCoresTextBox->SetText(sv->GetString("reservedCoreCount", "-1"));
|
||||
this->m_WorkerThreadsTextBox->SetText(sv->GetString("workerThreadCount", "-1"));
|
||||
this->m_ProcessorAffinityTextBox->SetText(sv->GetString("processorAffinity", "0"));
|
||||
this->m_NoAsyncJobsToggle->SetChecked(sv->GetBool("noAsync"));
|
||||
|
||||
// Network.
|
||||
this->m_NetEncryptionToggle->SetChecked(sv->GetBool("encryptPackets", true));
|
||||
this->m_NetRandomKeyToggle->SetChecked(sv->GetBool("randomNetKey", true));
|
||||
this->m_QueuedPacketThread->SetChecked(sv->GetBool("queuedPackets", true));
|
||||
this->m_NoTimeOutToggle->SetChecked(sv->GetBool("noTimeOut"));
|
||||
|
||||
// Video.
|
||||
this->m_WindowedToggle->SetChecked(sv->GetBool("windowed"));
|
||||
this->m_NoBorderToggle->SetChecked(sv->GetBool("borderless"));
|
||||
this->m_FpsTextBox->SetText(sv->GetString("maxFPS", "-1"));
|
||||
this->m_WidthTextBox->SetText(sv->GetString("width"));
|
||||
this->m_HeightTextBox->SetText(sv->GetString("height"));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -620,60 +588,69 @@ void CSurface::LoadSettings()
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSurface::SaveSettings()
|
||||
{
|
||||
const fs::path settingsPath(Format("platform/%s/%s", SDK_SYSTEM_CFG_PATH, LAUNCHER_SETTING_FILE));
|
||||
const fs::path parentPath = settingsPath.parent_path();
|
||||
CUtlString settingsPath;
|
||||
settingsPath.Format("platform/" SDK_SYSTEM_CFG_PATH "%s", LAUNCHER_SETTING_FILE);
|
||||
|
||||
if (!fs::exists(parentPath) && !fs::create_directories(parentPath))
|
||||
CUtlString settingsDir = settingsPath.DirName();
|
||||
|
||||
const char* pSettingsPath = settingsPath.String();
|
||||
const char* pSettingsDir = settingsDir.String();
|
||||
|
||||
FileSystem()->CreateDirHierarchy(pSettingsDir);
|
||||
|
||||
if (!FileSystem()->IsDirectory(pSettingsDir))
|
||||
{
|
||||
printf("%s: Failed to create directory: '%s'\n", __FUNCTION__,
|
||||
parentPath.relative_path().u8string().c_str());
|
||||
printf("%s: Failed to create directory: '%s'\n", __FUNCTION__, pSettingsPath);
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream fileStream(settingsPath, fstream::out);
|
||||
if (!fileStream)
|
||||
KeyValues kv("LauncherSettings");
|
||||
kv.SetInt("version", SDK_LAUNCHER_VERSION);
|
||||
|
||||
KeyValues* sv = new KeyValues("vars");
|
||||
|
||||
if (!sv)
|
||||
{
|
||||
printf("%s: Failed to create VDF file: '%s'\n", __FUNCTION__,
|
||||
settingsPath.u8string().c_str());
|
||||
return;
|
||||
printf("%s: Failed to allocate subkey: '%s'\n", __FUNCTION__, "vars");
|
||||
return; // No settings to apply
|
||||
}
|
||||
|
||||
vdf::object vRoot;
|
||||
vRoot.set_name("LauncherSettings");
|
||||
vRoot.add_attribute("version", std::to_string(SDK_LAUNCHER_VERSION));
|
||||
|
||||
vdf::object* vVars = new vdf::object();
|
||||
vVars->set_name("vars");
|
||||
kv.AddSubKey(sv);
|
||||
|
||||
// Game.
|
||||
vVars->add_attribute("playlistsFile", GetControlValue(this->m_PlaylistFileTextBox));
|
||||
vVars->add_attribute("enableCheats", GetControlValue(this->m_CheatsToggle));
|
||||
vVars->add_attribute("enableDeveloper", GetControlValue(this->m_DeveloperToggle));
|
||||
vVars->add_attribute("enableConsole", GetControlValue(this->m_ConsoleToggle));
|
||||
vVars->add_attribute("colorConsole", GetControlValue(this->m_ColorConsoleToggle));
|
||||
sv->SetString("playlistsFile", GetControlValue(this->m_PlaylistFileTextBox));
|
||||
sv->SetBool("enableCheats", this->m_CheatsToggle->Checked());
|
||||
sv->SetBool("enableDeveloper", this->m_DeveloperToggle->Checked());
|
||||
sv->SetBool("enableConsole", this->m_ConsoleToggle->Checked());
|
||||
sv->SetBool("colorConsole", this->m_ColorConsoleToggle->Checked());
|
||||
|
||||
// Engine.
|
||||
vVars->add_attribute("reservedCoreCount", GetControlValue(this->m_ReservedCoresTextBox));
|
||||
vVars->add_attribute("workerThreadCount", GetControlValue(this->m_WorkerThreadsTextBox));
|
||||
vVars->add_attribute("processorAffinity", GetControlValue(this->m_ProcessorAffinityTextBox));
|
||||
vVars->add_attribute("noAsync", GetControlValue(this->m_NoAsyncJobsToggle));
|
||||
sv->SetString("reservedCoreCount", GetControlValue(this->m_ReservedCoresTextBox));
|
||||
sv->SetString("workerThreadCount", GetControlValue(this->m_WorkerThreadsTextBox));
|
||||
sv->SetString("processorAffinity", GetControlValue(this->m_ProcessorAffinityTextBox));
|
||||
sv->SetBool("noAsync", this->m_NoAsyncJobsToggle->Checked());
|
||||
|
||||
// Network.
|
||||
vVars->add_attribute("encryptPackets", GetControlValue(this->m_NetEncryptionToggle));
|
||||
vVars->add_attribute("randomNetKey", GetControlValue(this->m_NetRandomKeyToggle));
|
||||
vVars->add_attribute("queuedPackets", GetControlValue(this->m_QueuedPacketThread));
|
||||
vVars->add_attribute("noTimeOut", GetControlValue(this->m_NoTimeOutToggle));
|
||||
sv->SetBool("encryptPackets", this->m_NetEncryptionToggle->Checked());
|
||||
sv->SetBool("randomNetKey", this->m_NetRandomKeyToggle->Checked());
|
||||
sv->SetBool("queuedPackets", this->m_QueuedPacketThread->Checked());
|
||||
sv->SetBool("noTimeOut", this->m_NoTimeOutToggle->Checked());
|
||||
|
||||
// Video.
|
||||
vVars->add_attribute("windowed", GetControlValue(this->m_WindowedToggle));
|
||||
vVars->add_attribute("borderless", GetControlValue(this->m_NoBorderToggle));
|
||||
vVars->add_attribute("maxFPS", GetControlValue(this->m_FpsTextBox));
|
||||
vVars->add_attribute("width", GetControlValue(this->m_WidthTextBox));
|
||||
vVars->add_attribute("height", GetControlValue(this->m_HeightTextBox));
|
||||
sv->SetBool("windowed", this->m_WindowedToggle->Checked());
|
||||
sv->SetBool("borderless", this->m_NoBorderToggle->Checked());
|
||||
sv->SetString("maxFPS", GetControlValue(this->m_FpsTextBox));
|
||||
sv->SetString("width", GetControlValue(this->m_WidthTextBox));
|
||||
sv->SetString("height", GetControlValue(this->m_HeightTextBox));
|
||||
|
||||
vRoot.add_child(std::unique_ptr<vdf::object>(vVars));
|
||||
CUtlBuffer outBuf(ssize_t(0), 0, CUtlBuffer::TEXT_BUFFER);
|
||||
kv.RecursiveSaveToFile(outBuf, 0);
|
||||
|
||||
vdf::write(fileStream, vRoot);
|
||||
if (!FileSystem()->WriteFile(pSettingsPath, "PLATFORM", outBuf))
|
||||
{
|
||||
printf("%s: Failed to create VDF file: '%s'\n", __FUNCTION__, pSettingsPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -735,11 +712,11 @@ void CSurface::LaunchGame(Forms::Control* pSender)
|
||||
string svParameter;
|
||||
pSurface->AppendParameterInternal(svParameter, "-launcher");
|
||||
|
||||
eLaunchMode launchMode = g_pLauncher->GetMainSurface()->BuildParameter(svParameter);
|
||||
eLaunchMode launchMode = g_Launcher.BuildParameter(svParameter);
|
||||
uint64_t nProcessorAffinity = pSurface->GetProcessorAffinity(svParameter);
|
||||
|
||||
if (g_pLauncher->CreateLaunchContext(launchMode, nProcessorAffinity, svParameter.c_str(), "startup_launcher.cfg"))
|
||||
g_pLauncher->LaunchProcess();
|
||||
if (g_Launcher.CreateLaunchContext(launchMode, nProcessorAffinity, svParameter.c_str(), "startup_launcher.cfg"))
|
||||
g_Launcher.LaunchProcess();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -790,41 +767,39 @@ void CSurface::ParseMaps()
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSurface::ParsePlaylists()
|
||||
{
|
||||
fs::path playlistPath(Format("platform\\%s", this->m_PlaylistFileTextBox->Text().ToCString()));
|
||||
m_PlaylistCombo->Items.Add("");
|
||||
CUtlString playlistPath;
|
||||
playlistPath.Format("platform\\%s", this->m_PlaylistFileTextBox->Text().ToCString());
|
||||
|
||||
if (!fs::exists(playlistPath))
|
||||
const char* pPlaylistPath = playlistPath.String();
|
||||
|
||||
if (!m_PlaylistCombo->Items.Contains(""))
|
||||
m_PlaylistCombo->Items.Add("");
|
||||
|
||||
if (!FileSystem()->FileExists(pPlaylistPath))
|
||||
return;
|
||||
|
||||
KeyValues kv("playlists");
|
||||
|
||||
if (!kv.LoadFromFile(FileSystem(), pPlaylistPath, nullptr))
|
||||
{
|
||||
printf("%s: Failed to parse playlists file: '%s'\n", __FUNCTION__, pPlaylistPath);
|
||||
return;
|
||||
}
|
||||
|
||||
bool success{ };
|
||||
std::ifstream iFile(playlistPath);
|
||||
vdf::object vRoot = vdf::read(iFile, &success);
|
||||
KeyValues* playlists = kv.FindKey("Playlists");
|
||||
|
||||
if (!success)
|
||||
{
|
||||
printf("%s: Failed to parse VDF file: '%s'\n", __FUNCTION__,
|
||||
playlistPath.u8string().c_str());
|
||||
return;
|
||||
}
|
||||
if (!playlists)
|
||||
return; // Empty playlists
|
||||
|
||||
try
|
||||
for (KeyValues* pSubKey = playlists->GetFirstTrueSubKey(); pSubKey != nullptr; pSubKey = pSubKey->GetNextTrueSubKey())
|
||||
{
|
||||
const auto& vcPlaylists = vRoot.childs.at("Playlists");
|
||||
for (auto [id, it] = std::tuple<int, decltype(vcPlaylists->childs.begin())>
|
||||
{ 1, vcPlaylists->childs.begin() }; it != vcPlaylists->childs.end(); id++, it++)
|
||||
const char* keyName = pSubKey->GetName();
|
||||
|
||||
if (!this->m_PlaylistCombo->Items.Contains(keyName))
|
||||
{
|
||||
if (!this->m_PlaylistCombo->Items.Contains(it->first.c_str()))
|
||||
{
|
||||
this->m_PlaylistCombo->Items.Add(it->first.c_str());
|
||||
}
|
||||
this->m_PlaylistCombo->Items.Add(keyName);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
printf("%s: Exception while parsing VDF file: %s\n", __FUNCTION__, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1300,8 +1275,4 @@ const char* CSurface::GetControlValue(Forms::Control* pControl)
|
||||
//-----------------------------------------------------------------------------
|
||||
CSurface::CSurface() : Forms::Form()
|
||||
{
|
||||
this->Init();
|
||||
this->Setup();
|
||||
}
|
||||
|
||||
CSurface* g_pMainUI;
|
@ -22,8 +22,10 @@ public:
|
||||
UIX::UIXListView* ConsoleListView() const { return m_ConsoleListView; };
|
||||
std::vector<LogList_t> m_LogList;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
eLaunchMode BuildParameter(string& svParameter);
|
||||
|
||||
private:
|
||||
void Setup();
|
||||
void LoadSettings();
|
||||
void SaveSettings();
|
||||
@ -44,8 +46,6 @@ private:
|
||||
const char* GetControlValue(Forms::Control* pControl);
|
||||
uint64_t GetProcessorAffinity(string& szParameter);
|
||||
|
||||
eLaunchMode BuildParameter(string& svParameter);
|
||||
|
||||
void AppendParameterInternal(string& svParameterList, const char* szParameter, const char* szArgument = nullptr);
|
||||
void AppendProcessorParameters(string& svParameter);
|
||||
void AppendConsoleParameters(string& svParameter);
|
||||
|
@ -8,6 +8,28 @@
|
||||
#include "basepanel.h"
|
||||
#include "sdklauncher.h"
|
||||
|
||||
#include "vstdlib/keyvaluessystem.h"
|
||||
#include "filesystem/filesystem_std.h"
|
||||
|
||||
static CKeyValuesSystem s_KeyValuesSystem;
|
||||
static CFileSystem_Stdio g_FullFileSystem;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Purpose: keyvalues singleton accessor
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
IKeyValuesSystem* KeyValuesSystem()
|
||||
{
|
||||
return &s_KeyValuesSystem;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Purpose: filesystem singleton accessor
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
CFileSystem_Stdio* FileSystem()
|
||||
{
|
||||
return &g_FullFileSystem;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Purpose: initializes and runs the user interface
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -16,8 +38,8 @@ void CLauncher::RunSurface()
|
||||
Forms::Application::EnableVisualStyles();
|
||||
UIX::UIXTheme::InitializeRenderer(new Themes::KoreTheme());
|
||||
|
||||
m_pSurface = new CSurface();
|
||||
Forms::Application::Run(g_pLauncher->m_pSurface);
|
||||
m_Surface.Init();
|
||||
Forms::Application::Run(&g_Launcher.m_Surface, false);
|
||||
UIX::UIXTheme::ShutdownRenderer();
|
||||
}
|
||||
|
||||
@ -366,21 +388,21 @@ BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
int main(int argc, char* argv[]/*, char* envp[]*/)
|
||||
{
|
||||
g_pLauncher->InitLogger();
|
||||
g_Launcher.InitLogger();
|
||||
if (argc < 2)
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
FreeConsole();
|
||||
#endif // NDEBUG
|
||||
g_pLauncher->RunSurface();
|
||||
g_Launcher.RunSurface();
|
||||
}
|
||||
else
|
||||
{
|
||||
int results = g_pLauncher->HandleCommandLine(argc, argv);
|
||||
int results = g_Launcher.HandleCommandLine(argc, argv);
|
||||
if (results != -1)
|
||||
return results;
|
||||
|
||||
return g_pLauncher->HandleInput();
|
||||
return g_Launcher.HandleInput();
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -388,4 +410,4 @@ int main(int argc, char* argv[]/*, char* envp[]*/)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Singleton Launcher.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
CLauncher* g_pLauncher(new CLauncher("win_console"));
|
||||
CLauncher g_Launcher("win_console");
|
||||
|
@ -6,17 +6,12 @@ class CLauncher
|
||||
public:
|
||||
CLauncher(const char* pszLoggerName)
|
||||
{
|
||||
m_pSurface = nullptr;
|
||||
m_pLogger = spdlog::stdout_color_mt(pszLoggerName);
|
||||
m_ProcessorAffinity = NULL;
|
||||
m_svCurrentDir = fs::current_path().u8string();
|
||||
}
|
||||
~CLauncher()
|
||||
{
|
||||
if (m_pSurface)
|
||||
{
|
||||
delete m_pSurface;
|
||||
}
|
||||
}
|
||||
|
||||
void AddLog(spdlog::level::level_enum nLevel, const char* szFormat, ...)
|
||||
@ -30,12 +25,9 @@ public:
|
||||
m_pLogger->log(nLevel, svBuffer);
|
||||
m_pLogger->flush();
|
||||
|
||||
if (m_pSurface)
|
||||
{
|
||||
m_pSurface->m_LogList.push_back(LogList_t(nLevel, svBuffer));
|
||||
m_pSurface->ConsoleListView()->SetVirtualListSize(static_cast<int32_t>(m_pSurface->m_LogList.size()));
|
||||
m_pSurface->ConsoleListView()->Refresh();
|
||||
}
|
||||
m_Surface.m_LogList.push_back(LogList_t(nLevel, svBuffer));
|
||||
m_Surface.ConsoleListView()->SetVirtualListSize(static_cast<int32_t>(m_Surface.m_LogList.size()));
|
||||
m_Surface.ConsoleListView()->Refresh();
|
||||
}
|
||||
|
||||
void RunSurface();
|
||||
@ -49,10 +41,10 @@ public:
|
||||
void SetupLaunchContext(const char* szConfig, const char* szGameDll, const char* szCommandLine);
|
||||
bool LaunchProcess() const;
|
||||
|
||||
CSurface* GetMainSurface() const { return m_pSurface; }
|
||||
eLaunchMode BuildParameter(string& parameterList) { return m_Surface.BuildParameter(parameterList); }
|
||||
|
||||
private:
|
||||
CSurface* m_pSurface;
|
||||
CSurface m_Surface;
|
||||
std::shared_ptr<spdlog::logger> m_pLogger;
|
||||
|
||||
uint64_t m_ProcessorAffinity;
|
||||
@ -64,4 +56,4 @@ private:
|
||||
|
||||
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
|
||||
|
||||
extern CLauncher* g_pLauncher;
|
||||
extern CLauncher g_Launcher;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
// Change this each time the settings format has changed.
|
||||
#define SDK_LAUNCHER_VERSION 1
|
||||
#define SDK_LAUNCHER_VERSION 2
|
||||
|
||||
// Uncomment this line to compile the launcher for dedicated server builds.
|
||||
//#define DEDI_LAUNCHER
|
||||
|
@ -11,7 +11,7 @@ namespace Forms
|
||||
std::atomic<bool> Application::IsGdipInitialized = false;
|
||||
ULONG_PTR Application::GdipToken = NULL;
|
||||
|
||||
void Application::Run(Form* MainWindow)
|
||||
void Application::Run(Form* MainWindow, bool DeleteWindow)
|
||||
{
|
||||
if (MainWindow == nullptr)
|
||||
return;
|
||||
@ -27,7 +27,7 @@ namespace Forms
|
||||
// Execute on the main loop
|
||||
Application::RunMainLoop(MainWindow);
|
||||
|
||||
if (MainWindow)
|
||||
if (MainWindow && DeleteWindow)
|
||||
delete MainWindow;
|
||||
|
||||
// Shutdown COM
|
||||
|
@ -12,7 +12,7 @@ namespace Forms
|
||||
public:
|
||||
// Begins running a standard application message loop on the current
|
||||
// thread, and makes the specified form visible.
|
||||
static void Run(Form* MainWindow);
|
||||
static void Run(Form* MainWindow, bool DeleteWindow);
|
||||
|
||||
// Begins running a dialog application loop on the
|
||||
// current thread, you MUST clean up the dialog after use.
|
||||
|
Loading…
x
Reference in New Issue
Block a user